Beats Per Minute

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
vedshree
Posts: 20
Joined: Wed Feb 26, 2014 6:26 am
Operating System: Please select

Beats Per Minute

Post by vedshree » Wed Feb 26, 2014 7:56 am

hello,

We are doing a project for our final year. The aim of our project is to calculate the Beats Per Minute ie tempo of a sound clip. According to the solution that we have thought of, we require to save the values of t1, t2, t3 (refer to the figure attached) ie the instants where the sound wave goes above a particular threshold in decibels that will be given as input and the instany where the sound wave goes below the threshold value. We also require to save the peak values p1, p2.. (refer to the figure attached) that will be considered as beat.

If this is a success, we will be contributing our work to audacity.

The following is the link for the image to be refered.
https://plus.google.com/photos/11138192 ... 4498427442

Hoping for support.
Thanks in advance.
Last edited by vedshree on Fri Apr 24, 2015 4:31 pm, edited 2 times in total.
Reason: fixed link

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

Re: Beats Per Minute

Post by steve » Wed Feb 26, 2014 3:50 pm

Same school as these guys? http://forum.audacityteam.org/viewtopic ... 52#p236652
See that topic for information about how one possible approach using the Nyquist scripting language.
Please pass that link on to your class mates so that we don't need to keep answering the same question ;)

Out of interest, have you been specifically asked to do this as a Nyquist plug-in, or in some other way?
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

vedshree
Posts: 20
Joined: Wed Feb 26, 2014 6:26 am
Operating System: Please select

Re: Beats Per Minute

Post by vedshree » Fri Feb 28, 2014 8:14 am

Hello,
I am extremely sorry for the inconvenience caused to you. Yes we have been specifically asked to add as a nyquist plugin which would calculate the beats per minute. The link that you have given, we tried to run that code but it is not working as per our expectation. Our specification has been mentioned in the previous post. Please can you help us with the nyquist coding which would give us the time at that instant of sound as shown in the diagram from the previous post.


Thanking you.

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

Re: Beats Per Minute

Post by steve » Fri Feb 28, 2014 1:41 pm

I don't think it would be right for me to do your homework for you - do you?
I'm happy to help you with your coding. How far have you got so far?
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

vedshree
Posts: 20
Joined: Wed Feb 26, 2014 6:26 am
Operating System: Please select

Re: Beats Per Minute

Post by vedshree » Sat Mar 01, 2014 9:03 am

That's what we are asking you for. We just want you to help us with the coding. For now we just want to know if there is any function which can help us retrieve a time instance and store it in a list. We want to locate the beats at equidistant points. We tried the coding by our own way but we are getting the unknown errors , Actually we are very new to nyquist coding so we are not understanding that we are going in which direction. So please if u could help us with our coding for given specifications.

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

Re: Beats Per Minute

Post by steve » Sat Mar 01, 2014 2:02 pm

vedshree wrote:we just want to know if there is any function which can help us retrieve a time instance and store it in a list.
There are several functions that can help with that, but no one function that does the whole task.
Did you read this topic? http://forum.audacityteam.org/viewtopic ... 52#p236652
There are a lot of tips and suggestions there.
vedshree wrote:We tried the coding by our own way but we are getting the unknown errors
What code? What errors?
If you post what you have written than we may be able to show where you have gone wrong.
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

vedshree
Posts: 20
Joined: Wed Feb 26, 2014 6:26 am
Operating System: Please select

Re: Beats Per Minute

Post by vedshree » Tue Mar 04, 2014 11:52 am

hello,
Here we are attaching the code that we have tried

Code: Select all

;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)))
In the above code we are trying to count the number of beats above the threshold. But here in the code time varaible is not incremented by 1 & we are getting the following error,
error: unbound function - THRES
if continued: try evaluating symbol again
Function: #<FSubr-SETQ: #af32250>
Arguments:
B
(THRES)
Function: #<FSubr-IF: #af3174c>
Arguments:
(AND P (> V THRES))
(SETQ B (THRES))
(SETQ CNT (+ CNT 1))
Function: #<FSubr-DO: #af317a0>
Arguments:
((B 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 B (+ B 1))
(SETQ V (SND-FETCH S2))
1>

After running the plugin the selected waveform part gets cut & we are getting this error in the debug prompt.

The above code is written in .ny file in plugins folder , Is this the right way to add the plugin or anything else is supposed to be added ?

So please can u help us how to save the time values where the wave goes above & below the input threshold value. Can u tell us exactly what functions should be used & where we are going wrong in our code ?

Thanking you.

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

Re: Beats Per Minute

Post by steve » Tue Mar 04, 2014 2:24 pm

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: http://forum.audacityteam.org/viewtopic ... 82#p184782
Any line numbers that I quote will refer to this version:

Code: Select all

;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)))
vedshree wrote:we are getting the following error,
error: unbound function - THRES
Line 30:

Code: Select all

      (setq b (thres))
should be:

Code: Select all

      (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/e ... ef-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.

vedshree wrote:The above code is written in .ny file in plugins folder , Is this the right way to add the plugin
Yes.

vedshree wrote:can u help us how to save the time values where the wave goes above & below the input threshold value.
"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:

Code: Select all

  (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:

Code: Select all

(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/ ... #index1000):

Code: Select all

(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/ ... l#index272
Last edited by steve on Fri Apr 24, 2015 4:31 pm, edited 2 times in total.
Reason: Topic moved to Nyquist forum
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

vedshree
Posts: 20
Joined: Wed Feb 26, 2014 6:26 am
Operating System: Please select

Re: Beats Per Minute

Post by vedshree » Wed Mar 05, 2014 4:09 pm

Hello,
Thank you so much for uo help, we have got an idea to move forward. And 'b' is the 'time' variable , at 1 place we forgot to change it , so sorry for that. But after running the same code with few changes suggested by you, we are getting 'Nyquist did not return audio' error. Can u please tell the reason for that ?

For your reference ,below is our code we implemented,

Code: Select all

;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 cnt (+ cnt 1)))
  (setq p (< v thres))
  (setq time (+ time 1))
  (setq v (snd-fetch s2)))  
Thanking you.
Last edited by vedshree on Fri Apr 24, 2015 4:31 pm, edited 2 times in total.
Reason: removed text size tags

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

Re: Beats Per Minute

Post by steve » Wed Mar 05, 2014 6:10 pm

Your code returns "l" which you set to NIL at the top of the DO loop.

Code: Select all

(do ((time 0) (l NIL) (p T) (v (snd-fetch s2)))
    ((not v) l)
The first line above is the start of the loop. Local variables TIME, L, P and V are initialised to 0, NIL, TRUE, and (SND-FETCH S2) respectively.
The second line is the "test" [ is V FALSE ?] and the return value. The "return value" is the thing that is returned when the loop exits.
See here: http://www.audacity-forum.de/download/e ... ef-093.htm

Nowhere in the loop do you change the value of "L", so it is still NIL when the loop exits.
I presume what you want to do is to use "L" as a list and push the time values into it.
See my previous post about storing the time values.

By the way, could you avoid using giant text. It makes it difficult to read on a small monitor. If forum visitors want big text they can set that in their browser.
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

Post Reply