From 19b56779e9ded9b997e1713ea9073aa569abdedb Mon Sep 17 00:00:00 2001 From: Vesa Date: Wed, 26 Mar 2014 00:22:14 +0200 Subject: [PATCH 1/2] Add smart oversampling interpolation --- plugins/watsyn/Watsyn.cpp | 38 ++++++++++++++++------ plugins/watsyn/Watsyn.h | 66 ++++++++++++++++++++++++++++++++------- 2 files changed, 82 insertions(+), 22 deletions(-) diff --git a/plugins/watsyn/Watsyn.cpp b/plugins/watsyn/Watsyn.cpp index b3b720d4d..747141304 100644 --- a/plugins/watsyn/Watsyn.cpp +++ b/plugins/watsyn/Watsyn.cpp @@ -81,6 +81,7 @@ WatsynObject::WatsynObject( float * _A1wave, float * _A2wave, m_rphase[B2_OSC] = 0.0f; // copy wavegraphs to the synth object to prevent race conditions + memcpy( &m_A1wave, _A1wave, sizeof( m_A1wave ) ); memcpy( &m_A2wave, _A2wave, sizeof( m_A2wave ) ); memcpy( &m_B1wave, _B1wave, sizeof( m_B1wave ) ); @@ -251,10 +252,10 @@ WatsynInstrument::WatsynInstrument( InstrumentTrack * _instrument_track ) : b1_rtune( 0.0f, -600.0f, 600.0f, 1.0f, this, tr( "Right detune B1" ) ), b2_rtune( 0.0f, -600.0f, 600.0f, 1.0f, this, tr( "Right detune B2" ) ), - a1_graph( -1.0f, 1.0f, WAVELEN, this ), - a2_graph( -1.0f, 1.0f, WAVELEN, this ), - b1_graph( -1.0f, 1.0f, WAVELEN, this ), - b2_graph( -1.0f, 1.0f, WAVELEN, this ), + a1_graph( -1.0f, 1.0f, GRAPHLEN, this ), + a2_graph( -1.0f, 1.0f, GRAPHLEN, this ), + b1_graph( -1.0f, 1.0f, GRAPHLEN, this ), + b2_graph( -1.0f, 1.0f, GRAPHLEN, this ), m_abmix( 0.0f, -100.0f, 100.0f, 0.1f, this, tr( "A-B Mix" ) ), m_envAmt( 0.0f, -200.0f, 200.0f, 1.0f, this, tr( "A-B Mix envelope amount" ) ), @@ -294,6 +295,11 @@ WatsynInstrument::WatsynInstrument( InstrumentTrack * _instrument_track ) : connect( &a2_rtune, SIGNAL( dataChanged() ), this, SLOT( updateFreq() ) ); connect( &b1_rtune, SIGNAL( dataChanged() ), this, SLOT( updateFreq() ) ); connect( &b2_rtune, SIGNAL( dataChanged() ), this, SLOT( updateFreq() ) ); + + connect( &a1_graph, SIGNAL( samplesChanged( int, int ) ), this, SLOT( updateWaves() ) ); + connect( &a2_graph, SIGNAL( samplesChanged( int, int ) ), this, SLOT( updateWaves() ) ); + connect( &b1_graph, SIGNAL( samplesChanged( int, int ) ), this, SLOT( updateWaves() ) ); + connect( &b2_graph, SIGNAL( samplesChanged( int, int ) ), this, SLOT( updateWaves() ) ); a1_graph.setWaveToSine(); a2_graph.setWaveToSine(); @@ -302,6 +308,7 @@ WatsynInstrument::WatsynInstrument( InstrumentTrack * _instrument_track ) : updateVolumes(); updateFreq(); + updateWaves(); } @@ -315,10 +322,11 @@ void WatsynInstrument::playNote( NotePlayHandle * _n, { if ( _n->totalFramesPlayed() == 0 || _n->m_pluginData == NULL ) { - WatsynObject * w = new WatsynObject( const_cast( a1_graph.samples() ), - const_cast( a2_graph.samples() ), - const_cast( b1_graph.samples() ), - const_cast( b2_graph.samples() ), + WatsynObject * w = new WatsynObject( + &A1_wave[0], + &A2_wave[0], + &B1_wave[0], + &B2_wave[0], m_amod.value(), m_bmod.value(), engine::mixer()->processingSampleRate(), _n, engine::mixer()->framesPerPeriod(), this ); @@ -491,7 +499,7 @@ void WatsynInstrument::saveSettings( QDomDocument & _doc, m_amod.saveSettings( _doc, _this, "amod" ); m_bmod.saveSettings( _doc, _this, "bmod" ); - m_selectedGraph.saveSettings( _doc, _this, "selgraph" ); +/* m_selectedGraph.saveSettings( _doc, _this, "selgraph" );*/ } @@ -548,7 +556,7 @@ void WatsynInstrument::loadSettings( const QDomElement & _this ) m_amod.loadSettings( _this, "amod" ); m_bmod.loadSettings( _this, "bmod" ); - m_selectedGraph.loadSettings( _this, "selgraph" ); +/* m_selectedGraph.loadSettings( _this, "selgraph" );*/ } @@ -596,6 +604,16 @@ void WatsynInstrument::updateFreq() } +void WatsynInstrument::updateWaves() +{ + // do cip+oversampling on the wavetables to improve quality + cipcpy( &A1_wave[0], const_cast( a1_graph.samples() ) ); + cipcpy( &A2_wave[0], const_cast( a2_graph.samples() ) ); + cipcpy( &B1_wave[0], const_cast( b1_graph.samples() ) ); + cipcpy( &B2_wave[0], const_cast( b2_graph.samples() ) ); +} + + WatsynView::WatsynView( Instrument * _instrument, QWidget * _parent ) : InstrumentView( _instrument, _parent ) diff --git a/plugins/watsyn/Watsyn.h b/plugins/watsyn/Watsyn.h index a351351a4..6ff570b3b 100644 --- a/plugins/watsyn/Watsyn.h +++ b/plugins/watsyn/Watsyn.h @@ -56,20 +56,24 @@ #define B2ROW 95 -extern const int WAVELEN = 220; -extern const int PMOD_AMT = 110; +const int GRAPHLEN = 220; +const int WAVELEN = 4400; -extern const int MOD_MIX = 0; -extern const int MOD_AM = 1; -extern const int MOD_RM = 2; -extern const int MOD_PM = 3; -extern const int NUM_MODS = 4; +const int WAVERATIO = WAVELEN / GRAPHLEN; -extern const int A1_OSC = 0; -extern const int A2_OSC = 1; -extern const int B1_OSC = 2; -extern const int B2_OSC = 3; -extern const int NUM_OSCS = 4; +const int PMOD_AMT = 110; + +const int MOD_MIX = 0; +const int MOD_AM = 1; +const int MOD_RM = 2; +const int MOD_PM = 3; +const int NUM_MODS = 4; + +const int A1_OSC = 0; +const int A2_OSC = 1; +const int B1_OSC = 2; +const int B2_OSC = 3; +const int NUM_OSCS = 4; class WatsynInstrument; @@ -131,6 +135,7 @@ private: ( ( x3 - x2 ) * m2 ); }*/ + int m_amod; int m_bmod; @@ -181,6 +186,7 @@ public: public slots: void updateVolumes(); void updateFreq(); + void updateWaves(); protected: float m_lvol [NUM_OSCS]; @@ -200,6 +206,37 @@ private: return ( _pan >= 0 ? 1.0 : 1.0 + ( _pan / 100.0 ) ) * _vol / 100.0; } + // memcpy with cubic interpolation (cip for short) and 10x oversampling to increase wavetable quality + inline void cipcpy( float * _dst, float * _src ) + { + // calculate cyclic tangents + float tang[GRAPHLEN]; + tang[0] = ( _src[1] - _src[ GRAPHLEN - 1] ) / 2; + tang[ GRAPHLEN - 1 ] = ( _src[0] - _src[ GRAPHLEN - 2 ] ) / 2; + for( int i = 1; i < GRAPHLEN-1; i++ ) + { + tang[i] = ( _src[i+1] - _src[i-1] ) / 2; + } + + // calculate cspline + for( int i=0; i < WAVELEN; i++ ) + { + const float s1 = _src[ i / WAVERATIO ]; + const float s2 = _src[ ( i / WAVERATIO + 1 ) % GRAPHLEN ]; + const float m1 = tang[ i / WAVERATIO ]; + const float m2 = tang[ ( i / WAVERATIO + 1 ) % GRAPHLEN ]; + + const float x = static_cast( i % WAVERATIO ) / WAVERATIO; + const float x2 = x * x; + const float x3 = x * x * x; + + _dst[i] = ( ( x3 * 2.0 - x2 * 3.0 + 1.0 ) * s1 ) + + ( ( x3 * -2.0 + x2 * 3.0 ) * s2 ) + + ( ( x3 - x2 * 2 + x ) * m1 ) + + ( ( x3 - x2 ) * m2 ); + } + } + FloatModel a1_vol; FloatModel a2_vol; FloatModel b1_vol; @@ -244,6 +281,11 @@ private: IntModel m_bmod; IntModel m_selectedGraph; + + float A1_wave [WAVELEN]; + float A2_wave [WAVELEN]; + float B1_wave [WAVELEN]; + float B2_wave [WAVELEN]; friend class WatsynObject; friend class WatsynView; From 07d37e0fbc66b14cadf387dbf8d0c04c87fab9ff Mon Sep 17 00:00:00 2001 From: Vesa Date: Wed, 26 Mar 2014 00:39:27 +0200 Subject: [PATCH 2/2] Forgot to change phasemod constant --- plugins/watsyn/Watsyn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/watsyn/Watsyn.h b/plugins/watsyn/Watsyn.h index 6ff570b3b..5b4072202 100644 --- a/plugins/watsyn/Watsyn.h +++ b/plugins/watsyn/Watsyn.h @@ -61,7 +61,7 @@ const int WAVELEN = 4400; const int WAVERATIO = WAVELEN / GRAPHLEN; -const int PMOD_AMT = 110; +const int PMOD_AMT = WAVELEN / 2; const int MOD_MIX = 0; const int MOD_AM = 1;