OK, so that’s not actually a “random sequence”, it’s a “permutation” of specified values, or in other words it is a given list that is “shuffled”.
Rather than generating the tones and then shuffling them (which would involve moving around a lot of audio data), it’s easier to just create a list to represent the levels, shuffle that list, then read the amplitudes sequentially from that shuffled list when we generate the audio.
So far we have code that looks something like this:
;version 4
;type generate
(defun tone ()
"Generates a 1000 Hz tone"
(mult (osc (hz-to-step 1000) 0.25)
(pwlv 0 0.02 1 0.23 1 0.25 0)))
(defun rest ()
"Generates between 1.8s and 2.8s silence"
(s-rest (+ 1.8 (rrandom))))
(defun gain ()
"Random number 0 to -45 in steps of -5"
(db-to-linear (* -5 (random 10))))
;; Generate a tone and repeat x200 with
;; randomised spacing and gain
(let ((tone (tone)))
(seqrep (i 200)
(seq (rest) (cue (mult (gain) tone)))))
Note that in the final line we have: (cue (mult (gain) tone))
We need to replace that with a tone that gets it’s amplitude from a shuffled list, so for clarity we can create a new function to get the next tone. In fact, on reflection, it may be easiest to write a function that creates our “silence-tone” pair:
(defun get-next-note ()
;some code here to generate the
;silence-tone pair
)
;; Generate a tone and repeat x200 with
;; randomised spacing and gain
(let ((tone (tone)))
(seqrep (i 200) (get-next-note)))
So, before we move on, what code do we need to put into the new “get-next-note” function to make it functionally the same as the code at the beginning of this post?
We could try something like this:
(defun get-next-note ()
(seq (rest)
(cue (mult (gain) tone))))
but Nyquist will complain that the variable “tone” is not defined.
We defined the variable “tone” in our “let” statement, but it is currently local to that “let” block, so our “get-next-note” function does not know that it exists.
To solve that, we need to pass the sound “tone” to the “get-next-note” function, and we do that by supplying it as an “argument” of the function.
See here for details - this is a very important feature of LISP functions: XLISP defun
Here’s the rewritten code. Try it out and ensure that you understand how it works, then we can move on to the next part, which is replacing the “rrandom” function with a “shuffle” function. I think we will need to write the “shuffle” function ourselves as I don’t think that Nyquist has one built in.
;version 4
;type generate
(defun tone ()
"Generates a 1000 Hz tone"
(mult (osc (hz-to-step 1000) 0.25)
(pwlv 0 0.02 1 0.23 1 0.25 0)))
(defun rest ()
"Generates between 1.8s and 2.8s silence"
(s-rest (+ 1.8 (rrandom))))
(defun gain ()
"Random number 0 to -45 in steps of -5"
(db-to-linear (* -5 (random 10))))
(defun get-next-note (tone)
"Generate a 'rest-tone' pair"
(seq (rest)
(cue (mult (gain) tone))))
;; Generate a sequence of 200 notes.
(let ((tone (tone)))
(seqrep (i 200) (get-next-note tone)))