Some improvements to LFO controller

git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@906 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Paul Giblock
2008-04-09 06:19:44 +00:00
parent fbc37ba9df
commit 7511380b45
6 changed files with 75 additions and 30 deletions

View File

@@ -1,3 +1,15 @@
2008-04-09 Paul Giblock <drfaygo/at/gmail/dot/com>
* 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 <drfaygo/at/gmail/dot/com>
* include/engine.h:

View File

@@ -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<float>( _val, 0.0f, 1.0f );
}
static int runningFrames();
static float runningTime();

View File

@@ -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;

View File

@@ -25,7 +25,6 @@
*
*/
#include <math.h>
#include <Qt/QtXml>
#include <QtCore/QObject>
#include <QtCore/QVector>
@@ -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;
}

View File

@@ -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 );
}

View File

@@ -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<lfoController>();
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 );
}