## working with audio samples

Using Nyquist scripts in Audacity.

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

### Re: working with audio samples

In the previous examples the time is calculated from the sample count.
time = sample-count / sample-rate
steve

Posts: 45100
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu

### Beats Per Minute

hi,

Thanks for all your help until now.

As you wanted to know what exactly we are trying to implement, we are working on a project for our final year Engineering course. We want to add a plugin to Audacity which will count the Tempo i.e Beats Per Minute of a sound clip. We have thought of a way to implement it. According to what we have thought, we need to store the time instant at which the sound wave rises above a given input threshold value that is in decibel, and also the instant when the wave falls below the threshold. We also require to store the peak value which is in decibel. For your better understanding, we have uploaded an image which will make you clear about the exact situation. According to the figure we need to save the values of t1,t2,t3... which is in seconds and the values of p1, p2,... which are the peak values, in decibel. The peak values will be considered as the beats which will be counted.

This is what we need according to what we have thought. If you can think of a better solution then please do let us know.

If this is a success we are willing to contribute this plugin to the Audacity.

shravani

Posts: 8
Joined: Wed Jan 29, 2014 7:43 am

### Beats Per Minute

shravani

Posts: 8
Joined: Wed Jan 29, 2014 7:43 am

### Re: working with audio samples

Have you seen my recent plug-in "Tempo Teller"?
The current version is:
rjh-tempo-teller.ny

I've decided not to work with single sample values. If you wanna do that, you should resample the audio track.

My algorithm is roughly as follows:
- take 30 s, resample to 51200 (100* 2^9)
- create a curve, following the peaks.
- Downsampling to get 4096 samples.
- take the FFT
- Each bin represents one bpm
- take only the magnitude for each bin
- make a harmonic product spectrum (*).
- search peaks that are enclosed by smaller magnitude values.
- search for the highest point on the curve defined by these three points.
- store the middle bin plus the offset and its magnitude.
- sort the list by the magnitude and return the (interpolated) bpm value.

(*) The harmonic product spectrum HPS is employed to eliminate higher harmonics from the spectrum. I have actually used summation instead of multiplication.
It works as follows:
the spectrum with 4096 bins is downsampled to 1/2, 1/3 ... 1/6 and all is added up.
For instance:
'0 4 0 4 0 3 0 2' plus
'4 4 3 2' equals
'4 8 3 6 0 3 0 2'
You can see that the fundamental frequency is now higher than the second harmonic.

Although I can't see your image, I think that you're working on a fully time domain based solution.

The first problem that I see is the threshold for the peaks. It's always a dangerous thing to use absolute values, at least it isn't elegant for "blind tempo estimation". Of course, you can urge the user to set this value but he will soon skip this task and use the default-- which probably produces a wrong result.
Even a learning phase with hundreds of songs won't you help much, each song has its own dynamic range.
A common approach is to get the local peaks in comparison to the global average and to adjust the threshold dynamically.
Here's a sample snippet that isolates strong peaks (actually RMS values) (and returns the audio):
Code: Select all
`(defun drum-filter (s ol-ratio blk blk2 cut &key isolate)(let* ((r-blk (/ *sound-srate* blk))    (rms (rms (reson s cut (/ cut 20) 2) r-blk (round (/ blk ol-ratio))))   (avg (snd-avg rms blk2 1 op-average))   (ctrl (snd-shape (mult avg (recip rms)) (snd-pwl 0 44100       (list 0 0.01 70000 0.01 75000 0.95 88201 1.0 88201)) 1))   (csr (snd-srate ctrl))   (drums-cut (mult s (snd-avg (snd-chase ctrl (/ 1 csr) (/ 1 csr)) 15 1 op-average))))(if isolate (diff s drums-cut) drums-cut)))(multichan-expand 'drum-filter s 0.1 147 1000 100 :isolate t)`

The function is called in the last line.
The first value is the hop size; 0.1 means that the window advances by 10 %.
then comes the window size in samples, those will be the local peaks, or better, the local RMS values in this function.
The third value is the amount of windows that make the environment for the local peak, in the sample code 147000 samples or 1000 windows.
There's also a center frequency for a reference frequency in Hz, 100 here. That's to get mostly kick drum hits for example. 10000 Hz would also well work for snare drum, cymbals etc.
There are some other, rather complicated functions used, but they serve only one purpose, namely to return a smoother audio.
"T" or "NIL" after ":isolate" will decide if the beats should be isolated or attenuated.

You can of course pursuit your original idea, it is possible to gather the sample values in one vector (single-dimensional array) and the on-/offset times in another one.
Robert J. H.

Posts: 1813
Joined: Thu May 31, 2012 8:33 am
Operating System: Windows 7

### Re: working with audio samples

Hello,

We want to save the time values when the sound wave rises above the input threshold value & falls below the threshold value so as to locate the beats. Please can you help us with the nyquist coding . As our main aim is to caculate beats per minutes for which we have added a new plugin in Audacity analyze menu.

Thank you.
Vanita

Posts: 1
Joined: Mon Feb 24, 2014 8:18 am

### Re: working with audio samples

Have a look at the code for "beat.ny" in the Audacity plug-ins folder.
steve

Posts: 45100
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu

### Re: working with audio samples

Is that what you want?
Code: Select all
`;; return first derivative(defun differentiator (s-in)  (biquad s-in  1 -1 0  1 0 0));; main function(defun get-times (snd-in threshold hold result)  (let* (     (*sr* (snd-srate snd-in))     (hour (round (* 3600 *sr*)))     (peaks (snd-oneshot (s-abs snd-in) threshold hold))     (start-stop (differentiator peaks))     (index (snd-pwl 0 *sr* (list 0 0.0 hour (float hour) (1+ hour))))     (times (mult start-stop index))     (shortened  (snd-compose times         (snd-inverse (integrate (s-abs start-stop)) 0 *sr*))))(eval result) ));;;; Definitions and outputs to Debug screen;; The input sound(setf sig (snd-from-array 0 *sound-srate*   #(0.1 0.3 0.5 0.3 0.1 0 -0.1 -0.3 -0.5 -0.3 -0.1 0 0 0)))(psetq threshold 0.2); = -14 dB(setf stay&hold (/ 3 *sound-srate*)); hold for min 3 samples ;;;; Input sound(snd-display sig)(terpri); New line;; First sound, 1 for all that is above threshold:(snd-display (get-times sig threshold stay&hold 'peaks))(terpri);; differentiate sound to get only start (1) and stop (-1):(snd-display (get-times sig threshold stay&hold 'start-stop))(terpri);; Multiply with the sample indices:(snd-display (get-times sig threshold stay&hold 'times))(terpri);; Remove all samples that are zero:(snd-display (get-times sig threshold stay&hold 'shortened))`

The start and stop times are returned as a sound. They are here expressed as sample indices, but you can change them easily to seconds by replacing '(float hour)' with3600.0 in the 'index' definition.
The Stay&Hold variable is to bridge valleys in the wave form. You can simply assign a value in seconds, e.g. 0.05 for 50 ms.
You have to add this value to the negative end times to get the proper time, where the peak goes under the threshold.
Change in the above example '3' to '4' and the zero crossing will be ignored. However, the returned sound will only have the start time, but the end time will be simply the total length - 4.
It is probably best to gather those pairs in a list for easier manipulation.
Robert J. H.

Posts: 1813
Joined: Thu May 31, 2012 8:33 am
Operating System: Windows 7

### Re: working with audio samples

I've used the above submitted code to "filter" out some prominent beats in the following example
The original loop is at the beginning. This loop is then analysed at 12000 Hz (that's made with "reson"), this leaves kick and snare (the high pitch of beater and stick are found).
The third part holds the bass beats alone, the filter is set to 50 Hz, 10 Hz wide.
The line that does the whole filtering for the kick drum is:
Code: Select all
`(mult s (get-times (reson s 50  10 1)  0.02 0.05 'peaks))`

Note that ['peaks] is taken from the function, that's the one that writes 1 for all samples above the threshold.
The hold value is 50 ms and the threshold -34 dB (= 0.02).
As I've mentioned before, finding the right threshold will be your greatest problem. Modern music has often a prominent drum accompaniment, not so older music. The tempo can of course also be found from instrument onsets, if cleverly analyzed.
drum loop 120.mp3
Robert J. H.

Posts: 1813
Joined: Thu May 31, 2012 8:33 am
Operating System: Windows 7

### Re: working with audio samples

Since I work with music, samples in that context would be a harmonic sound/noise that loops in a sample editor, and make notes with say, a pattern editor. Audacity can create "samples" from certain sounds, to be looped in music software (once exported as a wav or soft or flac)
weldo5

Posts: 52
Joined: Fri Nov 15, 2013 10:18 pm
Operating System: Windows 10

Previous