How can I amplitude modulate one channel with another ?

How can I amplitude modulate one channel with another in Audacity : say left with right.
Nyquist code or a plug-in please.

This assumes that the carrier wave is in the right channel:

(mult (sum 0.5 (scale 0.5 (aref s 0)))(aref s 1))

For 100% modulation, you must normalize the track before running the Nyquist command.

If you want to also remove the carrier wave, try:

(sim (mult (aref s 1) -0.5)
   (mult (sum 0.5 (scale 0.5 (aref s 0)))(aref s 1)))

Thank you Steve, this is what I was looking for.

Modulating a sine wave with a voice using your second code produces a very Daleky voice.

[I was expecting sine speech …]

That’s what the vocoder does. too. That case is a balanced modulator rather than straight AM. The carrier is only present when the talent speaks or sings.


That’s an interesting effect - somewhat more complicated than AM modulation - I’ll have to look into that when I get time.

If the voice is passed through a narrow band pass filter before AM with sine the result is more like sine speech.

Whilst not strictly “Sine Speech”, you may find this code interesting.
Note that it should only be run on a mono track.

(setq width 14)   ; Number of iterations - higher number for narrower bandpass
(setq amplify 2.2)    ; amplification factor to keep the level reasonable

(setq carrier (hzosc 1000))

;; start of function
(defun makenote (note freq q amp)
(dotimes (n q note)
(setq note (scale amp (highpass8 (lowpass8 note freq) freq)))))

;; call function
(setq mysound (sim (makenote s 300 width amplify)
   (makenote s 500 width amplify)
   (makenote s 700 width amplify)
   (makenote s 1100 width amplify)))

(sim (mult carrier -0.5)
   (mult (sum 0.5 (scale 0.5 mysound)) carrier))

The above code is much more like sine speech.
I think I have fathomed out how you did it :
4 narrow band pass filters, (narrowness inversely proportional to “width”), modulated with 1KHz sinusoidal carrier.

I am attempting to digest the Nyquist manual, although it may take me some time.

[BTW with some values the above code seems to change the geographic accent of speech, e.g. South African, Australian].

Another thought that I’ve not had time to try out:

Use two comb filters on the audio signal and multiply one be the other - should make some interesting noise :slight_smile:

Just to be sure, I assume that this code:
-1- accepts two ordinary audio tracks (not necessarily for one of the them to be a pure sine wave and play the carrier)
-2- and its generated track will likely have a DC average mainly if the two tracks are identical (as in squaring; the first process to find RMS).

I have the impression, so I may be wrong, that this code multiplies each sample by its corresponding one on the other track (having the same timing) and normalize the multiplication result. So if the two tracks are similar, all new samples will be positive.

Please correct me if this is not the case.
Thank you.


This is an old topic, and the code is using the old Nyquist syntax (deprecated).
In modern syntax the code would be:

(sim (mult (aref *track* 1) -0.5)
     (mult (sum 0.5 (scale 0.5 (aref *track* 0)))
           (aref *track* 1)))

  • track is the selected audio that is passed by Audacity to Nyquist. In this case, a stereo track is required, so track is an array of 2 sounds.
  • (aref track 0) is the sound from the left channel.
  • (aref track 1) is the sound from the right channel.
  • (mult (aref track 1) -0.5) multiplies the right channel sound by -0.5. In other words, it halves the amplitude and inverts it.
  • (sum 0.5 (scale 0.5 (aref s 0))) multiplies the left channel by 0.5, and adds 0.5 to each sample value.
  • sim is equivalent to sum. It adds sounds or numbers.

If the left and right channels are the same, then yes, all new samples will be positive.

Thank you, Steve, for your update code and the detailed description of each symbol.
I tested it on 32-bit wav two similar tracks (1m:35s). I got the following error message:

 error: bad argument type - #<Sound: #5dc0328>
Function: #<Subr-AREF: #612c168>
  #<Sound: #5dc0328>
1> error: bad argument type - #<Sound: #5dc0328>
Function: #<Subr-AREF: #6133e78>
  #<Sound: #5dc0328>

The code requires a stereo track.

Sorry, I thought working with two tracks is equivalent to working with stereo tracks 0 and 1

So it seems it is not possible to test one mono track multiplied by its duplicate or another one having the same time length.

Two mono tracks may be joined together to make a stereo track. See:

Sorry again. Now only I noticed that two tracks could be treated as one stereo track (0 and 1) or two separate mono tracks :blush:
After all, I am in the learning stage :slight_smile:
Thank you for your patience.

About the amplitude modulation by using LISP, I thought that, in case of two SOUNDs which have the same length and an upper limit of 0db:

-1- We can multiply their samples (having the same timing) respectively.
-2- And by taking the square root of each result, the volume of the new samples will not be above 0db.

I think that 32-bit wave sounds (or equivalent) are best for such task in respect of accuracy (if LISP can calculate the square root of a floating number).

Any comment?
Thank you.

Audacity works internally in 32-bit floating point format. Nyquist also treats sounds as 32-bit float. For the “valid” range (not exceeding 0 dB), the numeric values of samples are in the range +/- 1.

Therefore, multiplying two sounds that don’t exceed 0 dB, the product will not exceed 0 dB (sample values will be in the range +/- 1).

Your remark is indeed right. Thank you.
I forgot that, in this case, the values that represent the samples are treated as fractional numbers and not as integers. In writing MCU codes (in assembly always) for my various controllers, I used to work, for many decades, with the received ADC samples as being absolute or signed integers only.

For instance, your one line code, above, worked. I tested it with two similar tracks (using Duplicate). But I was expecting that samples which have high values (close to 0 dB) would generate samples of high amplitudes too, speaking relatively. Instead, the resulting amplitudes were all rather very low and the samples sum (thanks to another code from you) was close to zero (as if they were of a normal audio track).

I thought that, very briefly, something like “mult s1 s2” can do the multiplication (which also needs instructions that fetch s1 and s2 and export the result).
On the other hand, since you are a professional musician (most of your life working with audio sounds) you likely used making the result of any analyse or process code you write as an audio track to be heard. I am afraid that, here, the resulting track is strictly a set of numbers which is not supposed to generate an audio signal.

The “mult” function works with numbers or sounds.

(mult 3 2)  ;returns 6
(mult 3 my-sound)  ;multiplies each sample in "my-sound" by 3
(mult sound-a sound-b)  ;multiplies each sample in "sound-a" by the corresponding sample in "sound-b" and terminates when sound-a or sound-b run out of samples.