mirror of
https://github.com/LMMS/lmms.git
synced 2026-05-19 12:16:16 -04:00
@@ -32,23 +32,41 @@
|
||||
#include "engine.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
#define MAXLEN 12
|
||||
#define MIPMAPSIZE 1 << ( MAXLEN + 1 )
|
||||
#define MAXLEN 11
|
||||
#define MIPMAPSIZE 2 << ( MAXLEN + 1 )
|
||||
#define MIPMAPSIZE3 3 << ( MAXLEN + 1 )
|
||||
#define MAXTBL 23
|
||||
#define MINTLEN 2 << 0
|
||||
#define MAXTLEN 3 << MAXLEN
|
||||
|
||||
// table for table sizes
|
||||
const int TLENS[MAXTBL+1] = { 2 << 0, 3 << 0, 2 << 1, 3 << 1,
|
||||
2 << 2, 3 << 2, 2 << 3, 3 << 3,
|
||||
2 << 4, 3 << 4, 2 << 5, 3 << 5,
|
||||
2 << 6, 3 << 6, 2 << 7, 3 << 7,
|
||||
2 << 8, 3 << 8, 2 << 9, 3 << 9,
|
||||
2 << 10, 3 << 10, 2 << 11, 3 << 11 };
|
||||
|
||||
typedef struct
|
||||
{
|
||||
public:
|
||||
inline sample_t sampleAt( int _table, int _ph )
|
||||
{
|
||||
return m_data[ ( 1 << _table ) + _ph ];
|
||||
if( _table % 2 == 0 )
|
||||
{ return m_data[ TLENS[ _table ] + _ph ]; }
|
||||
else
|
||||
{ return m_data3[ TLENS[ _table ] + _ph ]; }
|
||||
}
|
||||
inline void setSampleAt( int _table, int _ph, sample_t _sample )
|
||||
{
|
||||
m_data[ ( 1 << _table ) + _ph ] = _sample;
|
||||
if( _table % 2 == 0 )
|
||||
{ m_data[ TLENS[ _table ] + _ph ] = _sample; }
|
||||
else
|
||||
{ m_data3[ TLENS[ _table ] + _ph ] = _sample; }
|
||||
}
|
||||
private:
|
||||
sample_t m_data [ MIPMAPSIZE ];
|
||||
sample_t m_data3 [ MIPMAPSIZE3 ];
|
||||
} WaveMipMap;
|
||||
|
||||
|
||||
@@ -96,10 +114,10 @@ public:
|
||||
static inline sample_t oscillate( float _ph, float _wavelen, Waveforms _wave )
|
||||
{
|
||||
// high wavelen/ low freq
|
||||
if( _wavelen >= 1 << MAXLEN )
|
||||
if( _wavelen > TLENS[ MAXTBL -1 ] )
|
||||
{
|
||||
const int t = MAXLEN;
|
||||
const int tlen = 1 << t;
|
||||
const int t = MAXTBL;
|
||||
const int tlen = TLENS[t];
|
||||
const float ph = fraction( _ph );
|
||||
const float lookupf = ph * static_cast<float>( tlen );
|
||||
const int lookup = static_cast<int>( lookupf );
|
||||
@@ -110,8 +128,8 @@ public:
|
||||
// low wavelen/ high freq
|
||||
if( _wavelen <= 2.0f )
|
||||
{
|
||||
const int t = 1;
|
||||
const int tlen = 2;
|
||||
const int t = 0;
|
||||
const int tlen = TLENS[t];
|
||||
const float ph = fraction( _ph );
|
||||
const float lookupf = ph * static_cast<float>( tlen );
|
||||
const int lookup = static_cast<int>( lookupf );
|
||||
@@ -121,69 +139,43 @@ public:
|
||||
}
|
||||
|
||||
// get the next higher tlen
|
||||
int t = 2;
|
||||
while( ( 1 << t ) < _wavelen ) { t++; }
|
||||
int t = 1;
|
||||
while( TLENS[t] < _wavelen ) { t++; }
|
||||
|
||||
const int tlen = 1 << t;
|
||||
int tlen = TLENS[t];
|
||||
const float ph = fraction( _ph );
|
||||
const float lookupf = ph * static_cast<float>( tlen );
|
||||
const int lookup = static_cast<int>( lookupf );
|
||||
int lookup = static_cast<int>( lookupf );
|
||||
const float ip = fraction( lookupf );
|
||||
|
||||
const sample_t s1 = s_waveforms[ _wave ].sampleAt( t, lookup );
|
||||
const sample_t s2 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 1 ) % tlen );
|
||||
return linearInterpolate( s1, s2, fraction( lookupf ) );
|
||||
//const sample_t sr = linearInterpolate( s1, s2, ip );
|
||||
|
||||
const int lm = lookup == 0 ? tlen - 1 : lookup - 1;
|
||||
const sample_t s0 = s_waveforms[ _wave ].sampleAt( t, lm );
|
||||
const sample_t s3 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 2 ) % tlen );
|
||||
const sample_t sr = cubicInterpolate( s0, s1, s2, s3, ip );
|
||||
|
||||
/*const int tlen1 = 1 << t;
|
||||
const int tlen2 = 1 << ( t - 1 );
|
||||
return sr;
|
||||
|
||||
const float ph = fraction( _ph );
|
||||
const float lookupf = ph * static_cast<float>( tlen1 );
|
||||
const int lookup1 = static_cast<int>( lookupf );
|
||||
const int lookup2 = static_cast<int>( ph * static_cast<float>( tlen2 ) );
|
||||
|
||||
const sample_t s1 = linearInterpolate( s_waveforms[ _wave ].sampleAt( t, lookup1 ),
|
||||
s_waveforms[ _wave ].sampleAt( t, ( lookup1 + 1 ) % tlen1 ),
|
||||
fraction( lookupf ) );
|
||||
const sample_t s2 = s_waveforms[ _wave ].sampleAt( t - 1, lookup2 );
|
||||
|
||||
const float ip = static_cast<float>( tlen1 - _wavelen ) / static_cast<float>( tlen2 );
|
||||
/* lookup = lookup << 1;
|
||||
tlen = tlen << 1;
|
||||
t += 1;
|
||||
const sample_t s3 = s_waveforms[ _wave ].sampleAt( t, lookup );
|
||||
const sample_t s4 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 1 ) % tlen );
|
||||
const sample_t s34 = linearInterpolate( s3, s4, ip );
|
||||
|
||||
return linearInterpolate( s1, s2, ip );*/
|
||||
};
|
||||
|
||||
/*! \brief The same as oscillate but uses cosinus interpolation instead of linear.
|
||||
*/
|
||||
static inline sample_t oscillateCos( float _ph, float _wavelen, Waveforms _wave )
|
||||
{
|
||||
int t = MAXLEN;
|
||||
while( ( 1 << t ) > _wavelen ) { t--; }
|
||||
t = qMax( 1, t );
|
||||
|
||||
const int tlen = 1 << t;
|
||||
const float ph = fraction( _ph );
|
||||
const int lookup = static_cast<int>( ph * tlen );
|
||||
const sample_t s1 = s_waveforms[ _wave ].sampleAt( t, lookup );
|
||||
const sample_t s2 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 1 ) % tlen );
|
||||
|
||||
return cosinusInterpolate( s1, s2, ph );
|
||||
};
|
||||
|
||||
/*! \brief The same as oscillate but without any interpolation.
|
||||
*/
|
||||
static inline sample_t oscillateNoip( float _ph, float _wavelen, Waveforms _wave )
|
||||
{
|
||||
int t = MAXLEN;
|
||||
while( ( 1 << t ) > _wavelen ) { t--; }
|
||||
t = qMax( 1, t );
|
||||
|
||||
const int tlen = 1 << t;
|
||||
const float ph = fraction( _ph );
|
||||
const int lookup = static_cast<int>( ph * tlen );
|
||||
return s_waveforms[ _wave ].sampleAt( t, lookup );
|
||||
const float ip2 = ( ( tlen - _wavelen ) / tlen - 0.5 ) * 2.0;
|
||||
|
||||
return linearInterpolate( s12, s34, ip2 );
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
static void generateWaves();
|
||||
|
||||
static bool s_wavesGenerated;
|
||||
|
||||
static WaveMipMap s_waveforms [NumBLWaveforms];
|
||||
};
|
||||
|
||||
@@ -79,13 +79,16 @@ inline float cubicInterpolate( float v0, float v1, float v2, float v3, float x )
|
||||
|
||||
inline float cosinusInterpolate( float v0, float v1, float x )
|
||||
{
|
||||
float f = cosf( x * ( F_PI_2 ) );
|
||||
return( v1 - f * (v1-v0) );
|
||||
const float f = ( 1.0f - cosf( x * F_PI ) ) * 0.5f;
|
||||
#ifdef FP_FAST_FMAF
|
||||
return fmaf( x, v1-v0, v0 );
|
||||
#else
|
||||
return f * (v1-v0) + v0;
|
||||
#endif
|
||||
// return( v0*f + v1*( 1.0f-f ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline float linearInterpolate( float v0, float v1, float x )
|
||||
{
|
||||
// take advantage of fma function if present in hardware
|
||||
|
||||
@@ -23,10 +23,11 @@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _LMMS_MATH_H
|
||||
#define _LMMS_MATH_H
|
||||
#ifndef LMMS_MATH_H
|
||||
#define LMMS_MATH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "lmms_constants.h"
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
|
||||
@@ -120,5 +121,12 @@ static inline double fastPow( double a, double b )
|
||||
return u.d;
|
||||
}
|
||||
|
||||
// sinc function
|
||||
static inline double sinc( double _x )
|
||||
{
|
||||
return _x == 0.0 ? 1.0 : sin( F_PI * _x ) / ( F_PI * _x );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1026,6 +1026,10 @@ MonstroInstrument::MonstroInstrument( InstrumentTrack * _instrument_track ) :
|
||||
m_sub3lfo2( 0.0f, -1.0f, 1.0f, 0.001f, this, tr( "Sub3-LFO2" ) )
|
||||
|
||||
{
|
||||
// make sure the wavetables exist:
|
||||
// generate bandlimited wavetables
|
||||
BandLimitedWave::generateWaves();
|
||||
|
||||
// setup waveboxes
|
||||
setwavemodel( m_osc2Wave )
|
||||
setwavemodel( m_osc3Wave1 )
|
||||
|
||||
@@ -27,30 +27,35 @@
|
||||
|
||||
|
||||
WaveMipMap BandLimitedWave::s_waveforms[4] = { };
|
||||
|
||||
bool BandLimitedWave::s_wavesGenerated = false;
|
||||
|
||||
void BandLimitedWave::generateWaves()
|
||||
{
|
||||
// don't generate if they already exist
|
||||
if( s_wavesGenerated ) return;
|
||||
|
||||
int i;
|
||||
|
||||
// saw wave - BLSaw
|
||||
for( i = 1; i <= MAXLEN; i++ )
|
||||
for( i = 0; i <= MAXTBL; i++ )
|
||||
{
|
||||
const int len = 1 << i;
|
||||
const double om = 1.0 / len;
|
||||
const int len = TLENS[i];
|
||||
//const double om = 1.0 / len;
|
||||
double max = 0.0;
|
||||
|
||||
for( int ph = 0; ph < len; ph++ )
|
||||
{
|
||||
int harm = 1;
|
||||
double s = 0.0f;
|
||||
double hlen;
|
||||
do
|
||||
{
|
||||
hlen = static_cast<double>( len ) / static_cast<double>( harm );
|
||||
const double amp = -1.0 / static_cast<double>( harm );
|
||||
const double a2 = cos( om * harm * F_2PI );
|
||||
s += amp * a2 * sin( static_cast<double>( ph * harm ) / static_cast<double>( len ) * F_2PI );
|
||||
//const double a2 = cos( om * harm * F_2PI );
|
||||
s += amp * /*a2 **/sin( static_cast<double>( ph * harm ) / static_cast<double>( len ) * F_2PI );
|
||||
harm++;
|
||||
} while( len/harm > 2 );
|
||||
} while( hlen >= 4.0 );
|
||||
s_waveforms[ BandLimitedWave::BLSaw ].setSampleAt( i, ph, s );
|
||||
max = qMax( max, qAbs( s ) );
|
||||
}
|
||||
@@ -63,23 +68,25 @@ void BandLimitedWave::generateWaves()
|
||||
}
|
||||
|
||||
// square wave - BLSquare
|
||||
for( i = 1; i <= MAXLEN; i++ )
|
||||
for( i = 0; i <= MAXTBL; i++ )
|
||||
{
|
||||
const int len = 1 << i;
|
||||
const double om = 1.0 / len;
|
||||
const int len = TLENS[i];
|
||||
//const double om = 1.0 / len;
|
||||
double max = 0.0;
|
||||
|
||||
for( int ph = 0; ph < len; ph++ )
|
||||
{
|
||||
int harm = 1;
|
||||
double s = 0.0f;
|
||||
double hlen;
|
||||
do
|
||||
{
|
||||
hlen = static_cast<double>( len ) / static_cast<double>( harm );
|
||||
const double amp = 1.0 / static_cast<double>( harm );
|
||||
const double a2 = cos( om * harm * F_2PI );
|
||||
s += amp * a2 * sin( static_cast<double>( ph * harm ) / static_cast<double>( len ) * F_2PI );
|
||||
//const double a2 = cos( om * harm * F_2PI );
|
||||
s += amp * /*a2 **/ sin( static_cast<double>( ph * harm ) / static_cast<double>( len ) * F_2PI );
|
||||
harm += 2;
|
||||
} while( len/harm > 2 );
|
||||
} while( hlen >= 4.0 );
|
||||
s_waveforms[ BandLimitedWave::BLSquare ].setSampleAt( i, ph, s );
|
||||
max = qMax( max, qAbs( s ) );
|
||||
}
|
||||
@@ -93,9 +100,9 @@ void BandLimitedWave::generateWaves()
|
||||
|
||||
|
||||
// triangle wave - BLTriangle
|
||||
for( i = 1; i <= MAXLEN; i++ )
|
||||
for( i = 0; i <= MAXTBL; i++ )
|
||||
{
|
||||
const int len = 1 << i;
|
||||
const int len = TLENS[i];
|
||||
//const double om = 1.0 / len;
|
||||
double max = 0.0;
|
||||
|
||||
@@ -103,14 +110,16 @@ void BandLimitedWave::generateWaves()
|
||||
{
|
||||
int harm = 1;
|
||||
double s = 0.0f;
|
||||
double hlen;
|
||||
do
|
||||
{
|
||||
hlen = static_cast<double>( len ) / static_cast<double>( harm );
|
||||
const double amp = 1.0 / static_cast<double>( harm * harm );
|
||||
//const double a2 = cos( om * harm * F_2PI );
|
||||
s += amp * /*a2 **/ sin( ( static_cast<double>( ph * harm ) / static_cast<double>( len ) +
|
||||
( ( harm + 1 ) % 4 == 0 ? 0.5 : 0.0 ) ) * F_2PI );
|
||||
harm += 2;
|
||||
} while( len/harm > 2 );
|
||||
} while( hlen >= 4.0 );
|
||||
s_waveforms[ BandLimitedWave::BLTriangle ].setSampleAt( i, ph, s );
|
||||
max = qMax( max, qAbs( s ) );
|
||||
}
|
||||
@@ -125,9 +134,9 @@ void BandLimitedWave::generateWaves()
|
||||
|
||||
// moog saw wave - BLMoog
|
||||
// basically, just add in triangle + 270-phase saw
|
||||
for( i = 1; i <= MAXLEN; i++ )
|
||||
for( i = 0; i <= MAXTBL; i++ )
|
||||
{
|
||||
const int len = 1 << i;
|
||||
const int len = TLENS[i];
|
||||
|
||||
for( int ph = 0; ph < len; ph++ )
|
||||
{
|
||||
@@ -138,4 +147,6 @@ void BandLimitedWave::generateWaves()
|
||||
}
|
||||
}
|
||||
|
||||
s_wavesGenerated = true;
|
||||
|
||||
}
|
||||
|
||||
@@ -65,7 +65,6 @@
|
||||
#include "ProjectRenderer.h"
|
||||
#include "DataFile.h"
|
||||
#include "song.h"
|
||||
#include "BandLimitedWave.h"
|
||||
|
||||
static inline QString baseName( const QString & _file )
|
||||
{
|
||||
@@ -120,9 +119,6 @@ int main( int argc, char * * argv )
|
||||
new QCoreApplication( argc, argv ) :
|
||||
new QApplication( argc, argv ) ;
|
||||
|
||||
// generate bandlimited wavetables for instruments to use
|
||||
BandLimitedWave::generateWaves();
|
||||
|
||||
Mixer::qualitySettings qs( Mixer::qualitySettings::Mode_HighQuality );
|
||||
ProjectRenderer::OutputSettings os( 44100, false, 160,
|
||||
ProjectRenderer::Depth_16Bit );
|
||||
|
||||
Reference in New Issue
Block a user