Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to use two channels in QAudioOutput?



  • I'm investigating using QAudioOutput for generating sound. I've figured out how to generate mono sound on a single channel, and am now trying to expand my program to handle stereo output.

    For my current test, I want to send a 440Hz wave to one speaker and a 220Hz wave to the other, but the same mixed sound is being sent to both. How do I fix this?

    I'm calculating the buffer I play in notifyPlayPressed():

    mainwindow.h:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QAudioOutput>
    #include <QByteArray>
    #include <QBuffer>
    #include <QMutex>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
        QAudioOutput* _audioOut = nullptr;
        QIODevice* _audioDevice = nullptr;
        QByteArray _audioBuf;
    
        int sampleRate = 44100;
        QMutex _bufMutex;
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
        void queueAudio(char* data, int size);
    
    public slots:
        void notifyPlayPressed();
        void audioNotify();
        void handleStateChanged(QAudio::State);
    
    private:
        void writeToDevice();
    
        Ui::MainWindow *ui;
    };
    
    #endif // MAINWINDOW_H
    

    mainwindow.cpp:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #include <QAudioFormat>
    #include <QDebug>
    #include "math.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        connect (ui->playBn, &QPushButton::clicked, this, &MainWindow::notifyPlayPressed);
    
    
        QAudioFormat format;
        // Set up the format, eg.
        format.setSampleRate(sampleRate);
        format.setChannelCount(2);
        format.setSampleSize(8 * sizeof(float));
        format.setCodec("audio/pcm");
        format.setByteOrder(QAudioFormat::LittleEndian);
        format.setSampleType(QAudioFormat::Float);
    
        QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
        if (!info.isFormatSupported(format)) {
            qWarning() << "Raw audio format not supported by backend, cannot play audio.";
            return;
        }
    
        _audioOut = new QAudioOutput(format, this);
        _audioOut->setNotifyInterval(128);
    
        connect(_audioOut, &QAudioOutput::notify, this, &MainWindow::audioNotify);
        connect(_audioOut, &QAudioOutput::stateChanged, this, &MainWindow::handleStateChanged);
        _audioDevice = _audioOut->start();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    
        _audioOut->stop();
        delete _audioOut;
    }
    
    void MainWindow::queueAudio(char* data, int size)
    {
        _bufMutex.lock();
        _audioBuf.append(data, size);
        writeToDevice();
        _bufMutex.unlock();
    }
    
    
    void MainWindow::audioNotify()
    {
        _bufMutex.lock();
        writeToDevice();
        _bufMutex.unlock();
    }
    
    
    void MainWindow::writeToDevice()
    {
        int numBytes = std::min(_audioOut->bytesFree(), _audioBuf.size());
        if (numBytes > 0)
        {
            _audioDevice->write(_audioBuf.data(), numBytes);
            _audioBuf.remove(0, numBytes);
        }
    }
    
    
    void MainWindow::notifyPlayPressed()
    {
        int bufferSize = sampleRate * sizeof(float) * 2;
        QByteArray _dataBuf(bufferSize, 0);
    
        {
            //Create 1 second of audio
            float* floatBuf = (float*)_dataBuf.data();
    
            for (int i = 0; i < sampleRate; ++i)
            {
                float seconds = i / (float)sampleRate;
                floatBuf[i * 2] = (float)cos(2 * M_PI * seconds * 220);
                floatBuf[i * 2 + 1] = (float)cos(2 * M_PI * seconds * 440);
            }
        }
    
        queueAudio(_dataBuf.data(), bufferSize);
    }
    

  • Lifetime Qt Champion

    Hi
    As far as i know, you can have 2 mono channels or one stereo .
    2 stereo channels is not supported as far as i have seen.
    They will always be mixed.
    It been suggested to use
    http://www.portaudio.com/
    instead but i can't say if good solution or not.



  • This post is deleted!

  • Lifetime Qt Champion



  • Actually, it looks like the above code is working. I just wasn't able to hear the difference clearly with the samples I as playing on my speakers.


Log in to reply