我正在尝试用QAudioOutput
与QThread
异步播放生成的声音。要将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);
};