Witam, bawie sie w apliakcji z nagrywaniem dzwieku,
dopiero dochodze do tworzenia watkow (wczesniej nie mialem z tym stycznosci)
ale z tego co czytam to w takiej aplikacji powininem stworzyć
osobno wątek do nagrywania, wątek do wczytywania nagrania, watek do zapisywania, watek do stopowania, watek do odtwarzania tak ? praktycznie do kazdej opcji ?
Nie za dużo tych wątków? W zasadzie żadnego wątka nie musisz tworzyć, jeśli robisz proste odtwarzanie/nagrywanie z/do pamięci, ponieważ funkcje zwrotne w portaudio działają w oddzielnych wątkach.
proste, proste (a co jeszcze można robić przykładowo? )
to jak mam kod z tym nagrywaniem, to u mnie jest, że można cokolwiek nacisnąć dopiero, gdy zakończy się nagrywanie, to samo z odtwarzaniem. (moge wkleic kod, ale pewnie go znasz, nic tam nie zmieniałem) Na co muszę zwrócić tam uwagę, aby to działało tak jak należy ?
Trochę przerabiania będzie.
- w onclickach przycisków zostawiasz stary kod do pętli
while( ( err = Pa_IsStreamActive( stream ) ) == 1 )
- w timerze (
wxTimer
) dajesz:
if(stream != nullptr)
{
if( Pa_IsStreamActive( stream ) == 1 ) return;
Pa_CloseStream( stream );
stream = nullptr;
}
Timer ustawiasz na jakieś 100ms i, co oczywiste, startujesz.
3. stream
musi być ustawiony w konstruktorze na null.
4. w miejscu, gdzie przydzielasz bufor popraw na:
if(data.recordedSamples != nullptr)
free(data.recordedSamples);
data.recordedSamples = (SAMPLE *) malloc( numBytes );
Oczywiście data.recordedSamples
musi być ustawione na null w konstruktorze.
To tak z grubsza, resztę sobie sam wydumaj.
@ up
wydaje mi się, że tak robię, a dalej podczas nagrywania nic nie mogę zrobić( a chcę wcisnąć stop)
(dodatkowo zauważyłem, że tylko podczas pierwszego nagrywania, po naciśnieciu start (nagrywanie trwa o 10 sekund dłużej niż nastawiam, te pierwsze 10 sekund są jakby użył Pa_Sleep(10000) przy kolejnym nacisnięciu już tego nie ma, hmm)
Start wygląda tak
data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE;
data.frameIndex = 0;
numSamples = totalFrames * NUM_CHANNELS;
numBytes = numSamples * sizeof(SAMPLE);
if( data.recordedSamples != nullptr )
free(data.recordedSamples);
data.recordedSamples = (SAMPLE *) malloc( numBytes );
for( i=0; i<numSamples; i++ ) data.recordedSamples[i] = 0;
err = Pa_Initialize();
if( err != paNoError ) goto done;
inputParameters.device = Pa_GetDefaultInputDevice();
if (inputParameters.device == paNoDevice) {
goto done;
}
inputParameters.channelCount = 2;
inputParameters.sampleFormat = PA_SAMPLE_TYPE;
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL;
/* Record some audio. -------------------------------------------- */
err = Pa_OpenStream(
&stream,
&inputParameters,
NULL, /* &outputParameters, */
SAMPLE_RATE,
FRAMES_PER_BUFFER,
paClipOff, /* we won't output out of range samples so don't bother clipping them */
recordCallback,
&data );
if( err != paNoError ) goto done;
err = Pa_StartStream( stream );
if( err != paNoError ) goto done;
while( ( err = Pa_IsStreamActive( stream ) ) == 1 )
done:
;
Wywal tę pętlę na końcu (może źle się wyraziłem w pierwszym punkcie - zostawiasz wszystko przed pętlą while
).
Wywołanie Pa_Initialize
przenieś do konstruktora, a Pa_Terminate
do destruktora.
Z tym goto
też przydałoby się coś zrobić. Wywal etykietę done
i zrób tak:
inputParameters.device = Pa_GetDefaultInputDevice();
if (inputParameters.device == paNoDevice) return;
err = Pa_OpenStream(...);
if( err != paNoError ) return;
err = Pa_StartStream( ... );
if( err != paNoError )
{
Pa_CloseStream( stream );
stream = nullptr;
}
Dobrze byłoby zrobić jakieś powiadamianie o błędzie (messagebox + Pa_GetErrorText
), ale to już sam sobie pokombinuj.
jeee śmiga jak ta lala ;))
A z tym 10 sekundowym, to przez nie ustawienie stream
w konstruktorze