basic FM question
-
- KVRist
- 392 posts since 1 Jul, 2004
Short question to the Rhino FM-gurus:
What happens in the following situation:
mo\ca|OSC1|OSC 2
-------------------
OSC1 | 006 | 090
OSC2 | 090 | 006
in order to compute a modulator for osc1 one needs the final waveform of osc2 and vice versa. How is this solved? (Are the modulators always the raw (unmodulated) waves or is there some kind of iteration that is interrupted after some cycles per sample?)
Greetings,
NothanUmber
What happens in the following situation:
mo\ca|OSC1|OSC 2
-------------------
OSC1 | 006 | 090
OSC2 | 090 | 006
in order to compute a modulator for osc1 one needs the final waveform of osc2 and vice versa. How is this solved? (Are the modulators always the raw (unmodulated) waves or is there some kind of iteration that is interrupted after some cycles per sample?)
Greetings,
NothanUmber
-
- KVRist
- 273 posts since 5 Mar, 2003 from US
I don't quite understand your question. However, assuming that both oscs are using sine waves, when an osc modulates itself (as 1 & 2 are in this example) the modulator will no longer be a pure sine wave, but closer to a sawtooth the higher the level of feedback. This modified wave then modulates the carrier to produce more overtones. This is the setup most other FM synths follow.
-
- KVRist
- Topic Starter
- 392 posts since 1 Jul, 2004
Well perhaps that helps to understand what I mean:
(syntax: resulting waveform := carrier fmmod modulator)
Here the table from above:
osc1Wave := osc1Wave fmmod osc1Wave
osc1Wave := osc1Wave fmmod osc2Wave
osc2Wave := osc2Wave fmmod osc2Wave
osc2Wave := osc2Wave fmmod osc1Wave
These lines show:
* There are two expressions that define the value of both osc1Wave and osc2Wave (which is executed first?)
* in order to compute any value one needs either osc1Wave or osc2Wave, but neither of them is known or can ever be computed in finite time (*) so the computation never ends.
Here are some ways out (perhaps Rhino uses one of these or does something completely different...):
* the modulators are always the raw unmodulated waves and the carrier is always the intermediate result from the last modulation. In that case one would have something like that:
modOsc1Wave1 := RawOsc1Wave fmmod RawOsc1Wave
modOsc1Wave2 := modOsc1Wave1 fmmod RawOsc2Wave
modOsc2Wave1 := RawOsc2Wave fmmod RawOsc1Wave
modOsc2Wave2 := modOsc2Wave fmmod RawOsc2Wave
(that's perhaps the most simple solution but e.g. the situation that you described above (where the result of the self-modulation of one osc would be used as a modulator for the second osc) wouldn't be possible with that approach though)
* the recursions are followed but after a fixed number of steps the unknown waves are replaced by the raw ones (or the ones that where computed at the last sample). The priority of lines that define the same wave could either be choosen at random, alternately or with a rule (first the self-modulating expressions etc.).
* Just could think of a third variant that would do what you described (is a little bit "forced" perhaps...): The modulators are always the raw oscillator waves except the oscillator self-modulates. Then the self modulation is computed first (with the raw oscillator) and all subsequent modulations are done with the result of that self-modulation.
(* And a fourth one (don't know whether that makes sense at all...): The carriers are always the unmodulated raw oscs and the modulator is the intermediate result from the last modulation:
modOsc1Wave1 := RawOsc1Wave fmmod RawOsc1Wave
modOsc1Wave2 := RawOsc1Wave fmmod RawOsc2Wave
modOsc2Wave1 := RawOsc2Wave fmmod modOsc1Wave1
modOsc2Wave2 := modOsc2Wave fmmod modOsc2Wave1
would also not fit to your example and is rather strange... but presumably I'm just thinking too complicated and there is an easy way out (or there exists no problem at all...)
)
Greetings,
NothanUmber
(*) except one can find a closed form for the recursion...
(syntax: resulting waveform := carrier fmmod modulator)
Here the table from above:
osc1Wave := osc1Wave fmmod osc1Wave
osc1Wave := osc1Wave fmmod osc2Wave
osc2Wave := osc2Wave fmmod osc2Wave
osc2Wave := osc2Wave fmmod osc1Wave
These lines show:
* There are two expressions that define the value of both osc1Wave and osc2Wave (which is executed first?)
* in order to compute any value one needs either osc1Wave or osc2Wave, but neither of them is known or can ever be computed in finite time (*) so the computation never ends.
Here are some ways out (perhaps Rhino uses one of these or does something completely different...):
* the modulators are always the raw unmodulated waves and the carrier is always the intermediate result from the last modulation. In that case one would have something like that:
modOsc1Wave1 := RawOsc1Wave fmmod RawOsc1Wave
modOsc1Wave2 := modOsc1Wave1 fmmod RawOsc2Wave
modOsc2Wave1 := RawOsc2Wave fmmod RawOsc1Wave
modOsc2Wave2 := modOsc2Wave fmmod RawOsc2Wave
(that's perhaps the most simple solution but e.g. the situation that you described above (where the result of the self-modulation of one osc would be used as a modulator for the second osc) wouldn't be possible with that approach though)
* the recursions are followed but after a fixed number of steps the unknown waves are replaced by the raw ones (or the ones that where computed at the last sample). The priority of lines that define the same wave could either be choosen at random, alternately or with a rule (first the self-modulating expressions etc.).
* Just could think of a third variant that would do what you described (is a little bit "forced" perhaps...): The modulators are always the raw oscillator waves except the oscillator self-modulates. Then the self modulation is computed first (with the raw oscillator) and all subsequent modulations are done with the result of that self-modulation.
(* And a fourth one (don't know whether that makes sense at all...): The carriers are always the unmodulated raw oscs and the modulator is the intermediate result from the last modulation:
modOsc1Wave1 := RawOsc1Wave fmmod RawOsc1Wave
modOsc1Wave2 := RawOsc1Wave fmmod RawOsc2Wave
modOsc2Wave1 := RawOsc2Wave fmmod modOsc1Wave1
modOsc2Wave2 := modOsc2Wave fmmod modOsc2Wave1
would also not fit to your example and is rather strange... but presumably I'm just thinking too complicated and there is an easy way out (or there exists no problem at all...)
Greetings,
NothanUmber
(*) except one can find a closed form for the recursion...
-
- KVRist
- Topic Starter
- 392 posts since 1 Jul, 2004
Due to Daniel's suggestion I played around with an oscilloscope yesterday and saw that all but the "the recursions are followed [...]self-modulating expressions etc.)" explaination don't match to the results of those experiments. So unless someone (the dev?) gives a better explaination I think it's working that way
Greetings,
NothanUmber
P.S.: It seems that I overestimated the usefulness of the oscilloscopes. (fm with factors > 10% already gives such chaotic waves that the information that one get's by watching them instead of just listening is not as big as I hoped, perhaps a spectral analysis is more comprehensible, will have to see...)
Greetings,
NothanUmber
P.S.: It seems that I overestimated the usefulness of the oscilloscopes. (fm with factors > 10% already gives such chaotic waves that the information that one get's by watching them instead of just listening is not as big as I hoped, perhaps a spectral analysis is more comprehensible, will have to see...)
-
- KVRist
- 30 posts since 16 Oct, 2001 from Poland
It's easy. The calculations are done sample by sample, so the modulators are always delayed w.r.t. the oscillator producing the wave. In other words, the recursion is done using previous sample values which is already known.
-
- KVRist
- Topic Starter
- 392 posts since 1 Jul, 2004
Thanks for the clarification!
Don't understand though why that isn't going berserk within a few seconds.
Here my naive understanding of a frequency modulation (perhaps synthesists mean something else with that term?):
modulatedFunction(x) = carrierFunction(x * modFactor * modulatorFunction(x))
*edit* the above doesn't make sense as one would always get carrierFunction(0) for a modFactor of 0 so perhaps it's more like
modulatedFunction(x) = carrierFunction(x + modFactor * modulatorFunction(x))
? Just changed the example below to that variant. Doesn't solve the "riddle" though... *edit*
If one applies the concept that MB mentioned e.g. to the case of self-modulation of a sine oscillator with a modulation factor of 100% then something like that would happen (or not?):
carrierFunction1(x) = modulatorFunction1(x) = sin(x)
carrierFunction2(x) = carrierFunction1(x + modulatorFunction1(x)) = sin(x + sin(x))
modulatorFunction2(x) = carrierFunction2(x)
carrierFunction3(x) = carrierFunction2(x + modulatorFunction2(x)) = sin((x + sin(x + sin(x))) + sin(x + sin(x + sin(x))))
...
modulatorFunction_n-1(x) = carrierFunction_n-1(x)
carrierFunction_n(x) = carrierFunction_n-1(x + modulatorFunction_n-1(x)) = something really big and complicated???
don't see some kind of fixpoint for that recursion, the expression is getting more and more complex with every iteration so I wonder why that doesn't lead to some kind of arbitrary-like noise after a short peroid of time,
presumably my understanding of fm is simply wrong...
Would be glad for any help, some fm-presets sound really wonderful and I'd really like to understand the "logics" behind this technique.
Greetings,
NothanUmber
Don't understand though why that isn't going berserk within a few seconds.
Here my naive understanding of a frequency modulation (perhaps synthesists mean something else with that term?):
modulatedFunction(x) = carrierFunction(x * modFactor * modulatorFunction(x))
*edit* the above doesn't make sense as one would always get carrierFunction(0) for a modFactor of 0 so perhaps it's more like
modulatedFunction(x) = carrierFunction(x + modFactor * modulatorFunction(x))
? Just changed the example below to that variant. Doesn't solve the "riddle" though... *edit*
If one applies the concept that MB mentioned e.g. to the case of self-modulation of a sine oscillator with a modulation factor of 100% then something like that would happen (or not?):
carrierFunction1(x) = modulatorFunction1(x) = sin(x)
carrierFunction2(x) = carrierFunction1(x + modulatorFunction1(x)) = sin(x + sin(x))
modulatorFunction2(x) = carrierFunction2(x)
carrierFunction3(x) = carrierFunction2(x + modulatorFunction2(x)) = sin((x + sin(x + sin(x))) + sin(x + sin(x + sin(x))))
...
modulatorFunction_n-1(x) = carrierFunction_n-1(x)
carrierFunction_n(x) = carrierFunction_n-1(x + modulatorFunction_n-1(x)) = something really big and complicated???
don't see some kind of fixpoint for that recursion, the expression is getting more and more complex with every iteration so I wonder why that doesn't lead to some kind of arbitrary-like noise after a short peroid of time,
presumably my understanding of fm is simply wrong...
Would be glad for any help, some fm-presets sound really wonderful and I'd really like to understand the "logics" behind this technique.
Greetings,
NothanUmber
Last edited by NothanUmber on Wed Dec 28, 2005 2:28 pm, edited 1 time in total.
-
- KVRAF
- 4737 posts since 20 Feb, 2004 from Gothenburg, Sweden
Basically you are correct, but there's no NEED for calculating all the past values, since they all are part of the previous calculated value already.
Here's how self-feedback with just one sine oscillator works, for each sample, do this:
out = sin(phase + lastOut * feedback)
lastOut = out;
That's it. This means that the fourth calculated sample is equal to (if phase increases with 0.1 for each sample)
out = sin(phase + sin(phase - 0.1 + sin(phase - 0.2 + sin(phase - 0.3) * feedback) * feedback) * feedback);
but there's no need for doing all those calculations since all previous calculations are part of "lastOut".
Here's how self-feedback with just one sine oscillator works, for each sample, do this:
out = sin(phase + lastOut * feedback)
lastOut = out;
That's it. This means that the fourth calculated sample is equal to (if phase increases with 0.1 for each sample)
out = sin(phase + sin(phase - 0.1 + sin(phase - 0.2 + sin(phase - 0.3) * feedback) * feedback) * feedback);
but there's no need for doing all those calculations since all previous calculations are part of "lastOut".
Stefan H Singer
https://dropshotaudio.com/
https://dropshotaudio.com/
-
- KVRAF
- 4737 posts since 20 Feb, 2004 from Gothenburg, Sweden
Also, with a feedback to high, it DOES freak out and turn to noise 
Stefan H Singer
https://dropshotaudio.com/
https://dropshotaudio.com/
-
- KVRist
- Topic Starter
- 392 posts since 1 Jul, 2004
Thanks stefan!
That makes my fears become true, the result of fm (at least when feedbacks are involved) doesn't seem to be intuitively predictable so presumably all one can do is to experiment and stop tweaking when it sounds nice... am not a fan of that concept
So I'll continue my experiments without using feedbacks first
Greetings,
NothanUmber
That makes my fears become true, the result of fm (at least when feedbacks are involved) doesn't seem to be intuitively predictable so presumably all one can do is to experiment and stop tweaking when it sounds nice... am not a fan of that concept
So I'll continue my experiments without using feedbacks first
Greetings,
NothanUmber
-
- KVRAF
- 4737 posts since 20 Feb, 2004 from Gothenburg, Sweden
Hm, in my head I usually KINDOF know what to expect from different feedback tweaks. when there's several oscs in series before the feedback (like osc1->osc2->osc3->osc1) it starts turning into an experiment though
But usually, when dealing with sines as the basic waveform, the feedback means that the entire sound gets more "saw alike". Unless you square the value before the feedback, then it gets "square alike". Heh.
Stefan H Singer
https://dropshotaudio.com/
https://dropshotaudio.com/
-
- KVRist
- Topic Starter
- 392 posts since 1 Jul, 2004
Ah, ok, will be bound to collect some experience then. If there'd only exist a shop where one could buy huge amounts of time...stefancrs wrote:Hm, in my head I usually KINDOF know what to expect from different feedback tweaks. when there's several oscs in series before the feedback (like osc1->osc2->osc3->osc1) it starts turning into an experiment thoughBut usually, when dealing with sines as the basic waveform, the feedback means that the entire sound gets more "saw alike". Unless you square the value before the feedback, then it gets "square alike". Heh.
Greetings,
NothanUmber
-
- KVRian
- 1184 posts since 13 May, 2004 from SF Bay Area, California
-
- KVRAF
- 3528 posts since 18 Apr, 2002 from British Columbia, Canada
or if asked by someone to whom they do matter, "why don't the calculation details matter to you?pummel wrote:Why do the calculation details matter?
