Open303 - open source 303 emulation project - collaborators wanted

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

Post

here's what i did: vb303_wf.rar (5.9MB)
so that's a tanh() over the saw, with some offset
the saw is as normal as can be, no phase mish-mash
i also updated my bandlimited saw code, added a comment at musicdsp
.. i just changed the "gibbs" fix a little, now it's even smoother around the edges
actually the negative peak is not louder (as i was thinking before) it's actually quieter, because it's smoother
i was fooled by the main-filter, when the cutoff is really low, the positive peak (which is actually louder) gets attenuated (because it's sharper, and has more high-freq harmonics)
but when the filter opens up, you can see how the positive peak is louder and sharper, negative is just smoothened by the tanh()

i have only one other idea about the square, again, a sort-of-tanh() distortion, but this time, the sawtooth fed thru a HP filter before getting distorted (this might explain the PW, and the sharp positive peak)
gonna test it too
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post

Hi guys,

i've been a bit silent here recently because i got carried away by working out the math for an envelope generator that may be useful here. it typically looks like that:
Image
the nice thing about this is that it generates a smooth curve without any 'breakpoints'. basically, it's just a multiplicative accumulator for the decay followed by a leaky integrator for the attack - presumably what most are doing anyway. however, it turned out to be surprisingly complicated to normalize such an envelope generator to a peak excursion of unity and to parametrize it in terms of the time-instant of the peak. i documented my derivations again in a little paper:

www.rs-met.com/documents/notes/AttackDecayEnvelope.pdf

...this is probably to be continued. i also did a proof-of-concept implementation in octave:

Code: Select all

clear all;

fs = 44100;
N  = 5*fs;      % number of samples to generate
td = 1.0;       % decay time constant (in seconds)
tp = 0.5;       % time of the peak
ta = tp/(3*td); % attack time constant (initial guess - works for tp<td)

% find the attack time constant such that the peak occurs at tp:
rp = tp/td;
if( rp > 1 )
 ra = 1.128*exp(0.9837*rp) - 1.355*(0.42*rp);  
else
 ra = 0.2073*rp^3 + 0.5512*rp^2 + 0.2398*rp;
end
ta = ra*td; % initial guess
if tp > 0 && tp <= td
 k = -log(td)-tp/td; 
 for i=1:1000
  taOld = ta;
  ta = -tp / (k+log(ta));
  if( abs(taOld-ta) < 1.e-12 )
   break;
  end
 end
elseif tp > 0 && tp > td
 k  = tp/td + log(td);
 for i=1:1000
  taOld = ta;
  ta = exp(k-tp/ta);
  if( abs(taOld-ta) < 1.e-12 )
   break;
  end
 end 
else
 ta = 0;
end

% compute the filter coefficients:
x  = exp( -1.0 / (fs*td)  );
bd = 1-x;
ad = -x;
x  = exp( -1.0 / (fs*ta)  );
ba = 1-x;
aa = -x;

% compute the normalizer:
if td == 0 
  error('zero decay time not allowed');
elseif ta == 0
 normalizer = 1/bd;
elseif ta == td
 np = tp*fs;
 xp = (np+1)*ba^2*aa^np;
 normalizer = 1/xp; 
else
 s   = 1 / (aa-ad);
 b01 = s * aa*ba*bd;
 b02 = s * ad*ba*bd;
 a01 = s * (ad-aa)*aa;
 a02 = s * (ad-aa)*ad;
 np  = tp*fs;
 xp  = b01*a01^np - b02*a02^np;
 normalizer = 1/xp;
end

% generate the decay by multiplicative accumulation:
env = zeros(N,1);
c   = -ad;
y   = bd*normalizer/c;
for n=1:N
 y      = c*y; 
 env(n) = y;
end

% generate the attack by leaky integration:
y  = 0;
for n=1:N
 y      = ba*env(n) - aa*y; 
 env(n) = y;
end

% plot the result:
t = (0:N-1)/fs;
plot(t, env);
grid on;
and will next turn to a c++ implementation which will probably become part of the next version of the AciDevil source.

yeah yeah - i know - the shape of 303 envelopes is not exactly exponential. but there's nothing stopping me from passing this envelope through some kind of shaper to account for that. ..which i will probably do at some stage
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

Robin, are you thinking of using this for all envelopes, or do you have a particular one in mind?
Swing is the difference between a drum machine and a sex machine.

Post

mistertoast wrote:Robin, are you thinking of using this for all envelopes, or do you have a particular one in mind?
for a pure 303 emu, i was mainly thinking about the filter envelope with accent (as this one has non-instantaneous attack). you know - this distinctive 'wow' (instead of just 'ow'). but in acidevil - as an extension of the 303 theme - i will also allow for non-zero attack for non-accented notes
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

Are you planning on modeling the increasing cutoff that happens on repeated accented notes? And would that complicate the use of your code?
Swing is the difference between a drum machine and a sex machine.

Post

mistertoast wrote:Are you planning on modeling the increasing cutoff that happens on repeated accented notes?
i'll certainly attempt to model that, although i'm not yet quite sure how. but probably just yet another RC.
And would that complicate the use of your code
i don't think so. i think, it will be just another thing that is added to the cutoff frequency. but we'll see.

btw.: how do you guys handle the bipolarity of the 303s filter envelope? i have my way doing it and will probably also document that soon. but i'd be curious what your takes on this point are.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

I'm trying to figure that out now. I think antto mentioned his approach just obliquely. Maybe he can elaborate?

I was hoping that the discharge would be constant throughout, every single sample, even when the envelope is gaining. I thought maybe I could just add an impulse during attack. This approach might let me handle the multiple-accent accumulation easily.
Swing is the difference between a drum machine and a sex machine.

Post

first off, i started with a bipolar envelope too (actually i just added a little negative DC to my envelope)
well, that made things complicated
so now, my envelope isn't bipolar, it's always in the range 0 to 1

i've modeled the accent system with a bunch of peakfollowers, multiplyers..
erm, that's actually not a "model" since it has nothing to do with the real one i guess, but it kind of achieves a very similar effect (i've spent a lot of time on it too)

Robin Whittle has some good explanation about that, capacitors, resistors and blah blah, how they are linked with the resonance knob and accent knob, but i don't understand it, i don't know how what parts i need to use to achieve it

i know it's something simple, just has to be done perfectly accurate to get the effect

now if someone can read that text (or the schemes) and tell me what happens.. ;]

as far as i understand from there, i think it's something like this:

envelope is bipolar, it gets amplified according to the value of the EnvMod knob (cutoff is added to the filter elsewere)
now the envelope goes thru a switch
during normal notes, the switch passes the envelope signal directly to the filter cutoff

during accented notes, the switch passes the envelope signal thru the "gimmick" circuit
there, when Accent knob is low - nothing different happens to the signal
the envelope is passed to the filter, and it looks like a normal note's envelope with minimum decay (nothing more)
then, Accent knob gets increased:
when the Resonance knob is low, the envelope signal is almost untouched
but when resonance is high, the envelope gets smoothened

i still don't know what kind of filters are there, how are they linked
how does the whole thing look like
i guess one of the LP filters has variable frequency (probably getting switched by the sequencer or something..)

the envelope probably gets added a really sharp peak (also, high in amplitude) because even smoothened by the filter, it looks like it was sharp, it must have high amplitude

damn, someone's gotta look in that schemes and tell us about it ;]
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post

i think, if i model the gimmick circuit even close, it would fail because of my envelopes
the envelope should be perfect (i mean, the bipolar thing about it) because it *think* there might be a HP filter in there, and you know what a HP filter does ;]
that's only a guess, not sure
tho, envelopes got to be perfect anyway
i might try to think of something, remember my mesurements on the cutoff freq at different knob settings, that's gotta give a clue about the bipolarity of the envelope
looking at the schematics, it says something like 10% so there is -10% DC added to the envelope
but that looks to me like a rough drawing there, so gotta be verified, tested
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post

I thought this was interesting.

http://media.createdigitalmedia.net/cdm ... s_back.jpg

Read the last bullet point under SID. The guy at Plogue (David Viens) put massive amounts of work into getting a zillion little things perfect on seven different chips. Oscs, filters, syncing, etc.

He modeled the oscs and the filters and tested them against tons of samples and tunes. Still, he ended up with a switch to let you decide (in just a couple cases on the SID) whether you wanted a modeled or sampled version of the waveform.

http://createdigitalmusic.com/2009/01/1 ... from-namm/

We have it way easier, in part because of the difference between two 303s. In the SID world, there are tons of chip tunes that depend precisely on the sound of the chip. People manipulate the parameters on those chips in all kinds of weird ways.

All these years later, I still remember coding a 6502 vertical blank interrupt on an Atari 800 to get the envelope I wanted on the POKEY chip. :-)
Swing is the difference between a drum machine and a sex machine.

Post

Robin from www.rs-met.com wrote:btw.: how do you guys handle the bipolarity of the 303s filter envelope? i have my way doing it and will probably also document that soon. but i'd be curious what your takes on this point are.
usually the envelopes are realized with 1-pole LP filters. it was pointed that this is not the case with tb-303. it can be seen from the schematics that the envelope goes thru antilog (exponential) amp. so lets say that env is that usual envelope (realized with 1-pole filters - exponential decay).
i would handle it like this:
2^((env-0.5)*envAmt)

Post

kunn wrote: usually the envelopes are realized with 1-pole LP filters. it was pointed that this is not the case with tb-303. it can be seen from the schematics that the envelope goes thru antilog (exponential) amp.
thanks for that clarification. unfortunately, i don't have enough EE background to read such things from circuit diagrams. is this also the case for the amplitude envelope?
so lets say that env is that usual envelope (realized with 1-pole filters - exponential decay).
i would handle it like this:
2^((env-0.5)*envAmt)
this must really be it! i could closely fit a 303 filter-sweep via passing an RC-generated envelope through this function, as can be seen here:

Image

...so, with this formula, we would not only account for the bipolarity but also for the non-exponential shape. :D although, i had to adjust the offset from 0.5 to something like 1/2.6
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

So Robin, you're saying you can fit the normal (not accented) 303 filter drop that happens during the note, right?

Here's the thought that keeps haunting me, which I alluded to last night. Every time I think about the filter drop, I think of a capacitor discharging because of the discussion of increasing cutoff on successive accented notes.

So what I'm wondering is whether at high tempos, that increasing cutoff quirk is magnified, because the capacitor hasn't discharged as much when the next note starts. Does the 303 just start from where it is and add voltage to the capacitor? Or does it try to dump all the charge and fail to empty it all out? (Note: I'm not a EE either.)

I think what I'm going to try to do, if I use this graph, is not go from X (time) to Y (cutoff), but have a way to get to Y from Y-1 (the previous cutoff). I don't want to have to keep track of where I am along the curve. I want to go from where I was last frame to where I should be this frame just by inspection of my current state.
Last edited by mistertoast on Tue Sep 22, 2009 4:19 pm, edited 1 time in total.
Swing is the difference between a drum machine and a sex machine.

Post

Robin from www.rs-met.com wrote: Image

...so, with this formula, we would not only account for the bipolarity but also for the non-exponential shape. :D although, i had to adjust the offset from 0.5 to something like 1/2.6
ok, just by looking at this, it looks quite like the curve i measured!
now, how can you make this "RC" work the same on any sampling rate? i guess it's kind of like filters?
i mean, if i set some time parameter, and it falls to some low value (it theoriticaly can't fall to zero ever, but anyway) i need the same effect at different sampling rate too

ideas?

report: square wave != tanh(HPF(saw))
tho, it was interesting..
so, square wave = tanh(saw+offset) .. or another tanh() similar clipper
anyway, i will probably replace the tanh() with something similar, because of the CPU usage ;]
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post

well, not sure what i'm doing exactly but i did some tests in mIRC (ploting the thing there

so, i did this kind of RC thing, where it just multiplies it's last output by a coefficient (which is normaly less than 1.0 and more than 0)
to start the whole thing, i set the previous output variable to 1.0

this gives probably an exponential curve (it looks like one)

i tested ploting it twice, but the second time, i process 2 samples, and plot only one of them (as if i've oversampled it x2) .. and i use another coefficient
i called the first one "rc1" (not oversampled) and the second one "rc2" (oversampled by 2)
it seems that no matter what the coefficient is, the curve looks the same (only stretched in time)
so, the two functions match pretty well (at least visualy) with these combinations of coefficients:

rc1 = 0.8
rc2 = 0.9

rc1 = 0.9
rc2 = 0.95

rc1 = 0.95
rc2 = 0.975

rc1 = 0.5
rc2 = 0.75

so it kind of looks simple, just need to think of the formula (based on sampling rate, or omega, or somethin..)
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”