Scope/life time of *scratch* and appending to it

Hi Steve,

Several (related) questions about the scratch variable:

  1. What is it’s lifetime, i.e. is it “alive” as long as one or more instances of Audacity is open?

  2. Can it hold only audio data or an array of text?

  3. Can I append data to scratch and not just overwrite existing data?

  4. If the above are possible, could I for example do this, all in the same instance of Audacity:

4a) Apply a ny plugin to a track that adds text data to scratch.
(That text could be for example the peak value of the track).

4b) Apply the same plugin to another track and append that data to scratch.

4c) Rinse and repeat, then,

4d) Say on the third track, append yet more data, but, also save the data in scratch to a file
so that all the data written will be from all the times the plugin was called, assuming of course
Audacity was not closed in between.

So for example something like the below (just a rough drawing to better illustrate what I mean):
If just the append option is selected, then it only appends to scratch.
If both are selected, it will append and then save it to a file.
Screen Shot 2021-11-03 at 8.42.17 PM.png
I know that Nyquist has very limited support for file browsing, so a hardcoded path and file name is OK.


Had some free time today, so went back to this.
As it turns out, quite easy to do all of the above.

Just need two “key” functions, namely:

strcat, and

(open out-path :direction :output)
— write data to file, then
(close FP)

Yes it should be “alive” until you quit Audacity.

Yes, but holding audio is tricky. See the Punch Copy / Paste plug-ins for an example.
Holding an array of text is no problem.

To append, “get” the data on scratch, append the new data, and then “put” the new (appended) data onto scratch.

4) Have you seen the scratch tutorial?*SCRATCH*_Tutorial

Thanks Steve.
Since Nyquist does not have an append function,
I used:

; to append
(setf *scratch* (strcat *scratch* "some text"))

; to clear
(setf *scratch* "")

Just putting text in scratch is fine but adding lists is even more handy.

In recent versions of Audacity there is a macro: STRING-APPEND
Example usage:

(setf data "hello")
(string-append data " world")
(print data)  ;prints "hello world"

(This macro might not be documented yet, but you can see the code for the macro here:

Thank you Steve.
Another one for my misc.lsp :smiley:

(defmacro string-append (str &rest strs)
  ;;; Append one or more strings to 'str'
  `(setf ,str (strcat ,str ,@strs)))

Where is this located? I can’t find it neither shipped with Audacity nor on the wiki unless it’s been renamed to something I can’t guess.

Something like

;version 4
;type process

(putprop '*SCRATCH* (snd-copy *track*) 'sample) 

"Sample stored in *SCRATCH*"

Doesn’t actually work. If I try to paste that form a 2nd plugin, it just gets zeros. No error is reported.

;version 4
;type process
(mult 2.0 (get '*SCRATCH* 'sample)) ;; gets zeroes

I’m guessing I have to read it in and force it to memory with snd-fetch-array?

Punch Copy / Paste is here on the forum:

So, I’m looking at the punch/paste code, but I don’t understand what I’m doing that’s different. Punch copy (which is a v3 plugin) does

(putprop '*scratch* s left)

where left is generated as

(setq left (propgen "left" id))

But that can’t be the difference that matters.

I see now the real deal is someplace else

    ; must reference sound in output so that sound in *scratch* is not cleared

And then it forces the sound to be read with snd-length. I guess I should try that.

Yeah, that was it. So minimally working example for copy-to-scratch is

;version 4
;type process

(putprop '*SCRATCH* (snd-copy *track*) 'sample) 

; reports length to user & forces copy retention!
(snd-length *track* 100000000)

Paste (with amplification) needed no change:

;version 4
;type process
(mult 2.0 (get '*SCRATCH* 'sample))

Although this will not release the sample. Meaning one can paste it again.

I think I know why it has to be like that. The Audacity callback that actually gives Nyquist the samples (StaticGetCallback) gets invalidated on a 2nd plugin run. So it’s a “use it or lose it” situation, i.e. the samples have to be acquired by Nyquist from Audacity before another plugin run begins.