Skip to content

Commit

Permalink
If concurrency is hard, you're probably overthinking it
Browse files Browse the repository at this point in the history
  • Loading branch information
sakertooth committed Oct 25, 2023
1 parent 63d03fa commit 330548c
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 93 deletions.
21 changes: 5 additions & 16 deletions include/AudioEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,13 @@
#ifndef LMMS_AUDIO_ENGINE_H
#define LMMS_AUDIO_ENGINE_H

#include <QMutex>

#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0))
#include <QRecursiveMutex>
#ifdef __MINGW32__
#include <mingw.mutex.h>
#else
#include <mutex>
#endif

#include <QThread>
#include <QWaitCondition>
#include <samplerate.h>

#include <vector>
Expand Down Expand Up @@ -476,17 +475,7 @@ 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;
std::mutex m_changeMutex;

bool m_waitingForWrite;

Expand Down
89 changes: 12 additions & 77 deletions src/core/AudioEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ namespace lmms
using LocklessListElement = LocklessList<PlayHandle*>::Element;

static thread_local bool s_renderingThread;
static thread_local bool s_runningChange;



Expand All @@ -89,13 +90,7 @@ AudioEngine::AudioEngine( bool renderOnly ) :
m_audioDevStartFailed( false ),
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_clearSignal(false)
{
for( int i = 0; i < 2; ++i )
{
Expand Down Expand Up @@ -165,8 +160,6 @@ AudioEngine::AudioEngine( bool renderOnly ) :

AudioEngine::~AudioEngine()
{
runChangesInModel();

for( int w = 0; w < m_numWorkers; ++w )
{
m_workers[w]->quit();
Expand Down Expand Up @@ -447,8 +440,6 @@ void AudioEngine::renderStageMix()

emit nextAudioBuffer(m_outputBufferRead);

runChangesInModel();

// and trigger LFOs
EnvelopeAndLfoParameters::instances()->trigger();
Controller::triggerFrameCounter();
Expand All @@ -459,6 +450,8 @@ void AudioEngine::renderStageMix()

const surroundSampleFrame *AudioEngine::renderNextBuffer()
{
const auto lock = std::lock_guard{m_changeMutex};

m_profiler.startPeriod();
s_renderingThread = true;

Expand Down Expand Up @@ -811,57 +804,16 @@ void AudioEngine::removePlayHandlesOfTypes(Track * track, PlayHandle::Types type

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

m_changesMutex.lock();
m_changes++;
m_changesMutex.unlock();

m_doChangesMutex.lock();
m_waitChangesMutex.lock();
if (m_isProcessing && !m_waitingForWrite && !m_changesSignal)
{
m_changesSignal = true;
m_changesRequestCondition.wait( &m_waitChangesMutex );
}
m_waitChangesMutex.unlock();
if (s_renderingThread || s_runningChange) { return; }
s_runningChange = true;
m_changeMutex.lock();
}




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

m_changesMutex.lock();
bool moreChanges = --m_changes;
m_changesMutex.unlock();

if( !moreChanges )
{
m_changesSignal = false;
m_changesAudioEngineCondition.wakeOne();
}
m_doChangesMutex.unlock();
}




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();
}
if (s_renderingThread || !s_runningChange) { return; }
s_runningChange = false;
m_changeMutex.unlock();
}

bool AudioEngine::isAudioDevNameValid(QString name)
Expand Down Expand Up @@ -1297,29 +1249,12 @@ void AudioEngine::fifoWriter::run()
auto buffer = new surroundSampleFrame[frames];
const surroundSampleFrame * b = m_audioEngine->renderNextBuffer();
memcpy( buffer, b, frames * sizeof( surroundSampleFrame ) );
write( buffer );
m_fifo->write(buffer);
}

// Let audio backend stop processing
write( nullptr );
m_fifo->write(nullptr);
m_fifo->waitUntilRead();
}




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();
}

} // namespace lmms

0 comments on commit 330548c

Please sign in to comment.