2017-12-27 23 views
1

私はC++プロジェクトで、独自のC++ APIを使用して、マイクアレイシステムから生のオーディオを読み込み/処理/再生しています。 QTを使ってソフトウェアをプログラミングしています。QT C++ QAudioOutputによるリアルタイムストリーミング

投稿者Real Time Streaming With QAudioOutput (QT)については、処理するのに約1000ms(1秒)かかる関数呼び出しからRaw Audioデータが得られた場合は、フォローアップを行い、何をすべきかアドバイスを求めたかったですか?リアルタイムのオーディオ再生をどうすれば達成できますか?

QIODevice :: QAudioFormat-> start()に書き込むときに読み込んでいたので、処理に約1秒かかりました。バッファのアンダーラン/オーバーランを防ぐためには、一定の期間のバイトを使用することをお勧めします。 http://cell0907.blogspot.sg/2012/10/qt-audio-output.html

QByteArrayとQDataStreamをセットアップして、関数呼び出しから受け取ったデータをストリーミングしました。

  • API CcmXXX()
  • は、マイクロホンアレイからデータを読み取って32ビット整数、32ビット整数、24ビットの分解能、8ビットLSBパディングゼロの
  • の配列を返します。
  • ブロックサイズ(1024サンプルに設定)x 40マイクロフォン
  • 各チャンクは、書き込まれたバイト数がピリオド・サイズ/フリー・バイト量に近づくまで約1ブロックを書き込みます。

テスト済み:約50ミリ秒の通知に私のスロットを接続して、1ピリオド分のバイトを書き込みます。循環バッファー形式のQByteArray。読み込み/書き込み部分にmutexロック/アンロックを追加しました。

結果:実際に再生されたオーディオの非常に短い分割ms、ジッタの多いサウンドおよび録音されていないサウンドが多数あります。

私のコードを改善する方法についてのフィードバックを提供してください。

void MainWindow::slot_writedata(){ 
    QMutex mutex; 
    mutex.lock(); 
    read_frames(); 
    mutex.unlock(); 
} 

void MainWindow::init_audio_output(){ 
    m_bytearray.resize(65536); 
    mstream = new QDataStream(&m_bytearray,QIODevice::ReadWrite); 
    mstream->setByteOrder(QDataStream::LittleEndian); 
    audio = new QAudioOutput(m_device,m_format,this); 
    audio->setBufferSize(131072); 
    audio->setNotifyInterval(50); 
    m_audiodevice = audio->start(); 
    connect(audio,SIGNAL(notify()),this,SLOT(slot_writedata())); 
    read_frames(); 
} 

スロット

QAudioFormat

void MainWindow::init_audio_format(){ 
      m_format.setSampleRate(48000); //(8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 192000 
      m_format.setByteOrder(QAudioFormat::LittleEndian); 
      m_format.setChannelCount(1); 
      m_format.setCodec("audio/pcm"); 
      m_format.setSampleSize(32); //(8, 16, 24, 32, 48, 64) 
      m_format.setSampleType(QAudioFormat::SignedInt); //(SignedInt, UnSignedInt, Float) 

      m_device = QAudioDeviceInfo::defaultOutputDevice(); 
      QAudioDeviceInfo info(m_device); 
      if (!info.isFormatSupported(m_format)) { 
       qWarning() << "Raw audio format not supported by backend, cannot play audio."; 
       return; 
      } 
} 

イニシャライズオーディオの設定とQByteArray /データストリーム0

フレーム読みするには、次のフレームを書き込むには

void MainWindow::read_frames(){ 
     qint32* buffer; 
     int frameSize, byteCount=0; 
     DWORD tdFrames, fdFrames; 
     float fvalue = 0; 
     qint32 q32value; 

     frameSize = 40 * mBlockSize; //40 mics 
     buffer = new int[frameSize]; 
     int periodBytes = audio->periodSize(); 
     int freeBytes = audio->bytesFree(); 
     int chunks = qMin(periodBytes/mBlockSize,freeBytes/mBlockSize); 

     CcmStartInput(); 

     while(chunks){ 
      CcmReadFrames(buffer,NULL,frameSize,0,&tdFrames,&fdFrames,NULL,CCM_WAIT); 
      if(tdFrames==0){ 
       break; 
      } 
      int diffBytes = periodBytes - byteCount; 

      if(diffBytes>=(int)sizeof(q32value)*mBlockSize){ 
       for(int x=0;x<mBlockSize;x++){ 
        q32value = (quint32)buffer[x]/256; 
        *mstream << (qint32)fvalue; 
        byteCount+=sizeof(q32value); 
       } 
      } 
      else{ 
       for(int x=0;x<(diffBytes/(int)sizeof(q32value));x++){ 
        q32value = (quint32)buffer[x]/256; 
        *mstream << (qint32) fvalue; 
        byteCount+=sizeof(q32value); 
       } 
      } 
      --chunks; 
     } 
     CcmStopInput(); 
     mPosEnd = mPos + byteCount; 
     write_frames(); 
     mPos += byteCount; 
     if(mPos >= m_bytearray.length()){ 
       mPos = 0; 
       mstream->device()->seek(0); //change mstream pointer back to bytearray start 
     } 
    } 

を:Qtの中

void MainWindow::write_frames() 
{ 
    int len = m_bytearray.length() - mPos; 
    int bytesWritten = mPosEnd - mPos; 

    if(len>=audio->periodSize()){ 
     m_audiodevice->write(m_bytearray.data()+mPos, bytesWritten); 
    } 
    else{ 

     w_data.replace(0,qAbs(len),m_bytearray.data()+mPos); 
     w_data.replace(qAbs(len),audio->periodSize()-abs(len),m_bytearray.data()); 
     m_audiodevice->write(w_data.data(),audio->periodSize()); 
    } 
} 

答えて

3

オーディオのサポートは、実際には非常に初歩的です。目標は、実現可能な最低限の実装と保守コストでメディアを再生することです。状況は特に窓では悪いです。私は古代のMME APIが依然としてオーディオ再生に使用されていると思います。

その結果、QtオーディオAPIはリアルタイムから非常に遠く、このようなアプリケーションには特に適していません。私はportaudioやrtaudioを使用することをお勧めします。これは、QtスタイルのIOデバイスをそのまま使えるようにすることができます。これにより、パフォーマンスの優れたプラットフォームのオーディオAPIへのアクセスが可能になり、非常に短い待ち時間で再生パフォーマンスが向上します。

+0

はい、絶対に。ほとんどすべてのビデオ/オーディオはQtに関連していますが、QMediaPlayerでもFFmpegのようなものを使用するのではなく、OSの再生機能(!!!)を使用していても、あらゆる種類の問題につながります。特殊なライブラリ(GUIのためにQtを混ぜたもの)を使う方が良いでしょう。 – TheSHEEEP

+0

コメントと提案いただきありがとうございます。私はそれらの図書館を試してみます!乾杯! – MrS05

+0

dtechとTheSHEEEPこんにちは、他のAPIについてさらにお尋ねします。私はrtaudio APIを追加しようとしました。私はhttp://www.music.mcgill.ca/~gary/rtaudio/からファイルをダウンロードしました。私はその後、CMakeメイクファイルを作成してDLLを生成し、それからrtaudio DLLまたはlibファイルを生成するためにメイクファイルをMingw64メイクで実行する必要がありますか? – MrS05

関連する問題