summaryrefslogtreecommitdiff
path: root/lib/rbcodec/dsp/compressor.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/dsp/compressor.c')
-rw-r--r--lib/rbcodec/dsp/compressor.c368
1 files changed, 183 insertions, 185 deletions
diff --git a/lib/rbcodec/dsp/compressor.c b/lib/rbcodec/dsp/compressor.c
index 3a8d52e4da..a6c1ac1018 100644
--- a/lib/rbcodec/dsp/compressor.c
+++ b/lib/rbcodec/dsp/compressor.c
@@ -29,6 +29,8 @@
29/*#define LOGF_ENABLE*/ 29/*#define LOGF_ENABLE*/
30#include "logf.h" 30#include "logf.h"
31 31
32static struct compressor_settings curr_set; /* Cached settings */
33
32static int32_t comp_rel_slope IBSS_ATTR; /* S7.24 format */ 34static int32_t comp_rel_slope IBSS_ATTR; /* S7.24 format */
33static int32_t comp_makeup_gain IBSS_ATTR; /* S7.24 format */ 35static int32_t comp_makeup_gain IBSS_ATTR; /* S7.24 format */
34static int32_t comp_curve[66] IBSS_ATTR; /* S7.24 format */ 36static int32_t comp_curve[66] IBSS_ATTR; /* S7.24 format */
@@ -38,214 +40,210 @@ static int32_t release_gain IBSS_ATTR; /* S7.24 format */
38 40
39/** COMPRESSOR UPDATE 41/** COMPRESSOR UPDATE
40 * Called via the menu system to configure the compressor process */ 42 * Called via the menu system to configure the compressor process */
41bool compressor_update(void) 43bool compressor_update(const struct compressor_settings *settings)
42{ 44{
43 static int curr_set[5]; 45 /* make settings values useful */
44 int new_set[5] = { 46 int threshold = settings->threshold;
45 global_settings.compressor_threshold, 47 bool auto_gain = settings->makeup_gain == 1;
46 global_settings.compressor_makeup_gain, 48 static const int comp_ratios[] = { 2, 4, 6, 10, 0 };
47 global_settings.compressor_ratio, 49 int ratio = comp_ratios[settings->ratio];
48 global_settings.compressor_knee, 50 bool soft_knee = settings->knee == 1;
49 global_settings.compressor_release_time}; 51 int release = settings->release_time * NATIVE_FREQUENCY / 1000;
50
51 /* make menu values useful */
52 int threshold = new_set[0];
53 bool auto_gain = (new_set[1] == 1);
54 const int comp_ratios[] = {2, 4, 6, 10, 0};
55 int ratio = comp_ratios[new_set[2]];
56 bool soft_knee = (new_set[3] == 1);
57 int release = new_set[4] * NATIVE_FREQUENCY / 1000;
58 52
59 bool changed = false; 53 bool changed = false;
60 bool active = (threshold < 0); 54 bool active = threshold < 0;
61 55
62 for (int i = 0; i < 5; i++) 56 if (memcmp(settings, &curr_set, sizeof (curr_set)))
63 { 57 {
64 if (curr_set[i] != new_set[i]) 58 /* Compressor settings have changed since last call */
65 { 59 changed = true;
66 changed = true;
67 curr_set[i] = new_set[i];
68 60
69#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE) 61#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
70 switch (i) 62 if (settings->threshold != curr_set.threshold)
71 { 63 {
72 case 0: 64 logf(" Compressor Threshold: %d dB\tEnabled: %s",
73 logf(" Compressor Threshold: %d dB\tEnabled: %s", 65 threshold, active ? "Yes" : "No");
74 threshold, active ? "Yes" : "No");
75 break;
76 case 1:
77 logf(" Compressor Makeup Gain: %s",
78 auto_gain ? "Auto" : "Off");
79 break;
80 case 2:
81 if (ratio)
82 { logf(" Compressor Ratio: %d:1", ratio); }
83 else
84 { logf(" Compressor Ratio: Limit"); }
85 break;
86 case 3:
87 logf(" Compressor Knee: %s", soft_knee?"Soft":"Hard");
88 break;
89 case 4:
90 logf(" Compressor Release: %d", release);
91 break;
92 }
93#endif
94 } 66 }
95 }
96 67
97 if (changed && active) 68 if (settings->makeup_gain != curr_set.makeup_gain)
98 {
99 /* configure variables for compressor operation */
100 static const int32_t db[] = {
101 /* positive db equivalents in S15.16 format */
102 0x000000, 0x241FA4, 0x1E1A5E, 0x1A94C8,
103 0x181518, 0x1624EA, 0x148F82, 0x1338BD,
104 0x120FD2, 0x1109EB, 0x101FA4, 0x0F4BB6,
105 0x0E8A3C, 0x0DD840, 0x0D3377, 0x0C9A0E,
106 0x0C0A8C, 0x0B83BE, 0x0B04A5, 0x0A8C6C,
107 0x0A1A5E, 0x09ADE1, 0x094670, 0x08E398,
108 0x0884F6, 0x082A30, 0x07D2FA, 0x077F0F,
109 0x072E31, 0x06E02A, 0x0694C8, 0x064BDF,
110 0x060546, 0x05C0DA, 0x057E78, 0x053E03,
111 0x04FF5F, 0x04C273, 0x048726, 0x044D64,
112 0x041518, 0x03DE30, 0x03A89B, 0x037448,
113 0x03412A, 0x030F32, 0x02DE52, 0x02AE80,
114 0x027FB0, 0x0251D6, 0x0224EA, 0x01F8E2,
115 0x01CDB4, 0x01A359, 0x0179C9, 0x0150FC,
116 0x0128EB, 0x010190, 0x00DAE4, 0x00B4E1,
117 0x008F82, 0x006AC1, 0x004699, 0x002305};
118
119 struct curve_point
120 { 69 {
121 int32_t db; /* S15.16 format */ 70 logf(" Compressor Makeup Gain: %s",
122 int32_t offset; /* S15.16 format */ 71 auto_gain ? "Auto" : "Off");
123 } db_curve[5]; 72 }
124 73
125 /** Set up the shape of the compression curve first as decibel 74 if (settings->ratio != cur_set.ratio)
126 values */
127 /* db_curve[0] = bottom of knee
128 [1] = threshold
129 [2] = top of knee
130 [3] = 0 db input
131 [4] = ~+12db input (2 bits clipping overhead) */
132
133 db_curve[1].db = threshold << 16;
134 if (soft_knee)
135 { 75 {
136 /* bottom of knee is 3dB below the threshold for soft knee*/
137 db_curve[0].db = db_curve[1].db - (3 << 16);
138 /* top of knee is 3dB above the threshold for soft knee */
139 db_curve[2].db = db_curve[1].db + (3 << 16);
140 if (ratio) 76 if (ratio)
141 /* offset = -3db * (ratio - 1) / ratio */ 77 { logf(" Compressor Ratio: %d:1", ratio); }
142 db_curve[2].offset = (int32_t)((long long)(-3 << 16)
143 * (ratio - 1) / ratio);
144 else 78 else
145 /* offset = -3db for hard limit */ 79 { logf(" Compressor Ratio: Limit"); }
146 db_curve[2].offset = (-3 << 16);
147 } 80 }
148 else 81
82 if (settings->knee != cur_set.knee)
149 { 83 {
150 /* bottom of knee is at the threshold for hard knee */ 84 logf(" Compressor Knee: %s", soft_knee?"Soft":"Hard");
151 db_curve[0].db = threshold << 16;
152 /* top of knee is at the threshold for hard knee */
153 db_curve[2].db = threshold << 16;
154 db_curve[2].offset = 0;
155 } 85 }
156 86
157 /* Calculate 0db and ~+12db offsets */ 87 if (settings->release_time != cur_set.release_time)
158 db_curve[4].db = 0xC0A8C; /* db of 2 bits clipping */
159 if (ratio)
160 { 88 {
161 /* offset = threshold * (ratio - 1) / ratio */ 89 logf(" Compressor Release: %d", release);
162 db_curve[3].offset = (int32_t)((long long)(threshold << 16)
163 * (ratio - 1) / ratio);
164 db_curve[4].offset = (int32_t)((long long)-db_curve[4].db
165 * (ratio - 1) / ratio) + db_curve[3].offset;
166 } 90 }
91#endif
92
93 curr_set = *settings;
94 }
95
96 if (!changed || !active)
97 return active;
98
99 /* configure variables for compressor operation */
100 static const int32_t db[] = {
101 /* positive db equivalents in S15.16 format */
102 0x000000, 0x241FA4, 0x1E1A5E, 0x1A94C8,
103 0x181518, 0x1624EA, 0x148F82, 0x1338BD,
104 0x120FD2, 0x1109EB, 0x101FA4, 0x0F4BB6,
105 0x0E8A3C, 0x0DD840, 0x0D3377, 0x0C9A0E,
106 0x0C0A8C, 0x0B83BE, 0x0B04A5, 0x0A8C6C,
107 0x0A1A5E, 0x09ADE1, 0x094670, 0x08E398,
108 0x0884F6, 0x082A30, 0x07D2FA, 0x077F0F,
109 0x072E31, 0x06E02A, 0x0694C8, 0x064BDF,
110 0x060546, 0x05C0DA, 0x057E78, 0x053E03,
111 0x04FF5F, 0x04C273, 0x048726, 0x044D64,
112 0x041518, 0x03DE30, 0x03A89B, 0x037448,
113 0x03412A, 0x030F32, 0x02DE52, 0x02AE80,
114 0x027FB0, 0x0251D6, 0x0224EA, 0x01F8E2,
115 0x01CDB4, 0x01A359, 0x0179C9, 0x0150FC,
116 0x0128EB, 0x010190, 0x00DAE4, 0x00B4E1,
117 0x008F82, 0x006AC1, 0x004699, 0x002305};
118
119 struct curve_point
120 {
121 int32_t db; /* S15.16 format */
122 int32_t offset; /* S15.16 format */
123 } db_curve[5];
124
125 /** Set up the shape of the compression curve first as decibel
126 values */
127 /* db_curve[0] = bottom of knee
128 [1] = threshold
129 [2] = top of knee
130 [3] = 0 db input
131 [4] = ~+12db input (2 bits clipping overhead) */
132
133 db_curve[1].db = threshold << 16;
134 if (soft_knee)
135 {
136 /* bottom of knee is 3dB below the threshold for soft knee*/
137 db_curve[0].db = db_curve[1].db - (3 << 16);
138 /* top of knee is 3dB above the threshold for soft knee */
139 db_curve[2].db = db_curve[1].db + (3 << 16);
140 if (ratio)
141 /* offset = -3db * (ratio - 1) / ratio */
142 db_curve[2].offset = (int32_t)((long long)(-3 << 16)
143 * (ratio - 1) / ratio);
167 else 144 else
168 { 145 /* offset = -3db for hard limit */
169 /* offset = threshold for hard limit */ 146 db_curve[2].offset = (-3 << 16);
170 db_curve[3].offset = (threshold << 16); 147 }
171 db_curve[4].offset = -db_curve[4].db + db_curve[3].offset; 148 else
172 } 149 {
173 150 /* bottom of knee is at the threshold for hard knee */
174 /** Now set up the comp_curve table with compression offsets in the 151 db_curve[0].db = threshold << 16;
175 form of gain factors in S7.24 format */ 152 /* top of knee is at the threshold for hard knee */
176 /* comp_curve[0] is 0 (-infinity db) input */ 153 db_curve[2].db = threshold << 16;
177 comp_curve[0] = UNITY; 154 db_curve[2].offset = 0;
178 /* comp_curve[1 to 63] are intermediate compression values 155 }
179 corresponding to the 6 MSB of the input values of a non-clipped 156
180 signal */ 157 /* Calculate 0db and ~+12db offsets */
181 for (int i = 1; i < 64; i++) 158 db_curve[4].db = 0xC0A8C; /* db of 2 bits clipping */
182 { 159 if (ratio)
183 /* db constants are stored as positive numbers; 160 {
184 make them negative here */ 161 /* offset = threshold * (ratio - 1) / ratio */
185 int32_t this_db = -db[i]; 162 db_curve[3].offset = (int32_t)((long long)(threshold << 16)
186 163 * (ratio - 1) / ratio);
187 /* no compression below the knee */ 164 db_curve[4].offset = (int32_t)((long long)-db_curve[4].db
188 if (this_db <= db_curve[0].db) 165 * (ratio - 1) / ratio) + db_curve[3].offset;
189 comp_curve[i] = UNITY; 166 }
190 167 else
191 /* if soft knee and below top of knee, 168 {
192 interpolate along soft knee slope */ 169 /* offset = threshold for hard limit */
193 else if (soft_knee && (this_db <= db_curve[2].db)) 170 db_curve[3].offset = (threshold << 16);
194 comp_curve[i] = fp_factor(fp_mul( 171 db_curve[4].offset = -db_curve[4].db + db_curve[3].offset;
195 ((this_db - db_curve[0].db) / 6), 172 }
196 db_curve[2].offset, 16), 16) << 8; 173
197 174 /** Now set up the comp_curve table with compression offsets in the
198 /* interpolate along ratio slope above the knee */ 175 form of gain factors in S7.24 format */
199 else 176 /* comp_curve[0] is 0 (-infinity db) input */
200 comp_curve[i] = fp_factor(fp_mul( 177 comp_curve[0] = UNITY;
201 fp_div((db_curve[1].db - this_db), db_curve[1].db, 16), 178 /* comp_curve[1 to 63] are intermediate compression values
202 db_curve[3].offset, 16), 16) << 8; 179 corresponding to the 6 MSB of the input values of a non-clipped
203 } 180 signal */
204 /* comp_curve[64] is the compression level of a maximum level, 181 for (int i = 1; i < 64; i++)
205 non-clipped signal */ 182 {
206 comp_curve[64] = fp_factor(db_curve[3].offset, 16) << 8; 183 /* db constants are stored as positive numbers;
207 184 make them negative here */
208 /* comp_curve[65] is the compression level of a maximum level, 185 int32_t this_db = -db[i];
209 clipped signal */ 186
210 comp_curve[65] = fp_factor(db_curve[4].offset, 16) << 8; 187 /* no compression below the knee */
211 188 if (this_db <= db_curve[0].db)
189 comp_curve[i] = UNITY;
190
191 /* if soft knee and below top of knee,
192 interpolate along soft knee slope */
193 else if (soft_knee && (this_db <= db_curve[2].db))
194 comp_curve[i] = fp_factor(fp_mul(
195 ((this_db - db_curve[0].db) / 6),
196 db_curve[2].offset, 16), 16) << 8;
197
198 /* interpolate along ratio slope above the knee */
199 else
200 comp_curve[i] = fp_factor(fp_mul(
201 fp_div((db_curve[1].db - this_db), db_curve[1].db, 16),
202 db_curve[3].offset, 16), 16) << 8;
203 }
204 /* comp_curve[64] is the compression level of a maximum level,
205 non-clipped signal */
206 comp_curve[64] = fp_factor(db_curve[3].offset, 16) << 8;
207
208 /* comp_curve[65] is the compression level of a maximum level,
209 clipped signal */
210 comp_curve[65] = fp_factor(db_curve[4].offset, 16) << 8;
211
212#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE) 212#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
213 logf("\n *** Compression Offsets ***"); 213 logf("\n *** Compression Offsets ***");
214 /* some settings for display only, not used in calculations */ 214 /* some settings for display only, not used in calculations */
215 db_curve[0].offset = 0; 215 db_curve[0].offset = 0;
216 db_curve[1].offset = 0; 216 db_curve[1].offset = 0;
217 db_curve[3].db = 0; 217 db_curve[3].db = 0;
218
219 for (int i = 0; i <= 4; i++)
220 {
221 logf("Curve[%d]: db: % 6.2f\toffset: % 6.2f", i,
222 (float)db_curve[i].db / (1 << 16),
223 (float)db_curve[i].offset / (1 << 16));
224 }
225
226 logf("\nGain factors:");
227 for (int i = 1; i <= 65; i++)
228 {
229 debugf("%02d: %.6f ", i, (float)comp_curve[i] / UNITY);
230 if (i % 4 == 0) debugf("\n");
231 }
232 debugf("\n");
233#endif
234
235 /* if using auto peak, then makeup gain is max offset -
236 .1dB headroom */
237 comp_makeup_gain = auto_gain ?
238 fp_factor(-(db_curve[3].offset) - 0x199A, 16) << 8 : UNITY;
239 logf("Makeup gain:\t%.6f", (float)comp_makeup_gain / UNITY);
240 218
241 /* calculate per-sample gain change a rate of 10db over release time 219 for (int i = 0; i <= 4; i++)
242 */ 220 {
243 comp_rel_slope = 0xAF0BB2 / release; 221 logf("Curve[%d]: db: % 6.2f\toffset: % 6.2f", i,
244 logf("Release slope:\t%.6f", (float)comp_rel_slope / UNITY); 222 (float)db_curve[i].db / (1 << 16),
245 223 (float)db_curve[i].offset / (1 << 16));
246 release_gain = UNITY;
247 } 224 }
248 225
226 logf("\nGain factors:");
227 for (int i = 1; i <= 65; i++)
228 {
229 debugf("%02d: %.6f ", i, (float)comp_curve[i] / UNITY);
230 if (i % 4 == 0) debugf("\n");
231 }
232 debugf("\n");
233#endif
234
235 /* if using auto peak, then makeup gain is max offset -
236 .1dB headroom */
237 comp_makeup_gain = auto_gain ?
238 fp_factor(-(db_curve[3].offset) - 0x199A, 16) << 8 : UNITY;
239 logf("Makeup gain:\t%.6f", (float)comp_makeup_gain / UNITY);
240
241 /* calculate per-sample gain change a rate of 10db over release time
242 */
243 comp_rel_slope = 0xAF0BB2 / release;
244 logf("Release slope:\t%.6f", (float)comp_rel_slope / UNITY);
245
246 release_gain = UNITY;
249 return active; 247 return active;
250} 248}
251 249