From the original SynthMaker forum (2004–2014), with its members’ names and dates.
global goon ·
a module that contains 4 or 6 or 8 sine wave oscillators as well as phase mod routing possibilities.
would it be more CPU friendly than making it with the inbuilt components?
heres a picture of how a 4 osc version of the module would look:
global goon ·
I mean using the built in code component btw
stefan ·
Yes, it's possible. And it would probably be more efficient indeed. You could try using both the look-up table (sin1() function) or taylor series (google for sine taylor series or something).
Granted, I myself would probably split it up into several modules so that I wouldn't have to bother with the phase routing type within the code component. Because of clarity etc.
global goon ·
thanks stefancrs, i'm just trying to suss out how to create a basic sine wave oscillator at the moment!
stefan ·
Ok, here goes the fastest one I know of (finished it earlier today):
polyin freq;
polyin phase;
polyout out;
float cos;
float sin;
float tCos,tSin;
float mul;
// since the code component does not support initialising of variables we have to do a hack
float isInitialised;
isInitialised= ((cos > 0) & 1.0) + ((cos < 0) & 1.0);
cos = (1.0 - isInitialised) * 0.99 + (isInitialised > 0) & cos;
mul = freq * 1.0 * 3.141592; // roughly pi
cos = cos - sin * mul;
sin = sin + cos * mul;
/*
this is the "obvious" implementation of phase modulation
tCos = cos - sin * phase;
tSin = sin + tCos * phase;
out = tSin;
but we can simplify it into one expression instead for better perfomance, like this */
out = sin + (cos - sin * phase) * phase;
Very cpu-friendly 🙂
global goon ·
fantastic!
global goon ·
i expanded on your code to make a module that has 6 oscillators. it has freq and level in for each and 1 output.
It's a fixed algorithm :- (f+e+d+c+b)-->a
It's very CPU friendly, a 10 note chord uses about 6% processing on my 2.8ghz pentium
float mul;
float totalPhase;
// since the code component does not support initialising of variables we have to do a hack
float isInitialised;
isInitialised= ((aCos > 0) & 1.0) + ((aCos < 0) & 1.0);
Nice sound. I made some very moody scapes with it. Once again, good work 🙂
jorge ·
Yeah, I'm playing with it too, creating some presets, could be interesting to exchange some. Thanks global goon
stefan ·
So how about arrays and loops jorge? 🙂
jorge ·
stefancrs wrote: So how about arrays and loops jorge? 🙂
Well, I blame global goon for me not having done it this morning 🙂 but I know what you mean, it would be handy to have them for the efficient Sine code, and I guess also having the variables initialise would make the code much more efficient.
What I had on my mind instead was to put the drawbar LFOs in global goon's synth 🙂. We'll see what happens, at least loop is very easy to implement as it is very similar to the hop function so I might have a go.
global goon ·
cool!
i tried it with feedback, but it doesn't overdrive in the way synthmakers inbuilt oscillators do.
Strange, I succesfully tried overdrive and created a sawtooth that way. A bit busy atm, so I can't really look at your code right now 🙂
jorge ·
I put some drawbar modules in global goon's schematic:
[old link]
global goon ·
awesome!
Tom7777 ·
Nice, thanks everyone
global goon ·
i worked out last night that the code for the oscillator only works with phases of up to 90degrees(0.25). here is an osm that demonstrates this: http://www.globalgoon.com/synthmaker/stefan%20phase%20mod.osm
// since the code component does not support initialising of variables we have to do a hack
float isInitialised;
isInitialised= ((cos > 0) & 1.0) + ((cos < 0) & 1.0);
cos = (1.0 - isInitialised) * 0.99 + (isInitialised > 0) & cos;
mul = freq * 6.283185; // roughly 2 * pi
cos = cos - sin * mul;
sin = sin + cos * mul;
tCos = cos - sin * 4 * phase ;
tSin = sin + tCos * 4 * phase;
out = tSin;
to make this oscillator produce the same wave as the inbuilt, i shifted it up an octave and multiplied the phase by 4.
In the osm above, you'll see that both stefans osc and the inbuilt one work similarly upto a phase of 0.25. After that point, stefs amplitude increases (change the float box "max phase angle" from 0.25 to 1 to see this)
stefan ·
Well, if you skip multiplying the phase by four, it's ok to let it go from -1.0 to 1.0 if a slight change in amplitude is ok by you. It is by me 🙂
-1..1 allows for a 180 degree change of phase, also it allows phase feedback from another oscillator and so forth.
But if this oscillator is not suitable, use the sin1() function instead. It's not as efficient, but it's also less restricted and more precise. Taylor series is another option, but you'd have to deal with negative phase and "mirroring" the first half of the cycle when going to the other half etc. But it's doable. Not as efficiently as this though.
Are you interested in having a slightly more cpu heavy version of this sine, but allowing phase to go from 0 to 360 degrees instead of from -90 to +90?
global goon ·
cheers stefancrs,
i like the sound of your oscillator and it's low cpusage - it's nice and subtle
if it isn't any trouble i'd like to see your 360 degree one!
stefan ·
polyin freq;
polyin phase;
polyout out;
float cos;
float sin;
float tCos,tSin;
float mul;
float mul2;
// since the code component does not support initialising of variables we have to do a hack
float isInitialised;
isInitialised= ((cos > 0) & 1.0) + ((cos < 0) & 1.0);
cos = (1.0 - isInitialised) * 0.99 + (isInitialised > 0) & cos;
mul = freq * 6.283185307; // roughly 2 * pi
cos = cos - sin * mul;
sin = sin + cos * mul;
mul2 = 3.1415926535897932 * 0.25;
tCos = cos;
tSin = sin;
loop(8) {
tCos = tCos - tSin * phase * mul2;
tSin = tSin + tCos * phase * mul2;
}
out = tSin;
You can change the number of iterations and the multiplier if you like to get a higher precision or a higher efficiency (pick one 🙂)
This is really a 720 degree one though, you can go forwards or backwards in phase 360 degrees.
Tom7777 ·
Thanks everyone 🙂
Shifrin ·
Cheers Stefan 🙂
Shif.
global goon ·
nice one stef!
stefan ·
Just thought of a small optimisation.
polyin freq;
polyin phase;
polyout out;
float cos;
float sin;
float tCos,tSin;
float mul;
float mul2;
// since the code component does not support initialising of variables we have to do a hack
float isInitialised;
isInitialised= ((cos > 0) & 1.0) + ((cos < 0) & 1.0);
cos = (1.0 - isInitialised) + (isInitialised > 0) & cos;
mul = freq * 6.283185307179586476925286766559; // pi * 2
cos = cos - sin * mul;
sin = sin + cos * mul;
phase = phase - (phase > 0.5) & 1.0;
phase = phase + (phase < -0.5) & 1.0;
mul2 = phase * 1.5707963267948966192313216916398; // pi * 0.5
tCos = cos;
tSin = sin;
I managed to introduce another feature on this osc. Hard/Soft syncing
To use it, connect output of another osc to "sync input. When this input croses form < 0 to > 0, phase gets set to zero
Thos ways of doing it:
Hardsync: Simply set the phase to 0
Softsync: smoothly crossfades phase over 1/steps samples
Still haven't found how much aliasing it produces...
// since the code component does not support initialising of variables we have to do a hack
float isInitialised;
isInitialised= ((cos > 0) & 1.0) + ((cos < 0) & 1.0);
cos = (1.0 - isInitialised) + (isInitialised > 0) & cos;
mul = freq * 6.283185307179586476925286766559; // pi * 2
// Read the sync trigger
gateup=(sync>=0)&0.5+(gatem1<0)&0.5;
gatem1=sync;
//Uncomment this block for hardsync
//csync=(gateup<1)&cos;
//ssync=(gateup<1)&sin;
//cos = csync;
//sin = ssync;
//Uncomment this block for softsync
syncing=max(syncing,gateup);
isync=isync+(syncing>=1)&step;
cos=isync+(1-isync)*cos;
sin=(1-isync)*sin;
// End of softsync block
cos = cos - sin * mul;
sin = sin + cos * mul;
phase = phase - (phase > 0.5) & 1.0;
phase = phase + (phase < -0.5) & 1.0;
mul2 = phase * 1.5707963267948966192313216916398; // pi * 0.5
tCos = cos;
tSin = sin;
out = tSin;
// Uncomment this block for softsync
syncing=(syncing>=1)&1-(isync>=1)&1;
isync=(syncing>=1)&isync;
// End of softsync block
jorge ·
Hi unkargherth
unkargherth wrote: I managed to introduce another feature on this osc. Hard/Soft syncing
I must say I'm very impressed, I guess this is the point where I can just stop working and let you guys do it all from now on. I knew the code component would open up a lot of possibilities but it's going a lot beyond my expectations. Thanks a lot unkargherth. I was already impressed with stefan's hack for initialising variables, everything seems possible even when it hasnt been implemented yet 🙂.
I also like this collaborative work where each person improves on what was there before, it's great. I feel I should contribute too but its getting too hard now 🙂
lalo ·
jorge wrote: I must say I'm very impressed, I guess this is the point where I can just stop working and let you guys do it all from now on.
yet ready for your world-travelling jorge? 😉
don't let yer lappy at home 😀
yes guys i'm very impressed!!
congrats to you all and to jorge and malc...when i'll finish understand all this code i'll start contribute 😀
lowe
lalo
jorge ·
lalo wrote: yet ready for your world-travelling jorge? 😉
don't let yer lappy at home 😀
Yeah, I think I'll start with Italy, do you know anyone in Italy where I could stay for a week or so?
Here is some soft syncing in action using the stefan/unkargherth/global goon code ( did I forget anyone? ):
lalo ·
jorge wrote:
lalo wrote: yet ready for your world-travelling jorge? 😉
don't let yer lappy at home 😀
Yeah, I think I'll start with Italy, do you know anyone in Italy where I could stay for a week or so?
😀..obviously by me 🙂
lalo
Shifrin ·
This is awesome stuff guys, wow. Thanks to all those who've contributed 🙂
Shif.
Wrote something here? To have a post removed or your name hidden, write to [email protected].