diff --git a/toonz/sources/common/tsound/tsound_qt.cpp b/toonz/sources/common/tsound/tsound_qt.cpp index 50caa62..fd1d64f 100644 --- a/toonz/sources/common/tsound/tsound_qt.cpp +++ b/toonz/sources/common/tsound/tsound_qt.cpp @@ -25,105 +25,38 @@ TThread::Mutex MutexOut; class TSoundOutputDeviceImp : public std::enable_shared_from_this { public: - bool m_isPlaying; - bool m_looped; - TSoundTrackFormat m_currentFormat; - std::set m_supportedRate; - bool m_opened; - double m_volume = 0.5; - - QAudioOutput *m_audioOutput; - QBuffer *m_buffer; - - TSoundOutputDeviceImp() - : m_isPlaying(false) - , m_looped(false) - , m_supportedRate() - , m_opened(false){}; + struct Output { + QByteArray *m_byteArray; + QBuffer *m_buffer; + QAudioOutput *m_audioOutput; + explicit Output(): m_byteArray(), m_buffer(), m_audioOutput() { } + }; + +private: + double m_volume; + bool m_looping; + QList m_outputs; +public: std::set m_listeners; - ~TSoundOutputDeviceImp(){}; + TSoundOutputDeviceImp(): m_volume(0.5), m_looping(false) {}; + ~TSoundOutputDeviceImp() { stop(); } - bool doOpenDevice(); - bool doSetStreamFormat(const TSoundTrackFormat &format); - bool doStopDevice(); - void play(const TSoundTrackP &st, TINT32 s0, TINT32 s1, bool loop, - bool scrubbing); - void prepareVolume(double volume); -}; + double getVolume() { return m_volume; } + double isLooping() { return m_looping; } + void prepareVolume(double x) { m_volume = x; } + void setLooping(bool x) { m_looping = x; } // looping not implemented here yet -//----------------------------------------------------------------------------- -namespace { + void clearAudioOutputs(bool keepActive = false); + QAudioOutput* createAudioOutput(QAudioFormat &format); + bool isPlaying(); + void setVolume(double x); + void stop(); -struct MyData { - char *entireFileBuffer; - - quint64 totalPacketCount; - quint64 fileByteCount; - quint32 maxPacketSize; - quint64 packetOffset; - quint64 byteOffset; - bool m_doNotify; - void *sourceBuffer; - // AudioConverterRef converter; - std::shared_ptr imp; - bool isLooping; - MyData() - : entireFileBuffer(0) - , totalPacketCount(0) - , fileByteCount(0) - , maxPacketSize(0) - , packetOffset(0) - , byteOffset(0) - , sourceBuffer(0) - , isLooping(false) - , m_doNotify(true) {} + void play(const TSoundTrackP &st, TINT32 s0, TINT32 s1, bool loop, bool scrubbing); }; -class PlayCompletedMsg : public TThread::Message { - std::set m_listeners; - MyData *m_data; - -public: - PlayCompletedMsg(MyData *data) : m_data(data) {} - - TThread::Message *clone() const { return new PlayCompletedMsg(*this); } - - void onDeliver() { - if (m_data->imp) { - if (m_data->m_doNotify == false) return; - m_data->m_doNotify = false; - if (m_data->imp->m_isPlaying) m_data->imp->doStopDevice(); - std::set::iterator it = - m_data->imp->m_listeners.begin(); - for (; it != m_data->imp->m_listeners.end(); ++it) - (*it)->onPlayCompleted(); - } - } -}; -} - -#define checkStatus(err) \ - if (err) { \ - printf("Error: 0x%x -> %s: %d\n", (int)err, __FILE__, __LINE__); \ - fflush(stdout); \ - } - -bool TSoundOutputDeviceImp::doOpenDevice() { - m_opened = false; - m_audioOutput = NULL; - m_opened = true; - return m_opened; -} - -bool TSoundOutputDeviceImp::doSetStreamFormat(const TSoundTrackFormat &format) { - if (!m_opened) doOpenDevice(); - if (!m_opened) return false; - m_opened = true; - return true; -} - //============================================================================== TSoundOutputDevice::TSoundOutputDevice() : m_imp(new TSoundOutputDeviceImp) { @@ -148,13 +81,6 @@ bool TSoundOutputDevice::installed() { return true; } //------------------------------------------------------------------------------ bool TSoundOutputDevice::open(const TSoundTrackP &st) { - if (!m_imp->doOpenDevice()) - throw TSoundDeviceException(TSoundDeviceException::UnableOpenDevice, - "Problem to open the output device"); - if (!m_imp->doSetStreamFormat(st->getFormat())) - throw TSoundDeviceException( - TSoundDeviceException::UnableOpenDevice, - "Problem to open the output device setting some params"); return true; } @@ -162,18 +88,11 @@ bool TSoundOutputDevice::open(const TSoundTrackP &st) { bool TSoundOutputDevice::close() { stop(); - m_imp->m_opened = false; return true; } //------------------------------------------------------------------------------ -void TSoundOutputDeviceImp::prepareVolume(double volume) { - m_volume = volume; -} - -//------------------------------------------------------------------------------ - void TSoundOutputDevice::prepareVolume(double volume) { m_imp->prepareVolume(volume); } @@ -196,37 +115,16 @@ void TSoundOutputDevice::play(const TSoundTrackP &st, TINT32 s0, TINT32 s1, swap(s0, s1); } - if (isPlaying()) { -#ifdef DEBUG - cout << "is playing, stop it!" << endl; -#endif - stop(); - } m_imp->play(st, s0, s1, loop, scrubbing); } //------------------------------------------------------------------------------ -void TSoundOutputDeviceImp::play(const TSoundTrackP &st, TINT32 s0, TINT32 s1, - bool loop, bool scrubbing) { - if (!doSetStreamFormat(st->getFormat())) return; - - MyData *myData = new MyData(); - - myData->imp = shared_from_this(); - myData->totalPacketCount = s1 - s0; - myData->fileByteCount = (s1 - s0) * st->getSampleSize(); - myData->entireFileBuffer = new char[myData->fileByteCount]; - - memcpy(myData->entireFileBuffer, st->getRawData() + s0 * st->getSampleSize(), - myData->fileByteCount); - - m_isPlaying = true; - myData->isLooping = loop; +void TSoundOutputDeviceImp::play(const TSoundTrackP &st, TINT32 s0, TINT32 s1, bool loop, bool scrubbing) { + clearAudioOutputs(true); + m_looping = loop; QAudioFormat format; - QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); - format.setSampleSize(st->getBitPerSample()); format.setCodec("audio/pcm"); format.setChannelCount(st->getChannelCount()); @@ -235,49 +133,69 @@ void TSoundOutputDeviceImp::play(const TSoundTrackP &st, TINT32 s0, TINT32 s1, ? QAudioFormat::SignedInt : QAudioFormat::UnSignedInt); format.setSampleRate(st->getSampleRate()); - QList sbos = info.supportedByteOrders(); - QList sccs = info.supportedChannelCounts(); - QList ssrs = info.supportedSampleRates(); - QList sstypes = info.supportedSampleTypes(); - QList ssss = info.supportedSampleSizes(); - QStringList supCodes = info.supportedCodecs(); - if (!info.isFormatSupported((format))) { - format = info.nearestFormat(format); - int newChannels = format.channelCount(); - int newBitsPerSample = format.sampleSize(); - int newSampleRate = format.sampleRate(); - QAudioFormat::SampleType newSampleType = format.sampleType(); - QAudioFormat::Endian newBo = format.byteOrder(); - } - int test = st->getSampleCount() / st->getSampleRate(); - QByteArray *data = - new QByteArray(myData->entireFileBuffer, myData->fileByteCount); - QBuffer *newBuffer = new QBuffer; - newBuffer->setBuffer(data); - newBuffer->open(QIODevice::ReadOnly); - newBuffer->seek(0); - if (m_audioOutput == NULL) { - m_audioOutput = new QAudioOutput(format, NULL); + + QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); + if (!info.isFormatSupported((format))) + format = info.nearestFormat(format); + + Output output; + qint64 totalPacketCount = s1 - s0; + qint64 fileByteCount = (s1 - s0) * st->getSampleSize(); + char* entireFileBuffer = new char[fileByteCount]; + memcpy(entireFileBuffer, st->getRawData() + s0 * st->getSampleSize(), fileByteCount); + output.m_byteArray = new QByteArray(entireFileBuffer, fileByteCount); + + output.m_buffer = new QBuffer(); + output.m_buffer->setBuffer(output.m_byteArray); + output.m_buffer->open(QIODevice::ReadOnly); + output.m_buffer->seek(0); + + output.m_audioOutput = new QAudioOutput(format); + output.m_audioOutput->start(output.m_buffer); + output.m_audioOutput->setVolume(m_volume); + + m_outputs.push_back(output); +} + +//------------------------------------------------------------------------------ + +void TSoundOutputDeviceImp::clearAudioOutputs(bool keepActive) { + for(QList::iterator i = m_outputs.begin(); i != m_outputs.end(); ) { + if (!keepActive || i->m_audioOutput->state() != QAudio::ActiveState) { + delete i->m_audioOutput; + delete i->m_buffer; + delete i->m_byteArray; + i = m_outputs.erase(i); + } else ++i; } - m_audioOutput->start(newBuffer); - m_audioOutput->setVolume(m_volume); } //------------------------------------------------------------------------------ -bool TSoundOutputDeviceImp::doStopDevice() { - m_isPlaying = false; - m_audioOutput->stop(); +bool TSoundOutputDeviceImp::isPlaying() { + clearAudioOutputs(true); + return !m_outputs.empty(); +} - return true; +//------------------------------------------------------------------------------ + +void TSoundOutputDeviceImp::setVolume(double x) { + prepareVolume(x); + clearAudioOutputs(true); + for(QList::iterator i = m_outputs.begin(); i != m_outputs.end(); ++i) + i->m_audioOutput->setVolume(x); } //------------------------------------------------------------------------------ -void TSoundOutputDevice::stop() { - if (m_imp->m_opened == false) return; +void TSoundOutputDeviceImp::stop() { + clearAudioOutputs(); +} - m_imp->doStopDevice(); +//------------------------------------------------------------------------------ + +void TSoundOutputDevice::stop() { + m_imp->stop(); } //------------------------------------------------------------------------------ @@ -295,16 +213,13 @@ void TSoundOutputDevice::detach(TSoundOutputDeviceListener *listener) { //------------------------------------------------------------------------------ double TSoundOutputDevice::getVolume() { - if (m_imp->m_audioOutput != NULL) - return m_imp->m_audioOutput->volume(); - else return m_imp->m_volume; + return m_imp->getVolume(); } //------------------------------------------------------------------------------ bool TSoundOutputDevice::setVolume(double volume) { - m_imp->m_volume = volume; - m_imp->m_audioOutput->setVolume(volume); + m_imp->setVolume(volume); return true; } @@ -314,15 +229,15 @@ bool TSoundOutputDevice::supportsVolume() { return true; } //------------------------------------------------------------------------------ -bool TSoundOutputDevice::isPlaying() const { return m_imp->m_isPlaying; } +bool TSoundOutputDevice::isPlaying() const { return m_imp->isPlaying(); } //------------------------------------------------------------------------------ -bool TSoundOutputDevice::isLooping() { return m_imp->m_looped; } +bool TSoundOutputDevice::isLooping() { return m_imp->isLooping(); } //------------------------------------------------------------------------------ -void TSoundOutputDevice::setLooping(bool loop) { m_imp->m_looped = loop; } +void TSoundOutputDevice::setLooping(bool loop) { m_imp->setLooping(loop); } //------------------------------------------------------------------------------