-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathBassDetect.pde
89 lines (74 loc) · 2.81 KB
/
BassDetect.pde
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public class BassDetect extends Thread {
private FFT fftBass;
private int bassIndex;
private float noiseFactor;
private float[] longWindow, shortWindow;
public float longThreshold, shortThreshold, noiseThreshold;
public BassDetect() {
// frequency analysis
fftBass = new FFT(player.bufferSize(), player.sampleRate());
fftBass.logAverages(22, 1); // number of "buckets" in the spectra
longWindow = new float[60*5]; // 60 frames * 5 seconds = 300 sample moving window
shortWindow = new float[6]; // 1/10th second = 6 sample moving window
// params
bassIndex = 1; // spectra "bucket" considerd to resemble bass
noiseFactor = 0.1; // noisiness factor, "just noticeable difference" constant
}
// continually compute a moving average of the measured bass amplitude,
// this can be thought of as the threshold required to register a "kick".
public void run() {
while (player.isPlaying()) {
// perform a forward FFT on the samples in active's mix buffer
fftBass.forward(player.mix);
// calculate the bass thresholds
longThreshold = getAvg(longWindow);
shortThreshold = getAvg(shortWindow);
noiseThreshold = ((noiseFactor * longThreshold > noiseFactor * 100) ? (noiseFactor * longThreshold) : (noiseFactor * 100));
// update the bass thresholds
longWindow[frameCount % longWindow.length] = fftBass.getAvg(bassIndex);
shortWindow[frameCount % shortWindow.length] = fftBass.getAvg(bassIndex);
try {
sleep(20);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// core beat detection logic
public boolean isKick() {
boolean isKick = false;
if ((shortThreshold >= (longThreshold - noiseThreshold)) && (shortThreshold > noiseThreshold)) {
isKick = true;
}
return isKick;
}
public float shortLevel() {
return shortThreshold;
}
public float longLevel() {
return longThreshold;
}
// draw bass thresholds as horizontal lines
// very useful when tweaking the beat detection!!
public void debugDraw() {
strokeWeight(5);
// WHITE = long "relative" threshold (5 second moving average)
stroke(255);
line(0, (height - longThreshold), width, (height - longThreshold));
// GREEN = short punchy bass measure (1/10th second moving average)
stroke(120, 90, 90);
line(0, (height - shortThreshold), width, (height - shortThreshold));
// BLUE = absolute lower bound (fixed)
stroke(180, 90, 90);
line(0, (height - noiseThreshold), width, (height - noiseThreshold));
}
// helper method for normalizing the frequency windows
private float getAvg(float[] vals) {
int n;
float sum=0;
for (n=0; n<vals.length; n++) {
sum += vals[n];
}
return sum/n;
}
}