shared-libraries/ScStwLibraries/sources/scstwsoundplayer.cpp

133 lines
4.3 KiB
C++

/****************************************************************************
** ScStw Libraries
** Copyright (C) 2020 Itsblue development
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "../headers/scstwsoundplayer.h"
ScStwSoundPlayer::ScStwSoundPlayer(QObject *parent) : QObject(parent)
{
this->waitLoop = new QEventLoop(this);
this->waitTimer = new QTimer(this);
this->soundFiles.insert(0, {{"path","qrc:/sound/AtYourMarksSound.wav"}, {"duration", 1000}});
this->soundFiles.insert(1, {{"path","qrc:/sound/ReadySound.wav"}, {"duration", 570}});
this->soundFiles.insert(2, {{"path","qrc:/sound/StartsignalSoundExtended.wav"}, {"duration", 3200}});
this->soundFiles.insert(3, {{"path","qrc:/sound/FalseStartSound.wav"}, {"duration", 2000}});
this->soundEffect = new QSoundEffect(this);
this->soundEffect->setLoopCount(1);
connect(this, &ScStwSoundPlayer::playbackStarted, this->waitLoop, &QEventLoop::quit);
connect(this->soundEffect, &QSoundEffect::playingChanged, this->waitLoop, &QEventLoop::quit);
}
bool ScStwSoundPlayer::play(int action, double volume, double *timeOfStart) {
if(!this->soundFiles.contains(action))
return false;
if(action > 2 || action < 0)
return false;
// stop playback
if(this->soundEffect->isPlaying())
this->soundEffect->stop();
// update currently playing action
this->currentlyPlayingAction = action;
// update volume
this->soundEffect->setVolume(volume);
// load
this->soundEffect->setSource(this->soundFiles[action]["path"].toString());
// wait for the effect to load
QEventLoop loop;
while(this->soundEffect->status() != QSoundEffect::Ready) {
QObject::connect(this->soundEffect, &QSoundEffect::statusChanged, &loop, &QEventLoop::quit);
loop.exec();
}
// start
this->soundEffect->play();
// emit a playback start
emit this->playbackStarted();
// save started at
this->playingStartedAt = QDateTime::currentMSecsSinceEpoch();
// pass the time of start if requested
if(timeOfStart != nullptr) {
*timeOfStart = this->playingStartedAt;
}
if(action < 2)
return this->waitForSoundFinish();
return true;
}
bool ScStwSoundPlayer::cancel(double volume) {
if(!this->soundEffect->isPlaying() )
return false;
// stop playback
this->soundEffect->stop();
this->waitLoop->quit();
if(this->currentlyPlayingAction != 2)
return true;
// update volume
this->soundEffect->setVolume(volume);
// load
this->soundEffect->setSource(this->soundFiles[3]["path"].toString());
// play
this->soundEffect->play();
return true;
}
bool ScStwSoundPlayer::waitForSoundFinish(double *timeOfStop) {
if(!this->soundEffect->isPlaying())
return false;
// wait until the audio output reports the sound is over
waitLoop->exec();
// wait until the sound is actually over
// the timeOffset is the buffer time before the audio started!
int timeOffset = this->soundFiles[this->currentlyPlayingAction]["duration"].toDouble() - (QDateTime::currentMSecsSinceEpoch() - playingStartedAt);
if(timeOffset > 0) {
QTimer timer;
timer.singleShot(timeOffset, this->waitLoop, &QEventLoop::quit);
this->waitLoop->exec();
}
// calculate the point in time where the sound playback actually ended
if(timeOfStop != nullptr) {
int latency = this->playingStartedAt + this->soundFiles[this->currentlyPlayingAction]["duration"].toDouble();
*timeOfStop = QDateTime::currentMSecsSinceEpoch() - latency;
}
return true;
}