Help for simply copy paste a selection.

Hello, I want to make a plugin to copy a selection of a track and paste it in the next track in the same position. But I want to do it just by pressing a key (associated with a plugin).
But I can not find the right command to use the copy / paste functions.
I know it has to be simple, few lines of language xlisp.
I studied some lisp when I used autocad for years, but with Nyquist, something as simple as copy / paste I do not know how to face it.

I’m sorry for my English.
A greeting.

It is possible to make a Nyquist plug-in to copy and paste from one track to the next, but it is quite tricky because Nyquist plug-ins process tracks sequentially and Lisp variables are reset when processing a track is complete. This means that the copied region must be stored somewhere that can survive beyond the processing of that track.

One option is to use the special Nyquist variable SCRATCH. This variable is unique in that it survives in memory after the Nyquist instance finishes.

In the simplest form, you cans test the value of SCRATCH to the selected audio when the plug-in processes the first track, and then return the value of SCRATCH when the plug-in processes the second track. This is not the recommended way for public release plug-ins as it could lead to plug-ins overwriting data required by other plug-ins, or reading data put there by unrelated plug-ins. The recommended way is to use “property lists”, and save data as a uniquely named property. (more information HERE). Nevertheless, setting the value of SCRATCH is quick and easy for an experimental plug-in.

Another problem is that internally, Nyquist uses pointers. In this case, we want SCRATCH to point to the audio data of the first track, but normally the audio data in track is cleared when Nyquist has finished processing the track, so this will not work:

(if (not (boundp '*scratch*))
    (setf *scratch* *track*)
    *scratch*)  ; returns nil audio because *track* was cleared.

So we need to ensure that the audio data from track is retained in memory.
An easy way to do this is with SND-LENGTH

So this will work once:

(if (not (boundp '*scratch*))
  (progn
    (setf *scratch* *track*)
    (snd-length *scratch* ny:all)
    "") ;Null string return value
    *scratch*)  ; returns the audio from *scratch*

but will fail on subsequent runs because we have left *scratch" with Null audio after the second track. We need to reset the plug-in after the second track.
To clear scratch we can set it to 'unbound

(setf *scratch* '*unbound*)

(do this before proceeding)

So putting this altogether:

(if (not (boundp '*scratch*))
  (progn
    (setf *scratch* *track*)
    (snd-length *scratch* ny:all)
    "") ;Null string return value
  (progn
    (setf rval *scratch*)
    (setf *scratch* '*unbound*)
    rval))

Note that this does not have any error checking, and it is not the recommended way to use scratch, but hopefully it will get you started.
Also note that as the selected audio is retained in RAM, this is not suitable for very long selections.

Hi, thanks steve. I did not think that such a simple action would have so many problems.
I tested it on the Nyquest promt and it worked, but only once, it never worked again.
I have tried before to clean the variable scratch * with (setf * scratch * '* unbound *) but it still does not work.
It seems like the scratch variable is not cleaned

With any kind of programming, you have to be very precise.
It is not:

* scratch *

it is:

*scratch*

Same goes for

'*unbound*

To check if scratch is bound to a value or not, enter this in the Nyquist Prompt and click the Debug button:

(print *scratch*)

If scratch is bound to a sound, even a Null sound, the debug window will show something like:

#<Sound: #373b2e0>

If scratch is not bound to any value, the debug window will show:

error: unbound variable - *SCRATCH*

the debug show :
error: unbound variable - SCRATCH
if continued: try evaluating symbol again
1> error: unbound variable - SCRATCH
if continued: try evaluating symbol again
1>

The debug info if use the code:

error: unbound variable - *TRACK*
if continued: try evaluating symbol again
Function: #<FSubr-SETF: #a955fa8>
Arguments:
  *SCRATCH*
  *TRACK*
Function: #<FSubr-PROGN: #a95b378>
Arguments:
  (SETF *SCRATCH* *TRACK*)
  (SND-LENGTH *SCRATCH* NY:ALL)
  ""
Function: #<FSubr-IF: #a95aa68>
Arguments:
  (NOT (BOUNDP (QUOTE *SCRATCH*)))
  (PROGN (SETF *SCRATCH* *TRACK*) (SND-LENGTH *SCRATCH* NY:ALL) "")
  (PROGN (SETF RVAL *SCRATCH*) (SETF *SCRATCH* (QUOTE *UNBOUND*)) RVAL)
1> error: unbound variable - *TRACK*
if continued: try evaluating symbol again
Function: #<FSubr-SETF: #3ccdcb0>
Arguments:
  *SCRATCH*
  *TRACK*
Function: #<FSubr-PROGN: #3cd3080>
Arguments:
  (SETF *SCRATCH* *TRACK*)
  (SND-LENGTH *SCRATCH* NY:ALL)
  ""
Function: #<FSubr-IF: #3cd2770>
Arguments:
  (NOT (BOUNDP (QUOTE *SCRATCH*)))
  (PROGN (SETF *SCRATCH* *TRACK*) (SND-LENGTH *SCRATCH* NY:ALL) "")
  (PROGN (SETF RVAL *SCRATCH*) (SETF *SCRATCH* (QUOTE *UNBOUND*)) RVAL)
1>

Are you using the current version of Audacity? The current version is 2.2.2
If you’re using an older version, get the current version from here: https://www.audacityteam.org/download/

Also, ensure that the “Use legacy (version 3) syntax” option is not selected in the Nyquist Prompt (that’s only for compatibility with old code).

i am using version 2.2.2
in Nyquist promt i disable “Use legacy (version 3) syntax” and now work. :wink:

In Nyquest pluguin format dont work, i need to define "use legacy " or similar in the header?

 ;nyquist plug-in
 ;name "Copy-Paste"
 ;type process
 ;version 1
(if (not (boundp '*scratch*))
  (progn
    (setf *scratch* *track*)
    (snd-length *scratch* ny:all)
    "") ;Null string return value
  (progn
    (setf rval *scratch*)
    (setf *scratch* '*unbound*)
    rval))

Change that to:

;version 4

i change to version 4, and dont work. I test 1, 2 ,3 and 4
A curious thing happens, after trying to use the plugin version (it does not work), if I use the Nyquest version, copy the selection of the track from below to the one above.

Hi, i solve the problem change header type to Generate, and now work fine.
The use of the plugin is to copy the voices of a central speaker track from one language to another language, respecting the background audio to synchronize with the rest of the channels (L, R, LFE, SL and SR)
Thanks so much for the help

 ;nyquist plug-in
 ;name "Copy-Paste"
 ;type Generate
 ;version 4
(if (not (boundp '*scratch*))
  (progn
    (setf *scratch* *track*)
    (snd-length *scratch* ny:all)
    "") ;Null string return value
  (progn
    (setf rval *scratch*)
    (setf *scratch* '*unbound*)
    rval))

hi steve i update audacity to versión 2.3.0 and the pluguin dont work fine.
Sometimes copy the sellection of the track from above to the track below, other times it does the reverse. Other times it does nothing or makes a small displacement.
Would it be possible to tell him to always copy the selection from track 0 to track 1?
Would it be possible to make this plugin using Macros in this new version?
A greeting.

It works fine for me.
It also works fine for me as a “;type process” plug-in, provided that there is an audio selection when pasting.

I do notice that there is no error checking in this plug-in, so the results may not be what you expect if you don’t mentally keep track of whether you car copying or pasting, or if you select multiple tracks, or if you select a stereo track (the plug-in does not support stereo tracks).

Please remind me why you want this as a plug-in. What is the purpose of it? Why not just use “Ctrl + C” to copy and “Ctrl + V” to paste?

the base of this plugin is to be able to copy the voices of a track and paste them in the same position in the track below. But this has to be done hundreds of times, that’s why CTRL + C and CTRL + V is something tedious.
The plugin fails many times and I do not understand why.
With the new version of audacity I have been able to create something similar using macros, much more stable.

This is the sequence of the macro:

SelSave:
ShiftUp:
Copy:
ShiftDown:
SelRestore:
Paste:

I can think of a couple of reasons:
Wrong number of tracks selected (the plug-in expects exactly 2 audio tracks)
One or more stereo tracks selected.
Insufficient free memory.

For that specific job, this version should be more reliable as it has some error checking. It also supports stereo tracks, and is probably more efficient:

;nyquist plug-in
;name "Copy-Paste"
;type process
;version 4

(cond
((/= (length (get '*selection* 'tracks)) 2)
  (setf *scratch* '*unbound*)
  "Clipboard cleared.\nTo copy from one track to another, select 2 tracks.")
((= (get '*track* 'index) 1) 
  (setf *scratch* *track*)
  (multichan-expand #'snd-play *track*)
  "")
((= (get '*track* 'index) 2)
  (if (and (arrayp *scratch*)(soundp *track*))
      (setf rslt (mult 0.5 (sum (aref *scratch* 0)(aref *scratch* 1))))
      (setf rslt *scratch*))
  (setf *scratch* '*unbound*)
  rslt))



Yes, a macro is probably better for this task.

Hi, the new pluguin work fine too. It necesary select the 2 tracks (copy-paste de audio) but work fine.
the two solutions are equally valid. Thank you so much.