Expression Generator

Here’s a plug-in written in response to this forum topic: https://forum.audacityteam.org/t/generating-f-x-type-wave-forms/45194/1
The idea of the plug-in is that an arbitrary function “f(x)” may be entered, and the plug-in will generate a waveform by evaluating the expression for a given range of “x”.

This version of the plug-in takes its default expression from dmonty’s initial enquiry:

x^3 * e^(sin ( x * 3)) * 0.00001

I’m sure some user’s would like to be able to enter the expression in this familiar arithmetic form, but I’ll leave that for someone else to write. To use this plug-in, the expression must be written as a LISP S-Expression. This allows us to use Nyquist’s built-in evaluation function rather than having to write a whole new parser. Taking the example above and writing it as a Nyquist / LISP expression:

(* x x x (power (exp 1.0) (sin (* x 3))) 0.00001)

Some things to note:
Euler’s number “e” is not defined in Nyquist, but can easily be derived using the EXP function.
For x^3, we could write (power x 3.0) but as we are also performing multiplication, it is as easy (and a bit shorter) to simply multiply three x’s.

A plot of this expression can be created with WolframAlpha
https://www.wolframalpha.com/input/?i=plot+x%5E3++e%5E(sin+(+x++3))+*+0.00001,+x%3D0+to+33
wa.png
and with the Expression Generator plug-in:
firsttrack000.png
and here is the plug-in:
ExpressionGenerator.ny (1.6 KB)
Installation instructions are as usual: http://manual.audacityteam.org/man/effect_menu.html#nyquist_effects
For more information about Nyquist, see: http://wiki.audacityteam.org/wiki/Nyquist

1 Like

Thought it might be useful to add some examples.

1) Generate a single cycle sine tone:
A sine tone is defined by the function (SIN x).
In Nyquist, the “x” value is in radians, so for a single cycle we need values of x to go through 2xPI radians.
2xPI is about 6.283185307
fullwindow-Expression Generator-000.png
Alternatively, if we want to reverse the phase (offset the phase by 180 degrees), we can use values of x from -3.141592654 to +3.141592654


2) Generate a 440 Hz tone for 1 second:
Rather than having to work out how many radians x needs to go through, we can simply make x go through the desired number of cycles (440), and enter the expression

(sin (* 2 pi x))

fullwindow-Expression Generator-001.png
and one more example, for values of x from 0 to 1:

(* 0.5 (+ 1 (sin (* (+ 0.75 x) 2 pi))) (sin (* 880 pi x)))

I’ve tried your ExpressionGenerator with tan …

(* x x x (power (tan x) (sin (* x 300))))

Upper trace created by ''ExpressionGenerator'' is displayed with spurious intermittent rectangles, (which do not survive export, the lower trace).png
The waveform displayed has intermittent spurious rectangles, (the upper trace shown).
However when that waveform is exported and re-opened in audacity the rectangles are gone, (the lower trace).

( Also the play-at-speed button

produces no sound on the original generated waveform,
but works OK when generated waveform is exported and re-opened in Audacity ].

What happens when x = PI/2 ?
What do you think ‘should’ happen when x = PI/2 ?


Just seemed odd that when exported then re-opened the display and playback were OK.
value must have crashed the rendering of the waveform, (to produce the rectangles glitches).

(sin (tan (/ x)))

bouncing ball-ish.png
'bouncing ball-ish'.png

(* .5 (abs (cos (/ 100 x ))))

'(abs (cos '.png
(abs (cos.png
What’s the full list of functions & operations we have to play with ?

Tan(PI/2) is “undefined”. It is neither +∞ or -∞. It is “not a number” (a “NaN”), and that is the problem. Audacity does not handle NaNs very well (but better now than in older releases). It’s the NaNs that cause the corruption. When exported, the NaNs are replaced by INF or -INF, which Audacity handles better.

Just about everything here: Index
provided that the expression returns a number (for the sample value).

One thing to watch out for: If you apply an arithmetic operator to integers, then integer arithmetic is used. If you want a fractional (floating point) result, then either one of the numbers must be a floating point number, or you must explicitly convert the number to floating point:

(setf *float-format* "%f") ; number format for debug output

(print (/ 1 4))         ; returns integer 0
(print (/ 4))           ; returns integer 0
(print (/ 1.0 4))       ; returns 0.25
(print (/ 4.0))         ; returns 0.25
(print (/ 1.0 4.0))     ; returns 0.25
(print (/ 1 (float 4))) ; returns 0.25
(print (/ (float 4)))   ; returns 0.25
(print (/ (float 1) 4)) ; returns 0.25
(print (float (/ 1 4))) ; returns float 0.0

Add atan to the list …

(* (atan (/ (* x x))) (cos (* 100 x x))))

like tuning analog radio.png
'like tuning analog radio'.png

There are also some constants available:

pi = 3.14159265…
t = true
nil = false
sound-srate = the track sample rate
control-srate = 1/20th of the track sample rate
dur = the specified duration in seconds

Are there any additional features that you think would be useful / interesting?

Most of the Nyquist plug-in “Property Lists” should also work.

White noise:

(- (rrandom) 0.5)

This is awesome! Thanks Steve.

Truncate can work …

(* (truncate x) (sin (* x 100 (truncate x))))

chewy.png
'Chewy'.png

Conditional expressions:

(if (< (rem (truncate (* dur 10 x)) 10) 5) 0.8 -0.8)

from 0 to 100
firsttrack000.png

New Audacity user here and this is my first post.

This is an awesome plugin! I’ve made some simple waveforms, but I’m trying to go more wild now.

I’m trying to convert the following equation:

sin^3 x

Which I’ve expanded to:

1/4 (3 sin(x) - sin(3 x))

But since I’m a complete newbie to LISP S I seem to get it wrong. This is what I think it should be:

* 0.25 (- ((3 (sin x)) (sin 3x)))

Any pointers in the right direction is highly appreciated!

I don’t currently have the plug-in installed, but try this:

(* 0.25 (- (* 3 (sin x)) (sin (* 3 x))))

If that doesn’t give you the expected result, let me know and I’ll install the plug-in to check.


The “rule” for S-Expressions is:

  • open parenthesis
  • function name
  • arguments
  • close parenthesis

Thus the expression:

1/4(sin(3x))

becomes:

(* (/ 1.0 4) (sin (* 3 x)))

or more simply written:

(* 0.25 (sin (* 3 x)))

Normally when writing in LISP (s-expression) syntax, line breaks and indentation are used to make long expressions more readable, but unfortunately Nyquist plug-ins don’t have a multi-line text input widget.