Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

WinAPI - WaveOut - Dziwne "brzdękanie" pomiędzy dźwiękami.

Ostatnio zmodyfikowano 2023-08-31 23:29
Autor Wiadomość
befejak
Temat założony przez niniejszego użytkownika
WinAPI - WaveOut - Dziwne "brzdękanie" pomiędzy dźwiękami.
» 2023-08-30 19:31:43
Witam, z góry przepraszam ale kod będzie całkiem długi jak na standardy forum.
 Od 2 dni staram się zrobić swój własny program do grania dźwięków, docelowo planuję wykorzystać
 wiedzę do zrobienia Klasy, która będzie grała muzykę i efekty dźwiękowe w grze.

Docelowo planuję używać plików WAV ale narazie staram się zrobić zwykły MIDI player albo po prostu Beep.

Udało mi się zrobić pierwszy program który się kompiluje i nie wysypuje.
 I nawet gra dźwięki ale... pomiędzy dźwiękami jest taki "brzdęk" jakby przerwa

Początkowo używałem funkcji sin() aby zrobić ładną krzywą i mieć "pisk" ale to też dawało mi ten brzdęk.
 Zamieniłem funkcję na po prostu jedną wartość ale te brzdęki cały czas są...

Nie ważne czy używam 44100 hz czy 2205 hz tak jak obecnie w kodzie brzdęki dalej są :(
 Szukałem po internecie ale nie wiem czemu to się dzieje, tutaj kod:

qBeep() z funkcją sin wyglądał tak:
C/C++
for( int i = 0; i < qSamples; i++ ) {
   
qBufferA[ i ] = sin( i ) * 16000; }

Obecny mój kod:
C/C++
#include <Windows.h>
#include <math.h>

void CALLBACK qWaveCall( HWAVEOUT _Wave, UINT qMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 );

class qlSound {
public:
   
bool qBuffer; short // qBuffer controls which buffer is playing and which writing
   
* qBufferA, // qBuffer==true -> play qBufferA, write next in qBufferB
   
* qBufferB, // qBuffer==false  -> play qBufferB, write next in qBufferA
   
* qBufferP; // This should point to buffer that is playing ( either qBufferA or qBufferB )
   
   
WAVEFORMATEX qFormat; // Format of Wave
   
WAVEHDR qHeader; // Header of Wave
   
HWAVEOUT qWave; // WaveOutHandle
   
    // ( 44100 Hz / 1 sec ) ( 20 updates / sec = 44100 / 20 = 2205 Samples / sec ( 20 UPS ) )
   
int qSamples; // Amount of "Sound samples" in single update
   
   
void qBeep( const int _Tone, const int _Duration ) {
       
qBufferP = qBufferA;
       
for( int i = 0; i < qSamples; i++ ) {
           
qBufferA[ i ] = 12222;
       
}
       
       
waveOutWrite( qWave, & qHeader, sizeof( WAVEHDR ) );
   
}
   
   
qlSound( const int _Samples = 2205 ) {
       
qSamples = _Samples;
       
qBufferA = new short[ qSamples ];
       
qBufferB = new short[ qSamples ];
       
       
qFormat.wFormatTag = WAVE_FORMAT_PCM;
       
qFormat.nChannels = 1;
       
qFormat.nSamplesPerSec = 44100;
       
qFormat.nAvgBytesPerSec = 44100 * sizeof( short );
       
qFormat.nBlockAlign = sizeof( short );
       
qFormat.wBitsPerSample = sizeof( short ) * 8;
       
qFormat.cbSize = 0;
       
       
qHeader.lpData =( LPSTR ) qBufferA;
       
qHeader.dwBufferLength = qSamples * sizeof( short );
       
qHeader.dwBytesRecorded = 0;
       
qHeader.dwUser = 0;
       
qHeader.dwFlags = 0;
       
qHeader.dwLoops = 0;
       
qHeader.lpNext = NULL;
       
qHeader.reserved = 0;
       
       
waveOutOpen( & qWave, WAVE_MAPPER, & qFormat,( DWORD_PTR ) qWaveCall, 0, CALLBACK_FUNCTION );
       
waveOutPrepareHeader( qWave, & qHeader, sizeof( WAVEHDR ) );
       
   
}
   
~qlSound() {
       
waveOutUnprepareHeader( qWave, & qHeader, sizeof( WAVEHDR ) );
       
waveOutClose( qWave );
       
delete[ ] qBufferA;
       
delete[ ] qBufferB;
   
}
}
qSound( 2205 );
void CALLBACK qWaveCall( HWAVEOUT _Wave, UINT qMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 ) {
   
switch( qMsg ) {
   
case WOM_OPEN: break;
   
case WOM_CLOSE: break;
   
case WOM_DONE:
       
qSound.qBeep( 500, 500 );
       
break;
   
}
}
int main() {
   
qSound.qBeep( 500, 500 );
   
while( true );
   
   
return 0;
}
P-180348
pekfos
» 2023-08-31 18:14:29
Dobrze zacząłeś z dwoma buforami, tylko powinieneś ich używać. Powinieneś wystawić oba bufory naraz, bo inaczej gdy przychodzi WOM_DONE, sterownik nie ma już czego grać. dwParam1 wskazuje na zużyty bufor. W callbacku wypełnij go danymi i wyślij, w tym czasie będzie odtwarzany dźwięk z drugiego bufora.
P-180349
befejak
Temat założony przez niniejszego użytkownika
» 2023-08-31 22:20:23
Odnośnie dwóch bufforów, na samym początku chciałem to zrobić tak:
C/C++
if( qBuffer ) qBufferP = qBufferA;
else qBufferP = qBufferB;

qBuffer = !qBuffer;

qHeader.lpData =( LPSTR ) qBufferP;


Ale moja aplikacja się wysypywała podczas kompilowania, uruchomiłem w wersji debug i doszło do tego że wysypuje się po stronie Windowsa z powodu tego qBufferP więc na czas testowania zrezygnowałem z dwóch bufforów.

Ustawiłem na stałe qBufferA jako data aby przynajmniej się kompilowało.

Czy powinienem używać dwóch Headerów ( jeden dla qBufferA a drugi dla qBufferB? )czy wystarczy jak zrobię.
C/C++
if( qBuffer ) {
   
qHeader.lpData =( LPSTR ) qBufferA;
} else {
   
qHeader.lpData =( LPSTR ) qBufferB;
}

Ponadto chciałbym zapytać, bo szukałem w internecie odpowiedzi i znalazłem opcje aby:
C/C++
do { }
while( !( wh.dwFlags & WHDR_DONE ) );
Kod rzekomo ma zatrzymać wykonywanie programu ( wątku ) do momentu aż obecny sample skończy grać.

Użyć flag nagłówka zamiast Callbacku i zrobić sobie swój własny niezależny wątek zajmujący się tylko muzyką i niczym innym, na innym forum powiedzieli mi że CallBack jest po prostu wolniejszy więc teraz staram się przepisać mój kod zgodnie z ich instrukcjami... tylko wydaje mi się że wykonywanie pustej pętli bez przerwy do momentu aż dźwięk skończy grać to trochę strata zasobów komputera?

Jaka jest wasza opinia na ten temat?
 Czy CallBack faktycznie jest mniej precyzyjny od takiej pętli i lepiej używać pętli?
P-180350
pekfos
» 2023-08-31 23:29:46
Użyj dwóch headerów. Ta pętla odpada bo będzie bez sensu wciągać całe dostępne zasoby procesora. Precyzja callbacka nie ma znaczenia, bo w momencie wywołania dla zwolnionego bufora A będziesz mieć cały bufor B już przekazany.
P-180351
« 1 »
  Strona 1 z 1