6 posts

Page

**1**of**1**- KVRer
- 13 posts since 4 Apr, 2017

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

- KVRAF
- 10557 posts since 8 Mar, 2005, from Utrecht, Holland

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!!

- KVRer
- 13 posts since 4 Apr, 2017

BertKoor wrote:This is simply modulation of the frequency of sine oscillators.

You want formulas? See

http://www.kvraudio.com/forum/viewtopic ... 9#p7087109

I'm not sure if I understand or if that is correct.

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 (x-axis). The only thing it is modulating to create this chorus sound is the amplitude of the partials (y-axis) 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?

- KVRAF
- 4979 posts since 11 Feb, 2006, from Helsinki, Finland

Right.. so we have this fun little equivalence: 2*cos(a)*cos(b) = cos(a-b) + cos(a+b)!

So if you amplitude modulate with another frequency (or a set of frequencies), you get side-bands 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 side-bands 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.

<- plugins | forum

- KVRer
- 6 posts since 5 Jul, 2018

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 delay-based 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 frequency-specific 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 upside-down 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 general for a chorus, I would expect there to be frequency changes. There is the specific case of a completely symmetrical chorus, where every delay-line has a matching delay-line with opposite delay.

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 frequency-shifts 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 (amplitude-weighted) 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 delay-based chorus. An alternative might be going for some other modulation pattern to get something that sounds thick or chorus-like 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 chorus-like, 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 full derivation

The exact modulation (amplitude/phase for a given frequency) for a delay-based 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 frequency-specific 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) + ...`

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

- 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)

(OK, so the delays are upside-down 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

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 (x-axis).

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 delay-line has a matching delay-line with opposite delay.

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

Other reasons

This is a reasonable explanation for not having frequency shifts, but it's also possible that frequency-shifts 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 (amplitude-weighted) 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 delay-based chorus. An alternative might be going for some other modulation pattern to get something that sounds thick or chorus-like 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 chorus-like, 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 phaser-like.
- 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) delay-lines. 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.

- KVRAF
- 4979 posts since 11 Feb, 2006, from Helsinki, Finland

signalsmith wrote:Also, hello KVR. I just joined, and I promise not every post I make is going to be this long.

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.

<- plugins | forum