-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdetectors.js
More file actions
92 lines (80 loc) · 2.76 KB
/
detectors.js
File metadata and controls
92 lines (80 loc) · 2.76 KB
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
/**
* https://github.com/peterkhayes/pitchfinder/blob/master/src/detectors/amdf.ts
*/
const DEFAULT_AMDF_PARAMS = {
sampleRate: 44100,
minFrequency: 82,
maxFrequency: 1000,
ratio: 5,
sensitivity: 0.1,
};
export function AMDF(params = {}) {
const config = {
...DEFAULT_AMDF_PARAMS,
...params,
};
const sampleRate = config.sampleRate;
const minFrequency = config.minFrequency;
const maxFrequency = config.maxFrequency;
const sensitivity = config.sensitivity;
const ratio = config.ratio;
const amd = [];
/* Round in such a way that both exact minPeriod as
exact maxPeriod lie inside the rounded span minPeriod-maxPeriod,
thus ensuring that minFrequency and maxFrequency can be found
even in edge cases */
const maxPeriod = Math.ceil(sampleRate / minFrequency);
const minPeriod = Math.floor(sampleRate / maxFrequency);
return function AMDFDetector(float32AudioBuffer) {
const maxShift = float32AudioBuffer.length;
let t = 0;
let minval = Infinity;
let maxval = -Infinity;
let frames1, frames2, calcSub, i, j, u, aux1, aux2;
// Find the average magnitude difference for each possible period offset.
for (i = 0; i < maxShift; i++) {
if (minPeriod <= i && i <= maxPeriod) {
for (
aux1 = 0, aux2 = i, t = 0, frames1 = [], frames2 = [];
aux1 < maxShift - i;
t++, aux2++, aux1++
) {
frames1[t] = float32AudioBuffer[aux1];
frames2[t] = float32AudioBuffer[aux2];
}
// Take the difference between these frames.
const frameLength = frames1.length;
calcSub = [];
for (u = 0; u < frameLength; u++) {
calcSub[u] = frames1[u] - frames2[u];
}
// Sum the differences.
let summation = 0;
for (u = 0; u < frameLength; u++) {
summation += Math.abs(calcSub[u]);
}
amd[i] = summation;
}
}
for (j = minPeriod; j < maxPeriod; j++) {
if (amd[j] < minval) minval = amd[j];
if (amd[j] > maxval) maxval = amd[j];
}
const cutoff = Math.round(sensitivity * (maxval - minval) + minval);
for (j = minPeriod; j <= maxPeriod && amd[j] > cutoff; j++);
const searchLength = minPeriod / 2;
minval = amd[j];
let minpos = j;
for (i = j - 1; i < j + searchLength && i <= maxPeriod; i++) {
if (amd[i] < minval) {
minval = amd[i];
minpos = i;
}
}
if (Math.round(amd[minpos] * ratio) < maxval) {
return sampleRate / minpos;
} else {
return null;
}
};
}