Название: Qt (QThread) + OpenAL
Отправлено: iamunix от Март 10, 2009, 23:03
Всем привет! Пытаюсь реализовать полноценную запись/воспроизведение звука. Не получается =( Исходные тексты прилагаются, укажите, пожалуйста, на ошибки (как работы с потоками, так и с библиотекой OpenAL) и посоветуйте как реализовать паузу во время проигрывания звукового сигнала. файл threadal.h C++ (Qt) #ifndef THREADAL_H #define THREADAL_H #include <QThread> #include <QTimer> #include <QVector> #include <al.h> #include <alc.h> class threadAl : public QThread { Q_OBJECT; public: threadAl( qint32 s, qint16 b ); void startRecord( QVector<quint8> * pntr ); void startRecord( QVector<qint16> * pntr ); void record( ); void play( ); void playSound( QVector<quint8> * pntr ); void playSound( QVector<qint16> * pntr ); void pause( ); void stop( ); void run( ); //private slots: // void slotNextValueTimer( ); //signals : // void currentValueTimer( int ); private: volatile bool recordFlag, pauseFlag, playFlag; volatile bool mono8, mono16; qint32 samples; QVector<quint8> * dataPointer8; QVector<qint16> * dataPointer16; ALCdevice* pDev; int bufferSize; QTimer * timer; unsigned int valueTimer; }; #endif // THREADAL_H
файл threadal.cpp C++ (Qt) #include "threadal.h" threadAl::threadAl( qint32 s, qint16 b ) { samples = s; if( b == 8 ) { mono8 = true; mono16 = false; } else { //if( b == 16 ) { mono8 = false; mono16 = true; } recordFlag = pauseFlag = playFlag = false; dataPointer8 = 0; dataPointer16 = 0; bufferSize=4096; valueTimer = 0; // timer = new QTimer; // connect( timer, SIGNAL(timeout()), // this, SLOT(slotNextValueTimer()) ); } void threadAl::record() { // RECORDING IN threadAl // timer->start(1000); // if( pauseFlag ) // timer->stop(); if( pDev == 0 ) { recordFlag = false; } else { alcCaptureStart(pDev); } quint8 iTotalSamplesRecorded8 = 0; qint16 iTotalSamplesRecorded16 = 0; ALCint samples_recorded; quint8 buffer8[ bufferSize/2 ]; qint16 buffer16[ bufferSize/2 ]; while( recordFlag == true ) { if( pauseFlag != true ) { if( mono8 ) { for(int i=0; i<bufferSize/2; i++) { buffer8[i]=0; } } else if( mono16 ) { for(int i=0; i<bufferSize/2; i++) { buffer16[i]=0; } } alcGetIntegerv(pDev, ALC_CAPTURE_SAMPLES, 1, &samples_recorded); while( samples_recorded < bufferSize/2 ) { alcGetIntegerv( pDev, ALC_CAPTURE_SAMPLES, 1, &samples_recorded ); } if( mono8 ) { alcCaptureSamples(pDev,buffer8+iTotalSamplesRecorded8,samples_recorded); for(int i=0; i<bufferSize/2; ++i ) { dataPointer8->push_back( buffer8[i] ); } } else if( mono16 ) { alcCaptureSamples(pDev,buffer16+iTotalSamplesRecorded16,samples_recorded); for(int i=0; i<bufferSize/2; ++i ) { dataPointer16->push_back( buffer16[i] ); } } } } } void threadAl::play() { // PLAYING IN threadAl int g_MainBufSzPlay; if( mono8 ) { g_MainBufSzPlay = dataPointer8->size(); } else if( mono16 ) { g_MainBufSzPlay = dataPointer16->size(); } // ALCdevice *pDev=alcOpenDevice(NULL); // ????????????????????????? pDev=alcOpenDevice(NULL); if(pDev){ ALCcontext *pCont=alcCreateContext(pDev,NULL); if(pCont){ // timer->start(1000); alcMakeContextCurrent(pCont); int numBuffers = g_MainBufSzPlay / (bufferSize) ; ALuint * buffer = new ALuint[numBuffers]; alGenBuffers(numBuffers, buffer); for( int k=0; k<numBuffers; ++k ) { if( mono8 ) { alBufferData(buffer[k], AL_FORMAT_MONO8, &((dataPointer8->constData())[bufferSize*k]), bufferSize, samples); } else { alBufferData(buffer[k], AL_FORMAT_MONO16, &((dataPointer16->constData())[bufferSize*k]), bufferSize, samples/2); } } ALuint source; alGenSources(1,&source); alSourceQueueBuffers( source, numBuffers, buffer ); alSourcePlay(source); ALint source_state; alGetSourcei(source,AL_SOURCE_STATE,&source_state); while(source_state==AL_PLAYING) { alGetSourcei(source,AL_SOURCE_STATE,&source_state); } alDeleteSources(1,&source); alDeleteBuffers(numBuffers,buffer); alcDestroyContext(pCont); delete[] buffer; } alcCloseDevice(pDev); } // timer->stop(); } void threadAl::run( ) { if( recordFlag == true ) { record(); } else if( playFlag == true ) { play(); } } void threadAl::playSound( QVector<quint8> * pntr ) { recordFlag = false; playFlag = true; dataPointer16 = 0; dataPointer8 = pntr; mono16 = false; mono8 = true; this->start(); } void threadAl::playSound( QVector<qint16> * pntr ) { recordFlag = false; playFlag = true; dataPointer8 = 0; dataPointer16 = pntr; mono8 = false; mono16 = true; this->start(); } void threadAl::startRecord( QVector<quint8> * pntr ) { recordFlag = true; playFlag = false; dataPointer16 = 0; dataPointer8 = pntr; dataPointer8->clear(); mono16 = false; mono8 = true; pDev=alcCaptureOpenDevice(NULL,samples,AL_FORMAT_MONO8,bufferSize); this->start(); } void threadAl::startRecord( QVector<qint16> * pntr ) { recordFlag = true; playFlag = false; dataPointer8 = 0; dataPointer16 = pntr; dataPointer16->clear(); mono8 = false; mono16 = true; pDev=alcCaptureOpenDevice(NULL,samples,AL_FORMAT_MONO16,bufferSize); this->start(); } void threadAl::stop( ) { recordFlag = pauseFlag = playFlag = false; alcCaptureStop(pDev); alcCaptureCloseDevice(pDev); // timer->stop(); emit(finished()); this->exit(0); } void threadAl::pause( ) { if(pauseFlag) { pauseFlag = false; } else { pauseFlag = true; /*timer->stop();*/ } } //void threadAl::slotNextValueTimer() { // emit currentValueTimer( ++valueTimer ); //}
фрагмент файла, в котором это все используется (mainwindow.cpp) C++ (Qt) ... void MainWindow::slotRecord() { recordFlag = true; if( !recordthreadAl ) { slotNew(); recordthreadAl = new threadAl( samples, bits ); if( mono8 ) { data8.clear(); recordthreadAl->startRecord( &data8 ); } else if( mono16 ) { data16.clear(); recordthreadAl->startRecord( &data16 ); } statusLabel->setText("Record active..."); slotParameters(); } else { slotStop(); } } void MainWindow::slotStop() { if( recordthreadAl && recordthreadAl->isRunning() ) { recordthreadAl->stop(); recordthreadAl->exit(0); recordthreadAl = 0; } statusLabel->setText("Record complete..."); slotParameters(); if( recordFlag ) { setData(); recordFlag=false; } recordthreadAl = 0; } void MainWindow::slotPlay() { if( recordthreadAl == 0 ) { recordthreadAl = new threadAl(samples, bits); connect( recordthreadAl, SIGNAL(finished()), this, SLOT(slotPlayFinish()) ); if( mono8 ) { recordthreadAl->playSound( &data8 ); } else if( mono16 ) { recordthreadAl->playSound( &data16 ); } statusLabel->setText( "Playing now..." ); slotParameters(); } else { slotStop(); slotPlay();} } void MainWindow::slotPause() { QMessageBox::information(this, "", "pause"); } ...
Заранее, очень признателен всем ответившим )
Название: Re: Qt (QThread) + OpenAL
Отправлено: ритт от Март 10, 2009, 23:43
уточнил бы хоть что именно не получается. а в идеале плюсом минимальный тестовый проектик прикрепил бы...
Название: Re: Qt (QThread) + OpenAL
Отправлено: iamunix от Март 11, 2009, 00:49
Так, сейчас постораюсь уточнить... =) Мне необходимо реализовать паузу при записи звука и проигрывании (что сложнее, на сколько я понимаю). Разработка ведется в Mac OS X, где данный пример "практически" работает, те записывает и воспроизводит звуковые данные, но, случается, и "вылетает"... сделал сборку в Win XP - запсь/воспроизведение работают как то... даже не через раз =( в Linux'e не собирал, решил сначала разобраться на данных сиситемах...
Таким образом, конечным результатом является создание потока, "умеющего" записывать и воспроизводить звуковые данные, с возможностью остановить (поставить на паузу) запись/воспроизведение, с любыми параметрами (mono8/mono16 и sampleRate = 8000, 11025, 16000, 22050, 44100, ... )
Форумчане, попробуйте, пожалуйста, скомпилировать у себя. Хочется верить, что, благодаря Вашей помощи, данное приложение будет реализованно и корректно работать в любой системе.
Константин, Вам отдельное спасибо, как первому проявившему интерес к данной теме )
|