Defer updates to SampleBuffer

Removed global lock from the Mixer
This commit is contained in:
Javier Serrano Polo
2016-06-18 05:29:21 +02:00
parent ecf9db66bd
commit 5606a04ad7
16 changed files with 65 additions and 93 deletions

View File

@@ -184,9 +184,9 @@ public:
// audio-port-stuff
inline void addAudioPort( AudioPort * _port )
{
lock();
requestChangeInModel();
m_audioPorts.push_back( _port );
unlock();
doneChangeInModel();
}
void removeAudioPort( AudioPort * _port );
@@ -274,16 +274,6 @@ public:
// methods needed by other threads to alter knob values, waveforms, etc
void lock()
{
m_globalMutex.lock();
}
void unlock()
{
m_globalMutex.unlock();
}
void lockInputFrames()
{
m_inputFramesMutex.lock();
@@ -429,7 +419,6 @@ private:
QString m_midiClientName;
// mutexes
QMutex m_globalMutex;
QMutex m_inputFramesMutex;
QMutex m_playHandleMutex; // mutex used only for adding playhandles
QMutex m_playHandleRemovalMutex;

View File

@@ -151,19 +151,16 @@ public:
void setLoopStartFrame( f_cnt_t _start )
{
QWriteLocker writeLocker(&m_varLock);
m_loopStartFrame = _start;
}
void setLoopEndFrame( f_cnt_t _end )
{
QWriteLocker writeLocker(&m_varLock);
m_loopEndFrame = _end;
}
void setAllPointFrames( f_cnt_t _start, f_cnt_t _end, f_cnt_t _loopstart, f_cnt_t _loopend )
{
QWriteLocker writeLocker(&m_varLock);
m_startFrame = _start;
m_endFrame = _end;
m_loopStartFrame = _loopstart;
@@ -202,13 +199,11 @@ public:
inline void setFrequency( float _freq )
{
QWriteLocker writeLocker(&m_varLock);
m_frequency = _freq;
}
inline void setSampleRate( sample_rate_t _rate )
{
QWriteLocker writeLocker(&m_varLock);
m_sampleRate = _rate;
}
@@ -224,31 +219,37 @@ public:
QString & toBase64( QString & _dst ) const;
static SampleBuffer * resample( sampleFrame * _data,
const f_cnt_t _frames,
const sample_rate_t _src_sr,
// protect calls from the GUI to this function with dataReadLock() and
// dataUnlock()
SampleBuffer * resample( const sample_rate_t _src_sr,
const sample_rate_t _dst_sr );
static inline SampleBuffer * resample( SampleBuffer * _buf,
const sample_rate_t _src_sr,
const sample_rate_t _dst_sr )
{
return resample( _buf->m_data, _buf->m_frames, _src_sr,
_dst_sr );
}
void normalizeSampleRate( const sample_rate_t _src_sr,
bool _keep_settings = false );
// protect calls from the GUI to this function with dataReadLock() and
// dataUnlock(), out of loops for efficiency
inline sample_t userWaveSample( const float _sample ) const
{
const float frame = _sample * m_frames;
f_cnt_t f1 = static_cast<f_cnt_t>( frame ) % m_frames;
f_cnt_t frames = m_frames;
sampleFrame * data = m_data;
const float frame = _sample * frames;
f_cnt_t f1 = static_cast<f_cnt_t>( frame ) % frames;
if( f1 < 0 )
{
f1 += m_frames;
f1 += frames;
}
return linearInterpolate( m_data[f1][0], m_data[ (f1 + 1) % m_frames ][0], fraction( frame ) );
return linearInterpolate( data[f1][0], data[ (f1 + 1) % frames ][0], fraction( frame ) );
}
void dataReadLock()
{
m_varLock.lockForRead();
}
void dataUnlock()
{
m_varLock.unlock();
}
static QString tryToMakeRelative( const QString & _file );

View File

@@ -31,9 +31,9 @@
#include "MidiTime.h"
#include "PlayHandle.h"
#include "SampleBuffer.h"
class BBTrack;
class SampleBuffer;
class SampleTCO;
class Track;

View File

@@ -43,6 +43,7 @@
#include "Mixer.h"
#include "NotePlayHandle.h"
#include "Knob.h"
#include "SampleBuffer.h"
#include "Song.h"
#include "ConfigManager.h"
#include "endian_handling.h"

View File

@@ -30,6 +30,7 @@
#include <QList>
#include <QMutex>
#include <QMutexLocker>
#include <samplerate.h>
#include "Instrument.h"
#include "PixmapButton.h"
@@ -37,7 +38,6 @@
#include "Knob.h"
#include "LcdSpinBox.h"
#include "LedCheckbox.h"
#include "SampleBuffer.h"
#include "MemoryManager.h"
#include "gig.h"

View File

@@ -36,6 +36,7 @@
#include "Mixer.h"
#include "NotePlayHandle.h"
#include "Knob.h"
#include "SampleBuffer.h"
#include "Song.h"
#include "patches_dialog.h"

View File

@@ -28,6 +28,7 @@
#define SF2_PLAYER_H
#include <QMutex>
#include <samplerate.h>
#include "Instrument.h"
#include "PixmapButton.h"
@@ -36,7 +37,6 @@
#include "LcdSpinBox.h"
#include "LedCheckbox.h"
#include "fluidsynth.h"
#include "SampleBuffer.h"
#include "MemoryManager.h"
class sf2InstrumentView;

View File

@@ -644,7 +644,7 @@ void VestigeInstrumentView::openPlugin()
{
return;
}
Engine::mixer()->lock();
Engine::mixer()->requestChangeInModel();
if (m_vi->p_subWindow != NULL) {
delete m_vi->p_subWindow;
@@ -652,7 +652,7 @@ void VestigeInstrumentView::openPlugin()
}
m_vi->loadFile( ofd.selectedFiles()[0] );
Engine::mixer()->unlock();
Engine::mixer()->doneChangeInModel();
if( m_vi->m_plugin && m_vi->m_plugin->pluginWidget() )
{
m_vi->m_plugin->pluginWidget()->setWindowIcon(

View File

@@ -122,9 +122,9 @@ void EffectChain::loadSettings( const QDomElement & _this )
void EffectChain::appendEffect( Effect * _effect )
{
Engine::mixer()->lock();
Engine::mixer()->requestChangeInModel();
m_effects.append( _effect );
Engine::mixer()->unlock();
Engine::mixer()->doneChangeInModel();
emit dataChanged();
}
@@ -134,21 +134,18 @@ void EffectChain::appendEffect( Effect * _effect )
void EffectChain::removeEffect( Effect * _effect )
{
Engine::mixer()->lock();
Engine::mixer()->requestChangeInModel();
Effect ** found = qFind( m_effects.begin(), m_effects.end(), _effect );
if( found == m_effects.end() )
{
goto fail;
Engine::mixer()->doneChangeInModel();
return;
}
m_effects.erase( found );
Engine::mixer()->unlock();
Engine::mixer()->doneChangeInModel();
emit dataChanged();
return;
fail:
Engine::mixer()->unlock();
}
@@ -252,7 +249,7 @@ void EffectChain::clear()
{
emit aboutToClear();
Engine::mixer()->lock();
Engine::mixer()->requestChangeInModel();
m_enabledModel.setValue( false );
for( int i = 0; i < m_effects.count(); ++i )
@@ -261,5 +258,5 @@ void EffectChain::clear()
}
m_effects.clear();
Engine::mixer()->unlock();
Engine::mixer()->doneChangeInModel();
}

View File

@@ -285,8 +285,8 @@ void FxMixer::toggledSolo()
void FxMixer::deleteChannel( int index )
{
// lock the mixer so channel deletion is performed between mixer rounds
Engine::mixer()->lock();
// channel deletion is performed between mixer rounds
Engine::mixer()->requestChangeInModel();
FxChannel * ch = m_fxChannels[index];
@@ -347,7 +347,7 @@ void FxMixer::deleteChannel( int index )
}
}
Engine::mixer()->unlock();
Engine::mixer()->doneChangeInModel();
}

View File

@@ -75,7 +75,6 @@ Mixer::Mixer( bool renderOnly ) :
m_audioDev( NULL ),
m_oldAudioDev( NULL ),
m_audioDevStartFailed( false ),
m_globalMutex( QMutex::Recursive ),
m_profiler(),
m_metronomeActive(false),
m_changesSignal( false ),
@@ -386,10 +385,6 @@ const surroundSampleFrame * Mixer::renderNextBuffer()
}
unlockPlayHandleRemoval();
// now we have to make sure no other thread does anything bad
// while we're acting...
lock();
// rotate buffers
m_writeBuffer = ( m_writeBuffer + 1 ) % m_poolDepth;
m_readBuffer = ( m_readBuffer + 1 ) % m_poolDepth;
@@ -453,8 +448,6 @@ const surroundSampleFrame * Mixer::renderNextBuffer()
// STAGE 3: do master mix in FX mixer
fxMixer->masterMix( m_writeBuf );
unlock();
emit nextAudioBuffer( m_readBuf );
@@ -481,7 +474,6 @@ const surroundSampleFrame * Mixer::renderNextBuffer()
void Mixer::clear()
{
// TODO: m_midiClient->noteOffAll();
lock();
lockPlayHandleRemoval();
for( PlayHandleList::Iterator it = m_playHandles.begin(); it != m_playHandles.end(); ++it )
{
@@ -493,7 +485,6 @@ void Mixer::clear()
}
}
unlockPlayHandleRemoval();
unlock();
}
@@ -620,9 +611,7 @@ void Mixer::removeAudioPort( AudioPort * _port )
_port );
if( it != m_audioPorts.end() )
{
lock();
m_audioPorts.erase( it );
unlock();
}
}
@@ -650,7 +639,7 @@ bool Mixer::addPlayHandle( PlayHandle* handle )
void Mixer::removePlayHandle( PlayHandle * _ph )
{
lockPlayHandleRemoval();
requestChangeInModel();
// check thread affinity as we must not delete play-handles
// which were created in a thread different than mixer thread
if( _ph->affinityMatters() &&
@@ -694,7 +683,7 @@ void Mixer::removePlayHandle( PlayHandle * _ph )
{
m_playHandlesToRemove.push_back( _ph );
}
unlockPlayHandleRemoval();
doneChangeInModel();
}
@@ -702,7 +691,7 @@ void Mixer::removePlayHandle( PlayHandle * _ph )
void Mixer::removePlayHandlesOfTypes( Track * _track, const quint8 types )
{
lockPlayHandleRemoval();
requestChangeInModel();
PlayHandleList::Iterator it = m_playHandles.begin();
while( it != m_playHandles.end() )
{
@@ -721,7 +710,7 @@ void Mixer::removePlayHandlesOfTypes( Track * _track, const quint8 types )
++it;
}
}
unlockPlayHandleRemoval();
doneChangeInModel();
}
@@ -729,18 +718,13 @@ void Mixer::removePlayHandlesOfTypes( Track * _track, const quint8 types )
bool Mixer::hasNotePlayHandles()
{
lock();
for( PlayHandleList::Iterator it = m_playHandles.begin(); it != m_playHandles.end(); ++it )
{
if( (*it)->type() == PlayHandle::TypeNotePlayHandle )
{
unlock();
return true;
}
}
unlock();
return false;
}

View File

@@ -170,6 +170,7 @@ void SampleBuffer::update( bool _keep_settings )
const bool lock = ( m_data != NULL );
if( lock )
{
Engine::mixer()->requestChangeInModel();
m_varLock.lockForWrite();
MM_FREE( m_data );
}
@@ -270,6 +271,7 @@ void SampleBuffer::update( bool _keep_settings )
if( lock )
{
m_varLock.unlock();
Engine::mixer()->doneChangeInModel();
}
emit sampleUpdated();
@@ -354,7 +356,7 @@ void SampleBuffer::normalizeSampleRate( const sample_rate_t _src_sr,
// do samplerate-conversion to our default-samplerate
if( _src_sr != Engine::mixer()->baseSampleRate() )
{
SampleBuffer * resampled = resample( this, _src_sr,
SampleBuffer * resampled = resample( _src_sr,
Engine::mixer()->baseSampleRate() );
MM_FREE( m_data );
m_frames = resampled->frames();
@@ -597,8 +599,6 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
const float _freq,
const LoopMode _loopmode )
{
QReadLocker readLocker(&m_varLock);
f_cnt_t startFrame = m_startFrame;
f_cnt_t endFrame = m_endFrame;
f_cnt_t loopStartFrame = m_loopStartFrame;
@@ -1147,12 +1147,12 @@ QString & SampleBuffer::toBase64( QString & _dst ) const
SampleBuffer * SampleBuffer::resample( sampleFrame * _data,
const f_cnt_t _frames,
const sample_rate_t _src_sr,
SampleBuffer * SampleBuffer::resample( const sample_rate_t _src_sr,
const sample_rate_t _dst_sr )
{
const f_cnt_t dst_frames = static_cast<f_cnt_t>( _frames /
sampleFrame * data = m_data;
const f_cnt_t frames = m_frames;
const f_cnt_t dst_frames = static_cast<f_cnt_t>( frames /
(float) _src_sr * (float) _dst_sr );
SampleBuffer * dst_sb = new SampleBuffer( dst_frames );
sampleFrame * dst_buf = dst_sb->m_origData;
@@ -1165,9 +1165,9 @@ SampleBuffer * SampleBuffer::resample( sampleFrame * _data,
{
SRC_DATA src_data;
src_data.end_of_input = 1;
src_data.data_in = _data[0];
src_data.data_in = data[0];
src_data.data_out = dst_buf[0];
src_data.input_frames = _frames;
src_data.input_frames = frames;
src_data.output_frames = dst_frames;
src_data.src_ratio = (double) _dst_sr / _src_sr;
if( ( error = src_process( state, &src_data ) ) )
@@ -1355,7 +1355,6 @@ void SampleBuffer::loadFromBase64( const QString & _data )
void SampleBuffer::setStartFrame( const f_cnt_t _s )
{
QWriteLocker writeLocker(&m_varLock);
m_startFrame = _s;
}
@@ -1364,7 +1363,6 @@ void SampleBuffer::setStartFrame( const f_cnt_t _s )
void SampleBuffer::setEndFrame( const f_cnt_t _e )
{
QWriteLocker writeLocker(&m_varLock);
m_endFrame = _e;
}

View File

@@ -790,7 +790,7 @@ void Song::clearProject()
}
Engine::mixer()->lock();
Engine::mixer()->requestChangeInModel();
if( gui && gui->getBBEditor() )
{
@@ -831,7 +831,7 @@ void Song::clearProject()
AutomationPattern::globalAutomationPattern( &m_masterPitchModel )->
clear();
Engine::mixer()->unlock();
Engine::mixer()->doneChangeInModel();
if( gui && gui->getProjectNotes() )
{
@@ -963,7 +963,7 @@ void Song::loadProject( const QString & fileName )
DataFile::LocaleHelper localeHelper( DataFile::LocaleHelper::ModeLoad );
Engine::mixer()->lock();
Engine::mixer()->requestChangeInModel();
// get the header information from the DOM
m_tempoModel.loadSettings( dataFile.head(), "bpm" );
@@ -1050,7 +1050,7 @@ void Song::loadProject( const QString & fileName )
AutomationPattern::resolveAllIDs();
Engine::mixer()->unlock();
Engine::mixer()->doneChangeInModel();
ConfigManager::inst()->addRecentlyOpenedProject( fileName );

View File

@@ -534,7 +534,7 @@ void FileBrowserTreeWidget::mouseReleaseEvent(QMouseEvent * me )
void FileBrowserTreeWidget::handleFile(FileItem * f, InstrumentTrack * it )
{
Engine::mixer()->lock();
Engine::mixer()->requestChangeInModel();
switch( f->handling() )
{
case FileItem::LoadAsProject:
@@ -582,7 +582,7 @@ void FileBrowserTreeWidget::handleFile(FileItem * f, InstrumentTrack * it )
break;
}
Engine::mixer()->unlock();
Engine::mixer()->doneChangeInModel();
}
@@ -604,12 +604,10 @@ void FileBrowserTreeWidget::activateListItem(QTreeWidgetItem * item,
}
else if( f->handling() != FileItem::NotSupported )
{
// engine::mixer()->lock();
InstrumentTrack * it = dynamic_cast<InstrumentTrack *>(
Track::create( Track::InstrumentTrack,
Engine::getBBTrackContainer() ) );
handleFile( f, it );
// engine::mixer()->unlock();
}
}
@@ -621,11 +619,9 @@ void FileBrowserTreeWidget::openInNewInstrumentTrack( TrackContainer* tc )
if( m_contextMenuItem->handling() == FileItem::LoadAsPreset ||
m_contextMenuItem->handling() == FileItem::LoadByPlugin )
{
// engine::mixer()->lock();
InstrumentTrack * it = dynamic_cast<InstrumentTrack *>(
Track::create( Track::InstrumentTrack, tc ) );
handleFile( m_contextMenuItem, it );
// engine::mixer()->unlock();
}
}

View File

@@ -508,6 +508,8 @@ void EnvelopeAndLfoView::paintEvent( QPaintEvent * )
osc_frames *= 100.0f;
}
// userWaveSample() may be used, called out of loop for efficiency
m_params->m_userWave.dataReadLock();
float old_y = 0;
for( int x = 0; x <= LFO_GRAPH_W; ++x )
{
@@ -558,6 +560,7 @@ void EnvelopeAndLfoView::paintEvent( QPaintEvent * )
graph_y_base + cur_y ) );
old_y = cur_y;
}
m_params->m_userWave.dataUnlock();
p.setPen( QColor( 201, 201, 225 ) );
int ms_per_osc = static_cast<int>( SECS_PER_LFO_OSCILLATION *

View File

@@ -585,11 +585,13 @@ QString graphModel::setWaveToUser()
QString fileName = sampleBuffer->openAndSetWaveformFile();
if( fileName.isEmpty() == false )
{
sampleBuffer->dataReadLock();
for( int i = 0; i < length(); i++ )
{
m_samples[i] = sampleBuffer->userWaveSample(
i / static_cast<float>( length() ) );
}
sampleBuffer->dataUnlock();
}
sharedObject::unref( sampleBuffer );