2011-10-15 4 views
13

나는이 질문을 Qt 포럼에 올렸지 만 대답이 없습니다. 그것이 내가 여기에 게시하는 이유입니다.Qt - 동시에 소리를 녹음하고 재생하는 방법

Qt에서 동시에 사운드를 녹음하고 재생할 수있는 방법이 있는지 알고 싶습니다. 마이크에서 소리를 녹음하고 동시에 스피커/헤드폰에서 소리를 내고 싶습니다.

Qt에서 이것을 수행 할 수있는 방법이 있습니까? 아니면 다른 라이브러리를 사용해야합니까?

솔루션이 크로스 플랫폼 (Windows, Linux 및 Mac을 커버해야 함)이면 좋을 것입니다. 그것이 가능하지 않다면, 리눅스 해결책은 할 것입니다.

나는 그런데 Qt 4.7을 사용하고 있습니다.

내 최신 구현이 here 주어집니다

편집. QIODevice의 하위 클래스를 만들고 writeDatareadData 메서드를 다시 구현하여 순환 버퍼로 읽기 및 쓰기를 수행 할 수 있도록했습니다. 나는 this suggestion에 따라 이것을했다.

가 는

오디오 데이터가 충분히 빠른 속도로 오디오 장치에 공급되지 않는

I 적용한 - QAudioOutput 인스턴스 this documentation에 따른 의미 Underrun Error 대향 때문에 코드는 작동하지 않는다 일시적으로이 문제를 해결하기위한 해킹. outputStateChanged 메서드에서 출력 상태가 IDLE으로 변경되었는지 확인하고 있는데 있으면 공용 버퍼를 지정하여 start() 메서드를 다시 호출합니다. 나는 이것을 정말로 영구적 인 해결책으로 사용하고 싶지 않습니다. 왜냐하면 그것은 정말로 해키 한 느낌이 들며 그 이유를 제대로 조사하지 않고 오류를 삼키기 때문입니다.

이 문제를 해결하려면 어떻게해야합니까?

또한이 모듈을 충분히 이해하지 못 했으므로 Phonon을 사용하여이 문제를 해결하려고했지만 실패했습니다.

+0

@BrianRoach : @BrianRoach : 시작 방법을 찾을 수 없어서 아무 것도 시도하지 않았습니다. 나는 사운드 입력 usinq QAudioInput을 취할 수 있고 QAudioOutput을 사용할 수있는 사운드를 재생할 수 있다는 것을 알고있다.하지만이 둘 모두는 파일에서 작동한다. 즉, QAudioInput은 입력을 파일에 저장하고 QAudioOutput은 그 파일에서 사운드를 재생한다. 이 접근법은 전이중 시나리오에서 반드시 작동하지 않을 것입니다. 이전 답변 중 일부를 찾았지만 모두 꽤 오래되었고 openAL, portAudio 등과 같은 다른 라이브러리를 사용하도록 제안했습니다.Qt 라이브러리를 사용하는 솔루션이 있는지 알고 싶었습니다. –

답변

9

,하지만 난 미디어 처리와 함께 오전, 그래서 용서 내 대답이 매우 구체적이지는 않지만보다 일반적인 관점에서 문제를 다루는 경우.

코드를 살펴 보았을 때 일반적으로 아이디어가 효과적이라고 생각합니다.그래도 몇 가지 문제를 참조하십시오

  • writeData 방법은 버퍼 전체 조건을 처리 할 준비하지 않는 것 같습니다. 순환 버퍼가 채워지면 이전 데이터를 덮어 쓰게되고 currentBufferLength 변수가 계속 잘못 증가합니다. 제 생각에는 여기에서해야 할 올바른 일은 손실 된 데이터를 건너 뛰고 currentBufferLength이 버퍼 크기를 지나서 커지지 않도록하기 위해 readPosition을 업데이트하는 것입니다.

  • 당신은 거의 동시에 같은 시간에 작가와 독자를 시작하고 있습니다. 대신에 작가를 시작하고 순환 버퍼를 프라임 한 다음 리더를 시작해야합니다. 0 대기 시간으로는 녹음하고 재생할 수 없습니다. 최소한 지연 시간은 개별 버퍼 쓰기 크기 일 수 있지만 실제로는 딸꾹질을 피하기 위해 작성자에게 몇 개의 버퍼가 있어야합니다.

  • 리더와 라이터를 별도로 디버깅해야합니다. 라이터 만 설정하고 순환 버퍼가 일정한 간격으로 기록되는지 확인하십시오 (먼저 위에서 제안한 오버플로 조건을 수정하십시오). 디버깅하려면 버퍼를 파일로 덤프 한 다음 오디오 플레이어 (예 : Audacity)에서 파일을 검사하거나 printf 디버깅을 사용하여 지속적으로 데이터를 가져올 수 있습니다. 그런 다음 독자와 비슷한 것을하십시오.

  • 최종 생각. readDatawriteData 메서드를 호출하는 코드는 다른 스레드, 아마도 두 개의 다른 스레드에서 실행 중일 수 있습니다. 하나는 판독기 용이고 다른 하나는 작성기 용입니다. 내 추측이 맞다면 원형 구조에 큰 문제가 있습니다. 읽기 및 쓰기 위치와 크기를 결정하는 변수에 대한 액세스를 보호해야합니다. 그렇지 않으면 경쟁 조건이 발생합니다.

행운을 빕니다.

+0

Miguel에게 감사드립니다. 귀하의 답변은 매우 유익합니다. 나는 이것을 염두에 둘 것이다 :-). –

1

QAudioInput을 시작한 후 가져온 QIOStream을 가져 와서 Phonon :: MediaSource를 만드는 데 사용합니다. 그런 다음 Phonon :: MediaSource와 Phonon :: AudioOutput 객체 사이에 경로를 만듭니다. Phonon::AudioOutputPhonon::MediaSource에 대한 자세한 내용은 체크 아웃 문서를 참조하십시오.

+0

아니, 나는 그것을 시도하지 않았다, 실제로 나는 그런 방법이 존재했다는 것을 몰랐다 (나는 Qt에서 초보자이다). 이 접근 방식을 시도하겠습니다. –

+0

두 클래스 사이에 경로를 만들 수있는 방법이 무엇인지 모르겠다. 두 클래스 중 어느 것도 Phonon의 일부가 아니기 때문에. –

+0

@SayemAhmed 좋은 지적. 귀하의 질문에 대한 답변을 편집했습니다. –

2

의견에 언급 된 클래스를 사용하는 데 문제가있는 이유가 표시되지 않습니다. 어느 쪽도 파일을 사용하는 것만으로 제한되지 않습니다.

QIODeviceQAudioInputstart() 메서드에서 반환 받아 QAudioOutputstart() 방법을 제공 : 나는 매우 Qt를 경험하고 있지 않다

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

나는 당신의 접근 방식을 시도했다. 처음에는 작동하는 것처럼 보였지만, 얼마 후 출력 상태는 유휴 상태가됩니다. 그것은 아마도 동기화 문제 또는 다른 이유로, 나도 몰라. 당신이 볼 수 있도록 편집 코드를 게시하고 있습니다. –

+0

나는 무슨 일이 일어나고 있는지 알아 냈습니다. 'audioOutput' 객체가 언더런 오류를 직면하고 있습니다. –

+0

다시 문제가 있습니다. 편집을 참조하십시오. –

2

m_output->write(outdata, len); 

이상이 문서를보고하십시오) (이

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

처럼 입력 및 출력 장치를 시작하고 readMore 출력에 대한 입력 샘플을 쓰기

.
이 샘플 애플리케이션이 음성을 마이크로폰으로부터 기록하고 재생할 Qt는에서 생성 동시에 아래 http://www.codeproject.com/Articles/421287/Cross-Platform-Microphone-Audio-Processing-Utility

2

는 64K 원형 버퍼에 음성 입력 마이크로폰, 장소 읽어 QT5에 기록 된 코드이다. 버퍼에 데이터가 있으면 PC의 스피커 인 오디오 출력에 데이터를 씁니다. 이것은 사운드 장치에 익숙해지기위한 좋은 출발점이 될 수있는 베어 본 코드입니다. 여기서 사운드 입출력은 하나의 객체에 있으므로 버퍼 문제가 발생할 수 있습니다. 끝내려면 입력과 출력을위한 별도의 객체를 만듭니다. 프로그램은 두 개의 파일로되어 있는데, 처음에는 qt 프로파일 (.pro)이고 두 번째 파일은 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;} 
관련 문제