Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QAudiobuffer how to get left and right channel from Qbytearray for playback in QAudioOutput

QAudiobuffer how to get left and right channel from Qbytearray for playback in QAudioOutput

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 3 Posters 3.6k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Banshee10000B Offline
    Banshee10000B Offline
    Banshee10000
    wrote on last edited by Banshee10000
    #1

    Hi all, Currently I'm stuck and the Qt documentation isn't helping me at all.

    I need a way to get and play the individual left and right audio channel of a QByteArray that contains PCM data.
    So far it looks like QAudioBuffer is the class to use however how do I use it.

    It doesn't have any members that I can find that I can fill it with a QByteArray.
    or maybe Im completely on the wrong track.

    I don't understand the QAudioBuffer class and how to use it.

    #include "Sound.h"
    #include <QDebug>
    
    #include <QtCore>
    #include <QtMultimedia/QAudioOutput>
    #include <QAudioBuffer>
    
    int sampleRate = 44100;
    int channelCount = 2;
    int sampleSize = 16;
    const QString codec = "audio/pcm";
    
    void SoundSystem::playSound(bool wait, qreal amplitude, float frequency, int msecs)
    {
        soundBuffer = new QByteArray();
    
        format = new QAudioFormat();
        format->setSampleRate(sampleRate);
        format->setChannelCount(channelCount);
        format->setSampleSize(sampleSize);
        format->setCodec(codec);
        format->setByteOrder(QAudioFormat::LittleEndian);
        format->setSampleType(QAudioFormat::UnSignedInt);
    
        output = new QAudioOutput(*format, this);
    
        outputBuffer = new QBuffer(soundBuffer);
        if (outputBuffer->open(QIODevice::ReadOnly) == false) {
            qCritical() << "Invalid operation while opening QBuffer. audio/pcm";
            return;
        }
    
        msecs = (msecs < 50) ? 50 : msecs;
    
        qreal singleWaveTime = amplitude / frequency;
    
        qreal samplesPerWave = qCeil(format->sampleRate() * singleWaveTime);
    
        quint32 waveCount = qCeil(msecs / (singleWaveTime * 1000.0));
    
        quint32 sampleSize = static_cast<quint32>(format->sampleSize() / 8.0);
    
        QByteArray data(waveCount * samplesPerWave * sampleSize * format->channelCount(), '\0');
    
        unsigned char* dataPointer = reinterpret_cast<unsigned char*>(data.data());
    
        for (quint32 currentWave = 0; currentWave < waveCount; currentWave++)
        {
            for (int currentSample = 0; currentSample < samplesPerWave; currentSample++)
            {
                double nextRadStep = (currentSample / static_cast<double>(samplesPerWave)) * (2 * M_PI);
    
                quint16 sampleValue = static_cast<quint16>((qSin(nextRadStep) > 0 ? 1 : -1) * 32767);
    
                for (int channel = 0; channel < format->channelCount(); channel++)
                {
                    qToLittleEndian(sampleValue, dataPointer);
                    dataPointer += sampleSize;
                }
            }
        }
       
        connect(output, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleAudioStateChanged(QAudio::State)));
    
        // Here I need to have Left, Right or Stereo channel data for playback.
        
            
        soundBuffer->append(data); 
       
        output->start(outputBuffer); // Output is a QAudioOutput  
    
        if(wait)
        {
            QEventLoop *loop = new QEventLoop();
            QObject::connect(output, SIGNAL(stateChanged(QAudio::State)), loop, SLOT(quit()));
    
            do
            {
                loop->exec(QEventLoop::WaitForMoreEvents);
    
                if(output->state() == QAudio::StoppedState)
                {
                    qDebug() << "Recieved Hard Stop";
                    output->stop();
                    soundBuffer->clear();
                }
            }
            while(output->state() == QAudio::ActiveState || output->state() == QAudio::SuspendedState); // Susspend to make pause working
            delete (loop);
        }
        soundBuffer->clear(); // Flush Buffer to append new sequance. else it will cause std::bad_alloc for large wave data. 
    }
    

    How can I achieve this using Qt Libs only ? any help would be greatly appreciated.
    Im using latest Qt 5.9.3 and Phonon isnt supported anymore

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      If you have a working solution that uses Phonon, then you might want to check the phonon4qt5 project.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • Banshee10000B Offline
        Banshee10000B Offline
        Banshee10000
        wrote on last edited by
        #3

        Sadly no I don't have a working solution, Im completely stuck right now. Ive read that Phonon has or had the ability to get the channel data separately.

        As Im using generated PCM data I just need a way to get the left and right channels data separately for playback. Either on left only or right only or both at the same time.

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Since it's interleaved data, you can mask the left or right data before putting it into the QByteArray.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • Banshee10000B Offline
            Banshee10000B Offline
            Banshee10000
            wrote on last edited by
            #5

            Could you maybe provide an example, I have not done masking yet.

            one thing i tried was:

            QByteArray leftSide, rightSide;

            for(int i = 0; i < data.length() / 2; i+=2)
            {
                   leftSide[i] = data[i];
                   rightSide[i+1] = data[i+1];
            }
            soundBuffer->append(rightSide);
            

            which didnt do much other then lower the volume but the sound still plays from both left and right channels.

            1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by
              #6
              quint16 input = 0xFFFF;
              
              quint16 leftOnly = input & 0x00FF;
              quint16 rightOnly = input & 0xFF00;
              

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              2
              • Banshee10000B Offline
                Banshee10000B Offline
                Banshee10000
                wrote on last edited by
                #7

                Still Lost. Ive tried a few things non of it seems to work for me. No audio on either channel. Im unclear on how

                quint16 input = 0xFFFF;
                

                Where does my QbyteArray data come into play if the quint16 is set ?
                Also I appriciate your help in this so far. Its just im lost.

                QDataStream dataStream(data);
                    quint16 input;
                    dataStream >> input;
                
                    quint16  leftOnly = input & 0x00FF;
                    quint16  rightOnly = input & 0xFF00;
                
                
                    QByteArray LeftSideData;
                    QDataStream out(&LeftSideData, QIODevice::WriteOnly | QIODevice::Append);
                    //out.setByteOrder(QDataStream::LittleEndian);
                    out << leftOnly;
                
                    soundBuffer->append(LeftSideData);
                    // soundBuffer->append(RightSideData);
                

                No audio when running Function.

                aha_1980A 1 Reply Last reply
                0
                • Banshee10000B Banshee10000

                  Still Lost. Ive tried a few things non of it seems to work for me. No audio on either channel. Im unclear on how

                  quint16 input = 0xFFFF;
                  

                  Where does my QbyteArray data come into play if the quint16 is set ?
                  Also I appriciate your help in this so far. Its just im lost.

                  QDataStream dataStream(data);
                      quint16 input;
                      dataStream >> input;
                  
                      quint16  leftOnly = input & 0x00FF;
                      quint16  rightOnly = input & 0xFF00;
                  
                  
                      QByteArray LeftSideData;
                      QDataStream out(&LeftSideData, QIODevice::WriteOnly | QIODevice::Append);
                      //out.setByteOrder(QDataStream::LittleEndian);
                      out << leftOnly;
                  
                      soundBuffer->append(LeftSideData);
                      // soundBuffer->append(RightSideData);
                  

                  No audio when running Function.

                  aha_1980A Offline
                  aha_1980A Offline
                  aha_1980
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  @Banshee10000

                  If I look at the code, I assume you are masking 8 bits of data each time.

                  Is your audio really 8 bit or do you use 16 bit resolution? Then I think you need to take every interleaved 16 bit for left and right (but I haven't looked up the PCM audio specs, so I might be wrong).

                  Regards

                  Qt has to stay free or it will die.

                  1 Reply Last reply
                  0
                  • SGaistS Offline
                    SGaistS Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    Since you want to do some "mixing" with your audio channels. What about using the DSPFilters project ?

                    They provide a nice interface to do interleaving/de-interleaving and other manipulations that you might find useful.

                    Interested in AI ? www.idiap.ch
                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                    1 Reply Last reply
                    0
                    • Banshee10000B Offline
                      Banshee10000B Offline
                      Banshee10000
                      wrote on last edited by
                      #10

                      When I create a test .Wav file by writing Wav header then this data then close and adjusting the header here is the data of the file. If that would help.

                      • Format : Wave
                      • File size : 30.5 MiB
                      • Duration : 3 min 1 s
                      • Overall bit rate mode : Constant
                      • Overall bit rate : 1 411 kb/s
                      • Format : PCM
                      • Format settings : Little / Signed
                      • Codec ID : 1
                      • Duration : 3 min 1 s
                      • Bit rate mode : Constant
                      • Bit rate : 1 411.2 kb/s
                      • Channel(s) : 2 channels
                      • Sampling rate : 44.1 kHz
                      • Bit depth : 16 bits
                      • Stream size : 30.5 MiB (100%)

                      The sampleSize = 16

                      1 Reply Last reply
                      0
                      • Banshee10000B Offline
                        Banshee10000B Offline
                        Banshee10000
                        wrote on last edited by
                        #11

                        Its not really mixing, It more just splitting the PCM to go either right or left. or play in stereo on the PC. Nothing more.
                        I'll have a look at the project. But Id really prefer to use Qt Libs only if at all possible. I didn't think this would turn out to be such a mission hehe.

                        Can't the QAudioBuffer class do this. Ive look st the documentation and they refer to left and right but i don't understand the Library as the documentation provided is very limited. Also please note that I'm new to Audio programming and Im also not a C++ expert by far. Its like stumbling around in the dark at this stage for me.

                        1 Reply Last reply
                        0
                        • Banshee10000B Offline
                          Banshee10000B Offline
                          Banshee10000
                          wrote on last edited by
                          #12

                          Ok so I have figured out a solution that will suite my needs
                          After constructing the Wav and getting the PCM data into a QByteArray The format in the buffer for PCM 16 Bit will be as follows (L,L,R,R,L,L,R,R....) so every two bytes are sent to one channel (pcm 16) then I nullify the channel I want to cancel so If I want the the left channel only to work the buffer will be (L,L,0,0,L,L,0,0) or visa versa for right.

                          So I don't need any external Libs and licenses for this project. Pure C++ and Qt Libs.

                          Thanks to @SGaist trying to help me. I did learn more about masking through this ordeal even tough I ended up not using masking it in the final solution.

                          1 Reply Last reply
                          0

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved