Open303 - open source 303 emulation project - collaborators wanted
- KVRAF
- 2569 posts since 4 Sep, 2006 from 127.0.0.1
the place where i put my hardclipper to make the "bump" is wrong..
i need to think.. grrr.. ;]
EDIT: now i'm thinkering.. could the shaper be (very) assymetrical?
or is there a hard clipper after it (or could it be the same hardclipper that's causing the bump)
even that the negative edge is smoother, the transition there starts sharp and decreases to the bottom smoothly, which looks like a hard clipper on the positive part, and a softer shaper on the negative part, hm..
i need to think.. grrr.. ;]
EDIT: now i'm thinkering.. could the shaper be (very) assymetrical?
or is there a hard clipper after it (or could it be the same hardclipper that's causing the bump)
even that the negative edge is smoother, the transition there starts sharp and decreases to the bottom smoothly, which looks like a hard clipper on the positive part, and a softer shaper on the negative part, hm..
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
- KVRAF
- 12615 posts since 7 Dec, 2004
of course, the ramp generator goes from +11 to +5.5. that goes through a nfet buffer which clips the top edge at about 9.5, although it's EXTREMELY variable. the gate voltage for a nfet can range from -4 to -10, which translates to a bias of from 1 to 6. the source voltage is 12.0, meaning you do this if you want to be exact:
ramp from 11 to 5.5;
add about 1.5;
soft clip from 11 to 11.5 only (the negative side isn't clipped or shaped) with:
if (input > 11) input = shape(input-11, 0.5)+11;
highpass filter the shaped ramp at about 12000hz and mix it back with itself at a ratio of 5|1
this gives you the input to the amp which shapes the ramp into a pulse;
to emulate that it's a bit more complicated and it might be easier for me to write the entire code and post that instead.
basically, the amp scales the signal by about 120, hard clips the negative side and applies a S curve shaper function;
it also applies a lossy integrator that goes toward 10 if the ramp is below the threshold and 8.5 if above with slightly different attack/release times;
the output is then: min(inverted+scaled+clipped, integrator-0.65)
ramp from 11 to 5.5;
add about 1.5;
soft clip from 11 to 11.5 only (the negative side isn't clipped or shaped) with:
if (input > 11) input = shape(input-11, 0.5)+11;
highpass filter the shaped ramp at about 12000hz and mix it back with itself at a ratio of 5|1
this gives you the input to the amp which shapes the ramp into a pulse;
to emulate that it's a bit more complicated and it might be easier for me to write the entire code and post that instead.
basically, the amp scales the signal by about 120, hard clips the negative side and applies a S curve shaper function;
it also applies a lossy integrator that goes toward 10 if the ramp is below the threshold and 8.5 if above with slightly different attack/release times;
the output is then: min(inverted+scaled+clipped, integrator-0.65)
- KVRAF
- 2569 posts since 4 Sep, 2006 from 127.0.0.1
i did another thing yesterday, but i had no time to finish it, it's based on "cheating" again
i still use my approximitation for the symmetry (shaped = shaper(-saw -offset_approx))
then i add a little bit of the sawtooth to this
x = shaped + saw * *knob; // i tweak this realtime
x = hpf1(x);
x = hpf2(x);
// two 1pole HP filters to make the whole thing ugly ;]
float c1 = *knob2;
float c2 = *knob3;
x = (x > c1 ? c1 : x);
x = (x < c2 ? c2 : x);
the first clipper is always clipping the positive part hardly (so there is no clue of it being HP-filtered before that)
this also solves my problem with the "smoother" edge being not so "smoother" in the positive->negative transition (well, visually, it's still less exciting to the resonant filter)
then, the second clipper is what makes the "bump"
my goal will be to try and approximate the behaviour of the "bump", the overall peak levels and the individual peak levels across the whole (useful) range of the oscillator ... without altering the c1 and c2 values (or at least not too much)
i just need time
what you're saying is probably right, but it looks like it'll be very CPU intensive
i'll do compromises, if my "cheap" approximitation is not pleasing to the ear, i'll probably forget about the CPU meters and do what it has to be done ;]
i'll be tweaking it after work, blah..
i still use my approximitation for the symmetry (shaped = shaper(-saw -offset_approx))
then i add a little bit of the sawtooth to this
x = shaped + saw * *knob; // i tweak this realtime
x = hpf1(x);
x = hpf2(x);
// two 1pole HP filters to make the whole thing ugly ;]
float c1 = *knob2;
float c2 = *knob3;
x = (x > c1 ? c1 : x);
x = (x < c2 ? c2 : x);
the first clipper is always clipping the positive part hardly (so there is no clue of it being HP-filtered before that)
this also solves my problem with the "smoother" edge being not so "smoother" in the positive->negative transition (well, visually, it's still less exciting to the resonant filter)
then, the second clipper is what makes the "bump"
my goal will be to try and approximate the behaviour of the "bump", the overall peak levels and the individual peak levels across the whole (useful) range of the oscillator ... without altering the c1 and c2 values (or at least not too much)
i just need time
what you're saying is probably right, but it looks like it'll be very CPU intensive
i'll do compromises, if my "cheap" approximitation is not pleasing to the ear, i'll probably forget about the CPU meters and do what it has to be done ;]
i'll be tweaking it after work, blah..
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
- KVRAF
- 12615 posts since 7 Dec, 2004
well, here is some emulation code:
it's fairly decent, one issue is that the top edge of the output waveform is too sharp - this is because the min() function is used to quickly emulate the behavior of the source voltage dropping changing the output from the amplifier's collector. i didn't use any electronics stuff here - i started off on that tangent and realized it's a complete waste of time and resources. the "work in progress" code was already ten times larger than this version and wasn't yet even emulating the amplifier which is the most complex part.
it should alias like hell even if you give it an antialiased ramp. i still recommend using the simple shaper i provided before - it sounds equally as accurate without the aliasing. i've only designed this by looking at it, not by listening, so the pulse width might be off. to fix that just adjust "width_correction" and the filter frequencies. there are lots of fudged values, the only way to eliminate them completely is to model the electronics - but those are basically also fudged. (amplification factors and so on for transistors.. blah)
http://www.speedyshare.com/files/19579837/303thing.exe
test application (sorry, my sever is down)
the source is quite large as it includes a whole graphics library, windowing, gui, and tons of utilities. i tried not to use anything weird, you should know how to implement fmax, fmin, etc.
Code: Select all
const float high_frequency = intgr::f(80.0f, rate);
const float high_frequency_b = intgr::f(10.0f, rate);
const float low_frequency = intgr::f(10.0f, rate);
const float saturation_point = 0.6f;
const float amplification = 85.0f;
const float edge_factor = 0.1f;
const float edge_factor_b = 1.0f;
const float width_correction = 0.0f;
// ramp
phase += delta;
if (phase > 1.0f) phase -= 1.0f;
ramp = 1.0f - (phase * 2.0f);
// nfet buffer
saturate = powf(fmax(ramp - saturation_point, 0.0f), 2.0f);
buffered = ramp - saturate * 1.5f;
// high peak filter
highf = buffered - highpass_buffer;
highpass_buffer += highf * high_frequency;
highmix = highf*0.2f + buffered;
// target voltage for source filter
d = shape(highmix, edge_factor) + 1.8f;
source += (d - source) * low_frequency;
// output voltage from amplifier
s = width_correction + highmix * -amplification;
pulse = fmax(fmin(shape(s, edge_factor_b), source), 0.0f);
// highpass filter
output = pulse - highpass_buffer_b;
highpass_buffer_b += (output - highpass_buffer_b) * high_frequency_b;
it should alias like hell even if you give it an antialiased ramp. i still recommend using the simple shaper i provided before - it sounds equally as accurate without the aliasing. i've only designed this by looking at it, not by listening, so the pulse width might be off. to fix that just adjust "width_correction" and the filter frequencies. there are lots of fudged values, the only way to eliminate them completely is to model the electronics - but those are basically also fudged. (amplification factors and so on for transistors.. blah)
http://www.speedyshare.com/files/19579837/303thing.exe
test application (sorry, my sever is down)
the source is quite large as it includes a whole graphics library, windowing, gui, and tons of utilities. i tried not to use anything weird, you should know how to implement fmax, fmin, etc.
- KVRAF
- 2569 posts since 4 Sep, 2006 from 127.0.0.1
ok, so the executable..
my observations are that the ramp is a "rising" one (-1 to +1)
what i see on your "plot".. i must invert it and it then looks exactly how i'm used to see it ;]
everything is there, the edges/transitions smoothness/sharpness, the "bump" and the varying positive_vs_negative peaks amplitudes..
the only thing that is missing now is the symmetry
and then it should be tweaked to match the 3 things i mentioned before (which must be based on samples from a chosen TB-303)
i'll first complete the tests of my own "cheap" approximitation..
but this is it, aciddose, you rock ;]
my observations are that the ramp is a "rising" one (-1 to +1)
what i see on your "plot".. i must invert it and it then looks exactly how i'm used to see it ;]
everything is there, the edges/transitions smoothness/sharpness, the "bump" and the varying positive_vs_negative peaks amplitudes..
the only thing that is missing now is the symmetry
and then it should be tweaked to match the 3 things i mentioned before (which must be based on samples from a chosen TB-303)
i'll first complete the tests of my own "cheap" approximitation..
but this is it, aciddose, you rock ;]
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
- KVRAF
- 12615 posts since 7 Dec, 2004
well this isn't really "it", but it'll send you in the right direction toward getting a "perfect" emulation. it lacks the exponential (diode function) attack.
the nicest thing is actually the test platform i wrote, you could get the source for that if you wanted. it's super easy to add knobs and blah blah, although i suppose it would also be easy to use something like synthedit to test this sort of stuff. it would also be nice if the platform allowed you to hear whatever is happening. currently it just samples the waveform at the display resolution.
i tweaked it a bit more last night, but i'm aiming at a moving target - between my circuit model results and a set of filtered samples. what i really need is to look at the waveform directly from the oscillator of a real 303 without it being filtered or manipulated in any other way. i'd need a 303 for that.. so it'll have to be left up to somebody who has one and an oscilloscope.
again, the ramp isn't a rising one - the output "mixer" in the 303 inverts the whole signal after it was filtered by the vcf and scaled by the vca. that's important if the filter includes asymmetric non-linearity.
the nicest thing is actually the test platform i wrote, you could get the source for that if you wanted. it's super easy to add knobs and blah blah, although i suppose it would also be easy to use something like synthedit to test this sort of stuff. it would also be nice if the platform allowed you to hear whatever is happening. currently it just samples the waveform at the display resolution.
i tweaked it a bit more last night, but i'm aiming at a moving target - between my circuit model results and a set of filtered samples. what i really need is to look at the waveform directly from the oscillator of a real 303 without it being filtered or manipulated in any other way. i'd need a 303 for that.. so it'll have to be left up to somebody who has one and an oscilloscope.
again, the ramp isn't a rising one - the output "mixer" in the 303 inverts the whole signal after it was filtered by the vcf and scaled by the vca. that's important if the filter includes asymmetric non-linearity.
- KVRAF
- 2569 posts since 4 Sep, 2006 from 127.0.0.1
what i am doing is kinda like this:
1) change code if needed, recompile.
2) Save As VST (the whole synth with the changes..)
3) load my DAW, compare
4) write coefficients to CurveExpert for later use ;P~
so, in the DAW, i got a project with a bunch of samples from rv0
i'm using a sample with the square wave, at fully open filter (max envmod, max cutoff, max decay) and reso=0
in the sample, it's playing a pattern of a bunch of notes from the lowest to the highest possible by the sequencer, with TUNE=MIN
the lowest note there is at approximately 17.35Hz, the highest at ~146
i've programmed the same pattern in my synth, and i have (approximately) the same "bad" tuning
i "loop" around at each note one at a time and tweak my synth, i'm watching both waveforms (the audio sample and my synth) on an oscilloscope, and a spectroscope
i'm close to finished now, i'll need to "automate" 2 values depending on the oscillator frequency: the negative clipper value, and the additional raw-sawtooth mix level
the other values i tweaked will remain "static" ..
this is still "cheating" but what the hell
..
btw, someone here said he *knows* how the waveforms look before the main-filter, but he wouldn't tell it (it's a secret) .. how generous..
oops, he might be watching us ;]
1) change code if needed, recompile.
2) Save As VST (the whole synth with the changes..)
3) load my DAW, compare
4) write coefficients to CurveExpert for later use ;P~
so, in the DAW, i got a project with a bunch of samples from rv0
i'm using a sample with the square wave, at fully open filter (max envmod, max cutoff, max decay) and reso=0
in the sample, it's playing a pattern of a bunch of notes from the lowest to the highest possible by the sequencer, with TUNE=MIN
the lowest note there is at approximately 17.35Hz, the highest at ~146
i've programmed the same pattern in my synth, and i have (approximately) the same "bad" tuning
i "loop" around at each note one at a time and tweak my synth, i'm watching both waveforms (the audio sample and my synth) on an oscilloscope, and a spectroscope
i'm close to finished now, i'll need to "automate" 2 values depending on the oscillator frequency: the negative clipper value, and the additional raw-sawtooth mix level
the other values i tweaked will remain "static" ..
this is still "cheating" but what the hell
..
btw, someone here said he *knows* how the waveforms look before the main-filter, but he wouldn't tell it (it's a secret) .. how generous..
oops, he might be watching us ;]
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
- KVRAF
- 12615 posts since 7 Dec, 2004
well the ones generated by my code should be almost exact other than the min() thing and lack of diode function that i mentioned. the only issue remaining is that reality is sometimes slightly different than theory and simulations, and other things like component variation and temperature can influence this stuff. the thing i don't know is if that kind of stuff is actually important or not. some people say one tb can sound much better than another, so that might mean component variations are important. people tend not to pay attention to the temperature influence, and that would need to be measured with a freezer and a heater.
- KVRAF
- 2569 posts since 4 Sep, 2006 from 127.0.0.1
i got audio samples from a bunch of different sources..
there are some things that match very closely between all of them (like the envelope curve, the overall look of the square waveform (bump, assymetry)
but some things vary a little or a lot indeed
the exact place of the bump for example
symmetry too (tho, a little)
the tuning (but it might be a result of internal "correction")
knob response..
as rv0 said, the scheme in the manual is not complete/exact, and there were different "revisions" produced around.. so the difference from one TB-303 to another might be *huge* (if you look closely)
anyway, i'm still messing with my approximitation, it's getting better, i need just a bit more time, don't wanna rush, it has to look good
i'm currently playing with a hardclipper on the negative part only, and i "remixed" your shaper a little bit to have sharper positive edges
..i use two different coefficients for when the "input" is below or above zero
ahh.. tomorow..
there are some things that match very closely between all of them (like the envelope curve, the overall look of the square waveform (bump, assymetry)
but some things vary a little or a lot indeed
the exact place of the bump for example
symmetry too (tho, a little)
the tuning (but it might be a result of internal "correction")
knob response..
as rv0 said, the scheme in the manual is not complete/exact, and there were different "revisions" produced around.. so the difference from one TB-303 to another might be *huge* (if you look closely)
anyway, i'm still messing with my approximitation, it's getting better, i need just a bit more time, don't wanna rush, it has to look good
i'm currently playing with a hardclipper on the negative part only, and i "remixed" your shaper a little bit to have sharper positive edges
..i use two different coefficients for when the "input" is below or above zero
ahh.. tomorow..
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
-
- KVRist
- 445 posts since 10 Jun, 2004
I'm not sure if you are referring to me, but..antto wrote: btw, someone here said he *knows* how the waveforms look before the main-filter, but he wouldn't tell it (it's a secret) .. how generous..
![]()
I measured the oscillator section decoupled from the filter when I was working on this stuff years ago. The waveforms before the filter are not that spectacular, in fact they look pretty simple (not unlike the stuff you and aciddose already have come up with). The signals are also sketched in the 303 schematics and they do look that way so its not an approximation.
The tricky part is when the filter is attached it kind of messes up the oscillator signal and gives you all those bumps and it also messes with the duty cycle somehow of the square wave. So what I did what model the osc+filter together, as close as possible. When I had a decent model of the filter and the output matched my samples I took the inverse of the filter function and *inverse filtered* the output to get the input signal to the filter. I did this for a number of samples and this way I got the osc function that I really wanted to model instead of trying to model the osc and filter individually.
I'm not claiming this is the only way to do this, I think many ways will lead to rome.
--Mike
- KVRAF
- 2569 posts since 4 Sep, 2006 from 127.0.0.1
Mike, i wasn't referring to you, you're a nice guy ;]
what i'm doing leads to a simple square indeed, it's just that i'm comparing to a sample and all the differences are easy to be seen
i agree that in the TB-303 it's all one big circuit, instead of individual "modules" .. this is one of the tricky things about this synth
but after all, i'm comparing the output of my synth to the output of rv0's synth ;]
what i'm doing leads to a simple square indeed, it's just that i'm comparing to a sample and all the differences are easy to be seen
i agree that in the TB-303 it's all one big circuit, instead of individual "modules" .. this is one of the tricky things about this synth
but after all, i'm comparing the output of my synth to the output of rv0's synth ;]
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
-
Muon Software Ltd Muon Software Ltd https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=89
- KVRian
- 1461 posts since 21 Nov, 2000
That was me, and I *never* said it was a secret. Anybody with a suitably modified 303 could take those samples, its hardly any kind of secret.btw, someone here said he *knows* how the waveforms look before the main-filter, but he wouldn't tell it (it's a secret) .. how generous..
What I actually said that I would consider contributing to an open-source effort to analyse the 303, but what you're doing, as we already discussed at some length, is not going to be open-source.
Regards
Dave
-
Muon Software Ltd Muon Software Ltd https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=89
- KVRian
- 1461 posts since 21 Nov, 2000
...and I suppose that means, by extension, that I'm not. I can live with that.Mike, i wasn't referring to you, you're a nice guy ;]
- KVRAF
- 2569 posts since 4 Sep, 2006 from 127.0.0.1
Dave: ok, you didn't said it was a secret, sorry, my bad memory
"Anybody with a suitably modified 303 could take those samples.." you're perfectly right, UNfortunately, i don't see much of these people here
and yup, my synth is a closed-source top-secret rocket-science project, there is no way for mortals to find out for example how i'm approximating the square wave, or which filter i'm using, or what's the shape of my cutoff envelope.. no way, access denied.. just don't look in the previous pages or i will have to kill you ;]
you ain't a bad guy, don't missunderstand me, it's just that you have been following this thread, you've wrote some long posts, but yet, you haven't told us anything about the 303 itself, which is not wrong, but slightly offtopic
i'm still hoping to see you come up one day here in this thread, and say "ok, here you are, some screenshots of the raw square wave.." .. or anything similar ;]
no bad intentions meant!
"Anybody with a suitably modified 303 could take those samples.." you're perfectly right, UNfortunately, i don't see much of these people here
and yup, my synth is a closed-source top-secret rocket-science project, there is no way for mortals to find out for example how i'm approximating the square wave, or which filter i'm using, or what's the shape of my cutoff envelope.. no way, access denied.. just don't look in the previous pages or i will have to kill you ;]
no, it's just my bad english, i wanted to tell Mike that what he's doing both for the people, and for us here is nice of him.. replace the comma with a fullstop thereDave wrote:...and I suppose that means, by extension, that I'm not. I can live with that.antto wrote: Mike, i wasn't referring to you, you're a nice guy ;]
you ain't a bad guy, don't missunderstand me, it's just that you have been following this thread, you've wrote some long posts, but yet, you haven't told us anything about the 303 itself, which is not wrong, but slightly offtopic
i'm still hoping to see you come up one day here in this thread, and say "ok, here you are, some screenshots of the raw square wave.." .. or anything similar ;]
no bad intentions meant!
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
- KVRAF
- 2569 posts since 4 Sep, 2006 from 127.0.0.1
vb303_rv0_anttosawsqr_test01_06_6.wav (4MB)
well, phew.. it looks fair
i cheated a lot..
the symmetry, the additional sawtooth mix level, the negative clipper level, and the final volume are adjusted depending on frequency
it's not "correct" .. the smoother edge is smoother, but the shape is not exact, so my circuit is wrong somewhere, but anyway, the purpose of this smoother edge is only important to the filter, so it's fair..
the need to adjust the final volume also tells that my circuit is wrong somewhere..
so that kinda looks like this:
i just found some small thing i need to investigate tomorrow, but if nothing happens, i'll probably use this code here
well, phew.. it looks fair
i cheated a lot..
the symmetry, the additional sawtooth mix level, the negative clipper level, and the final volume are adjusted depending on frequency
it's not "correct" .. the smoother edge is smoother, but the shape is not exact, so my circuit is wrong somewhere, but anyway, the purpose of this smoother edge is only important to the filter, so it's fair..
the need to adjust the final volume also tells that my circuit is wrong somewhere..
so that kinda looks like this:
Code: Select all
x = sawtooth; // my ramp, it's -1 to +1!
xh = x * xha;
x = shp((-x - soff), 0.027);
x = (x > c2 ? c2 : x); // positive clipper here
x = x + xh; // adding some of the sawtooth here
x = hpf2(x,21Hz);
x = (x < -c ? -c : x); // negative clipper
output = x * ac; // amplitude correction
erm, the approximitations for these values are ugly, they waste CPU, but what the hell..
double FcX2 = Fc * Fc; // optimization
double xha = 0.36907658 + -0.00084413331 * Fc + 71.608498 / (FcX2);
double soff = (0.90412745 + -0.0082430065 * Fc) / (1.0 + 0.057837048 * Fc + 3.1131084e-005 * (FcX2));
double c = 0.82866767 * exp(-exp(4.1103204 - 0.1668213 * Fc));
double c2 = 0.545;
double Fc_pow = pow(Fc,-4.4282836);
double ac = ((0.47700034 * 0.0019996586 + 321.55132 * Fc_pow) / (0.0019996586 + Fc_pow)) * 2.2;
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
