Reading or changing the separate envelope channel from Nyquist

Audacity has support for a separate envelope channel for each track, that is effectively applied as an fx.

How can I read or write the track’s envelope channel from a Nyquist effect (“;type process”) or from a Nyquist macro (“;type tool”)?

Basically, instead of applying a “destructive” fx from a process fx (by returning a new sound), I’d like create (from Nyquist) an envelope that the user can later tweak by hand. This would sort of mimic the workflow approach taken in some fabled “industry standard” software (iZotope RX).

It needs to be a Nyquist Macro.

A limitation of the “delete” option is that it is all or nothing. It is not possible to delete specific points from an envelope. The workaround is to read the envelope points, delete all of them, then re-create the ones that you didn’t want to delete.

See the two plug-ins here:
(They were written quite a while ago, and I’ve not tested since, but hopefully they will still work).

Awesome, thanks. For anyone else interested, the essence is that you can set that from tool plug-ins with SetEnvelope (or even from the Ny prompt with the right header).

;; for testing from a Ny cmd prompt
;version 4
;type tool
(psetq t0 0.3 t1 0.9 v0 1.0 v1 1.0)
(aud-do-command "SetEnvelope" :time t0 :value v0)
(aud-do-command "SetEnvelope" :time (+ t0 0.01) :value 0)
(aud-do-command "SetEnvelope" :time (- t1 0.01) :value 0)
(aud-do-command "SetEnvelope" :time t1 :value v1)

The times are absolute though, i.e. relative to the whole track. Audacity doesn’t have per clip (non-destructive) envelopes, although you can get something equivalent going if you use enough tracks. Or make your Ny macro understand clips and set the envelope surrounding just one (or some) of them. But there’s the issue of what what happens if the user moves the clip manually later.

Also, since macro bits can’t return values, it seems there’s no mirrored GetEnvelope equivalent, but you can do at least from the “Extra > Scriptables II > Get Info”

That will give back in a dialog box e.g.

(((track 0) (clip 0) (start 0) (points(((t 0.3) (y 1))
        ((t 0.31) (y 1e-07))
        ((t 0.89) (y 1e-07))
        ((t 0.9) (y 1)))) (end 8.03399)))

I’m trying to find how do that from a Ny macro. Ok, that’s done with aud-get-info which can actually return something to the Nyquist macro.

Actually Steve’s mute.ny has a function (get-env-level) that parses these and calculates the envelope effect at a given point. :blush:

You can use:

(first (aud-do "GetInfo: Type=Envelopes Format=LISP"))

which returns a string.

or, easier to use:

(aud-get-info "Envelopes")

which returns a LISP list.

Was that an update to your original post, or did I just miss it when I first read it?

If you’re interested in how this works:

(aud-get-info "Envelopes") ; returns a list of lists

Example return value:

(((TRACK 0)
  (CLIP 0)
  (START 0)
  (POINTS (((T 0.991832)(Y 1)) ((T 7.95216)(Y 0.209677))))
  (END 10))
 ((TRACK 1)
  (CLIP 0)
  (START 0)
  (POINTS (((T 0)(Y 0.451613)) ((T 2.3804)(Y 1))))
  (END 4))
 ((TRACK 1)
  (CLIP 1)
  (START 4)
  (POINTS (((T 4.99417)(Y 1)) ((T 9.13069)(Y 0.0322581))))
  (END 10)))

The outer list contains one element for each audio clip:
((clip1-info) (clip2-info) …)

In the “Example return value” we can see that the project contains 3 clips.
Each “clip-info” element contains a series of lists, each with a keyword and a value:
((TRACK val) (CLIP val) (START val) (POINTS val) (END val))

  • TRACK: The track index (starts at 0)
  • CLIP: The clip index (starts at 0)
  • START: The start time of the clip
  • POINTS: A list of envelope points
  • END: The end time of the clip

The list of POINTS is in the form:
(((T val)(Y val)) ((T val)(Y val)) …)
where T is the time coordinate of the point, and Y is the vertical coordinate of the point.

Thus we can step through the envelope points like this:

;debugflags trace

(defun assoc-val (key a-list)
  ;; Find key in a-list and return associated value
  (second (assoc key a-list)))

(let ((envelopes (aud-get-info "Envelopes"))
      points p tracknum)
  (dolist (clip-info envelopes) ;step through clips
    (setf points (assoc-val 'POINTS clip-info))
    (setf tracknum (assoc-val 'TRACK clip-info))
    (dolist (p points)  ;step through points in current clip
      ; Print point to debug window
      (format t "Track: ~a   Time: ~a   Value: ~a~%"
              (assoc-val 'T p)
              (assoc-val 'Y p))))
  "") ;return empty string as no-op