Raw Audio Data Playback



  • Hi All,

    I have set the correct settings for my QAudioFormats according to my pc, however, after start() is executed, I don't hear anything.

    1. Does raw audio data need processing before it can be played? E.g, normalising the data to the various step levels?

    2. When selecting 'audio/pcm' does it mean, the default output device will be playing audio based on pcm?

    3. How could I also directly implement an int array as the source to audio->start( QIOdevice* device)?

    From: http://doc.qt.io/qt-5/qaudiooutput.html

    void MainWindow::doThat()
    {
            QString myFile = "brilliant_terrain.raw";
            sourceFile = new QFile();
            sourceFile->setFileName(myFile);
            sourceFile->open(QIODevice::ReadWrite);
    
            if (sourceFile->error() != QFile::NoError){
                qDebug()<<"Open FIle error";
            }
    
            QAudioFormat format;
            // Set up the format, eg.
            format.setSampleRate(44100);
            format.setChannelCount(1);
            format.setSampleSize(32);
            format.setCodec("audio/pcm");
            format.setByteOrder(QAudioFormat::LittleEndian);
            format.setSampleType(QAudioFormat::UnSignedInt);
    
            QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
            if (!info.isFormatSupported(format)) {
                qWarning() << "Raw audio format not supported by backend, cannot play audio.";
                return;
            }
    
    //        qDebug()<<info.supportedCodecs();
    //        qDebug()<<info.supportedByteOrders();
    //        qDebug()<<info.supportedChannelCounts();
    //        qDebug()<<info.supportedSampleRates();
    //        qDebug()<<info.supportedSampleSizes();
    
            audio = new QAudioOutput(format, this);
            connect(audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged(QAudio::State)));
            audio->start(sourceFile);
            qDebug()<<"Audio Start";
    
    
    }
    
    void MainWindow::handleStateChanged(QAudio::State newState)
    {
        switch (newState) {
            case QAudio::IdleState:
                // Finished playing (no more data)
                audio->stop();
                sourceFile->close();
                qDebug()<<"Finished Playing";
                delete audio;
                break;
    
            case QAudio::StoppedState:
                // Stopped for other reasons
                if (audio->error() != QAudio::NoError) {
                    // Error handling
                }
                break;
    
            default:
                // ... other cases as appropriate
                break;
        }
    }
    

  • Lifetime Qt Champion

    Hi,

    1. What kind of raw data is that ? What format ? What sample rate ? What sample size ?

    2. It means that you are going to feed it PCM data to play

    3. You have to use the second overload and you'll have to implement handling of your data to feed the device properly.



  • @scottnat said in Raw Audio Data Playback:

    How could I also directly implement an int array as the source to audio->start( QIOdevice* device)

    You must store the data in a QByteArray first (in the correct ByteOrder, here LittleEndian as in your example), then assign that QByteArray to a buffer, e.g. as follows:

    QByteArray*     m_data;
    
    // --> fill m_data with your PCM data
    
    QBuffer         m_buffer; //this is really a QIODevice
    
    m_buffer.setBuffer(m_data);
    m_buffer.open(QIODevice::ReadOnly);
    
    m_audioOutput->start(&m_buffer);
    

    That's how I did it: I first read the complete file from disk into the QByteArray, but of course you can also directly pass the open file to the start() method.

    QFile m_file;   //this is also a QIODevice
    m_file.setFileName(fileName);
    m_file.open(QIODevice::ReadOnly);
    m_audioOutput->start(&m_file);
    


  • @SGaist Thanks for the reply.

    It is 32 bit int.
    Little Endian
    8000 Hz
    32 bits per sample.

    Feed it PCM data to play and second overload? Could you emphasise on that?



  • @Diracsbracket Thank you. I will give this a shot.



  • Hi, @Diracsbracket

    Basically I have 1024 x uint32 values stored in audioData. Since they are uint32, each number has a size of 4 bytes.
    I store that number in a QByteArray, byte by byte in little endian.
    frameMax is 1024.

    1. However, when I play the audio, there is still no sound being played. Is something wrong with the way I filled my QByteArray?
    2. My QAudioFormat is set to play at UnSignedInt - 32 bit resolution. So will QAudioOutput understand that my buffer is only feeding in byte by byte, and not 4 bytes?
    3. My application will crash after audio has stopped.
            QByteArray  m_data;
            QDataStream mydataStream(&m_data,QIODevice::WriteOnly);
            mydataStream.setByteOrder(QDataStream::LittleEndian);
            quint32 n = 0;
    
            for (int i =0; i < frameMax; i++){
                n = audioData[i];
                for(int j = 0; j != sizeof(n); ++j)
                {
                    m_data.append((char)(n&(0xFF << (j*8)) >>(j*8)));
                }
            }
    
            QBuffer m_buffer;
            m_buffer.setBuffer(&m_data);
            m_buffer.open(QIODevice::ReadOnly);
            audio->start(&m_buffer);
    


  • @scottnat said in Raw Audio Data Playback:

           n = audioData[i];
            for(int j = 0; j != sizeof(n); ++j)
            {
                m_data.append((char)(n&(0xFF << (j*8)) >>(j*8)));
            }
    

    You can directly use the << operator of QDataStream instead of the inner loop you're using, like so:

    mydataStream << audioData[i];
    

    Furthermore, the documentation of QDataStream states that when passing a QByteArray to it

    "Since QByteArray is not a QIODevice subclass, internally a QBuffer is created to wrap the byte array."
    

    So you might just as well create your m_buffer first, assign your m_data QByteArray to it and pass m_buffer directly to mydataStream, to avoid the creation of the internal buffer.



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.