Open303 - open source 303 emulation project - collaborators wanted

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

Post

The tb-303 has six bits of R2R DAC. So at 1v/o this means we have 64 notes / 12 = 5.333~ octaves.

So the maximum output is going to be near 5.333v. This produces 659 Hz.

Taking the tuning ranges into account I'm sure you can probably go over 1k, but not much further.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

Wow, I only occasionally visit this forum (though I really should more) but I just had the strangest flashback to see this thread again. I was reading this back at the start of my C++ DSP journey like 10 years ago! Lol. Got loads of great info from it tho, released a 303,808,909 thing off the back of this thread and now have a business doing audio dev - so yeah, I guess what I’m trying to say is thanks everyone!

Post

Well if this is going to stall because of time issues, I'll be willing to help out. I don't have any audio specific coding skills, but I know C/C++ relatively well, and have a degree in electronic engineering. My biggest problem is that I might not be able to dedicate time to it consistently.

PM me if it looks like I can be of help.

Post

aciddose wrote: Thu Jun 27, 2019 6:54 pm Ultimately the most important factor at play is the smooth vs. hard edge. The ramp reset edge is sharp but the other edge of the pulse is smooth and frequency dependent. The sh-09 for example uses a pulse shaper with 20x (680k/33k = 20.60606~) gain to achieve the same effect. Since the majority of the spectra is a single easy-to-produce "sharp" edge it means we don't need to worry so much about bandwidth for the other "soft" edge.
The problem here is that if you would like to BLEP it directly, then the smooth edge from the low amplification is really THE problem. The smooth edge is audibly important, because it means that the spectrum looks like a pulse at low frequencies, but more and more like a saw at higher frequencies. Where this transition happens depends on the oscillator pitch, but for typical 303 pitch it's very much relevant in the audible range. Because the transition point varies wildly, just using a smoother BLEP for the soft edge is "less than satisfactory" although I do wonder if you could fake it with a short low-order polynomial segment.

It's been a while since I played with this, but if I recall correctly, the whole thing (also the PW variatiation) takes some time to reach a steady state every time the pitch changes, even without any glide. In fact, I wonder if it's audibly more important when not gliding. Running a simulation of the whole shaper is hardly a problem, but then this screws up any band-limiting even for the hard edge, even if the input is a perfect BLEP saw or something.

Post

A low order polynomial segment (either ^1 or ^2) does the job nicely. It's then possible to apply ^2 to the whole thing with a 2x oversample to approximate the logarithmic RC curves more accurately. That gets well within the bounds of "close enough nobody would ever hear the difference."

I find the spectra from a simple flat segment works well enough but you can definitely see the difference in harmonic falloff compared to a diode/transistor curve. Honestly the naive opamp model (all linear segments) works 100% fine in most cases.

The shape is a flat-edged pulse on both sides at higher frequencies. The width/slope of the smooth edge is frequency dependent, so at 10 Hz it'll be 100x as wide as 1000 Hz. The effect from the capacitor can be modeled by defining the linear/low-order "soft" edge segment based upon a lossy-integrator. It's fairly minor though.

That's the whole point of the spice netlist. It lets you look at exactly what goes on.

From the netlist with the .step function uncommented:

Image


One way to handle the lossy-integrator-like attack is to simply apply a lossy-integrator. The only issue would be at higher frequencies where the sharp x ... inf cutoff frequency modulation would produce sidebands... but by that point the filter can be taking no effect by blending between the filtered and unfiltered pulses from a naive sharp-edged source.

Being 100% accurate requires switched filter + switched shaper + linear segments + blep ^0, ^1, and possibly ^2, but it is certainly possible.

I'd aim for a less accurate wavetable based solution to start with... so the pulse sharpness would depend on the initial note or with a more complex wavetable oscillator the tables could blend/interpolate in multiple dimensions during a slide. That's reasonably trivial... although it wouldn't cover weird cases like frequency modulation across five octaves on a per-cycle basis... that's a bit of a stretch anyway.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

To test this I simply applied a 0v 3v CV frequency pulse at 400ms interval (190ms width).

This gives you a picture of a fairly wide frequency range. Given a glide the effect would be less noticeable of course, yes.

Code: Select all

* tb-303 oscillator + exponential current source + pulse waveshaper

* 0v CV Hz = 440 * (2^(1/12))^(3 - 12*5) = 16.35 Hz
* fit two cycles + third edge = 2 * 1000 (ms) / 16.35 = 122.32 ms
.tran 0 800m 0 20u

* ideally this would be made to run with .step to render the output in various semitones or octaves.
* unfortunately i'm not aware of any function to generate parameterized filenames for the .wave function.
* you'll need to manually adjust the parameter and filenames for output (0v = pulse0, 1v = pulse1, 2v = pulse2, ...)
;.step param CV 0 5 1
.wave z:\pulse.wav 16 48.0K V(o_p)
.wave z:\ramp.wav 16 48.0K V(o_r)

V1 vp 0 DC 12
V2 vh 0 DC 5.333

* cv input
;VIN1 cvin 0 wavefile=z:/dont_mess_up_bassline.wav chan=0
VG cvin 0 PULSE(0 3 0 1u 1u 190m 400m 0)
;B1 cvb 0 V=V(cvin)*(128/12) - 4.7062 - 1
B1 cvb 0 V=V(cvin) - 4.7062

* middle c = 440 * (2^(1/12))^3 = ~523.25113 Hz
* -4.7xxx trimmed for ~523 Hz at 5v CV input
;.param CV 3
;V4 cvb 0 DC {-4.7062 + CV}

* exponential current source
* this is a cheap pnp-buffered single npn transistor which is totally inaccurate
* the real circuit uses stabilization via a matched NPN and an opamp for feedback
* as far as accuracy of the oscillator core however it should have no notable effect
R77 cvb ii 220k
R7 cv ii 220k
* scale adjustment (1v/octave)
R8 ii 0 4040
R9 vp ib 100k
Q6 0 ii ib 2N3906
Q7 ir ib 0 2N3904
R88 cp ir 2.2k

* scr
* P a = anode
* N n = -gate
* P p = gate
* N k = cathode
Q27 sa sn vp 2N3906
D25 sa sp    1N4148
Q25 sn sp cp 2N3904
Q24 sp sp sr 2N3904
R101 sr vh   10k

* capacitor
.ic V(cp) 5.1
C3 vp cp 10n

* buffer
* MPF104 is the wrong NJFET for the buffer,
* the FET Vto and other properties affect offset and clipping (top of ramp)
* which in turn affect pulsewidth for the pulse waveshaper
JQ1 vp cp ramp MPF104
R1 ramp 0 10k

* shaper input filter
R2 ramp pl_in 100k
C1 ramp rhp 10n
R3 rhp pl_in 10k

* pulse shaper
* R5 & R4 will adjust pulse width, C2 tone/"curve" for low notes
* you can find lots of discussion about trimming the width
* in various places online (for 303 based clones)
R5 vp pl_i 22k
C2 pl_i 0 1u
Q2 pulse pl_in pl_i 2N3906
R4 vh pulse 10k

* highpass and 1/5 scaling for the outputs
* ramp
R90 ramp d_r 1000k
C90 d_r o_r 100n
R91 o_r 0 220k
* pulse
R80 pulse d_p 1000k
C80 d_p o_p 100n
R81 o_p 0 220k

* models
.MODEL 1N4148 D (IS=14.2P RS=4.2 N=1.7 BV=75 IBV=5U CJO=1.74P VJ=0.75 M=0.333 TT=4.32N)
.MODEL 2N3904 NPN(IS=6.73E-15 BF=416.4 VAF=74.03 IKF=0.06678 ISE=6.73E-15 NE=1.259 BR=0.7374 RB=10 RC=1 CJE=4.5E-12 TF=3.012E-10 XTF=2 VTF=4 ITF=0.4 CJC=3.638E-12 MJC=0.3085 TR=2.395E-7 XTB=1.5 KF=9E-16 )
.MODEL 2N3906 PNP(IS=4E-14 BF=400 VAF=50 IKF=0.02 ISE=7E-15 NE=1.16 BR=7.5 RC=2.4 CJE=6.3E-12 VJE=0.75 TF=5E-10 CJC=5.8E-12 VJC=0.75 TR=2.3E-8 VJS=0.75 XTB=1.5 KF=6E-16 )
* the MPF104 model has been trimmed with Vto=-1.45 to get what "looks reasonable"
* A better JFET model would probably be the best solution here
.MODEL MPF104 NJF(Beta=488.9u Betatce=-.5 Rd=1 Rs=1 Lambda=3.83m Vto=-1.45 Vtotc=-2.5m Is=181.3f Isr=1.747p N=1 Nr=2 Xti=3 Alpha=2.543u Vk=152.2 Cgd=4p M=.3114 Pb=.5 Fc=.5 Cgs=4.627p Kf=4.284E-18 Af=1)
.END
Some of the node names a bit nicer here... but that's all personal preference really.

Image

So we can see the width + amplitude is dependent upon the charge of the capacitor in the shaper. This is node "pl_i". I removed the plot of the shaper input because it honestly doesn't provide any useful info... but of course the offset at the input shifts too given the much smaller capacitor there... not in my opinion in any reasonably notable way though.

The effect is quite high frequency with 22k 1u = 1 / (2*pi * 22000 * 1e-6) = 7.2343~ Hz. We already know this is a time constant of approximately 50 ms for 90%.

That said it should add a somewhat audible effect since a few of the initial pulses might be either louder or quieter depending upon the exact phase and frequency before the CV step (frequency jump).

So I agree it's not something to be ignored... but it isn't extremely important. We're talking very short exponential decay width and amplitude "blips" of 50 ms. That's definitely a common technique used in synthesizer presets to get a little initial "pop". "Punchy" would be the word.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

aciddose wrote: Fri Jun 28, 2019 9:57 pm So I agree it's not something to be ignored... but it isn't extremely important. We're talking very short exponential decay width and amplitude "blips" of 50 ms. That's definitely a common technique used in synthesizer presets to get a little initial "pop". "Punchy" would be the word.
The VCF has enough HP poles in the loop to have some low-frequency resonance, which the low-frequency content of the transients is going to excite. This then results in DC offset modulation within the non-linear filter, potentially making it much more audible after the VCF.

Partially off-topic rant follows: I think one of the major problems with many VA synthesizers is that they tend to stop processing voices after the VCA closes. Over the years, I've become more and more convince that this is a terrible thing to do. This is obviously to save CPU, but it means that you lose all the fun interplay between notes that you'd get in a real analog, especially if there is a lot of DC blocking caps and non-linear stages near saturation... and it kinda prevents some funky ADSR abuse as well.

Post

mystran wrote: Sat Jun 29, 2019 4:43 am Partially off-topic rant follows: I think one of the major problems with many VA synthesizers is that they tend to stop processing voices after the VCA closes. Over the years, I've become more and more convince that this is a terrible thing to do. This is obviously to save CPU, but it means that you lose all the fun interplay between notes that you'd get in a real analog, especially if there is a lot of DC blocking caps and non-linear stages near saturation... and it kinda prevents some funky ADSR abuse as well.
Yep. A simple solution is to only stop processing during total silence. So if a synth part has ended in a track, the plug-in won't waste CPU cycles producing no output whatsoever. On the other hand rests between notes are unaffected by this, so nothing is lost in terms of realism.

Richard
Synapse Audio Software - www.synapse-audio.com

Post

It's also possible as an optimization to count the time you've been idle... so long as there are only single charge/current flows unidirectional such as the capacitor in an envelope it means you can recompute the exact voltage/position when you start processing again. For a simple oscillator this also works fine as it's nothing but a phase increment... only fails when you get into more complex stuff like noise/chaos.

The same applies to any identical capacitors regardless of if they're in the audio path or part of modulation. So it only really becomes necessary to process full voices when you have some complex stuff going on like leakage at zero cv or similar. The exp/log function calls are very quickly made up for when you idle for 100s of samples or more so usually this means cutting total cost by very large amounts.

Yes though... it seems hardly any authors take continuous operation into account. It's a different way of thinking about the problem, where in analog circuits we're really dealing in terms of old mechanical systems like clocks, hydraulics and such. That's the analog != digital conundrum, since problems are so much easier to solve in the digital way we can expect the majority of solutions will be such.

The "funky ADSR" long attack extra long release with quick decay is one of my favorite tricks. Instant chaos-like modulation on an analog. That's definitely a function I'd never fail to get working on a synthesizer. These elements of continuous operation are what create the unique "evolving" effects like you see in an orchestra. I think without a doubt I'd place that concept as #1 on the list of important "analog" properties.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

aciddose wrote: Sat Jun 29, 2019 1:54 pm It's also possible as an optimization to count the time you've been idle... so long as there are only single charge/current flows unidirectional such as the capacitor in an envelope it means you can recompute the exact voltage/position when you start processing again. For a simple oscillator this also works fine as it's nothing but a phase increment... only fails when you get into more complex stuff like noise/chaos.
It doesn't take very much to break such optimisations. Modulated PWM or sync oscillator (or even something like the 303 pulse shaper) running into a DC blocker is already essentially impossible to predict without processing the near-past modulation (eg. a couple of DC blocker time-constants). Feed the result into a non-linear VCF feeding into another DC blocker feeding into a non-linear VCA... you're basically screwed, even before you start worrying what happens to silent voices when the "knobs" are turned by the user. That's really not a very complicated patch either, it only starts getting worse from there.

Sooner or later you just end up in a situation where you either (1) try to guess some "good enough" starting state for new voice (and then spend your time trying to troubleshoot the corner cases; this being the classic approach) or (2) run the whole thing, every voice, all the time (and have your users complain about it; there's plenty of complaints about this in some of the Roland Cloud threads for example, because apparently at least some of the recent Roland's emulations do the right thing, no personal experience though).
aciddose wrote: Sat Jun 29, 2019 1:54 pm The "funky ADSR" long attack extra long release with quick decay is one of my favorite tricks.
Yeah, that's exactly what I had in mind.

Post

Also on the actual subject, but related (and probably also mentioned in the thread several times, but let's repeat): in 303, when playing faster patterns the VCF accent circuitry takes several notes to discharge after being triggered, resulting in the notes following an accent having slightly higher cutoff from the remaining accent modulation. When several accents are triggered in a row, the subsequent accents also push the VCF cutoff higher as the accent cap is already partially charged, so it has time to reach a higher voltage. This behaviour is very much tempo dependent (and especially obviously in something fast like full-on Goa), since the faster the tempo, the less time there is for proper discharge.

As far as I can tell, accents can also be triggered during a slide (you hear this in some old tracks). The accent flip-flop being clocked from the slide signal is kinda interesting though, it'd be interesting to measure the actual signals out of the MC to see what the actual signals actually look like, in terms of how the slides are strobed..

edit: oh, found the answer, the slide signal is always strobed on every note! Whether or not a note is a slide only affects whether or not the slide signal stays on for the duration of the note.
Last edited by mystran on Sat Jun 29, 2019 4:44 pm, edited 1 time in total.

Post

That would depend how the pattern data is actually stored which could probably be worked out via dumping the firmware and RAM. I've done this with the M1, Alpha Juno and a few others but sadly disassemblers like IDA aren't able to handle real paging (such as page address wrapping) and only implement a kludge to handle it which fails in most cases of assembly language. Both these systems use a 8080-compatible chip so the 386 disassemblers can almost "work" but it becomes mostly a process of manual disassembly where the tool fights you rather than helping.

Apparently the tb-303 uses a μPD650C-133... so it's just another copycat NEC CPU like all the roland and most other similar gear used at the time. It should be possible to disassemble.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

aciddose wrote: Sat Jun 29, 2019 4:40 pm That would depend how the pattern data is actually stored which could probably be worked out via dumping the firmware and RAM. I've done this with the M1, Alpha Juno and a few others but sadly disassemblers like IDA aren't able to handle real paging (such as page address wrapping) and only implement a kludge to handle it which fails in most cases of assembly language. Both these systems use a 8080-compatible chip so the 386 disassemblers can almost "work" but it becomes mostly a process of manual disassembly where the tool fights you rather than helping.
There's also the question of whether the slide is also strobed on rests... urgh..

Post

Actually the more I look at this, the more I feel like I just don't have a clue WTF should actually be happening in terms of the "finer details" .. :D

edit:

Urgh, so given that the same signal is used as clock for the accent flip-flop, the pitch hex flip-flop and as the slide-switch control signal... one would kinda imagine that the way it has to work is that it goes high on every note, and stays high for slides. This means that the beginning of every note slides for a short moment.

Now the other interesting thing is that according to the service manual (and datasheets), both the accent flip-flop (MC14013B) and the pitch hex flip-flop (MC14174B?) seem to be edge triggered, so even if we have multiple slides, the signal has to go down at some point between the notes. This then means that even if a note is still sliding when it ends, it'll get set to the final pitch before we start sliding to another pitch?

So... the question is, what is the actual timing for the falling edge of the slide signal for (1) notes without slide and (2) notes with slide. Apparently the worst-case clock pulse tWH/tWL for the accent flip-flop (the slower of the two, according to datasheets) could be up to 250ns... but more likely the slide will stay on (for non-sliding notes) for longer and go down (for sliding notes) earlier, because I find it really hard to believe the Roland engineers would try to push it... but how much longer/earlier?

Post

And.. when you finally figure out what the magic words are, Google will find you what you need:
http://sonic-potions.com/Documentation/ ... timing.pdf

Paper claims a pulse of 44us at the beginning of every note... that's about 2 samples at 44.1kHz, so might be border-line significant. When a slide follows a slide, it's pulled low for ~9us, as I predicted just before finding the paper, but that's almost certainly too short to really cause anything interesting except the glide reset to the actual value of the previous note.

The paper also answers pretty much all the other questions one might have about the control signals.

Post Reply

Return to “DSP and Plugin Development”