From 9768dd37008c0fffe982f8964a05ce0b28bc4e36 Mon Sep 17 00:00:00 2001 From: Paul Giblock Date: Fri, 23 Nov 2007 18:56:21 +0000 Subject: [PATCH] LB302 reformat, ToolButton appearance git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@611 0778d3d1-df1d-0410-868b-ea421aaaa00d --- ChangeLog | 9 + plugins/lb302/lb302.cpp | 1282 ++++++++++++++++++----------------- plugins/lb302/lb302.h | 363 +++++----- src/widgets/tool_button.cpp | 2 +- 4 files changed, 856 insertions(+), 800 deletions(-) diff --git a/ChangeLog b/ChangeLog index bb5045f79..189360408 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2007-11-23 Paul Giblock + + * plugins/lb302/lb302.cpp: + * plugins/lb302/lb302.h: + reformated code to match code style rules + + * src/widgets/tool_button.cpp: + improved appearance of toolbar buttons + 2007-11-23 Tobias Doerffel * plugins/ladspa_browser/ladspa_browser.cpp: diff --git a/plugins/lb302/lb302.cpp b/plugins/lb302/lb302.cpp index 787e624bc..e1644fbea 100644 --- a/plugins/lb302/lb302.cpp +++ b/plugins/lb302/lb302.cpp @@ -3,11 +3,11 @@ * to emulate the Roland TB303 bass synth * * Copyright (c) 2006-2007 Paul Giblock - * + * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * * lb302FilterIIR2 is based on the gsyn filter code by Andy Sloane. - * + * * lb302Filter3Pole is based on the TB303 instrument written by * Josep M Comajuncosas for the CSounds library * @@ -51,10 +51,10 @@ // // New config // -#define LB_24_IGNORE_ENVELOPE +#define LB_24_IGNORE_ENVELOPE #define LB_FILTERED //#define LB_DECAY -//#define LB_24_RES_TRICK +//#define LB_24_RES_TRICK #define LB_DIST_RATIO 4.0 #define LB_24_VOL_ADJUST 3.0 @@ -82,7 +82,7 @@ plugin::descriptor lb302_plugin_descriptor = STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ), "LB302", QT_TRANSLATE_NOOP( "pluginBrowser", - "Incomplete monophonic immitation tb303" ), + "Llamafied tb303" ), "Paul Giblock ", 0x0100, plugin::Instrument, @@ -92,513 +92,562 @@ plugin::descriptor lb302_plugin_descriptor = } + // // lb302Filter // -lb302Filter::lb302Filter(lb302FilterKnobState* p_fs) : - fs(p_fs), - vcf_c0(0), - vcf_e0(0), - vcf_e1(0) +lb302Filter::lb302Filter( lb302FilterKnobState * _fs ) : + m_fs( _fs ), + m_c0( 0 ), + m_e0( 0 ), + m_e1( 0 ) { }; -void lb302Filter::recalc() -{ - vcf_e1 = exp(6.109 + 1.5876*(fs->envmod) + 2.1553*(fs->cutoff) - 1.2*(1.0-(fs->reso))); - vcf_e0 = exp(5.613 - 0.8*(fs->envmod) + 2.1553*(fs->cutoff) - 0.7696*(1.0-(fs->reso))); - vcf_e0*=M_PI/44100.0; - vcf_e1*=M_PI/44100.0; - vcf_e1 -= vcf_e0; - vcf_rescoeff = exp(-1.20 + 3.455*(fs->reso)); + +void lb302Filter::recalc( void ) +{ + m_e1 = exp( 6.109 + 1.5876*(m_fs->envmod) + + 2.1553*(m_fs->cutoff) - 1.2*( 1.0 - (m_fs->reso) ) ); + m_e0 = exp( 5.613 - 0.8*(m_fs->envmod) + + 2.1553*(m_fs->cutoff) - 0.7696*( 1.0 - (m_fs->reso) ) ); + + m_e0 *= M_PI / 44100.0; + m_e1 *= M_PI / 44100.0; + m_e1 -= m_e0; + + m_rescoeff = exp( -1.20 + 3.455 * (m_fs->reso) ); }; -void lb302Filter::envRecalc() + +void lb302Filter::envRecalc( void ) { - vcf_c0 *= fs->envdecay; // Filter Decay. vcf_decay is adjusted for Hz and ENVINC - // vcf_rescoeff = exp(-1.20 + 3.455*(fs->reso)); moved above + m_c0 *= m_fs->envdecay; // Filter Decay. vcf_decay is adjusted for Hz and ENVINC + // vcf_rescoeff = exp(-1.20 + 3.455*(fs->reso)); moved above }; -void lb302Filter::playNote() + +void lb302Filter::playNote( void ) { - vcf_c0 = vcf_e1; + m_c0 = m_e1; } + + // // lb302FilterIIR2 // -lb302FilterIIR2::lb302FilterIIR2(lb302FilterKnobState* p_fs) : - lb302Filter(p_fs), - vcf_d1(0), - vcf_d2(0), - vcf_a(0), - vcf_b(0), - vcf_c(1) +lb302FilterIIR2::lb302FilterIIR2( lb302FilterKnobState * _fs ) : + lb302Filter( _fs ), + m_d1( 0 ), + m_d2( 0 ), + m_a( 0 ), + m_b( 0 ), + m_c( 1 ) { - m_dist = new effectLib::distortion<>( 1.0, 1.0f); - + m_dist = new effectLib::distortion<>( 1.0, 1.0f ); + }; - - -lb302FilterIIR2::~lb302FilterIIR2() +lb302FilterIIR2::~lb302FilterIIR2( void ) { delete m_dist; } - -void lb302FilterIIR2::recalc() +void lb302FilterIIR2::recalc( void ) { - lb302Filter::recalc(); + lb302Filter::recalc(); //m_dist->setThreshold(0.5+(fs->dist*2.0)); - m_dist->setThreshold(fs->dist*75.0); + m_dist->setThreshold( m_fs->dist * 75.0 ); }; -void lb302FilterIIR2::envRecalc() -{ - float k, w; - - lb302Filter::envRecalc(); - w = vcf_e0 + vcf_c0; // e0 is adjusted for Hz and doesn't need ENVINC - k = exp(-w/vcf_rescoeff); - // Does this mean c0 is inheritantly? - vcf_a = 2.0*cos(2.0*w) * k; - vcf_b = -k*k; - vcf_c = 1.0 - vcf_a - vcf_b; +void lb302FilterIIR2::envRecalc( void ) +{ + float k, w; + + lb302Filter::envRecalc(); + + w = m_e0 + m_c0; // e0 is adjusted for Hz and doesn't need ENVINC + k = exp( -w / m_rescoeff ); // Does this mean c0 is inheritantly? + + m_a = 2.0 * cos( 2.0 * w ) * k; + m_b = -k * k; + m_c = 1.0 - m_a - m_b; } -float lb302FilterIIR2::process(const float& samp) +float lb302FilterIIR2::process( const float & _samp ) { - float ret = vcf_a*vcf_d1 + vcf_b*vcf_d2 + vcf_c*samp; - // Delayed samples for filter - vcf_d2 = vcf_d1; - vcf_d1 = ret; + float ret = ( m_a * m_d1 ) + + ( m_b * m_d2 ) + + ( m_c * _samp ); - if(fs->dist > 0) - ret=m_dist->nextSample(ret); - // output = IIR2 + dry - return ret; + // Delayed samples for filter + m_d2 = m_d1; + m_d1 = ret; + + if( m_fs->dist > 0 ) + ret = m_dist->nextSample( ret ); + + // output = IIR2 + dry + return ret; } -void lb302FilterIIR2::getState(lb302FilterState* fs) + +void lb302FilterIIR2::getState( lb302FilterState * _fs ) { - fs->iir.vcf_c0 = vcf_c0; - fs->iir.vcf_a = vcf_a; - fs->iir.vcf_b = vcf_b; - fs->iir.vcf_c = vcf_c; - fs->iir.vcf_d1 = vcf_d1; - fs->iir.vcf_d2 = vcf_d2; + _fs->iir.c0 = m_c0; + _fs->iir.a = m_a; + _fs->iir.b = m_b; + _fs->iir.c = m_c; + _fs->iir.d1 = m_d1; + _fs->iir.d2 = m_d2; } -void lb302FilterIIR2::setState(const lb302FilterState* fs) + +void lb302FilterIIR2::setState( const lb302FilterState * _fs ) { - vcf_c0 = fs->iir.vcf_c0; - vcf_a = fs->iir.vcf_a; - vcf_b = fs->iir.vcf_b; - vcf_c = fs->iir.vcf_c; - vcf_d1 = fs->iir.vcf_d1; - vcf_d2 = fs->iir.vcf_d2; + m_c0 = _fs->iir.c0; + m_a = _fs->iir.a; + m_b = _fs->iir.b; + m_c = _fs->iir.c; + m_d1 = _fs->iir.d1; + m_d2 = _fs->iir.d2; } + + + // // lb302Filter3Pole // -lb302Filter3Pole::lb302Filter3Pole(lb302FilterKnobState *p_fs) : - lb302Filter(p_fs), - ay1(0), - ay2(0), - aout(0), - lastin(0) +lb302Filter3Pole::lb302Filter3Pole( lb302FilterKnobState * _fs ) : + lb302Filter( _fs ), + m_ay1( 0 ), + m_ay2( 0 ), + m_aout( 0 ), + m_lastin( 0 ) { }; -void lb302Filter3Pole::recalc() + + +void lb302Filter3Pole::recalc( void ) { - // DO NOT CALL BASE CLASS - vcf_e0 = 0.000001; - vcf_e1 = 1.0; + // DO NOT CALL BASE CLASS + + m_e0 = 0.000001; + m_e1 = 1.0; } -// TODO: Try using k instead of vcf_reso -void lb302Filter3Pole::envRecalc() + +void lb302Filter3Pole::envRecalc( void ) { - float w,k; - float kfco; + // TODO: Try using k instead of vcf_reso + float w, k; + float kfco; - lb302Filter::envRecalc(); - - - w = vcf_e0 + vcf_c0; // e0 is adjusted for Hz and doesn't need ENVINC - k = (fs->cutoff > 0.975)?0.975:fs->cutoff; - kfco = 50.f+(k)*((2300.f-1600.f*(fs->envmod))+(w)*(700.f+1500.f*(k)+(1500.f+(k)*(44100.f/2.f-6000.f))*(fs->envmod))); - //+iacc*(.3+.7*kfco*kenvmod)*kaccent*kaccurve*2000 + lb302Filter::envRecalc(); + w = m_e0 + m_c0; // e0 is adjusted for Hz and doesn't need ENVINC + k = ( m_fs->cutoff > 0.975 ) ? 0.975 : m_fs->cutoff; + kfco = 50.f + + k * ( + ( 2300.f - 1600.f * m_fs->envmod) + + w * ( + 700.f + + 1500.f * k + + ( 1500.f + k * ( 44100.f / 2.f - 6000.f ) ) * + m_fs->envmod + ) + ); + //+iacc*(.3+.7*kfco*kenvmod)*kaccent*kaccurve*2000 #ifdef LB_24_IGNORE_ENVELOPE - // kfcn = fs->cutoff; - kfcn = 2.0 * kfco / LB_HZ; + // kfcn = fs->cutoff; + m_kfcn = 2.0 * kfco / LB_HZ; #else - kfcn = w; + m_kfcn = w; #endif - kp = ((-2.7528*kfcn + 3.0429)*kfcn + 1.718)*kfcn - 0.9984; - kp1 = kp+1.0; - kp1h = 0.5*kp1; + m_kp = ( ( -2.7528 * m_kfcn + 3.0429 ) * m_kfcn + 1.718 ) * m_kfcn - 0.9984; + m_kp1 = m_kp + 1.0; + m_kp1h = 0.5 * m_kp1; #ifdef LB_24_RES_TRICK - k = exp(-w/vcf_rescoeff); - kres = (((k))) * (((-2.7079*kp1 + 10.963)*kp1 - 14.934)*kp1 + 8.4974); + k = exp( -w / m_rescoeff ); + m_kres = k * + ( ( ( -2.7079 * m_kp1 + 10.963 ) * m_kp1 - 14.934 ) * m_kp1 + 8.4974 ); #else - kres = (((fs->reso))) * (((-2.7079*kp1 + 10.963)*kp1 - 14.934)*kp1 + 8.4974); + m_kres = m_fs->reso * + ( ( ( -2.7079 * m_kp1 + 10.963 ) * m_kp1 - 14.934 ) * m_kp1 + 8.4974 ); #endif - value = 1.0+( (fs->dist) *(1.5 + 2.0*kres*(1.0-kfcn))); // ENVMOD was DIST*/ + + m_value = 1.0 + ( (m_fs->dist) * ( 1.5 + 2.0 * m_kres * ( 1.0 - m_kfcn ) ) ); } -float lb302Filter3Pole::process(const float& samp) + +float lb302Filter3Pole::process( const float & _samp ) { - float ax1 = lastin; - float ay11 = ay1; - float ay31 = ay2; - lastin = (samp) - tanh(kres*aout); - ay1 = kp1h * (lastin+ax1) - kp*ay1; - ay2 = kp1h * (ay1 + ay11) - kp*ay2; - aout = kp1h * (ay2 + ay31) - kp*aout; - - return tanh(aout*value)*LB_24_VOL_ADJUST/(1.0+fs->dist); + float ax1 = m_lastin; + float ay11 = m_ay1; + float ay31 = m_ay2; + + m_lastin = _samp - tanh( m_kres * m_aout ); + m_ay1 = m_kp1h * ( m_lastin + ax1 ) - m_kp * m_ay1; + m_ay2 = m_kp1h * ( m_ay1 + ay11 ) - m_kp * m_ay2; + m_aout = m_kp1h * ( m_ay2 + ay31 ) - m_kp * m_aout; + + return tanh( m_aout * m_value ) * LB_24_VOL_ADJUST / ( 1.0 + m_fs->dist ); } -void lb302Filter3Pole::getState(lb302FilterState* fs) + +void lb302Filter3Pole::getState( lb302FilterState * _fs ) { - fs->pole.aout = aout; - fs->pole.vcf_c0 = vcf_c0; - fs->pole.kp = kp; - fs->pole.kp1h = kp1h; - fs->pole.kres = kres; - fs->pole.ay1 = ay1; - fs->pole.ay2 = ay2; - fs->pole.lastin = lastin; - fs->pole.value = value; + _fs->pole.aout = m_aout; + _fs->pole.c0 = m_c0; + _fs->pole.kp = m_kp; + _fs->pole.kp1h = m_kp1h; + _fs->pole.kres = m_kres; + _fs->pole.ay1 = m_ay1; + _fs->pole.ay2 = m_ay2; + _fs->pole.lastin = m_lastin; + _fs->pole.value = m_value; } -void lb302Filter3Pole::setState(const lb302FilterState* fs) + +void lb302Filter3Pole::setState( const lb302FilterState * _fs ) { - aout = fs->pole.aout; - vcf_c0 = fs->pole.vcf_c0; - kp = fs->pole.kp; - kp1h = fs->pole.kp1h; - kres = fs->pole.kres; - ay1 = fs->pole.ay1; - ay2 = fs->pole.ay2; - lastin = fs->pole.lastin; - value = fs->pole.value; + m_aout = _fs->pole.aout; + m_c0 = _fs->pole.c0; + m_kp = _fs->pole.kp; + m_kp1h = _fs->pole.kp1h; + m_kres = _fs->pole.kres; + m_ay1 = _fs->pole.ay1; + m_ay2 = _fs->pole.ay2; + m_lastin = _fs->pole.lastin; + m_value = _fs->pole.value; } + + // // LBSynth // lb302Synth::lb302Synth( instrumentTrack * _channel_track ) : - instrument( _channel_track, &lb302_plugin_descriptor ) + instrument( _channel_track, &lb302_plugin_descriptor ), + + m_vco_shape( SAWTOOTH ), + m_vco_slide( 0 ), + m_vco_slideinc( 0 ), + m_vco_slidebase( 0 ), + m_vco_detune( 0 ), + m_vco_inc( 0.0 ), + m_vco_k( 0 ), + m_vco_c( 0 ), + + m_vcf_envpos( ENVINC ), + + m_vca_attack( 1.0 - 0.96406088 ), + m_vca_decay( 0.99897516 ), + m_vca_a0( 0.5 ), // Experimenting between (0.5) and 1.0 + m_vca_a( 9 ), + m_vca_mode( 3 ), + + m_useHoldNote( false ), + m_sampleCnt( 0 ), + m_releaseFrame( 1<<24 ), + m_catchFrame( 0 ), + m_catchDecay( 0 ), + m_lastFramesPlayed( 1 ), + m_lastOffset( 0 ), + + m_periodStates( NULL ), + m_periodStatesCnt( 0 ) + { - // GUI + // GUI - vcf_cut_knob = new knob( knobBright_26, this, tr( "VCF Cutoff Frequency" ), - _channel_track ); - vcf_cut_knob->setRange( 0.0f, 1.5f, 0.005f ); // Originally [0,1.0] - vcf_cut_knob->setInitValue( 0.75f ); - vcf_cut_knob->move( 75, 130 ); - vcf_cut_knob->setHintText( tr( "Cutoff Freq:" ) + " ", "" ); - vcf_cut_knob->setLabel( tr("CUT") ); + m_vcfCutKnob = new knob( knobBright_26, this, tr( "VCF Cutoff Frequency" ), + _channel_track ); - vcf_res_knob = new knob( knobBright_26, this, tr( "VCF Resonance" ), - _channel_track ); - vcf_res_knob->setRange( 0.0f, 1.25f, 0.005f ); // Originally [0,1.0] - vcf_res_knob->setInitValue( 0.75f ); - vcf_res_knob->move( 120, 130 ); - vcf_res_knob->setHintText( tr( "Resonance:" ) + " ", "" ); - vcf_res_knob->setLabel( tr("RES") ); + m_vcfCutKnob->setRange( 0.0f, 1.5f, 0.005f ); // Originally [0,1.0] + m_vcfCutKnob->setInitValue( 0.75f ); + m_vcfCutKnob->move( 75, 130 ); + m_vcfCutKnob->setHintText( tr( "Cutoff Freq:" ) + " ", "" ); + m_vcfCutKnob->setLabel( tr( "CUT" ) ); - vcf_mod_knob = new knob( knobBright_26, this, tr( "VCF Envelope Mod" ), - _channel_track ); - vcf_mod_knob->setRange( 0.0f, 1.0f, 0.005f ); // Originally [0,1.0] - vcf_mod_knob->setInitValue( 1.0f ); - vcf_mod_knob->move( 165, 130 ); - vcf_mod_knob->setHintText( tr( "Env Mod:" ) + " ", "" ); - vcf_mod_knob->setLabel( tr("ENV MOD") ); + m_vcfResKnob = new knob( knobBright_26, this, tr( "VCF Resonance" ), + _channel_track ); - vcf_dec_knob = new knob( knobBright_26, this, tr( "VCF Envelope Decay" ), - _channel_track ); - vcf_dec_knob->setRange( 0.0f, 1.0f, 0.005f ); // Originally [0,1.0] - vcf_dec_knob->setInitValue( 0.1f ); - vcf_dec_knob->move( 210, 130 ); - vcf_dec_knob->setHintText( tr( "Decay:" ) + " ", "" ); - vcf_dec_knob->setLabel( tr("DEC") ); + m_vcfResKnob->setRange( 0.0f, 1.25f, 0.005f ); // Originally [0,1.0] + m_vcfResKnob->setInitValue( 0.75f ); + m_vcfResKnob->move( 120, 130 ); + m_vcfResKnob->setHintText( tr( "Resonance:" ) + " ", "" ); + m_vcfResKnob->setLabel( tr( "RES" ) ); - slideToggle = new ledCheckBox( "Slide", this, - tr( "Slide" ), - _channel_track ); - slideToggle->move( 10, 180 ); + m_vcfModKnob = new knob( knobBright_26, this, tr( "VCF Envelope Mod" ), + _channel_track ); + + m_vcfModKnob->setRange( 0.0f, 1.0f, 0.005f ); // Originally [0,1.0] + m_vcfModKnob->setInitValue( 1.0f ); + m_vcfModKnob->move( 165, 130 ); + m_vcfModKnob->setHintText( tr( "Env Mod:" ) + " ", "" ); + m_vcfModKnob->setLabel( tr( "ENV MOD" ) ); + + m_vcfDecKnob = new knob( knobBright_26, this, tr( "VCF Envelope Decay" ), + _channel_track ); + + m_vcfDecKnob->setRange( 0.0f, 1.0f, 0.005f ); // Originally [0,1.0] + m_vcfDecKnob->setInitValue( 0.1f ); + m_vcfDecKnob->move( 210, 130 ); + m_vcfDecKnob->setHintText( tr( "Decay:" ) + " ", "" ); + m_vcfDecKnob->setLabel( tr( "DEC" ) ); + + m_slideToggle = new ledCheckBox( "Slide", this, tr( "Slide" ), + _channel_track ); + + m_slideToggle->move( 10, 180 ); + + m_accentToggle = new ledCheckBox( "Accent", this, tr( "Accent" ), + _channel_track ); + m_accentToggle->move( 10, 200 ); + m_accentToggle->setDisabled( true ); + + m_deadToggle = new ledCheckBox( "Dead", this, tr( "Dead" ), + _channel_track ); + + m_deadToggle->move( 10, 220 ); + + m_db24Toggle = new ledCheckBox( "24dB/oct", this, + tr( "303-es-que, 24dB/octave, 3 pole filter" ), + _channel_track ); + + m_db24Toggle->move( 10, 150 ); + + m_slideDecKnob = new knob( knobBright_26, this, tr( "Slide Decay" ), + _channel_track ); + m_slideDecKnob->setRange( 0.0f, 1.0f, 0.005f ); // Originally [0,1.0] + m_slideDecKnob->setInitValue( 0.6f ); + m_slideDecKnob->move( 210, 75 ); + m_slideDecKnob->setHintText( tr( "Slide Decay:" ) + " ", "" ); + m_slideDecKnob->setLabel( tr( "SLIDE")); + + m_vcoFineDetuneKnob = new knob( knobBright_26, this, + tr( "Fine detuning of the VCO. Between -100 and 100 cents." ), + _channel_track ); + m_vcoFineDetuneKnob->setRange( -100.0f, 100.0f, 1.0f ); + m_vcoFineDetuneKnob->setInitValue( 0.0f ); + m_vcoFineDetuneKnob->move( 165, 75 ); + m_vcoFineDetuneKnob->setHintText( tr( "VCO Fine Detuning:" ) + " ", "cents" ); + m_vcoFineDetuneKnob->setLabel( tr( "DETUNE" ) ); - accentToggle = new ledCheckBox( "Accent", this, - tr( "Accent" ), - _channel_track ); - accentToggle->move( 10, 200 ); - accentToggle->setDisabled(true); + m_distKnob = new knob( knobBright_26, this, tr( "Distortion" ), + _channel_track ); + m_distKnob->setRange( 0.0f, 1.0f, 0.01f ); // Originally [0,1.0] + m_distKnob->setInitValue( 0.0f ); + m_distKnob->move( 210, 190 ); + m_distKnob->setHintText( tr( "DIST:" ) + " ", "" ); + m_distKnob->setLabel( tr( "DIST" ) ); + + m_waveKnob = new knob( knobBright_26, this, tr( "Waveform" ), + _channel_track ); + m_waveKnob->setRange( 0.0f, 5.0f, 1.0f ); // Originally [0,1.0] + m_waveKnob->setInitValue( 0.0f ); + m_waveKnob->move( 120, 75 ); + m_waveKnob->setHintText( tr( "WAVE:" ) + " ", "" ); + m_waveKnob->setLabel( tr( "WAVE" ) ); - deadToggle = new ledCheckBox( "Dead", this, - tr( "Dead" ), - _channel_track ); - deadToggle->move( 10, 220 ); + connect( m_vcfCutKnob, SIGNAL( valueChanged( float ) ), + this, SLOT ( filterChanged( float ) ) ); - db24Toggle = new ledCheckBox( "24dB/oct", this, - tr( "303-es-que, 24dB/octave, 3 pole filter" ), - _channel_track ); - db24Toggle->move( 10, 150); + connect( m_vcfResKnob, SIGNAL( valueChanged( float ) ), + this, SLOT ( filterChanged( float ) ) ); + connect( m_vcfModKnob, SIGNAL( valueChanged( float ) ), + this, SLOT ( filterChanged( float ) ) ); - slide_dec_knob = new knob( knobBright_26, this, tr( "Slide Decay" ), - _channel_track ); - slide_dec_knob->setRange( 0.0f, 1.0f, 0.005f ); // Originally [0,1.0] - slide_dec_knob->setInitValue( 0.6f ); - slide_dec_knob->move( 210, 75 ); - slide_dec_knob->setHintText( tr( "Slide Decay:" ) + " ", "" ); - slide_dec_knob->setLabel( tr( "SLIDE")); + connect( m_vcfDecKnob, SIGNAL( valueChanged( float ) ), + this, SLOT ( filterChanged( float ) ) ); - vco_fine_detune_knob = new knob( knobBright_26, this, - tr("Fine detuning of the VCO. Ranged between -100 and 100 centes."), - _channel_track ); - vco_fine_detune_knob->setRange(-100.0f, 100.0f, 1.0f); - vco_fine_detune_knob->setInitValue(0.0f); - vco_fine_detune_knob->move(165,75); - vco_fine_detune_knob->setHintText( tr( "VCO Fine Detuning:") + " ", "cents"); - vco_fine_detune_knob->setLabel( tr( "DETUNE")); + connect( m_vcoFineDetuneKnob, SIGNAL( valueChanged( float ) ), + this, SLOT ( detuneChanged( float) ) ); + connect( m_db24Toggle, SIGNAL( toggled( bool ) ), + this, SLOT ( db24Toggled( bool) ) ); - dist_knob = new knob( knobBright_26, this, tr( "Distortion" ), - _channel_track ); - dist_knob->setRange( 0.0f, 1.0f, 0.01f ); // Originally [0,1.0] - dist_knob->setInitValue( 0.0f ); - dist_knob->move( 210, 190 ); - dist_knob->setHintText( tr( "DIST:" ) + " ", "" ); - dist_knob->setLabel( tr( "DIST")); + connect( m_distKnob, SIGNAL( valueChanged(float) ), + this, SLOT ( filterChanged( float ) ) ); + connect( m_waveKnob, SIGNAL( valueChanged(float) ), + this, SLOT ( waveChanged( float ) ) ); - wave_knob = new knob( knobBright_26, this, tr( "Waveform" ), - _channel_track ); - wave_knob->setRange( 0.0f, 5.0f, 1.0f ); // Originally [0,1.0] - wave_knob->setInitValue( 0.0f ); - wave_knob->move( 120, 75 ); - wave_knob->setHintText( tr( "WAVE:" ) + " ", "" ); - wave_knob->setLabel( tr( "WAVE")); - - - connect( vcf_cut_knob, SIGNAL( valueChanged( float ) ), - this, SLOT ( filterChanged( float ) ) ); - - connect( vcf_res_knob, SIGNAL( valueChanged( float ) ), - this, SLOT ( filterChanged( float ) ) ); - - connect( vcf_mod_knob, SIGNAL( valueChanged( float ) ), - this, SLOT ( filterChanged( float ) ) ); - - connect( vcf_dec_knob, SIGNAL( valueChanged( float ) ), - this, SLOT ( filterChanged( float ) ) ); - - connect( vco_fine_detune_knob, SIGNAL( valueChanged( float ) ), - this, SLOT ( detuneChanged( float) ) ); - - connect( db24Toggle, SIGNAL( toggled( bool ) ), - this, SLOT ( db24Toggled( bool) ) ); - - connect( dist_knob, SIGNAL( valueChanged(float) ), - this, SLOT ( filterChanged( float ))); - - connect( wave_knob, SIGNAL( valueChanged(float) ), - this, SLOT ( waveChanged( float ))); - - setAutoFillBackground( TRUE ); + setAutoFillBackground( FALSE ); QPalette pal; - pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( - "artwork" ) ); + pal.setBrush( backgroundRole(), + PLUGIN_NAME::getIconPixmap( "artwork" ) ); setPalette( pal ); - // SYNTH + // SYNTH - vco_inc = 0.0; - vco_c = 0; - vco_k = 0; - - vco_slide = 0; vco_slideinc = 0; - vco_slidebase = 0; + m_fs.cutoff = 0; + m_fs.envmod = 0; + m_fs.reso = 0; + m_fs.envdecay = 0; + m_fs.dist = 0; - fs.cutoff = 0; fs.envmod = 0; - fs.reso = 0; fs.envdecay = 0; - fs.dist = 0; + m_vcf = new lb302FilterIIR2( &m_fs ); - vcf_envpos = ENVINC; - vco_detune = 0; + recalcFilter(); - vca_mode = 3; vca_a = 0; // Start VCA on an attack. - - //vca_attack = 1.0 - 0.94406088; - vca_attack = 1.0 - 0.96406088; - vca_decay = 0.99897516; - - vco_shape = SAWTOOTH; - - vca_a0 = 0.5; // Experimenting between original (0.5) and 1.0 - vca_a = 9; - vca_mode = 3; - - vcf = new lb302FilterIIR2(&fs); - - use_hold_note = false; - sample_cnt = 0; - release_frame = 1<<24; - catch_frame = 0; - catch_decay = 0; - - recalcFilter(); - - lastFramesPlayed = 1; // because we subtract 1 later - last_offset = 0; - - period_states = NULL; - period_states_cnt = 0; - - filterChanged(0.0); - detuneChanged(0.0); + filterChanged( 0.0 ); + detuneChanged( 0.0 ); } - - lb302Synth::~lb302Synth() { - delete vcf; + delete m_vcf; } void lb302Synth::saveSettings( QDomDocument & _doc, - QDomElement & _this ) + QDomElement & _this ) { - vcf_cut_knob->saveSettings( _doc, _this, "vcf_cut" ); - vcf_res_knob->saveSettings( _doc, _this, "vcf_res" ); - vcf_mod_knob->saveSettings( _doc, _this, "vcf_mod" ); - vcf_dec_knob->saveSettings( _doc, _this, "vcf_dec" ); + m_vcfCutKnob->saveSettings( _doc, _this, "vcf_cut" ); + m_vcfResKnob->saveSettings( _doc, _this, "vcf_res" ); + m_vcfModKnob->saveSettings( _doc, _this, "vcf_mod" ); + m_vcfDecKnob->saveSettings( _doc, _this, "vcf_dec" ); - vco_fine_detune_knob->saveSettings( _doc, _this, "vco_detune" ); - wave_knob->saveSettings( _doc, _this, "shape"); - dist_knob->saveSettings( _doc, _this, "dist"); - slide_dec_knob->saveSettings( _doc, _this, "slide_dec"); + m_vcoFineDetuneKnob->saveSettings( _doc, _this, "vco_detune" ); + m_waveKnob->saveSettings( _doc, _this, "shape" ); + m_distKnob->saveSettings( _doc, _this, "dist" ); + m_slideDecKnob->saveSettings( _doc, _this, "slide_dec" ); - slideToggle->saveSettings( _doc, _this, "slide"); - deadToggle->saveSettings( _doc, _this, "dead"); - db24Toggle->saveSettings( _doc, _this, "db24"); + m_slideToggle->saveSettings( _doc, _this, "slide" ); + m_deadToggle->saveSettings( _doc, _this, "dead" ); + m_db24Toggle->saveSettings( _doc, _this, "db24" ); } - - void lb302Synth::loadSettings( const QDomElement & _this ) { - vcf_cut_knob->loadSettings( _this, "vcf_cut" ); - vcf_res_knob->loadSettings( _this, "vcf_res" ); - vcf_mod_knob->loadSettings( _this, "vcf_mod" ); - vcf_dec_knob->loadSettings( _this, "vcf_dec" ); + m_vcfCutKnob->loadSettings( _this, "vcf_cut" ); + m_vcfResKnob->loadSettings( _this, "vcf_res" ); + m_vcfModKnob->loadSettings( _this, "vcf_mod" ); + m_vcfDecKnob->loadSettings( _this, "vcf_dec" ); - vco_fine_detune_knob->loadSettings( _this, "vco_detune" ); - dist_knob->loadSettings( _this, "dist"); - wave_knob->loadSettings( _this, "shape"); - slide_dec_knob->loadSettings( _this, "slide_dec"); + m_vcoFineDetuneKnob->loadSettings( _this, "vco_detune" ); + m_distKnob->loadSettings( _this, "dist" ); + m_waveKnob->loadSettings( _this, "shape" ); + m_slideDecKnob->loadSettings( _this, "slide_dec" ); - slideToggle->loadSettings( _this, "slide"); - deadToggle->loadSettings( _this, "dead"); - db24Toggle->loadSettings( _this, "db24"); + m_slideToggle->loadSettings( _this, "slide" ); + m_deadToggle->loadSettings( _this, "dead" ); + m_db24Toggle->loadSettings( _this, "db24" ); - filterChanged(0.0); - detuneChanged(0.0); + filterChanged( 0.0 ); + detuneChanged( 0.0 ); } + // TODO: Split into one function per knob. envdecay doesn't require // recalcFilter. void lb302Synth::filterChanged( float ) { - fs.cutoff = vcf_cut_knob->value(); - fs.reso = vcf_res_knob->value(); - fs.envmod = vcf_mod_knob->value(); - fs.dist = LB_DIST_RATIO*dist_knob->value(); + m_fs.cutoff = m_vcfCutKnob->value(); + m_fs.reso = m_vcfResKnob->value(); + m_fs.envmod = m_vcfModKnob->value(); + m_fs.dist = m_distKnob->value() * LB_DIST_RATIO; - float d = 0.2 + (2.3*vcf_dec_knob->value()); - d*=LB_HZ; // d *= smpl rate - fs.envdecay = pow(0.1, 1.0/d * ENVINC); // decay is 0.1 to the 1/d * ENVINC - // vcf_envdecay is now adjusted for both - // sampling rate and ENVINC - recalcFilter(); + float d = 0.2 + ( 2.3 * m_vcfDecKnob->value() ); + d *= LB_HZ; + m_fs.envdecay = pow( 0.1, 1.0 / d * ENVINC ); + // vcf_envdecay is now adjusted for both sampling rate and ENVINC + + recalcFilter(); } + void lb302Synth::db24Toggled( bool ) { - delete vcf; - if(db24Toggle->isChecked()) { - vcf = new lb302Filter3Pole(&fs); - } - else { - vcf = new lb302FilterIIR2(&fs); - } - recalcFilter(); + delete m_vcf; + + if( m_db24Toggle->isChecked() ) { + m_vcf = new lb302Filter3Pole( &m_fs ); + } + else { + m_vcf = new lb302FilterIIR2( &m_fs ); + } + recalcFilter(); } void lb302Synth::detuneChanged( float ) { - float freq = vco_inc*LB_HZ/vco_detune; - float slidebase_freq=0; + float freq = m_vco_inc * LB_HZ / m_vco_detune; + float slidebase_freq = 0; - if(vco_slide) { - slidebase_freq = vco_slidebase*LB_HZ/vco_detune; - } - - vco_detune = powf(2.0f, (float)vco_fine_detune_knob->value()/1200.0f); - vco_inc = freq*vco_detune/LB_HZ; + if( m_vco_slide ) { + slidebase_freq = m_vco_slidebase * LB_HZ / m_vco_detune; + } - // If a slide note is pending, - if(vco_slideinc) - vco_slideinc = vco_inc; + m_vco_detune = powf( 2.0f, + (float)m_vcoFineDetuneKnob->value() / 1200.0f); - // If currently sliding, - // May need to rescale vco_slide as well - if(vco_slide) - vco_slidebase=slidebase_freq*vco_detune/LB_HZ; + m_vco_inc = freq * m_vco_detune/LB_HZ; + + // If a slide note is pending, + if( m_vco_slideinc ) + m_vco_slideinc = m_vco_inc; + + // If currently sliding, + // May need to rescale vco_slide as well + if( m_vco_slide) + m_vco_slidebase = slidebase_freq * m_vco_detune / LB_HZ; } + // TODO: Set vco_shape in here. void lb302Synth::waveChanged( float ) { - switch(int(rint(wave_knob->value()))) { - case 0: wave_knob->setHintText(tr("Sawtooth "),""); break; - case 1: wave_knob->setHintText(tr("Inverted Sawtooth "),""); break; - case 2: wave_knob->setHintText(tr("Triangle "),""); break; - case 3: wave_knob->setHintText(tr("Square "),""); break; - case 4: wave_knob->setHintText(tr("Rounded Square "),""); break; - case 5: wave_knob->setHintText(tr("Moog "),""); break; - } + switch( (int)rint( m_waveKnob->value() ) ) { + case 0: + m_waveKnob->setHintText( tr( "Sawtooth " ), "" ); + break; + case 1: + m_waveKnob->setHintText( tr( "Inverted Sawtooth " ), "" ); + break; + case 2: + m_waveKnob->setHintText( tr( "Triangle " ), "" ); + break; + case 3: + m_waveKnob->setHintText( tr( "Square " ), "" ); + break; + case 4: + m_waveKnob->setHintText( tr( "Rounded Square " ), "" ); + break; + case 5: + m_waveKnob->setHintText( tr( "Moog " ), "" ); + break; + } } + QString lb302Synth::nodeName( void ) const { return( lb302_plugin_descriptor.name ); @@ -607,224 +656,216 @@ QString lb302Synth::nodeName( void ) const // OBSOLETE. Break apart once we get Q_OBJECT to work. >:[ void lb302Synth::recalcFilter() { - vcf->recalc(); + m_vcf->recalc(); - // THIS IS OLD 3pole/24dB code, I may reintegrate it. Don't need it - // right now. Should be toggled by LB_24_RES_TRICK at the moment. + // THIS IS OLD 3pole/24dB code, I may reintegrate it. Don't need it + // right now. Should be toggled by LB_24_RES_TRICK at the moment. - /*kfcn = 2.0 * (((vcf_cutoff*3000))) / LB_HZ; - kp = ((-2.7528*kfcn + 3.0429)*kfcn + 1.718)*kfcn - 0.9984; - kp1 = kp+1.0; - kp1h = 0.5*kp1; - kres = (((vcf_reso))) * (((-2.7079*kp1 + 10.963)*kp1 - 14.934)*kp1 + 8.4974); - value = 1.0+( (((0))) *(1.5 + 2.0*kres*(1.0-kfcn))); // ENVMOD was DIST*/ + /*kfcn = 2.0 * (((vcf_cutoff*3000))) / LB_HZ; + kp = ((-2.7528*kfcn + 3.0429)*kfcn + 1.718)*kfcn - 0.9984; + kp1 = kp+1.0; + kp1h = 0.5*kp1; + kres = (((vcf_reso))) * (((-2.7079*kp1 + 10.963)*kp1 - 14.934)*kp1 + 8.4974); + value = 1.0+( (((0))) *(1.5 + 2.0*kres*(1.0-kfcn))); // ENVMOD was DIST*/ - vcf_envpos = ENVINC; // Trigger filter update in process() + m_vcf_envpos = ENVINC; // Trigger filter update in process() } -inline int MIN(int a, int b) { - return (a= ENVINC) { - vcf->envRecalc(); - - vcf_envpos = 0; + if( m_vcf_envpos >= ENVINC ) { + m_vcf->envRecalc(); - if (vco_slide) { - vco_inc=vco_slidebase-vco_slide; - // Calculate coeff from dec_knob on knob change. - vco_slide*= 0.9+(slide_dec_knob->value()*0.0999); // TODO: Adjust for Hz and ENVINC + m_vcf_envpos = 0; - } + if( m_vco_slide ) { + m_vco_inc = m_vco_slidebase - m_vco_slide; + // Calculate coeff from dec_knob on knob change. + // TODO: Adjust for Hz and ENVINC + m_vco_slide *= 0.9 + ( m_slideDecKnob->value() * 0.0999 ); + } } - sample_cnt++; - vcf_envpos++; + m_sampleCnt++; + m_vcf_envpos++; - // unused variables - //float old_vco_k = vco_k; - //bool looking; - int decay_frames = 128; + int decayFrames = 128; // update vco - vco_c += vco_inc; + m_vco_c += m_vco_inc; - if(vco_c > 0.5) vco_c -= 1.0; + if( m_vco_c > 0.5 ) + m_vco_c -= 1.0; - if (catch_decay > 0) { - if (catch_decay < decay_frames) { - catch_decay++; - } - else if (use_hold_note) { - use_hold_note = false; - initNote(&hold_note); - } - } - - - switch(int(rint(wave_knob->value()))) { - case 0: vco_shape = SAWTOOTH; break; - case 1: vco_shape = INVERTED_SAWTOOTH; break; - case 2: vco_shape = TRIANGLE; break; - case 3: vco_shape = SQUARE; break; - case 4: vco_shape = ROUND_SQUARE; break; - case 5: vco_shape = MOOG; break; - default: vco_shape = SAWTOOTH; break; - } - - // add vco_shape_param the changes the shape of each curve. - // merge sawtooths with triangle and square with round square? - switch (vco_shape) { - case SAWTOOTH: // p0: curviness of line - vco_k = vco_c; // Is this sawtooth backwards? - break; - - case INVERTED_SAWTOOTH: // p0: curviness of line - vco_k = -vco_c; // Is this sawtooth backwards? - break; - - // TODO: I think TRIANGLE is broken. - case TRIANGLE: // p0: duty rev.saw<->triangle<->saw p1: curviness - vco_k = (vco_c*2.0)+0.5; - if (vco_k>0.5) vco_k = 1.0-vco_k; - break; - - case SQUARE: // p0: slope of top - vco_k = (vco_c<0)?0.5:-0.5; - break; - - case ROUND_SQUARE: // p0: width of round - vco_k = (vco_c<0)?(sqrtf(1-(vco_c*vco_c*4))-0.5):-0.5; - break; - - case MOOG: // Maybe the fall should be exponential/sinsoidal instead of quadric. - // [-0.5, 0]: Rise, [0,0.25]: Slope down, [0.25,0.5]: Low - vco_k = (vco_c*2.0)+0.5; - if (vco_k>1.0) vco_k = -0.5 ; - else if (vco_k>0.5) { - w = 2.0*(vco_k-0.5)-1.0; - vco_k = 0.5 - sqrtf(1.0-(w*w)); - } - vco_k *= 2.0; // MOOG wave gets filtered away - break; - } - - //vca_a = 0.5; - // Write out samples. -#ifdef LB_FILTERED - samp = vcf->process(vco_k)*2.0*vca_a; -#else - samp = vco_k*vca_a; -#endif - /* - float releaseFrames = desiredReleaseFrames(); - samp *= (releaseFrames - catch_decay)/releaseFrames; - */ - samp *= (float)(decay_frames - catch_decay)/(float)decay_frames; - - for(int c=0; c=release_frame) { - vca_mode=1; - } - - // Handle Envelope - // TODO: Add decay once I figure out how to extend past the end of a note. - if(vca_mode==0) { - vca_a+=(vca_a0-vca_a)*vca_attack; - if(sample_cnt>=0.5*44100) - vca_mode = 2; - } - else if(vca_mode == 1) { - vca_a *= vca_decay; - - // the following line actually speeds up processing - if(vca_a < (1/65536.0)) { vca_a = 0; vca_mode = 3; } + if( m_catchDecay > 0 ) { + if( m_catchDecay < decayFrames ) { + m_catchDecay++; + } + else if( m_useHoldNote ) { + m_useHoldNote = false; + initNote( &m_holdNote ); + } } - // Store state - period_states[i].vco_c = vco_c; - period_states[i].vca_a = vca_a; // Doesn't change anything (currently) - period_states[i].vca_mode = vca_mode; // Doesn't change anything (currently) - period_states[i].sample_cnt = sample_cnt; // Doesn't change anything (currently) - vcf->getState(&period_states[i].fs); + + switch( (int)rint( m_waveKnob->value() ) ) { + case 0: m_vco_shape = SAWTOOTH; break; + case 1: m_vco_shape = INVERTED_SAWTOOTH; break; + case 2: m_vco_shape = TRIANGLE; break; + case 3: m_vco_shape = SQUARE; break; + case 4: m_vco_shape = ROUND_SQUARE; break; + case 5: m_vco_shape = MOOG; break; + default: m_vco_shape = SAWTOOTH; break; + } + + // add vco_shape_param the changes the shape of each curve. + // merge sawtooths with triangle and square with round square? + switch (m_vco_shape) { + case SAWTOOTH: // p0: curviness of line + m_vco_k = m_vco_c; // Is this sawtooth backwards? + break; + + case INVERTED_SAWTOOTH: // p0: curviness of line + m_vco_k = -m_vco_c; // Is this sawtooth backwards? + break; + + case TRIANGLE: // p0: duty rev.saw<->triangle<->saw p1: curviness + m_vco_k = ( m_vco_c * 2.0 ) + 0.5; + if( m_vco_k > 0.5 ) + m_vco_k = 1.0 - m_vco_k; + break; + + case SQUARE: // p0: slope of top + m_vco_k = ( m_vco_c < 0 ) ? 0.5 : -0.5; + break; + + case ROUND_SQUARE: // p0: width of round + m_vco_k = ( m_vco_c < 0 ) ? + ( sqrtf( 1 - ( m_vco_c*m_vco_c * 4 ) ) - 0.5) : + -0.5; + break; + + case MOOG: // Maybe the fall should be exponential/sinsoidal instead of quadric. + // [-0.5, 0]: Rise, [0,0.25]: Slope down, [0.25,0.5]: Low + m_vco_k = ( m_vco_c * 2.0 ) + 0.5; + if( m_vco_k > 1.0 ) + m_vco_k = -0.5; + else if( m_vco_k > 0.5 ) { + w = 2.0 * ( m_vco_k - 0.5 ) - 1.0; + m_vco_k = 0.5 - sqrtf( 1.0 - w*w ); + } + m_vco_k *= 2.0; // MOOG wave gets filtered away + break; + } + + // Write out samples. +#ifdef LB_FILTERED + samp = m_vcf->process( m_vco_k ) * 2.0 * m_vca_a; +#else + samp = m_vco_k * m_vca_a; +#endif + /* + float releaseFrames = desiredReleaseFrames(); + samp *= (releaseFrames - catch_decay)/releaseFrames; + */ + samp *= (float)( decayFrames - m_catchDecay ) / + (float)decayFrames; + + for( int c=0; c < DEFAULT_CHANNELS; c++ ) { + _outbuf[i][c] = samp; + } + + + if( (int)i >= m_releaseFrame ) { + m_vca_mode = 1; + } + + // Handle Envelope + // TODO: Add decay once I figure out how to extend past the end of a note. + if( m_vca_mode == 0 ) { + m_vca_a += ( m_vca_a0 - m_vca_a ) * m_vca_attack; + if( m_sampleCnt >= 0.5 * 44100 ) + m_vca_mode = 2; + } + else if( m_vca_mode == 1) { + m_vca_a *= m_vca_decay; + + // the following line actually speeds up processing + if( m_vca_a < 1/65536.0 ) { + m_vca_a = 0; + m_vca_mode = 3; + } + } + // Store state + m_periodStates[i].vco_c = m_vco_c; + m_periodStates[i].vca_a = m_vca_a; // Doesn't change anything (currently) + m_periodStates[i].vca_mode = m_vca_mode; // Doesn't change anything (currently) + m_periodStates[i].sampleCnt = m_sampleCnt; // Doesn't change anything (currently) + m_vcf->getState(&m_periodStates[i].fs); } return 1; } + /* Prepares the active LB302 note. I separated this into a function because it - * needs to be called on0playNote() when a new note is started. It also needs + * needs to be called onPlayNote() when a new note is started. It also needs * to be called from process() when a prior edge-to-edge note is done releasing. */ -void lb302Synth::initNote( lb302Note *n) +void lb302Synth::initNote( lb302Note * _n ) { - catch_decay = 0; + m_catchDecay = 0; - vco_inc = n->vco_inc; - - // TODO: Try moving to the if() below - if(n->dead == 0 || (vca_mode==1 || vca_mode==3)) { - sample_cnt = 0; - vca_mode = 0; vca_a = 0; - } - else { - vca_mode = 2; - } + m_vco_inc = _n->vco_inc; - // Initiate Slide - // TODO: Break out into function, should be called again on detuneChanged - if (vco_slideinc) { - vco_slide = vco_inc-vco_slideinc; - vco_slidebase = vco_inc; - vco_slideinc = 0; - } - else { - vco_slide = 0; - } - // End break-out + // TODO: Try moving to the if() below + if( _n->dead == 0 || ( m_vca_mode == 1 || m_vca_mode == 3 ) ) { + m_sampleCnt = 0; + m_vca_mode = 0; + m_vca_a = 0; + } + else { + m_vca_mode = 2; + } - // Slide note, save inc for next note - if (slideToggle->value()) { - vco_slideinc = vco_inc; // May need to equal vco_slidebase+vco_slide if last note slid - } + // Initiate Slide + // TODO: Break out into function, should be called again on detuneChanged + if( m_vco_slideinc ) { + m_vco_slide = m_vco_inc - m_vco_slideinc; + m_vco_slidebase = m_vco_inc; + m_vco_slideinc = 0; + } + else { + m_vco_slide = 0; + } + // End break-out + // Slide note, save inc for next note + if( m_slideToggle->value() ) { + // May need to equal vco_slidebase+vco_slide if last note slid + m_vco_slideinc = m_vco_inc; + } - recalcFilter(); - - if(n->dead ==0){ - // Swap next two blocks?? - vcf->playNote(); - // Ensure envelope is recalculated - vcf_envpos = ENVINC; + recalcFilter(); - // Double Check - vca_mode = 0; - vca_a = 0.0; - } + if( _n->dead == 0 ) { + // Swap next two blocks?? + m_vcf->playNote(); + // Ensure envelope is recalculated + m_vcf_envpos = ENVINC; + + // Better safe then sorry + m_vca_mode = 0; + m_vca_a = 0.0; + } } @@ -846,18 +887,21 @@ void lb302Synth::playNote( notePlayHandle * _n, bool ) // per default we resume at the last played frames - only in // some special-cases (which we catch below) we have to resume // somewhere else - f_cnt_t resume_pos = lastFramesPlayed-1; + f_cnt_t resumePos = m_lastFramesPlayed - 1; - bool decay_note = false; + bool decayNote = false; // find out which situation we're in constNotePlayHandleVector v = - notePlayHandle::nphsOfInstrumentTrack( getInstrumentTrack(), TRUE ); + notePlayHandle::nphsOfInstrumentTrack( + getInstrumentTrack(), TRUE ); + // more than one note running? if( v.count() > 1 ) { - const notePlayHandle * on = v.first(); // oldest note - const notePlayHandle * yn = v.last(); // youngest note + const notePlayHandle * on = v.first(); // oldest note + const notePlayHandle * yn = v.last(); // youngest note + // are we playing a released note and the new (youngest) note // has taken over successfully (i.e. played more than the // difference of the two offsets)? @@ -865,7 +909,7 @@ void lb302Synth::playNote( notePlayHandle * _n, bool ) yn->totalFramesPlayed() >= yn->offset() - on->offset() ) { // then we do not need to play something anymore - return; + return; } // have to fill up the frames left to the new note so limit @@ -889,120 +933,103 @@ void lb302Synth::playNote( notePlayHandle * _n, bool ) // the offset of the youngest note, otherwise we get // frames with both waves overlapped engine::getMixer()->clearAudioBuffer( - _n->getInstrumentTrack()->getAudioPort()-> - firstBuffer(), - framesPerPeriod - yn->offset(), yn->offset() ); - resume_pos = yn->offset() - on->offset() - 1; + _n->getInstrumentTrack()->getAudioPort()->firstBuffer(), + framesPerPeriod - yn->offset(), + yn->offset() ); + + resumePos = yn->offset() - on->offset() - 1; // make sure we have positive value, otherwise we're // accessing states out of borders - while( resume_pos < 0 ) + while( resumePos < 0 ) { - resume_pos += framesPerPeriod; + resumePos += framesPerPeriod; } - decay_note = true; - } + decayNote = true; + } } -#ifdef LB_DEBUG - if( _n->released() ) - { - } - else - { - } - -#endif - ///=== WEIRD CODE FOR MONOPHONIC BEHAVIOUR - END === /// /// Malloc our period history buffer - if (period_states == NULL) { - period_states = new lb302State[framesPerPeriod]; + if( m_periodStates == NULL ) { + m_periodStates = new lb302State[framesPerPeriod]; - for (int i=0; i < framesPerPeriod; i++) { - period_states[i].vco_c = vco_c; - period_states[i].vca_a = vca_a; // Doesn't change anything (currently) - period_states[i].vca_mode = vca_mode; // Doesn't change anything (currently) - period_states[i].sample_cnt = sample_cnt; // Doesn't change anything (currently) - vcf->getState(&period_states[i].fs); - } - } + for( int i = 0; i < framesPerPeriod; i++ ) { + m_periodStates[i].vco_c = m_vco_c; + m_periodStates[i].vca_a = m_vca_a; // Doesn't change anything (currently) + m_periodStates[i].vca_mode = m_vca_mode; // Doesn't change anything (currently) + m_periodStates[i].sampleCnt = m_sampleCnt; // Doesn't change anything (currently) + m_vcf->getState( &m_periodStates[i].fs ); + } + } - // now resume at the proper position and process as usual - lb302State *state = &period_states[resume_pos]; + // now resume at the proper position and process as usual + lb302State * state = &m_periodStates[resumePos]; - /// Actually resume the state, now that we have the right state object. - vco_c = state->vco_c; - vca_a = state->vca_a; - vca_mode = state->vca_mode; - sample_cnt = state->sample_cnt; - vcf->setState(&state->fs); + /// Actually resume the state, now that we have the right state object. + m_vco_c = state->vco_c; + m_vca_a = state->vca_a; + m_vca_mode = state->vca_mode; + m_sampleCnt = state->sampleCnt; + m_vcf->setState( &state->fs ); - /// Currently have release/decay disabled - // Start the release decay if this is the first release period. - //if (_n->released() && catch_decay == 0) - // catch_decay = 1; - + m_releaseFrame = _n->framesLeft() - desiredReleaseFrames(); - release_frame = _n->framesLeft() - desiredReleaseFrames(); + if( _n->totalFramesPlayed() <= 0 ) { - if ( _n->totalFramesPlayed() <= 0 ) { - /// This code is obsolete, hence the "if false" - - // Existing note. Allow it to decay. - if(deadToggle->value()==0 && decay_note) { + // Existing note. Allow it to decay. + if( m_deadToggle->value() == 0 && decayNote ) { #ifdef LB_DECAY - if (catch_decay < 1) { - // BEGIN NOT SURE OF... - //lb302State *st = &period_states[period_states_cnt-1]; - //vca_a = st->vca_a; - //sample_cnt = st->sample_cnt; - // END NOT SURE OF + if( m_catchDecay < 1 ) { + // BEGIN NOT SURE OF... + //lb302State *st = &period_states[period_states_cnt-1]; + //vca_a = st->vca_a; + //sample_cnt = st->sample_cnt; + // END NOT SURE OF - // Reserve this note for retrigger in process() - hold_note.vco_inc = _n->frequency()*vco_detune/LB_HZ; // TODO: Use actual sampling rate. - hold_note.dead = deadToggle->value(); - use_hold_note = true; - catch_decay = 1; - } - else { - } + // Reserve this note for retrigger in process() + m_holdNote.vco_inc = _n->frequency() * m_vco_detune/LB_HZ; + m_holdNote.dead = m_deadToggle->value(); + m_useHoldNote = true; + m_catchDecay = 1; + } #else - lb302Note note; - note.vco_inc = _n->frequency()*vco_detune/LB_HZ; // TODO: Use actual sampling rate. - note.dead = deadToggle->value(); - initNote(¬e); - vca_mode=0; - vca_a = state->vca_a; + lb302Note note; + note.vco_inc = _n->frequency() * m_vco_detune/LB_HZ; + note.dead = m_deadToggle->value(); + + initNote( ¬e ); + m_vca_mode = 0; + m_vca_a = state->vca_a; #endif - } - /// Start a new note. - else { - lb302Note note; - note.vco_inc = _n->frequency()*vco_detune/LB_HZ; // TODO: Use actual sampling rate. - note.dead = deadToggle->value(); - initNote(¬e); - use_hold_note = false; - } + } + /// Start a new note. + else { + lb302Note note; + note.vco_inc = _n->frequency() * m_vco_detune/LB_HZ; + note.dead = m_deadToggle->value(); + + initNote( ¬e ); + m_useHoldNote = false; + } + } - } - sampleFrame *buf = new sampleFrame[frames]; - process(buf, frames); - getInstrumentTrack()->processAudioBuffer( buf, frames, _n ); + process( buf, frames ); + getInstrumentTrack()->processAudioBuffer( buf, frames, _n ); - delete[] buf; + delete[] buf; - lastFramesPlayed = frames;//_n->framesLeftForCurrentPeriod(); //_n->totalFramesPlayed(); + m_lastFramesPlayed = frames; + //_n->framesLeftForCurrentPeriod(); //_n->totalFramesPlayed(); } - void lb302Synth::deleteNotePluginData( notePlayHandle * _n ) { } @@ -1012,13 +1039,12 @@ void lb302Synth::deleteNotePluginData( notePlayHandle * _n ) extern "C" { -// neccessary for getting instance out of shared lib -plugin * lmms_plugin_main( void * _data ) -{ -return( new lb302Synth( - static_cast( _data ) ) ); -} - + // neccessary for getting instance out of shared lib + plugin * lmms_plugin_main( void * _data ) + { + return( new lb302Synth( + static_cast( _data ) ) ); + } } diff --git a/plugins/lb302/lb302.h b/plugins/lb302/lb302.h index 0311394e7..54f8b0efe 100644 --- a/plugins/lb302/lb302.h +++ b/plugins/lb302/lb302.h @@ -3,12 +3,12 @@ * emulate the Roland TB303 bass synth * * Copyright (c) 2006-2007 Paul Giblock - * + * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * * lb302FilterIIR2 is based on the gsyn filter code by Andy Sloane. - * - * lb302Filter3Pole is based on the TB303 instrument written by + * + * lb302Filter3Pole is based on the TB303 instrument written by * Josep M Comajuncosas for the CSounds library * * This program is free software; you can redistribute it and/or @@ -41,260 +41,281 @@ class knob; class notePlayHandle; -class lb302FilterKnobState + +// lb302FilterKnobState +// Bridges the lb302 plugin and it's active filter. +struct lb302FilterKnobState { - public: - float cutoff; - float reso; - float envmod; - float envdecay; - float dist; +public: + float cutoff; + float reso; + float envmod; + float envdecay; + float dist; }; -class lb302FilterIIR2State + +// lb302FilterIIR2State +// State of the IIR2 filter, separated for achieving gapless playback +struct lb302FilterIIR2State { - public: - float vcf_c0; - float vcf_a; - float vcf_b; - float vcf_c; - float vcf_d1; - float vcf_d2; +public: + float c0; + float a; + float b; + float c; + float d1; + float d2; }; -class lb302Filter3PoleState + +// lb302Filter3PoleState +// State of the 3-Pole filter, separated for achieving gapless playback +struct lb302Filter3PoleState { - public: - float vcf_c0; - float kp, - kp1h, - kres, - ay1, - ay2, - lastin, - value; - float aout; +public: + float c0; + float kp; + float kp1h; + float kres; + float ay1; + float ay2; + float lastin; + float value; + float aout; }; - -typedef union + + +// lb302FilterState +// Captured state of the active filter. Allows lb302State to generically +// hold on to one state or the other, without caring. +typedef union { - lb302FilterIIR2State iir; - lb302Filter3PoleState pole; -} + lb302FilterIIR2State iir; + lb302Filter3PoleState pole; +} lb302FilterState; +// lb302Filter +// Used to filter the lb302. Uses FilterKnobState pointer as input class lb302Filter { - public: - lb302Filter(lb302FilterKnobState* p_fs); - virtual ~lb302Filter() {}; +public: + lb302Filter( lb302FilterKnobState* _fs ); + virtual ~lb302Filter( void ) {}; - virtual void recalc(); - virtual void envRecalc(); - virtual float process(const float& samp)=0; - virtual void playNote(); + virtual void recalc( void ); + virtual void envRecalc( void ); + virtual float process( const float & _samp ) = 0; + virtual void playNote( void ); - virtual void getState(lb302FilterState* fs)=0; - virtual void setState(const lb302FilterState* fs)=0; + virtual void getState( lb302FilterState * _fs ) = 0; + virtual void setState( const lb302FilterState * _fs ) = 0; - protected: - lb302FilterKnobState *fs; - - // Filter Decay - float vcf_c0; // c0=e1 on retrigger; c0*=ed every sample; cutoff=e0+c0 - float vcf_e0, // e0 and e1 for interpolation - vcf_e1; - float vcf_rescoeff; // Resonance coefficient [0.30,9.54] +protected: + lb302FilterKnobState *m_fs; + + // Filter Decay + float m_c0; // c0=e1 on retrigger; c0*=ed every sample; + float m_e0; // e0 and e1 for interpolation + float m_e1; + float m_rescoeff; // Resonance coefficient [0.30,9.54] }; + +// lb302FilterIIR2 +// The IIR2 filter implementation class lb302FilterIIR2 : public lb302Filter { - public: - lb302FilterIIR2(lb302FilterKnobState* p_fs); - virtual ~lb302FilterIIR2(); +public: + lb302FilterIIR2( lb302FilterKnobState * _fs ); + virtual ~lb302FilterIIR2( void ); - virtual void recalc(); - virtual void envRecalc(); - virtual float process(const float& samp); + virtual void recalc( void ); + virtual void envRecalc( void ); + virtual float process( const float & _samp ); - virtual void getState(lb302FilterState* fs); - virtual void setState(const lb302FilterState* fs); + virtual void getState( lb302FilterState * _fs ); + virtual void setState( const lb302FilterState * _fs ); - protected: - float vcf_d1, // d1 and d2 are added back into the sample with - vcf_d2; // vcf_a and b as coefficients. IIR2 resonance - // loop. +protected: + float m_d1; // d1 and d2 are added back into the sample with + float m_d2; // vcf_a and b as coefficients. IIR2 resonance + // loop. - // IIR2 Coefficients for mixing dry and delay. - float vcf_a, // Mixing coefficients for the final sound. - vcf_b, // - vcf_c; - - effectLib::monoToStereoAdaptor > * m_dist_fx; + // IIR2 Coefficients for mixing dry and delay. + float m_a; + float m_b; + float m_c; + + effectLib::monoToStereoAdaptor< effectLib::distortion<> > * m_dist_fx; effectLib::distortion<> * m_dist; }; +// lb302Filter3Pole +// The 3-pole filter implementation class lb302Filter3Pole : public lb302Filter { - public: - lb302Filter3Pole(lb302FilterKnobState* p_fs); +public: + lb302Filter3Pole(lb302FilterKnobState * _fs); - //virtual void recalc(); - virtual void envRecalc(); - virtual void recalc(); - virtual float process(const float& samp); + virtual void envRecalc( void ); + virtual void recalc( void ); + virtual float process( const float & _samp ); - virtual void getState(lb302FilterState* fs); - virtual void setState(const lb302FilterState* fs); + virtual void getState( lb302FilterState * _fs ); + virtual void setState( const lb302FilterState * _fs ); - protected: - float kfcn, - kp, - kp1, - kp1h, - kres; - float ay1, - ay2, - aout, - lastin, - value; +protected: + float m_kfcn; + float m_kp; + float m_kp1; + float m_kp1h; + float m_kres; + + float m_ay1; + float m_ay2; + float m_aout; + + float m_lastin; + float m_value; }; - -class lb302State +// lb302State +// State of the VCA and pointer to VCF state. Used with period states +// in lb302Synth to provide gapless, smooth playback +struct lb302State { public: - float vco_c; - float vca_a; - int vca_mode; - int sample_cnt; + float vco_c; + float vca_a; + int vca_mode; + int sampleCnt; - lb302FilterState fs; + lb302FilterState fs; }; -class lb302Note + +// lb302Note +// Description of a note used in lb302: frequency and deadness. Struct +// exists to allow reuse of code contained in initNote(). +struct lb302Note { public: - float vco_inc; - bool dead; + float vco_inc; + bool dead; }; +// lb302Synth +// Here it is, lb302Synth in all its glory. class lb302Synth : public instrument { - Q_OBJECT + Q_OBJECT + public: lb302Synth( instrumentTrack * _channel_track ); virtual ~lb302Synth(); virtual void FASTCALL playNote( notePlayHandle * _n, - bool _try_parallelizing ); + bool _try_parallelizing ); virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _parent ); + QDomElement & _parent ); virtual void FASTCALL loadSettings( const QDomElement & _this ); virtual QString nodeName( void ) const; - virtual bool isMonophonic(void) const { - return true; - } + virtual bool isMonophonic( void ) const { + return true; + } virtual f_cnt_t desiredReleaseFrames( void ) const { return 4048; } -private: - - void initNote(lb302Note *note); - - -private: - knob * vcf_cut_knob; - knob * vcf_res_knob; - knob * vcf_dec_knob; - knob * vcf_mod_knob; - - knob * vco_fine_detune_knob; - - knob * dist_knob; - knob * wave_knob; - - ledCheckBox * slideToggle; - ledCheckBox * accentToggle; - ledCheckBox * deadToggle; - ledCheckBox * db24Toggle; - - knob * slide_dec_knob; - public slots: - void filterChanged(float); - void detuneChanged(float); - void waveChanged(float); - void db24Toggled( bool ); + void filterChanged( float ); + void detuneChanged( float ); + void waveChanged( float ); + void db24Toggled( bool ); private: - + void initNote( lb302Note * note ); + + knob * m_vcfCutKnob; + knob * m_vcfResKnob; + knob * m_vcfDecKnob; + knob * m_vcfModKnob; + + knob * m_vcoFineDetuneKnob; + + knob * m_distKnob; + knob * m_waveKnob; + + knob * m_slideDecKnob; + + ledCheckBox * m_slideToggle; + ledCheckBox * m_accentToggle; + ledCheckBox * m_deadToggle; + ledCheckBox * m_db24Toggle; private: - // Oscillator - float vco_inc, // Sample increment for the frequency. Creates Sawtooth. - vco_k, // Raw oscillator sample [-0.5,0.5] - vco_c; // Raw oscillator sample [-0.5,0.5] + void recalcFilter( void ); - float vco_slide, //* Current value of slide exponential curve. Nonzero=sliding - vco_slideinc, //* Slide base to use in next node. Nonzero=slide next note - vco_slidebase; //* The base vco_inc while sliding. + int process( sampleFrame *outbuf, const Uint32 size ); - float vco_detune; + // Oscillator + enum vcoShape { SAWTOOTH, INVERTED_SAWTOOTH, SQUARE, TRIANGLE, MOOG, ROUND_SQUARE }; + vcoShape m_vco_shape; - enum vco_shape_t { SAWTOOTH, INVERTED_SAWTOOTH, SQUARE, TRIANGLE, MOOG, ROUND_SQUARE }; - vco_shape_t vco_shape; + float m_vco_slide; //* Current value of slide exponential curve. Nonzero=sliding + float m_vco_slideinc; //* Slide base to use in next node. Nonzero=slide next note + float m_vco_slidebase; //* The base vco_inc while sliding. - // User settings - lb302FilterKnobState fs; - lb302Filter *vcf; - lb302Note hold_note; - bool use_hold_note; - - int lastFramesPlayed; - int release_frame; + float m_vco_detune; + float m_vco_inc; // Sample increment for the frequency. Creates Sawtooth. + float m_vco_k; // Raw oscillator sample [-0.5,0.5] + float m_vco_c; // Raw oscillator sample [-0.5,0.5] - - // More States - int vcf_envpos; // Update counter. Updates when >= ENVINC + // More States + int m_vcf_envpos; // Update counter. Updates when >= ENVINC - float vca_attack, // Amp attack - vca_decay, // Amp decay - vca_a0, // Initial amplifier coefficient - vca_a; // Amplifier coefficient. - - // Envelope State - int vca_mode; // 0: attack, 1: decay, 2: idle + // Envelope State + float m_vca_attack; // Amp attack + float m_vca_decay; // Amp decay + float m_vca_a0; // Initial amplifier coefficient + float m_vca_a; // Amplifier coefficient. - // My hacks - int sample_cnt; - - int last_offset; + int m_vca_mode; // 0: attack, 1: decay, 2: idle - lb302State *period_states; - int period_states_cnt; + // User settings + lb302FilterKnobState m_fs; + lb302Filter * m_vcf; + lb302Note m_holdNote; - int catch_frame; - int catch_decay; + bool m_useHoldNote; - void recalcFilter(); + int m_sampleCnt; + int m_releaseFrame; - int process(sampleFrame *outbuf, const Uint32 size); + int m_catchFrame; + int m_catchDecay; -} ; + int m_lastFramesPlayed; + int m_lastOffset; + + lb302State * m_periodStates; + int m_periodStatesCnt; + +}; #endif diff --git a/src/widgets/tool_button.cpp b/src/widgets/tool_button.cpp index 7bfa8b8c0..1a0957353 100644 --- a/src/widgets/tool_button.cpp +++ b/src/widgets/tool_button.cpp @@ -41,7 +41,7 @@ toolButton::toolButton( const QPixmap & _pixmap, const QString & _tooltip, m_colorStandard( s_stdColor ), m_colorHighlighted( s_hlColor ) { - setAutoFillBackground( TRUE ); + setAutoFillBackground( FALSE ); QPalette pal = palette(); pal.setColor( backgroundRole(), m_colorStandard ); pal.setColor( QPalette::Window, m_colorStandard );