-
Notifications
You must be signed in to change notification settings - Fork 10
/
beat_detection.h
151 lines (124 loc) · 4.39 KB
/
beat_detection.h
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
Notes on songs to test:
every other beat is doubled: Human -- The Human League
alternating drum and symbol: Candy -- Paolo Nutini
deep long oscillations and alt double: If I Had A Heart -- Fever Ray
weird beat, weird instruments: Nightwalking Your Memory -- Vector Lovers
^-- this one works pretty well with simple amplitude
*/
/*
Smoothing can be done by adjusting `samples_inst_n` or
*/
// main sample history container
const uint16_t samples_long_n = 220;
uint16_t samples_long[6][samples_long_n];
uint16_t samples_long_count = 0; // for rollover
// "instant" sample history container
const uint16_t samples_inst_n = 3;
uint16_t samples_inst[6][samples_inst_n];
uint16_t samples_inst_count = 0; // for rollover
uint16_t averages[6];
uint16_t variances[6];
uint16_t threshold = 20; // don't count beat if sample less than this
bool beats[6];
float ratios[6];
bool detect_beat(uint16_t * buckets, uint8_t log_level){
if(log_level==3){
char s[100];
sprintf(s," *Buckets: %05d %05d %05d %05d %05d %05d", buckets[0], buckets[1], buckets[2], buckets[3], buckets[4], buckets[5]);
SerialUSB.print(s);
}
// compute average of samples for each buckets
for( uint16_t i = 0; i < 6; i++ ){
samples_long[i][samples_long_count] = buckets[i]; // save sample for averaging
samples_inst[i][samples_inst_count] = buckets[i]; // save sample for averaging
// char s[100];
// sprintf(s," buckets[%03d] == %05d; samples_long[%03d][%03d] == %05d; samples_inst[%03d][%03d] == %05d;", i, buckets[i], i, samples_long_count, samples_long[i][samples_long_count], i, samples_inst_count, samples_inst[i][samples_inst_count] );
// SerialUSB.print(s);
int average = 0;
for( uint16_t j = 0; j < samples_long_n; j++ ){
average += samples_long[i][j];
}
averages[i] = floor( average / samples_long_n );
}
if(log_level==1){
char s[100];
sprintf(s," Averages: %05d %05d %05d %05d %05d %05d", averages[0], averages[1], averages[2], averages[3], averages[4], averages[5]);
SerialUSB.print(s);
}
// compute variance of samples for each bucket
for( uint16_t i = 0; i < 6; i++ ){
int sum_of_squared_diffs = 0;
for( uint16_t j = 0; j < samples_long_n; j++ ){
int diff = samples_long[i][j] - averages[i];
sum_of_squared_diffs += diff * diff;
}
variances[i] = floor( sqrt( sum_of_squared_diffs ) / samples_long_n );
}
if(log_level==1){
char s[100];
sprintf(s," Variance: %04d %04d %04d %04d %04d %04d", variances[0], variances[1], variances[2], variances[3], variances[4], variances[5]);
SerialUSB.print(s);
}
// compute whether current sample is higher than average by factor dep on variance
for(int i = 0; i < 6; i++ ){
int average = 0;
for( uint16_t j = 0; j < samples_inst_n; j++ ){
average += samples_inst[i][j];
}
int now_sample = floor( average / samples_inst_n );
if( now_sample < threshold ){
ratios[i] = 0.00;
beats[i] = false;
} else {
if( averages[i] > 0){
float ratio = (float) now_sample / averages[i];
if( ratio > 9.99 ){
ratios[i] = 9.99;
} else {
ratios[i] = ratio;
}
beats[i] = ratio > 1.0;
} else {
if( now_sample > 0){
ratios[i] = 9.99;
beats[i] = true;
} else {
ratios[i] = 0.00;
beats[i] = false;
}
}
}
}
if(log_level==2){
for( uint16_t i = 0; i < 6; i++ ){
if( beats[i] ){
char s[4];
sprintf(s," %03d", (int) (ratios[i] * 100.0) );
SerialUSB.print(s);
// SerialUSB.print(" ");
// SerialUSB.print(ratios[i]);
// SerialUSB.print(" ");
} else {
SerialUSB.print(" ");
}
}
}
if(log_level==2){
// see which of 6 has highest variance
int highest_variance =0, highest_slot=0;
for( uint16_t i = 0; i < 6; i++ ){
if( variances[i] > highest_variance ){
highest_variance = variances[i];
highest_slot = i;
}
}
SerialUSB.print(" ");
SerialUSB.print(highest_slot);
// // see if current sample for highest varying slot is above average
// float ratio = samples_long[highest_slot][samples_long_count] / averages[highest_slot];
}
// advance sample counters
if(++samples_long_count >= samples_long_n) samples_long_count = 0;
if(++samples_inst_count >= samples_inst_n) samples_inst_count = 0;
}