Nyquist crash with snd-avg

Using Nyquist scripts in Audacity.
Post and download new plug-ins.
Forum rules
If you require help using Audacity, please post on the forum board relevant to your operating system:
Windows
Mac OS X
GNU/Linux and Unix-like
Paul L
Posts: 1782
Joined: Mon Mar 11, 2013 7:37 pm
Operating System: Please select

Nyquist crash with snd-avg

Post by Paul L » Mon Nov 11, 2013 2:11 am

I am still using 2.0.3. This is a bug in the library, for real this time.

Audacity crashes when snd-avg is given certain inputs and the resulting sound is evaluated.

The problem depends only on the lengths of the sounds involved, not the values of the samples.

Do this in the Nyquist prompt.

Code: Select all

(setf srate 44100.0)

(defun make-sound (length)
  (let ((arr (make-array length)))
    (dotimes (ii length) (setf (aref arr ii) 0))
    (snd-from-array 0 srate arr)))

(let* ((nn 44100)
       (mm 650)
       (snd1 (make-sound nn))
       (snd2 (make-sound mm))
       (snd3 (convolve snd1 snd2))
       (snd4 (snd-xform snd3 srate 0 (/ (/ mm 2.0) srate) MAX-STOP-TIME 1.0)))
  (snd-avg snd4 440 220 OP-PEAK))
This is an abstraction of what I am trying to do. Certain combinations of values for mm and nn are poisonous, others not. It is not obvious what the pattern is yet, but I started running into this only when I made mm much larger than before.

Paul L
Posts: 1782
Joined: Mon Mar 11, 2013 7:37 pm
Operating System: Please select

Re: Nyquist crash with snd-avg

Post by Paul L » Mon Nov 11, 2013 6:12 am

Here is a simpler way to demonstrate the crash. As written it does not crash. Change the definition of nn as commented and it does crash, and apparently for any larger value.

Is it significant that this least value of nn that causes a crash is one half of the step size?

If I fix nn at 110 and vary mm, I get a crash for 550 (another multiple of half the step size! -- and I presume for all all larger mm) but not for 549 (and I presume all smaller).

And notice this strangeness: If use-convolve is nil, there is no crash. Yet if snd3 is defined by convolve, there is a crash, even though it has been completely evaluated first by snd-flatten.

Code: Select all

(setf srate 44100.0)

(defun make-sound (length)
  (let ((arr (make-array length)))
    (dotimes (ii length) (setf (aref arr ii) 0))
    (snd-from-array 0 srate arr)))

(setf use-convolve t)

(let* ((mm 650)
       (nn 109) ; crashes with (nn 110)
       (snd1 (make-sound nn))
       (snd2 (make-sound mm))
       (snd3 (if use-convolve
		 (convolve snd1 snd2)
		 (make-sound (+ nn mm))))
       (_ (print (snd-flatten snd3 ny:all))))
  (snd-avg snd3 440 220 OP-PEAK))

Paul L
Posts: 1782
Joined: Mon Mar 11, 2013 7:37 pm
Operating System: Please select

Re: Nyquist crash with snd-avg

Post by Paul L » Mon Nov 11, 2013 6:35 am

I explored the boundaries of the problem a little more.

Code: Select all

(setf srate 44100.0)

(defun make-sound (length)
  (let ((arr (make-array length)))
    (dotimes (ii length) (setf (aref arr ii) 0))
    (snd-from-array 0 srate arr)))

(setf use-convolve t)

(let ((multiplier 5)
      (half-step 110))
  (let* ((mm (* multiplier half-step))
	 (nn (1- half-step)) ; (nn half-step)
	 (snd1 (make-sound nn))
	 (snd2 (make-sound mm))
	 (snd3 (if use-convolve
		   (convolve snd1 snd2)
		   (make-sound (+ nn mm))))
	 (_ (print (snd-flatten snd3 ny:all))))
    (snd-avg snd3 (* 4 half-step) (* 2 half-step) OP-PEAK)))
Changed half-step to many values from 1 to 110 and got no crashes.

Changed the definition of nn as commented, and it seems any positive value of half-step causes a crash, no matter how small.

Paul L
Posts: 1782
Joined: Mon Mar 11, 2013 7:37 pm
Operating System: Please select

Re: Nyquist crash with snd-avg

Post by Paul L » Mon Nov 11, 2013 6:49 am

Now take this version, and just vary multiplier. 5 is the least value causing a crash, but there is no crash with 6 or 8. I did try up to 11 and got crashes for 7, 9, 10, 11.

That's enough for tonight.

Code: Select all

(setf srate 44100.0)

(defun make-sound (length)
  (let ((arr (make-array length)))
    (dotimes (ii length) (setf (aref arr ii) 0))
    (snd-from-array 0 srate arr)))

(setf use-convolve t)

(let ((multiplier 5)
      (half-step 110))
  (let* ((mm (* multiplier half-step))
	 (nn half-step)
	 (snd1 (make-sound nn))
	 (snd2 (make-sound mm))
	 (snd3 (if use-convolve
		   (convolve snd1 snd2)
		   (make-sound (+ nn mm))))
	 (_ (print (snd-flatten snd3 ny:all))))
    (snd-avg snd3 (* (1- multiplier) half-step) (* 2 half-step) OP-PEAK)))

steve
Site Admin
Posts: 80679
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu

Re: Nyquist crash with snd-avg

Post by steve » Mon Nov 11, 2013 1:21 pm

Paul L wrote:Changed the definition of nn as commented, and it seems any positive value of half-step causes a crash, no matter how small.
Do you mean "even" value?
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

Paul L
Posts: 1782
Joined: Mon Mar 11, 2013 7:37 pm
Operating System: Please select

Re: Nyquist crash with snd-avg

Post by Paul L » Mon Nov 11, 2013 5:25 pm

You refer to the third of my four messages above. I said any positive value for the HALF-step, which means an even value of the step. I just reconfirmed that there is a crash with half-step of 109.

steve
Site Admin
Posts: 80679
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu

Re: Nyquist crash with snd-avg

Post by steve » Mon Nov 11, 2013 9:01 pm

It's an interesting bug (and yes, I do agree that it's a bug ;))

Taking your first code example, if you remove the snd-avg command from the end:

Code: Select all

(setf srate 44100.0)

(defun make-sound (length)
  (let ((arr (make-array length)))
    (dotimes (ii length) (setf (aref arr ii) 0))
    (snd-from-array 0 srate arr)))

(let* ((nn 44100)
       (mm 650)
       (snd1 (make-sound nn))
       (snd2 (make-sound mm))
       (snd3 (convolve snd1 snd2))
       (snd4 (snd-xform snd3 srate 0 (/ (/ mm 2.0) srate) MAX-STOP-TIME 1.0)))
  snd4)
then snd4 is returned to the track.
Then if you run snd-avg:

Code: Select all

(snd-avg s 440 220 OP-PEAK)
it completes correctly with no error.

There should really be no difference between splitting the process in two like this and your original code, yet the original code reliably crashes.
My current guess is that convolve is doing something bad and that snd-avg is then stepping in it.

I think that to sort this one out will require running the code in a proper debugging environment (one for Rodger).
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

Paul L
Posts: 1782
Joined: Mon Mar 11, 2013 7:37 pm
Operating System: Please select

Re: Nyquist crash with snd-avg

Post by Paul L » Mon Nov 11, 2013 10:10 pm

Something about the intermediate result is foiling snd-avg, for sure. Strangely it remains so even though snd-flatten is first done to the result of convolve.
This bug makes me unhappy enough that I will trywriting my own snd-avg using snd-fromobject

Paul L
Posts: 1782
Joined: Mon Mar 11, 2013 7:37 pm
Operating System: Please select

Re: Nyquist crash with snd-avg

Post by Paul L » Tue Nov 12, 2013 1:51 am

That workaround works!

Code: Select all

(defmacro update-op (op x val)
  (let ((temp1 (gensym))
	(temp2 (gensym)))
    `(let ((,temp1 ,val)
	   (,temp2 ,x))
       (setf ,x (if ,temp2 (,op ,temp2 ,temp1) ,temp1)))))
(defmacro update-max (x val) `(update-op max ,x ,val))
(defmacro update-min (x val) `(update-op min ,x ,val))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; define a class that wraps a nullary closure as an object with :next method
(setf object-from-closure (send class :new '(closure)))
(send object-from-closure :answer :next '()
      '((funcall closure)))
(send object-from-closure :answer :isnew '(cl)
      '((setf closure cl)))

(defun make-object-from-closure (closure)
  (send object-from-closure :new closure))

;;; do what snd-avg does, only assuming the block size is a multiple of
;;; the step size, and operation is OP-PEAK.
(defun my-snd-avg (snd steps-per-block step-size)
  (let* ((t0 (snd-t0 snd))
	 (reduced-srate (/ (snd-srate snd) step-size))
	 (my-snd (snd-copy snd))
	 (arr (make-array steps-per-block))
	 (index (1- steps-per-block))
	 (count steps-per-block)
	 (f
	  #'(lambda ()
	      (prog1
		  (dotimes
		      (_ count (let (temp) 
				 (dotimes (jj steps-per-block temp)
				   (let ((val (aref arr jj)))
				     (when val (update-max temp val))))))
		    (let ((samples
			   (snd-fetch-array my-snd step-size step-size)))
		      (setf (aref arr index)
			    (and samples (let (temp)
					   (dotimes (jj step-size temp)
					     (update-max
					      temp (abs (aref samples jj))))))
			    index (if (zerop index)
				      (1- steps-per-block)
				      (1- index)))))
		(setf count 1)))))
    (snd-fromobject t0 reduced-srate (make-object-from-closure f))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(setf srate 44100.0)

(defun make-sound (length)
  (let ((arr (make-array length)))
    (dotimes (ii length) (setf (aref arr ii) 0))
    (snd-from-array 0 srate arr)))

(setf use-convolve t)
(setf crash nil)


(let ((multiplier 5)
      (half-step 110))
  (let* ((mm (* multiplier half-step))
	 (nn half-step)
	 (snd1 (make-sound nn))
	 (snd2 (make-sound mm))
	 (snd3 (if use-convolve
		   (convolve snd1 snd2)
		   (make-sound (+ nn mm))))
	 (_ (print (snd-flatten snd3 ny:all))))
    (if crash
	(snd-avg snd3 (* (1- multiplier) half-step) (* 2 half-step) OP-PEAK)
	(my-snd-avg snd3 (/ (1- multiplier) 2) (* 2 half-step)))))

Paul L
Posts: 1782
Joined: Mon Mar 11, 2013 7:37 pm
Operating System: Please select

Re: Nyquist crash with snd-avg

Post by Paul L » Tue Nov 12, 2013 10:21 am

Another detail worth mentioning. It appears, from the time it takes to crash, that something is wrong at the end of the sound returned from snd-avg. The crash happens later if the bad sound is longer. The progress indicator for my plug-in advances almost to the end before crashing.

Post Reply