Adding randomized silence (Windows 10, Audacity 2.1.3)

Sure, you just need to modify

(* -5 (+ 1 (random 10)))

Looking at the documentation: Appendix 3: XLISP: An Object-oriented Lisp

(random n)
[LISP] – compute a random number between 0 and |n|-1 inclusive.
If n is 0, return 0.
n – the upper bound (integer)
returns – a random number

Can you work it out from that?

I think I figured it out :slight_smile:

(* -5 (+ 0 (random 10))))))

Thanks a lot :slight_smile:

Yes that will give you a maximum value of “0”, and the minimum (most negative) is -5 x 9 = -45 (I don’t recall, did you want -45 or -50?) but you don’t really need to add “0”:
(* -5 (random 10))

I wanted just -45 dB :slight_smile: Thanks once again for all of your help :slight_smile: I really want to make it up to you somehow :slight_smile:

Your welcome.
I think we’re done so I’ll close this topic now.

Audacity 2.1.3
Hi :slight_smile: I’m deeply asking for help once again in reference to the topic from this post https://forum.audacityteam.org/t/adding-randomized-silence-windows-10-audacity-2-1-3/46301/18 . Is it possible to force in the code that all of this randomized tones (multiples of 5 dB) appear exactly 10 times each ?

[Topic re-opened and new topic merged]

Do you mean, 10 occurrences any -45 dB, 10 at -40 dB … and so on up to 0 dB, so 100 tones total?
If so, do you mean that there should be 10 sequences of 10 tones, in which each tone is at one of the defined dB levels, or do you mean 100 tones, 10 at each level, jumbled up into one random sequence of 100 tones?

It would probably help if you told us the purpose of this, then I might understand more clearly what you want.

Exactly :slight_smile:

That is what I exactly mean :slight_smile:

Purpose of this is an experiment which I conduct with my academic and we measure reaction time from tones occurences. It’s kind of student research group.

And I have one another question :slight_smile: is it possible to incorporate in code randomized occurence of tones at 2 frequencies in this earlier given terms ?

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)))

Here’s a long-winded implementation of the Fisher-Yates shuffle algorithm.
For details about the algorithm, see: https://en.wikipedia.org/wiki/Fisher–Yates_shuffle

Try this out and see how it works. We can tidy this code later and make it a lot cleaner.

;; Fisher-Yates_shuffle (modern algorithm)
;; From: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
;;
;; -- To shuffle an array a of n elements (indices 0..n-1):
;; for i from 0 to n-2 do
;;      j <- random integer such that i <= j < n
;;      exchange a[i] and a[j]


;Create a list
(setf amplitudes (list 0 1 2 3 4 5 6 7 8 9))
(print amplitudes)  ;print it
(terpri)            ;print empty line (terminate print)

(defun exchange (datalist i j)
"Swap the i and j elements in datalist"
  ;; Print out to debug what we are doing
  (format t "Swapping data[~a]:~a <-> data[~a]:~a~%"
          i (nth i datalist)
          j (nth j datalist))
  ;; Swap them
  (setf temp (nth i datalist))
  (setf (nth i datalist)(nth j datalist))
  (setf (nth j datalist) temp)
  ; print out what we've done
  (print datalist)(terpri))


;;Main program
;; (see Wikipedia for details of this algorithm)

(let ((n (length amplitudes)))
  (dotimes (index (- n 2))
    (setq jmin index)
    (setq jmax n)
    (setq jrange (- jmax jmin))
    (setq j (+ jmin (random jrange)))
    (exchange amplitudes index j)))

(format nil "Output is in debug window.")

Thanks a lot :slight_smile: I think I get it. Merging a silence and tone into pair make it the easiest to shuffle that merged list. I think I also understand the Fisher-Yates shuffle algorithm. But I have also another question : is it possible to incorporate in that code occurence of tones at 2 frequencies in given terms ? I mean in one track 100 tones at frequency 1000 Hz, 10 at each level and 100 tones at frequency 4000 Hz, 10 at each level, all of this shuffled ?

Hi :slight_smile: could I count on help with my issue :slight_smile: ?

Sure that would be possible, but probably best not to take too much on at once. By splitting the task into functions, we are making the program modular, so it should be fairly straightforward to extend the program by adding new “modules”.

Did you see this post? Sort and Shuffle functions
How are you going to incorporate that into your program?

You could write the list of ‘gains’ (that will be shuffled) by hand as
(setf gainlist (list 0 -5 -10 -15 -20 -25 -30 -35 -40 -45 0 -5 -10…))
but as we’re writing a program, why not just tell the computer to generate the list for us:

;; Make a list of 100 numbers for gain levels where
;; 10 are at each is multiple of 5 between 0 and -45.

(defun gainlist (&aux glist)
  (do ((gain 0 (- gain 5)))
      ((= gain -50) glist)
    (dotimes (i 10)
      (push gain glist))))

;; Test it
(print (gainlist))

Thanks a lot :slight_smile: this is the code I put into the Nyquist Prompt but I still get errors

;version 4
;type generate

(defun tone ()
  (mult (osc (hz-to-step 1000) 0.25)
        (pwlv 0 0.02 1 0.23 1 0.25 0)))

(defun rest ()
  (s-rest (+ 1.8 (rrandom))))

(defun gain ()
  (db-to-linear (* -5 (random 10))))

(defun gainlist (&aux glist)
  (do ((gain 0 (- gain 5)))
      ((= gain -50) glist)
    (dotimes (i 10)
      (push gain glist))))

(print (gainlist))

(defun shuffle (gain)
  (let ((n (length gain)))
    (do* ((i (1- n) (1- i))
          (j (random (1+ i))(random (1+ i))))
         ((= i 1) gainlist)
      (swap (nth i gain) (nth j gain)))))

(defmacro swap (x y)
  `(let ((temp ,x))
      (setf ,x ,y)
      (setf ,y temp)))

(let ((input (format nil "~a" gainlist)))  ;keep a copy so we can print it
  (format nil "Input:\t ~a~%Output:\t ~a"
              input
              (shuffle gainlist)))

(defun get-next-note (tone)
  (seq (rest)
       (cue (mult (gain) tone))))

(let ((tone (tone)))
  (seqrep (i 200) (get-next-note tone)))

And the list of errors

error: unbound variable - GAINLIST
if continued: try evaluating symbol again
Function: #<FSubr-LET: #4286980>
Arguments:
  ((INPUT (FORMAT NIL "~a" GAINLIST)))
  (FORMAT NIL "Input:\t ~a~%Output:\t ~a" INPUT (SHUFFLE GAINLIST))
1> GET-NEXT-NOTE
1> #<Sound: #562ec38>
1>

The list of gains is printed. I know that I do here something wrong, but I can’t figure out what. I am wondering also if that loop at the end is needed when we created the list of those 100 ampitudes.

Hi :slight_smile: could I get some help ? I’m a little bit helpless with programming. Big thanks in advance :slight_smile:

You have used “GAINLIST” as both a variable and a function name (which is perfectly valid, though can be a bit confusing).

In the statement:

(print (gainlist))

you are referring to the function. You can see that it is a reference to a function because the name “gainlist” is immediately after a “(”


In other places, for example:

(let ((input (format nil "~a" gainlist)))  ;keep a copy so we can print it

you are referring to a “variable” called "gainlist.

The error message is complaining about your use of a variable called “gainlist” and is saying that the variable is used without being bound to a value (you are attempting to use the variable before you have set it to a value).

So let’s look at the places where you have used it:

(defun shuffle (gain)
  (let ((n (length gain)))
    (do* ((i (1- n) (1- i))
          (j (random (1+ i))(random (1+ i))))
         ((= i 1) gainlist)
      (swap (nth i gain) (nth j gain)))))



(let ((input (format nil "~a" gainlist)))  ;keep a copy so we can print it

[/code]

  (format nil "Input:\t ~a~%Output:\t ~a"
              input
              (shuffle gainlist)))

and where do you set the value of “gainlist”?
I don’t see that you have set it anywhere.

Generally I like to define all of my functions before I write the main script, so my plug-ins usually have a structure in the form of:

  1. set global variables (if any)
  2. define functions
  3. run the code

We are not currently using any global variables, but we are defining a lot of functions (and one macro), so let’s put those all together first:

;version 4
;type generate

(defun tone ()
  (mult (osc (hz-to-step 1000) 0.25)
        (pwlv 0 0.02 1 0.23 1 0.25 0)))

(defun rest ()
  (s-rest (+ 1.8 (rrandom))))

(defun gain ()
  (db-to-linear (* -5 (random 10))))

(defun gainlist (&aux glist)
  (do ((gain 0 (- gain 5)))
      ((= gain -50) glist)
    (dotimes (i 10)
      (push gain glist))))

(defun shuffle (gain)
  (let ((n (length gain)))
    (do* ((i (1- n) (1- i))
          (j (random (1+ i))(random (1+ i))))
         ((= i 1) gainlist)
      (swap (nth i gain) (nth j gain)))))

(defmacro swap (x y)
  `(let ((temp ,x))
      (setf ,x ,y)
      (setf ,y temp)))

(defun get-next-note (tone)
  (seq (rest)
       (cue (mult (gain) tone))))

Then we can add the main program that uses those functions.

The question now is, “what do we want the program to do?”

The answer:

  1. Create a list of gain values.
  2. Shuffle that list of gain values
  3. Generate a tone
  4. Create a sequence that repeats the tone, amplifying each occurrence by successive gain values from the shuffled list

For the first three steps, a “LET” structure (“special form”) looks like it will be suitable. However, the order in which we do things is important - we must (obviously) create the list of gain values before we can shuffle the list, so we must use “LET*” rather than “LET”.
See the difference here:
LET http://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/xlisp/xlisp-ref/xlisp-ref-148.htm
LET* http://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/xlisp/xlisp-ref/xlisp-ref-149.htm

So let’s try that bit first:

(defun gainlist (&aux glist)
  (do ((gain 0 (- gain 5)))
      ((= gain -50) glist)
    (dotimes (i 10)
      (push gain glist))))

(defun shuffle (gains)
  (let ((n (length gains)))
    (do* ((i (1- n) (1- i))
          (j (random (1+ i))(random (1+ i))))
         ((= i 1) gains)
      (swap (nth i gains) (nth j gains)))))

(defmacro swap (x y)
  `(let ((temp ,x))
      (setf ,x ,y)
      (setf ,y temp)))

(let* ((gain-list (gainlist)) ;set gain-list to the list returned by the function (gainlist)
       (gain-list (shuffle gain-list))) ;set gain-list to a shuffled version of itself
  ;; have a look to see if this is working
  (print gain-list))

but actually we can simplify that by combining the first two lines of the LET* statement into a single line:

(defun gainlist (&aux glist)
  (do ((gain 0 (- gain 5)))
      ((= gain -50) glist)
    (dotimes (i 10)
      (push gain glist))))

(defun shuffle (gains)
  (let ((n (length gains)))
    (do* ((i (1- n) (1- i))
          (j (random (1+ i))(random (1+ i))))
         ((= i 1) gains)
      (swap (nth i gains) (nth j gains)))))

(defmacro swap (x y)
  `(let ((temp ,x))
      (setf ,x ,y)
      (setf ,y temp)))
       
(let ((gain-list (shuffle (gainlist))))
  ;; have a look to see if this is working
  (print gain-list))

(Note that we can now use LET rather than LET*)

Are you following this so far? Does it make sense and is it working for you PiTeRr?

;version 4
;type generate

(defun tone ()
  (mult (osc (hz-to-step 1000) 0.25)
        (pwlv 0 0.02 1 0.23 1 0.25 0)))

(defun gainlist (&aux glist)
  (do ((gain 0 (- gain 5)))
      ((= gain -50) glist)
    (dotimes (i 10)
      (push gain glist))))

(defun shuffle (gains)
  (let ((n (length gains)))
    (do* ((i (1- n) (1- i))
          (j (random (1+ i))(random (1+ i))))
         ((= i 1) gains)
      (swap (nth i gains) (nth j gains)))))

(defmacro swap (x y)
  `(let ((temp ,x))
      (setf ,x ,y)
      (setf ,y temp)))

(defun rest ()
  (s-rest (+ 1.8 (rrandom))))

(defun get-next-note (tone gain)
  (seq (rest)
       (cue (mult (db-to-linear gain) tone))))
       
(let ((gain-list (shuffle (gainlist)))
      (tone (tone)))
  (seqrep (i (length gain-list))
          (get-next-note tone (nth i gain-list))))

Yes, now I get it much better and I need to study more carefully all of the LISP structures to understand it well :slight_smile: this code is working perfectly and that is what I meant :slight_smile: huge thanks :slight_smile: but my final issue is to create a sequence of 100 tones at frequency of 1000 Hz and 100 tones at frequency of 4000 Hz and all of this should be shuffled. This is going to complicate a code but I am really obligated to do it in this way. I would be tremendously greatful for your further help in that issue :slight_smile: