mirror of
https://github.com/LMMS/lmms.git
synced 2026-04-03 22:04:26 -04:00
Merge pull request #511 from diizy/wavetablesynth
Watsyn: Add smart oversampling interpolation
This commit is contained in:
@@ -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<float*>( a1_graph.samples() ),
|
||||
const_cast<float*>( a2_graph.samples() ),
|
||||
const_cast<float*>( b1_graph.samples() ),
|
||||
const_cast<float*>( 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<float*>( a1_graph.samples() ) );
|
||||
cipcpy( &A2_wave[0], const_cast<float*>( a2_graph.samples() ) );
|
||||
cipcpy( &B1_wave[0], const_cast<float*>( b1_graph.samples() ) );
|
||||
cipcpy( &B2_wave[0], const_cast<float*>( b2_graph.samples() ) );
|
||||
}
|
||||
|
||||
|
||||
WatsynView::WatsynView( Instrument * _instrument,
|
||||
QWidget * _parent ) :
|
||||
InstrumentView( _instrument, _parent )
|
||||
|
||||
@@ -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 = WAVELEN / 2;
|
||||
|
||||
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<float>( 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;
|
||||
|
||||
Reference in New Issue
Block a user