Bandlimited wave generation implemented for LMMS, currently only utilized by Monstro

This commit is contained in:
Vesa
2014-04-07 22:55:44 +03:00
parent 9024647f32
commit e10bbeb84e
5 changed files with 402 additions and 36 deletions

View File

@@ -97,7 +97,7 @@ MonstroSynth::MonstroSynth( MonstroInstrument * _i, NotePlayHandle * _nph,
m_l_last = 0.0f;
m_r_last = 0.0f;
// constants for very simple antialias/bandlimiting by amp delta capping
// constants for amp delta capping
m_adcap1 = ADCAP1 / m_samplerate;
m_adcap2 = ADCAP2 / m_samplerate;
}
@@ -400,10 +400,10 @@ void MonstroSynth::renderOutput( fpp_t _frames, sampleFrame * _buf )
if( o2r_p < 0 ) o2r_p -= floorf( o2r_p );
// multi-wave DC Oscillator
sample_t O2L = oscillate( o2w, o2l_p );
sample_t O2R = oscillate( o2w, o2r_p );
sample_t O2L = oscillate( o2w, o2l_p, BandLimitedWave::freqToLen( o2l_f, m_samplerate ) );
sample_t O2R = oscillate( o2w, o2r_p, BandLimitedWave::freqToLen( o2r_f, m_samplerate ) );
// do simple alias reduction filtering before volume is touched, by capping amplitude delta
// do amplitude delta cap
O2L = qBound( m_osc2l_last - m_adcap1, O2L, m_osc2l_last + m_adcap1 );
O2R = qBound( m_osc2r_last - m_adcap1, O2R, m_osc2r_last + m_adcap1 );
m_osc2l_last = O2L;
@@ -454,12 +454,12 @@ void MonstroSynth::renderOutput( fpp_t _frames, sampleFrame * _buf )
if( o3r_p < 0 ) o3r_p -= floorf( o3r_p );
// multi-wave DC Oscillator, sub-osc 1
sample_t O3AL = oscillate( o3w1, o3l_p );
sample_t O3AR = oscillate( o3w1, o3r_p );
sample_t O3AL = oscillate( o3w1, o3l_p, BandLimitedWave::freqToLen( o3l_f, m_samplerate ) );
sample_t O3AR = oscillate( o3w1, o3r_p, BandLimitedWave::freqToLen( o3r_f, m_samplerate ) );
// multi-wave DC Oscillator, sub-osc 2
sample_t O3BL = oscillate( o3w2, o3l_p );
sample_t O3BR = oscillate( o3w2, o3r_p );
sample_t O3BL = oscillate( o3w2, o3l_p, BandLimitedWave::freqToLen( o3l_f, m_samplerate ) );
sample_t O3BR = oscillate( o3w2, o3r_p, BandLimitedWave::freqToLen( o3r_f, m_samplerate ) );
// calc and modulate sub
sub = o3sub;
@@ -468,7 +468,7 @@ void MonstroSynth::renderOutput( fpp_t _frames, sampleFrame * _buf )
sample_t O3L = linearInterpolate( O3AL, O3BL, sub );
sample_t O3R = linearInterpolate( O3AR, O3BR, sub );
// do very simple bandlimit filtering by amp delta capping, before volume is touched
// do amp delta capping, before volume is touched
O3L = qBound( m_osc3l_last - m_adcap1, O3L, m_osc3l_last + m_adcap1 );
O3R = qBound( m_osc3r_last - m_adcap1, O3R, m_osc3r_last + m_adcap1 );
m_osc3l_last = O3L;
@@ -490,7 +490,7 @@ void MonstroSynth::renderOutput( fpp_t _frames, sampleFrame * _buf )
m_osc3l_phase = fraction( m_osc3l_phase + 1.0f / ( static_cast<float>( m_samplerate ) / o3l_f ) );
m_osc3r_phase = fraction( m_osc3r_phase + 1.0f / ( static_cast<float>( m_samplerate ) / o3r_f ) );
// simple bandlimiting
// amp delta caps
sample_t L = O1L + O3L + ( omod == MOD_MIX ? O2L : 0.0f );
sample_t R = O1R + O3R + ( omod == MOD_MIX ? O2R : 0.0f );
@@ -591,7 +591,7 @@ void MonstroSynth::renderModulators( fpp_t _frames )
{
const f_cnt_t t = f + tfp;
const float ph = m_lfo1_phase + lfo1_po;
lfo1_s = oscillate( WAVE_SQRSOFT, ph );
lfo1_s = oscillate( WAVE_SQRSOFT, ph, lfo1_r );
if( t < m_parent->m_lfo1_att ) lfo1_s *= ( static_cast<sample_t>( t ) / m_parent->m_lfo1_att );
m_lfo1_buf[f] = lfo1_s;
m_lfo1_phase += 1.0f / lfo1_r;
@@ -613,7 +613,7 @@ void MonstroSynth::renderModulators( fpp_t _frames )
{
const f_cnt_t t = f + tfp;
const float ph = m_lfo1_phase + lfo1_po;
lfo1_s = oscillate( WAVE_SINABS, ph );
lfo1_s = oscillate( WAVE_SINABS, ph, lfo1_r );
if( t < m_parent->m_lfo1_att ) lfo1_s *= ( static_cast<sample_t>( t ) / m_parent->m_lfo1_att );
m_lfo1_buf[f] = lfo1_s;
m_lfo1_phase += 1.0f / lfo1_r;
@@ -708,7 +708,7 @@ void MonstroSynth::renderModulators( fpp_t _frames )
{
const f_cnt_t t = f + tfp;
const float ph = m_lfo2_phase + lfo2_po;
lfo2_s = oscillate( WAVE_SQRSOFT, ph );
lfo2_s = oscillate( WAVE_SQRSOFT, ph, lfo2_r );
if( t < m_parent->m_lfo2_att ) lfo2_s *= ( static_cast<sample_t>( t ) / m_parent->m_lfo2_att );
m_lfo2_buf[f] = lfo2_s;
m_lfo2_phase += 1.0f / lfo2_r;
@@ -730,7 +730,7 @@ void MonstroSynth::renderModulators( fpp_t _frames )
{
const f_cnt_t t = f + tfp;
const float ph = m_lfo2_phase + lfo2_po;
lfo2_s = oscillate( WAVE_SINABS, ph );
lfo2_s = oscillate( WAVE_SINABS, ph, lfo2_r );
if( t < m_parent->m_lfo2_att ) lfo2_s *= ( static_cast<sample_t>( t ) / m_parent->m_lfo2_att );
m_lfo2_buf[f] = lfo2_s;
m_lfo2_phase += 1.0f / lfo2_r;

View File

@@ -37,6 +37,7 @@
#include "combobox.h"
#include "Oscillator.h"
#include "lmms_math.h"
#include "BandLimitedWave.h"
//
// UI Macros
@@ -66,15 +67,21 @@
#define setwavemodel( name ) \
name .addItem( tr( "Sine wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sin" ) ) ); \
name .addItem( tr( "Triangle wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "tri" ) ) ); \
name .addItem( tr( "Saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "saw" ) ) ); \
name .addItem( tr( "Ramp wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "ramp" ) ) ); \
name .addItem( tr( "Square wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sqr" ) ) ); \
name .addItem( tr( "Bandlimited Triangle wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "tri" ) ) ); \
name .addItem( tr( "Bandlimited Saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "saw" ) ) ); \
name .addItem( tr( "Bandlimited Ramp wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "ramp" ) ) ); \
name .addItem( tr( "Bandlimited Square wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sqr" ) ) ); \
name .addItem( tr( "Bandlimited Moog saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "moog" ) ) ); \
name .addItem( tr( "Soft square wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sqrsoft" ) ) ); \
name .addItem( tr( "Moog saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "moog" ) ) ); \
name .addItem( tr( "Abs. sine wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sinabs" ) ) ); \
name .addItem( tr( "Absolute sine wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sinabs" ) ) ); \
name .addItem( tr( "Exponential wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "exp" ) ) ); \
name .addItem( tr( "White noise" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "noise" ) ) );
name .addItem( tr( "White noise" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "noise" ) ) ); \
name .addItem( tr( "Digital Triangle wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "tri" ) ) ); \
name .addItem( tr( "Digital Saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "saw" ) ) ); \
name .addItem( tr( "Digital Ramp wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "ramp" ) ) ); \
name .addItem( tr( "Digital Square wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sqr" ) ) ); \
name .addItem( tr( "Digital Moog saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "moog" ) ) ); \
#define setlfowavemodel( name ) \
name .addItem( tr( "Sine wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sin" ) ) ); \
@@ -82,8 +89,8 @@
name .addItem( tr( "Saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "saw" ) ) ); \
name .addItem( tr( "Ramp wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "ramp" ) ) ); \
name .addItem( tr( "Square wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sqr" ) ) ); \
name .addItem( tr( "Soft square wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sqrsoft" ) ) ); \
name .addItem( tr( "Moog saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "moog" ) ) ); \
name .addItem( tr( "Soft square wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sqrsoft" ) ) ); \
name .addItem( tr( "Abs. sine wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sinabs" ) ) ); \
name .addItem( tr( "Exponential wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "exp" ) ) ); \
name .addItem( tr( "Random" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "rand" ) ) );
@@ -136,12 +143,20 @@ const int WAVE_TRI = 1;
const int WAVE_SAW = 2;
const int WAVE_RAMP = 3;
const int WAVE_SQR = 4;
const int WAVE_SQRSOFT = 5;
const int WAVE_MOOG = 6;
const int WAVE_MOOG = 5;
const int WAVE_SQRSOFT = 6;
const int WAVE_SINABS = 7;
const int WAVE_EXP = 8;
const int WAVE_NOISE = 9;
const int NUM_WAVES = 10;
const int WAVE_TRI_D = 10;
const int WAVE_SAW_D = 11;
const int WAVE_RAMP_D = 12;
const int WAVE_SQR_D = 13;
const int WAVE_MOOG_D = 14;
const int NUM_WAVES = 15;
// modulation enumerators
const int MOD_MIX = 0;
@@ -156,8 +171,8 @@ const float MIN_FREQ = 18.0f;
const float MAX_FREQ = 48000.0f;
// constants for amp delta capping - these will be divided by samplerate by the synth
const float ADCAP1 = 44100 / 4;
const float ADCAP2 = 44100 / 4.5;
const float ADCAP1 = 44100 / 2;
const float ADCAP2 = 44100 / 3;
class MonstroInstrument;
@@ -205,7 +220,7 @@ private:
return fastPow( _s, exp );
}
inline sample_t oscillate( int _wave, const float _ph )
inline sample_t oscillate( int _wave, const float _ph, float _wavelen )
{
switch( _wave )
{
@@ -213,16 +228,20 @@ private:
return Oscillator::sinSample( _ph );
break;
case WAVE_TRI:
return Oscillator::triangleSample( _ph );
//return Oscillator::triangleSample( _ph );
return BandLimitedWave::oscillate( _ph, _wavelen, BandLimitedWave::BLTriangle );
break;
case WAVE_SAW:
return Oscillator::sawSample( _ph );
//return Oscillator::sawSample( _ph );
return BandLimitedWave::oscillate( _ph, _wavelen, BandLimitedWave::BLSaw );
break;
case WAVE_RAMP:
return Oscillator::sawSample( _ph ) * -1.0;
//return Oscillator::sawSample( _ph ) * -1.0;
return BandLimitedWave::oscillate( _ph, _wavelen, BandLimitedWave::BLSaw ) * -1.0;
break;
case WAVE_SQR:
return Oscillator::squareSample( _ph );
//return Oscillator::squareSample( _ph );
return BandLimitedWave::oscillate( _ph, _wavelen, BandLimitedWave::BLSquare );
break;
case WAVE_SQRSOFT:
{
@@ -234,7 +253,8 @@ private:
break;
}
case WAVE_MOOG:
return Oscillator::moogSawSample( _ph );
//return Oscillator::moogSawSample( _ph );
return BandLimitedWave::oscillate( _ph, _wavelen, BandLimitedWave::BLMoog );
break;
case WAVE_SINABS:
return qAbs( Oscillator::sinSample( _ph ) );
@@ -243,9 +263,25 @@ private:
return Oscillator::expSample( _ph );
break;
case WAVE_NOISE:
default:
return Oscillator::noiseSample( _ph );
break;
case WAVE_TRI_D:
return Oscillator::triangleSample( _ph );
break;
case WAVE_SAW_D:
return Oscillator::sawSample( _ph );
break;
case WAVE_RAMP_D:
return Oscillator::sawSample( _ph ) * -1.0;
break;
case WAVE_SQR_D:
return Oscillator::squareSample( _ph );
break;
case WAVE_MOOG_D:
return Oscillator::moogSawSample( _ph );
break;
}
return 0.0;
}
@@ -275,10 +311,10 @@ private:
sample_t m_osc3l_last;
sample_t m_osc3r_last;
sample_t m_l_last;
sample_t m_r_last;
float m_adcap1;
float m_adcap2;
};