Help creating simple plugin

In my experimentation with Audacity, I have long sought a method of reducing that harsh, ear-drilling sound of listening to headphones versus speakers. A simple delay of specific nature has satisfied this purpose. It still sounds like headphones, but it creates a sense of air and separation.

I want to create a Nyquist plugin, and I know exactly what the user-adjusted variables and effects will be, but I do not how how to administer it.
I would call it “Headphone satisfaction”, tentatively

The procedure is as follows:

  1. The main stereo track is duplicated, and the channels reversed.
  2. This track is delayed by 20-60 ms, as a “Width” setting that will cause a muddy sound if brought too high.
  3. The track is then low-passed at 200-2000 hz as a “Tightness” setting that causes audible phase issues if too high
  4. The track is then attenuated by 0-10 dB, as a “Strength” setting: less attenuation, more strength

These tracks are mixed in to form the final output.

Some quick hints (not much time yet):

1. Reverse the stereo channels:

;; (aref s 0) = left channel
;; (aref s 1) = right channel
(vector (aref s 1) (aref s 0))

2. For a delay function with a fixed time in (milli)seconds see the time-shift-abs function.
3. Far a lowpass filter see the “lp” function in the Nyquist manual.
4. For attenuation by -10 dB see the “scale-db” function in the Nyquist manual.

HTH - edgar

If you’ve not found them yet, here’s some useful links:

http://audacityteam.org/help/nyquist
http://wiki.audacityteam.org/wiki/Nyquist_Plug-ins_Reference
http://www.cs.cmu.edu/~rbd/doc/nyquist/
http://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/xlisp/xlisp-index.htm

And a rough bit of code that you can run in the Nyquist Prompt effect:

(setq delay 30) ; milliseconds
(setq freq 1000) ; Hz
(setq atten -10) ; dB

(setq delay (/ 30 1000.0)) ; convert to seconds
(setq atten (db-to-linear atten)) ; convert to linear

(let ((delay-snd (vector (aref s 1)(aref s 0))))
   (sim (cue s)
      (at-abs delay (cue
         (scale atten
            (lp delay-snd freq))))))

To convert this into a plug-in you need to add the Nyquist Plug-in header and change the first three lines into ;control widgets, for example:

;control delay "Delay Time" real "milliseconds" 30 20 60

You may also want to add in some error checking to avoid silly values being typed into the plug-in and to ensure that a sensible error message is produced if the effect is applied to a mono track.

Okay, so I added in the controls

;control delay "Width" real "ms" 30 10 100
;control freq "Tightness" real "hz" 1000 200 2000
;control atten "Strength" real "dB" -4 0 -12

(setq delay 30) ; milliseconds
(setq freq 1000) ; Hz
(setq atten -10) ; dB

(setq delay (/ 30 1000.0)) ; convert to seconds
(setq atten (db-to-linear atten)) ; convert to linear

(let ((delay-snd (vector (aref s 1)(aref s 0))))
   (sim (cue s)
      (at-abs delay (cue
         (scale atten
            (lp delay-snd freq))))))

I don’t know how to make an error occur if applied to a mono track, though. The list of error handling operations is way too thick, and I don’t even know if they are what I need to be doing.

Your ;control lines look right, but you will need to remove the three lines below the ;control lines.
The ;control lines allow the user to enter values for the variables “delay”, “freq” and “atten” (via slider widgets), but the next three lines will then set those same variables to 30, 1000 and -10 respectively, thus overriding the user settings.

You will also need to add the rest of the Nyquist header for it to work as a plug-in.

For error checking you need to use a structure like:

IF PRINT (otherwise)
(look up “IF” in the XLisp manual for examples. You could also look at some of my plug-ins that are on the wiki - most of them include some sort of error checking)

If you look up Predicate Functions in the XLisp manual you will see a list of functions that can be used to check if something is true or not. In the case of checking for a stereo track, a stereo track is an array containing two sounds (the left and right channels). This means that we can check to see if the “s” variable is an array or not. If it is an array, then we know that the track is stereo.

Something like:

(if (arrayp s)
  (progn
    ........
    ........
; this is the program
    ........
    ........)
   (format nil "Error.nThis effect requires a stereo track"))

Let me take a wild stab at this:

;control delay "Width" real "ms" 30 10 100
;control freq "Tightness" real "hz" 1000 200 2000
;control atten "Strength" real "dB" -4 0 -12

(if (arrayp s)
  (progn (setq delay (/ 30 1000.0)) ; convert to seconds
(setq atten (db-to-linear atten)) ; convert to linear

(let ((delay-snd (vector (aref s 1)(aref s 0))))
   (sim (cue s)
      (at-abs delay (cue
         (scale atten
            (lp delay-snd freq)))))))
   (format nil "Error.nThis effect requires a stereo track"))

Rather than just taking a “wild stab”, if you add the Nyquist Plug-in header you can put it into your Audacity plug-ins folder and test it.

(setq delay (/ 30 1000.0)) ; convert to seconds

This line is intended to convert the value of “delay” from milliseconds to seconds by dividing the value by 1000.0
However, as it is currently written it will always set “delay” to 0.03
The correct line should be:

(setq delay (/ delay 1000.0))

There’s also a problem with the “Strength” control.
The correct format for the control should be:
;control var-name text-left real text-right initial-value minimum maximum

In your ;control line the “minimum” value for the variable “atten” is set at “0” whereas you really want the minimum value to be some negative number, such as:

;control atten "Strength" real "dB" -4 -48 0

Here I’ve set the minimum value to -48 and the maximum to 0.

The code that tests for stereo tracks looks right.