From 2d07d845e15c691df196bdabf7cb15cdbe0ea904 Mon Sep 17 00:00:00 2001 From: Javier Serrano Polo Date: Mon, 5 Jun 2006 19:26:34 +0000 Subject: [PATCH] oscillator rewrite git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@148 0778d3d1-df1d-0410-868b-ea421aaaa00d --- include/oscillator.h | 108 ++---- include/panning.h | 2 +- plugins/organic/organic.cpp | 186 +++++----- plugins/organic/organic.h | 16 + .../triple_oscillator/triple_oscillator.cpp | 237 ++++++++----- plugins/triple_oscillator/triple_oscillator.h | 18 +- src/lib/oscillator.cpp | 328 ++++++++---------- 7 files changed, 467 insertions(+), 428 deletions(-) diff --git a/include/oscillator.h b/include/oscillator.h index 94c213f0f..eb4fbeb76 100644 --- a/include/oscillator.h +++ b/include/oscillator.h @@ -37,15 +37,6 @@ #include "mixer.h" #include "sample_buffer.h" #include "lmms_constants.h" -#include "volume_knob.h" - - -// fwd-decl because we need it for the typedef below... -class oscillator; - -typedef void ( oscillator:: * oscFuncPtr ) - ( sampleFrame * _ab, const fpab_t _frames, - const ch_cnt_t _chnl ); class oscillator @@ -68,11 +59,13 @@ public: FREQ_MODULATION, AMP_MODULATION, MIX, SYNC } ; - oscillator( const modulationAlgos _modulation_algo, const float _freq, - const Sint16 _phase_offset, const float _volume_factor, - const volumeKnob * _volume_knob, - const sample_rate_t _sample_rate, - oscillator * _m_subOsc ) FASTCALL; + oscillator( const waveShapes * _wave_shape, + const modulationAlgos * _modulation_algo, + const float * _freq, + const float * _detuning, + const float * _phase_offset, + const float * _volume, + oscillator * _m_subOsc = NULL ) FASTCALL; virtual ~oscillator() { delete m_subOsc; @@ -83,36 +76,9 @@ public: m_userWave = _wave; } - inline void update( sampleFrame * _ab, const fpab_t _frames, - const ch_cnt_t _chnl ) - { - ( this->*m_callUpdate )( _ab, _frames, _chnl ); - } + void update( sampleFrame * _ab, const fpab_t _frames, + const ch_cnt_t _chnl ); - inline void setNewFreq( const float _new_freq ) - { - // save current state - we need it later for restoring same - // phase (otherwise we'll get clicks in the audio-stream) - const float v = m_sample * m_oscCoeff; - m_freq = _new_freq; - recalcOscCoeff( fraction( v ) ); - } - - static oscillator * FASTCALL createOsc( const waveShapes _wave_shape, - const modulationAlgos _modulation_algo, - const float _freq, - const Sint16 _phase_offset, - const float _volume_factor, - const volumeKnob * _volume_knob, - const sample_rate_t _sample_rate, - oscillator * _m_subOsc = NULL ); - inline bool syncOk( void ) - { - const float v1 = m_sample * m_oscCoeff; - const float v2 = ++m_sample * m_oscCoeff; - // check whether v2 is in next period - return( floorf( v2 ) > floorf( v1 ) ); - } /*#define FLOAT_TO_INT(in,out) \ register const float round_const = -0.5f; \ __asm__ __volatile__ ("fadd %%st,%%st(0)\n" \ @@ -195,44 +161,36 @@ public: } -protected: - float m_freq; - float m_volumeFactor; - const volumeKnob * m_volumeKnob; - Sint16 m_phaseOffset; - const sample_rate_t m_sampleRate; +private: + const waveShapes * m_waveShape; + const modulationAlgos * m_modulationAlgo; + const float * m_freq; + const float * m_detuning; + const float * m_volume; + const float * m_ext_phaseOffset; oscillator * m_subOsc; - f_cnt_t m_sample; - float m_oscCoeff; + float m_phaseOffset; + float m_phase; sampleBuffer * m_userWave; - oscFuncPtr m_callUpdate; - float volumeFactor( void ); + void updateNoSub( sampleFrame * _ab, const fpab_t _frames, + const ch_cnt_t _chnl ); + void updateFM( sampleFrame * _ab, const fpab_t _frames, + const ch_cnt_t _chnl ); + void updateAM( sampleFrame * _ab, const fpab_t _frames, + const ch_cnt_t _chnl ); + void updateMix( sampleFrame * _ab, const fpab_t _frames, + const ch_cnt_t _chnl ); + void updateSync( sampleFrame * _ab, const fpab_t _frames, + const ch_cnt_t _chnl ); - virtual void FASTCALL updateNoSub( sampleFrame * _ab, - const fpab_t _frames, - const ch_cnt_t _chnl ) = 0; - virtual void FASTCALL updateFM( sampleFrame * _ab, - const fpab_t _frames, - const ch_cnt_t _chnl ) = 0; - virtual void FASTCALL updateAM( sampleFrame * _ab, - const fpab_t _frames, - const ch_cnt_t _chnl ) = 0; - virtual void FASTCALL updateMix( sampleFrame * _ab, - const fpab_t _frames, - const ch_cnt_t _chnl ) = 0; - virtual void FASTCALL updateSync( sampleFrame * _ab, - const fpab_t _frames, - const ch_cnt_t _chnl ) = 0; + float syncInit( sampleFrame * _ab, const fpab_t _frames, + const ch_cnt_t _chnl ); + bool syncOk( float _osc_coeff ); - inline void sync( void ) - { - m_sample = 0; - } - - void FASTCALL recalcOscCoeff( const float _additional_phase_offset = - 0.0 ); + sample_t getSample( const float _sample ); + void FASTCALL recalcPhase( void ); } ; diff --git a/include/panning.h b/include/panning.h index 09799fbd1..5d9a98c7c 100644 --- a/include/panning.h +++ b/include/panning.h @@ -28,8 +28,8 @@ #include "types.h" -const panning PANNING_LEFT = ( 0 - 100); const panning PANNING_RIGHT = ( 0 + 100); +const panning PANNING_LEFT = - PANNING_RIGHT; const panning PANNING_CENTER = 0; const panning DEFAULT_PANNING = PANNING_CENTER; diff --git a/plugins/organic/organic.cpp b/plugins/organic/organic.cpp index 80f92f4aa..3175615f2 100644 --- a/plugins/organic/organic.cpp +++ b/plugins/organic/organic.cpp @@ -97,14 +97,24 @@ QPixmap * organicInstrument::s_artwork = NULL; organicInstrument::organicInstrument( instrumentTrack * _channel_track ) : instrument( _channel_track, &organic_plugin_descriptor ), - specialBgHandlingWidget( PLUGIN_NAME::getIconPixmap( "artwork" ) ) + specialBgHandlingWidget( PLUGIN_NAME::getIconPixmap( "artwork" ) ), + m_modulationAlgo( oscillator::MIX ) { m_num_oscillators = 8; - + m_osc = new oscillatorData[m_num_oscillators]; + m_osc[0].harmonic = log2f( 0.5f ); // one octave below + m_osc[1].harmonic = log2f( 0.75f ); // a fifth below + m_osc[2].harmonic = log2f( 1.0f ); // base freq + m_osc[3].harmonic = log2f( 2.0f ); // first overtone + m_osc[4].harmonic = log2f( 3.0f ); // second overtone + m_osc[5].harmonic = log2f( 4.0f ); // . + m_osc[6].harmonic = log2f( 5.0f ); // . + m_osc[7].harmonic = log2f( 6.0f ); // . + for (int i=0; i < m_num_oscillators; i++) { m_osc[i].waveShape = oscillator::SIN_WAVE; @@ -124,7 +134,7 @@ organicInstrument::organicInstrument( instrumentTrack * _channel_track ) : // setup volume-knob m_osc[i].volKnob = new volumeKnob( knobGreen_17, this, tr( - "Osc %1 volume" ).arg( i+1 ), eng() ); + "Osc %1 volume" ).arg( i+1 ), eng(), i ); m_osc[i].volKnob->move( 25+i*20, 110 ); m_osc[i].volKnob->setRange( 0, 100, 1.0f ); m_osc[i].volKnob->setInitValue( 100 ); @@ -133,7 +143,7 @@ organicInstrument::organicInstrument( instrumentTrack * _channel_track ) : // setup panning-knob m_osc[i].panKnob = new knob( knobGreen_17, this, - tr( "Osc %1 panning" ).arg( i + 1 ), eng() ); + tr( "Osc %1 panning" ).arg( i + 1 ), eng(), i ); m_osc[i].panKnob->move( 25+i*20, 130 ); m_osc[i].panKnob->setRange( PANNING_LEFT, PANNING_RIGHT, 1.0f ); m_osc[i].panKnob->setInitValue( DEFAULT_PANNING ); @@ -143,7 +153,7 @@ organicInstrument::organicInstrument( instrumentTrack * _channel_track ) : // setup knob for left fine-detuning m_osc[i].detuneKnob = new knob( knobGreen_17, this, tr( "Osc %1 fine detuning left" ).arg( i+1 ), - eng() ); + eng(), i ); m_osc[i].detuneKnob->move( 25+i*20, 150 ); m_osc[i].detuneKnob->setRange( -100.0f, 100.0f, 1.0f ); m_osc[i].detuneKnob->setInitValue( 0.0f ); @@ -151,11 +161,22 @@ organicInstrument::organicInstrument( instrumentTrack * _channel_track ) : "left:" ).arg( i + 1 ) + " ", " " + tr( "cents" ) ); - - - + + connect( m_osc[i].volKnob, SIGNAL( idKnobChanged( int ) ), + this, SLOT( updateVolume( int ) ) ); + connect( m_osc[i].panKnob, SIGNAL( idKnobChanged( int ) ), + this, SLOT( updateVolume( int ) ) ); + updateVolume( i ); + + connect( m_osc[i].detuneKnob, SIGNAL ( idKnobChanged( int ) ), + this, SLOT( updateDetuning( int ) ) ); + updateDetuning( i ); + } + connect( eng()->getMixer(), SIGNAL( sampleRateChanged() ), + this, SLOT( updateAllDetuning() ) ); + // setup knob for FX1 fx1Knob = new knob( knobGreen_17, this, tr( "FX1" ), eng() ); @@ -185,18 +206,7 @@ organicInstrument::organicInstrument( instrumentTrack * _channel_track ) : connect( m_randBtn, SIGNAL ( clicked() ), this, SLOT( randomiseSettings() ) ); - // set harmonics - m_osc[0].harmonic = 0.5f; // one octave below - m_osc[1].harmonic = 0.75f; // a fifth below - m_osc[2].harmonic = 1.0f; // base freq - m_osc[3].harmonic = 2.0f; // first overtone - m_osc[4].harmonic = 3.0f; // second overtone - m_osc[5].harmonic = 4.0f; // . - m_osc[6].harmonic = 5.0f; // . - m_osc[7].harmonic = 6.0f; // . - - if( s_artwork == NULL ) { s_artwork = new QPixmap( PLUGIN_NAME::getIconPixmap( @@ -289,84 +299,58 @@ void organicInstrument::playNote( notePlayHandle * _n ) { if( _n->totalFramesPlayed() == 0 ) { - float freq = getInstrumentTrack()->frequency( _n ); - oscillator * oscs_l[m_num_oscillators]; oscillator * oscs_r[m_num_oscillators]; for( Sint8 i = m_num_oscillators-1; i >= 0; --i ) { - // volume - float volume = 1.0 / m_num_oscillators ; - float volume_l = volume * ( m_osc[i].panKnob->value() + - PANNING_RIGHT ) / 100.0f; - float volume_r = volume * ( PANNING_RIGHT - - m_osc[i].panKnob->value() ) / - 100.0f; - - // detuning - float osc_detuning_l = +m_osc[i].detuneKnob->value() / 10.0f; - float osc_detuning_r = -m_osc[i].detuneKnob->value() / 10.0f; - - // frequency - float freq_l = freq * m_osc[i].harmonic + osc_detuning_l; - float freq_r = freq * m_osc[i].harmonic + osc_detuning_r; - - // randomize the phaseOffset [0,360] - int phase_l = (int) (rand() * 360.0); - int phase_r = (int) (rand() * 360.0); + // randomize the phaseOffset [0,1) + m_osc[i].phaseOffsetLeft = rand() + / ( RAND_MAX + 1.0f ); + m_osc[i].phaseOffsetRight = rand() + / ( RAND_MAX + 1.0f ); - // Nyquist boundary check - if (freq > (eng()->getMixer()->sampleRate() >> 2)) - { - volume = 0; - } - // initialise ocillators if (i == (m_num_oscillators-1)) { // create left oscillator - oscs_l[i] = oscillator::createOsc( - m_osc[i].waveShape, - oscillator::MIX, - freq_l, - phase_l, - volume_l, - m_osc[i].volKnob, - eng()->getMixer()->sampleRate() ); + oscs_l[i] = new oscillator( + &m_osc[i].waveShape, + &m_modulationAlgo, + &_n->m_frequency, + &m_osc[i].detuningLeft, + &m_osc[i].phaseOffsetLeft, + &m_osc[i].volumeLeft ); // create right oscillator - oscs_r[i] = oscillator::createOsc( - m_osc[i].waveShape, - oscillator::MIX, - freq_r, - phase_r, - volume_r, - m_osc[i].volKnob, - eng()->getMixer()->sampleRate() ); + oscs_r[i] = new oscillator( + &m_osc[i].waveShape, + &m_modulationAlgo, + &_n->m_frequency, + &m_osc[i].detuningRight, + &m_osc[i].phaseOffsetRight, + &m_osc[i].volumeRight ); } else { // create left oscillator - oscs_l[i] = oscillator::createOsc( - m_osc[i].waveShape, - oscillator::MIX, - freq_l, - phase_l, - volume_l, - m_osc[i].volKnob, - eng()->getMixer()->sampleRate(), + oscs_l[i] = new oscillator( + &m_osc[i].waveShape, + &m_modulationAlgo, + &_n->m_frequency, + &m_osc[i].detuningLeft, + &m_osc[i].phaseOffsetLeft, + &m_osc[i].volumeLeft, oscs_l[i + 1] ); // create right oscillator - oscs_r[i] = oscillator::createOsc( - m_osc[i].waveShape, - oscillator::MIX, - freq_r, - phase_r, - volume_r, - m_osc[i].volKnob, - eng()->getMixer()->sampleRate(), + oscs_r[i] = new oscillator( + &m_osc[i].waveShape, + &m_modulationAlgo, + &_n->m_frequency, + &m_osc[i].detuningRight, + &m_osc[i].phaseOffsetRight, + &m_osc[i].volumeRight, oscs_r[i + 1] ); } @@ -398,8 +382,10 @@ void organicInstrument::playNote( notePlayHandle * _n ) for (int i=0 ; i < frames ; i++) { - buf[i][0] = waveshape( buf[i][0], t ) * volKnob->value() / 100.0; - buf[i][1] = waveshape( buf[i][1], t ) * volKnob->value() / 100.0; + buf[i][0] = waveshape( buf[i][0], t ) * volKnob->value() + / 100.0f; + buf[i][1] = waveshape( buf[i][1], t ) * volKnob->value() + / 100.0f; } // -- -- @@ -505,6 +491,46 @@ void organicInstrument::randomiseSettings() } + + + +void organicInstrument::updateVolume( int _i ) +{ + m_osc[_i].volumeLeft = + ( 1.0f - m_osc[_i].panKnob->value() / (float)PANNING_RIGHT ) + * m_osc[_i].volKnob->value() / m_num_oscillators / 100.0f; + m_osc[_i].volumeRight = + ( 1.0f + m_osc[_i].panKnob->value() / (float)PANNING_RIGHT ) + * m_osc[_i].volKnob->value() / m_num_oscillators / 100.0f; +} + + + + +void organicInstrument::updateDetuning( int _i ) +{ + m_osc[_i].detuningLeft = powf( 2.0f, m_osc[_i].harmonic + + (float)m_osc[_i].detuneKnob->value() / 100.0f ) + / static_cast( eng()->getMixer()->sampleRate() ); + m_osc[_i].detuningRight = powf( 2.0f, m_osc[_i].harmonic + - (float)m_osc[_i].detuneKnob->value() / 100.0f ) + / static_cast( eng()->getMixer()->sampleRate() ); +} + + + + +void organicInstrument::updateAllDetuning( void ) +{ + for( int i = 0; i < m_num_oscillators; ++i ) + { + updateDetuning( i ); + } +} + + + + int organicInstrument::intRand( int min, int max ) { // int randn = min+int((max-min)*rand()/(RAND_MAX + 1.0)); diff --git a/plugins/organic/organic.h b/plugins/organic/organic.h index e7af8d03f..24bcb98b0 100644 --- a/plugins/organic/organic.h +++ b/plugins/organic/organic.h @@ -88,6 +88,14 @@ private: knob * panKnob; knob * detuneKnob; float harmonic; + float volumeLeft; + float volumeRight; + // normalized detuning -> x/sampleRate + float detuningLeft; + float detuningRight; + // normalized offset -> x/360 + float phaseOffsetLeft; + float phaseOffsetRight; }; oscillatorData* m_osc; @@ -98,10 +106,18 @@ private: oscillator * oscRight; } ; + const oscillator::modulationAlgos m_modulationAlgo; + knob * fx1Knob; knob * volKnob; pixmapButton * m_randBtn; +private slots: + + void updateVolume( int _i ); + void updateDetuning( int _i ); + void updateAllDetuning( void ); + } ; diff --git a/plugins/triple_oscillator/triple_oscillator.cpp b/plugins/triple_oscillator/triple_oscillator.cpp index 856fe7c3c..054265cc5 100644 --- a/plugins/triple_oscillator/triple_oscillator.cpp +++ b/plugins/triple_oscillator/triple_oscillator.cpp @@ -83,7 +83,8 @@ plugin::descriptor tripleoscillator_plugin_descriptor = tripleOscillator::tripleOscillator( instrumentTrack * _channel_track ) : instrument( _channel_track, &tripleoscillator_plugin_descriptor ), m_modulationAlgo1( oscillator::MIX ), - m_modulationAlgo2( oscillator::MIX ) + m_modulationAlgo2( oscillator::MIX ), + m_modulationAlgo3( oscillator::MIX ) { for( int i = 0; i < NUM_OF_OSCILLATORS; ++i ) { @@ -219,10 +220,11 @@ tripleOscillator::tripleOscillator( instrumentTrack * _channel_track ) : // setup volume-knob m_osc[i].volKnob = new volumeKnob( knobSmall_17, this, tr( - "Osc %1 volume" ).arg( i+1 ), eng() ); + "Osc %1 volume" ).arg( i+1 ), eng(), i ); m_osc[i].volKnob->move( 6, 104+i*50 ); m_osc[i].volKnob->setRange( MIN_VOLUME, MAX_VOLUME, 1.0f ); - m_osc[i].volKnob->setInitValue( DEFAULT_VOLUME / 3 ); + m_osc[i].volKnob->setInitValue( DEFAULT_VOLUME + / NUM_OF_OSCILLATORS ); m_osc[i].volKnob->setHintText( tr( "Osc %1 volume:" ).arg( i+1 ) + " ", "%" ); #ifdef QT4 @@ -238,7 +240,7 @@ tripleOscillator::tripleOscillator( instrumentTrack * _channel_track ) : // setup panning-knob m_osc[i].panKnob = new knob( knobSmall_17, this, - tr( "Osc %1 panning" ).arg( i + 1 ), eng() ); + tr( "Osc %1 panning" ).arg( i + 1 ), eng(), i ); m_osc[i].panKnob->move( 33, 104+i*50 ); m_osc[i].panKnob->setRange( PANNING_LEFT, PANNING_RIGHT, 1.0f ); m_osc[i].panKnob->setInitValue( DEFAULT_PANNING ); @@ -257,7 +259,7 @@ tripleOscillator::tripleOscillator( instrumentTrack * _channel_track ) : // setup coarse-knob m_osc[i].coarseKnob = new knob( knobSmall_17, this, tr("Osc %1 coarse detuning").arg( i + 1 ), - eng() ); + eng(), i ); m_osc[i].coarseKnob->move( 66, 104 + i * 50 ); m_osc[i].coarseKnob->setRange( -2 * NOTES_PER_OCTAVE, 2 * NOTES_PER_OCTAVE, 1.0f ); @@ -279,7 +281,7 @@ tripleOscillator::tripleOscillator( instrumentTrack * _channel_track ) : // setup knob for left fine-detuning m_osc[i].fineLKnob = new knob( knobSmall_17, this, tr( "Osc %1 fine detuning left" ).arg( i+1 ), - eng() ); + eng(), i ); m_osc[i].fineLKnob->move( 90, 104 + i * 50 ); m_osc[i].fineLKnob->setRange( -100.0f, 100.0f, 1.0f ); m_osc[i].fineLKnob->setInitValue( 0.0f ); @@ -301,7 +303,8 @@ tripleOscillator::tripleOscillator( instrumentTrack * _channel_track ) : // setup knob for right fine-detuning m_osc[i].fineRKnob = new knob( knobSmall_17, this, tr( "Osc %1 fine detuning right" - ).arg( i + 1 ), eng() ); + ).arg( i + 1 ), + eng(), i ); m_osc[i].fineRKnob->move( 110, 104 + i * 50 ); m_osc[i].fineRKnob->setRange( -100.0f, 100.0f, 1.0f ); m_osc[i].fineRKnob->setInitValue( 0.0f ); @@ -323,7 +326,7 @@ tripleOscillator::tripleOscillator( instrumentTrack * _channel_track ) : m_osc[i].phaseOffsetKnob = new knob( knobSmall_17, this, tr( "Osc %1 phase-" "offset" ).arg( i+1 ), - eng() ); + eng(), i ); m_osc[i].phaseOffsetKnob->move( 142, 104 + i * 50 ); m_osc[i].phaseOffsetKnob->setRange( 0.0f, 360.0f, 1.0f ); m_osc[i].phaseOffsetKnob->setInitValue( 0.0f ); @@ -349,7 +352,7 @@ tripleOscillator::tripleOscillator( instrumentTrack * _channel_track ) : m_osc[i].stereoPhaseDetuningKnob = new knob( knobSmall_17, this, tr( "Osc %1 stereo phase-" "detuning" ).arg( i+1 ), - eng() ); + eng(), i ); m_osc[i].stereoPhaseDetuningKnob->move( 166, 104 + i * 50 ); m_osc[i].stereoPhaseDetuningKnob->setRange( 0.0f, 360.0f, 1.0f ); @@ -372,6 +375,36 @@ tripleOscillator::tripleOscillator( instrumentTrack * _channel_track ) : "channel. This is very good for creating wide " "stereo-sounds." ).arg( i+1 ) ); + // Connect knobs with oscillators' inputs + connect( m_osc[i].volKnob, SIGNAL( idKnobChanged( int ) ), + this, SLOT( updateVolume( int ) ) ); + connect( m_osc[i].panKnob, SIGNAL( idKnobChanged( int ) ), + this, SLOT( updateVolume( int ) ) ); + updateVolume( i ); + + connect( m_osc[i].coarseKnob, SIGNAL( idKnobChanged( int ) ), + this, SLOT( updateDetuningLeft( int ) ) ); + connect( m_osc[i].coarseKnob, SIGNAL( idKnobChanged( int ) ), + this, SLOT( updateDetuningRight( int ) ) ); + connect( m_osc[i].fineLKnob, SIGNAL( idKnobChanged( int ) ), + this, SLOT( updateDetuningLeft( int ) ) ); + connect( m_osc[i].fineRKnob, SIGNAL( idKnobChanged( int ) ), + this, SLOT( updateDetuningRight( int ) ) ); + updateDetuningLeft( i ); + updateDetuningRight( i ); + + connect( m_osc[i].phaseOffsetKnob, + SIGNAL( idKnobChanged( int ) ), + this, SLOT( updatePhaseOffsetLeft( int ) ) ); + connect( m_osc[i].phaseOffsetKnob, + SIGNAL( idKnobChanged( int ) ), + this, SLOT( updatePhaseOffsetRight( int ) ) ); + connect( m_osc[i].stereoPhaseDetuningKnob, + SIGNAL( idKnobChanged( int ) ), + this, SLOT( updatePhaseOffsetLeft( int ) ) ); + updatePhaseOffsetLeft( i ); + updatePhaseOffsetRight( i ); + pixmapButton * sin_wave_btn = new pixmapButton( this, eng() ); sin_wave_btn->move( 188, 105 + i * 50 ); sin_wave_btn->setActiveGraphic( embed::getIconPixmap( @@ -491,6 +524,9 @@ tripleOscillator::tripleOscillator( instrumentTrack * _channel_track ) : SLOT( osc2UserDefWaveDblClick() ) ); } } + + connect( eng()->getMixer(), SIGNAL( sampleRateChanged() ), + this, SLOT( updateAllDetuning() ) ); } @@ -603,91 +639,52 @@ void tripleOscillator::playNote( notePlayHandle * _n ) { if( _n->totalFramesPlayed() == 0 ) { - float freq = getInstrumentTrack()->frequency( _n ); - oscillator * oscs_l[NUM_OF_OSCILLATORS]; oscillator * oscs_r[NUM_OF_OSCILLATORS]; for( Sint8 i = NUM_OF_OSCILLATORS-1; i >= 0; --i ) { - float osc_detuning_l = pow( 2.0, ( - (float)m_osc[i].coarseKnob->value() * 100.0f + - (float)m_osc[i].fineLKnob->value() ) / 1200.0f); - float osc_detuning_r = pow( 2.0, ( - (float)m_osc[i].coarseKnob->value() * 100.0f + - (float)m_osc[i].fineRKnob->value() ) / 1200.0f); - - float vol_fac_l = ( m_osc[i].panKnob->value() + - PANNING_RIGHT ) / 100.0f; - float vol_fac_r = ( PANNING_RIGHT - - m_osc[i].panKnob->value() ) / - 100.0f; - - if( vol_fac_l > 1.0f ) - { - vol_fac_l = 1.0f; - } - if( vol_fac_r > 1.0f ) - { - vol_fac_r = 1.0f; - } - // the third oscs needs no sub-oscs... if( i == 2 ) { - oscs_l[i] = oscillator::createOsc( - m_osc[i].waveShape, - oscillator::MIX, - freq*osc_detuning_l, - static_cast( - m_osc[i].phaseOffsetKnob->value() + - m_osc[i].stereoPhaseDetuningKnob->value() ), - vol_fac_l, - m_osc[i].volKnob, - eng()->getMixer()->sampleRate() ); - oscs_r[i] = oscillator::createOsc( - m_osc[i].waveShape, - oscillator::MIX, - freq*osc_detuning_r, - static_cast( - m_osc[i].phaseOffsetKnob->value() ), - vol_fac_r, - m_osc[i].volKnob, - eng()->getMixer()->sampleRate() ); + oscs_l[i] = new oscillator( + &m_osc[i].waveShape, + &m_modulationAlgo3, + &_n->m_frequency, + &m_osc[i].detuningLeft, + &m_osc[i].phaseOffsetLeft, + &m_osc[i].volumeLeft ); + oscs_r[i] = new oscillator( + &m_osc[i].waveShape, + &m_modulationAlgo3, + &_n->m_frequency, + &m_osc[i].detuningRight, + &m_osc[i].phaseOffsetRight, + &m_osc[i].volumeRight ); } else { - oscs_l[i] = oscillator::createOsc( - m_osc[i].waveShape, + oscs_l[i] = new oscillator( + &m_osc[i].waveShape, getModulationAlgo( i + 1 ), - freq*osc_detuning_l, - static_cast( - m_osc[i].phaseOffsetKnob->value() + - m_osc[i].stereoPhaseDetuningKnob->value() ), - vol_fac_l, - m_osc[i].volKnob, - eng()->getMixer()->sampleRate(), + &_n->m_frequency, + &m_osc[i].detuningLeft, + &m_osc[i].phaseOffsetLeft, + &m_osc[i].volumeLeft, oscs_l[i + 1] ); - oscs_r[i] = oscillator::createOsc( - m_osc[i].waveShape, + oscs_r[i] = new oscillator( + &m_osc[i].waveShape, getModulationAlgo( i + 1 ), - freq*osc_detuning_r, - static_cast( - m_osc[i].phaseOffsetKnob->value() ), - vol_fac_r, - m_osc[i].volKnob, - eng()->getMixer()->sampleRate(), + &_n->m_frequency, + &m_osc[i].detuningRight, + &m_osc[i].phaseOffsetRight, + &m_osc[i].volumeRight, oscs_r[i + 1] ); } - if( m_osc[i].waveShape == oscillator::USER_DEF_WAVE ) - { - oscs_l[i]->setUserWave( - m_osc[i].m_sampleBuffer ); - oscs_r[i]->setUserWave( - m_osc[i].m_sampleBuffer ); - } + oscs_l[i]->setUserWave( m_osc[i].m_sampleBuffer ); + oscs_r[i]->setUserWave( m_osc[i].m_sampleBuffer ); } @@ -810,15 +807,95 @@ void tripleOscillator::osc2UserDefWaveDblClick( void ) -oscillator::modulationAlgos tripleOscillator::getModulationAlgo( int _n ) + +void tripleOscillator::updateVolume( int _i ) { - if( _n == 1 ) + float panningFactorLeft; + float panningFactorRight; + + if( m_osc[_i].panKnob->value() >= 0.0f ) { - return( m_modulationAlgo1 ); + panningFactorLeft = 1.0f - m_osc[_i].panKnob->value() + / (float)PANNING_RIGHT; + panningFactorRight = 1.0f; } else { - return( m_modulationAlgo2 ); + panningFactorLeft = 1.0f; + panningFactorRight = 1.0f + m_osc[_i].panKnob->value() + / (float)PANNING_RIGHT; + } + + m_osc[_i].volumeLeft = panningFactorLeft * m_osc[_i].volKnob->value() + / 100.0f; + m_osc[_i].volumeRight = panningFactorRight * m_osc[_i].volKnob->value() + / 100.0f; +} + + + + +void tripleOscillator::updateDetuningLeft( int _i ) +{ + m_osc[_i].detuningLeft = powf( 2.0f, ( + (float)m_osc[_i].coarseKnob->value() * 100.0f + + (float)m_osc[_i].fineLKnob->value() ) / 1200.0f ) + / static_cast( eng()->getMixer()->sampleRate() ); +} + + + + +void tripleOscillator::updateDetuningRight( int _i ) +{ + m_osc[_i].detuningRight = powf( 2.0f, ( + (float)m_osc[_i].coarseKnob->value() * 100.0f + + (float)m_osc[_i].fineRKnob->value() ) / 1200.0f ) + / static_cast( eng()->getMixer()->sampleRate() ); +} + + + + +void tripleOscillator::updateAllDetuning( void ) +{ + for( int i = 0; i < NUM_OF_OSCILLATORS; ++i ) + { + updateDetuningLeft( i ); + updateDetuningRight( i ); + } +} + + + + +void tripleOscillator::updatePhaseOffsetLeft( int _i ) +{ + m_osc[_i].phaseOffsetLeft = ( m_osc[_i].phaseOffsetKnob->value() + + m_osc[_i].stereoPhaseDetuningKnob->value() ) / 360.0f; +} + + + + +void tripleOscillator::updatePhaseOffsetRight( int _i ) +{ + m_osc[_i].phaseOffsetRight = m_osc[_i].phaseOffsetKnob->value() + / 360.0f; +} + + + + +oscillator::modulationAlgos * tripleOscillator::getModulationAlgo( int _n ) +{ + if( _n == 1 ) + { + return( &m_modulationAlgo1 ); + } + else + { + return( &m_modulationAlgo2 ); } } diff --git a/plugins/triple_oscillator/triple_oscillator.h b/plugins/triple_oscillator/triple_oscillator.h index b1b5a40d9..0ba0ed399 100644 --- a/plugins/triple_oscillator/triple_oscillator.h +++ b/plugins/triple_oscillator/triple_oscillator.h @@ -73,6 +73,13 @@ protected slots: void mod1Ch( int _n ); void mod2Ch( int _n ); + void updateVolume( int _i ); + void updateDetuningLeft( int _i ); + void updateDetuningRight( int _i ); + void updateAllDetuning( void ); + void updatePhaseOffsetLeft( int _i ); + void updatePhaseOffsetRight( int _i ); + private: instrumentTrack * m_instrumentTrack; @@ -90,6 +97,14 @@ private: automatableButtonGroup * waveBtnGrp; pixmapButton * usrWaveBtn; sampleBuffer * m_sampleBuffer; + float volumeLeft; + float volumeRight; + // normalized detuning -> x/sampleRate + float detuningLeft; + float detuningRight; + // normalized offset -> x/360 + float phaseOffsetLeft; + float phaseOffsetRight; } m_osc[NUM_OF_OSCILLATORS]; struct oscPtr @@ -103,10 +118,11 @@ private: oscillator::modulationAlgos _modulation_algo, int _n );*/ /* void FASTCALL setModulationAlgo( oscillator::modulationAlgos _new_modulation_algo, int _n );*/ - oscillator::modulationAlgos FASTCALL getModulationAlgo( int _n ); + oscillator::modulationAlgos * FASTCALL getModulationAlgo( int _n ); oscillator::modulationAlgos m_modulationAlgo1; oscillator::modulationAlgos m_modulationAlgo2; + const oscillator::modulationAlgos m_modulationAlgo3; automatableButtonGroup * m_mod1BtnGrp; automatableButtonGroup * m_mod2BtnGrp; diff --git a/src/lib/oscillator.cpp b/src/lib/oscillator.cpp index b17e23cca..4b87d5dc0 100644 --- a/src/lib/oscillator.cpp +++ b/src/lib/oscillator.cpp @@ -29,245 +29,171 @@ -oscillator::oscillator( const modulationAlgos _modulation_algo, - const float _freq, const Sint16 _phase_offset, - const float _volume_factor, const volumeKnob * _volume_knob, - const sample_rate_t _sample_rate, +oscillator::oscillator( const waveShapes * _wave_shape, + const modulationAlgos * _modulation_algo, + const float * _freq, + const float * _detuning, + const float * _phase_offset, + const float * _volume, oscillator * _sub_osc ) : + m_waveShape( _wave_shape ), + m_modulationAlgo( _modulation_algo ), m_freq( _freq ), - m_volumeFactor( _volume_factor ), - m_volumeKnob( _volume_knob ), - m_phaseOffset( _phase_offset ), - m_sampleRate( _sample_rate ), + m_detuning( _detuning ), + m_volume( _volume ), + m_ext_phaseOffset( _phase_offset ), m_subOsc( _sub_osc ), m_userWave( NULL ) +{ + m_phaseOffset = *m_ext_phaseOffset; + m_phase = m_phaseOffset; +} + + + + +void oscillator::update( sampleFrame * _ab, const fpab_t _frames, const ch_cnt_t _chnl ) { if( m_subOsc != NULL ) { - switch( _modulation_algo ) + switch( *m_modulationAlgo ) { case FREQ_MODULATION: - m_callUpdate = &oscillator::updateFM; + updateFM( _ab, _frames, _chnl ); break; - case AMP_MODULATION: - m_callUpdate = &oscillator::updateAM; + updateAM( _ab, _frames, _chnl ); break; - case MIX: - m_callUpdate = &oscillator::updateMix; + updateMix( _ab, _frames, _chnl ); break; case SYNC: - m_callUpdate = &oscillator::updateSync; + updateSync( _ab, _frames, _chnl ); break; } } else { - m_callUpdate = &oscillator::updateNoSub; + updateNoSub( _ab, _frames, _chnl ); } - - recalcOscCoeff(); } -float oscillator::volumeFactor( void ) -{ - return( m_volumeFactor * m_volumeKnob->value() / 100.0f ); -} - - // if we have no sub-osc, we can't do any modulation... just get our samples -#define defineNoSubUpdateFor(x,getSampleFunction) \ -void x::updateNoSub( sampleFrame * _ab, const fpab_t _frames, \ - const ch_cnt_t _chnl ) \ -{ \ - for( fpab_t frame = 0; frame < _frames; ++frame ) \ - { \ - _ab[frame][_chnl] = getSampleFunction( ++m_sample * \ - m_oscCoeff ) * volumeFactor(); \ - } \ +void oscillator::updateNoSub( sampleFrame * _ab, const fpab_t _frames, + const ch_cnt_t _chnl ) +{ + recalcPhase(); + float osc_coeff = *m_freq * *m_detuning; + + for( fpab_t frame = 0; frame < _frames; ++frame ) + { + _ab[frame][_chnl] = getSample( m_phase ) * *m_volume; + m_phase += osc_coeff; + } } // do fm by using sub-osc as modulator -#define defineFMUpdateFor(x,getSampleFunction) \ -void x::updateFM( sampleFrame * _ab, const fpab_t _frames, \ - const ch_cnt_t _chnl ) \ -{ \ - m_subOsc->update( _ab, _frames, _chnl ); \ - for( fpab_t frame = 0; frame < _frames; ++frame ) \ - { \ - _ab[frame][_chnl] = getSampleFunction( ++m_sample * \ - m_oscCoeff + \ - _ab[frame][_chnl] ) * \ - volumeFactor(); \ - /* following line is REAL FM */ \ -/* float new_freq = powf( 2.0, _ab[frame][_chnl] ); \ - _ab[frame][_chnl] = getSampleFunction( ++m_sample*((m_freq * \ - new_freq )/mixer::inst()->sampleRate() )) * volumeFactor(); \ - _ab[frame][_chnl] = getSampleFunction( ++m_sample*(m_oscCoeff *\ - _ab[frame][_chnl] )) * volumeFactor();*/ \ - } \ +void oscillator::updateFM( sampleFrame * _ab, const fpab_t _frames, + const ch_cnt_t _chnl ) +{ + m_subOsc->update( _ab, _frames, _chnl ); + recalcPhase(); + float osc_coeff = *m_freq * *m_detuning; + + for( fpab_t frame = 0; frame < _frames; ++frame ) + { + m_phase += _ab[frame][_chnl]; + if ( m_phase < 0.0f ) + { + m_phase -= floorf(m_phase); + } + _ab[frame][_chnl] = getSample( m_phase ) * *m_volume; + m_phase += osc_coeff; + } } // do am by using sub-osc as modulator -#define defineAMUpdateFor(x,getSampleFunction) \ -void x::updateAM( sampleFrame * _ab, const fpab_t _frames, \ - const ch_cnt_t _chnl ) \ -{ \ - m_subOsc->update( _ab, _frames, _chnl ); \ - for( fpab_t frame = 0; frame < _frames; ++frame ) \ - { \ - _ab[frame][_chnl] *= getSampleFunction( ++m_sample * \ - m_oscCoeff ) * volumeFactor(); \ - } \ +void oscillator::updateAM( sampleFrame * _ab, const fpab_t _frames, + const ch_cnt_t _chnl ) +{ + m_subOsc->update( _ab, _frames, _chnl ); + recalcPhase(); + float osc_coeff = *m_freq * *m_detuning; + + for( fpab_t frame = 0; frame < _frames; ++frame ) + { + _ab[frame][_chnl] *= getSample( m_phase ) * *m_volume; + m_phase += osc_coeff; + } } // do mix by using sub-osc as mix-sample -#define defineMixUpdateFor(x,getSampleFunction) \ -void x::updateMix( sampleFrame * _ab, const fpab_t _frames, \ - const ch_cnt_t _chnl ) \ -{ \ - m_subOsc->update( _ab, _frames, _chnl ); \ - for( fpab_t frame = 0; frame < _frames; ++frame ) \ - { \ - _ab[frame][_chnl] += getSampleFunction( ++m_sample * \ - m_oscCoeff ) * volumeFactor(); \ - } \ +void oscillator::updateMix( sampleFrame * _ab, const fpab_t _frames, + const ch_cnt_t _chnl ) +{ + m_subOsc->update( _ab, _frames, _chnl ); + recalcPhase(); + float osc_coeff = *m_freq * *m_detuning; + + for( fpab_t frame = 0; frame < _frames; ++frame ) + { + _ab[frame][_chnl] += getSample( m_phase ) * *m_volume; + m_phase += osc_coeff; + } } // sync with sub-osc (every time sub-osc starts new period, we also start new // period) -#define defineSyncUpdateFor(x,getSampleFunction) \ -void x::updateSync( sampleFrame * _ab, const fpab_t _frames, \ - const ch_cnt_t _chnl ) \ -{ \ - for( fpab_t frame = 0; frame < _frames ; ++frame ) \ - { \ - if( m_subOsc->syncOk() ) \ - { \ - sync(); \ - } \ - _ab[frame][_chnl] = getSampleFunction( ++m_sample * \ - m_oscCoeff ) * volumeFactor(); \ - } \ +void oscillator::updateSync( sampleFrame * _ab, const fpab_t _frames, + const ch_cnt_t _chnl ) +{ + float sub_osc_coeff = m_subOsc->syncInit( _ab, _frames, _chnl ); + recalcPhase(); + float osc_coeff = *m_freq * *m_detuning; + + for( fpab_t frame = 0; frame < _frames ; ++frame ) + { + if( m_subOsc->syncOk( sub_osc_coeff ) ) + { + m_phase = m_phaseOffset; + } + _ab[frame][_chnl] = getSample( m_phase ) * *m_volume; + m_phase += osc_coeff; + } } -#define generateOscillatorCodeFor(x,getSampleFunction); \ -class x : public oscillator \ -{ \ -public: \ - inline x( const modulationAlgos modulation_algo, \ - const float _freq, \ - const Sint16 _phase_offset, const float _volume_factor, \ - const volumeKnob * _volume_knob, \ - const sample_rate_t _sample_rate, \ - oscillator * _sub_osc ) : \ - oscillator( modulation_algo, _freq, _phase_offset, \ - _volume_factor, _volume_knob, \ - _sample_rate, _sub_osc ) \ - { \ - } \ - virtual ~x() \ - { \ - } \ - \ -protected: \ - void updateNoSub( sampleFrame * _ab, const fpab_t _frames, \ - const ch_cnt_t _chnl ); \ - void updateFM( sampleFrame * _ab, const fpab_t _frames, \ - const ch_cnt_t _chnl ); \ - void updateAM( sampleFrame * _ab, const fpab_t _frames, \ - const ch_cnt_t _chnl ); \ - void updateMix( sampleFrame * _ab, const fpab_t _frames, \ - const ch_cnt_t _chnl ); \ - void updateSync( sampleFrame * _ab, const fpab_t _frames, \ - const ch_cnt_t _chnl ); \ - \ -} ; \ - \ -defineNoSubUpdateFor( x, getSampleFunction ) \ -defineFMUpdateFor( x, getSampleFunction ) \ -defineAMUpdateFor( x, getSampleFunction ) \ -defineMixUpdateFor( x, getSampleFunction ) \ -defineSyncUpdateFor( x, getSampleFunction ) - -generateOscillatorCodeFor( sinWaveOsc, sinSample ); -generateOscillatorCodeFor( triangleWaveOsc, triangleSample ); -generateOscillatorCodeFor( sawWaveOsc, sawSample ); -generateOscillatorCodeFor( squareWaveOsc, squareSample ); -generateOscillatorCodeFor( moogSawWaveOsc, moogSawSample ); -generateOscillatorCodeFor( expWaveOsc, expSample ); -generateOscillatorCodeFor( noiseWaveOsc, noiseSample ); -generateOscillatorCodeFor( userWaveOsc, userWaveSample ); - - - -oscillator * oscillator::createOsc( const waveShapes _wave_shape, - const modulationAlgos _modulation_algo, - const float _freq, - const Sint16 _phase_offset, - const float _volume_factor, - const volumeKnob * _volume_knob, - const sample_rate_t _sample_rate, - oscillator * _sub_osc ) +inline sample_t oscillator::getSample( const float _sample ) { - switch( _wave_shape ) + switch( *m_waveShape ) { case SIN_WAVE: - return( new sinWaveOsc( _modulation_algo, _freq, - _phase_offset, _volume_factor, - _volume_knob, - _sample_rate, _sub_osc ) ); + return( sinSample( _sample ) ); case TRIANGLE_WAVE: - return( new triangleWaveOsc( _modulation_algo, _freq, - _phase_offset, _volume_factor, - _volume_knob, - _sample_rate, _sub_osc ) ); + return( triangleSample( _sample ) ); case SAW_WAVE: - return( new sawWaveOsc( _modulation_algo, _freq, - _phase_offset, _volume_factor, - _volume_knob, - _sample_rate, _sub_osc ) ); + return( sawSample( _sample ) ); case SQUARE_WAVE: - return( new squareWaveOsc( _modulation_algo, _freq, - _phase_offset, _volume_factor, - _volume_knob, - _sample_rate, _sub_osc ) ); + return( squareSample( _sample ) ); case MOOG_SAW_WAVE: - return( new moogSawWaveOsc( _modulation_algo, _freq, - _phase_offset, _volume_factor, - _volume_knob, - _sample_rate, _sub_osc ) ); + return( moogSawSample( _sample ) ); case EXP_WAVE: - return( new expWaveOsc( _modulation_algo, _freq, - _phase_offset, _volume_factor, - _volume_knob, - _sample_rate, _sub_osc ) ); + return( expSample( _sample ) ); case WHITE_NOISE_WAVE: - return( new noiseWaveOsc( _modulation_algo, _freq, - _phase_offset, _volume_factor, - _volume_knob, - _sample_rate, _sub_osc ) ); + return( noiseSample( _sample ) ); case USER_DEF_WAVE: - return( new userWaveOsc( _modulation_algo, _freq, - _phase_offset, _volume_factor, - _volume_knob, - _sample_rate, _sub_osc ) ); + return( userWaveSample( _sample ) ); default: - return( new sinWaveOsc( _modulation_algo, _freq, - _phase_offset, _volume_factor, - _volume_knob, - _sample_rate, _sub_osc ) ); + return( sinSample( _sample ) ); } } @@ -275,21 +201,41 @@ oscillator * oscillator::createOsc( const waveShapes _wave_shape, -// should be called every time phase-offset or frequency is changed... -void oscillator::recalcOscCoeff( const float additional_phase_offset ) +// should be called every time phase-offset is changed... +inline void oscillator::recalcPhase( void ) { - m_oscCoeff = m_freq / static_cast( m_sampleRate ); - - m_sample = static_cast( ( m_phaseOffset * ( 1.0f / 360.0f ) + - additional_phase_offset ) * - ( m_sampleRate / m_freq ) ); - // because we pre-increment m_sample in update-function, we should - // decrement it here... (not possible when 0 because it is - // unsigned - overflow!!!) - if( m_sample > 0 ) + if( m_phaseOffset != *m_ext_phaseOffset ) { - --m_sample; + m_phase += 1.0f - m_phaseOffset; + m_phaseOffset = *m_ext_phaseOffset; + m_phase += m_phaseOffset; } + m_phase = fraction( m_phase ); +} + + + + +inline bool oscillator::syncOk( float _osc_coeff ) +{ + const float v1 = m_phase; + m_phase += _osc_coeff; + // check whether m_phase is in next period + return( floorf( m_phase ) > floorf( v1 ) ); +} + + + + +float oscillator::syncInit( sampleFrame * _ab, const fpab_t _frames, + const ch_cnt_t _chnl ) +{ + if( m_subOsc != NULL ) + { + m_subOsc->update( _ab, _frames, _chnl ); + } + recalcPhase(); + return( *m_freq * *m_detuning ); } #endif