Skip to content

Commit

Permalink
Revamp synchronization with the audio engine
Browse files Browse the repository at this point in the history
  • Loading branch information
sakertooth committed Sep 21, 2023
1 parent 3a0e68c commit fa3bbbf
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 66 deletions.
23 changes: 10 additions & 13 deletions include/AudioEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@

#include <QMutex>

#ifdef __MINGW32__
#include <mingw.condition_variable.h>
#else
#include <condition_variable>
#endif

#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0))
#include <QRecursiveMutex>
#endif
Expand Down Expand Up @@ -475,19 +481,10 @@ class LMMS_EXPORT AudioEngine : public QObject

bool m_clearSignal;

bool m_changesSignal;
unsigned int m_changes;
QMutex m_changesMutex;
#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0))
QRecursiveMutex m_doChangesMutex;
#else
QMutex m_doChangesMutex;
#endif
QMutex m_waitChangesMutex;
QWaitCondition m_changesAudioEngineCondition;
QWaitCondition m_changesRequestCondition;

bool m_waitingForWrite;
bool m_runChanges;
int m_numChanges;
std::condition_variable m_numChangesCond, m_runChangesCond;
std::mutex m_numChangesMutex, m_runChangesMutex;

friend class Engine;
friend class AudioEngineWorkerThread;
Expand Down
79 changes: 26 additions & 53 deletions src/core/AudioEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,8 @@ AudioEngine::AudioEngine( bool renderOnly ) :
m_profiler(),
m_metronomeActive(false),
m_clearSignal( false ),
m_changesSignal( false ),
m_changes( 0 ),
#if (QT_VERSION < QT_VERSION_CHECK(5,14,0))
m_doChangesMutex( QMutex::Recursive ),
#endif
m_waitingForWrite( false )
m_runChanges(false),
m_numChanges(0)
{
for( int i = 0; i < 2; ++i )
{
Expand Down Expand Up @@ -444,8 +440,6 @@ void AudioEngine::renderStageMix()

emit nextAudioBuffer(m_outputBufferRead);

runChangesInModel();

// and trigger LFOs
EnvelopeAndLfoParameters::instances()->trigger();
Controller::triggerFrameCounter();
Expand All @@ -463,6 +457,7 @@ const surroundSampleFrame *AudioEngine::renderNextBuffer()
renderStageInstruments(); // STAGE 1: run and render all play handles
renderStageEffects(); // STAGE 2: process effects of all instrument- and sampletracks
renderStageMix(); // STAGE 3: do master mix in mixer
runChangesInModel(); // STAGE 4: call runChangesInModel to process pending non-automated changes

s_renderingThread = false;
m_profiler.finishPeriod(processingSampleRate(), m_framesPerPeriod);
Expand Down Expand Up @@ -805,57 +800,44 @@ void AudioEngine::removePlayHandlesOfTypes(Track * track, PlayHandle::Types type

void AudioEngine::requestChangeInModel()
{
if( s_renderingThread )
return;

m_changesMutex.lock();
m_changes++;
m_changesMutex.unlock();
if (s_renderingThread || !m_isProcessing) { return; }

m_doChangesMutex.lock();
m_waitChangesMutex.lock();
if (m_isProcessing && !m_waitingForWrite && !m_changesSignal)
{
m_changesSignal = true;
m_changesRequestCondition.wait( &m_waitChangesMutex );
auto lock = std::lock_guard{m_numChangesMutex};
++m_numChanges;
}
m_waitChangesMutex.unlock();
}



auto lock = std::unique_lock{m_runChangesMutex};
m_runChangesCond.wait(lock, [this] { return m_runChanges; });
}

void AudioEngine::doneChangeInModel()
{
if( s_renderingThread )
return;

m_changesMutex.lock();
bool moreChanges = --m_changes;
m_changesMutex.unlock();
if (s_renderingThread || !m_isProcessing) { return; }

if( !moreChanges )
{
m_changesSignal = false;
m_changesAudioEngineCondition.wakeOne();
auto lock = std::lock_guard{m_numChangesMutex};
--m_numChanges;
}
m_doChangesMutex.unlock();
}



m_numChangesCond.notify_one();
}

void AudioEngine::runChangesInModel()
{
if( m_changesSignal )
{
m_waitChangesMutex.lock();
// allow changes in the model from other threads ...
m_changesRequestCondition.wakeOne();
// ... and wait until they are done
m_changesAudioEngineCondition.wait( &m_waitChangesMutex );
m_waitChangesMutex.unlock();
auto lock = std::lock_guard{m_runChangesMutex};
m_runChanges = true;
}
m_runChangesCond.notify_all();

{
auto lock = std::unique_lock{m_numChangesMutex};
m_numChangesCond.wait(lock, [this] { return m_numChanges == 0; });
}

auto lock = std::lock_guard{m_runChangesMutex};
m_runChanges = false;
}

bool AudioEngine::isAudioDevNameValid(QString name)
Expand Down Expand Up @@ -1304,16 +1286,7 @@ void AudioEngine::fifoWriter::run()

void AudioEngine::fifoWriter::write( surroundSampleFrame * buffer )
{
m_audioEngine->m_waitChangesMutex.lock();
m_audioEngine->m_waitingForWrite = true;
m_audioEngine->m_waitChangesMutex.unlock();
m_audioEngine->runChangesInModel();

m_fifo->write( buffer );

m_audioEngine->m_doChangesMutex.lock();
m_audioEngine->m_waitingForWrite = false;
m_audioEngine->m_doChangesMutex.unlock();
m_fifo->write(buffer);
}

} // namespace lmms

0 comments on commit fa3bbbf

Please sign in to comment.