Merge pull request #19 from l8on/master
[SugarCubes.git] / Audio.pde
1 /**
2 * This is a reusable equalizer class that lets you get averaged
3 * bands with dB scaling and smoothing.
4 */
5 public static class GraphicEQ {
6
7 private final LX lx;
8
9 public final BasicParameter level = new BasicParameter("LVL", 0.5);
10 public final BasicParameter range = new BasicParameter("RNGE", 0.5);
11 public final BasicParameter slope = new BasicParameter("SLOP", 0.5);
12 public final BasicParameter attack = new BasicParameter("ATK", 0.5);
13 public final BasicParameter release = new BasicParameter("REL", 0.5);
14
15 private final FFT fft;
16 private final int numBands;
17
18 private final LinearEnvelope[] bandVals;
19
20 public final static int DEFAULT_NUM_BANDS = 16;
21
22 public GraphicEQ(LX lx) {
23 this(lx, DEFAULT_NUM_BANDS);
24 }
25
26 /**
27 * Note that the number of bands is a suggestion. Due to the FFT implementation
28 * the actual number may be slightly different.
29 */
30 public GraphicEQ(LX lx, int num) {
31 this.lx = lx;
32 fft = new FFT(lx.audioInput().bufferSize(), lx.audioInput().sampleRate());
33 fft.window(FFT.HAMMING);
34 fft.logAverages(50, num/8);
35 numBands = this.fft.avgSize();
36 bandVals = new LinearEnvelope[numBands];
37 for (int i = 0; i < bandVals.length; ++i) {
38 (bandVals[i] = new LinearEnvelope(0, 0, 500)).trigger();
39 }
40 }
41
42 static final float logTen = log(10);
43 public static float log10(float val) {
44 return log(val) / logTen;
45 }
46
47 public float getLevel(int band) {
48 return bandVals[band].getValuef();
49 }
50
51 public float getAverageLevel(int minBand, int numBands) {
52 float avg = 0;
53 for (int i = minBand; i < minBand + numBands; ++i) {
54 avg += bandVals[i].getValuef();
55 }
56 avg /= numBands;
57 return avg;
58 }
59
60 public void run(double deltaMs) {
61 fft.forward(lx.audioInput().mix);
62 float zeroDBReference = pow(10, 100*(1-level.getValuef())/20.);
63 float decibelRange = 12 + range.getValuef() * 60;
64 float decibelSlope = slope.getValuef() * 60.f / numBands;
65 for (int i = 0; i < numBands; ++i) {
66 float raw = fft.getAvg(i);
67 float decibels = 20*log10(raw / zeroDBReference);
68 float positiveDecibels = decibels + decibelRange;
69 positiveDecibels += i*decibelSlope;
70 float value = constrain(positiveDecibels / decibelRange, 0, 1);
71
72 if (value > bandVals[i].getValuef()) {
73 bandVals[i].setRangeFromHereTo(value, attack.getValuef() * 20).trigger();
74 }
75 }
76 for (LinearEnvelope band : bandVals) {
77 band.run(deltaMs);
78 if (!band.isRunning() && band.getValuef() > 0) {
79 band.setRangeFromHereTo(0, release.getValuef() * 1600).trigger();
80 }
81 }
82 }
83 }
84
85