FOF style synthesis
Apparently the Access Virus Ti utilizes very uncommon oscillators known as the graintable and formant oscillators. I did a ton of research and couldn‘t find any vst that gives me what I want so I thought I could do my own.
The underlying synthesis type seems to be FOF synthesis. Csound has an implementation of fof but I could not find any implementation for max. Could someone point me in the right direction please?
hey,
try this:
https://forum.ircam.fr/projects/detail/max-sound-box/
and let me know how you get on. i'm struggling with it myself at the moment
the fof and fob externals once were given up because they said "use paf instead, it´s better"
there are still people working with the chant objects and fof.
you can implement that in gen~:
https://ccrma.stanford.edu/~mjolsen/220a/fp.html
i tried yesterday(for only 15mins) and failed, but it was fun... and using MC objects gets you many voices pretty quickly:
Yeah I thought that Stanford guy you linked had one of the clearest essays on the topic. Man they can be hard to read.
Nice patch!
Has anyone gotten closer to building a graintable oscillator?
Wavetable and granular oscillators are variations on looping a tiny sample. What's the definition of graintable?
I had been asking that myself too. The virus ti has oscillators called graintable oscillators. I already searched for hours and came to the conclusion that it must have something to do with fof style synthesis, wavetables and a granular behavior of the osc scrolling through the wavetable. Could still be wrong though.
The sounds achieved with the graintables by the virus ti are not doable with any other synth afaik and as far as I've tried.
Ok well if your goal is to make music then just download a free wavetable synth, a free granular synth and a free formant filter. And muck about with them. Resample the output from one into the other etc.
If your goal is to develop a software emulation of a specific synth... You'd have to find some sort of schematic for the Virus TI I guess. Figure out exactly what the signal chain is.
Can you send me a link to a Virus graintable sound that you think is not achievable otherwise please? I'd like to hear it.
The "glassy/liquid" random sounding stabs that come in very prominent at 1:46
Spectra Sonics - Planet Species
My goal is to be able to use this sound in my music without a virus ti. So I'll try to get this done with max. However I have no idea where to get the schematics of the virus ti...
Btw, the virus is a virtual analog synth. Schematics won't help much....you'd need to disassemble the firmware to know whats really going on.
From the manual:
"The remaining oscillator modes all make use of a new technology for the Virus TI, called Grain Table. The basic idea behind this technology, is to take the existing wavetables, and apply similar techniques as those used in some granular sampling and pitch-shifting algorithms to open up a whole new world of possibilities. Each of the two main types: Grain Table and Formant Table are presented in both Simple and Complex formats. In each case, the Simple mode offers fewer parameters, and a higher polyphony than Complex, with the values of parameters common to each mode remaining constant.
It’s important to note that the characteristics of the Grain Table and Formant Table oscillators are quite different to those of traditional “granular” sampling/synthesis techniques, which tend to be associ- ated with other-worldly “clouds” of sound. In the Virus TI, we have instead employed the technology to achieve a very musical result which should prove every bit as useful as the other oscillator types in all manner of musical projects."
Or at least a detailed enough description of how the different parts of the synth interact in broad strokes. But I reckon you can pretty much make any sound any which way. Can anyone else jump in and suggest how that sound might have been constructed?
Here's my attempt. I made simple additive bell tones, drenched them in reverb and used an arpeggiator to trigger them. I resampled those tones with granular and wavetable. Tried to get some of those buzzier/chirpier bits by varying the grain length and trying audio rate looping.
I think that sound is so intense because of the reverb and the layering and the stereo imaging and the fact that there's a lot of inharmonic partials to each noise. A really clean digital delay is at work there too. Also it sounds like there's a filter picking out different harmonics as it sweeps up and down.
You created a nice sound there. Intriguing sounding. But its far away from what I'm trying to achieve. I tried multiple synths. A good way to start is a saw wave with a high resonant bandpass 24db/oct filter with a randomly controlled frequency cutoff and a very short ping pong delay with reverb. But still far away. There is something weird with that original sound...it's like there was a phasor on it with an env linked to the cutoff. But as I said, the virus really does something that I do not understand and that about 5 people I came across were aware of this fact. Thats what makes it so interesting.
In this video the effect of the special oscillators can be heard quite prominent:
You might want to look at a couple of examples in the gen~ examples folder: gen~.ola.pulse.maxpat, and gen~.modfm.maxpat.
I don't know if the algorithm is exactly the same (not really clear from the description above what the graintable algorithm is), but at least similar in principle to the FOF/granular approach to crerating oscillators.
Both can get toward some pretty acid sounds.
look at a couple of examples in the gen~ examples folder: gen~.ola.pulse.maxpat
ha, it's the BB-8 sound!
Well....it even more off. Listen to the spectrasonics track I posted.I'm sorry, but its definitely not the BB sound. The amp envelope is like the BB sound...short impulses. But the timbre is quite different. It feels more spectral and it has a tail that kinda "wobbles" through different frequencies....
YOU ARE THE ONE who has a 'tail that kinda "wobbles"'! 😜 HAAA! sorry! i couldn't resist. just joking of course 😅
...and my sincere apologies: i didn't mean to make a 'serious' comparison to BB-8, it was just a startlingly humorous similarity to me so i posted some hasty randomness... to get back on topic, though, i think you should have a look at the other example that Graham mentioned: "gen~.modfm.maxpat"
and then put that through the moog-filter example, plus maybe some chorus effect, and it'll start getting you close to what i hear in the Virus tutorial vid.
My goal is to be able to use this sound in my music without a virus ti.
at some point, you just have to dive in and try things yourself, no one else is going to be as interested in finding this specific of a sound - the Virus video also uses sounds involving other wavetables that have nothing to do with formant/FOF synths so there's quite a bit being referred to here...(and the Spectra Sonics involves trance music which you are not allowed(by the laws of the universe) to use MaxMSP for 😇 so i can't help you with that sound, such blasphemy would be sacreligious and unholy😱 ...just joking again, but ya, i don't like trance music, so i thank you most of all for leaving a timestamp to save me from some serious pain🙉).
Yeah, that pulsar has a very BB-8 feel -- add something like a flanger-chorus and it would get even closer :-)
I listened to the spectrasonics track at 1:46 for a bit. It's not super easy to pinpoint the sound in all the delays and spatializations and so forth, but to me it sounds like a wavetable oscillator with a few formants (could be FM'd or could be just scanning through wavetables that have those formants), and with some parameter being driven by a sample & hold. I can imagine being able to achieve something like that via a granular method, basically being really precise about lining up grains to create more complex waveforms. You could get there by building on the scheduling parts of gen~.ola.pulsar and but replacing the enveloped waveform with a (possibly enveloped?) wavetable lookup.
I really like the BB8 sound though ;-)
Right, the tutorial vid makes it a bit clearer, and it does seem like this is really a bunch of grains in periodic series where each grain reads from a wavetable, but you have some control over squishing the grain length as a duty cycle ratio of the inter-onset period (for the formant shift). Probably enveloped, possibly also layered in octaves or other harmonics?
All the above is doable in gen~.
Give credit where credit is due! Right @Raja the resident alien! Nice work on the BB8 sound. Good accurate work
Luckily I had a talk with someone who already reverse engineered the oscillator algorithm I'm trying to recreate here. This is what he told me:
"Remember that a "grain" is a short burst of sound - almost like a very, very short pluck synth, only a few ms long. Playing a single note on a granular synth will cause hundreds of these little plucks to be produced in a continuous stream. It's important to understand that granular synths have two different "pitch" controls. One is the grain density: the rate at which new grains are produced. For example, if the grain density is 440 Hz, then 440 new grains will be produced per second. The other pitch control is "grain pitch" and it refers to the frequency of the waveform inside each grain. These two controls are totally independent.
When grain density is high enough (above roughly 30 Hz) the sensation of pitch is created by grain density. For example, if grain density is 440 Hz, the resulting sound will appear to have a pitch of A4, regardless of what the grain pitch is set to. So what does the grain pitch do? Simply put, it controls the formants. For example, if each grain has a grain pitch of 880 Hz, then each grain will consist of a short burst of 880 Hz oscillation. This will create a formant at A5, regardless of what the pitch (grain density is). So let's say for example the density is 440 and the grain pitch is 880. The resulting sound will have a pitch of A4 and a formant one octave above, at A5. This is assuming that the waveform being used in the grains is a simple sine wave. If a more complex waveform is used, then a complex formant shape will be created, not just a single formant. But no matter what wavetable you use, adjusting the grain pitch will always cause the formants to be adjusted by the same amount. For example, if you raise the grain pitch by an octave, then all the formants will go up by an octave. The pitch will not change. It's a lot like oscillator hard sync: changing the pitch of the slave oscillator does not change the pitch of the resulting sound, it only moves the formants around. Pitch is controlled by the master oscillator. Grain density is like the master oscillator, while grain pitch is like the slave oscillator. (Yes, I know I am going to be canceled any moment now for using that terminology).
Ok, now we are in a position to understand what is happening with the "F-shift" control on the Virus. Basically F-shift controls the grain pitch. It causes the formants to go up and down. In the grain complex mode, the formants are also keytracked to the pitch, while in grain complex mode the formants are not keytracked (this is the only difference between these modes).
Now the F-spread function was a little trickier to figure out but here's what I believe is going on. When F-spread is at zero, every grain in the stream is exactly the same as every other grain. As F-spread increases, the grains begin to separate into a pattern of alternating grains. One grain is pitched up, the next grain is pitched down, and repeat. This causes the formants to go up and down simultaneously. This also explains why the oscillator sounds like it drops an octave when F-spread is activated.
Note that there is a lot more involved in reproducing these oscillators, but this is the basics. In particular, you have to fine-tune the grain envelopes, which have a subtle effect on the spectrum."
My question is: is this doable with max4live? As I feel like I'd need a lot of low level control. I need to make sure that each grain contains one cycle of the waveform. I need to be able to control the rate at which a grain is produced and I need to control the pitch of each grain. And I need to have two sets of grains where I can control the pitch individually.
"there are still people working with the chant objects and fof."
aren´t [fof~] and [fob~] max v3 and 68k only?
"Give credit where credit is due!" -- OK, Raja performed a patcher I wrote many years back based on a design from Curtis Roads' book Microsound. I highly recommend that book for you, it clarifies exactly what is going on here, and has wonderful detail about many other fascinating things in the microsonic scale. https://mitpress.mit.edu/books/microsound
From the description above of the Virus, it is simpler than I thought, and basically a normal implementation of granular synthesis using table-lookup for the grain content. Roads' book goes into good detail about the relationships between grain period and grain length for frequency and formant perception, as well as the important effects envelopes have on the spectrum. (It is indeed related to hard-sync, if you have an oscillator that doesn't cycle.)
The thing that makes it a little different perhaps is this alternating of two grain pitches (the "F-spread" factor) -- perhaps a particular subset of Xenakis' sieves if you want to look at it that way. Roads also talks about this kind of thing in his book.
To the final question, absolutely this is possible in gen~. Independent control of sequencing/scheduling ("density"), grain duration, grain envelope, and the content of the grain (source, pitch, pan, amplitude etc.) are demonstrated in the gen~.ola.granular.maxpat and gen~.ola.pulsar.maxpat examples included with Max. It should be pretty easy to adapt these.
A really important thing left unclear in that description above is whether the grains can overlap (i.e., if the scheduling period ("density") is never longer than the grain period ("formant")). If they don't, the algorithm is even simpler, and you can look at the gen~.pulsar.maxpat as a starting point.
What's also left unclear in that description is what envelopes are used. I don't know if the Virus gives you control over them, but anyway this is Max, you can experiment and find something you like; lots of possible shapes. If your wavetables start from zero-crossings then a rampdown envelope might be fine, and will have more bite than more typical gaussian-like envelopes.
I highly recommend exploring the various possibilities with granular approaches -- there's a vast space here that *still* hasn't been fully adopted in mainstream synthesis worlds.
Graham
haha! I would have thought you would love trance music with a name like raja the resident alien!
forgive my newbiness... what's that x/y user interface object in your bb8 patch?
what's that ... in your bb8 patch?
hehehehe...😂 i think this has been the misunderstanding: it's not my BB8 patch, i was just posting a screenshot going off of Graham's recommendation(right before my post about BB8) to check out the standard-included gen~ example file he created called, "gen~.ola.pulsar.maxpat" which can be found if you go in Max's help menu, and look in the Examples folder:
Examples->gen->gen~.ola.pulsar.maxpat
the x/y user-interface is a jsui that i think Graham created just for that helpfile... y'all should check it out :) and he also mentioned "gen~.modfm.maxpat" (don't mind me, i posted nothing of importance in this thread, but y'all should follow Graham's advice) 🍻
I would have thought you would love trance music with a name like raja the resident alien!
nah, not for me, i've been into Johnny Cash these days 😁🤠
Carrying on to ask here instead of creating a new thread:
How do I hardsync 2 oscillators? In gen
Yeah, that's something I've been wanting to do for a while. It sounds simple in theory -- just resetting the phase of osc1 to zero when osc2 completes a cycle -- but turns out to be pretty tricky.
Naive version: Assuming you're driving osc1 with a [phasor], you can reset the phasor by sending a trigger (any nonzero impulse) to its 2nd inlet. If you're driving osc2 with a phasor, you can get the cycle complete trigger by sending [phasor] -> [delta] -> [abs] -> [> 0.5].
But... this isn't really ideal, for a few reasons.
- You might not have direct access to the osc1's phasor (it might be externally driven). Not a problem: you can shift the phase of a phasor at any time using [- ]->[wrap 0 1]. The 2nd inlet to the [- ] is the phase offset. When a sync is triggered, [latch] the current input phase and send that to the [- ] 2nd input. Presto synco.
- If you don't have access to osc2's driving phasor you can assume (hope) that it has exactly one rising zero crossing per cycle (true of sine and also *probably* saw, triangle, pulse etc.). Get that trigger by osc2 -> [> 0] -> [change] -> [> 0].
- The ideal sync point should be subsample accurate as it won't actually fall exactly on a sample frame but will actually be somewhere *between* two frames. Which means, we shouldn't reset to phase=0, but some number very close to zero. Using the latch/-/wrap method above lets us do that, the only trick is to compute exactly what that "close to zero" point should be. Hint: it's an interpolation between the current phase and the previous frame's phase. The interpolation factor here is the sub-sample location. It depends on knowing where exactly between frames the zerocrossing actually happened. That can be inferred from the slope and crossing of osc2: by linear approximation. If osc2 was a zero-crossing you can use its current value divided by its current + previous value to get this subsample location.
There is still a problem that you will very likely produce aliasing with hardsync; first because it will introduce sharp jumps in the waveform as you suddenly cut back to zero or near-zero, and possibly second because of intermodulation frequencies between the two oscs (I think).
- The hard jumps could be minimized by some kind of smoothing filter but there will always be some spectral tradeoffs. Depending on what the phasor is driving, it *might* work to apply this to the driving phasor's phase offset (the bit that went into the [- ]), rather than the output waveform itself. One of the better solutions might be using a BLEP waveform to replace steps. This requires a bit of lookahead and is a bit fiddly (especially when sync triggers happen faster than the BLEP table length -- probably easier to just disallow that if the BLEP is short enough), but at least the lookahead/blep size is a constant.
- I don't know about the intermodulation stuff off the top of my head, but at a rough guess you might consider that breaking a waveform in half will double all the frequencies, and so on. As sync points fall in different ratios of the original wave you might get upper and lower sidebands. It's very related to formant synthesis. If sidebands are somewhat predictable from the incoming phasor frequencies you might be able to autotune an antialiasing filter to combat it.
Some "softsync" methods may be worth looking into, like preventing sync points if the step size would be too large, or using phase reversal rather than reset.
On the other hand, the more you tame the sync, the more chance you have of losing the "hard"ness of it! Finding the sweet spot might take a bit of work. Having some reference recordings of analogue hardsync (or actual analog hardware) to compare to would be a good idea.
Graham
.. here's the subsample accurate sync point part of the above:
Cheesus....what a hassle! Thank you for sharing that patch Graham!
The reason why I'm asking for a hardsync:
It seems I found out how the granular oscillator really works. There are two oscillators, a and b. A with frequency x and b with frequency y. There is a certain harmonic offset between frequency x and y. These two oscillators are added together and "kinda" hardsynced to another oscillator - the carrier - which is multiplied with the sum of a and b. So a and b get phase reset when the carrier completes a cycle and they also get "enveloped" by the carrier which gives the impression of a grain.
This actually seems to be the whole thing. Which is exactly what the grainlet formant oscillator of mutable instruments eurorack module plaits does.
One difference to the virus though, the virus also plays wavetables. Not only sines. Still need to figure out how to implement a wavetable oscillator in this manner but that seems to be it. I actually don't know how hard my sync needs to be.
So after all it is just basic synchronous granular synthesis with no grain overlap and arbitrary table-based grain content.
You can adapt the hardsync patch I posted above, but replace the carrier phasor with a frequency-dependent accumulator ([+=] or [accum]) and use that to [sample] a wavetable and a window function with @boundmode ignore to ensure it is silent outside the window duration. You might want a conditional in there to ensure the accumultor won't reset unless it has already completed the window (a [latch] conditional on phase > 1). I.e. to prevent the envelope from retriggering until the window is done.
Graham
Exactly, it seems to be pretty straight forward and not that hard to implement.
I'm wondering though. If I were to go with a "overlapping" grain design, I'd need a different design to play back multiple grains at the same time so 1 audio stream would be not enough.
I would need to create a structure that holds a grain of audio that I can then polyphonically play back but with shifted start end end points...pretty much a "regular" granulator thing. How would one go to implement that...preferably in gen~?
I think I'd get one voice working. Then make duplicates of that for multiple grain voices, and distribute the new grain triggers in a round-robin manner to each voice. For example, using a [counter 4] and [selector 4] to rotate the triggers between each voice.
So I'm now pretty much done with understanding how I'd implement this and I've already started and made some progress.
However there is one last thing I'm not sure how to do. Its the formant shift and formant spread functionality. Imagine a Sine wave. If you turn up formant spread you get a signal like this:
[sine(detuneUP)][sine(detuneDown)][sine(detuneUP)][sine(detuneDown)]
the more "spread" is cranked the further the voices are tuned away from each other. every sine in a [] contains one cycle.
I think the best way to do this would be by capturing a wave cycle of each stream in a buffer and then construct the final signal stream as a consecutively row of these buffers.
Other suggestions?
use 2 parallel modulators and windowing?
Could you explain that in detail?
So you would use only one osc which will get affected by two alternating modulators and multiplied by another signal that does the windowing? Will the phase be stable?
i dont know enough about fof and gen to post an example, but to me it sounds like you would just apply 2 formants and alternate between them.