From 7511380b45800b2d53eb648d519f249aff09ff86 Mon Sep 17 00:00:00 2001 From: Paul Giblock Date: Wed, 9 Apr 2008 06:19:44 +0000 Subject: [PATCH] Some improvements to LFO controller git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@906 0778d3d1-df1d-0410-868b-ea421aaaa00d --- ChangeLog | 12 ++++++++ include/controller.h | 6 ++++ include/lfo_controller.h | 8 ++++-- src/core/controller.cpp | 6 ++-- src/core/lfo_controller.cpp | 25 ++++++++++++---- src/gui/lfo_controller_dialog.cpp | 48 +++++++++++++++++++------------ 6 files changed, 75 insertions(+), 30 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7aca462e84..19936ea325 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2008-04-09 Paul Giblock + + * include/controller.h: + * src/core/controller.cpp: + fit values between 0.0 and 1.0 + + * include/lfo_controller.h: + * src/gui/lfo_controller_dialog.cpp: + * src/core/lfo_controller.cpp: + add more parameters to LFO controller + + 2008-04-08 Paul Giblock * include/engine.h: diff --git a/include/controller.h b/include/controller.h index 79723d38f4..8e1cbd0084 100644 --- a/include/controller.h +++ b/include/controller.h @@ -33,6 +33,7 @@ #include "engine.h" #include "mixer.h" #include "mv_base.h" +#include "templates.h" class controllerDialog; class controller; @@ -64,6 +65,11 @@ public: return "Dummy Controller"; } + inline static float fittedValue( float _val ) + { + return tLimit( _val, 0.0f, 1.0f ); + } + static int runningFrames(); static float runningTime(); diff --git a/include/lfo_controller.h b/include/lfo_controller.h index 125aa1a0b6..b715d0c2d5 100644 --- a/include/lfo_controller.h +++ b/include/lfo_controller.h @@ -78,13 +78,15 @@ slots: */ - floatModel m_lfoAttackModel; + floatModel m_lfoBaseModel; tempoSyncKnobModel m_lfoSpeedModel; floatModel m_lfoAmountModel; + floatModel m_lfoPhaseModel; intModel m_lfoWaveModel; int m_duration; int m_phaseCorrection; + int m_phaseOffset; friend class lfoControllerDialog; @@ -116,9 +118,11 @@ protected: lfoController * m_lfo; - knob * m_lfoAttackKnob; + knob * m_lfoBaseKnob; tempoSyncKnob * m_lfoSpeedKnob; knob * m_lfoAmountKnob; + knob * m_lfoPhaseKnob; + pixmapButton * m_userLfoBtn; automatableButtonGroup * m_lfoWaveBtnGrp; diff --git a/src/core/controller.cpp b/src/core/controller.cpp index 82ffb4956f..275e8c6691 100644 --- a/src/core/controller.cpp +++ b/src/core/controller.cpp @@ -25,7 +25,6 @@ * */ -#include #include #include #include @@ -60,7 +59,7 @@ float controller::currentValue( int _offset ) { if( _offset == 0 || isSampleExact() ) { - m_currentValue = value( _offset ); + m_currentValue = fittedValue( value( _offset ) ); } return m_currentValue; @@ -69,8 +68,7 @@ float controller::currentValue( int _offset ) float controller::value( int _offset ) { - // 44100 frames/sec - return 0.5 + sinf((float)(runningFrames()) / 44100.0f) / 2; + return 0.5f; } diff --git a/src/core/lfo_controller.cpp b/src/core/lfo_controller.cpp index b6e592a954..b809fd5b10 100644 --- a/src/core/lfo_controller.cpp +++ b/src/core/lfo_controller.cpp @@ -41,36 +41,47 @@ const float TWO_PI = 6.28318531f; lfoController::lfoController( model * _parent ) : controller( _parent ), - m_lfoAttackModel( 0.0, 0.0, 1.0, 0.001, this ), + m_lfoBaseModel( 0.5, 0.0, 1.0, 0.001, this ), m_lfoSpeedModel( 0.1, 0.01, 5.0, 0.0001, 20000.0, this ), m_lfoAmountModel( 1.0, -1.0, 1.0, 0.005, this ), + m_lfoPhaseModel( 0.0, 0.0, 360.0, 4.0, this ), m_lfoWaveModel( SineWave, 0, NumLfoShapes, 1, this ), m_duration( 1000 ), - m_phaseCorrection( 0 ) + m_phaseCorrection( 0 ), + m_phaseOffset( 0 ) { } lfoController::~lfoController() { - m_lfoAttackModel.disconnect( this ); + m_lfoBaseModel.disconnect( this ); m_lfoSpeedModel.disconnect( this ); m_lfoAmountModel.disconnect( this ); m_lfoWaveModel.disconnect( this ); + m_lfoPhaseModel.disconnect( this ); } + // This code took forever to get right. It can -// definately be optimized a bit. +// definately be optimized. +// The code should probably be integrated with the oscillator class. But I +// don't know how to use oscillator because it is so confusing + float lfoController::value( int _offset ) { int frame = runningFrames() + _offset + m_phaseCorrection; // Recalculate speed each period + // Actually, _offset != only if HQ, and we may want to recalc in that case, + // so this statement may be unrequired if (_offset == 0) { // The new duration in frames // (Samples/Second) / (periods/second) = (Samples/cycle) int newDuration = engine::getMixer()->sampleRate() / m_lfoSpeedModel.value(); + + m_phaseOffset = m_lfoPhaseModel.value() * newDuration / 360.0; if (newDuration != m_duration) { // frame offset @@ -99,13 +110,15 @@ float lfoController::value( int _offset ) frame = runningFrames() + m_phaseCorrection; m_duration = newDuration; + } } // 44100 frames/sec - return 0.5 + (m_lfoAmountModel.value() * - sinf( TWO_PI * float(frame * m_lfoSpeedModel.value()) / engine::getMixer()->sampleRate() ) / 2.0f); + return m_lfoBaseModel.value() + ( m_lfoAmountModel.value() * + sinf( TWO_PI * float( ( frame+m_phaseOffset ) * m_lfoSpeedModel.value() ) / + engine::getMixer()->sampleRate() ) / 2.0f ); } diff --git a/src/gui/lfo_controller_dialog.cpp b/src/gui/lfo_controller_dialog.cpp index cc8e66ac6c..0e56cc92ad 100644 --- a/src/gui/lfo_controller_dialog.cpp +++ b/src/gui/lfo_controller_dialog.cpp @@ -54,10 +54,11 @@ const int KNOB_X_SPACING = 32; const int LFO_GRAPH_X = 6; const int LFO_GRAPH_Y = ENV_KNOBS_LBL_Y+14; const int LFO_KNOB_Y = LFO_GRAPH_Y-2; -const int LFO_PREDELAY_KNOB_X = LFO_GRAPH_X + 10; -const int LFO_ATTACK_KNOB_X = LFO_PREDELAY_KNOB_X+KNOB_X_SPACING; -const int LFO_SPEED_KNOB_X = LFO_ATTACK_KNOB_X+KNOB_X_SPACING; +const int LFO_BASE_KNOB_X = LFO_GRAPH_X + 10; +const int LFO_SPEED_KNOB_X = LFO_BASE_KNOB_X+KNOB_X_SPACING; const int LFO_AMOUNT_KNOB_X = LFO_SPEED_KNOB_X+KNOB_X_SPACING; +const int LFO_PHASE_KNOB_X = LFO_AMOUNT_KNOB_X+KNOB_X_SPACING; + const int LFO_SHAPES_X = LFO_GRAPH_X;//PREDELAY_KNOB_X; const int LFO_SHAPES_Y = LFO_GRAPH_Y + 50; @@ -66,19 +67,14 @@ lfoControllerDialog::lfoControllerDialog( controller * _model, QWidget * _parent { setFixedSize( 256, 64 ); - toolTip::add( this, tr( "Poor lonely controller" ) ); + toolTip::add( this, tr( "LFO Controller" ) ); - - - m_lfoAttackKnob = new knob( knobBright_26, this, - tr( "LFO-attack-time" ) ); - m_lfoAttackKnob->setLabel( tr( "ATT" ) ); - m_lfoAttackKnob->move( LFO_ATTACK_KNOB_X, LFO_KNOB_Y ); - m_lfoAttackKnob->setHintText( tr( "LFO-attack:" ) + " ", "" ); - m_lfoAttackKnob->setWhatsThis( - tr( "Use this knob for setting attack-time of the current LFO. " - "The bigger this value the longer the LFO needs to " - "increase its amplitude to maximum." ) ); + m_lfoBaseKnob = new knob( knobBright_26, this, + tr( "LFO base value" ) ); + m_lfoBaseKnob->setLabel( tr( "BASE" ) ); + m_lfoBaseKnob->move( LFO_BASE_KNOB_X, LFO_KNOB_Y ); + m_lfoBaseKnob->setHintText( tr( "Base amount:" ) + " ", "" ); + m_lfoBaseKnob->setWhatsThis( tr("todo") ); m_lfoSpeedKnob = new tempoSyncKnob( knobBright_26, this, @@ -87,9 +83,9 @@ lfoControllerDialog::lfoControllerDialog( controller * _model, QWidget * _parent m_lfoSpeedKnob->move( LFO_SPEED_KNOB_X, LFO_KNOB_Y ); m_lfoSpeedKnob->setHintText( tr( "LFO-speed:" ) + " ", "" ); m_lfoSpeedKnob->setWhatsThis( - tr( "Use this knob for setting speed of the current LFO. The " + tr( "Use this knob for setting speed of the LFO. The " "bigger this value the faster the LFO oscillates and " - "the faster will be your effect." ) ); + "the faster the effect." ) ); m_lfoAmountKnob = new knob( knobBright_26, this, @@ -103,6 +99,21 @@ lfoControllerDialog::lfoControllerDialog( controller * _model, QWidget * _parent "selected size (e.g. volume or cutoff-frequency) will " "be influenced by this LFO." ) ); + m_lfoPhaseKnob = new knob( knobBright_26, this, + tr( "LFO phase" ) ); + m_lfoPhaseKnob->setLabel( tr( "PHS" ) ); + m_lfoPhaseKnob->move( LFO_PHASE_KNOB_X, LFO_KNOB_Y ); + m_lfoPhaseKnob->setHintText( tr( "Phase offset:" ) + " ", "" + tr( "degrees" ) ); + m_lfoPhaseKnob->setWhatsThis( + tr( "With this knob you can set the phase-offset of " + "the LFO. That means you can move the " + "point within an oscillation where the " + "oscillator begins to oscillate. For example " + "if you have a sine-wave and have a phase-" + "offset of 180 degrees the wave will first go " + "down. It's the same with a square-wave." + ) ); + pixmapButton * sin_lfo_btn = new pixmapButton( this, NULL ); sin_lfo_btn->move( LFO_SHAPES_X, LFO_SHAPES_Y ); @@ -261,9 +272,10 @@ void lfoControllerDialog::modelChanged( void ) { m_lfo = castModel(); - m_lfoAttackKnob->setModel( &m_lfo->m_lfoAttackModel ); + m_lfoBaseKnob->setModel( &m_lfo->m_lfoBaseModel ); m_lfoSpeedKnob->setModel( &m_lfo->m_lfoSpeedModel ); m_lfoAmountKnob->setModel( &m_lfo->m_lfoAmountModel ); + m_lfoPhaseKnob->setModel( &m_lfo->m_lfoPhaseModel ); m_lfoWaveBtnGrp->setModel( &m_lfo->m_lfoWaveModel ); }