2011-10-15 20 views
13

Qtフォーラムにこの質問を掲載しましたが、答えはありませんでした。だから私はここにそれを掲示している。Qt - 音を同時に録音して再生する方法

Qtで同時にサウンドを録音して再生する方法はありますか?マイクからサウンドを録音したいと同時に、スピーカー/ヘッドフォンで再生したいと思います。

Qtでこれを行う方法はありますか?または、他のライブラリを使用する必要がありますか?

解決策がクロスプラットフォーム(Windows、Linux、Macをカバーする必要がある)の場合は、素晴らしいことでしょう。それが不可能な場合は、Linuxの解決策があります。

私は途中でQt 4.7を使用しています。

編集

私の最新の実装はhereを与えています。 QIODeviceのサブクラスを作成し、循環バッファで読み書きを行えるようにwriteDatareadDataメソッドを再実装しました。私はこれをthis suggestionとして行っています。

オーディオデータはIを適用して十分に速い速度

でオーディオ装置に供給されていない - QAudioOutputインスタンスUnderrun Errorに面しているため、このコードはまたthis documentationに従って意味し、動作しません一時的にこの問題を解決するためのハックです。 outputStateChangedメソッドでは、出力の状態がIDLEに変更されているかどうかを確認していますが、それがある場合は、共通バッファを指定してstart()メソッドを再度呼び出しています。私はこれを恒久的な解決策として使用したくないのです。なぜなら、それは本当にハッキリと感じるからです。そして、その理由を適切に調査せずにエラーを飲み込んでいるからです。

この問題を解決するにはどうすればよいですか?

私はPhononを使用してこれを解決しようとしましたが、このモジュールの十分な知識がないために失敗しました。

+0

@BrianRoach:@BrianRoach:私は始める方法が見つからないので、何も試していません。 QAudioInputを使用して音を鳴らすことができますが、私はQAudioOutputを使用することができますが、これらは両方ともファイル上で動作します。つまり、QAudioInputは入力をファイルに格納し、QAudioOutputはそのファイルから音を再生します。このアプローチは、全二重のシナリオではうまくいかないでしょうか?私は以前の答えのいくつかを見つけましたが、それらのすべてはかなり古く、openAL、portAudioなどの他のライブラリを使用することを提案していますQtライブラリを使用するソリューションがあるかどうかを知りたかったのです。 –

答えて

9

私はQtのと非常に経験豊富ではないんだけど、私はメディアを処理していますので、私を許して私の答えがあまり具体的ではないが、より一般的な視点からあなたの問題に対処していれば。

私はあなたのコードを見ましたが、私は一般的にあなたの考えはうまくいくと思います。でも、私はいくつかの問題を参照してください。

  • writeData方法は、バッファフル状態を処理するために準備されていないようです。循環バッファがいっぱいになると古いデータが上書きされ、変数currentBufferLengthが間違ってインクリメントされ続けます。私はここで正しいことは、失われたデータをスキップし、currentBufferLengthがバッファサイズを超えて成長するのを防ぐためにreadPositionを更新することだと思います。

  • あなたはほぼ同じ時間にライターとリーダーの両方を開始しています。代わりに、ライターを起動して循環バッファーを準備し、リーダーを起動する必要があります。 0レイテンシで録音して再生することはできません。少なくともあなたの待ち時間は個々のバッファ書き込みのサイズになりますが、実際には、ちょっとした問題を避けるために、いくつかのバッファで先行する必要があります。

  • リーダーとライターを別々にデバッグする必要があります。ライターだけをセットアップし、循環バッファが一定の間隔で書き込まれることを確認します(最初に上で提案したようにオーバーフロー状態を修正します)。デバッグするには、バッファをファイルにダンプしてからオーディオプレーヤー(Audacityなど)でファイルをチェックするか、printfデバッグを使用して常にデータを取得することができます。次に、読者だけと似たようなことをする。

  • 最終的な考え。 readDatawriteDataメソッドを呼び出すコードはおそらく他のスレッド、おそらく2つの異なるスレッド、1つはリーダー用、もう1つはライター用です。私の推測が正しいとすれば、循環構造に大きな問題があります。競合条件がない場合は、読み書き位置とサイズを決定する変数へのアクセスを保護する必要があります。

幸運。

+0

Miguelに感謝します。あなたの答えはかなり有益です。私はこれらを覚えておきます:-)。 –

1

あなたはQAudioInputを起動してからPhonon :: MediaSourceを作成するために使用するQIOStreamを使用します。その後、そのPhonon :: MediaSourceとPhonon :: AudioOutputオブジェクトの間にパスを作成します。 Phonon::AudioOutputPhonon::MediaSourceの詳細については、チェックアウトのドキュメントをご覧ください。

+0

いいえ、私はそれを試していない、実際には私はそのような方法が存在する(私はQtの初心者です)知らなかった。このアプローチを試してみましょう。 –

+0

これらのクラスのどれもPhononの一部ではないので、どのようにしてこれら2つのクラスの間にパスを作成できますかわかりません。 –

+0

@SayemAhmed良い点。私はあなたの質問に答えるために私の応答を編集しました。 –

2

コメントに記載されているクラスを使用する際に問題が発生する理由はありません。どちらもファイルを使用するだけではありません。

QIODeviceQAudioInputstart()メソッドから返されるとQAudioOutputstart()方法にそれを与える取る:

QIODevice *myDevice = myQAudioInput->start(); 
myQAudioOutput->start(myDevice); 
+0

私はあなたのアプローチを試みました。最初はうまくいくように見えましたが、しばらくして出力状態はアイドル状態になります。これはおそらく同期の問題や何かのために、私は知らない。私はあなたが一見を持つことができるように編集で自分のコードを投稿しています。 –

+0

私は何が起こっているのか把握しています。 'audioOutput'オブジェクトがアンダーランエラーに直面しています。 –

+0

私は再び何か問題を抱えています。編集をご覧ください。 –

2

スタートこの

m_output= m_audioOutput->start(); 
    m_input = m_audioInput->start(); 
    connect(m_input, SIGNAL(readyRead()), SLOT(readMore())); 

のような入力と出力デバイスとreadMore(中出力に入力サンプルを書き込み)

m_output->write(outdata, len); 

以上のため、この記事をご覧ください。
このサンプルアプリケーションはQtの中で作成されたマイクから録音すると同時に音声を再生します http://www.codeproject.com/Articles/421287/Cross-Platform-Microphone-Audio-Processing-Utility以下

2

は、マイクをオーディオ入力を読み取るためにQT5で書かれたコードであり、そして64K循環バッファにそれを配置します。バッファにデータがあれば、そのデータをPCのスピーカーであるオーディオ出力に書き込みます。これは、サウンドデバイスに慣れ親しむための出発点になるはずの裸のコードです。ここで、サウンドの入出力は1つのオブジェクトにあることに注意してください。これはバッファの問題を引き起こす可能性があります。これ以上来るには、入力と出力のために別々のオブジェクトを作成します。 プログラムは2つのファイルにあり、最初はqtプロファイル(.pro)で、2番目はmain.cppファイルです。

#AudioEcho.pro file for QT5.2.1 

QT  += core 
QT  -= gui 
QT += multimedia widgets 
TARGET = AudioEcho 
CONFIG += console 
CONFIG -= app_bundle 
TEMPLATE = app 
SOURCES += main.cpp 


//main.cpp file 
#include <QDebug> 
#include <QIODevice> 
#include <QAudioInput> 
#include <QAudioOutput> 
#include <QCoreApplication> 

class myAudio :public QIODevice 
{ 
    // Q_OBJECT 

public: 
    QAudioOutput *audioOut; 
    QAudioInput *audioIn; 

    myAudio(); 
    ~myAudio(){} 
    void fillBuffer(); 
    QAudioFormat formatIn,formatOut; 
    QByteArray buff; 
    char *pbuff; 
    quint64 RXbuff; 
    quint64 buffPtr; 
protected: 
    qint64 readData(char *data, qint64 maxlen); 
    qint64 writeData(const char *data, qint64 len); 
    qint64 bytesAvailable() const; 
}; 

#define SAMPLE_RATE 22050 
#define CHANNELS 1 
#define SAMPLE_SIZE 16 
#define SAMPLE_TYPE SignedInt 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 
    myAudio *m= new myAudio(); 
    return a.exec(); 
} 
myAudio::myAudio() 
    { 
    formatIn.setSampleRate(SAMPLE_RATE); 
    formatIn.setChannelCount(CHANNELS); 
    formatIn.setSampleSize(SAMPLE_SIZE); 
    formatIn.setCodec("audio/pcm"); 
    formatIn.setByteOrder(QAudioFormat::LittleEndian); 
    formatIn.setSampleType(QAudioFormat::SAMPLE_TYPE); 

    formatOut.setSampleRate(SAMPLE_RATE); 
    formatOut.setChannelCount(CHANNELS); 
    formatOut.setSampleSize(SAMPLE_SIZE); 
    formatOut.setCodec("audio/pcm"); 
    formatOut.setByteOrder(QAudioFormat::LittleEndian); 
    formatOut.setSampleType(QAudioFormat::SAMPLE_TYPE); 

//print out the output device setup parameters 
    QAudioDeviceInfo   deviceOut(QAudioDeviceInfo::availableDevices(QAudio::AudioOutput).at(0));  //select output device 0 
    qDebug()<<"Selected Output device ="<<deviceOut.deviceName(); 

//print out the input device setup parameters 
    QAudioDeviceInfo  deviceIn(QAudioDeviceInfo::availableDevices(QAudio::AudioInput).at(0));  //select output device 0 
    qDebug()<<"Selected input device ="<<deviceIn.deviceName(); 

//configure device 
    audioOut = new QAudioOutput(deviceOut,formatOut,0); 
    audioIn = new QAudioInput (deviceIn, formatIn,0); 

//print out the device specifications 
    foreach(const QAudioDeviceInfo &deviceInfo,  QAudioDeviceInfo::availableDevices(QAudio::AudioInput)) 
      { 
      qDebug() << "\nSuported Input devices"; 
      qDebug() << "\nDevice name: "    << deviceInfo.deviceName(); 
      qDebug() << "Supported channel count: " << deviceInfo.supportedChannelCounts(); 
      qDebug() << "Supported Codec: "   << deviceInfo.supportedCodecs(); 
      qDebug() << "Supported byte order: "  << deviceInfo.supportedByteOrders(); 
      qDebug() << "Supported Sample Rate: "  << deviceInfo.supportedSampleRates(); 
      qDebug() << "Supported Sample Size: "  << deviceInfo.supportedSampleSizes(); 
      qDebug() << "Supported Sample Type: "  << deviceInfo.supportedSampleTypes(); 
      qDebug() << "Preferred Device settings:" << deviceInfo.preferredFormat(); 
      } 
    foreach(const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) 
     { 
     qDebug() << "\nSuported output devices"; 
     qDebug() << "Device name: "    << deviceInfo.deviceName(); 
     qDebug() << "Supported channel count: " << deviceInfo.supportedChannelCounts(); 
     qDebug() << "Supported Codec: "   << deviceInfo.supportedCodecs(); 
     qDebug() << "Supported byte order: "  << deviceInfo.supportedByteOrders(); 
     qDebug() << "Supported Sample Rate: "  << deviceInfo.supportedSampleRates(); 
     qDebug() << "Supported Sample Size: "  << deviceInfo.supportedSampleSizes(); 
     qDebug() << "Supported Sample Type: "  << deviceInfo.supportedSampleTypes(); 
     qDebug() << "Preferred Device settings:" << deviceInfo.preferredFormat(); 
     } 

     buff.resize(0x10000); //create a rx buffer 

     pbuff=buff.data();  //get the buff address; 
     RXbuff=0;    //set RX buffer pointer 

     qDebug()<<"File open"<<open(QIODevice::ReadWrite); 
     qDebug()<<"is device Sequential="<<isSequential(); 
     audioIn->start(this); //start reading device 

     audioOut->setVolume(0.5); //volume 0 to 1.0 
     audioOut->start(this); //start writing to device 
} 

//QIODevice Class (Protected Functions)This function is called by QIODevice. 
//send to output(Speaker) 
qint64 myAudio::readData(char *data, qint64 len) 
{ 
static quint64 TXbuff=0; 
qint64 total = 0; 
while (len > total && RXbuff>TXbuff)//write and synchonise buffers 
     { 
     //write data to speaker 
     memcpy(&data[total],&pbuff[TXbuff%0x10000],2); //copy 2 Bytes 
     TXbuff+=2; //point to next buffer 16 bit location 
     total+=2; 
     } 
return total; //the reset interval 
} 


//audio input (from Microphone) 
qint64 myAudio::writeData(const char *data, qint64 len) 
{ 
int total=0; 
while (len > total) 
     { 
     memcpy(&pbuff[RXbuff%0x10000],&data[total], 2); //write 2Bytes into circular buffer(64K) 
     RXbuff+=2; //next 16bit buffer location 
     total+=2; //next data location 
     } 
return (total); //return total number of bytes received 
} 

qint64 myAudio::bytesAvailable() const{return 0;} 
関連する問題