Nyquist Transformation Environment

… continued from the Nyquist Cookie Monster discussion:



edgar: I’ve started a new discussion here because this will become a rather lengthy topic…

The Nyquist transformation environment is probably the most difficult part of Nyquist to understand and I do not even want to say that I myself have fully understood all the details. Here is what happens inside Audacity, as seen from the Nyquist Lisp level:

;; the Nyquist interpreter starts

(load "../audacity/nyquist/init.lsp")

;; the following values are set by
;; the Audacity Nyquist interface
;; at every start of a Nyquist plugin

(setf s             <sound-from-Audacity-selection>
      len           <number-of-samples-in-Audacity-selection>
      *sound-srate* <sample-frequency-of-Audacity-track>
      *warp*        '(0 <length-of-Audacity-selection-in-seconds> nil))

;; --- Nyquist Plugin Code ---

;; first the variables from the 'control' lines
;; in the Nyquist plugin header are assigned

;; then the plugin code runs

;; --- end of Nyquist Plugin Code ---

;; after the plugin code is finished
;; the 's' sound [or a string or a labels list]
;; is returned to Audacity

I think the main difference between CMU Nyquist and Nyquist in Audacity is that in CMU Nyquist, when the code starts to run, no time and no samples exist, so everything can be set-up from scratch. That’s why things like warp feel much more ‘natural’ in CMU Nyquist than in Audacity, where in most cases samples already exist (at least in ‘process’ and ‘analyze’ plugins) and also warp already has a predefined value, depending on the length of the Audacity selection. In Audacity warp does not equal to 1.0 seconds, instead a warp value of 1.0 equals to the length of the Audacity selection in seconds.

See also Audacity and Nyquist → Nyquist Variables

From the warp perspective, the Audacity Nyquist plugin code is called like:

(stretch-abs <length-of-Audacity-selection-in-seconds>
  ;; plugin-code
)

This way the length of the Audacity selection is applied to the behaviour of all Nyquist functions in the plugin.

I remember very well that I had relly heavy problems in the beginning to make the examples from the ‘Time warp’ and ‘Time stretch’ sections of the Nyquist manual work in Audacity, but maybe there are some better examples to work on? I would like to find a way how the Nyquist ‘warp’ and ‘stretch’ behaviours could be explained more suitable for the work with Audacity, where Nyquist must work under much more restricted conditions than at the CMU.

Any further questions, ideas or examples?

An example from a conversation in another forum thread:

Looking at these two bits of code, one might be tempted to think that they do the same thing:

(setq mysound
(sim s (at 0.5 (cue s))))
(stretch-abs 1 (cue mysound))



(defun mysound (s-in)
(sim s (at 0.5 (cue s-in))))
(stretch-abs 1 (mysound s))

However, they don’t.

In the case of the first code;
If the length of “s” is L, then the length of “mysound” is 1.5(L)
(stretch-abs 1 …) does not stretch the sound to 1 second, it maps each unit of logical time maps to 1 unit of real time.
(Nyquist Functions)
So the logical time is 1.5(L), and mapping each unit of logical time to one unit of real time will produce a length of 1.5(L)

In the second piece of code;
(stretch-abs …) is applied to the (mysound) function, which means that the “0.5” in the (at 0.5 …) function is mapped to 0.5 seconds.
So the length of the returned audio is L + (0.5 seconds)

Attempt of an answer…

Example 1

(setq mysound (sim s (at 0.5 (cue s))))
(stretch-abs 1 (cue mysound))

steve: If the length of “s” is L, then the length of “mysound” is 1.5(L)
(stretch-abs 1 …) does not stretch the sound to 1 second, it maps each unit of logical time maps to 1 unit of real time.

edgar: attempt of an explanation…

;; The first line is computed with the global *warp* time-stretch,
;; where a value of 1.0 equals to the length of the Audacity sound.
;; The start-time of (AT 0.5 ...) will be:
;;   0.5 * <length-of-Audacity-sound>
;; SIM will produce a sound with a total length of:
;;   1.5 * <length-of-Audacity-sound>
;;
(setq mysound (sim s (at 0.5 (cue s))))

;; Here the *warp* time-stretch value to (cue mysound) is 1.0,
;; where the value of 1.0 equals to the length of one second.
;; The (cue mysound) object already has a length of 1.5 seconds,
;; so the sound object returned by (stretch-abs 1 ...) will have
;; a total length of 1.0 * 1.5 seconds.
;;
(stretch-abs 1 (cue mysound))

Until here we have a sound with a total length of 1.5 seconds. But when the 1.5-seconds sound gets returned to Audacity, the build-in STRETCH-ABS in the Audacity Nyquist interface will stretch the 1.5-seconds sound to ‘1.5 * ’, so the effective code from the Audacity perspective works like this:

(stretch-abs <length-of-Audacity-sound>
  (setq mysound (sim s (at 0.5 (cue s)))))

(stretch-abs <length-of-Audacity-sound>
  (stretch-abs 1 (cue mysound)))

That’s why, as the final result, a sound with a length of ‘1.5 * ’ will get inserted into the Audacity track.

The problem here is: Because of the build-in STRETCH-ABS in the Audacity Nyquist interface, to the Nyquist programmer it seems as if STRETCH-ABS produces ‘mysterious’ results when used in Audacity Nyquist plugin code.

To me myself, understanding the effects caused by the build-in WARP and STRETCH-ABS behaviours in the Audacity Nyquist interface was the most difficult part when I tried to find out how to work with Nyquist in Audacity some years ago, but once I understood how this works, the mystery of the Nyquist time behaviours had been disappeared…

Example 2

(defun mysound (s-in)
  (sim s (at 0.5 (cue s-in))))

(stretch-abs 1 (mysound s))

steve: (stretch-abs …) is applied to the (mysound) function,
which means that the “0.5” in the (at 0.5 …) function is mapped to 0.5 seconds.
So the length of the returned audio is L + (0.5 seconds)

edgar: again an attempt of some kind of explanation…

;; The MYSOUND function is called by STRETCH-ABS [below]
;; with a the *warp* time-stretch value of 1.0 seconds.
;; The start-time of (AT 0.5 ...) will be:
;;   0.5 * 1.0 seconds
;; SIM will produce a sound with a total length of:
;;   <length-of-Audacity-sound> + (0.5 * 1.0) seconds
;;
(defun mysound (s-in)
  (sim s (at 0.5 (cue s-in))))

;; Here (stretch-abs 1 ...) stretches (mysound s) to a length of
;;   1.0 * (<length-of-Audacity-sound> + 0.5 seconds)
;;
(stretch-abs 1 (mysound s))

With the ‘defun’ call resolved, the code from the Audacity perspective looks like this:

(stretch-abs <length-of-Audacity-sound>
  (stretch-abs 1 (sim s (at 0.5 (cue s-in))))

Here again, the stretch effect of (stretch-abs 1 …) gets counter-acted by the build-in STRETCH-ABS in the Audacity Nyquist interface.

Considerations

The problem with the build-in WARP and STRETCH-ABS is not so easy as one might think:

When using Nyquist for music composition [that’s what Nyquist was made for] or in Audacity in ‘generate’ plugins, imagine a simple Nyquist code line like:

(osc 60)

A Nyquist programmer expects this code to produce a sound with the exact length of the Audacity selection, but this is only possible if the warp time-stretch value is bound to the length of the Audacity selection, so the resulting sound can be stretched to a fitting length by the build-in STRETCH-ABS function in the Audacity Nyquist interface.

With a warp time-stretch value bound to 1.0 seconds and without the build-in STRETCH-ABS function the code from above would have the effect that the Audacity selection would be changed by the plugin code to a length of one second as soon as the sound gets returned to Audacity, what is clearly not the result that an Audacity user expects from using a Nyquist plugin.

So the build-in WARP and STRETCH-ABS are twofold, they are very useful for music composition and Audacity ‘generate’ plugins, but on the other side you have to be very careful if you try to time-shift parts of an Audacity selection in Nyquist ‘process’ plugins [Audacity ‘Effect’ menu].

The warp variable has a second important purpose, it synchronizes the time behaviour of sounds and envelopes, which in Nyquist have different sample-rates. But this is a different discussion, it has nothing to do with the questions above, but is also important to know and to keep in mind.

Preliminary Conclusion

I think it would be very helpful to develope or document some ‘standard strategies’ for using time behaviours in Audacity ‘process’ plugins. Here are some ideas I used in the past in several plugins.

If you need behaviours in seconds, Roger suggested to use the Nyquist ABS-ENV macro:

(abs-env (osc 60))

This will produce a sine-wave of exactly one second length, but it will also produce the nasty effect of changing the length of the Audacity selection as soon as the sound gets returned to Audacity. But ABS-ENV could help to solve the problems with AT. There are also some other ABS functions like AT-ABS etc., which also must be investigated for their exact behaviour in Audacity.

Warning: the one-second example has turned out to be nonsense, see below…

A way to compute a ‘real second’ with Nyquist in Audacity:

;;      len           (get-duration 1.0)
;;  -------------  =  ------------------
;;  *sound-srate*        *one-second*

(setq *one-second* (/ len (* *sound-srate* (get-duration 1.0))))

If you copy the following code into the text window of the Audacity Nyquist prompt:

(setq *one-second* (/ len (* *sound-srate* (get-duration 1.0))))

(stretch-abs *one-second* (osc 60))

It will produce the same result like ABS-ENV above.[/color]

Any further ideas? What are the most difficult problems in practical Nyquist programming with Audacity?

This probably won’t help you (or anyone) much, but you can input:
(PRINT (LIST WARP))
at the Nyquist Prompt and press DEBUG and you can see the contents of WARP.

From what I know, WARP is just a variable that contains a list/table filled with three pieces of data, two of which are supposedly ALWAYS 0 and NIL (in Audacity), and the other is a/the length of selected audio. You can change this last variable (which is actually the middle data in the list) using the AT command. Still haven’t figured out how doing this helps other functions (such as SIM) “move the audio” or “auto-expand” the timeline or what (QUOTE WARP) does in XLISP, but that’s about it. :cry:

Interesting discussion and thanks for posting a pointer to this. It might help to think of the environment as a set of implicit parameters that are passed to every function. User-defined functions implicitly get the parameters and pass them on to any functions that are called. The environment manipulation functions like STRETCH and ABS-ENV also receive the implicit functions but they manipulate them before passing them on to the enclosed expression. Technically, these “implicit parameters” are more like global variables, but there’s some special support in XLISP so that when you leave STRETCH or ABS-ENV or whatever, the previous value is automatically restored (this is called dynamic scoping). The important thing to remember is that the environment is manipulated before computing audio (you can’t simply make a short sine tone and then stretch it later, you have to know how long to make it going in). Another way to think about this is that if you think of evaluating nested expressions and applying function calls as descending into deeper and deeper levels until you hit a primitive that actually computes data, then the environment is manipulated on the way down, used by the primitives, and then restored on the way back up. It’s not part of signal manipulation but rather setting up (implicit) parameters needed by the signal manipulation primitives (in particular start time and duration).

The previous example of one-second seems odd. Isn’t one-second always equal to 1?

I like the idea of some examples for common situations. It seems like the most common will be

  • How do you turn off the stretch factor and use seconds?
  • If you turn off stretch, how do you retain the original selection length?

This is true at the top level where Audacity invokes your plug-in, but your plug-in can change the environment, so these values may not be 0 and NIL everywhere within your plug-in. You should never use these values directly.

Audacity does not completely respect the Nyquist environment, e.g. when you make a selection, Audacity pretends like the beginning of the selection is at time 0. I’m not sure if this was a wise decision, but that’s how it works. Also, if you return a sound that starts at, say time=1, Audacity will treat the beginning of the sound as the beginning of the selection. This might also be a bad decision, but again, that’s how it works.

One way to experiment with this is to have your plug-in return silence plus something interesting. E.g. (S-REST) will just replace the selection with silence, and (SUM (S-REST) (MY-SOUND)) will add (MY-SOUND) to the silence. This is different from just returning (MY-SOUND) because if (MY-SOUND) starts at 1.0, Nyquist will compute 1.0s of zeros from (S-REST) followed by the shifted sound. You’ll actually see your sound appear at an offset from the start of the selection. To work in seconds, you probably want to do something like: (SUM (S-REST) (ABS-ENV (MY-SOUND))). Note that if (MY-SOUND) extends beyond the selection, Audacity will not truncate the samples but insert them. There are ways to truncate a sound if you want to maintain the selection size, but this post is too long already…

Warning: this is wrong what I had written here, see below…

Unfortunately no, in Audacity 1.0 is always equal to the length of the Audacity selection in seconds, but never to 1.0 seconds, or if, then only by chance. This problem is introduced by the build-in WARP and STRETCH-ABS behaviour and the non-1.0 value is exactly the eternal source of confusion.

In Audacity one-second always must be recomputed from (get-duration 1.0) [the length of the Audacity selection in seconds], LEN [the number of samples in the Audacity selection] and sound-srate [the sample frequency of the Audacity track]. Computing absolute time values in seconds with Nyquist in Audacity is pure horror, because every time value depends on at least three other values.

That’s also exactly the time-shift problem with Nyquist in Audacity.

Examples for time-shift effects

I would be very happy to find a solution, where I can write:

(time-shift start end offset sound) ; or any other argument ordering

where START, END, and OFFSET are either seconds or fractions of the selection-length. The samples from START to END then get time-shifted by the value of OFFSET. This way arbitrary delays could be implemented very easy, where negative time-shifts need special care because Nyquist cannot handle t0 values less than zero [which never appear in music composition].

Another common question is trimming a certain amount of seconds from the beginning, end or both ends of a sound in seconds. This is also a time-shift issue because if you trim sound from the beginning you must time-shift the new start-time backwards to t0.

But I would first like to wait for other effect suggestions…

So if you have (osc 60) in a Generate plug-in the warp time-stretch value is NOT bound to the length of the Audacity selection, but in a Process plug-in it IS bound to the length of the Audacity selection. Is that right?

Shouldn’t that be:

(setq *one-second* (/ (* (get-duration 1.0) *sound-srate*) len))
(stretch-abs *one-second* (osc 60))

not that it matters in this case, as both (/ len (* sound-srate (get-duration 1.0))) and (/ (* (get-duration 1.) sound-srate) len) evaluate to 1,
but if we were to calculate half a second using (get-duration 0.5), then it would need to be
(setq half-second (/ (* (get-duration 0.5) sound-srate) len))


Stretching sounds from the Audacity track?
Something like this?

(setq dur 2.0)

(force-srate *sound-srate* (stretch-abs (/ dur (get-duration 1.0))(sound s)))

Sorry for my nonsense writing: Nyquist in Audacity had been fixed and I haven’t noticed. I had no sound for nearly a year because of eternal Ubuntu problems and I’m obviosly not up-to-date with Audacity. I have added RED NOTES to some of my writing above, which turned out to be WRONG!

I will now re-read the whole stuff again…

Before this starts to become an esoteric meta-discussion [littered with bugs introduced by my own writing] I will sit down and try to write some possibly simple code examples, tested with Audacity CVS HEAD to make sure I will not again warm-up bugs which already had been fixed.

Yes, I think these are the two most important issues.

Counter-question: do you know the Vinal Scratch Tutorial? This would be fun to write an Audacity plugin out of it! Or is there already one from David Sky?

I’ve not seen it as a plug-in, but a direct implementation is probably not that interesting from the standpoint of warp related functions. Most of the interesting stuff is in the (fmosc …) function. It does make some pretty groovy noises though :smiley: (especially if the ‘pch’ parameter is pushed up quite high)

;nyquist plug-in
;version 1
;type generate
;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin"
;name "ScratchSynth..."
;action "Generating weird sounds..."
;info "From 'Vinyl Scratch' tutorial.n"

;control lfo "LFO" real "Hz" 1 0.5 440
;control s-length "Length" real "seconds" 5 1 100
;control p "pitch parameter" real "" 1.2 0.5 10

   (defun ring (s-in dur pch scl)
     (let ((modstep1 (hz-to-step (* (step-to-hz pch) (sqrt 2.0))))
           (modstep2 (hz-to-step (* (step-to-hz pch) (sqrt 11.0)))))
       (stretch dur 
         (mult 
           (env 0.05 0.1 0.2 1 0.6 0.24 1)
           (fmosc pch (mult 
	                (pwl 0.07 1800 0.15 1000 0.4 680 0.8 240 1 100 1) 
		        scl 
                        (osc modstep1)
                        (osc modstep2)))))))

(ring  s s-length (hz-to-step lfo) p)

Possibly a more interesting effect, (and this may be more along the lines of what you were thinking), would be an effect that will “scratch” the sound from the Audacity track (as a ‘process’ effect). It would also be a rather more difficult head scratcher.
David Sky did produce a “TurntableWarp” effect (http://audacityteam.org/download/nyquistplugins ), which would make a good basis for approaching the problem.

Perhaps something like this:

;nyquist plug-in
;version 1
;type process
;name "Scratchin..."
;action "scrathchin..."
;info "Probably best on a short section.nThis version is for MONO only. To use on stereo tracks, split them firstn(or modify the plug-in).nNOT release quality. Expect to get clicks.nn"
;control dummy "This control does nothing" real "" 1 0 1
; Variable Resample function by Roger B. Dannenberg
(defun variable-resample (steps snd)
; p1 helps convert steps to a ratio
  (let ((p1 (/ (log 2.0) 12)) ratio map)
; pitch ratio
    (setf ratio (s-exp (mult steps p1))) 
; map from real-time to sound time
    (setf map (integrate ratio))
(snd-compose snd (force-srate *sound-srate* map))))

(setq dur (get-duration 1))
(force-srate 44100 (stretch-abs 1
(variable-resample 
(pwl 0 0 (* dur 0.1) 0 (* dur 0.2) 12 (* dur 0.25) -24 (* dur 0.3) 0 (* dur 0.35) 0 (* dur 0.4) 12  (* dur 0.45) -24 (* dur 0.5) 0 (* dur 0.55) 0 (* dur 0.6) 12 (* dur 0.65) -24 (* dur 0.7) 0 dur)
(sound s))))

and here’s a little demo:

Several hours later the first usable result:

(time-shift-abs OFFSET SOUND &optional WET)

OFFSET - a time offset in positive or negative integer or floating-point seconds
SOUND - a Nyquist sound object
WET - the volume level of the time-shifted sound between 0.0 and 1.0

The TIME-SHIFT-ABS function time-shifts the sound by an offset in seconds. The function can handle positive time-shifts [to the right] as well as negative time-shifts [to the left] where the returned sound has exactly the same length as the input sound. If applied to the sound in an Audacity selection, the function does not change the length of the selection.

The ‘wet’ parameter is part of the usual ‘dry/wet’ relationship, where ‘wet’ is the volume level of the time-shifted sound and ‘dry’ is the volume level of the original sound. The default for ‘wet’ is 0.5, what equals to 50% original sound and 50% time-shifted sound. The higher the ‘wet’ level, the lower the ‘dry’ level, where the ‘dry’ level gets computed automatically from the value of the ‘wet’ level. A ‘wet’ value of 0.0 or below equals to the original sound only, a ‘wet’ value of 1.0 or above equals to the time-shifted sound only.

Here is the uncommented code for the Audacity Nyquist prompt:

(defun time-shift-abs (offset sound &optional (wet 0.5))
  (let ((dur (get-duration 1.0)))
    (if (or (>= offset dur) (<= wet 0.0))
        sound
        (let* ((start  (if (minusp offset) (abs offset) 0.0))
               (end    (if (plusp offset) (- dur offset) dur))
               (offset (max 0.0 offset))
               (wet    (max 0.0 (min 1.0 wet)))
               (dry    (- 1.0 wet)))
          (sum (scale dry sound)
               (scale wet (at-abs offset
                            (cue (extract-abs start end sound)))))))))

Here is an over-commented version of the same code:

(defun time-shift-abs (offset sound &optional (wet 0.5))
  (let ((dur (get-duration 1.0))
    ;; 'dur' is the duration of the Audacity selection in seconds
    (if (or (>= offset dur) (<= wet 0.0))
        ;; if the time-shifted sound is outside of the Audacity selection
        ;; or if the volume of the time-shifted sound is zero or below
        ;; then we do not need to compute the time-shifted sound
        sound
        ;; otherwise we must compute the complete time-shift
                      ;; if the offset is negative we must
                      ;; cut away samples from the beginning
        (let* ((start (if (minusp offset) (abs offset) 0.0))
                      ;; if the offset is positive we must
                      ;; cut away samples from the end
               (end   (if (plusp offset) (- dur offset) dur))
               ;; the offset must be positive or zero, because
               ;; Nyquist cannot handle negative start-times
               (offset (max 0.0 offset))
               ;; the volume level of the time-shifted sound must
               ;; not be less than zero and not be greater than 1.0
               (wet (max 0.0 (min 1.0 wet)))
               ;; the volume level of the original sound is
               ;; 1.0 minus the volume level of the time-shifted sound
               (dry (- 1.0 wet)))
          (sum (scale dry sound) ; the volume of the original sound
                          ;; shift the sound to the 'offset' in seconds
               (scale wet (at-abs offset
                            ;; we only use the part between 'start' and 'end'
                            (cue (extract-abs start end sound)))))))))

I do not think of this code as ‘perfect’ or ‘finished’, I have written it as a basis for further discussion. Maybe it would be useful to set-up a page with screenshots what I did and why. But first I need some sleep now. For today I say good night folks, see you tomorrow…

  • edgar

Left-overs from yesterday [sorry, it’s a bit jumbled, but I didn’t want to produce another huge text box]:

steve: Question about warp: If you have (osc 60) in a Generate plug-in the warp time-stretch value is NOT bound to the length of the Audacity selection, but in a Process plug-in it IS bound to the length of the Audacity selection. Is that right?

edgar: No, the warp time-stretch value is ALWAYS bound to the length of the Audacity selection, no matter what type of plugin. The only exception is if you choose a ‘generate’ plugin from the Audacity ‘Generate’ menu and there is no Audacity selection, then the plugin creates a new track, where the warp time-stretch value is left to the default of 1.0, as defined in ‘nyquist.lsp’.

steve: Suggestion: stretching sounds from the Audacity track, something like this:

(setq dur 2.0)
(force-srate *sound-srate*
  (stretch-abs (/ dur (get-duration 1.0))
    (sound s)))

edgar: Does in principle the same thing as “Audacity->Effect->Change speed”. Maybe interesting to document how this works with Nyquist, but does the “Change speed” Effect need to be re-invented again? Or maybe you have another idea where this could be used and I haven’t understood the context?

steve: FMOSC makes some pretty groovy noises though…

edgar: FM-synthesis is fun, but also a rather endless topic, we could start another thread about this…

steve: David Sky did produced a “TurntableWarp” effect…

edgar: The Turntable-Warp plugin does in principle the same thing as the Audacity Time-Track. This also does not necessarily to be re-invented again. It would be interesting to find out how Nyquist could be used to create a real “Scratchin” effect, where the sound runs partially backwards, but this would probably need a slow SND-FETCH implementation together with a sample-array buffer because Nyquist cannot compute backwards in time. If anybody is interested in this, please start a new thread…

That’s confused me :confused:
Why is it then that this plug-in always creates a tone of 1 second duration, whether there is a selection or not?

;nyquist plug-in
;version 1
;type generate
;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin"
;name "Tone Generate..."
;action "Generating Tone..."
;info ""

;control note "Frequency" real "Hz" 440 1 1000

(osc (hz-to-step note))

whereas this plug-in will create a tone of length equal to the selection:

;nyquist plug-in
;version 1
;type process
;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin"
;name "Tone Convert..."
;action "Converting to Tone..."
;info ""

;control note "Frequency" real "Hz" 440 1 1000

(osc (hz-to-step note))



I was thinking in terms of more complex effects that need to stretch sounds from the Audacity track, rather than as an effect in its own right. (more of a code snippet than a plug-in).

I like the (time-shift-abs OFFSET SOUND &optional WET) function - a neat solution :slight_smile:

Except that the Turntabe-warp plug-in does what it says on the tin. I’ve never been able to get particularly good results with the Time-Track, there always seems to be a good deal of inconsistency between what the time track says should be happening, and what actually is happening to the sound.
Again I was thinking of this more in terms of code snippets - the “Scratchin” plug-in is basically a recycling of the TurntableWarp effect - or more accurately, another application of Rodger Dannenberg’s “Variable Resample” function.

I notice that the audio sample has not been downloaded yet, but even without the sound going backward (which as you say would probably need a very slow SND-FETCH implementation) I think it produces a reasonable “scratch” type of effect.

steve: Why is it then that this plug-in [see above] always creates a tone of 1 second duration, whether there is a selection or not?

edgar: Looking at “audacity/src/effects/nyquist.cpp”, function “EffectNyquist::ProcessOne()” I see that with Audacity ‘generate’ plugins [represented by the INSERT_EFFECT flag] the length of the Audacity track is defined as zero what has to the consequence that in “audacity/lib-src/libnyquits/nyx.c” in the function “nyx_set_audio_params” the values of Nyquist LEN and warp time-stretch are also initialized with zero. This is clearly an Audacity bug.

steve: [About time-stretch functions] I was thinking in terms of more complex effects that need to stretch sounds from the Audacity track, rather than as an effect in its own right. (more of a code snippet than a plug-in).

edgar: Question: How should a time-stretch handle the Audacity selection? I’m asking because in multi-track situations it’s an crucial issue that a plugin doesn’t change the length of the selection. There must be found a way how to tell the function wether changing the selection is allowed or not.

In this context I remember that around Chrismas a problem was that Nyquist plugins changed the length of the selection by +/-1 sample depending on the mouse position. Has this ever been solved?

steve: I notice that the audio sample has not been downloaded yet…

edgar: I had copied the code directly from the screen because I first had to de-mess it:

;nyquist plug-in
;version 1
;type process
;name "Scratchin..."
;action "scrathchin..."
;info "Probably best on a short section.nThis version is for MONO only. To use on stereo tracks, split them firstn(or modify the plug-in).nNOT release quality. Expect to get clicks.nn"
;control dummy "This control does nothing" real "" 1 0 1

; Variable Resample function by Roger B. Dannenberg
(defun variable-resample (steps snd)
  (let* ((p1 (/ (log 2.0) 12))           ; helps convert steps to a ratio
         (ratio (s-exp (mult steps p1))) ; pitch ratio
         (map (integrate ratio)))        ; map from real-time to sound time
    (snd-compose snd (force-srate *sound-srate* map))))

(let ((dur (get-duration 1)))
  (force-srate 44100 (stretch-abs 1
    (variable-resample
      (pwl 0 0 (* dur 0.1)    0
               (* dur 0.2)   12
               (* dur 0.25) -24
               (* dur 0.3)    0
               (* dur 0.35)   0
               (* dur 0.4)   12
               (* dur 0.45) -24
               (* dur 0.5)    0
               (* dur 0.55)   0
               (* dur 0.6)   12
               (* dur 0.65) -24
               (* dur 0.7)    0  dur)
      (sound s)))))

Have you any idea how a user interface for defining your own PWL breakpoints should look like?

I see how that will explain the behaviour, thanks for the explanation. I don’t understand enough about the Audacity source code to be able to work that out myself, so I assumed it was intentional.

I’ve just tested this in Audacity 1.2.6 and see that (exactly as you described) “the warp time-stretch value is ALWAYS bound to the length of the Audacity selection, no matter what type of plugin”.

There are still some minor peculiarities regarding the first and last samples in the selection, but I think that it has essentially been solved now.

Hmm yes, sorry about the scrawl, it was rather late at night and I wanted to get it posted before bed. :blush: (though I don’t take any responsibility for the layout of the Variable Resample function - I took that straight from here: http://audacityteam.org/nyquist/turntablewarp.ny :wink: )

I actually meant the audio sample “quiet-storm-before-after.mp3”

I’ve been struggling with that question in relation to making an “Envelope” plug-in that is accessible for VIP’s (visually impaired persons).
With the current limitations of the Audacity/Nyquist interface, I think it comes down to either a whole lot of sliders (t1,l1,t2,l2…tn,ln), or text input widget.

Yes, I know, I recognize David-Sky-code from miles away. David wrote his code with a stoneage DOS computer with the help of “WordPerfect” [stoneage text processor] macros. Because he was unable see the result on the screen, it always was an “adventure” to read his code. But it had been lots of fun to work with David.

But now unfortunately some bad news:

I’m sorry to tell but it turns out that in the current Auadcity CVS HEAD the length of the sound returned by a Nyquist plugins is still dependent of the mouse pointer position between two samples when the user selects the sound in Audacity, so Nyquist plugins still destroy the the phase coherence of the Audacity track by chance. The returned sound of Nyquist plugins must be considered as unreliable.

To me it makes not much sense to continue the warp discussion until this bug is fixed. I have started a new thread:

(force-srate 44100 (pwl 1 1 ))

The end of the envelope goes to zero. Is that supposed to happen or is it a bug?

(control-srate-abs *sound-srate* (pwl 1 1))

The end of the envelope is at 1.0