2011-10-15 14 views
13

मैंने इस प्रश्न को क्यूटी मंच पर पोस्ट किया, लेकिन कोई जवाब नहीं मिला। यही कारण है कि मैं इसे यहां पोस्ट कर रहा हूं।क्यूटी - एक साथ ध्वनि रिकॉर्ड और चलाने के लिए कैसे

मैं जानना चाहता था कि क्यूटी में एक ही समय में ध्वनि रिकॉर्ड करने और चलाने का कोई तरीका है। मैं एक माइक्रोफोन से ध्वनि रिकॉर्ड करना चाहता हूं और साथ ही मैं इसे स्पीकर/हेडफोन में खेलना चाहता हूं।

क्या क्यूटी में ऐसा करने का कोई तरीका है? या मुझे किसी अन्य पुस्तकालय का उपयोग करने की ज़रूरत है?

यह समाधान अच्छा होगा अगर समाधान क्रॉस-प्लेटफार्म है (मुझे विंडोज़, लिनक्स और मैक को कवर करने की आवश्यकता है)। यदि यह संभव नहीं है, तो एक लिनक्स समाधान करेगा।

मैं क्यूटी 4.7 का उपयोग कर रहा हूं।

संपादित

मेरे नवीनतम कार्यान्वयन here दिया जाता है। मैंने QIODevice का उप-वर्ग बनाया है और इसके writeData और readData विधि को फिर से कार्यान्वित किया है ताकि एक परिपत्र बफर के साथ पढ़ना और लिखना किया जा सके। मैंने इसे this suggestion के अनुसार किया है।

ऑडियो डेटा एक काफी तेजी से दर पर ऑडियो डिवाइस को खिलाया जा रहा नहीं है

मैं आवेदन किया है - यह कोड भी क्योंकि QAudioOutput उदाहरण Underrun Error का सामना कर रहा है, जो this documentation के अनुसार इसका मतलब है काम नहीं करता है अस्थायी रूप से इस समस्या को हल करने के लिए एक हैक। outputStateChanged विधि में, मैं यह देखने के लिए जांच कर रहा हूं कि आउटपुट की स्थिति IDLE में बदल गई है और यदि यह है, तो मैं आम बफर निर्दिष्ट करते हुए start() विधि को फिर से कॉल कर रहा हूं। मैं इसे स्थायी समाधान के रूप में उपयोग नहीं करना चाहता क्योंकि यह वास्तव में हैकी महसूस करता है और क्योंकि मैं इसके कारणों की उचित जांच किए बिना त्रुटि निगल रहा हूं।

इस समस्या को हल करने के लिए मुझे क्या करना चाहिए?

मैंने Phonon का उपयोग करके इसे हल करने का भी प्रयास किया लेकिन असफल रहा क्योंकि मेरे पास इस मॉड्यूल का पर्याप्त ज्ञान नहीं है।

+0

@ ब्रायनरोच: मैंने कुछ भी करने की कोशिश नहीं की है, क्योंकि मुझे शुरुआत करने का कोई तरीका नहीं मिला। मुझे पता है कि मैं ध्वनि इनपुट usinq QAudioInput ले सकता हूं और ध्वनि चलाने के लिए मैं QAudioOutput का उपयोग कर सकता हूं, लेकिन ये दोनों एक फ़ाइल पर काम करते हैं, जैसे QAudioInput फ़ाइल में इनपुट संग्रहीत करता है और फिर QAudioOutput उस फ़ाइल से ध्वनि चलाता है। यह दृष्टिकोण निश्चित रूप से पूर्ण डुप्लेक्स परिदृश्य में काम नहीं करेगा, है ना? मुझे पिछले कुछ जवाब मिल गए, लेकिन उनमें से सभी बहुत पुराने हैं और वे ओपनल, पोर्टऑडियो आदि जैसे अन्य पुस्तकालयों का उपयोग करने का सुझाव देते हैं।मैं जानना चाहता था कि कोई समाधान उपलब्ध है जो क्यूटी पुस्तकालयों का उपयोग करता है। –

उत्तर

9

मैं बहुत क्यूटी के साथ अनुभव नहीं कर रहा हूँ, लेकिन मैं मीडिया से निपटने के साथ हूँ, तो मुझे माफ कर दो अगर मेरा जवाब बहुत विशिष्ट नहीं है बल्कि इसके बजाय आपकी समस्या को अधिक सामान्य दृष्टिकोण से संबोधित करता है।

मैंने आपके कोड को देखा, और मुझे लगता है कि आम तौर पर आपके विचार को काम करना चाहिए।मैं हालांकि कुछ समस्याएं देखें:

  • writeData विधि एक बफर पूर्ण हालत को संभालने के लिए तैयार रहने की नहीं लगती। जब सर्कुलर बफर भरता है तो यह पुराने डेटा को ओवरराइट कर देगा, और currentBufferLength चर को बढ़ाने के लिए गलत तरीके से जारी रहेगा। मुझे लगता है कि यहां करने के लिए सही चीज readPosition को खोने वाले डेटा को छोड़ने के लिए, और बफर आकार के पहले से बढ़ने से currentBufferLength को रोकने के लिए है।

  • आप लेखक और पाठक दोनों को एक ही समय में शुरू कर रहे हैं। इसके बजाय, आपको लेखक को शुरू करना चाहिए और गोलाकार बफर का प्रमुख होना चाहिए, फिर पाठक शुरू करें। ध्यान रखें कि आप कभी भी शून्य विलंबता के साथ रिकॉर्ड और खेलने में सक्षम नहीं होंगे। कम से कम आपकी विलंबता एक व्यक्तिगत बफर लिखने का आकार होगी, लेकिन व्यावहारिक रूप से आपको शायद कुछ बफर द्वारा आगे बढ़ने के लिए लेखक की आवश्यकता होगी ताकि हिचकी से बच सकें।

  • आपको पाठक और लेखक को अलग से डिबग करना चाहिए। केवल लेखक को स्थापित करें और सत्यापित करें कि सर्कुलर बफर नियमित अंतराल पर लिखा जा रहा है (पहले ऊपर उल्लिखित ओवरफ्लो स्थिति को ठीक करें)। डीबग करने के लिए, आप बफर को फ़ाइल में डंप कर सकते हैं और फिर ऑडियो प्लेयर (ऑडैसिटी, उदाहरण के लिए) में फ़ाइल को चेक कर सकते हैं, या आप लगातार डेटा प्राप्त करने के लिए प्रिंटफ डिबगिंग का उपयोग कर सकते हैं। फिर केवल एक पाठक के साथ कुछ ऐसा ही करें।

  • अंतिम विचार। कोड जो आपके readData और writeData विधियों को कॉल करता है, शायद अन्य धागे, संभवतः दो अलग-अलग धागे, पाठक के लिए एक और लेखक के लिए एक अन्य पर चल रहा है। अगर मेरा अनुमान सही है, तो आपको अपनी परिपत्र संरचना के साथ एक बड़ी समस्या है। आपको उन चरों तक पहुंच की रक्षा करना है जो पढ़ने और लिखने की स्थिति और आकार निर्धारित करते हैं, यदि आपके पास दौड़ की स्थिति नहीं है।

शुभकामनाएं।

+0

धन्यवाद मिगुएल। आपका जवाब काफी जानकारीपूर्ण है। मैं इन्हें ध्यान में रखूंगा :-)। –

1

आप QIOStream लेते हैं जो आपको QAudioInput शुरू करने से मिलता है और इसे फोनन :: मीडियासोर्स बनाने के लिए उपयोग करता है। फिर आप उस फोनन :: मीडियासोर्स और फोनॉन :: ऑडियोऑटपुट ऑब्जेक्ट के बीच एक पथ बनाते हैं। अधिक जानकारी के लिए Phonon::AudioOutput और Phonon::MediaSource के लिए चेकआउट दस्तावेज़।

+0

नहीं, मैंने कोशिश नहीं की है, असल में मुझे नहीं पता था कि इस तरह का एक तरीका मौजूद है (मैं क्यूटी में एक नौसिखिया हूं)। मुझे इस दृष्टिकोण की कोशिश करने दो। –

+0

मुझे नहीं पता कि मैं इन दो वर्गों के बीच एक रास्ता कैसे बना सकता हूं, क्योंकि उनमें से कोई भी फोनन का हिस्सा नहीं है। –

+0

@ सैम अहमद अच्छा बिंदु। मैंने आपके प्रश्न को संबोधित करने के लिए अपनी प्रतिक्रिया संपादित की। –

2

मुझे नहीं पता कि आपकी टिप्पणी में वर्णित कक्षाओं का उपयोग करने में कोई समस्या क्यों होगी। न केवल फाइलों का उपयोग करने के लिए प्रतिबंधित हैं।

QIODeviceQAudioInput की start() विधि से लौटे ले लो और यह QAudioOutput की start() विधि के लिए दे:

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

मैंने आपके दृष्टिकोण की कोशिश की है। सबसे पहले यह काम करना प्रतीत होता था, लेकिन कुछ समय बाद, आउटपुट स्थिति निष्क्रिय हो जाती है। यह शायद सिंक्रनाइज़ेशन समस्या या कुछ और वजह से है, मुझे नहीं पता। मैं अपने कोड को संपादन में पोस्ट कर रहा हूं ताकि आप एक नज़र देख सकें। –

+0

मैंने यह पता लगाया है कि क्या हो रहा है। 'ऑडियोऑटपुट' ऑब्जेक्ट को अंडर्रुन त्रुटि का सामना करना पड़ रहा है। –

+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); 

कृपया अधिक के लिए इस लेख को देखो।
यह नमूना आवेदन क्यूटी में बनाई गई है माइक्रोफोन से रिकॉर्ड और ऑडियो खेलेंगे एक साथ http://www.codeproject.com/Articles/421287/Cross-Platform-Microphone-Audio-Processing-Utility

2

नीचे QT5 में लिखा ऑडियो इनपुट, माइक्रोफोन, और एक 64K परिपत्र बफर में यह स्थानों को पढ़ने के लिए कोड है। एक बार बफर के पास डेटा होने पर यह ऑडियो आउटपुट, पीसी पर स्पीकर को लिखता है। यह बेयर हड्डियों का कोड है जो ध्वनि डिवाइस से परिचित होने के लिए एक अच्छा प्रारंभिक बिंदु होना चाहिए। ध्यान दें, कि यहां ध्वनि इनपुट और आउटपुट एक ऑब्जेक्ट में हैं, यह बफर समस्याओं का कारण बन सकता है। आने के लिए इनपुट और आउटपुट के लिए एक अलग ऑब्जेक्ट बनाएं। प्रोग्राम दो फाइलों में है, पहला क्यूटी प्रोफाइल (.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;} 
संबंधित मुद्दे