From d331dfe352ea7e3aef07a8d98aa71985f9586434 Mon Sep 17 00:00:00 2001 From: Vesa Date: Tue, 20 May 2014 15:34:53 +0300 Subject: [PATCH] Move improvements to sample-exact controller handling, also some coding style fixes --- include/AutomatableModel.h | 8 ++++---- include/Controller.h | 6 +++--- include/song.h | 15 +++++++++++++-- src/core/AutomatableModel.cpp | 12 ++++++------ src/core/Controller.cpp | 9 +++++++-- src/core/LfoController.cpp | 22 ++++++++++++++++------ src/core/song.cpp | 6 ++++++ 7 files changed, 55 insertions(+), 23 deletions(-) diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index 76ea20efa..d0c0aab87 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -256,14 +256,14 @@ public: float globalAutomationValueAt( const MidiTime& time ); - bool strictStepSize() const + bool hasStrictStepSize() const { - return m_strictStepSize; + return m_hasStrictStepSize; } void setStrictStepSize( const bool b ) { - m_strictStepSize = b; + m_hasStrictStepSize = b; } public slots: @@ -320,7 +320,7 @@ private: // used to determine if step size should be applied strictly (ie. always) // or only when value set from gui (default) - bool m_strictStepSize; + bool m_hasStrictStepSize; AutoModelVector m_linkedModels; bool m_hasLinkedModels; diff --git a/include/Controller.h b/include/Controller.h index 209df5d1f..4a7a754e4 100644 --- a/include/Controller.h +++ b/include/Controller.h @@ -114,7 +114,7 @@ public: return tLimit( _val, 0.0f, 1.0f ); } - static unsigned int runningPeriods() + static long runningPeriods() { return s_periods; } @@ -152,7 +152,7 @@ protected: // again every time ValueBuffer m_valueBuffer; // when we last updated the valuebuffer - so we know if we have to update it - unsigned int m_bufferLastUpdated; + long m_bufferLastUpdated; float m_currentValue; bool m_sampleExact; @@ -163,7 +163,7 @@ protected: static ControllerVector s_controllers; - static unsigned int s_periods; + static long s_periods; signals: diff --git a/include/song.h b/include/song.h index dc58a8d94..e5f938712 100644 --- a/include/song.h +++ b/include/song.h @@ -22,8 +22,8 @@ * */ -#ifndef _SONG_H -#define _SONG_H +#ifndef SONG_H +#define SONG_H #include #include @@ -131,6 +131,10 @@ public: { return currentTick(); } + inline f_cnt_t getFrames() const + { + return currentFrame(); + } inline bool isTempoAutomated() { return m_tempoModel.isAutomated(); @@ -310,6 +314,12 @@ private: { return m_playPos[m_playMode].getTicks(); } + + inline f_cnt_t currentFrame() const + { + return m_playPos[m_playMode].getTicks() * engine::framesPerTick() + m_playPos[m_playMode].currentFrame(); + } + void setPlayPos( tick_t _ticks, PlayModes _play_mode ); void saveControllerStates( QDomDocument & _doc, QDomElement & _this ); @@ -362,6 +372,7 @@ private: signals: void projectLoaded(); void playbackStateChanged(); + void playbackPositionChanged(); void lengthChanged( int _tacts ); void tempoChanged( bpm_t _new_bpm ); void timeSignatureChanged( int _old_ticks_per_tact, diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index cbf903257..fa2d4c3e2 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -48,7 +48,7 @@ AutomatableModel::AutomatableModel( DataType type, m_range( max - min ), m_centerValue( m_minValue ), m_setValueDepth( 0 ), - m_strictStepSize( false ), + m_hasStrictStepSize( false ), m_hasLinkedModels( false ), m_controllerConnection( NULL ), m_valueBuffer( static_cast( engine::mixer()->framesPerPeriod() ) ) @@ -331,7 +331,7 @@ void AutomatableModel::setAutomatedValue( const float value ) ++m_setValueDepth; const float oldValue = m_value; - const float scaled_value = + const float scaledValue = ( m_scaleType == Linear ) ? value : logToLinearScale( @@ -339,7 +339,7 @@ void AutomatableModel::setAutomatedValue( const float value ) (value - minValue()) / maxValue() ); - m_value = fittedValue( scaled_value ); + m_value = fittedValue( scaledValue ); if( oldValue != m_value ) { @@ -405,7 +405,7 @@ float AutomatableModel::fittedValue( float value, bool forceStep ) const { value = tLimit( value, m_minValue, m_maxValue ); - if( m_step != 0 && ( m_strictStepSize || forceStep ) ) + if( m_step != 0 && ( m_hasStrictStepSize || forceStep ) ) { value = nearbyintf( value / m_step ) * m_step; } @@ -526,7 +526,7 @@ float AutomatableModel::controllerValue( int frameOffset ) const "lacks implementation for a scale type"); break; } - if( typeInfo::isEqual( m_step, 1 ) && m_strictStepSize ) + if( typeInfo::isEqual( m_step, 1 ) && m_hasStrictStepSize ) { return qRound( v ); } @@ -710,7 +710,7 @@ float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) // fits value into [0,1]: (value - minValue()) / maxValue() ); - return fittedValue( scaled_value ); + return fittedValue( scaledValue ); } // if we still find no pattern, the value at that time is undefined so // just return current value as the best we can do diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp index 2ca1dacc2..2618fe588 100644 --- a/src/core/Controller.cpp +++ b/src/core/Controller.cpp @@ -40,7 +40,7 @@ #include "PeakController.h" -unsigned int Controller::s_periods = 0; +long Controller::s_periods = 0; QVector Controller::s_controllers; @@ -50,7 +50,7 @@ Controller::Controller( ControllerTypes _type, Model * _parent, Model( _parent, _display_name ), JournallingObject(), m_valueBuffer( engine::mixer()->framesPerPeriod() ), - m_bufferLastUpdated( 0 ), + m_bufferLastUpdated( -1 ), m_connectionCount( 0 ), m_type( _type ) { @@ -82,6 +82,7 @@ Controller::Controller( ControllerTypes _type, Model * _parent, } } } + updateValueBuffer(); } @@ -184,6 +185,10 @@ void Controller::triggerFrameCounter() void Controller::resetFrameCounter() { + for( int i = 0; i < s_controllers.size(); ++i ) + { + s_controllers.at( i )->m_bufferLastUpdated = 0; + } s_periods = 0; } diff --git a/src/core/LfoController.cpp b/src/core/LfoController.cpp index 16c70c4d3..5ae601066 100644 --- a/src/core/LfoController.cpp +++ b/src/core/LfoController.cpp @@ -66,6 +66,8 @@ LfoController::LfoController( Model * _parent ) : connect( engine::getSong(), SIGNAL( playbackStateChanged() ), this, SLOT( updatePhase() ) ); + connect( engine::getSong(), SIGNAL( playbackPositionChanged() ), + this, SLOT( updatePhase() ) ); updateDuration(); } @@ -87,11 +89,19 @@ LfoController::~LfoController() void LfoController::updateValueBuffer() { - m_phaseOffset = m_phaseModel.value() / 360.0; - - float * values = m_valueBuffer.values(); - + m_phaseOffset = m_phaseModel.value() / 360.0; + float * values = m_valueBuffer.values(); float phase = m_currentPhase + m_phaseOffset; + + // roll phase up until we're in sync with period counter + m_bufferLastUpdated++; + while( m_bufferLastUpdated != s_periods ) + { + phase += static_cast( engine::framesPerTick() ) / m_duration; + m_bufferLastUpdated++; + } + + for( int i = 0; i < m_valueBuffer.length(); i++ ) { const float currentSample = m_sampleFunction != NULL @@ -104,13 +114,13 @@ void LfoController::updateValueBuffer() } m_currentPhase = absFraction( phase - m_phaseOffset ); - m_bufferLastUpdated = s_periods; } void LfoController::updatePhase() { - m_currentPhase = ( engine::getSong()->getTicks() * engine::framesPerTick() ) / m_duration; + m_currentPhase = ( engine::getSong()->getFrames() ) / m_duration; + m_bufferLastUpdated = s_periods - 1; } diff --git a/src/core/song.cpp b/src/core/song.cpp index 5f3719a8a..735bfdba4 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -523,6 +523,12 @@ void song::setPlayPos( tick_t _ticks, PlayModes _play_mode ) m_elapsedMilliSeconds += (((( _ticks - m_playPos[_play_mode].getTicks()))*60*1000/48)/getTempo()); m_playPos[_play_mode].setTicks( _ticks ); m_playPos[_play_mode].setCurrentFrame( 0.0f ); + +// send a signal if playposition changes during playback + if( isPlaying() ) + { + emit playbackPositionChanged(); + } }