oscillator rewrite
git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@148 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
@@ -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 );
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<float>( eng()->getMixer()->sampleRate() );
|
||||
m_osc[_i].detuningRight = powf( 2.0f, m_osc[_i].harmonic
|
||||
- (float)m_osc[_i].detuneKnob->value() / 100.0f )
|
||||
/ static_cast<float>( 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));
|
||||
|
||||
@@ -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 );
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
@@ -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<int>(
|
||||
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<int>(
|
||||
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<int>(
|
||||
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<int>(
|
||||
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<float>( 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<float>( 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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<float>( m_sampleRate );
|
||||
|
||||
m_sample = static_cast<f_cnt_t>( ( 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
|
||||
|
||||
Reference in New Issue
Block a user