diff --git a/include/envelope_and_lfo_widget.h b/include/envelope_and_lfo_widget.h index 9d7699ad4..9afdce14a 100644 --- a/include/envelope_and_lfo_widget.h +++ b/include/envelope_and_lfo_widget.h @@ -89,7 +89,7 @@ public: float FASTCALL level( f_cnt_t _frame, const f_cnt_t _release_begin, - const f_cnt_t _frame_offset ) const; + const f_cnt_t _frame_offset ); inline bool used( void ) const { @@ -105,6 +105,15 @@ public: return( "el" ); } + void lock( void ) + { + m_busyMutex.lock(); + } + void unlock( void ) + { + m_busyMutex.unlock(); + } + public slots: void updateSampleVars( void ); @@ -183,7 +192,7 @@ private: USER } m_lfoShape; - volatile bool m_busy; + QMutex m_busyMutex; diff --git a/src/core/envelope_and_lfo_widget.cpp b/src/core/envelope_and_lfo_widget.cpp index 3342146a0..9928353c4 100644 --- a/src/core/envelope_and_lfo_widget.cpp +++ b/src/core/envelope_and_lfo_widget.cpp @@ -124,8 +124,7 @@ envelopeAndLFOWidget::envelopeAndLFOWidget( float _value_for_zero_amount, m_lfoAmountIsZero( FALSE ), m_lfoShapeData( NULL ), m_userWave( eng() ), - m_lfoShape( SIN ), - m_busy( FALSE ) + m_lfoShape( SIN ) { if( s_envGraph == NULL ) { @@ -564,12 +563,8 @@ inline float FASTCALL envelopeAndLFOWidget::lfoLevel( f_cnt_t _frame, float FASTCALL envelopeAndLFOWidget::level( f_cnt_t _frame, const f_cnt_t _release_begin, - const f_cnt_t _frame_offset ) const + const f_cnt_t _frame_offset ) { - if( m_busy ) - { - return( 0.0f ); - } const float lfo_level = lfoLevel( _frame, _frame_offset ); float env_level; if( _frame < _release_begin && _frame < m_pahdFrames ) @@ -629,7 +624,7 @@ void envelopeAndLFOWidget::saveSettings( QDomDocument & _doc, void envelopeAndLFOWidget::loadSettings( const QDomElement & _this ) { - m_busy = TRUE; + m_busyMutex.lock(); m_predelayKnob->loadSettings( _this, "pdel" ); m_attackKnob->loadSettings( _this, "att" ); @@ -650,7 +645,7 @@ void envelopeAndLFOWidget::loadSettings( const QDomElement & _this ) "lfosyncmode" ).toInt() ); m_userWave.setAudioFile( _this.attribute( "userwavefile" ) ); - m_busy = FALSE; + m_busyMutex.unlock(); updateSampleVars(); update(); @@ -910,176 +905,166 @@ void envelopeAndLFOWidget::paintEvent( QPaintEvent * ) void envelopeAndLFOWidget::updateSampleVars( void ) { - if( !m_busy ) - { - m_busy = TRUE; + m_busyMutex.lock(); - const float frames_per_env_seg = SECS_PER_ENV_SEGMENT * + const float frames_per_env_seg = SECS_PER_ENV_SEGMENT * eng()->getMixer()->sampleRate(); - const f_cnt_t predelay_frames = static_cast( + const f_cnt_t predelay_frames = static_cast( frames_per_env_seg * expKnobVal( m_predelayKnob->value() ) ); - const f_cnt_t attack_frames = static_cast( - frames_per_env_seg * + const f_cnt_t attack_frames = static_cast( frames_per_env_seg * expKnobVal( m_attackKnob->value() ) ); - const f_cnt_t hold_frames = static_cast( - frames_per_env_seg * + const f_cnt_t hold_frames = static_cast( frames_per_env_seg * expKnobVal( m_holdKnob->value() ) ); - const f_cnt_t decay_frames = static_cast( - frames_per_env_seg * + const f_cnt_t decay_frames = static_cast( frames_per_env_seg * expKnobVal( m_decayKnob->value() * m_sustainKnob->value() ) ); - m_sustainLevel = 1.0f - m_sustainKnob->value(); - m_amount = m_amountKnob->value(); - if( m_amount >= 0 ) - { - m_amountAdd = ( 1.0f - m_amount ) * - m_valueForZeroAmount; - } - else - { - m_amountAdd = m_valueForZeroAmount; - } + m_sustainLevel = 1.0f - m_sustainKnob->value(); + m_amount = m_amountKnob->value(); + if( m_amount >= 0 ) + { + m_amountAdd = ( 1.0f - m_amount ) * m_valueForZeroAmount; + } + else + { + m_amountAdd = m_valueForZeroAmount; + } - m_pahdFrames = predelay_frames + attack_frames + hold_frames + + m_pahdFrames = predelay_frames + attack_frames + hold_frames + decay_frames; - m_rFrames = static_cast( frames_per_env_seg * + m_rFrames = static_cast( frames_per_env_seg * expKnobVal( m_releaseKnob->value() ) ); - if( static_cast( floorf( m_amount * 1000.0f ) ) == 0 ) - { - //m_pahdFrames = 0; - m_rFrames = 0; - } + if( static_cast( floorf( m_amount * 1000.0f ) ) == 0 ) + { + //m_pahdFrames = 0; + m_rFrames = 0; + } - sample_t * new_pahd_env = new sample_t[m_pahdFrames]; - sample_t * new_r_env = new sample_t[m_rFrames]; + sample_t * new_pahd_env = new sample_t[m_pahdFrames]; + sample_t * new_r_env = new sample_t[m_rFrames]; - for( f_cnt_t i = 0; i < predelay_frames; ++i ) - { - new_pahd_env[i] = m_amountAdd; - } + for( f_cnt_t i = 0; i < predelay_frames; ++i ) + { + new_pahd_env[i] = m_amountAdd; + } - f_cnt_t add = predelay_frames; + f_cnt_t add = predelay_frames; - for( f_cnt_t i = 0; i < attack_frames; ++i ) - { - new_pahd_env[add+i] = ( (float)i / attack_frames ) * + for( f_cnt_t i = 0; i < attack_frames; ++i ) + { + new_pahd_env[add+i] = ( (float)i / attack_frames ) * m_amount + m_amountAdd; - } + } - add += attack_frames; - for( f_cnt_t i = 0; i < hold_frames; ++i ) - { - new_pahd_env[add+i] = m_amount + m_amountAdd; - } + add += attack_frames; + for( f_cnt_t i = 0; i < hold_frames; ++i ) + { + new_pahd_env[add+i] = m_amount + m_amountAdd; + } - add += hold_frames; - for( f_cnt_t i = 0; i < decay_frames; ++i ) - { - new_pahd_env[add+i] = ( m_sustainLevel + ( 1.0f - + add += hold_frames; + for( f_cnt_t i = 0; i < decay_frames; ++i ) + { + new_pahd_env[add+i] = ( m_sustainLevel + ( 1.0f - (float)i / decay_frames ) * ( 1.0f - m_sustainLevel ) ) * m_amount + m_amountAdd; - } + } - delete[] m_pahdEnv; - delete[] m_rEnv; + delete[] m_pahdEnv; + delete[] m_rEnv; - m_pahdEnv = new_pahd_env; - m_rEnv = new_r_env; + m_pahdEnv = new_pahd_env; + m_rEnv = new_r_env; - for( f_cnt_t i = 0; i < m_rFrames; ++i ) - { - new_r_env[i] = ( (float)( m_rFrames - i ) / m_rFrames + for( f_cnt_t i = 0; i < m_rFrames; ++i ) + { + new_r_env[i] = ( (float)( m_rFrames - i ) / m_rFrames // * m_sustainLevel ) * m_amount; - } + } - // save this calculation in real-time-part - m_sustainLevel = m_sustainLevel * m_amount + m_amountAdd; - + // save this calculation in real-time-part + m_sustainLevel = m_sustainLevel * m_amount + m_amountAdd; - const float frames_per_lfo_oscillation = - SECS_PER_LFO_OSCILLATION * + + const float frames_per_lfo_oscillation = SECS_PER_LFO_OSCILLATION * eng()->getMixer()->sampleRate(); - m_lfoPredelayFrames = static_cast( - frames_per_lfo_oscillation * + m_lfoPredelayFrames = static_cast( frames_per_lfo_oscillation * expKnobVal( m_lfoPredelayKnob->value() ) ); - m_lfoAttackFrames = static_cast( - frames_per_lfo_oscillation * + m_lfoAttackFrames = static_cast( frames_per_lfo_oscillation * expKnobVal( m_lfoAttackKnob->value() ) ); - m_lfoOscillationFrames = static_cast( + m_lfoOscillationFrames = static_cast( frames_per_lfo_oscillation * m_lfoSpeedKnob->value() ); - if( m_x100Cb->isChecked() ) - { - m_lfoOscillationFrames /= 100; - } - m_lfoAmount = m_lfoAmountKnob->value() * 0.5f; - - m_used = TRUE; - if( static_cast( floorf( m_lfoAmount * 1000.0f ) ) == 0 ) - { - m_lfoAmountIsZero = TRUE; - if( static_cast( floorf( m_amount * 1000.0f ) ) == - 0 ) - { - m_used = FALSE; - } - } - else - { - m_lfoAmountIsZero = FALSE; - } - - if( m_lfoAmountIsZero == FALSE ) - { - delete[] m_lfoShapeData; - m_lfoShapeData = new sample_t[m_lfoOscillationFrames]; - for( f_cnt_t frame = 0; frame < m_lfoOscillationFrames; - ++frame ) - { - const float phase = frame / static_cast( - m_lfoOscillationFrames ); - // hope, compiler optimizes well and places - // branches out of loop and generates one loop - // for each branch... - switch( m_lfoShape ) - { - case TRIANGLE: - m_lfoShapeData[frame] = - oscillator::triangleSample( phase ); - break; - - case SQUARE: - m_lfoShapeData[frame] = - oscillator::squareSample( phase ); - break; - - case SAW: - m_lfoShapeData[frame] = - oscillator::sawSample( phase ); - break; - case USER: - m_lfoShapeData[frame] = - m_userWave.userWaveSample( phase ); - break; - case SIN: - default: - m_lfoShapeData[frame] = - oscillator::sinSample( phase ); - break; - } - m_lfoShapeData[frame] *= m_lfoAmount; - } - } - m_busy = FALSE; + if( m_x100Cb->isChecked() ) + { + m_lfoOscillationFrames /= 100; } + m_lfoAmount = m_lfoAmountKnob->value() * 0.5f; + + m_used = TRUE; + if( static_cast( floorf( m_lfoAmount * 1000.0f ) ) == 0 ) + { + m_lfoAmountIsZero = TRUE; + if( static_cast( floorf( m_amount * 1000.0f ) ) == 0 ) + { + m_used = FALSE; + } + } + else + { + m_lfoAmountIsZero = FALSE; + } + + if( m_lfoAmountIsZero == FALSE ) + { + delete[] m_lfoShapeData; + m_lfoShapeData = new sample_t[m_lfoOscillationFrames]; + for( f_cnt_t frame = 0; frame < m_lfoOscillationFrames; + ++frame ) + { + const float phase = frame / static_cast( + m_lfoOscillationFrames ); + // in gcc, optimization level 3 may place + // branches out of loop and generates one loop + // for each branch... + switch( m_lfoShape ) + { + case TRIANGLE: + m_lfoShapeData[frame] = + oscillator::triangleSample( phase ); + break; + + case SQUARE: + m_lfoShapeData[frame] = + oscillator::squareSample( phase ); + break; + + case SAW: + m_lfoShapeData[frame] = + oscillator::sawSample( phase ); + break; + case USER: + m_lfoShapeData[frame] = + m_userWave.userWaveSample( phase ); + break; + case SIN: + default: + m_lfoShapeData[frame] = + oscillator::sinSample( phase ); + break; + } + m_lfoShapeData[frame] *= m_lfoAmount; + } + } + + m_busyMutex.unlock(); } diff --git a/src/core/envelope_tab_widget.cpp b/src/core/envelope_tab_widget.cpp index 6754f184a..8c80785cd 100644 --- a/src/core/envelope_tab_widget.cpp +++ b/src/core/envelope_tab_widget.cpp @@ -238,7 +238,12 @@ float FASTCALL envelopeTabWidget::volumeLevel( notePlayHandle * _n, release_begin += eng()->getMixer()->framesPerAudioBuffer(); } - return( m_envLFOWidgets[VOLUME]->level( _frame, release_begin, 0 ) ); + m_envLFOWidgets[VOLUME]->lock(); + float volume_level = + m_envLFOWidgets[VOLUME]->level( _frame, release_begin, 0 ); + m_envLFOWidgets[VOLUME]->unlock(); + + return( volume_level ); } @@ -277,6 +282,10 @@ void envelopeTabWidget::processAudioBuffer( sampleFrame * _ab, eng()->getMixer()->sampleRate() ); } + m_envLFOWidgets[VOLUME]->lock(); + m_envLFOWidgets[CUT]->lock(); + m_envLFOWidgets[RES]->lock(); + if( m_filterGroupBox->isActive() ) { int old_filter_cut = 0; @@ -457,6 +466,10 @@ void envelopeTabWidget::processAudioBuffer( sampleFrame * _ab, } } }*/ + + m_envLFOWidgets[RES]->unlock(); + m_envLFOWidgets[CUT]->unlock(); + m_envLFOWidgets[VOLUME]->unlock(); }