Concatenating sounds with Nyquist


I’m brand new to Nyquist, I hope somebody can help me with this.

I have a sample and I want to chop it into small pieces, say 0.1s, and apply an effect to each piece with varying intensity, then concatenate them all together again.

I understand that the nyquist script’s last return value will become the output, and I know how to apply my effect to the entire sample, for eaxmple:

(lp x *track*)

will apply a high-pass at value x on the whole sample, and extract-abs extracts part of my sample, so I can define a variable and put it in there:

(extract-abs 1 0.1 *track*)

Will extract a 0.1s sample starting at 1s into my original sample, putting these 2 together, I can do

(defvar snippet (extract-abs 0 0.1 *track*))
(lp x snippet)

to apply the filter to my 0.1s snippet, I just need to be able to copy this 0.1s of processed data, and place it in a buffer, or create a blank sample and concatenate a series of snippets together, or overwrite the original sample in-place, the problem is I don’t know how to do this.

I think I have a basic handle on loops, so I don’t need a complete solution, I just need something for either copying sample data or concatenating samples together.

Thanks for any help

The short answer is:
Use either SEQ, SEQREP, or SIM and AT.

Longer answer:
This is a one of the trickier things to do with Nyquist, especially getting your head around the idea of “behaviours” and how Nyquist handles “logical time”, but I’ll try to give some helpful hints.

A few comments -

EXTRACT-ABS will indeed allow you to extract sections of a sound, but beware of long sounds. The entire sound will be loaded into RAM.

DEFVAR is a macro and is provided to simplify porting code from Common Lisp to XLISP. XLISP does not have different concepts of ‘variables’, ‘parameters’ and ‘constants’. In XLISP they are all variables, so you can simply use SETF. (DEFVAR was not included in early versions of Nyquist, but it is now).

The most concise solution is to use SEQREP, but if there are hundreds of sections this could give a stack overflow error. If you have a very large number of sections, then concatenating in a DO loop with SIM and AT is the better solution.

One warning about using SEQREP: don’t try to use var as a counter as that will not work.

Note that both SEQREP and AT are expecting a “behaviour” rather than a “sound”.
I think the simplest way of thinking about behaviours vs sounds is to think of nouns and verbs, where a “sound” is by analogy a noun, and a “behaviour” is by analogy a verb. A “sound” is a “value” of type SOUND, whereas as “behaviour” is something that may produce a sound.

If you have a sound when you need a behaviour, use the function CUE.
If you don’t use CUE, the code will probably still work, but will produce warnings.

Here’s a small example using a DO loop:

(defun getclip (t0)
  ;; Return a 1 second section of *track* starting at time=t0.
  (extract-abs t0 (1+ t0) *track*))

(setf dur (get-duration 1)) ;duration of the selection

(let ((output (s-rest 0)) ;initialise output as a sound, length zero
  (do ((i 0 (1+ i))
       (j 0 (+ j 2)))
      ((> j dur) output)  ;end when j>dur and return output
    ;; get the next clip
    (setf newclip (getclip j))
    ;; Set the logical stop time of the new clip
    (setf newclip (set-logical-stop (cue newclip) 1.0))
    ;; Add the new clip to the output sound
    (setf output
        (sim output
          (at-abs i (cue newclip))))))

For another example, look at rhythmtrack.ny (included in Audacity’s plug-ins folder).

Hi Steve, thanks for the detailed answer.

I have been experimenting with seq / seqrep and actually just opened the exact file you mentioned - rhythmtrack.ny

I will try your loop example.