I’ve reformatted your code with some line breaks and indentations to make it more easily readable.
See here for advice about indenting LISP code: https://forum.audacityteam.org/t/conventions-for-nyquist-plug-ins/16324/16
Any line numbers that I quote will refer to this version:
;nyquist plug-in
;version 1
;type analyze
;categories "http://audacityteam.org/namespace#OnsetDetector"
;name "Beats Per Minute"
;action "BPM..."
;codetype lisp
;control thresval "Threshold Percentage" int "" 85 5 100
(defvar cnt 10)
(setf s1
(if (arrayp s)
(snd-add (aref s 0) (aref s 1))
s))
(defun signal ()
(force-srate 1000
(lp (snd-follow (lp s1 50) 0.001 0.01 0.1 512)
10)))
(setq max (peak (signal) NY:ALL))
(setq thres (* (/ thresval 100.0) max))
(setq s2 (signal))
(do ((time 0) (l NIL) (p T) (v (snd-fetch s2)))
((not v) l)
(if (and p (> v thres))
(setq b thres)
(setq cnt (+ cnt 1)))
(setq p (< v thres))
(setq time (+ time 1))
(setq v (snd-fetch s2)))
Line 30:
(setq b (thres))
should be:
(setq b thres)
because THRES is a variable, not a function.
I’d also suggest using a different name for your variable “MAX” as “MAX” is a function name in Nyquist/XLisp (http://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/xlisp/xlisp-ref/xlisp-ref-170.htm)
and not using single character variable names, especially not the character “l” which can easily be confused with the number “1” in some fonts.
Questions to consider:
What do the variables “l”, “p”, “b” and “v” represent?
I can guess that you intend for “time” to represents the time value of the current sample and that “thresval” is your threshold value.
Yes.
“p” is set to true [T] when the sample value is below the threshold.
“p” is set to false [NIL] when the sample value is above the threshold.
In line 29:
(if (and p (> v thres))
you test to see if the threshold has been crossed “upward” (from below, to above the threshold). This is the point at which you need to capture the time.
I don’t know what “b” is intended to represent. You have set it equal to the threshold value. Why?
If you want to store a list of times, you need to add the current time value to the list. For example:
(setf time-list ()) ; an empty list.
(setq time 3) ; an arbitrary time value.
; add the value of TIME to the list:
(setf time-list (cons time time-list))
(print time-list) ; prints the list to the debug window: (3)
(setq time 7) ; another arbitrary time value.
(setf time-list (cons time time-list))
(print time-list) ; prints: (7 3)
It is a little cumbersome to write (setf lis (cons val lis)) each time, but fortunately there is a useful abbreviation (see: http://www.cs.cmu.edu/~rbd/doc/nyquist/part13.html#index1000):
(setf time-list ()) ; an empty list.
(setq time 3) ; an arbitrary time value.
; add the value of TIME to the list:
(push time time-list)
(print time-list) ; prints the list to the debug window: (3)
(setq time 7) ; another arbitrary time value.
(push time time-list)
(print time-list) ; prints: (7 3)
Currently your TIME value is just a sample count. In order to convert that to real time in seconds, you need to divide by the sample rate of the audio that you are analyzing [S2]. You can get the sample rate of S2 with the function SND-SRATE http://www.cs.cmu.edu/~rbd/doc/nyquist/part8.html#index272