Open303 - open source 303 emulation project - collaborators wanted

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS
JC-303

Post

i will give the waveforms another try (especialy the square..)
btw, in the 88200Hz sample, i can see where you switched the waveform from saw to square right before the end of a note, it's very ugly, i like it ;]
:P
i can see now, my HP filters were wrong again, i knew that because of the way the overal DC "weigth" was different than any sample, even tho the "shapes" looked very close
and another thing i see on this audio sample, which proves my theory about the "bump" on the square..
it is a result from a hard clipper which is clipping some HP-filtered square (or whatever)
there is a low note at one place, where the bump should be pretty visible (in the middle) but it is "away" on the first cycle of this long note because the previous note was very high
erm, i'm not sure if i explained it well, but that's it

now my "bump" is based on an approximitation (i'm adding DC-offset, which is cheating)
but i am pretty sure that if i can get all the HP filters around the oscillator section right - there will be no need for cheating and the waveform will be nailed ;]
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post

float shape(float input, float coefficient) { return (input / (fabsf(input) + coefficient)) * (1.0f + coefficient); }

low += (input - low) * low_coefficient;
high += (low - high) * high_coefficient;
high_bypass = (low - input) * high_bypass_level;
low_bypass = high * low_bypass_level;
shaped = shape(high - input, shape_coefficient);
square_output = high_bypass + low_bypass + shaped;

given the correct coefficients, this is the 100% accurate shaper for the tb-303 square wave. the input is a slightly highpassed ramp wave as generated by the oscillator. just use a typical minblit ramp and it should be fine. the shape coefficient should be about 1/100

Post

thanks rv0 for the samples. grabbed them. yeah, i've been silent here for a while since i was doing other stuff. but now that i have the samples, i can pick it up again. i will upload a new version of the code to the repository when i have calibrated the resonance vs. cutoff tuning according to the samples.

@rv0: if you want upload access to the sourceforge repository, just let me know. i'm not yet all that familiar how to manage all these things but i'll look into it once the interest is there.

edit: the same goes of course for anyone else who wants upload access...and thanks aciddose for the pseudocode. any indications what the filter coefficients would be?

...but however, i guess my current code will have difficulty to use this because i'm actually pre-rendering the square-wave into a table instead of generating it on the fly. i do it this way because i want to avoid realtime waveshaping due to potential aliasing. my current code generates a mip-map from the wave-shaped saw ....but i'm open to reconsider that if it's good for the sound.
Last edited by Music Engineer on Fri Nov 27, 2009 4:16 pm, edited 1 time in total.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

aciddose wrote:float shape(float input, float coefficient) { return (input / (fabsf(input) + coefficient)) * (1.0f + coefficient); }

low += (input - low) * low_coefficient;
high += (low - high) * high_coefficient;
high_bypass = (low - input) * high_bypass_level;
low_bypass = high * low_bypass_level;
shaped = shape(high - input, shape_coefficient);
square_output = high_bypass + low_bypass + shaped;

given the correct coefficients, this is the 100% accurate shaper for the tb-303 square wave. the input is a slightly highpassed ramp wave as generated by the oscillator. just use a typical minblit ramp and it should be fine. the shape coefficient should be about 1/100
so, "input" is the ramp, already HP-filtered or not?

and these "low" and "high" look like LP/HP filters? i guess i should use the exp(-2*pi*Fc/Fs) to make 'em behave the same way at any sampling rate?

tho, i can't say untill i try this, but i suspect there is no easy way for this "bump" to show up, unless it's a result of the "high_bypass" addition
also, *any* filtering before this shaper is responsible for the symmetry, so it'll be very tricky to find the coefficients
EDIT: and this shaper, looks dangerous with the division :-o
looks pretty close to atan() but far different from tanh() (what i was using)
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post

Robin: i understand, but a "perfect" square wave is not what you need here
even if you use two sawtooths (one inverted) and variable symmetry depending on the frequency - there are still some ugly stuff going on in there (the smoother negative peak, and the "bUmp")
also, don't forget that the usual octave range of the TB-303 sequencer (even with the highest tuning) is kinda low
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post

antto wrote:Robin: i understand, but a "perfect" square wave is not what you need here even if you use two sawtooths (one inverted) and variable symmetry depending on the frequency - there are still some ugly stuff going on in there (the smoother negative peak, and the "bUmp")
yes, i'm aware that my approach currently ignores these details - pre-rendering can't take filtering before waveshaping into account. but i'm a kinda anti-aliasing fetishist. in this context here, i consider aliasing as more detrimental to the sound (and also to realism) than missing some little details in the waveshape. but we'll see...maybe i'll change my mind
also, don't forget that the usual octave range of the TB-303 sequencer (even with the highest tuning) is kinda low
i see. although, i don't really want to restrict the note range artificially. however, maybe i could accept some slight aliasing in a range which is rarely used anyway.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

aciddose: damn! i still don't get how this works, i was almost dissapointed with it untill i increased the levels to find the result very familiar ;]
symmetry is looking/sounding promissing, negative vs positive peak levels too
gotta check the symmetry closer now, and i hope to see a "bump" somewhere ;]

great thing to play with
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post

it's 100% accurate for a fixed wave.

"i do it this way because i want to avoid realtime waveshaping due to potential aliasing. my current code generates a mip-map from the wave-shaped saw ....but i'm open to reconsider that if it's good for the sound."

you definitely could render into a table using this function, just let it run for a second before sampling a cycle.

to eliminate most of the aliasing just adjust the low cutoff, maybe replace it with a steeper filter. you could also 2x oversample and use a half band filter - we're talking about a 303 here, first the pitch can't even go high enough to produce very evident aliasing, second we're only generating a single channel osc -> shaper -> filter -> amp -> mixer/shaper anyway, so you can go overkill on stuff like oversampling.

you could even go as far as to generate a naive waveform if you really wanted, the aliasing wouldn't be too bad if it's used as a 303 is generally. (to play c1, c1, c0, c2, c1, c1, c0, c2)

i don't know what the coefficients should be exactly, you need to compare to a specific 303 that you want to mimic. the high cutoff should be about 100hz, while the low is near 12000hz... but that's just guessing. generally when i'm using this shaper i tweak it in real-time, putting it after a oscillator or filter as part of a synth.

by the way, valid coefficients for the shaper are:

log: +inf to 1/+inf
exp: -inf to -1 + 1/-inf

i generally do something like: coeff = 100 - (100 - 1/100) * value^(1/3)

Post

aciddose: i don't see the "bump" on the negative peak, so there must be some additional hard clipper after this whole circuit
i also find it hard to figure how to tweak the symmetry

at the very low frequencies, the square is very assymetrical in one direction (the negative part is longer)
as frequency increases it reaches perfect symmetry at some point, then after that, it goes in the other direction..
i can post my measurements if you're interested

i figured the shaper coefficient is only responsible for the negative peak "smoothness"
i'm currently using very low values there (0.001 or something)

and, um, am i right about the exp(-2 * pi * Fc/Fs) for the low_ and high_coefficient?
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post

that function is only accurate for high frequencies, and it's still only an approximation, but you could use it if you wanted.

in the real 303 circuit things are actually a bit more complex:

the real shape function for a transistor as in the circuit is a combination of the diode function with a saturation function, but the transistor saturates based upon the current fed to it from a capacitor which discharges more with longer "on" pulse cycles. at lower frequencies you start to get a triangular charge/discharge of that capacitor which changes the saturation point of the transistor. this downward edge i'd say isn't audible, though.

the important part of the waveform is that the "on" edge of the pulse is soft (actually the result of amplifying the ramp, plus the diode+saturation shaper function) and the "off" edge is very sharp. this is emulated by feeding some of the high frequency from the input ramp into the output - one edge becomes sharper.

Image
on

Image
off

if you really care about this so-called "bump", to perfectly emulate it the shaping must be done in real-time, the source capacitor has memory of whatever previous frequency was being generated. to adjust symmetry you can either simply take what is given to you as you adjust the highpass coefficient (works perfectly...) or add some offset to the input of the shape function.

Image
25hz "bump"

Image
50hz, "bump"

a 100% perfect emulation has many more filters and a more complicated shaper function to the point where the shaper takes more processing power than the ramp oscillator. it will also produce far more aliasing where it is impossible to eliminate it without huge oversampling values like 128x.

you should listen to the waveform rather than looking at it, although phase plays a very important part in how the filter saturates, you only need to be concerned about wild variations in phase for that to be a significant concern.

remember that the high/low bypass amplitudes can be negative.

Post

http://www.box.net/shared/a29673h57l <- image
this is an old image i draw..
top: my square
bottom: TB-303 square
it's some low note, you can see this "bump" on the TB-303 square only
i've drawn in red how the square looks without entering the filter (and all the HP filters there)
i only guessed how it looks in the TB-303 but it must be something like that

it's on the negative part of the square, it's a result from a little HP filter + clipper only on the negative part of the signal (or there is some DC-offset, whatever)
also, the transition from positive to negative is the smoother one

in my approximitation i inverted the sawtooth before i send it to the shaper
otherwise i get the wrong symmetry ;]

this smoother edge is not so important to the ear, as to the filter
at higher cutoff frequencies, the filter resonates only at the positive peak, which IS important

EDIT: thinking a little bit more..
aciddose: in your approximitation, what determines the symmetry is this
shaped = shape(high - input, shape_coefficient);
which is either a low or high-pass filter (one pole)
i already tryied one pole HP filter before the shaper, it was close, but it was not enough to match the exact symmetry accross the whole range of the TB-303 (all 3 octaves of the sequencer + min/max TUNE knob)

then i tryied with two HP filters in series but that messed things up (phases got wrong)
maybe with a stronger (steeper) HP filter it'll work but i'm not sure
so instead, i measured the symmetry closely and generated an approximitation, i'm basicaly adding variable DC offset in the shaper, based on the oscillator frequency, which works great..

i think i'll return to my old approach, but i'll probably use your shaper instead of my tanh() ;]
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post

the photos i posted are absolutely perfect, the real output from the tb before the filter or any highpass. if you want to make your waveforms exact, match to those.

Post

then i think you're watching it top-side-down?

let's say that the sawtooth starts at -1 and rises to +1
then the square is made out of a inverted copy of this sawtooth
what i see on your photo doesn't have a bump on the negative part
but if you invert it, you CAN have a bump if you put a hard clipper there

also, the "smoother" transition is the one that goes from positive to negative
in your case, you have the opposite, so you're definately looking it reversed

i might give it a second try, but it's not easy to get the same symmetry..
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post

it isn't reversed ... the output of the tb is inverted by the "mixer" stage.

Post

well in most of the audio samples i got (rv0, acidvoice, ladyada..) , the sawtooth is -1 to +1, and the square is how i explained..
so in the square shaper, it MUST be inverted :shrug:
i'll record a demo of a pattern using the whole note range of the sequencer + TUNE knob, both with the filter and raw oscillator signal..
after i get back from work..
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post Reply

Return to “DSP and Plugin Development”