Russian Qt Forum
Сентябрь 21, 2024, 10:37 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Qt (QThread) + OpenAL  (Прочитано 5703 раз)
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"); }
...
 

Заранее, очень признателен всем ответившим )
Записан
ритт
Гость
« Ответ #1 : Март 10, 2009, 23:43 »

уточнил бы хоть что именно не получается. а в идеале плюсом минимальный тестовый проектик прикрепил бы...
Записан
iamunix
Гость
« Ответ #2 : Март 11, 2009, 00:49 »

Так, сейчас постораюсь уточнить... =) 
Мне необходимо реализовать паузу при записи звука и проигрывании (что сложнее, на сколько я понимаю). Разработка ведется в Mac OS X, где данный пример "практически" работает, те записывает и воспроизводит звуковые данные, но, случается, и "вылетает"... сделал сборку в Win XP - запсь/воспроизведение работают как то... даже не через раз =( в Linux'e не собирал, решил сначала разобраться на данных сиситемах...

Таким образом, конечным результатом является создание потока, "умеющего" записывать и воспроизводить звуковые данные, с возможностью остановить (поставить на паузу) запись/воспроизведение, с любыми параметрами (mono8/mono16 и sampleRate = 8000, 11025, 16000, 22050, 44100, ... )

Форумчане, попробуйте, пожалуйста, скомпилировать у себя. Хочется верить, что, благодаря Вашей помощи, данное приложение будет реализованно и корректно работать в любой системе.

Константин, Вам отдельное спасибо, как первому проявившему интерес к данной теме )
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.318 секунд. Запросов: 20.