AM and FM Tone Generators

If you mean that you want the sound to be “shaped” with a “raised cosine” envelope (see picture) then you can shape any type of generated tone using this code (run it in the “Nyquist Prompt” effect):

(setq dur (get-duration 1))
(abs-env
  (mult s 0.5 (sum 1 (osc (hz-to-step (/ dur 4.0)) dur *sine-table* -90))))

firsttrack000.png

I would like to create an fm synthesizer, like Yamaha dx 7.
I can only do simple modulations, with a carrier wave and a modulator. How can I for example bind modulators, example:
Operator 2 modulates one, 3 modulates two etc. Thanks in advance

I’d recommend that you focus on AM modulation initially, as it is much less difficult to implement in Nyquist than FM synthesis.

AM (amplitude modulation) is what happens when you multiply one signal with another signal.

Signal-A x Signal-B => modulation.

Note that, as in arithmetic, “A x B” is the same as “B x A”.
Example: modulating a 1000 Hz signal with a 10 Hz signal:
(The “0.8” in the code below scales the signal by a factor of 0.8 so that the output is not too loud)

(mult 0.8 (hzosc 1000) (hzosc 10))

and modulating a 10 Hz signal with a 1000 Hz signal:

(mult 0.8 (hzosc 10) (hzosc 1000))

You can modulate (multiply) any number of signals together:

(mult 0.8 (hzosc 10) (hzosc 20) (hzosc 112) (hzosc 234) (hzosc 440) (hzosc 543))

You can also mix together modulated signals. “Mixing” is the same as “adding”.

(mult 0.17 (sum (hzosc 10) (hzosc 20) (hzosc 112) (hzosc 234) (hzosc 440) (hzosc 543)))

or any combination of adding and multiplying:

(mult 0.3 (sum (mult (hzosc 10) (hzosc 440))
               (mult (hzosc 20) (hzosc 112))
               (mult (hzosc 234) (hzosc 543))))

To make the code more manageable, you can assign signals to variable and then work with the variables:

(setf sig-A (mult (hzosc 10) (hzosc 440)))
(setf sig-B (mult (hzosc 20) (hzosc 112)))
(setf sig-C (mult (hzosc 234) (hzosc 543)))

(setf mix (sum sig-A sig-B sig-C))

;scale the output
(mult 0.3 mix)

As the code becomes more complex, it can be useful to create “functions” to handle calculations that are done several times.
In this example we create a function “modulate” that modulates two sounds, and scales the output to a specified “gain” level:

(defun modulate (sig1 sig2 gain)
  (mult sig1 sig2 gain))

(sum (modulate (hzosc 14) (hzosc 540) 0.3)
     (modulate (hzosc 27) (hzosc 221) 0.3)
     (modulate (hzosc 234) (hzosc 432) 0.3))

and a “modulate” function that accepts an arbitrary number of signals (minimum 2 signals):

(defun modulate (gain &rest sigs)
  (when (< (length sigs) 2)
    (error "modulate requires at least three parameters"))
  (let ((mix 1))  ;create local variable "mix" with value 1.
    ;; modulate the list of signals.
    (dolist (sig sigs)
      (setf mix (mult mix sig)))
    ; scale the output by "gain".
    (mult gain mix)))

; Call the function
(modulate  0.8 (hzosc 10) (hzosc 440) (hzosc 20) (hzosc 112) (hzosc 234) (hzosc 543))

and similarly, a function that mixes an arbitrary number of signals:

(defun mix (gain &rest sigs)
  (when (< (length sigs) 2)
    (error "modulate requires at least three parameters"))
  (let ((mix 1))  ;create local variable "mix" with value 1.
    ;; modulate the list of signals.
    (dolist (sig sigs)
      (setf mix (sum mix sig)))
    ; scale the output by "gain".
    (mult gain mix)))

; Call the function
(mix  0.13 (hzosc 8) (hzosc 333) (hzosc 17) (hzosc 123) (hzosc 432) (hzosc 543))