Roland Supersaw - any idea how the original was done?

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

Music Engineer wrote: Tue Dec 06, 2022 5:28 am Oh - and the forum hides your link, saying:
AUTO-ADMIN: Non-MP3, WAV, OGG, SoundCloud, YouTube, Vimeo, Twitter and Facebook links in this post have been protected automatically. Once the member reaches 5 posts the links will function as normal.
If you, want, you can try sending it to me via private message, then I will post it here (it apparently also gets removed when quoting - IIRC, this wasn't always the case)
This one?
stepvhen wrote: Mon Dec 05, 2022 3:04 am It started from a paper by Kleimola et al. "Phaseshaping Oscillator Algorithms for Musical Sound Synthesis" https://mural.maynoothuniversity.ie/4100/1/SMC2010.pdf. Within they describe a method for generating a hardsync wave (and also a supersaw, sorta, but I dropped that one due to phase bumping). My yass() uses this hardsync, but sets the base frequency so low you won't hear the sync action. This generates each saw needed by multiplying by some factor.

Post

AUTO-ADMIN: Non-MP3, WAV, OGG, SoundCloud, YouTube, Vimeo, Twitter and Facebook links in this post have been protected automatically. Once the member reaches 5 posts the links will function as normal.
Music Engineer wrote: Tue Dec 06, 2022 5:28 am
stepvhen wrote: Mon Dec 05, 2022 3:04 am Apologies for necrobumping this thread with my first post on this forum.
You apologize? Man, if your results are correct (I can't verify them) then you have just posted the ultimate solution to a long standing question, so thanks a lot!
Thanks. I wanted to post something here. From what I could find, this thread is the most comprehensive resource on the topic. All of the links to papers, analog examples, etc were stuff I found myself (before i found this thread, much to my dismay). I hope its worth something, and I haven't been starting at my computer too closely for the last week that I can't judge things right any more.
1. The detune coefficients look to be 5, 16, 28, divided by 256. That is, f * (1 +/- d/256), where f is the fundamental frequency, and d is 5, 16, or 28. [...] These factors also neatly work out to summing to 7, and not just slightly above it (which makes sense, its all balanced). [...] It follows that the next pair of saws to be added (to make 9) would be 41/256, then 55, 70, and 88, etc.
[...] Oh - wait: this summing criterion seems to always hold, no matter what values I choose. For example, using 7,20,25 instead of 5,16,28, I still get 7 as sum (a := d/256):

1 + (1+a*7)+(1-a*7) + (1+a*20)+(1-a*20) + (1+a*25)+(1-a*25) = 7

so this summing criterion doesn't really seem to determine the pattern (...which actually becomes pretty obvious recognizing that (1+x)+(1-x) = 2 for any x).
yeah as long as it matches on either side it will balance out, which may be good for perceived tuning.

(Side note, this produces the same kind of frequency spread as Amplitude Modulation. I wonder if generating a supersaw in the analog domain is easier than once thought. Two ring modulators with very low frequency sine waves as carriers, saw wave as modulator, mixed with the original signal. You'd have to influence the carrier frequencies in a linear relationship with the saw wave though, to get a correct spread across the spectrum... I might try that later with my modular gear but anyway, not practical, but a precedent for what kind of harmonic spectrum this creates).

The coefficients match Adam Szabo's thesis and russel on ghostfact (https://www.ghostfact.com/jp-8000-supersaw/), both linked much earlier in the thread. At maximum detune, Szabo and russel found the following frequencies for the "sidebands", with my integer coefs following:

Code: Select all (#)

Wave   Szabo       russel     stepvhen
1      0.88997686  0.8930     0.89062500
2      0.93711560  0.9390     0.93750000
3      0.98047643  0.9800     0.98046875
4      1.000000    1.0000     1.00000000
5      1.01991221  1.0200     1.01953125
6      1.06216538  1.0640     1.06250000
7      1.10745242  1.1100     1.10937500

Szabo/stepvhen %	russel/stepvhen %
99.92                   100.26
99.95                   100.16
100                     99.95
100                     100
100.03                  100.04
99.96                   100.14
99.82                   100.05
I was unconvinced that it was asymmetrical in the original, and that the designers would have used floating point values. I also assumed there was a margin of error for these measurements. Neither reports on methodology for coming up with those detune amounts, and only provide one set of points for analysis, so we can't confirm one way or another. But since the integer coefficients are so close, I'm currently convinced its how it was done.
So, what's the general rule for the detuning coeffs here? I'm really not very good in that "what number comes next" game.
The distance between 5 and 16 is 11, and between 16 and 28 is 12. Starting with 5 and an increment of 11, increase the increment with every new term. (5+11) = 16, (16+12) = 28, (28+13) = 41, etc. I doubt there is anything special here, other than keeping the coefficients low so they are close to the fundamental, and spaced out so they are away from eachother. I did find a higher number of sidebands started to clash together, and the volume drop was hard to justify without adding a compressor. I think 7 total waves is a sweetspot.
2. I've found a 2nd order RBJ filter (e.g. the stock JSFX in Reaper by Stillwell), with Q of sqrt(2), and cutoff at 2.5*f to be a match, visually at least. I don't have a JP-8000, and all the links to samples are dead by now (if anybody has some of the samples discussed here that they could share, that would be great)
Does this refer to the highpass that is apparently present in the JP-8000 supersaw?
Yes. The waveshape in Adam Szabo's thesis looks to be caused by this kind of highpass. The extra bumps gives a clue to a higher Q on the filter, and I just adjusted the parameters until we had a full return to 0. So if the fundamental is 440, the cutoff would be 1100.

Its just mostly an heuristic based guess though. I can't compare it to any samples currently. But it works and looks right. Given the wave still has the rest of the JP8000 to go through, I'm not too hung up on accuracy here.

Post

mystran wrote: Tue Dec 06, 2022 10:44 am This one? ...
No - I was referring to the link that is apparently supposed to appear at the top of the post but was removed by the forum software due to stepvhen not yet having posted at least 5 posts. This pdf link is visible just fine here, too.

EDIT: yeah - OK - seems I was just confused about how the forum works. It may have been this one after all. All right now. Nevermind.
Last edited by Music Engineer on Wed Dec 07, 2022 11:59 am, edited 4 times in total.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

stepvhen wrote: Tue Dec 06, 2022 4:21 pmThe distance between 5 and 16 is 11, and between 16 and 28 is 12. Starting with 5 and an increment of 11, increase the increment with every new term. (5+11) = 16, (16+12) = 28, (28+13) = 41, etc.
Ah - OK - thanks! Sometimes, I don't see the wood for the trees! :dog:
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

not sure how far this thread progressed in the last 13 years, but i also remember that somewhere it was explained that it was 7 simple, parallel oscillators using the same (exponentially distributed) distance from the base frequency, the closer the louder, and the "more" was made by raising their volume.

and if you want to know more, be careful, because when the secret is uncovered the fun will be over.

just experiment with different frequency ratios and see what happens.

and in case you want to bandlimit, use a basic additive approach to create the waveform, that can save a lot of headache.

Post

Dev of the JP-8000/JP-8080 emulator confirmed that the Supersaw on those synths is detuned naive saws at a high sample rate with a highpass.

https://synthanatomy.com/2026/01/je-808 ... stery.html
Image
Don't do it my way.

Post

OK, here's a screen-grab from that talk, presumably of actual de-compiled code from the original rom:

Image

This code looks a bit weird to me, though I'm only a DSP newbie so hopefully someone can help me figure this out. I'm guessing the "spread" parameter correlates to the "Mix" (CTRL 2) slider while the "detune" parameter is the CTRL 1 slider. But it looks like the "sum" variable is just adding up pitches, which is weird. And then that sum is passed to some mysterious high_pass function? What exactly is this next() function supposed to be outputting? Surely not a raw pcm sample, right? Doesn't a highpass require some sort of state to be passed to it? And what's the point of that saw[] array that just keeps increasing with each next() call? Also what's the deal with that bit shift on the voice_detune? Just casually dividing by 128?? I'm so confused, somebody please help!
Image

Post

NAD wrote: Tue Jan 13, 2026 12:24 pm But it looks like the "sum" variable is just adding up pitches, which is weird. And then that sum is passed to some mysterious high_pass function?
The "sum" variable is adding together all the individual waveforms at a particular time instant and then the result (mix of several saws) is put through a single high-pass together. The state of the high_pass() function is probably kept in global variables.

Post

mystran wrote: Tue Jan 13, 2026 1:10 pm
NAD wrote: Tue Jan 13, 2026 12:24 pm But it looks like the "sum" variable is just adding up pitches, which is weird. And then that sum is passed to some mysterious high_pass function?
The "sum" variable is adding together all the individual waveforms at a particular time instant and then the result (mix of several saws) is put through a single high-pass together. The state of the high_pass() function is probably kept in global variables.
Is the idea that when it reaches the limit of a 24 bit signed integer it wraps around and that's what makes a saw?
Image

Post

Certainly. This way it has the best possible frequency resolution and saves instructions.

Post

Ok I think I get it now. Thank you!
Image

Post

That screenshot should be considered pseudocode not actual code of the emulator. It just showcases the principle of how it works. And, more importantly, the detuning factors.

Post

NAD wrote: Tue Jan 13, 2026 2:07 pm
mystran wrote: Tue Jan 13, 2026 1:10 pm
NAD wrote: Tue Jan 13, 2026 12:24 pm But it looks like the "sum" variable is just adding up pitches, which is weird. And then that sum is passed to some mysterious high_pass function?
The "sum" variable is adding together all the individual waveforms at a particular time instant and then the result (mix of several saws) is put through a single high-pass together. The state of the high_pass() function is probably kept in global variables.
Is the idea that when it reaches the limit of a 24 bit signed integer it wraps around and that's what makes a saw?
No. The saw[i] variables must be less than 24 bits (so they wrap around earlier) or this code doesn't make any sense.

Post

Yeah, sum would overflow if all variables had same length.

Post

I'm still blown away by the work The Usual Suspects did. Im OG trance music fan. That genere was built on JP8000 originally. This "what is a proper supersaw" debate has been going on for decades. (Even this hread is 17 yeas old. 😅) ...and they just ...ended it. ❤️

(Now I kinda wish every dev with a unisono capable synth would add these original coeficients as a detune mode, hihi. 👉👈)
Evovled into noctucat...
http://www.noctucat.com/

Post Reply

Return to “DSP and Plugin Development”