Beats Per Minute

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: Conventions for Nyquist Plug-ins - #16 by steve
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 (XLISP max)
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 Nyquist Functions