This is an interesting thread. Let's keep it going.  I wonder what the best solution is.  How about if the existing core layout was not a limiting factor? How would we do it with a blank canvas?

Paul

On Apr 7, 2010 1:53 PM, "Stefan Fendt" <stefan@sfendt.de> wrote:

Maybe this is of use for someone...

// Oversampled "naive" Oscillator to suppress audible aliasing. This concept
// will work also with a wavetable-based oscillator. It does _not_
deliver alias
// *free*-output, but the alias is sufficiently suppressed to be
unaudible at
// 32-times oversampling and above.
//
// Usually one would use a FIR-Filter for this, but an IIR-Filter works also
// and gives the output some "analogue" touch-up... ;-) Despite that the
IIR is
// faster and we are not interested in having something with
zero-phase-shift
// anyways...
//
// This is proof of concept-code, so do not expect any beauty...
//
// (C)2010 S.Fendt, released into the public domain in the hope it will
be usefull
// for someone...

#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdlib>

class lowpassfilter
{
double a0,a1,a2,b1,b2;
double x0,x1,x2,y1,y2,y0;

public:

lowpassfilter( float rel_frequency )
{
double fx = cos( M_PIl*rel_frequency );
double fy = sin( M_PIl*rel_frequency );

double sD = sqrt( pow( (-1.0) - fx, 2.0 ) + pow( -fy, 2.0 ) )/
sqrt( pow( (+1.0) - fx, 2.0 ) + pow( -fy, 2.0 ) );
double sR = sD/fabs( pow(sD, 2.0) - 1.0 )*2.0;

if( sR > 10000 ) sR=10000;

double alpha = asin( fy / sR );

double px = 0;
double py = 0;

if( fx >= 0 )
{
double sX = fx + sR*cos( asin( fy / sR ) );
px = cos(M_PI-alpha*0.45)*sR+sX;
py = sin(M_PI-alpha*0.45)*sR;
}
else
{
double sX = fx - sR*cos( asin( fy / sR ) );
px = cos(alpha*0.45)*sR+sX;
py = sin(alpha*0.45)*sR;
}

a0 = ( px*px + py*py - 2.0 * px + 1 )/4.0;

a1 = +2.0 * a0;
a2 = +1.0 * a0;

b1 = +2.0 * px;
b2 = -( px*px + py*py );

x0 = x1 = x2 = y0 = y1 = y2 = 0.0;
}

inline double run( double in )
{
x2 = x1; x1 = x0; x0 = in;
y2 = y1; y1 = y0;

y0 = x0*a0 + x1*a1 + x2*a2 + y1*b1 + y2*b2;

return( y0 );
}
};

class oscillator
{
float phase;
float frequency;
float samplerate;
int oversampling;
int pos;

float out;

lowpassfilter* lp0;
lowpassfilter* lp1;
lowpassfilter* lp2;
lowpassfilter* lp3;

public:

oscillator(float samplerate)
{
this->samplerate = samplerate;
this->phase = 0;
this->frequency = 8000;
this->oversampling = 256; // 64times oversampling runs >10times
faster
// than realtime on my system
(E5400@2.7GHz)
// and is free of audible aliasing...
out = 0;

lp0 = new lowpassfilter( 0.66/(float)oversampling );
lp1 = new lowpassfilter( 0.66/(float)oversampling );
lp2 = new lowpassfilter( 0.66/(float)oversampling );
lp3 = new lowpassfilter( 0.66/(float)oversampling );
}

~oscillator()
{
}

float run()
{
const float alpha = 0.125f/(float)oversampling;

for(int n=0; n<oversampling; n++)
{
phase += frequency/(samplerate*(float)oversampling);
phase  = phase>1.0f? phase-1.0f:phase;

if(1)
{
if(phase<0.125)
out = lp3->run(lp2->run(lp1->run(lp0->run( +0.5 ))));
else
out = lp3->run(lp2->run(lp1->run(lp0->run( -0.5 ))));
}
else
{
out = lp3->run(lp2->run(lp1->run(lp0->run(
(phase-0.5)*2.0 ))));
}
}
return( out );
}

void set_frequency( float frequency )
{
this->frequency = frequency;
}
};

int main()
{
std::fstream fileout( "outfile.dat", std::ios::out|std::ios::binary );

float samplerate = 44100;
union
{
float f;
char  c[4];
} sample;

oscillator m_oscillator( samplerate );

float f0 = 100;
float f1 = 8000;

for(int n=0; n<(int)(samplerate*10); n++ )
{
m_oscillator.set_frequency( f0*((float)n/(samplerate*10)) + f1 *
(1.0-(float)n/(samplerate*10)) );
sample.f = m_oscillator.run();
fileout.write( &sample.c[0], 4 );
}
fileout.close();

}

------------------------------------------------------------------------------