使用QThread的QAudioOutput异步播放声音

时间:2016-12-04 11:20:31

标签: c++ qt qthread

我正在尝试用QAudioOutputQThread异步播放生成的声音。要将QAudioOutput用于QThread,我们需要QThread拥有自己的事件循环。因此,我使用QObject::moveToThread()方法从doc example开始。

声音生成正常。因为如果我播放声音并等待完成sound->playSound(true);,那么声音播放就可以了。但是,如果我使用sound->playSound(false);,则没有声音,就像没有事件循环一样。

我使用while(1){}因为在原始代码中,Interpreter是一个很长的while()循环,其中发生了许多事情(图形,声音等)。

1)如果我等待声音sound->playSound(true);,我得到了这个输出:

try playSound
handleAudioStateChanged ActiveState
handleAudioStateChanged IdleState
return from playSound

2)如果我异步播放声音sound->playSound(false);我得到了这个输出:

try playSound
handleAudioStateChanged ActiveState
return from playSound

如何在QAudioOutput中使用QThread异步播放声音,同时在无限循环中执行大量其他昂贵工作?

的main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"

void Interpreter::doWork() {
    bool result = false;
    sound = new SoundSystem();
    qDebug() << "try playSound";
    sound->playSound(true); //bool wait=true/false
    qDebug() << "return from playSound";
    while(1){}
    emit resultReady(result);
}

Controller::Controller() {
    interpreterThread = new QThread();
    Interpreter *i = new Interpreter;
    connect(interpreterThread, &QThread::finished, i, &QObject::deleteLater);
    connect(this, &Controller::startInterpreter, i, &Interpreter::doWork);
    connect(i, &Interpreter::resultReady, this, &Controller::stopRunFinalized);
    i->moveToThread(interpreterThread);
    interpreterThread->start();
}

Controller::~Controller() {
    interpreterThread->quit();
    interpreterThread->wait();
}

void Controller::stopRunFinalized(bool i){
    qDebug() << "stopRunFinalized";
}

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
    Controller *t = new Controller;
    t->startInterpreter();
}

MainWindow::~MainWindow(){}

mainwindow.h

#include <QMainWindow>
#include <QThread>
#include <QDebug>
#include "Sound.h"

class Interpreter : public QObject {
Q_OBJECT
public:
    SoundSystem *sound;
public slots:
    void doWork();
signals:
    void resultReady(bool);
};


class Controller : public QObject {
Q_OBJECT
public:
    Controller();
    ~Controller();
    QThread *interpreterThread;
//public slots:
    void stopRunFinalized(bool);
signals:
    void startInterpreter();
};


class MainWindow : public QMainWindow {
Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
};

Sound.cpp - 用于生成2秒的简单波形声音

#include "Sound.h"
#include <QDebug>

void  SoundSystem::playSound(bool wait) {
    double wave;
    double wavebit;
    short s;
    char *cs = (char *) &s;
    QByteArray* array = new QByteArray();
    QBuffer buffer(array);
    const double pi = 4*atan(1.0);

    buffer.open(QIODevice::ReadWrite|QIODevice::Truncate);
    wave=0.0;
    wavebit=0.0;

    // lets build a sine wave into buffer
    int length = 44100 * 440 / 1000;
    wavebit = 2 * pi / (44100.0 / 1000.0);
    for(int i = 0; i < length; i++) {
        s = (int16_t) (0x7fff * sin(wave));
        buffer.write(cs,sizeof(int16_t));
        wave+=wavebit;
    }
    buffer.seek(0);

    // setup the audio format
    format.setSampleRate(44100);
    format.setChannelCount(1);
    format.setSampleSize(16);   // 16 bit audio
    format.setCodec("audio/pcm");
    format.setSampleType(QAudioFormat::SignedInt);
    audio = new QAudioOutput(format);
    connect(audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleAudioStateChanged(QAudio::State)));
    audio->start(&buffer);

    if(wait){
        QEventLoop *loop = new QEventLoop();
        QObject::connect(audio, SIGNAL(stateChanged(QAudio::State)), loop, SLOT(quit()));
        do {
            loop->exec(QEventLoop::WaitForMoreEvents);
        } while(audio->state() == QAudio::ActiveState);
        delete (loop);
    }
}

void SoundSystem::handleAudioStateChanged(QAudio::State newState){
    qDebug() << "handleAudioStateChanged" << newState;
}

Sound.h

#include <math.h>
#include <QObject>
#include <QAudioOutput>
#include <QBuffer>
#include <QEventLoop>

class SoundSystem : public QObject
{
    Q_OBJECT

public:
    void playSound(bool wait);
    QAudioOutput* audio;
    QAudioFormat format;
private slots:
    void handleAudioStateChanged(QAudio::State);
};

0 个答案:

没有答案