Porting C++ to SM's Code component

This is a brief tutorial by exonerate to show you the difference between a filter coded in C++ and the same filter coded in SynthMaker’s Code component. You can download the filter from here,Download OSM

The code we will use is taken from Tobybear's filter explorer.

Original C++

Here’s the original C++ starting with the header file…..

class Badboy
{
public:
 Badboy();
 void init();
 void calc();
 float process(float x);
 ~Badboy();
 float getC0();
 void setC0(float c);
 float getC1();
 void setC1(float c);
protected:
 float a0,a1,a2;
 float b1,b2;
 float t0,t1,t2;
 float c0,c1;
 float xold1,xold2;
 float yold1,yold2;
 float y;
 float samplerate;
};''

And here comes the source file……….

#include "Badboy.h"
#define pi 3.141592f
 
Badboy::Badboy()
{
 samplerate=44100.0;
 c0=0.0;c1=0.0;
 t0=0.0;t1=0.0;t2=0.0;
 init();
}
 
Badboy::~Badboy()
{
}
 
void Badboy::init()
{
 // initialize values
 xold1=0.0;xold2=0.0;
 yold1=0.0;yold2=0.0;
 y=0;
 calc();
};
 
void Badboy::calc()
{
 // calculate temporary variables
 t0=cos(pi*(0.6*c0+0.01));
 t1=sin(pi*(0.6*c0+0.01))/(6*(c1+0.001));
 t2=1+t1;
 // calculate coefficients
 a0=(1-t0)/(2*t2);
 a1=(1-t0)/2*t2;
 a2=(1-t0)/(2*t2);
 b1=-2*t0/t2;
 b2=((1-t1)/t2);
};
 
float Badboy::process(float x)
{
 // process input
 yold2=yold1;
 yold1=y;
 y=
 a2*xold2+
 a1*xold1+
 a0*x
 -b2*yold2
 -b1*yold1;
 xold2=xold1;
 xold1=x;
 return y;
}
 
float Badboy::getC0()
{ return c0; }
 
void Badboy::setC0(float c)
{ c0=c;calc(); }
 
float Badboy::getC1()
{ return c1; }
 
void Badboy::setC1(float c)
{ c1=c;calc(); }

SynthMaker Translation

Before I try to explain any of the differences between the C++ version and the SynthMaker version, I think it will help to see the SynthMaker code first, so here it is:

streamin in;
streamin cut;
streamin res;
streamout out;

float a0,a1,a2;
 float b1,b2;
 float t0,t1,t2;
 float xold1,xold2;
 float yold1,yold2;

 hop(256){
 // calculate temporary variables
 t0=cos1(0.5*(0.6*cut+0.01));
 t1=sin1(0.5*(0.06*cut+0.01))/(6*(res+0.1));
 t2=1+t1;
 }
 // calculate coefficients
 a0=(1-t0)/(2*t2);
 a1=(1-t0)/2*t2;
 a2=(1-t0)/(2*t2);
 b1=-2*t0/t2;
 b2=((1-t1)/t2);

 // process input
 out=
 a2*xold2+
 a1*xold1+
 a0*in
 -b2*yold2
 -b1*yold1;
  
xold2=xold1;
 xold1=in; 
 yold2=yold1;
 yold1=out;

Firstly notice how much more streamlined the SynthMaker code is, this is because SM’s Code component is designed for quick implementation of algorithms.

As you can see, everything is written inside the Code component. There is no need to include a header file; just declare your floats after the streamin/streamout lines.

Trigonometry in SM

Another important difference in SynthMaker is with the sin, cos, & tan functions, if you look at the source file of the original C++ code, at the top you will see…..#define pi 3.141592f…..and then in the t0 assignment you will see…………. sin(pi*(0.6*c0+0.01)

In SynthMaker it is not needed to define pi, you can see that in the SM code the t0 assignment is written…….. sin1(0.5*(0.6*cut+0.01)…… this works exactly the same as the C++ version but saves having to define pi.

Here’s the explanation from the manual….

sin1(a)    cos1(a)    tan1(a)

Mathematical sine, cosine and tangent.

The 1 indicates that the input value a is converted to a value in the range 0-1 and not 0 and 2pi. So 0.5 would be equivalent to pi and 1.25 would be equivalent to pi/2

In SynthMaker Code any float that is not assigned a value, will automatically be given a value of zero, so there’s no need to write…….xold1 = 0.0 or xold2 = 0.0 ect…like in the C++ code.

Hop saves CPU

Also you may have noticed the hop command in the SynthMaker code this is used to save CPU by only calculating the t0,t1 and t2 assignments every 256 samples. If you want greater precision (for example, to connect faster LFOs), then lower the hop number. You can experiment with larger numbers if you are very concerned about CPU usage.

tutorials/porting_c_to_sm_code.txt · Last modified: 2008/05/20 23:11 (external edit)