-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathutil.pde
138 lines (112 loc) · 3.35 KB
/
util.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
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
int freqToPitch(float f) {
int p = round(69.0 + 12.0 *(log(f/440.0) / log(2.0)));
if ( p > 0 && p < 128 ) {
return p;
} else {
return 0;
}
}
float pitchToFreq(int p) {
return 440.0 * pow(2, (p - 69) / 12.0);
}
// Find the lowest frequency in an octave range
float octaveLowRange(int octave) {
// find C - C0 is MIDI note 12
return pitchToFreq(12 + octave * 12);
}
// Find the highest frequency in an octave range
float octaveHighRange(int octave) {
// find B - B0 is MIDI note 23
return pitchToFreq(23 + octave * 12);
}
// Types of FFT bin weighting algorithms
public static final int UNIFORM = 0;
public static final int DISCRETE = 1;
public static final int LINEAR = 2;
public static final int QUADRATIC = 3;
public static final int EXPONENTIAL = 4;
int WEIGHT_TYPE = UNIFORM; // default
// Applies FFT bin weighting. x is the distance from a real semi-tone
float binWeight(int type, float x) {
switch(type) {
case DISCRETE:
return (x <= 0.2) ? 1.0 : 0.0;
case LINEAR:
return 1 - x;
case QUADRATIC:
return 1.0 - pow(x, 2);
case EXPONENTIAL:
return pow(exp(1.0), 1.0 - x)/exp(1.0);
case UNIFORM:
default:
return 1.0;
}
}
void normalizePCP() {
float pcpMax = max(pcp[frameNumber]);
for ( int k = 0; k < 12; k++ ) {
pcp[frameNumber][k] /= pcpMax;
}
}
void zeroPadBuffer() {
for (int i = 0; i < fftBufferSize; i++) {
buffer[i] = 0f;
}
}
void precomputeOctaveRegions() {
for ( int j = 0; j < 8; j++) {
fftBinStart[j] = 0;
fftBinEnd[j] = 0;
for ( int k = 0; k < fftSize; k++) {
float freq = k / (float)fftBufferSize * audio.sampleRate();
if ( freq >= octaveLowRange(j) && fftBinStart[j] == 0 ) {
fftBinStart[j] = k;
} else if ( freq > octaveHighRange(j) && fftBinEnd[j] == 0 ) {
fftBinEnd[j] = k;
break;
}
}
}
println("Start: " + fftBinStart[0] + " End: " + fftBinEnd[7] + " (" + fftSize + " total)");
}
void openAudioFile(String audioFile) {
if ( TRACK_LOADED ) {
audio.pause();
audio.close();
loadedAudioFile = "";
sliderProgress.setValue(0);
sliderProgress.setMax(0);
TRACK_LOADED = false;
}
audio = minim.loadFile(sketchPath + "/music/" + audioFile, bufferSize);
audio.addListener(sampler);
frames = round((float)audio.length() / 1000f * (float)audio.sampleRate() / (float)bufferSize);
println("\nAudio source: " + audioFile + " " + audio.length() / 1000 + " seconds (" + frames + " frames)");
println("Time size: " + bufferSize + " bytes / Sample rate: " + audio.sampleRate() / 1000f + "kHz");
println("FFT bandwidth: " + (2.0 / fftBufferSize) * ((float)audio.sampleRate() / 2.0) + "Hz");
if (audio.type() == Minim.STEREO) {
println("Channels: 2 (STEREO)\n");
} else {
println("Channels: 1 (MONO)\n");
}
fft = new FFT(fftBufferSize, audio.sampleRate());
// Setup Arrays
notes = new Note[frames][0];
pcp = new float[frames][12];
precomputeOctaveRegions();
sliderProgress.setMax(audio.length());
cuePosition = audio.position();
// Switch back to general tab
controlP5.window(this).activateTab("default");
frameNumber = -1;
loadedAudioFile = audioFile;
TRACK_LOADED = true;
audio.play();
}
boolean isLoaded() {
if ( TRACK_LOADED && frameNumber > -1 ) {
return true;
} else {
return false;
}
}