Generator funkcyjny z karty dźwiękowej
Czwartek, 01 Lipiec 2010
Generator funkcji jest podstawowym narzędziem elektronika
konstruktora. Jednak fabryczne generatory są drogie i nie każdy
może sobie pozwolić na taki luksus. Alternatywnym rozwiązaniem
jest generator software\'owy, czyli program komputerowy sterujący
kartą dźwiękową. Koszt tego rozwiązania żaden, a program może
być w wielu przypadkach użyteczny.
64 ELEKTRONIKA PRAKTYCZNA 7/2010
Notatnik konstruktora
Podstawowe informacje:
? Zakres częstotliwości wyjściowej:
1 Hz...20 kHz (sinus).
? Rozdzielczość ustawiania częstotliwości:
0,1 Hz.
? Maksymalna amplituda napięcia wyjściowego:
zależna od karty dźwiękowej.
? Generowanie przebiegów o kształtach:
sinusoidalnym, trójkątnym, prostokątnym.
W opisanym generatorze wykorzystuje
się przetworniki C/A na karcie dźwiękowej
z częstotliwością próbkowania 96 kHz lub
44,2 kHz na kartach starszego typu. Sygnał
jest pobierany z wyjść karty dźwiękowej,
które są najczęściej typu jack. Oczywiście,
jak widać z samej zasady działania, genera-
tor taki ma gorsze parametry niż generator
sprzętowy. Generatory pozwalają uzyskać
częstotliwości sygnału wyjściowego powy-
żej 1 MHz, a ten jedynie kilkadziesiąt kilo-
herców i to tylko dla sinusoidy. Do badania
urządzeń akustycznych to jednak w zupeł-
ności wystarczy, a z powodu niskiej ceny
nasz generator może być konkurencyjny w
stosunku do firmowych. Inną zaletą jest to,
że przy niskich częstotliwościach możemy
uzyskać bardzo małe zniekształcenia. Sygnał
odwzorowany jest z rodzielczością 16 bitów,
czyli 65536 poziomów napięć. Dodatkowym
mankamentem kart dźwiękowych jest to, że
na sygnał wyjściowy nakładają się zakłóce-
nia elektromagnetyczne wytwarzane przez
płytę główną komputera oraz to, że wyjście
jest separowane kondensatorem sprzęgają-
cym o niewielkiej pojemności, co ogranicza
pasmo od dołu.
Zasada działania
Do bufora o odpowiedniej długości wpi-
sywane są kolejne wartości chwilowe am-
Generator funkcyjny
z karty dźwiękowej
Generator funkcji jest podstawowym narzędziem elektronika
konstruktora. Jednak fabryczne generatory są drogie i nie każdy
może sobie pozwolić na taki luksus. Alternatywnym rozwiązaniem
jest generator software?owy, czyli program komputerowy sterujący
kartą dźwiękową. Koszt tego rozwiązania żaden, a program może
być w wielu przypadkach użyteczny.
plitudy sygnału generowanego. Następnie
bufor jest cyklicznie odczytywany przez pro-
gram obsługi urządzeń typu ?Wave?, a zapi-
sane w nim wartości są kolejno podawane na
wyjście przetwornika C/A karty dźwiękowej.
Szybkość odczytu z bufora jest stała i równa
maksymalnej częstotliwości próbkowania
dla danej karty. Z tego powodu o częstot-
liwości wytwarzanego przebiegu decyduje
rozłożenie danych w buforze.
Należy również zauważyć, że dane po-
winny być tak rozłożone, aby mieściły na ca-
łej długości bufora całkowitą liczbą okresów.
Wynika to z faktu, że gdy licznik procedury
odczytującej dojdzie do końca bufora, zostaje
wyzerowany i odczytywanie zaczyna się od
początku. Gdybyśmy nie zachowali ciągłości
sygnału, wystąpiłby silny impuls zakłócający
przy przejściu licznika do początku bufora.
Należy zauważyć pewną prawidłowość.
Częstotliwość sygnału wyjściowego jest pro-
porcjonalna do liczby okresów zawartych
w buforze oraz zależy od czasu odczytu całe-
go bufora. Można to wyrazić wzorem:
gdzie:
? N: liczba okresów w całym buforze,
? Tbuf
: czas odczytu całego bufora.
W naszym przypadku chcemy, aby czę-
stotliwość ustawiana była z rozdzielczością
0,1 Hz, więc długość bufora ustalamy tak,
aby całkowity czas odczytu wynosił 10 s.
Można to wyrazić za pomocą następującego
wzoru:
gdzie:
? fp
: częstotliwość próbkowania.
? Tbuf
: czas odczytu całego bufora.
? kanały: liczba kanałów.
? bajty: liczba bajtów na próbkę.
W naszym przypadku fp
=96 kHz,
Tbuf
=10 s, kanały=2 (stereo), bajty=2
(16 bitów). Dane są zapisywane w posta-
ci liczby całkowitej ze znakiem w notacji
U2, czyli odpowiadają typowi short języ-
ka C++.
Opisane wyżej zależności pokazano gra-
ficznie na rysunku 1 i rysunku 2.
Interfejs użytkownika
Interfejs użytkownika napisano w po-
staci okna dialogowego o stałej wielkości.
Można w nim wydzielić dwie podstawo-
we sekcje: ustawiania częstotliwości oraz
ustawiania amplitudy. Parametry te można
zmieniać za pomocą suwaków lub wpisując
odpowiednie wartości w pola tekstowe. Do
zmiany zakresów służą przyciski typu ?Ra-
dio button? i odpowiednio dla częstotliwo-
ści są to:
Rysunek 1. Związek między rozmieszczeniem danych w buforze a częstotliwością
65ELEKTRONIKA PRAKTYCZNA 7/2010
Generator funkcyjny z karty dźwiękowej
nych oraz uruchomieniu odpowiedniej pro-
cedury odtwarzającej. Ważniejsze fragmenty
programu realizującego generator funkcyjny
umieszczono na listingu 1, którego dokładne
przestudiowanie pozwoli zrozumieć sposób
działania programu.
Dokładniejszy opis funkcji ?Wave Audio?
można znaleźć na stronie: http://msdn.microsoft.
com/en-us/library w sekcji: ?Win32 and COM
Development/Audio and Video/Windows Multi-
media/Multimedia Audio/Waveform Audio.
Program napisano jako zwykłą aplika-
cję Win32, niewykorzystującą żadnych roz-
szerzeń ani dodatkowych bibliotek. Projekt
został skompilowany z użyciem Microsoft-
Visual C++ ver.6.0, ale można go zaimporto-
wać do nowszych wersji.
Tomasz Krogulski
tomaszkro@op.pl
Ponadto, przyciskami w sekcji ustawia-
nia kształtu możemy zmieniać kształt gene-
rowanego sygnału. Do wyboru są opcje po-
dobne jak w typowym generatorze funkcji,
czyli: sinus, trójkąt, prostokąt.
W przypadku gdy w komputerze mamy
więcej niż jedno urządzenie typu ?Wave Au-
dio?, możemy je wybrać za pomocą kontrolki
typu ?Combo box?.
Po przyciśnięciu przycisku ?Parametry?
wyświetlane są parametry bieżącej (wybra-
nej) karty dźwiękowej, natomiast wybranie
przycisku ?Informacja? powoduje wyświe-
tlenie podstawowych informacji na temat
programu.
Procedura generująca dźwięk
Działanie tej procedury w zasadzie pole-
ga na odpowiednim wypełnieniu bufora da-
? 100 Hz: umożliwia uzyskanie częstotli-
wości do 100 Hz,
? 1 kHz: umożliwia uzyskanie częstotliwo-
ści do 1 kHz,
? 20 kHz: umożliwia uzyskanie częstotli-
wości do 20 kHz.
Dla amplitudy są to:
? 1:1: maksymalna amplituda równa mak-
symalnemu napięciu wyjściowemu karty
dźwiękowej,
? 1:10: maksymalna amplituda równa 10%
maksymalnego napięcia wyjściowego
karty dźwiękowej,
? 1:100 maksymalna amplituda równa 1%
maksymalnego napięcia wyjściowego
karty dźwiękowej.
Przy wpisaniu do pola tekstowego odpo-
wiedniej wartości położenia suwaków oraz przy-
ciski zakresów są aktualizowane automatycznie.
Rysunek 2. Rozmieszczenie danych w buforze
Listing 1. Ważniejsze fragmenty programu generatora funkcyjnego
//zmienne globalne:
char FU_Buffer[96000*4*10]; bufor odtwarzanych danych;
HWAVEOUT FU_Hw = NULL; handler urządzenia ?Wave Audio?;
WAVEFORMATEX FU_Wf; struktura parametrów przetwarzania;
WAVEHDR FU_Hdr; nagłówek bufora;
/*parametry:
freq - częstotliwość*10;
amp - amplituda (0-100000);
shape - kształt: 0 - sinus, 1 - trójkąt, 2 - prostokąt;
idx - indeks urządzenia ;
chn ? liczba kanałów;
fsample - częstotliwość próbkowania; */
void StartWave(int freq, int amp, int shape, int idx, int chn, int fsample)
{
if(FU_Hw) // Zamknięcie urządzenia ?Wave Audio?, jeśli jest otwarte
{
waveOutReset(FU_Hw);
waveOutUnprepareHeader(FU_Hw, &FU_Hdr, sizeof(FU_Hdr));
waveOutClose(FU_Hw);
}
FU_Wf.nChannels = chn; // wypełnienie struktury
FU_Wf.nSamplesPerSec = fsample; // parametrów przetwarzania
FU_Wf.wBitsPerSample = 16; // która jest następnie przekazana
FU_Wf.nAvgBytesPerSec = fsample*4; // do funkcji ?waveOutOpen?
FU_Wf.wFormatTag = WAVE_FORMAT_PCM;
FU_Wf.nBlockAlign = 4;
FU_Wf.cbSize = 0;
// otwarcie urządzenia ?Wave Audio?
MMRESULT re1 = waveOutOpen(&FU_Hw, idx, &FU_Wf, NULL, NULL, CALLBACK_NULL);
// wypełninie struktury nagłówka w której zawarty jest sposób
// odtwarzania dźwięku (sygnału)
FU_Hdr.dwBufferLength = fsample*chn*2*10; // długość bufora
FU_Hdr.lpData = FU_Buffer; // adres bufora
66 ELEKTRONIKA PRAKTYCZNA 7/2010
Notatnik konstruktora
Listing 1. cd.
FU_Hdr.dwLoops = 0xFFFFFFFF; // liczba powtórzeń odczytu (całego
// bufora) wpisałem maksymalną wartość, co w praktyce oznacza
// nieskończoną liczbę powtórzeń
FU_Hdr.dwFlags = WHDR_BEGINLOOP|WHDR_ENDLOOP;
// Nagłówek jest pierwszym i zarazem ostatnim w pętli odtwarzania.
union {
char *cpt;
short *wpt;
short (*lpt)[2];
} pt;
int i;
pt.cpt = FU_Buffer;
for(i=0; i(0.5/freal) ? -32768 : 32767;
}
if(chn==1) // przepisanie wartości do bufora
pt.wpt[i] = val;
else {
pt.lpt[i][0] = val;
pt.lpt[i][1] = val;
}
}
// aby odtworzyć zawartość bufora, należy najpierw utworzyć nagłówek
// za pomocą
// funkcji ?waveOutPrepareHeader?
waveOutPrepareHeader(FU_Hw, &FU_Hdr, sizeof(FU_Hdr));
// ustawianie amplitudy za pomocą funkcji ?waveOutSetVolume?
waveOutSetVolume(FU_Hw,(unsigned short)((double)amp/100000.0*65535.0));
// rozpoczęcie odczytu - czyli start generatora
waveOutWrite(FU_Hw, &FU_Hdr, sizeof(FU_Hdr));
}
// Opis funkcji interfejsu API Windowsów obsługi urządzeń ?Wave
// AUDIO? wykorzystywanych w naszej procedurze:
// Otwarcie danego urządzenia ?Wave AUDIO?
MMRESULT waveOutOpen(
LPHWAVEOUT phwo, // zwracany handler dla nowo otwartego urządzenia ?Wave AUDIO?
UINT_PTR uDeviceID, // numer urządzenia
LPWAVEFORMATEX pwfx, // struktura z parametrami odtwarzania
DWORD_PTR dwCallback, // wskaźnik do procedury obsługi odtwarzania
DWORD_PTR dwCallbackInstance, // dana przesyłana do procedury obsługi
DWORD fdwOpen // flagi - w naszym przypadku 0
);
// Zamknięcie urządzenia ?Wave AUDIO?
waveOutClose(
LPHWAVEOUT phwo // handler urządzenia
);
// Wyłączenie urządzenia (zatrzymanie odtwarzania)
waveOutReset(
LPHWAVEOUT phwo // handler urządzenia
);
67ELEKTRONIKA PRAKTYCZNA 7/2010
Generator funkcyjny z karty dźwiękowej
Listing 1. cd.
// Przygotowanie nagłówka - trzeba wywołać przed wywołaniem
// ?waveOutWrite?
waveOutPrepareHeader(
LPHWAVEOUT phwo // handler urządzenia
LPWAVEHDR pwh, // przygotowywany nagłówek
UINT cbwh // wielkość nagłówka
);
// Zwolnienie nagłówka oraz związanego z nim bufora danych
// trzeba ją wywołać przed zwolnieniem bufora danych
waveOutUnprepareHeader(
HWAVEOUT hwo, // handler urządzenia
LPWAVEHDR pwh, // przygotowywany nagłówek
UINT cbwh // wielkość nagłówka
);
// Ustawia poziom głośności
waveOutSetVolume(
HWAVEOUT hwo, // handler urządzenia
DWORD dwVolume // poziom głośności 0-65536
);
// Procedura rozpoczynająca odtwarzanie dźwięku (zapis do kraty
// dźwiękowej)
waveOutWrite(
HWAVEOUT hwo, // handler urządzenia
LPWAVEHDR pwh, // wskaźnik do nagłówka
UINT cbwh // wielkość nagłówka
);
// Opis struktur wykorzystywanych przez powyższe funkcje
WAVEFORMATEX // struktura z parametrami odtwarzania
Poszczególne pola:
WORD wFormatTag; // typ format urządzenia
WORD nChannels; // liczba kanałów
DWORD nSamplesPerSec; // częstotliwość przetwarzania
DWORD nAvgBytesPerSec; // średnia ilość bitów na sekundę = nBlockAlign*nSamplesPerSec
WORD nBlockAlign; // liczba bajtów dla jednej próbki - w naszym przypadku 4
WORD wBitsPerSample; // liczba bitów jednej próbki
WORD cbSize; // rozmiar dodatkowych danych - w naszym przypadku 0
WAVEHDR // nagłówek danych do odtwarzania
Poszczególne pola:
LPSTR lpData; // adres bufora
DWORD dwBufferLength; // długość bufora
DWORD dwBytesRecorded; // liczba odczytanych bajtów
DWORD_PTR dwUser; // dane użytkownika
DWORD dwFlags; // najważniejsze flagi to: WHDR_BEGINLOOP - pierwszy nagłówek w
// pętli, WHDR_ENDLOOP - ostatni nagłówek;
DWORD dwLoops; // liczba powtórzeń pętli
struct wavehdr_tag *lpNext; // wskaźnik do następnego nagłówka
DWORD_PTR reserved; // zarezerwowane
R E K L A M A
Zobacz więcej w kategorii Notatnik konstruktora