Page 1 of 2
Nyquist crash with snd-avg
Posted: Mon Nov 11, 2013 2:11 am
by Paul L
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.
Re: Nyquist crash with snd-avg
Posted: Mon Nov 11, 2013 6:12 am
by Paul L
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))
Re: Nyquist crash with snd-avg
Posted: Mon Nov 11, 2013 6:35 am
by Paul L
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.
Re: Nyquist crash with snd-avg
Posted: Mon Nov 11, 2013 6:49 am
by Paul L
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)))
Re: Nyquist crash with snd-avg
Posted: Mon Nov 11, 2013 1:21 pm
by steve
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?
Re: Nyquist crash with snd-avg
Posted: Mon Nov 11, 2013 5:25 pm
by Paul L
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.
Re: Nyquist crash with snd-avg
Posted: Mon Nov 11, 2013 9:01 pm
by steve
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:
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).
Re: Nyquist crash with snd-avg
Posted: Mon Nov 11, 2013 10:10 pm
by Paul L
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
Re: Nyquist crash with snd-avg
Posted: Tue Nov 12, 2013 1:51 am
by Paul L
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)))))
Re: Nyquist crash with snd-avg
Posted: Tue Nov 12, 2013 10:21 am
by Paul L
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.