Creating a chorus effect by modulating the levels of partials (sines in additive synth)?

mikejm
 KVRer
 26 posts since 5 Apr, 2017
Creating a chorus effect by modulating the levels of partials (sines in additive synth)?
Razor by Native Instruments is an additive sine wave synth that simulates many effects like chorus by directly modulating the levels of the partials. For example, here you can see the partials being modulated up and down in creating a "chorus" sound:
What equation would be necessary to create such an effect, per partial?
Ie. Given a "rate constant" for the chorus effect, and the frequency or partial number of each sine, with what equation could this be replicated?
Thanks
What equation would be necessary to create such an effect, per partial?
Ie. Given a "rate constant" for the chorus effect, and the frequency or partial number of each sine, with what equation could this be replicated?
Thanks

BertKoor
 KVRAF
 10740 posts since 8 Mar, 2005 from Utrecht, Holland
Re: Creating a chorus effect by modulating the levels of partials (sines in additive synth)?
This is simply modulation of the frequency of sine oscillators.
You want formulas? See
http://www.kvraudio.com/forum/viewtopic ... 9#p7087109
You want formulas? See
http://www.kvraudio.com/forum/viewtopic ... 9#p7087109
We are the KVR collective. Resistance is futile. You will be assimilated.
My MusicCalc is back online!!
My MusicCalc is back online!!

mikejm
 KVRer
 26 posts since 5 Apr, 2017
Re: Creating a chorus effect by modulating the levels of partials (sines in additive synth)?
I'm not sure if I understand or if that is correct.BertKoor wrote:This is simply modulation of the frequency of sine oscillators.
You want formulas? See
http://www.kvraudio.com/forum/viewtopic ... 9#p7087109
According to the visual depiction of the sine wave partials by Razor's display, there is no change in the frequency of any of the partials (xaxis). The only thing it is modulating to create this chorus sound is the amplitude of the partials (yaxis) which is what creates the beating effect of the chorus.
However, the core code behind Razor is incredibly complex and hard to piece out so it is hard for me to figure out how they do this. Modulating frequency (pitch) however does not seem to be part of it at least from what is evident in the animation example I provided.
Any further ideas/thoughts?

mystran
 KVRAF
 5001 posts since 12 Feb, 2006 from Helsinki, Finland
Re: Creating a chorus effect by modulating the levels of partials (sines in additive synth)?
Right.. so we have this fun little equivalence: 2*cos(a)*cos(b) = cos(ab) + cos(a+b)!
So if you amplitude modulate with another frequency (or a set of frequencies), you get sidebands shifted from the carrier frequency. If you do this for all your harmonics, but use modulation frequencies proportional to the frequencies of the harmonics, you get something that very much resembles a chorus effect. I don't know if this is how Razor does it, but it seems like the most likely approach. There is also the complex variant that'll let you shift in one direction only, but for a chorus that would be a lot of extra calculations for little to no practical benefit.
So if you amplitude modulate with another frequency (or a set of frequencies), you get sidebands shifted from the carrier frequency. If you do this for all your harmonics, but use modulation frequencies proportional to the frequencies of the harmonics, you get something that very much resembles a chorus effect. I don't know if this is how Razor does it, but it seems like the most likely approach. There is also the complex variant that'll let you shift in one direction only, but for a chorus that would be a lot of extra calculations for little to no practical benefit.
If you'd like Signaldust to return, please ask Katinka Tuisku to resign.

signalsmith
 KVRer
 7 posts since 5 Jul, 2018
Re: Creating a chorus effect by modulating the levels of partials (sines in additive synth)?
TL;DR: For the simplest possible case (symmetric chorus, single LFO), the modulation for each partial would be:
The full derivation
The exact modulation (amplitude/phase for a given frequency) for a delaybased chorus depends on things like delay lengths, number of voices, LFO shape, and so on. There are lots of details like lower frequencies not being affected as much, or complex frequencyspecific interactions (like the way the 7th partial in your example remains constant in your example).
To emulate those exactly, I'm not sure there's a better/cleaner way than calculating it than directly  i.e. figure out what your chorus's delay times would be at that instant, and just add up various delayed versions of the partial, so your output is
If you want, you can split that into separate sin/cos components, using the rule sin(a+b) = sin(a)cos(b) + cos(a)sin(b), which then lets you calculate an amplitude for your display
(OK, so the delays are upsidedown there and should be negated, but I don't believe that makes a difference to the sound as long as they're all consistent.)
If your chorus's delay lines are weighted, you'd need to add some gain factors to each delayN component, and perhaps an extra "1 + " to output_sin if there's a dry signal.
Frequency changes, and symmetrical delays
In the equations above, that means delay2 = delay1, delay4 = delay3, and so on  which would mean that output_cos comes out as 0 (because sin(delay1*freq) = sin(delay2*freq), etc.), so you can drop all those calculations. You can also drop half the output_sin calculations (because cos(delay1*freq) = cos(delay2*freq), etc.) so you get a 4x speedup overall.
This boils down to exactly the case that @mystran talked about  I don't know how much you see it in actual choruses because you need negative delay (i.e. latency), and it'll make a subtle difference to the sound, but not necessarily a bad one.
This means that the simplest possible case to calculate is for a symmetrical chorus, with a single LFO (driving two delays in opposite directions), and the equations for this are in the TL;DR section at the top. If you have more delay lines (but still symmetrical), you just get more terms:
Other reasons
This is a reasonable explanation for not having frequency shifts, but it's also possible that frequencyshifts are there, but not shown in the visualisation. This might be for simplicity (calculating it exactly is slightly trickier than amplitude  I suspect just differentiating the phase will get you an unstable result), or it might be because it's too small to be visible.
A slow/tight chorus might detune by only 5 cents, which is 0.3%. The modulated frequency ends up pretty much as the (amplitudeweighted) average of the detunings of the delay lines + dry, so it's totally plausible that the frequency is modulating, but only by 0.1% or something.
Other modulation sources
Anyway  that's if you wanted to exactly simulate a delaybased chorus. An alternative might be going for some other modulation pattern to get something that sounds thick or choruslike but with its own character.
Instead of an LFO, you could use lowpassed noise to sound breathy and organic, or some other weirder input. You again have a choice between modulating both sin/cos components, or just modulating one and leaving the other as 0  it will make a very slight difference.
To remain choruslike, I would expect:
Also, hello KVR. I just joined, and I promise not every post I make is going to be this long.
Code: Select all
chorus_delay_seconds = chorus_depth*sin(chorus_phase)
output_sin = dry + wet*sin(chorus_delay_seconds*partial_freq)
// Use it to modulate the partial
output = sin(phase)*output_sin
The exact modulation (amplitude/phase for a given frequency) for a delaybased chorus depends on things like delay lengths, number of voices, LFO shape, and so on. There are lots of details like lower frequencies not being affected as much, or complex frequencyspecific interactions (like the way the 7th partial in your example remains constant in your example).
To emulate those exactly, I'm not sure there's a better/cleaner way than calculating it than directly  i.e. figure out what your chorus's delay times would be at that instant, and just add up various delayed versions of the partial, so your output is
Code: Select all
sin(phase + delay1*freq) + sin(phase + delay2*freq) + ...
Code: Select all
sin(phase)*(cos(delay1*freq) + cos(delay2*freq) + ...) + cos(phase)*(sin(delay1*freq) + sin(delay2*freq) + ...)
or:
sin(phase)*output_sin + cos(phase)*output_cos
where
output_sin = cos(delay1*freq) + cos(delay2*freq) + ...
output_cos = sin(delay1*freq) + sin(delay2*freq) + ...
magnitude for display:
sqrt(output_sin*output_sin + output_cos*output_cos)
If your chorus's delay lines are weighted, you'd need to add some gain factors to each delayN component, and perhaps an extra "1 + " to output_sin if there's a dry signal.
Frequency changes, and symmetrical delays
In general for a chorus, I would expect there to be frequency changes. There is the specific case of a completely symmetrical chorus, where every delayline has a matching delayline with opposite delay.mikejm wrote:According to the visual depiction of the sine wave partials by Razor's display, there is no change in the frequency of any of the partials (xaxis).
In the equations above, that means delay2 = delay1, delay4 = delay3, and so on  which would mean that output_cos comes out as 0 (because sin(delay1*freq) = sin(delay2*freq), etc.), so you can drop all those calculations. You can also drop half the output_sin calculations (because cos(delay1*freq) = cos(delay2*freq), etc.) so you get a 4x speedup overall.
This boils down to exactly the case that @mystran talked about  I don't know how much you see it in actual choruses because you need negative delay (i.e. latency), and it'll make a subtle difference to the sound, but not necessarily a bad one.
This means that the simplest possible case to calculate is for a symmetrical chorus, with a single LFO (driving two delays in opposite directions), and the equations for this are in the TL;DR section at the top. If you have more delay lines (but still symmetrical), you just get more terms:
Code: Select all
chorus_seconds1 = chorus_depth1*sin(chorus_phase1)
chorus_seconds2 = chorus_depth2*sin(chorus_phase2)
...
output_sin = dry + wet1*sin(chorus_seconds1 *partial_freq) + wet2*sin(chorus_seconds2 *partial_freq) + ...
// Use it to modulate the partial
output = sin(phase)*output_sin
This is a reasonable explanation for not having frequency shifts, but it's also possible that frequencyshifts are there, but not shown in the visualisation. This might be for simplicity (calculating it exactly is slightly trickier than amplitude  I suspect just differentiating the phase will get you an unstable result), or it might be because it's too small to be visible.
A slow/tight chorus might detune by only 5 cents, which is 0.3%. The modulated frequency ends up pretty much as the (amplitudeweighted) average of the detunings of the delay lines + dry, so it's totally plausible that the frequency is modulating, but only by 0.1% or something.
Other modulation sources
Anyway  that's if you wanted to exactly simulate a delaybased chorus. An alternative might be going for some other modulation pattern to get something that sounds thick or choruslike but with its own character.
Instead of an LFO, you could use lowpassed noise to sound breathy and organic, or some other weirder input. You again have a choice between modulating both sin/cos components, or just modulating one and leaving the other as 0  it will make a very slight difference.
To remain choruslike, I would expect:
 The frequency of the modulation is generally proportional to the frequency of the partial  so a 800Hz partial would be modulating twice as fast as a 400Hz one. If they are modulating at the same rate instead of proportionally, I'd expect it to sound more phaserlike.
 The amplitude of the modulation reduces for frequencies below some limit. This limit frequency is related to the maximum delay time of our (by this point metaphorical) delaylines. I think you could approximate this by (1  1/(1 + R^2)), where R=partial_freq/limit_freq.
Also, hello KVR. I just joined, and I promise not every post I make is going to be this long.

mystran
 KVRAF
 5001 posts since 12 Feb, 2006 from Helsinki, Finland
Re: Creating a chorus effect by modulating the levels of partials (sines in additive synth)?
Welcome... and don't you worry about long posts in the DSP development forum (not that they are rare in KVR in general). We like the dirty details here.signalsmith wrote: Also, hello KVR. I just joined, and I promise not every post I make is going to be this long.
If you'd like Signaldust to return, please ask Katinka Tuisku to resign.