[.uhm] FM Synthesis in Hive

Official support for: u-he.com
Post Reply New Topic
RELATED
PRODUCTS

Post

Just like the Karplus-Strong thread, this one is for FM Synthesis, or, to be precise, "Delta X", the phase modulation synthesis which gave the Yamaha DX series its name.

Again, you need the Hive Tech Preview thread and ist downloads a pre-requisites:

http://www.kvraudio.com/forum/viewtopic ... 1&t=511390

Bypassing further ado, let's dive right in:

Chapter 1: FM Fundamentals

The fundamental idea of FM is to take a sine wave oscillator (modulator) to modulate the *phase* of another sine wave oscillator (carrier). What you hear is the carrier, which has a richer spectrum than two sine waves would suggest. The spectrum (or resulting waveform) depends on the frequency relation of those two oscillators as well as on the depth/amplitude of the phase modulation. Sonic movement similar to filter sweeps in classic subtractive synthesis is achieved by scaling the volume of the modulator signal with envelopes. Disharmonic sounds (bells etc.) can be achieved by altering pitch, or simple by having a non-integer frequency relation of modulator and carrier.

While Wavetables can of course only ever have harmonic content, there's still a whole lot of FM goodness available.

Here's a simple sine wave oscillator:

Code: Select all

Wave "sin(2*pi*phase)"
Remember that sin/cos etc. expect values in Radians, so we have to scale our phase by 2*pi. This is our fundamental building block.

Now, let's create another sine, but of any harmonic of choice:

Code: Select all

Wave "sin(2*pi*phase * 16)"
Yep, that's the 16th harmonic (fundamental being the 1st).

Now, let's see how to move phase, since that's what we want to modulate:

Code: Select all

Wave "sin(2*pi*phase + table*2*pi)"
When you run this one, the sine wave moves from right to left. Each frame has a different phase.

Lesson: *Multiply* 2*pi*phase by n to change harmonic. *Add* 2*pi*n to change phase.

The general FM operator

So, in general our FM operators consist of the following formula:

sin( 2*pi*phase*harmonic + 2*pi*delta*depth )

optionally shortened to

sin( 2*pi* (phase*harmonic + delta*depth) )

Where harmonic is a whole number (1,2,3,4...16 or so) and delta is the output of another operator, optionally scaled by a depth parameter (Typically between 0 and, maybe, 5 or so, but that's up to anyone).

Note: I wrote harmonic, delta and depth in italics because we need to replace them with variables or functions available in the scripting language.

Examples!

Here's the simple most FM wavetable .uhm script:

Code: Select all

Wave "sin(2*pi*phase + sin(2*pi*phase*4))"
This one creates a dull static squar-ish waveform. Not much movement. Also, while it's nice to have it all in one line, let's start making it tidy.

Code: Select all

Wave "sin(2*pi*phase*4)"
Wave "sin(2*pi*phase + x)"
^^ This is the same, but each operator gets its own line. The "x" always contains the value written to the wavetable in previous lines, so it's a good way to separate things. It also coincides with the x in DX (but that really is just coincidence).

Now, let's modulate the depth.

Code: Select all

Wave "sin(2*pi*phase*4)"
Wave "sin(2*pi*phase + x*(1-table))"
Yep, now we're getting somewhere. It sweeps.

It is still a bit boring though. If you look at patch sheets from FM synths, they usually have Time/Level envelopes, shaping a nice short initial Decay to some low value, followed by a slow long decay towards zero. FM is renowned for its percussive sounds.

Hence:

Envelopes!

Of course you can do envelopes any way you like. You can create your wavetables bit by bit using the start/end frame positions. But that's tedious. Hence there is a 8-segment Time/Level envelope built into the engine. It nicely lends itself to FM Synthesis.

Code: Select all

Info "Simple FM patch"
NumFrames=101

/*
	Introducing: The Envelope Feature!
	
	No. | Time | Level
	0   |  --- |  1.0
	1   |  0.2 |  0.3
	2   |  0.8 |  0.0
	...
	8   |      |    
*/

Envelope L0=1 T1=0.2 L1=0.3 T2=0.8 L2=0.0

Wave "sin( 2*pi*phase * 5 )" // Modulator on 5th harmonic

Wave "sin( 2*pi*(phase + x * env(table)) )"
Now, let's check this out:

Code: Select all

Envelope L0=1 T1=0.2 L1=0.3 T2=0.8 L2=0.0
We can create a Time/Level envelope, starting at Level 0, followed by pairs of Time and Level values 1-8

Before you ask: This envelope only exists in the script. It does not magically appear in Hive somewhere.

The way you use it, is in the last line. The envelope is accessed by the env(...) function in the formula parser:

Code: Select all

Wave "sin( 2*pi*(phase + x * env(table)) )"
You can use *any* variable, formula whatsoever as time base for the envelope. If you use "table", the envelope will neatly evolve from first frame to last, as long as the Time values are between 0 and 1. You can also use env(frame) for envelopes where the times are set up to have things happen at specific frames. In general I prefer "table" though, as I can change the NumFrames afterwards without affecting the envelope.

(and yes, you can use "phase" as time base as well, in case of which the envelope evolves over the course of the cycle... see "Tut03 Classic Waves Part 3.uhm" for creating waveforms using the envelope.)

Now. Let that sink in. I'll think of something for the next chapters. More operators? Layering? Feedback modulation?

Post

Urs wrote:More operators? Layering? Feedback modulation?
RCM from SY77/99. :P

Post

EvilDragon wrote:RCM from SY77/99. :P
:roll: I only got trash when using AWM as modulator. No wonder people didn't take to it.

Post

Urs, what is the time unit for the envelope Tn= feature?
Feel free to call me Brian.

Post

bmrzycki wrote:Urs, what is the time unit for the envelope Tn= feature?
Here's the thing you need an a-ha moment for: It's up to you! It's whatever t you put into env(t)

If you want to use the envelope to draw a triangle wave, you might want to make it go from 0 to 2047, because that's what index travels through:

Code: Select all

Envelope L0=0 T1=512 L1=1 T2=1024 L2=-1 T3=512 L4=0
Wave "env(index)"
or you go by phase, which is in the tutorial script:

Code: Select all

Envelope L0=0 T1=0.25 L1=1 T2=0.5 L2=-1 T3=0.25 L4=0
Wave "env(phase)"
There are numerous applications for it. Whenever phase, index whatever is too "linear" for the task at hand, the envelope feature might just do the trick!

Post

Also, you can almost directly translate DX-7 patch sheets to .uhm envelopes (less key scaling and stuff, but still...)

Post

Howard wrote:
EvilDragon wrote:RCM from SY77/99. :P
:roll: I only got trash when using AWM as modulator. No wonder people didn't take to it.
Yeah using raw samples would be trash, but if you filter them before hitting an operator...

Post

I really like the brightness and clearness of the uhm scripts. Very crisp, firm and stable. And there's no spectral leakage or any degradation and artifacts when playing very low and very high notes. Really impressive stuff.

Code: Select all

Info "FM thing that uses two envelopes"
NumFrames = 10

Seed "71915651"
Envelope L0=0.3 T1=0.2  L1=1.0 T2=0.8  L2=0.03 // simple AD envelope
Spectrum lowest=1 highest=16 "env(randf + table) * phase * pi" // it started as env(table) but then I threw in some other stuff just for fun and it worked
Wave start=6 "bandpass(x, 0.3, 0.9)" // I didn't like the transition in frames 6-10, so I altered them with bandpass filter

Envelope L0=0.3 T1=0.5  L1=0.0 T2=0.0  L2=1.0 T3=0.1  L3=0.0 T4=0.0  L4=0.35 T5=0.3  L5=0.05 T6=0.0  L6=0.1 T7=0.1  L7=0.3 // I'm feeling so smart right now
Wave start=2 "sin(2*pi * (phase + (x * env(table))))" // FMing starts from frame 2 to add some extra movement

Normalize base=each

Post

Urs wrote:Also, you can almost directly translate DX-7 patch sheets to .uhm envelopes (less key scaling and stuff, but still...)
Your Dx Piano.uhm is just Brilliant Urs! :hug:
I was playing a lot with it today and it is working and reacting to key and velocity like a charm. Like the real thing.

Now I beginning to understand that you'v put more operators and different envelopes into the script.

OMG! What will coming to us from this Script.
I'v already put away all my work and can't stop playing with the wavetables.
Wavetables get a new meaning now, how can it be so fresh and clean.

Wavetable HD 4k :tu:

Post

drzhnn wrote:I really like the brightness and clearness of the uhm scripts. Very crisp, firm and stable. And there's no spectral leakage or any degradation and artifacts when playing very low and very high notes. Really impressive stuff.
Yeah! The low and high notes sound lovely... so clean bright and clear... yet not harsh or cold. Very impressive...

Post

hehehe... that's why I was dying to publish this asap... glad you like it :-)

Post

DX Piano wavetable + 8 voice unison and some detuning = instant TX816!

Post

EvilDragon wrote:DX Piano wavetable + 8 voice unison and some detuning = instant TX816!
:clown:

Post

A simple 5OP FM script I made as a second layer for the additive preset I posted in the other thread :

Code: Select all

NumFrames=256

Wave "sin(2*pi*phase*7)
Envelope curve=quadric L0=0.03 T1=0.1 L1=0
Wave "sin(2*pi*(phase+x*env(table))*5)"
Envelope curve=quadric L0=0.2 T1=0.2 L1=0
Wave "sin(2*pi*(phase+x*env(table))*2)"
Envelope curve=quadric L0=0.1 T1=1 L1=0.2
Wave "x*env(table)"
Envelope curve=quadric L0=0 T1=0.5 L1=0.05 T2=0.5 L2=0
Wave blend=add "sin(2*pi*phase*8)*env(table)"
Wave "sin(2*pi*(phase+x))"
I might try to convert some of my old Sega Genesis (Yamaha YM2612 sound chip) sounds to scripts later. I mean, you can quantize envelopes and bit reduce the operators in scripts, so it should maybe be possible to get close.

Post

Hehehe, you're moving faster than I can keep up with :)

Post Reply

Return to “u-he”