c++qtqt6qbytearray

Convert QAudioBuffer to QByteArray : loss of information?


I have a WAV file that I decode with the QAudioDecoder. As a result I have a QAudioBuffer object. I want to store the data stored in QAudioBuffer in a QByteArray for my QIODevice derived class. I want to use this data in the ReadData method of my derived class for audio output. I now have 2 questions:

Thanks in advance.

Here is the code

QAudioFormat *format_decoder;
format_decoder = new QAudioFormat;
format_decoder->setSampleRate(44100);
format_decoder->setChannelCount(1);
format_decoder->setSampleFormat(QAudioFormat::Int16);

QAudioDecoder decoder;
decoder.setSource(filenameSource);
decoder.setAudioFormat(*format_decoder);
decoder.start();

QObject::connect(&decoder, &QAudioDecoder::bufferReady, this, &MainWindow::slot_bufReady);

and the slot

void MainWindow::slot_bufReady(){

QAudioBuffer buffer = m_audioDecoder->read();
QByteArray buffer_ByteArray(buffer.constData<char>(), buffer.byteCount());

QFile file(filenameTest1);
if(!file.open(QIODevice::WriteOnly|QIODevice::Append)) {
        qDebug() << "ERRO ";  }

QTextStream strem(&file);
for(auto const dat: buffer_ByteArray)  {
        strem<< qreal(dat)/128.0<< "\r\n";
    }
file.cloe();


Solution

  • This looks suspicious:

    for(auto const dat: buffer_ByteArray)  {
            strem<< qreal(dat)/128.0<< "\r\n";
        }
    

    Your audio format is 16-bit mono. Reading it byte by byte is a non-starter. Read it sample by sample. That is, read two bytes at a time and convert. More likely this:

    int16_t* data = (int16_t*)(buffer.data());
    int samples = buffer.sampleCount();
    for (int i = 0; i < samples; i++)
    {
        strem << data[i] << "\r\n";
    }
    
    

    The above will save your samples into a text file. You could plot it with Excel. But as others have said, that's not as useful as saving in as binary. You could prepend a WAV file header such that it can be played and analyzed with other tools.

    Update

    If your intent is to transcode from 16-bit to 8-bit, this is how you would likely do it:

     int16_t* data = (int16_t*)(buffer.data());
     QByteArray buffer_ByteArray(buffer.sampleCount(), '\0');
     for (size_t i = 0; i < samples; i++) {
         buffer_ByteArray[i] = (char)(data[i] / 256); // 16-bit to 8-bit
     }
    

    Note: some audio platforms use unsigned integers for 8-bit audio. That is the zero amplitude sample is 0x80. This is the case for 8-bit WAV files. If that's in play, then change this line:

    buffer_ByteArray[i] = (char)(data[i] / 256); // 16-bit to 8-bit
    

    To this:

    char c = (char)(data[i] / 256); // 16-bit to 8-bit signed
    const unsigned char mask = 0x80;
    buffer_ByteArray[i] = (char)(mask ^ c);