Delay with bpm and panning

Regards!
I have a delay plugin with bpm, but I do not know how to do with panning.
Delay bpm.ny (699 Bytes)
There is a function that makes the selection extend, but I do not want it since the music will be heard out of time.
I took the code from this plug-in from the audacity wiki, where it shows an example of plug {in with delay.
After I have the effect with panning I will implement some filters to make it more musical.
From already thank you very much.


UPDATE:
The most recent version of this plug-in is available on the Audacity wiki: https://wiki.audacityteam.org/wiki/Nyquist_Effect_Plug-ins#Delay_BPM_with_Panning

To do panning with a plug-in, the audio must be in a stereo track.
Stereo tracks are handles as arrays, so you can test if the track is stereo by checking if track is an array.

(if (arrayp *track*)
    (print "Stereo")
    (print "Mono"))

Panning is then achieved by adjusting the proportion of sound in each channel. The first element of a 2 channel stereo sound array is the left channel.

There’s an example of delay with panning here: https://wiki.audacityteam.org/wiki/Nyquist_Effect_Plug-ins#Bouncing_Ball_Delay_with_Panning

Please note that it is highly recommended to indent code to aid readability. See here for a good introduction to LISP indentation: http://dept-info.labri.fr/~idurand/enseignement/lst-info/PFS/Common/Strandh-Tutorial/indentation.html

I will always work with stereo tracks, so I do not need to verify.
I have tried to understand the code of this wiki plug-in, but there are many calculations.
What I want to do is sound the sound, then a delay in one channel and then in the other.

Perhaps this will help to get you started:

(setf delays (vector 0.4 0.8))  ;left delay 0.4s, right delay 0.8s
(setf delay-level 0.6)

(defun stereo-delay (sig delay)
  (sim sig
       (at-abs delay (cue (mult sig delay-level)))))

(if (arrayp *track*)
    (multichan-expand #'stereo-delay *track* delays)
    "Error.\nStereo track required")

Hi Steve, I like your code, but it has no function to adjust the number of echoes and the stereo width.
I found the volume of the echoes and the delay time in each channel.

If you only want to use Nyquist plug-ins, then there are many free Nyquist plug-ins available here: https://wiki.audacityteam.org/wiki/Download_Nyquist_Plug-ins

If you want to learn how to create and / or modify Nyquist plug-ins, then there are many resources available: https://forum.audacityteam.org/t/manuals-and-reference-material/32817/1

Hello forum people, today I managed to make the delay with panning and bpm.
I was comparing the functions of the delay plugin with panning and a fixed delay plug-in of an example and I have given that by taking out a function I could take out the ball that bounces and pick up a lag.
I have examined the delay that already comes with audacity and I have extracted a function so as not to extend the duration of the selection, and now I am sharing them.
Later maybe add some filter options to expand the musical possibilities.
Let me know if you like, any doubt I answer.
Delay bpm.ny (1.38 KB)

Have you uploaded the correct version? It does not appear to work. Would you like some help debugging it?

Hello Steve, try this.
Delay bpm.ny (1.34 KB)
I have everything perfect now, the only thing I can not do is not extend the selection.
If I put many echoes the panning is on one side and increases its amplitude in an uncontrolled way.

You can fix that by changing the last line from:

(stretch-abs 1 (multichan-expand #'constrain-abs (panbounces s count) (get-duration *sound-srate* )))

to:

(let ((dur (get-duration 1)))
  (stretch-abs 1
    (multichan-expand #'extract-abs (panbounces s count) dur)))

Question:
What is supposed to happen if there is a sound in the original track that is already panned hard over to one side?
Should it echo in both left and right, or only echo on the side where the original sound is?
If the amount of decay is zero, and the “Pan spread” is greater than zero, should the echoes be all the same volume, or alternate between quiet and loud?

If the panning behavior in your plug-in is what you actually want, then here’s a shorter way to write the processing code (I’ve hard coded the settings in this example, but they may easily be replaced with controls):

(setf delay 0.2)    ;delay time (seconds)
(setf decay -3.0)   ;decay per echo (dB)
(setf echoes 3)     ;number of echoes (int)
(setf spread 0.3)   ;stereo spread (0 to 1)

(defun delay (sig channel dur)
  (let ((out sig))
    (dotimes (i echoes (extract-abs 0 dur out))
      (setf out
        (sim out
             (at-abs (* (1+ i) delay)
                (if (evenp (+ i channel))
                    (loud decay (cue (mult (- 1 spread) sig)))
                    (loud decay (cue sig)))))))))

(let ((dur (get-duration 1)))
  (multichan-expand #'delay *track* #(0 1) dur))

This code gives a good behavior, without errors.
With this code I can put how many delays I want and one sounds on one side and another on another. :slight_smile:
The problem is that each delay sounds at the same level, for example, set the decay to -6 db. All delays sound in this range, without a linear decay.
Thanks Steve, below is the plug-in in its new version.
Delay bpm.ny (1.01 KB)

If you want each successive echo to be decreased in level by “decay”, then you can increment the number that is passed to loud like this:

(defun delay (sig channel dur)
  (let ((out sig))
    (do ((i 0 (1+ i))
         (gain decay (+ gain decay)))
        ((= i echoes) (extract-abs 0 dur out))
      (setf out
        (sim out
             (at-abs (* (1+ i) delay)
                (if (evenp (+ i channel))
                    (loud gain (cue (mult (- 1 spread) sig)))
                    (loud gain (cue sig)))))))))

I’m still not convinced that panning is being handled correctly, but you have not replied to my earlier question about what exactly you want “pan spread” to do.

What I would expect (as a user of this effect), would be that the original sound retains it’s original stereo image, and that the echoes bounce left and right even for sounds that originate hard left or hard right. To do this, you would need to create a 2 channel stereo output when processing the left channel input, then add a stereo output from processing the right channel input. So if we call the input channels “InL” and “InR”, then “InL” produces “OutL1” and “OutR1”, and “InR” produces “OutL2” and OutR2", and the output of the effect is “OutL1” + “OutL2” in the left channel, and “OutR1” + “OutR2” in the right channel.

I like the current behavior.
Like I do not know how to make that division of outputs for audio channels.
Delay bpm.ny (1.07 KB)
I would use it for voices or some synthetic electronic music instruments like saw waves or square waves. And taking advantage of the synchronization feature with the bpm of the song, in some situations I would apply it in small sections with one or two echoes without panning.

The thing that I see as a problem with the “Pan spread movement”, is that if there is a sound that is hard over one side in the original audio, the echo does not pan, it just fluctuates in volume.

Probably the easiest way to deal with that would be mix the delayed signals to mono and then pan the mono signal. That could be done with something like this:

(defun stereo-pan (stereo-sig where)
  (let ((mono-sig (mono-mix stereo-sig)))
    (pan mono-sig where)))

(defun mono-mix (stereo)
  (mult 0.5 (sum (aref stereo 0)
                 (aref stereo 1))))

However, there are a couple of disadvantages:

  1. When the “spread” is zero, the processed signal becomes entirely mono (probably not what we want)
  2. When the “spread” is zero, the amplitude of the echo is only half of the expected level

A better solution would be to create our own pan law function so that we get true stereo when the spread is close to zero, and tending towards a mono mix when the spread is greater. For example, something like this (I’ve used the American names for note values, as is the custom for Audacity):

;nyquist plug-in
;version 4
;type process
;name "Delay with bpm and panning..."
;action "Performing Delay with bpm and panning..."

;control decay "Decay" float "dB" -6 -24 0
;control bpm "Tempo" float "bpm" 120 1 500
;control notes "Note values:" choice "Half note (0.5),Quarter note (1),Eighth note (2),Sixteenth note (4),Thirty-second note (8),Sixty-fourth note (16)" 2
;control echoes "Number of echoes" int "times" 5 1 100
;control spread "Pan spread" float "move" 0.0 -1 1

(setq notes
  (case notes
    (0 120)
    (1 60)
    (2 30)
    (3 15)
    (4 7.5)
    (t 3.75)))

(setq delay (* notes (/ bpm)))

(defun stereo-delay (sig)
  (let ((out sig))
    (do ((i 1 (1+ i))
         (gain decay (+ gain decay))
         (where spread (* -1 where)))
        ((> i echoes) out)
      (setf out
        (sim out
             (at-abs (* i delay)
                (panning (loud gain (cue sig)) where)))))))

(defun panning (stereo-sig where)
  (let* ((mono-gain (* where where))
         (where (/ (+ 1 where) 2.0))  ;range 0 to 1
         (mono-sig (mono-mix stereo-sig)))
    (sum (mult mono-gain (pan mono-sig where))
         (stereo-pan stereo-sig where))))

(defun stereo-pan (stereo-sig where)
  (setf gain  (- 2 (* 4 (abs (- where 0.5)))))
  (vector (mult gain (- 1 where) (aref stereo-sig 0))
          (mult gain where (aref stereo-sig 1))))

(defun mono-mix (stereo)
  (mult 0.5 (sum (aref stereo 0)
                 (aref stereo 1))))

(if (arrayp *track*)
    (stereo-delay *track*)
    "Error.\nStereo track required.")

It sounds good.
In case this plug-in is published in the wiki, it is necessary to explain the spread control, which can be confusing for some users.
The value 0 produces echoes in mono.
Negative values produce deeper movements, with the first echo positioned on the left channel. And positive values also produce deeper echoes, but the first echo sounds in the right channel.

Hello Steve, now that I have everything perfect in the delay, as I said in another post, I decided to add filter options to my delay to make it more musical and creative. Below I leave the plug-in using the last code you have put, plus my options.
Delay bpm.ny (2 KB)
You like?

Hello Steve, i have problems to run this code:

;nyquist plug-in
;version 4
;type process
;name "Delay with bpm and panning..."
;action "Performing Delay with bpm and panning..."

;control decay "Decay" float "dB" -6 -24 0
;control bpm "Tempo" float "bpm" 120 1 500
;control notes "Note values:" choice "Half note (0.5),Quarter note (1),Eighth note (2),Sixteenth note (4),Thirty-second note (8),Sixty-fourth note (16)" 2
;control echoes "Number of echoes" int "times" 5 1 100
;control spread "Pan spread" float "move" 0.0 -1 1
;control options "Select aditional options for the delayed sound:" choice "Normal,Add} high pass filter,Add low pass filter,Add band pass filter" 0
;control lower "Lower frequency for the filter:" int "hz" 300 20 10000
;control upper "Upper frequency for the filter:" int "hz" 3000 20 10000

(setq notes
  (case notes
    (0 120)
    (1 60)
    (2 30)
    (3 15)
    (4 7.5)
    (t 3.75)))
(setq delay (* notes (/ bpm)))

(defun sig ()
(case options
(0 *track*)
(1 (highpass2 *track* upper 1))
(1 (lowpass2 *track* lower 1))
(t (highpass2 (lowpass2 *track* upper 1) lower 1))))

(defun stereo-delay (sig dur)
  (let ((out sig))
    (do ((i 1 (1+ i))
         (gain decay (+ gain decay))
         (where spread (* -1 where)))
        ((= i echoes) (extract-abs 0 dur out))
      (setf out
        (sim out
             (at-abs (* (1+ i) delay)
                (panning (loud gain (cue (sig))) where)))))))

(defun panning (stereo-sig where)
  (let* ((mono-gain (* where where))
         (where (/ (+ 1 where) 2.0))  ;range 0 to 1
         (mono-sig (mono-mix stereo-sig)))
    (sum (mult mono-gain (pan mono-sig where))
         (stereo-pan stereo-sig where))))

(defun stereo-pan (stereo-sig where)
  (setf gain  (- 2 (* 4 (abs (- where 0.5)))))
  (vector (mult gain (- 1 where) (aref stereo-sig 0))
          (mult gain where (aref stereo-sig 1))))

(defun mono-mix (stereo)
  (mult 0.5 (sum (aref stereo 0)
                 (aref stereo 1))))

(let  ((dur (get-duration 1)))
(if (arrayp *track*)
    (multichan-expand #'stereo-delay *track* dur)))
    "Error.\
Stereo track required.")

That works nicely. I like the low-pass version - it sounds like the sound is echoing into the distance.

In the previous version, “stereo-delay” was called with a stereo sound - that is, with an array of sounds, so when the “panning” function was called, it was being passed a stereo sound.
In the latest version, you are calling “stereo-delay” with a mono sound, so when “panning” is called, it is being passed a mono sound. The "panning function then calls the “stereo-pan” function, but the “stereo-pan” function requires a stereo sound.

Where do I change the function? I want to limit the duration with extract-abs.