Commit | Line | Data |
---|---|---|
4c006f7b MS |
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 | ||
d12e46b6 | 7 | private final LX lx; |
4c006f7b MS |
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 | ||
d12e46b6 | 22 | public GraphicEQ(LX lx) { |
4c006f7b MS |
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 | */ | |
d12e46b6 | 30 | public GraphicEQ(LX lx, int num) { |
4c006f7b MS |
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) { | |
922def98 | 38 | (bandVals[i] = new LinearEnvelope(0, 0, 500)).trigger(); |
4c006f7b MS |
39 | } |
40 | } | |
41 | ||
4760e696 MS |
42 | static final float logTen = log(10); |
43 | public static float log10(float val) { | |
4c006f7b MS |
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 | ||
34327c96 | 60 | public void run(double deltaMs) { |
4c006f7b MS |
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()) { | |
4760e696 | 73 | bandVals[i].setRangeFromHereTo(value, attack.getValuef() * 20).trigger(); |
4c006f7b MS |
74 | } |
75 | } | |
76 | for (LinearEnvelope band : bandVals) { | |
77 | band.run(deltaMs); | |
78 | if (!band.isRunning() && band.getValuef() > 0) { | |
4760e696 | 79 | band.setRangeFromHereTo(0, release.getValuef() * 1600).trigger(); |
4c006f7b MS |
80 | } |
81 | } | |
82 | } | |
83 | } | |
84 | ||
85 |