From abe61f289426e8bcbb96d80bff4a75c2159fd858 Mon Sep 17 00:00:00 2001 From: Javier Serrano Polo Date: Sat, 11 Jun 2016 02:50:12 +0200 Subject: [PATCH] Protect reads to SampleBuffer with read locks --- include/Oscillator.h | 4 +-- include/SampleBuffer.h | 38 +++++++++++++++----------- include/SampleRecordHandle.h | 2 +- plugins/GigPlayer/GigPlayer.cpp | 1 + plugins/GigPlayer/GigPlayer.h | 2 +- plugins/sf2_player/sf2_player.cpp | 1 + plugins/sf2_player/sf2_player.h | 2 +- src/core/EnvelopeAndLfoParameters.cpp | 3 ++ src/core/LfoController.cpp | 2 ++ src/core/Oscillator.cpp | 12 ++++++++ src/core/SampleBuffer.cpp | 31 +++++++++++++++------ src/gui/widgets/EnvelopeAndLfoView.cpp | 3 ++ src/gui/widgets/Graph.cpp | 2 ++ 13 files changed, 73 insertions(+), 30 deletions(-) diff --git a/include/Oscillator.h b/include/Oscillator.h index e146b5af0e1..f9e80c6de00 100644 --- a/include/Oscillator.h +++ b/include/Oscillator.h @@ -80,7 +80,7 @@ class EXPORT Oscillator } - inline void setUserWave( const SampleBuffer * _wave ) + inline void setUserWave( SampleBuffer * _wave ) { m_userWave = _wave; } @@ -164,7 +164,7 @@ class EXPORT Oscillator Oscillator * m_subOsc; float m_phaseOffset; float m_phase; - const SampleBuffer * m_userWave; + SampleBuffer * m_userWave; void updateNoSub( sampleFrame * _ab, const fpp_t _frames, diff --git a/include/SampleBuffer.h b/include/SampleBuffer.h index dbb2f71ace6..cdcfe11089d 100644 --- a/include/SampleBuffer.h +++ b/include/SampleBuffer.h @@ -225,31 +225,37 @@ class EXPORT SampleBuffer : public QObject, public sharedObject QString & toBase64( QString & _dst ) const; - static SampleBuffer * resample( sampleFrame * _data, - const f_cnt_t _frames, - 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 ); - } + // set lock to false if a lock has been acquired already + SampleBuffer * resample( const sample_rate_t _src_sr, + const sample_rate_t _dst_sr, + bool lock ); void normalizeSampleRate( const sample_rate_t _src_sr, bool _keep_settings = false ); + // protect calls 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( frame ) % m_frames; + f_cnt_t frames = m_frames; + sampleFrame * data = m_data; + const float frame = _sample * frames; + f_cnt_t f1 = static_cast( 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 ); diff --git a/include/SampleRecordHandle.h b/include/SampleRecordHandle.h index b6a44439674..2d38e464933 100644 --- a/include/SampleRecordHandle.h +++ b/include/SampleRecordHandle.h @@ -30,9 +30,9 @@ #include #include "Mixer.h" -#include "SampleBuffer.h" class BBTrack; +class SampleBuffer; class SampleTCO; class Track; diff --git a/plugins/GigPlayer/GigPlayer.cpp b/plugins/GigPlayer/GigPlayer.cpp index ac07420dd62..063917e4700 100644 --- a/plugins/GigPlayer/GigPlayer.cpp +++ b/plugins/GigPlayer/GigPlayer.cpp @@ -42,6 +42,7 @@ #include "InstrumentPlayHandle.h" #include "NotePlayHandle.h" #include "Knob.h" +#include "SampleBuffer.h" #include "Song.h" #include "ConfigManager.h" #include "endian_handling.h" diff --git a/plugins/GigPlayer/GigPlayer.h b/plugins/GigPlayer/GigPlayer.h index e637fcd6ac4..08a3b184cf5 100644 --- a/plugins/GigPlayer/GigPlayer.h +++ b/plugins/GigPlayer/GigPlayer.h @@ -30,6 +30,7 @@ #include #include #include +#include #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" diff --git a/plugins/sf2_player/sf2_player.cpp b/plugins/sf2_player/sf2_player.cpp index 50a39c34952..a7c5c8fa09a 100644 --- a/plugins/sf2_player/sf2_player.cpp +++ b/plugins/sf2_player/sf2_player.cpp @@ -35,6 +35,7 @@ #include "InstrumentPlayHandle.h" #include "NotePlayHandle.h" #include "Knob.h" +#include "SampleBuffer.h" #include "Song.h" #include "patches_dialog.h" diff --git a/plugins/sf2_player/sf2_player.h b/plugins/sf2_player/sf2_player.h index 2a6995c01d6..8996b3e14d4 100644 --- a/plugins/sf2_player/sf2_player.h +++ b/plugins/sf2_player/sf2_player.h @@ -28,6 +28,7 @@ #define SF2_PLAYER_H #include +#include #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; diff --git a/src/core/EnvelopeAndLfoParameters.cpp b/src/core/EnvelopeAndLfoParameters.cpp index 271bfd6f49c..9d5eb2b7fda 100644 --- a/src/core/EnvelopeAndLfoParameters.cpp +++ b/src/core/EnvelopeAndLfoParameters.cpp @@ -241,11 +241,14 @@ inline sample_t EnvelopeAndLfoParameters::lfoShapeSample( fpp_t _frame_offset ) void EnvelopeAndLfoParameters::updateLfoShapeData() { + // userWaveSample() may be used, called out of loop for efficiency + m_userWave.dataReadLock(); const fpp_t frames = Engine::mixer()->framesPerPeriod(); for( fpp_t offset = 0; offset < frames; ++offset ) { m_lfoShapeData[offset] = lfoShapeSample( offset ); } + m_userWave.dataUnlock(); m_bad_lfoShapeData = false; } diff --git a/src/core/LfoController.cpp b/src/core/LfoController.cpp index e1b20a492d3..fe3541e7e74 100644 --- a/src/core/LfoController.cpp +++ b/src/core/LfoController.cpp @@ -103,6 +103,7 @@ void LfoController::updateValueBuffer() int amountInc = amountBuffer ? 1 : 0; float *amountPtr = amountBuffer ? &(amountBuffer->values()[ 0 ] ) : &amount; + m_userDefSampleBuffer->dataReadLock(); for( int i = 0; i < m_valueBuffer.length(); i++ ) { const float currentSample = m_sampleFunction != NULL @@ -114,6 +115,7 @@ void LfoController::updateValueBuffer() phase += 1.0 / m_duration; amountPtr += amountInc; } + m_userDefSampleBuffer->dataUnlock(); m_currentPhase = absFraction( phase - m_phaseOffset ); } diff --git a/src/core/Oscillator.cpp b/src/core/Oscillator.cpp index 78be9315ff3..5ef1d64f6c2 100644 --- a/src/core/Oscillator.cpp +++ b/src/core/Oscillator.cpp @@ -119,7 +119,9 @@ void Oscillator::updateNoSub( sampleFrame * _ab, const fpp_t _frames, updateNoSub( _ab, _frames, _chnl ); break; case UserDefinedWave: + m_userWave->dataReadLock(); updateNoSub( _ab, _frames, _chnl ); + m_userWave->dataUnlock(); break; } } @@ -155,7 +157,9 @@ void Oscillator::updatePM( sampleFrame * _ab, const fpp_t _frames, updatePM( _ab, _frames, _chnl ); break; case UserDefinedWave: + m_userWave->dataReadLock(); updatePM( _ab, _frames, _chnl ); + m_userWave->dataUnlock(); break; } } @@ -191,7 +195,9 @@ void Oscillator::updateAM( sampleFrame * _ab, const fpp_t _frames, updateAM( _ab, _frames, _chnl ); break; case UserDefinedWave: + m_userWave->dataReadLock(); updateAM( _ab, _frames, _chnl ); + m_userWave->dataUnlock(); break; } } @@ -227,7 +233,9 @@ void Oscillator::updateMix( sampleFrame * _ab, const fpp_t _frames, updateMix( _ab, _frames, _chnl ); break; case UserDefinedWave: + m_userWave->dataReadLock(); updateMix( _ab, _frames, _chnl ); + m_userWave->dataUnlock(); break; } } @@ -263,7 +271,9 @@ void Oscillator::updateSync( sampleFrame * _ab, const fpp_t _frames, updateSync( _ab, _frames, _chnl ); break; case UserDefinedWave: + m_userWave->dataReadLock(); updateSync( _ab, _frames, _chnl ); + m_userWave->dataUnlock(); break; } } @@ -299,7 +309,9 @@ void Oscillator::updateFM( sampleFrame * _ab, const fpp_t _frames, updateFM( _ab, _frames, _chnl ); break; case UserDefinedWave: + m_userWave->dataReadLock(); updateFM( _ab, _frames, _chnl ); + m_userWave->dataUnlock(); break; } } diff --git a/src/core/SampleBuffer.cpp b/src/core/SampleBuffer.cpp index 7040babcba0..67987531d3a 100644 --- a/src/core/SampleBuffer.cpp +++ b/src/core/SampleBuffer.cpp @@ -353,8 +353,9 @@ 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, - Engine::mixer()->baseSampleRate() ); + SampleBuffer * resampled = resample( _src_sr, + Engine::mixer()->baseSampleRate(), + false ); MM_FREE( m_data ); m_frames = resampled->frames(); m_data = MM_ALLOC( sampleFrame, m_frames ); @@ -1146,12 +1147,18 @@ QString & SampleBuffer::toBase64( QString & _dst ) const -SampleBuffer * SampleBuffer::resample( sampleFrame * _data, - const f_cnt_t _frames, - const sample_rate_t _src_sr, - const sample_rate_t _dst_sr ) +SampleBuffer * SampleBuffer::resample( const sample_rate_t _src_sr, + const sample_rate_t _dst_sr, + bool lock ) { - const f_cnt_t dst_frames = static_cast( _frames / + if( lock ) + { + m_varLock.lockForRead(); + } + + sampleFrame * data = m_data; + const f_cnt_t frames = m_frames; + const f_cnt_t dst_frames = static_cast( frames / (float) _src_sr * (float) _dst_sr ); SampleBuffer * dst_sb = new SampleBuffer( dst_frames ); sampleFrame * dst_buf = dst_sb->m_origData; @@ -1164,9 +1171,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 ) ) ) @@ -1180,6 +1187,12 @@ SampleBuffer * SampleBuffer::resample( sampleFrame * _data, { printf( "Error: src_new() failed in sample_buffer.cpp!\n" ); } + + if( lock ) + { + m_varLock.unlock(); + } + dst_sb->update(); return dst_sb; } diff --git a/src/gui/widgets/EnvelopeAndLfoView.cpp b/src/gui/widgets/EnvelopeAndLfoView.cpp index 5c364c19bd2..c6598d4f5b3 100644 --- a/src/gui/widgets/EnvelopeAndLfoView.cpp +++ b/src/gui/widgets/EnvelopeAndLfoView.cpp @@ -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( SECS_PER_LFO_OSCILLATION * diff --git a/src/gui/widgets/Graph.cpp b/src/gui/widgets/Graph.cpp index 3fea035cde1..ead7ee86c59 100644 --- a/src/gui/widgets/Graph.cpp +++ b/src/gui/widgets/Graph.cpp @@ -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( length() ) ); } + sampleBuffer->dataUnlock(); } sharedObject::unref( sampleBuffer );