Mix multi-channel track to mono

This is probably the most useless piece of code that I’ve ever written :smiley:

It is just a code snippet that could be used within a plug-in, though it will also work in the “Nyquist Prompt” effect.

;; The following function could be more simple as Audacity currently only supports
;; mono or stereo tracks, but this function is written to support n channel tracks.
(defun mix (s-in)
  (if (arrayp s-in) ; if multichannel
    (let ((chan (length s-in))) ; number of audio channels
      (scale (/ 1.0 chan) ; scale by number of channels
        (do ((i 1 (setq i (1+ i)))) ; from i=1, increment i
          ((= i chan)(aref s-in 0)) ; till i=chan, return first channel
          (setf (aref s-in 0)(sum (aref s-in 0)(aref s-in i)))))) ; mix channels to first channel
  s-in))
            
;; to call function
(mix s)

or in it’s raw form without all of the comments:

(defun mix (s-in)
  (if (arrayp s-in)
    (let ((chan (length s-in)))
      (scale (/ 1.0 chan)
        (do ((i 1 (setq i (1+ i))))
          ((= i chan)(aref s-in 0))
          (setf (aref s-in 0)(sum (aref s-in 0)(aref s-in i))))))
  s-in))

(mix s)

What it does is to add (mix) all of the channels into the first (left) channel, then scale the output by the number of channels.
If the sound (s) is a single channel sound, then the function simply returns the sound unchanged.
The “if” condition is required because single channel sounds are treated by Nyquist as ordinary variables, but multi-channel sounds are handled as arrays - each element of the array being the mono sound for the corresponding channel.

Why is it so useless?

  1. because the same effect can be done better using the normal “Tracks > Stereo Track to Mono”,
  2. because Audacity currently only supports multi-channel tracks of up to 2 channels (stereo), so it would be much more simple to just use:
(scale 0.5 (sum (aref s 0)(aref s 1)))

However, if Audacity ever does support multi-channel tracks with more than 2 channels, then this will be a really useful function.

Or a more “exotic” way of doing the same thing:

(defun mix (s-in)
  (if (arrayp s-in)
    (let ((c 0)(n (/ 1.0(length s-in))))
    (multichan-expand #'(lambda (x) 
      (if (= c 0)(setq c 1)(setf (aref s-in 0)(sum(aref s-in 0)x)))) s-in)
    (scale n (aref s-in 0)))
  s-in))

(mix s)

An interesting thing (that appears to be undocumented elsewhere) is that lambda expressions can be used with multichan-expand