diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/dsp.c | 638 | ||||
-rw-r--r-- | apps/dsp.h | 7 | ||||
-rw-r--r-- | apps/fixedpoint.h | 2 | ||||
-rw-r--r-- | apps/lang/dansk.lang | 6 | ||||
-rw-r--r-- | apps/lang/deutsch.lang | 6 | ||||
-rw-r--r-- | apps/lang/english.lang | 227 | ||||
-rw-r--r-- | apps/lang/francais.lang | 6 | ||||
-rw-r--r-- | apps/lang/italiano.lang | 6 | ||||
-rw-r--r-- | apps/lang/polski.lang | 6 | ||||
-rw-r--r-- | apps/lang/svenska.lang | 6 | ||||
-rw-r--r-- | apps/lang/tagalog.lang | 6 | ||||
-rw-r--r-- | apps/lang/walon.lang | 8 | ||||
-rw-r--r-- | apps/menus/sound_menu.c | 19 | ||||
-rw-r--r-- | apps/pcmbuf.c | 24 | ||||
-rw-r--r-- | apps/pcmbuf.h | 1 | ||||
-rw-r--r-- | apps/plugin.c | 1 | ||||
-rw-r--r-- | apps/plugin.h | 5 | ||||
-rw-r--r-- | apps/plugins/test_codec.c | 24 | ||||
-rw-r--r-- | apps/settings.c | 6 | ||||
-rw-r--r-- | apps/settings.h | 6 | ||||
-rw-r--r-- | apps/settings_list.c | 56 |
21 files changed, 568 insertions, 498 deletions
diff --git a/apps/dsp.c b/apps/dsp.c index e7a6a9182a..a5ceecb048 100644 --- a/apps/dsp.c +++ b/apps/dsp.c | |||
@@ -137,6 +137,15 @@ struct eq_state | |||
137 | /* 10ch */ | 137 | /* 10ch */ |
138 | }; | 138 | }; |
139 | 139 | ||
140 | struct compressor_menu | ||
141 | { | ||
142 | int threshold; /* dB - from menu */ | ||
143 | int ratio; /* from menu */ | ||
144 | int gain; /* dB - from menu */ | ||
145 | bool soft_knee; /* 0 = hard knee, 1 = soft knee */ | ||
146 | int release; /* samples - from menu */ | ||
147 | }; | ||
148 | |||
140 | /* Include header with defines which functions are implemented in assembly | 149 | /* Include header with defines which functions are implemented in assembly |
141 | code for the target */ | 150 | code for the target */ |
142 | #include <dsp_asm.h> | 151 | #include <dsp_asm.h> |
@@ -171,7 +180,6 @@ struct dsp_config | |||
171 | int32_t tdspeed_percent; /* Speed% * PITCH_SPEED_PRECISION */ | 180 | int32_t tdspeed_percent; /* Speed% * PITCH_SPEED_PRECISION */ |
172 | bool tdspeed_active; /* Timestretch is in use */ | 181 | bool tdspeed_active; /* Timestretch is in use */ |
173 | int frac_bits; | 182 | int frac_bits; |
174 | long limiter_preamp; /* limiter amp gain in S7.24 format */ | ||
175 | #ifdef HAVE_SW_TONE_CONTROLS | 183 | #ifdef HAVE_SW_TONE_CONTROLS |
176 | /* Filter struct for software bass/treble controls */ | 184 | /* Filter struct for software bass/treble controls */ |
177 | struct eqfilter tone_filter; | 185 | struct eqfilter tone_filter; |
@@ -187,7 +195,7 @@ struct dsp_config | |||
187 | channels_process_fn_type apply_crossfeed; | 195 | channels_process_fn_type apply_crossfeed; |
188 | channels_process_fn_type eq_process; | 196 | channels_process_fn_type eq_process; |
189 | channels_process_fn_type channels_process; | 197 | channels_process_fn_type channels_process; |
190 | return_fn_type limiter_process; | 198 | return_fn_type compressor_process; |
191 | }; | 199 | }; |
192 | 200 | ||
193 | /* General DSP config */ | 201 | /* General DSP config */ |
@@ -253,58 +261,17 @@ static int32_t *resample_buf; | |||
253 | #define RESAMPLE_BUF_LEFT_CHANNEL 0 | 261 | #define RESAMPLE_BUF_LEFT_CHANNEL 0 |
254 | #define RESAMPLE_BUF_RIGHT_CHANNEL (sample_buf_count/2 * RESAMPLE_RATIO) | 262 | #define RESAMPLE_BUF_RIGHT_CHANNEL (sample_buf_count/2 * RESAMPLE_RATIO) |
255 | 263 | ||
256 | /* limiter */ | 264 | /* compressor */ |
257 | /* MAX_COUNT is largest possible sample count in limiter_process. This is | 265 | /* MAX_COUNT is largest possible sample count in compressor_process */ |
258 | needed in case time stretch makes the count in dsp_process larger than | 266 | #define MAX_COUNT (SMALL_SAMPLE_BUF_COUNT * RESAMPLE_RATIO / 2) |
259 | the limiter buffer. */ | 267 | static struct compressor_menu c_menu; |
260 | #define MAX_COUNT MAX(SMALL_SAMPLE_BUF_COUNT * RESAMPLE_RATIO / 2, LIMITER_BUFFER_SIZE) | 268 | static int32_t comp_rel_slope IBSS_ATTR; /* S7.24 format */ |
261 | static int count_adjust; | 269 | static int32_t comp_makeup_gain IBSS_ATTR; /* S7.24 format */ |
262 | static bool limiter_buffer_active; | 270 | static int32_t comp_curve[65] IBSS_ATTR; /* S7.24 format */ |
263 | static bool limiter_buffer_full; | 271 | static int32_t gain_buffer[MAX_COUNT] IBSS_ATTR; |
264 | static bool limiter_buffer_emptying; | 272 | static int32_t release_gain IBSS_ATTR; |
265 | static int32_t limiter_buffer[2][LIMITER_BUFFER_SIZE] IBSS_ATTR; | 273 | |
266 | static int32_t *start_lim_buf[2] IBSS_ATTR, | 274 | static int compressor_process(int count, int32_t *buf[]); |
267 | *end_lim_buf[2] IBSS_ATTR; | ||
268 | static uint16_t lim_buf_peak[LIMITER_BUFFER_SIZE] IBSS_ATTR; | ||
269 | static uint16_t *start_peak IBSS_ATTR, | ||
270 | *end_peak IBSS_ATTR; | ||
271 | static uint16_t out_buf_peak[MAX_COUNT]; | ||
272 | static uint16_t *out_buf_peak_index IBSS_ATTR; | ||
273 | static uint16_t release_peak IBSS_ATTR; | ||
274 | static int32_t in_samp IBSS_ATTR, | ||
275 | samp0 IBSS_ATTR; | ||
276 | |||
277 | static void reset_limiter_buffer(struct dsp_config *dsp); | ||
278 | static int limiter_buffer_count(bool buf_count); | ||
279 | static int limiter_process(int count, int32_t *buf[]); | ||
280 | static uint16_t get_peak_value(int32_t sample); | ||
281 | |||
282 | /* The clip_steps array essentially stores the results of fp_factor from | ||
283 | * 0 to 12 dB, in 48 equal steps, in S3.28 format. */ | ||
284 | const long clip_steps[49] ICONST_ATTR = { 0x10000000, | ||
285 | 0x10779AFA, 0x10F2B409, 0x1171654C, 0x11F3C9A0, 0x1279FCAD, | ||
286 | 0x13041AE9, 0x139241A2, 0x14248EF9, 0x14BB21F9, 0x15561A92, | ||
287 | 0x15F599A0, 0x1699C0F9, 0x1742B36B, 0x17F094CE, 0x18A38A01, | ||
288 | 0x195BB8F9, 0x1A1948C5, 0x1ADC619B, 0x1BA52CDC, 0x1C73D51D, | ||
289 | 0x1D488632, 0x1E236D3A, 0x1F04B8A1, 0x1FEC982C, 0x20DB3D0E, | ||
290 | 0x21D0D9E2, 0x22CDA2BE, 0x23D1CD41, 0x24DD9099, 0x25F12590, | ||
291 | 0x270CC693, 0x2830AFD3, 0x295D1F37, 0x2A925471, 0x2BD0911F, | ||
292 | 0x2D1818B3, 0x2E6930AD, 0x2FC42095, 0x312931EC, 0x3298B072, | ||
293 | 0x3412EA24, 0x35982F3A, 0x3728D22E, 0x38C52808, 0x3A6D8847, | ||
294 | 0x3C224CD9, 0x3DE3D264, 0x3FB2783F}; | ||
295 | /* The gain_steps array essentially stores the results of fp_factor from | ||
296 | * 0 to -12 dB, in 48 equal steps, in S3.28 format. */ | ||
297 | const long gain_steps[49] ICONST_ATTR = { 0x10000000, | ||
298 | 0xF8BC9C0, 0xF1ADF94, 0xEAD2988, 0xE429058, 0xDDAFD68, | ||
299 | 0xD765AC1, 0xD149309, 0xCB59186, 0xC594210, 0xBFF9112, | ||
300 | 0xBA86B88, 0xB53BEF5, 0xB017965, 0xAB18964, 0xA63DDFE, | ||
301 | 0xA1866BA, 0x9CF1397, 0x987D507, 0x9429BEE, 0x8FF599E, | ||
302 | 0x8BDFFD3, 0x87E80B0, 0x840CEBE, 0x804DCE8, 0x7CA9E76, | ||
303 | 0x792070E, 0x75B0AB0, 0x7259DB2, 0x6F1B4BF, 0x6BF44D5, | ||
304 | 0x68E4342, 0x65EA5A0, 0x63061D6, 0x6036E15, 0x5D7C0D3, | ||
305 | 0x5AD50CE, 0x5841505, 0x55C04B8, 0x535176A, 0x50F44D9, | ||
306 | 0x4EA84FE, 0x4C6D00E, 0x4A41E78, 0x48268DF, 0x461A81C, | ||
307 | 0x441D53E, 0x422E985, 0x404DE62}; | ||
308 | 275 | ||
309 | 276 | ||
310 | /* Clip sample to signed 16 bit range */ | 277 | /* Clip sample to signed 16 bit range */ |
@@ -944,13 +911,6 @@ static void set_gain(struct dsp_config *dsp) | |||
944 | dsp->data.gain = fp_mul(dsp->data.gain, eq_precut, 24); | 911 | dsp->data.gain = fp_mul(dsp->data.gain, eq_precut, 24); |
945 | } | 912 | } |
946 | 913 | ||
947 | /* only preamp for the limiter if limiter is active and sample depth | ||
948 | * allows safe pre-amping (12 dB is OK with 29 or less frac bits) */ | ||
949 | if ((dsp->limiter_preamp) && (dsp->frac_bits <= 29)) | ||
950 | { | ||
951 | dsp->data.gain = fp_mul(dsp->data.gain, dsp->limiter_preamp, 24); | ||
952 | } | ||
953 | |||
954 | #ifdef HAVE_SW_VOLUME_CONTROL | 914 | #ifdef HAVE_SW_VOLUME_CONTROL |
955 | if (global_settings.volume < SW_VOLUME_MAX || | 915 | if (global_settings.volume < SW_VOLUME_MAX || |
956 | global_settings.volume > SW_VOLUME_MIN) | 916 | global_settings.volume > SW_VOLUME_MIN) |
@@ -1308,8 +1268,8 @@ int dsp_process(struct dsp_config *dsp, char *dst, const char *src[], int count) | |||
1308 | if (dsp->channels_process) | 1268 | if (dsp->channels_process) |
1309 | dsp->channels_process(chunk, t2); | 1269 | dsp->channels_process(chunk, t2); |
1310 | 1270 | ||
1311 | if (dsp->limiter_process) | 1271 | if (dsp->compressor_process) |
1312 | chunk = dsp->limiter_process(chunk, t2); | 1272 | chunk = dsp->compressor_process(chunk, t2); |
1313 | 1273 | ||
1314 | dsp->output_samples(chunk, &dsp->data, (const int32_t **)t2, (int16_t *)dst); | 1274 | dsp->output_samples(chunk, &dsp->data, (const int32_t **)t2, (int16_t *)dst); |
1315 | 1275 | ||
@@ -1358,15 +1318,6 @@ int dsp_output_count(struct dsp_config *dsp, int count) | |||
1358 | if (count > RESAMPLE_BUF_RIGHT_CHANNEL) | 1318 | if (count > RESAMPLE_BUF_RIGHT_CHANNEL) |
1359 | count = RESAMPLE_BUF_RIGHT_CHANNEL; | 1319 | count = RESAMPLE_BUF_RIGHT_CHANNEL; |
1360 | 1320 | ||
1361 | /* If the limiter buffer is filling, some or all samples will | ||
1362 | * be captured by it, so expect fewer samples coming out. */ | ||
1363 | if (limiter_buffer_active && !limiter_buffer_full) | ||
1364 | { | ||
1365 | int empty_space = limiter_buffer_count(false); | ||
1366 | count_adjust = MIN(empty_space, count); | ||
1367 | count -= count_adjust; | ||
1368 | } | ||
1369 | |||
1370 | return count; | 1321 | return count; |
1371 | } | 1322 | } |
1372 | 1323 | ||
@@ -1375,13 +1326,6 @@ int dsp_output_count(struct dsp_config *dsp, int count) | |||
1375 | */ | 1326 | */ |
1376 | int dsp_input_count(struct dsp_config *dsp, int count) | 1327 | int dsp_input_count(struct dsp_config *dsp, int count) |
1377 | { | 1328 | { |
1378 | /* If the limiter buffer is filling, the output count was | ||
1379 | * adjusted downward. This adjusts it back so that input | ||
1380 | * count is not affected. | ||
1381 | */ | ||
1382 | if (limiter_buffer_active && !limiter_buffer_full) | ||
1383 | count += count_adjust; | ||
1384 | |||
1385 | /* count is now the number of resampled input samples. Convert to | 1329 | /* count is now the number of resampled input samples. Convert to |
1386 | original input samples. */ | 1330 | original input samples. */ |
1387 | if (dsp->resample) | 1331 | if (dsp->resample) |
@@ -1499,7 +1443,8 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) | |||
1499 | dsp_update_functions(dsp); | 1443 | dsp_update_functions(dsp); |
1500 | resampler_new_delta(dsp); | 1444 | resampler_new_delta(dsp); |
1501 | tdspeed_setup(dsp); | 1445 | tdspeed_setup(dsp); |
1502 | reset_limiter_buffer(dsp); | 1446 | if (dsp == &AUDIO_DSP) |
1447 | release_gain = (1 << 24); | ||
1503 | break; | 1448 | break; |
1504 | 1449 | ||
1505 | case DSP_FLUSH: | 1450 | case DSP_FLUSH: |
@@ -1508,7 +1453,8 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) | |||
1508 | resampler_new_delta(dsp); | 1453 | resampler_new_delta(dsp); |
1509 | dither_init(dsp); | 1454 | dither_init(dsp); |
1510 | tdspeed_setup(dsp); | 1455 | tdspeed_setup(dsp); |
1511 | reset_limiter_buffer(dsp); | 1456 | if (dsp == &AUDIO_DSP) |
1457 | release_gain = (1 << 24); | ||
1512 | break; | 1458 | break; |
1513 | 1459 | ||
1514 | case DSP_SET_TRACK_GAIN: | 1460 | case DSP_SET_TRACK_GAIN: |
@@ -1588,369 +1534,257 @@ void dsp_set_replaygain(void) | |||
1588 | set_gain(&AUDIO_DSP); | 1534 | set_gain(&AUDIO_DSP); |
1589 | } | 1535 | } |
1590 | 1536 | ||
1591 | /** RESET THE LIMITER BUFFER | 1537 | /** SET COMPRESSOR |
1592 | * Force the limiter buffer to its initial state and discard | 1538 | * Called by the menu system to configure the compressor process */ |
1593 | * any samples held there. */ | 1539 | void dsp_set_compressor(int c_threshold, int c_ratio, int c_gain, |
1594 | static void reset_limiter_buffer(struct dsp_config *dsp) | 1540 | int c_knee, int c_release) |
1595 | { | 1541 | { |
1596 | if (dsp == &AUDIO_DSP) | 1542 | bool changed = false; |
1543 | bool active = (c_threshold < 0); | ||
1544 | const int comp_ratio[] = {2, 4, 6, 10, 0}; | ||
1545 | int new_ratio = comp_ratio[c_ratio]; | ||
1546 | bool new_knee = (c_knee == 1); | ||
1547 | int new_release = c_release * NATIVE_FREQUENCY / 1000; | ||
1548 | |||
1549 | if (c_menu.threshold != c_threshold) | ||
1597 | { | 1550 | { |
1598 | int i; | 1551 | changed = true; |
1599 | logf(" reset_limiter_buffer"); | 1552 | c_menu.threshold = c_threshold; |
1600 | for (i = 0; i < 2; i++) | 1553 | logf(" Compressor Threshold: %d dB\tEnabled: %s", |
1601 | start_lim_buf[i] = end_lim_buf[i] = limiter_buffer[i]; | 1554 | c_menu.threshold, active ? "Yes" : "No"); |
1602 | start_peak = end_peak = lim_buf_peak; | ||
1603 | limiter_buffer_full = false; | ||
1604 | limiter_buffer_emptying = false; | ||
1605 | release_peak = 0; | ||
1606 | } | 1555 | } |
1607 | } | ||
1608 | 1556 | ||
1609 | /** OPERATE THE LIMITER BUFFER | 1557 | if (c_menu.ratio != new_ratio) |
1610 | * Handle all samples entering or exiting the limiter buffer. */ | ||
1611 | static inline int set_limiter_buffer(int count, int32_t *buf[]) | ||
1612 | { | ||
1613 | int32_t *in_buf[] = {buf[0], buf[1]}, | ||
1614 | *out_buf[] = {buf[0], buf[1]}; | ||
1615 | int empty_space, i, out_count; | ||
1616 | const long clip_max = AUDIO_DSP.data.clip_max; | ||
1617 | const int ch = AUDIO_DSP.data.num_channels - 1; | ||
1618 | out_buf_peak_index = out_buf_peak; | ||
1619 | |||
1620 | if (limiter_buffer_emptying) | ||
1621 | /** EMPTY THE BUFFER | ||
1622 | * since the empty flag has been set, assume no inbound samples and | ||
1623 | return all samples in the limiter buffer to the outbound buffer */ | ||
1624 | { | 1558 | { |
1625 | count = limiter_buffer_count(true); | 1559 | changed = true; |
1626 | out_count = count; | 1560 | c_menu.ratio = new_ratio; |
1627 | logf(" Emptying limiter buffer: %d", count); | 1561 | if (c_menu.ratio) |
1628 | while (count-- > 0) | 1562 | logf(" Compressor Ratio: %d:1", c_menu.ratio); |
1629 | { | 1563 | else |
1630 | for (i = 0; i <= ch; i++) | 1564 | logf(" Compressor Ratio: Limit"); |
1631 | { | ||
1632 | /* move samples in limiter buffer to output buffer */ | ||
1633 | *out_buf[i]++ = *start_lim_buf[i]++; | ||
1634 | if (start_lim_buf[i] == &limiter_buffer[i][LIMITER_BUFFER_SIZE]) | ||
1635 | start_lim_buf[i] = limiter_buffer[i]; | ||
1636 | /* move limiter buffer peak values to output peak values */ | ||
1637 | if (i == 0) | ||
1638 | { | ||
1639 | *out_buf_peak_index++ = *start_peak++; | ||
1640 | if (start_peak == &lim_buf_peak[LIMITER_BUFFER_SIZE]) | ||
1641 | start_peak = lim_buf_peak; | ||
1642 | } | ||
1643 | } | ||
1644 | } | ||
1645 | limiter_buffer_full = false; | ||
1646 | limiter_buffer_emptying = false; | ||
1647 | } | 1565 | } |
1648 | else /* limiter buffer NOT emptying */ | 1566 | |
1567 | if (c_menu.gain != c_gain) | ||
1568 | { | ||
1569 | changed = true; | ||
1570 | c_menu.gain = c_gain; | ||
1571 | if (c_menu.gain >= 0) | ||
1572 | logf(" Compressor Makeup Gain: %d dB", c_menu.gain); | ||
1573 | else | ||
1574 | logf(" Compressor Makeup Gain: Auto"); | ||
1575 | } | ||
1576 | |||
1577 | if (c_menu.soft_knee != new_knee) | ||
1649 | { | 1578 | { |
1650 | if (count <= 0) return 0; | 1579 | changed = true; |
1580 | c_menu.soft_knee = new_knee; | ||
1581 | logf(" Compressor Knee: %s", c_menu.soft_knee==1?"Soft":"Hard"); | ||
1582 | } | ||
1583 | |||
1584 | if (c_menu.release != new_release) | ||
1585 | { | ||
1586 | changed = true; | ||
1587 | c_menu.release = new_release; | ||
1588 | logf(" Compressor Release: %d", c_menu.release); | ||
1589 | } | ||
1590 | |||
1591 | if (changed && active) | ||
1592 | { | ||
1593 | /* configure variables for compressor operation */ | ||
1594 | int i; | ||
1595 | const int32_t db[] ={0x000000, /* positive db equivalents in S15.16 format */ | ||
1596 | 0x241FA4, 0x1E1A5E, 0x1A94C8, 0x181518, 0x1624EA, 0x148F82, 0x1338BD, 0x120FD2, | ||
1597 | 0x1109EB, 0x101FA4, 0x0F4BB6, 0x0E8A3C, 0x0DD840, 0x0D3377, 0x0C9A0E, 0x0C0A8C, | ||
1598 | 0x0B83BE, 0x0B04A5, 0x0A8C6C, 0x0A1A5E, 0x09ADE1, 0x094670, 0x08E398, 0x0884F6, | ||
1599 | 0x082A30, 0x07D2FA, 0x077F0F, 0x072E31, 0x06E02A, 0x0694C8, 0x064BDF, 0x060546, | ||
1600 | 0x05C0DA, 0x057E78, 0x053E03, 0x04FF5F, 0x04C273, 0x048726, 0x044D64, 0x041518, | ||
1601 | 0x03DE30, 0x03A89B, 0x037448, 0x03412A, 0x030F32, 0x02DE52, 0x02AE80, 0x027FB0, | ||
1602 | 0x0251D6, 0x0224EA, 0x01F8E2, 0x01CDB4, 0x01A359, 0x0179C9, 0x0150FC, 0x0128EB, | ||
1603 | 0x010190, 0x00DAE4, 0x00B4E1, 0x008F82, 0x006AC1, 0x004699, 0x002305}; | ||
1651 | 1604 | ||
1652 | empty_space = limiter_buffer_count(false); | 1605 | struct curve_point |
1606 | { | ||
1607 | int32_t db; /* S15.16 format */ | ||
1608 | int32_t offset; /* S15.16 format */ | ||
1609 | } db_curve[4]; | ||
1653 | 1610 | ||
1654 | if (empty_space > 0) | 1611 | /** Set up the shape of the compression curve first as decibel values*/ |
1655 | /** FILL BUFFER | 1612 | /* db_curve[0] = bottom of knee |
1656 | * use as many inbound samples as necessary to fill the buffer */ | 1613 | [1] = threshold |
1614 | [2] = top of knee | ||
1615 | [3] = 0 db input */ | ||
1616 | db_curve[1].db = c_menu.threshold << 16; | ||
1617 | db_curve[1].offset = 0; | ||
1618 | if (c_menu.soft_knee) | ||
1657 | { | 1619 | { |
1658 | /* don't try to fill with more samples than available */ | 1620 | /* bottom of knee is 3dB below the threshold for soft knee*/ |
1659 | if (empty_space > count) | 1621 | db_curve[0].db = db_curve[1].db - (3 << 16); |
1660 | empty_space = count; | 1622 | db_curve[0].offset = 0; |
1661 | logf(" Filling limiter buffer: %d", empty_space); | 1623 | /* top of knee is 3dB above the threshold for soft knee */ |
1662 | while (empty_space-- > 0) | 1624 | db_curve[2].db = db_curve[1].db + (3 << 16); |
1663 | { | 1625 | if (c_menu.ratio) |
1664 | for (i = 0; i <= ch; i++) | 1626 | /* offset = -3db * (ratio - 1) / ratio */ |
1665 | { | 1627 | db_curve[2].offset = (int32_t)((long long)(-3 << 16) |
1666 | /* put inbound samples in the limiter buffer */ | 1628 | * (c_menu.ratio - 1) / c_menu.ratio); |
1667 | in_samp = *in_buf[i]++; | 1629 | else |
1668 | *end_lim_buf[i]++ = in_samp; | 1630 | /* offset = -3db for hard limit */ |
1669 | if (end_lim_buf[i] == &limiter_buffer[i][LIMITER_BUFFER_SIZE]) | 1631 | db_curve[2].offset = (-3 << 16); |
1670 | end_lim_buf[i] = limiter_buffer[i]; | ||
1671 | if (in_samp < 0) /* make positive for comparison */ | ||
1672 | in_samp = -in_samp - 1; | ||
1673 | if (in_samp <= clip_max) | ||
1674 | in_samp = 0; /* disregard if not clipped */ | ||
1675 | if (i == 0) | ||
1676 | samp0 = in_samp; | ||
1677 | if (i == ch) | ||
1678 | { | ||
1679 | /* assign peak value for each inbound sample pair */ | ||
1680 | *end_peak++ = ((samp0 > 0) || (in_samp > 0)) ? | ||
1681 | get_peak_value(MAX(samp0, in_samp)) : 0; | ||
1682 | if (end_peak == &lim_buf_peak[LIMITER_BUFFER_SIZE]) | ||
1683 | end_peak = lim_buf_peak; | ||
1684 | } | ||
1685 | } | ||
1686 | count--; | ||
1687 | } | ||
1688 | /* after buffer fills, the remaining inbound samples are cycled */ | ||
1689 | } | 1632 | } |
1690 | 1633 | else | |
1691 | limiter_buffer_full = (end_lim_buf[0] == start_lim_buf[0]); | ||
1692 | out_count = count; | ||
1693 | |||
1694 | /** CYCLE BUFFER | ||
1695 | * return buffered samples and backfill limiter buffer with new ones. | ||
1696 | * The buffer is always full when cycling. */ | ||
1697 | while (count-- > 0) | ||
1698 | { | 1634 | { |
1699 | for (i = 0; i <= ch; i++) | 1635 | /* bottom of knee is at the threshold for hard knee */ |
1700 | { | 1636 | db_curve[0].db = c_menu.threshold << 16; |
1701 | /* copy incoming sample */ | 1637 | db_curve[0].offset = 0; |
1702 | in_samp = *in_buf[i]++; | 1638 | /* top of knee is at the threshold for hard knee */ |
1703 | /* put limiter buffer sample into outbound buffer */ | 1639 | db_curve[2].db = c_menu.threshold << 16; |
1704 | *out_buf[i]++ = *start_lim_buf[i]++; | 1640 | db_curve[2].offset = 0; |
1705 | /* put incoming sample on the end of the limiter buffer */ | ||
1706 | *end_lim_buf[i]++ = in_samp; | ||
1707 | /* ring buffer pointer wrap */ | ||
1708 | if (start_lim_buf[i] == &limiter_buffer[i][LIMITER_BUFFER_SIZE]) | ||
1709 | start_lim_buf[i] = limiter_buffer[i]; | ||
1710 | if (end_lim_buf[i] == &limiter_buffer[i][LIMITER_BUFFER_SIZE]) | ||
1711 | end_lim_buf[i] = limiter_buffer[i]; | ||
1712 | if (in_samp < 0) /* make positive for comparison */ | ||
1713 | in_samp = -in_samp - 1; | ||
1714 | if (in_samp <= clip_max) | ||
1715 | in_samp = 0; /* disregard if not clipped */ | ||
1716 | if (i == 0) | ||
1717 | { | ||
1718 | samp0 = in_samp; | ||
1719 | /* assign outgoing sample its associated peak value */ | ||
1720 | *out_buf_peak_index++ = *start_peak++; | ||
1721 | if (start_peak == &lim_buf_peak[LIMITER_BUFFER_SIZE]) | ||
1722 | start_peak = lim_buf_peak; | ||
1723 | } | ||
1724 | if (i == ch) | ||
1725 | { | ||
1726 | /* assign peak value for each inbound sample pair */ | ||
1727 | *end_peak++ = ((samp0 > 0) || (in_samp > 0)) ? | ||
1728 | get_peak_value(MAX(samp0, in_samp)) : 0; | ||
1729 | if (end_peak == &lim_buf_peak[LIMITER_BUFFER_SIZE]) | ||
1730 | end_peak = lim_buf_peak; | ||
1731 | } | ||
1732 | } | ||
1733 | } | 1641 | } |
1734 | } | 1642 | /* 0db input is also max offset point (most compression) */ |
1735 | 1643 | db_curve[3].db = 0; | |
1736 | return out_count; | 1644 | if (c_menu.ratio) |
1737 | } | 1645 | /* offset = threshold * (ratio - 1) / ratio */ |
1738 | 1646 | db_curve[3].offset = (int32_t)((long long)(c_menu.threshold << 16) | |
1739 | /** RETURN LIMITER BUFFER COUNT | 1647 | * (c_menu.ratio - 1) / c_menu.ratio); |
1740 | * If argument is true, returns number of samples in the buffer, | ||
1741 | * otherwise, returns empty space remaining */ | ||
1742 | static int limiter_buffer_count(bool buf_count) | ||
1743 | { | ||
1744 | int count; | ||
1745 | if (limiter_buffer_full) | ||
1746 | count = LIMITER_BUFFER_SIZE; | ||
1747 | else if (end_lim_buf[0] >= start_lim_buf[0]) | ||
1748 | count = (end_lim_buf[0] - start_lim_buf[0]); | ||
1749 | else | ||
1750 | count = (end_lim_buf[0] - start_lim_buf[0]) + LIMITER_BUFFER_SIZE; | ||
1751 | return buf_count ? count : (LIMITER_BUFFER_SIZE - count); | ||
1752 | } | ||
1753 | |||
1754 | /** FLUSH THE LIMITER BUFFER | ||
1755 | * Empties the limiter buffer into the buffer pointed to by the argument | ||
1756 | * and returns the number of samples in that buffer */ | ||
1757 | int dsp_flush_limiter_buffer(char *dest) | ||
1758 | { | ||
1759 | if ((!limiter_buffer_active) || (limiter_buffer_count(true) <= 0)) | ||
1760 | return 0; | ||
1761 | |||
1762 | logf(" dsp_flush_limiter_buffer"); | ||
1763 | int32_t flush_buf[2][LIMITER_BUFFER_SIZE]; | ||
1764 | int32_t *src[2] = {flush_buf[0], flush_buf[1]}; | ||
1765 | |||
1766 | limiter_buffer_emptying = true; | ||
1767 | int count = limiter_process(0, src); | ||
1768 | AUDIO_DSP.output_samples(count, &AUDIO_DSP.data, | ||
1769 | (const int32_t **)src, (int16_t *)dest); | ||
1770 | return count; | ||
1771 | } | ||
1772 | |||
1773 | /** GET PEAK VALUE | ||
1774 | * Return a small value representing how much the sample is clipped. This | ||
1775 | * should only be called if a sample is actually clipped. Sample is a | ||
1776 | * positive value. | ||
1777 | */ | ||
1778 | static uint16_t get_peak_value(int32_t sample) | ||
1779 | { | ||
1780 | const int frac_bits = AUDIO_DSP.frac_bits; | ||
1781 | int mid, | ||
1782 | hi = 48, | ||
1783 | lo = 0; | ||
1784 | |||
1785 | /* shift sample into 28 frac bit range for comparison */ | ||
1786 | if (frac_bits > 28) | ||
1787 | sample >>= (frac_bits - 28); | ||
1788 | if (frac_bits < 28) | ||
1789 | sample <<= (28 - frac_bits); | ||
1790 | |||
1791 | /* if clipped out of range, return maximum value */ | ||
1792 | if (sample >= clip_steps[48]) | ||
1793 | return 48 * 90; | ||
1794 | |||
1795 | /* find amount of sample clipping on the table */ | ||
1796 | do | ||
1797 | { | ||
1798 | mid = (hi + lo) / 2; | ||
1799 | if (sample < clip_steps[mid]) | ||
1800 | hi = mid; | ||
1801 | else if (sample > clip_steps[mid]) | ||
1802 | lo = mid; | ||
1803 | else | 1648 | else |
1804 | return mid * 90; | 1649 | /* offset = threshold for hard limit */ |
1805 | } | 1650 | db_curve[3].offset = (c_menu.threshold << 16); |
1806 | while (hi > (lo + 1)); | 1651 | |
1807 | 1652 | /* Now set up the comp_curve table with compression offsets in the form | |
1808 | /* interpolate linearly between steps (less accurate but faster) */ | 1653 | of gain factors in S7.24 format */ |
1809 | return ((hi-1) * 90) + (((sample - clip_steps[hi-1]) * 90) / | 1654 | comp_curve[0] = (1 << 24); |
1810 | (clip_steps[hi] - clip_steps[hi-1])); | 1655 | for (i = 1; i < 64; i++) |
1811 | } | ||
1812 | |||
1813 | /** SET LIMITER | ||
1814 | * Called by the menu system to configure the limiter process */ | ||
1815 | void dsp_set_limiter(int limiter_level) | ||
1816 | { | ||
1817 | if (limiter_level > 0) | ||
1818 | { | ||
1819 | if (!limiter_buffer_active) | ||
1820 | { | 1656 | { |
1821 | /* enable limiter process */ | 1657 | int32_t this_db = -db[i]; |
1822 | AUDIO_DSP.limiter_process = limiter_process; | 1658 | /* no compression below the knee */ |
1823 | limiter_buffer_active = true; | 1659 | if (this_db <= db_curve[0].db) |
1660 | comp_curve[i] = (1 << 24); | ||
1661 | |||
1662 | /* if soft knee and below top of knee, interpolate along soft knee slope */ | ||
1663 | else if (c_menu.soft_knee && (this_db <= db_curve[2].db)) | ||
1664 | comp_curve[i] = fp_factor(fp_mul(((this_db - db_curve[0].db) / 6), | ||
1665 | db_curve[2].offset, 16), 16) << 8; | ||
1666 | |||
1667 | /* interpolate along ratio slope above the knee */ | ||
1668 | else | ||
1669 | comp_curve[i] = fp_factor(fp_mul(fp_div((this_db - db_curve[1].db), | ||
1670 | -db_curve[1].db, 16), db_curve[3].offset, 16), 16) << 8; | ||
1824 | } | 1671 | } |
1825 | /* limiter preamp is a gain factor in S7.24 format */ | 1672 | comp_curve[64] = fp_factor(db_curve[3].offset, 16) << 8; |
1826 | long old_preamp = AUDIO_DSP.limiter_preamp; | 1673 | |
1827 | long new_preamp = fp_factor((((long)limiter_level << 24) / 10), 24); | 1674 | logf("\n *** Compression Offsets ***"); |
1828 | if (old_preamp != new_preamp) | 1675 | for (i = 0; i <= 3; i++) |
1829 | { | 1676 | { |
1830 | AUDIO_DSP.limiter_preamp = new_preamp; | 1677 | logf("Curve[%d]: db: % .1f\toffset: % .4f", i, (float)db_curve[i].db / (1 << 16), |
1831 | set_gain(&AUDIO_DSP); | 1678 | (float)db_curve[i].offset / (1 << 16)); |
1832 | logf(" Limiter enable: Yes\tLimiter amp: %.8f", | ||
1833 | (float)AUDIO_DSP.limiter_preamp / (1 << 24)); | ||
1834 | } | 1679 | } |
1835 | } | 1680 | |
1836 | else | 1681 | logf("\nGain factors:"); |
1837 | { | 1682 | for (i = 1; i <= 64; i++) |
1838 | /* disable limiter process*/ | ||
1839 | if (limiter_buffer_active) | ||
1840 | { | 1683 | { |
1841 | AUDIO_DSP.limiter_preamp = (1 << 24); | 1684 | debugf("%02d: %.6f ", i, (float)comp_curve[i] / (1 << 24)); |
1842 | set_gain(&AUDIO_DSP); | 1685 | if (i % 4 == 0) debugf("\n"); |
1843 | /* pcmbuf_flush_limiter_buffer(); */ | ||
1844 | limiter_buffer_active = false; | ||
1845 | AUDIO_DSP.limiter_process = NULL; | ||
1846 | reset_limiter_buffer(&AUDIO_DSP); | ||
1847 | logf(" Limiter enable: No\tLimiter amp: %.8f", | ||
1848 | (float)AUDIO_DSP.limiter_preamp / (1 << 24)); | ||
1849 | } | 1686 | } |
1687 | |||
1688 | /* if using auto peak, then makeup gain is max offset - .1dB headroom */ | ||
1689 | int32_t db_makeup = (c_menu.gain == -1) ? | ||
1690 | -(db_curve[3].offset) - 0x199A : c_menu.gain << 16; | ||
1691 | comp_makeup_gain = fp_factor(db_makeup, 16) << 8; | ||
1692 | logf("Makeup gain:\t%.6f", (float)comp_makeup_gain / (1 << 24)); | ||
1693 | |||
1694 | /* calculate per-sample gain change a rate of 10db over release time */ | ||
1695 | comp_rel_slope = 0xAF0BB2 / c_menu.release; | ||
1696 | logf("Release slope:\t%.6f", (float)comp_rel_slope / (1 << 24)); | ||
1697 | |||
1698 | release_gain = (1 << 24); | ||
1850 | } | 1699 | } |
1700 | |||
1701 | /* enable/disable the compressor */ | ||
1702 | AUDIO_DSP.compressor_process = active ? compressor_process : NULL; | ||
1851 | } | 1703 | } |
1852 | 1704 | ||
1853 | /** LIMITER PROCESS | 1705 | /** GET COMPRESSION GAIN |
1854 | * Checks pre-amplified signal for clipped samples and smoothly reduces gain | 1706 | * Returns the required gain factor in S7.24 format in order to compress the |
1855 | * around the clipped samples using a preset attack/release schedule. | 1707 | * sample in accordance with the compression curve. Always 1 or less. |
1856 | */ | 1708 | */ |
1857 | static int limiter_process(int count, int32_t *buf[]) | 1709 | static inline int32_t get_compression_gain(int32_t sample) |
1858 | { | 1710 | { |
1859 | /* Limiter process passes through if limiter buffer isn't active, or the | 1711 | const int frac_bits = AUDIO_DSP.frac_bits; |
1860 | * sample depth is too large for safe pre-amping */ | ||
1861 | if ((!limiter_buffer_active) || (AUDIO_DSP.frac_bits > 29)) | ||
1862 | return count; | ||
1863 | 1712 | ||
1864 | count = set_limiter_buffer(count, buf); | 1713 | /* sample must be positive */ |
1714 | if (sample < 0) | ||
1715 | sample = -sample - 1; | ||
1716 | |||
1717 | /* shift sample into 22 frac bit range */ | ||
1718 | if (frac_bits > 22) | ||
1719 | sample >>= (frac_bits - 22); | ||
1720 | if (frac_bits < 22) | ||
1721 | sample <<= (22 - frac_bits); | ||
1865 | 1722 | ||
1866 | if (count <= 0) | 1723 | /* index is 6 MSB, rem is 16 LSB */ |
1867 | return 0; | 1724 | int index = sample >> 16; |
1725 | int rem = (sample & 0xFFFF) << 8; | ||
1868 | 1726 | ||
1869 | const int attack_slope = 15; /* 15:1 ratio between attack and release */ | 1727 | /* interpolate from the compression curve */ |
1870 | const int buffer_count = limiter_buffer_count(true); | 1728 | return comp_curve[index] + (int32_t)FRACMUL_SHL((comp_curve[index + 1] |
1729 | - comp_curve[index]), rem, 7); | ||
1730 | } | ||
1731 | |||
1732 | /** COMPRESSOR PROCESS | ||
1733 | * Changes the gain of the samples according to the compressor curve | ||
1734 | */ | ||
1735 | static int compressor_process(int count, int32_t *buf[]) | ||
1736 | { | ||
1737 | const int num_chan = AUDIO_DSP.data.num_channels; | ||
1738 | const int32_t fp_one = (1 << 24); | ||
1871 | 1739 | ||
1740 | int32_t sample_gain, /* S7.24 format */ | ||
1741 | this_gain; /* S7.24 format */ | ||
1872 | int i, ch; | 1742 | int i, ch; |
1873 | uint16_t max_peak = 0, | ||
1874 | gain_peak, | ||
1875 | gain_rem; | ||
1876 | long gain; | ||
1877 | 1743 | ||
1878 | /* step through limiter buffer in reverse order, in order to find the | 1744 | /* Step forward through the output buffer, and modify the offset values |
1879 | * appropriate max_peak for modifying the output buffer */ | ||
1880 | for (i = buffer_count - 1; i >= 0; i--) | ||
1881 | { | ||
1882 | const uint16_t peak_i = lim_buf_peak[(start_peak - lim_buf_peak + i) % | ||
1883 | LIMITER_BUFFER_SIZE]; | ||
1884 | /* if no attack slope, nothing to do */ | ||
1885 | if ((peak_i == 0) && (max_peak == 0)) continue; | ||
1886 | /* if new peak, start attack slope */ | ||
1887 | if (peak_i >= max_peak) | ||
1888 | { | ||
1889 | max_peak = peak_i; | ||
1890 | } | ||
1891 | /* keep sloping */ | ||
1892 | else | ||
1893 | { | ||
1894 | if (max_peak > attack_slope) | ||
1895 | max_peak -= attack_slope; | ||
1896 | else | ||
1897 | max_peak = 0; | ||
1898 | } | ||
1899 | } | ||
1900 | /* step through output buffer the same way, but this time modifying peak | ||
1901 | * values to create a smooth attack slope. */ | ||
1902 | for (i = count - 1; i >= 0; i--) | ||
1903 | { | ||
1904 | /* if no attack slope, nothing to do */ | ||
1905 | if ((out_buf_peak[i] == 0) && (max_peak == 0)) continue; | ||
1906 | /* if new peak, start attack slope */ | ||
1907 | if (out_buf_peak[i] >= max_peak) | ||
1908 | { | ||
1909 | max_peak = out_buf_peak[i]; | ||
1910 | } | ||
1911 | /* keep sloping */ | ||
1912 | else | ||
1913 | { | ||
1914 | if (max_peak > attack_slope) | ||
1915 | max_peak -= attack_slope; | ||
1916 | else | ||
1917 | max_peak = 0; | ||
1918 | out_buf_peak[i] = max_peak; | ||
1919 | } | ||
1920 | } | ||
1921 | /* Now step forward through the output buffer, and modify the peak values | ||
1922 | * to establish a smooth, slow release slope.*/ | 1745 | * to establish a smooth, slow release slope.*/ |
1923 | for (i = 0; i < count; i++) | 1746 | for (i = 0; i < count; i++) |
1924 | { | 1747 | { |
1925 | /* if no release slope, nothing to do */ | 1748 | sample_gain = fp_one; |
1926 | if ((out_buf_peak[i] == 0) && (release_peak == 0)) continue; | 1749 | for (ch = 0; ch < num_chan; ch++) |
1927 | /* if new peak, start release slope */ | ||
1928 | if (out_buf_peak[i] >= release_peak) | ||
1929 | { | 1750 | { |
1930 | release_peak = out_buf_peak[i]; | 1751 | this_gain = get_compression_gain(buf[ch][i]); |
1752 | if (this_gain < sample_gain) | ||
1753 | sample_gain = this_gain; | ||
1931 | } | 1754 | } |
1932 | /* keep sloping */ | 1755 | /* if no release slope, only apply makeup gain */ |
1756 | if ((sample_gain == fp_one) && (release_gain == fp_one)) | ||
1757 | gain_buffer[i] = comp_makeup_gain; | ||
1933 | else | 1758 | else |
1934 | { | 1759 | { |
1935 | release_peak--; | 1760 | /* if larger offset, start release slope */ |
1936 | out_buf_peak[i] = release_peak; | 1761 | if (sample_gain <= release_gain) |
1762 | release_gain = sample_gain; | ||
1763 | else /* keep sloping */ | ||
1764 | { | ||
1765 | if (release_gain < (fp_one - comp_rel_slope)) | ||
1766 | release_gain += comp_rel_slope; | ||
1767 | else | ||
1768 | release_gain = fp_one; | ||
1769 | } | ||
1770 | /* store offset with release and also apply makeup gain */ | ||
1771 | if ((release_gain == fp_one) && (comp_makeup_gain == fp_one)) | ||
1772 | gain_buffer[i] = fp_one; | ||
1773 | else | ||
1774 | gain_buffer[i] = FRACMUL_SHL(release_gain, comp_makeup_gain, 7); | ||
1937 | } | 1775 | } |
1938 | } | 1776 | } |
1939 | /* Implement the limiter: adjust gain of the outbound samples by the gain | 1777 | |
1940 | * amounts in the gain steps array corresponding to the peak values. */ | 1778 | /* Implement the compressor: apply those gain factors to the output |
1779 | * buffer samples */ | ||
1780 | |||
1941 | for (i = 0; i < count; i++) | 1781 | for (i = 0; i < count; i++) |
1942 | { | 1782 | { |
1943 | if (out_buf_peak[i] > 0) | 1783 | if (gain_buffer[i] != fp_one) |
1944 | { | 1784 | { |
1945 | gain_peak = (out_buf_peak[i] + 1) / 90; | 1785 | for (ch = 0; ch < num_chan; ch++) |
1946 | gain_rem = (out_buf_peak[i] + 1) % 90; | 1786 | buf[ch][i] = FRACMUL_SHL(buf[ch][i], gain_buffer[i], 7); |
1947 | gain = gain_steps[gain_peak]; | ||
1948 | if ((gain_peak < 48) && (gain_rem > 0)) | ||
1949 | gain -= gain_rem * ((gain_steps[gain_peak] - | ||
1950 | gain_steps[gain_peak + 1]) / 90); | ||
1951 | for (ch = 0; ch < AUDIO_DSP.data.num_channels; ch++) | ||
1952 | buf[ch][i] = FRACMUL_SHL(buf[ch][i], gain, 3); | ||
1953 | } | 1787 | } |
1954 | } | 1788 | } |
1955 | return count; | 1789 | return count; |
1956 | } | 1790 | } |
diff --git a/apps/dsp.h b/apps/dsp.h index b2d8493445..ab42d73b24 100644 --- a/apps/dsp.h +++ b/apps/dsp.h | |||
@@ -26,8 +26,7 @@ | |||
26 | #include <stdbool.h> | 26 | #include <stdbool.h> |
27 | 27 | ||
28 | #define NATIVE_FREQUENCY 44100 | 28 | #define NATIVE_FREQUENCY 44100 |
29 | #define LIMITER_BUFFER_SIZE 288 /* ~6.5 ms */ | 29 | |
30 | #define MAX_LIMITER_GAIN 80 /* 8 dB */ | ||
31 | enum | 30 | enum |
32 | { | 31 | { |
33 | STEREO_INTERLEAVED = 0, | 32 | STEREO_INTERLEAVED = 0, |
@@ -82,7 +81,7 @@ int32_t sound_get_pitch(void); | |||
82 | void dsp_set_timestretch(int32_t percent); | 81 | void dsp_set_timestretch(int32_t percent); |
83 | int32_t dsp_get_timestretch(void); | 82 | int32_t dsp_get_timestretch(void); |
84 | int dsp_callback(int msg, intptr_t param); | 83 | int dsp_callback(int msg, intptr_t param); |
85 | int dsp_flush_limiter_buffer(char *dest); | 84 | void dsp_set_compressor(int c_threshold, int c_ratio, int c_gain, |
86 | void dsp_set_limiter(int limiter_level); | 85 | int c_knee, int c_release); |
87 | 86 | ||
88 | #endif | 87 | #endif |
diff --git a/apps/fixedpoint.h b/apps/fixedpoint.h index fd68fc162c..6670e597fb 100644 --- a/apps/fixedpoint.h +++ b/apps/fixedpoint.h | |||
@@ -61,7 +61,7 @@ long fp_sincos(unsigned long phase, long *cos); | |||
61 | #define FP_NEGINF -(0x7fffffff) | 61 | #define FP_NEGINF -(0x7fffffff) |
62 | 62 | ||
63 | /* fracbits in range 12 - 22 work well. Higher is better for | 63 | /* fracbits in range 12 - 22 work well. Higher is better for |
64 | * calculating dB, lower is better for calculating ratio. | 64 | * calculating dB, lower is better for calculating factor. |
65 | */ | 65 | */ |
66 | /* long fp_decibels(unsigned long factor, unsigned int fracbits); */ | 66 | /* long fp_decibels(unsigned long factor, unsigned int fracbits); */ |
67 | long fp_factor(long decibels, unsigned int fracbits); | 67 | long fp_factor(long decibels, unsigned int fracbits); |
diff --git a/apps/lang/dansk.lang b/apps/lang/dansk.lang index 1c005fb9ac..e4393e7dd3 100644 --- a/apps/lang/dansk.lang +++ b/apps/lang/dansk.lang | |||
@@ -12646,15 +12646,15 @@ | |||
12646 | user: core | 12646 | user: core |
12647 | <source> | 12647 | <source> |
12648 | *: none | 12648 | *: none |
12649 | swcodec: "Limiter Preamp" | 12649 | swcodec: "Compressor" |
12650 | </source> | 12650 | </source> |
12651 | <dest> | 12651 | <dest> |
12652 | *: none | 12652 | *: none |
12653 | swcodec: "Begrænser forforstærkning" | 12653 | swcodec: "Compressor" |
12654 | </dest> | 12654 | </dest> |
12655 | <voice> | 12655 | <voice> |
12656 | *: none | 12656 | *: none |
12657 | swcodec: "Begrænser for-forstærkning" | 12657 | swcodec: "Compressor" |
12658 | </voice> | 12658 | </voice> |
12659 | </phrase> | 12659 | </phrase> |
12660 | <phrase> | 12660 | <phrase> |
diff --git a/apps/lang/deutsch.lang b/apps/lang/deutsch.lang index bdacebaa27..e7f78f800e 100644 --- a/apps/lang/deutsch.lang +++ b/apps/lang/deutsch.lang | |||
@@ -12641,15 +12641,15 @@ | |||
12641 | user: core | 12641 | user: core |
12642 | <source> | 12642 | <source> |
12643 | *: none | 12643 | *: none |
12644 | swcodec: "Limiter Preamp" | 12644 | swcodec: "Compressor" |
12645 | </source> | 12645 | </source> |
12646 | <dest> | 12646 | <dest> |
12647 | *: none | 12647 | *: none |
12648 | swcodec: "Begrenzer-Vorverstärkung" | 12648 | swcodec: "Compressor" |
12649 | </dest> | 12649 | </dest> |
12650 | <voice> | 12650 | <voice> |
12651 | *: none | 12651 | *: none |
12652 | swcodec: "Begrenzer-Vorverstärkung" | 12652 | swcodec: "Compressor" |
12653 | </voice> | 12653 | </voice> |
12654 | </phrase> | 12654 | </phrase> |
12655 | <phrase> | 12655 | <phrase> |
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 08412d376d..72e0a4ce90 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -12707,15 +12707,15 @@ | |||
12707 | user: core | 12707 | user: core |
12708 | <source> | 12708 | <source> |
12709 | *: none | 12709 | *: none |
12710 | swcodec: "Limiter Preamp" | 12710 | swcodec: "Compressor" |
12711 | </source> | 12711 | </source> |
12712 | <dest> | 12712 | <dest> |
12713 | *: none | 12713 | *: none |
12714 | swcodec: "Limiter Preamp" | 12714 | swcodec: "Compressor" |
12715 | </dest> | 12715 | </dest> |
12716 | <voice> | 12716 | <voice> |
12717 | *: none | 12717 | *: none |
12718 | swcodec: "Limiter Preamp" | 12718 | swcodec: "Compressor" |
12719 | </voice> | 12719 | </voice> |
12720 | </phrase> | 12720 | </phrase> |
12721 | <phrase> | 12721 | <phrase> |
@@ -12769,3 +12769,224 @@ | |||
12769 | radio: "Other" | 12769 | radio: "Other" |
12770 | </voice> | 12770 | </voice> |
12771 | </phrase> | 12771 | </phrase> |
12772 | <phrase> | ||
12773 | id: LANG_COMPRESSOR_THRESHOLD | ||
12774 | desc: in sound settings | ||
12775 | user: core | ||
12776 | <source> | ||
12777 | *: none | ||
12778 | swcodec: "Threshold" | ||
12779 | </source> | ||
12780 | <dest> | ||
12781 | *: none | ||
12782 | swcodec: "Threshold" | ||
12783 | </dest> | ||
12784 | <voice> | ||
12785 | *: none | ||
12786 | swcodec: "Threshold" | ||
12787 | </voice> | ||
12788 | </phrase> | ||
12789 | <phrase> | ||
12790 | id: LANG_COMPRESSOR_RATIO | ||
12791 | desc: in sound settings | ||
12792 | user: core | ||
12793 | <source> | ||
12794 | *: none | ||
12795 | swcodec: "Ratio" | ||
12796 | </source> | ||
12797 | <dest> | ||
12798 | *: none | ||
12799 | swcodec: "Ratio" | ||
12800 | </dest> | ||
12801 | <voice> | ||
12802 | *: none | ||
12803 | swcodec: "Ratio" | ||
12804 | </voice> | ||
12805 | </phrase> | ||
12806 | <phrase> | ||
12807 | id: LANG_COMPRESSOR_RATIO_2 | ||
12808 | desc: in sound settings | ||
12809 | user: core | ||
12810 | <source> | ||
12811 | *: none | ||
12812 | swcodec: "2:1" | ||
12813 | </source> | ||
12814 | <dest> | ||
12815 | *: none | ||
12816 | swcodec: "2:1" | ||
12817 | </dest> | ||
12818 | <voice> | ||
12819 | *: none | ||
12820 | swcodec: "2 to 1" | ||
12821 | </voice> | ||
12822 | </phrase> | ||
12823 | <phrase> | ||
12824 | id: LANG_COMPRESSOR_RATIO_4 | ||
12825 | desc: in sound settings | ||
12826 | user: core | ||
12827 | <source> | ||
12828 | *: none | ||
12829 | swcodec: "4:1" | ||
12830 | </source> | ||
12831 | <dest> | ||
12832 | *: none | ||
12833 | swcodec: "4:1" | ||
12834 | </dest> | ||
12835 | <voice> | ||
12836 | *: none | ||
12837 | swcodec: "4 to 1" | ||
12838 | </voice> | ||
12839 | </phrase> | ||
12840 | <phrase> | ||
12841 | id: LANG_COMPRESSOR_RATIO_6 | ||
12842 | desc: in sound settings | ||
12843 | user: core | ||
12844 | <source> | ||
12845 | *: none | ||
12846 | swcodec: "6:1" | ||
12847 | </source> | ||
12848 | <dest> | ||
12849 | *: none | ||
12850 | swcodec: "6:1" | ||
12851 | </dest> | ||
12852 | <voice> | ||
12853 | *: none | ||
12854 | swcodec: "6 to 1" | ||
12855 | </voice> | ||
12856 | </phrase> | ||
12857 | <phrase> | ||
12858 | id: LANG_COMPRESSOR_RATIO_10 | ||
12859 | desc: in sound settings | ||
12860 | user: core | ||
12861 | <source> | ||
12862 | *: none | ||
12863 | swcodec: "10:1" | ||
12864 | </source> | ||
12865 | <dest> | ||
12866 | *: none | ||
12867 | swcodec: "10:1" | ||
12868 | </dest> | ||
12869 | <voice> | ||
12870 | *: none | ||
12871 | swcodec: "10 to 1" | ||
12872 | </voice> | ||
12873 | </phrase> | ||
12874 | <phrase> | ||
12875 | id: LANG_COMPRESSOR_RATIO_LIMIT | ||
12876 | desc: in sound settings | ||
12877 | user: core | ||
12878 | <source> | ||
12879 | *: none | ||
12880 | swcodec: "Limit" | ||
12881 | </source> | ||
12882 | <dest> | ||
12883 | *: none | ||
12884 | swcodec: "Limit" | ||
12885 | </dest> | ||
12886 | <voice> | ||
12887 | *: none | ||
12888 | swcodec: "Limit" | ||
12889 | </voice> | ||
12890 | </phrase> | ||
12891 | <phrase> | ||
12892 | id: LANG_COMPRESSOR_GAIN | ||
12893 | desc: in sound settings | ||
12894 | user: core | ||
12895 | <source> | ||
12896 | *: none | ||
12897 | swcodec: "Makeup Gain" | ||
12898 | </source> | ||
12899 | <dest> | ||
12900 | *: none | ||
12901 | swcodec: "Makeup Gain" | ||
12902 | </dest> | ||
12903 | <voice> | ||
12904 | *: none | ||
12905 | swcodec: "Makeup Gain" | ||
12906 | </voice> | ||
12907 | </phrase> | ||
12908 | <phrase> | ||
12909 | id: LANG_AUTO | ||
12910 | desc: in sound settings | ||
12911 | user: core | ||
12912 | <source> | ||
12913 | *: none | ||
12914 | swcodec: "Auto" | ||
12915 | </source> | ||
12916 | <dest> | ||
12917 | *: none | ||
12918 | swcodec: "Auto" | ||
12919 | </dest> | ||
12920 | <voice> | ||
12921 | *: none | ||
12922 | swcodec: "Auto" | ||
12923 | </voice> | ||
12924 | </phrase> | ||
12925 | <phrase> | ||
12926 | id: LANG_COMPRESSOR_KNEE | ||
12927 | desc: in sound settings | ||
12928 | user: core | ||
12929 | <source> | ||
12930 | *: none | ||
12931 | swcodec: "Knee" | ||
12932 | </source> | ||
12933 | <dest> | ||
12934 | *: none | ||
12935 | swcodec: "Knee" | ||
12936 | </dest> | ||
12937 | <voice> | ||
12938 | *: none | ||
12939 | swcodec: "Knee" | ||
12940 | </voice> | ||
12941 | </phrase> | ||
12942 | <phrase> | ||
12943 | id: LANG_COMPRESSOR_HARD_KNEE | ||
12944 | desc: in sound settings | ||
12945 | user: core | ||
12946 | <source> | ||
12947 | *: none | ||
12948 | swcodec: "Hard Knee" | ||
12949 | </source> | ||
12950 | <dest> | ||
12951 | *: none | ||
12952 | swcodec: "Hard Knee" | ||
12953 | </dest> | ||
12954 | <voice> | ||
12955 | *: none | ||
12956 | swcodec: "Hard Knee" | ||
12957 | </voice> | ||
12958 | </phrase> | ||
12959 | <phrase> | ||
12960 | id: LANG_COMPRESSOR_SOFT_KNEE | ||
12961 | desc: in sound settings | ||
12962 | user: core | ||
12963 | <source> | ||
12964 | *: none | ||
12965 | swcodec: "Soft Knee" | ||
12966 | </source> | ||
12967 | <dest> | ||
12968 | *: none | ||
12969 | swcodec: "Soft Knee" | ||
12970 | </dest> | ||
12971 | <voice> | ||
12972 | *: none | ||
12973 | swcodec: "Soft Knee" | ||
12974 | </voice> | ||
12975 | </phrase> | ||
12976 | <phrase> | ||
12977 | id: LANG_COMPRESSOR_RELEASE | ||
12978 | desc: in sound settings | ||
12979 | user: core | ||
12980 | <source> | ||
12981 | *: none | ||
12982 | swcodec: "Release Time" | ||
12983 | </source> | ||
12984 | <dest> | ||
12985 | *: none | ||
12986 | swcodec: "Release Time" | ||
12987 | </dest> | ||
12988 | <voice> | ||
12989 | *: none | ||
12990 | swcodec: "Release Time" | ||
12991 | </voice> | ||
12992 | </phrase> | ||
diff --git a/apps/lang/francais.lang b/apps/lang/francais.lang index 43fe7561f2..7d4af8ade7 100644 --- a/apps/lang/francais.lang +++ b/apps/lang/francais.lang | |||
@@ -12663,15 +12663,15 @@ | |||
12663 | user: core | 12663 | user: core |
12664 | <source> | 12664 | <source> |
12665 | *: none | 12665 | *: none |
12666 | swcodec: "Limiter Preamp" | 12666 | swcodec: "Compressor" |
12667 | </source> | 12667 | </source> |
12668 | <dest> | 12668 | <dest> |
12669 | *: none | 12669 | *: none |
12670 | swcodec: "Limiteur préampli." | 12670 | swcodec: "Compressor" |
12671 | </dest> | 12671 | </dest> |
12672 | <voice> | 12672 | <voice> |
12673 | *: none | 12673 | *: none |
12674 | swcodec: "Limiteur préampli" | 12674 | swcodec: "Compressor" |
12675 | </voice> | 12675 | </voice> |
12676 | </phrase> | 12676 | </phrase> |
12677 | <phrase> | 12677 | <phrase> |
diff --git a/apps/lang/italiano.lang b/apps/lang/italiano.lang index 075520d2af..0727320c45 100644 --- a/apps/lang/italiano.lang +++ b/apps/lang/italiano.lang | |||
@@ -12636,15 +12636,15 @@ | |||
12636 | user: core | 12636 | user: core |
12637 | <source> | 12637 | <source> |
12638 | *: none | 12638 | *: none |
12639 | swcodec: "Limiter Preamp" | 12639 | swcodec: "Compressor" |
12640 | </source> | 12640 | </source> |
12641 | <dest> | 12641 | <dest> |
12642 | *: none | 12642 | *: none |
12643 | swcodec: "Limitatore Preamp" | 12643 | swcodec: "Compressor" |
12644 | </dest> | 12644 | </dest> |
12645 | <voice> | 12645 | <voice> |
12646 | *: none | 12646 | *: none |
12647 | swcodec: "Limitatore Preamp" | 12647 | swcodec: "Compressor" |
12648 | </voice> | 12648 | </voice> |
12649 | </phrase> | 12649 | </phrase> |
12650 | <phrase> | 12650 | <phrase> |
diff --git a/apps/lang/polski.lang b/apps/lang/polski.lang index 5595526145..86017a4998 100644 --- a/apps/lang/polski.lang +++ b/apps/lang/polski.lang | |||
@@ -12644,15 +12644,15 @@ | |||
12644 | user: core | 12644 | user: core |
12645 | <source> | 12645 | <source> |
12646 | *: none | 12646 | *: none |
12647 | swcodec: "Limiter Preamp" | 12647 | swcodec: "Compressor" |
12648 | </source> | 12648 | </source> |
12649 | <dest> | 12649 | <dest> |
12650 | *: none | 12650 | *: none |
12651 | swcodec: "Wzmacnianie cichych fragmentów" | 12651 | swcodec: "Compressor" |
12652 | </dest> | 12652 | </dest> |
12653 | <voice> | 12653 | <voice> |
12654 | *: none | 12654 | *: none |
12655 | swcodec: "Wzmacnianie cichych fragmentów" | 12655 | swcodec: "Compressor" |
12656 | </voice> | 12656 | </voice> |
12657 | </phrase> | 12657 | </phrase> |
12658 | <phrase> | 12658 | <phrase> |
diff --git a/apps/lang/svenska.lang b/apps/lang/svenska.lang index 7a1564bded..24c33e7d0b 100644 --- a/apps/lang/svenska.lang +++ b/apps/lang/svenska.lang | |||
@@ -12637,15 +12637,15 @@ | |||
12637 | user: core | 12637 | user: core |
12638 | <source> | 12638 | <source> |
12639 | *: none | 12639 | *: none |
12640 | swcodec: "Limiter Preamp" | 12640 | swcodec: "Compressor" |
12641 | </source> | 12641 | </source> |
12642 | <dest> | 12642 | <dest> |
12643 | *: none | 12643 | *: none |
12644 | swcodec: "Limiter-förförstärkning" | 12644 | swcodec: "Compressor" |
12645 | </dest> | 12645 | </dest> |
12646 | <voice> | 12646 | <voice> |
12647 | *: none | 12647 | *: none |
12648 | swcodec: "Limiter-förförstärkning" | 12648 | swcodec: "Compressor" |
12649 | </voice> | 12649 | </voice> |
12650 | </phrase> | 12650 | </phrase> |
12651 | <phrase> | 12651 | <phrase> |
diff --git a/apps/lang/tagalog.lang b/apps/lang/tagalog.lang index 667a9d8c28..4600eab9f4 100644 --- a/apps/lang/tagalog.lang +++ b/apps/lang/tagalog.lang | |||
@@ -12445,15 +12445,15 @@ | |||
12445 | user: core | 12445 | user: core |
12446 | <source> | 12446 | <source> |
12447 | *: none | 12447 | *: none |
12448 | swcodec: "Limiter Preamp" | 12448 | swcodec: "Compressor" |
12449 | </source> | 12449 | </source> |
12450 | <dest> | 12450 | <dest> |
12451 | *: none | 12451 | *: none |
12452 | swcodec: "Limiter Preamp" | 12452 | swcodec: "Compressor" |
12453 | </dest> | 12453 | </dest> |
12454 | <voice> | 12454 | <voice> |
12455 | *: none | 12455 | *: none |
12456 | swcodec: "Limiter Preamp" | 12456 | swcodec: "Compressor" |
12457 | </voice> | 12457 | </voice> |
12458 | </phrase> | 12458 | </phrase> |
12459 | <phrase> | 12459 | <phrase> |
diff --git a/apps/lang/walon.lang b/apps/lang/walon.lang index c645ad10a2..c7a06ff55a 100644 --- a/apps/lang/walon.lang +++ b/apps/lang/walon.lang | |||
@@ -12632,19 +12632,19 @@ | |||
12632 | </voice> | 12632 | </voice> |
12633 | </phrase> | 12633 | </phrase> |
12634 | <phrase> | 12634 | <phrase> |
12635 | id: LANG_LIMITER | 12635 | id: LANG_COMPRESSOR |
12636 | desc: in sound settings | 12636 | desc: in sound settings |
12637 | user: core | 12637 | user: core |
12638 | <source> | 12638 | <source> |
12639 | *: none | 12639 | *: none |
12640 | swcodec: "Limiter Preamp" | 12640 | swcodec: "Compressor" |
12641 | </source> | 12641 | </source> |
12642 | <dest> | 12642 | <dest> |
12643 | *: none | 12643 | *: none |
12644 | swcodec: "Aschatrece Preamp" | 12644 | swcodec: "Compressor" |
12645 | </dest> | 12645 | </dest> |
12646 | <voice> | 12646 | <voice> |
12647 | *: none | 12647 | *: none |
12648 | swcodec: "Aschatrece Preamp" | 12648 | swcodec: "Compressor" |
12649 | </voice> | 12649 | </voice> |
12650 | </phrase> | 12650 | </phrase> |
diff --git a/apps/menus/sound_menu.c b/apps/menus/sound_menu.c index 678d495d07..60315804a9 100644 --- a/apps/menus/sound_menu.c +++ b/apps/menus/sound_menu.c | |||
@@ -105,8 +105,21 @@ static int timestretch_callback(int action,const struct menu_item_ex *this_item) | |||
105 | &global_settings.timestretch_enabled, timestretch_callback); | 105 | &global_settings.timestretch_enabled, timestretch_callback); |
106 | MENUITEM_SETTING(dithering_enabled, | 106 | MENUITEM_SETTING(dithering_enabled, |
107 | &global_settings.dithering_enabled, lowlatency_callback); | 107 | &global_settings.dithering_enabled, lowlatency_callback); |
108 | MENUITEM_SETTING(limiter_level, | 108 | |
109 | &global_settings.limiter_level, lowlatency_callback); | 109 | /* compressor submenu */ |
110 | MENUITEM_SETTING(compressor_threshold, | ||
111 | &global_settings.compressor_threshold, lowlatency_callback); | ||
112 | MENUITEM_SETTING(compressor_ratio, | ||
113 | &global_settings.compressor_ratio, lowlatency_callback); | ||
114 | MENUITEM_SETTING(compressor_gain, | ||
115 | &global_settings.compressor_makeup_gain, lowlatency_callback); | ||
116 | MENUITEM_SETTING(compressor_knee, | ||
117 | &global_settings.compressor_knee, lowlatency_callback); | ||
118 | MENUITEM_SETTING(compressor_release, | ||
119 | &global_settings.compressor_release_time, lowlatency_callback); | ||
120 | MAKE_MENU(compressor_menu,ID2P(LANG_COMPRESSOR), NULL, Icon_NOICON, | ||
121 | &compressor_threshold, &compressor_ratio, &compressor_gain, | ||
122 | &compressor_knee, &compressor_release); | ||
110 | #endif | 123 | #endif |
111 | 124 | ||
112 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | 125 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) |
@@ -140,7 +153,7 @@ MAKE_MENU(sound_settings, ID2P(LANG_SOUND_SETTINGS), NULL, Icon_Audio, | |||
140 | #if CONFIG_CODEC == SWCODEC | 153 | #if CONFIG_CODEC == SWCODEC |
141 | ,&crossfeed_menu, &equalizer_menu, &dithering_enabled | 154 | ,&crossfeed_menu, &equalizer_menu, &dithering_enabled |
142 | ,×tretch_enabled | 155 | ,×tretch_enabled |
143 | ,&limiter_level | 156 | ,&compressor_menu |
144 | #endif | 157 | #endif |
145 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | 158 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) |
146 | ,&loudness,&avc,&superbass,&mdb_enable,&mdb_strength | 159 | ,&loudness,&avc,&superbass,&mdb_enable,&mdb_strength |
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index 66a4ed4128..319e3e8044 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c | |||
@@ -1170,30 +1170,6 @@ bool pcmbuf_is_crossfade_enabled(void) | |||
1170 | * Commit any remaining samples in the PCM buffer for playback. */ | 1170 | * Commit any remaining samples in the PCM buffer for playback. */ |
1171 | void pcmbuf_play_remainder(void) | 1171 | void pcmbuf_play_remainder(void) |
1172 | { | 1172 | { |
1173 | pcmbuf_flush_limiter_buffer(); | ||
1174 | |||
1175 | if (audiobuffer_fillpos) | 1173 | if (audiobuffer_fillpos) |
1176 | pcmbuf_flush_fillpos(); | 1174 | pcmbuf_flush_fillpos(); |
1177 | } | 1175 | } |
1178 | |||
1179 | /** FLUSH LIMITER BUFFER | ||
1180 | * Empty the limiter buffer and commit its contents | ||
1181 | * to the PCM buffer for playback. */ | ||
1182 | void pcmbuf_flush_limiter_buffer(void) | ||
1183 | { | ||
1184 | char *dest; | ||
1185 | int out_count = LIMITER_BUFFER_SIZE; | ||
1186 | |||
1187 | /* create room at the end of the PCM buffer for any | ||
1188 | samples that may be held back in the limiter buffer */ | ||
1189 | while ((dest = pcmbuf_request_buffer(&out_count)) == NULL) | ||
1190 | { | ||
1191 | cancel_cpu_boost(); | ||
1192 | sleep(1); | ||
1193 | } | ||
1194 | |||
1195 | /* flush the limiter buffer into the PCM buffer */ | ||
1196 | out_count = dsp_flush_limiter_buffer(dest); | ||
1197 | if (out_count > 0) | ||
1198 | pcmbuf_write_complete(out_count); | ||
1199 | } | ||
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h index 12a41a253c..4cb1c1acb7 100644 --- a/apps/pcmbuf.h +++ b/apps/pcmbuf.h | |||
@@ -76,6 +76,5 @@ void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude); | |||
76 | int pcmbuf_used_descs(void); | 76 | int pcmbuf_used_descs(void); |
77 | int pcmbuf_descs(void); | 77 | int pcmbuf_descs(void); |
78 | void pcmbuf_play_remainder(void); | 78 | void pcmbuf_play_remainder(void); |
79 | void pcmbuf_flush_limiter_buffer(void); | ||
80 | 79 | ||
81 | #endif | 80 | #endif |
diff --git a/apps/plugin.c b/apps/plugin.c index a497ad0456..aa7077edae 100644 --- a/apps/plugin.c +++ b/apps/plugin.c | |||
@@ -467,7 +467,6 @@ static const struct plugin_api rockbox_api = { | |||
467 | dsp_process, | 467 | dsp_process, |
468 | dsp_input_count, | 468 | dsp_input_count, |
469 | dsp_output_count, | 469 | dsp_output_count, |
470 | dsp_flush_limiter_buffer, | ||
471 | #endif /* CONFIG_CODEC == SWCODEC */ | 470 | #endif /* CONFIG_CODEC == SWCODEC */ |
472 | 471 | ||
473 | /* playback control */ | 472 | /* playback control */ |
diff --git a/apps/plugin.h b/apps/plugin.h index 4981230df3..b4a6b4fc1b 100644 --- a/apps/plugin.h +++ b/apps/plugin.h | |||
@@ -133,12 +133,12 @@ void* plugin_get_buffer(size_t *buffer_size); | |||
133 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ | 133 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ |
134 | 134 | ||
135 | /* increase this every time the api struct changes */ | 135 | /* increase this every time the api struct changes */ |
136 | #define PLUGIN_API_VERSION 171 | 136 | #define PLUGIN_API_VERSION 172 |
137 | 137 | ||
138 | /* update this to latest version if a change to the api struct breaks | 138 | /* update this to latest version if a change to the api struct breaks |
139 | backwards compatibility (and please take the opportunity to sort in any | 139 | backwards compatibility (and please take the opportunity to sort in any |
140 | new function which are "waiting" at the end of the function table) */ | 140 | new function which are "waiting" at the end of the function table) */ |
141 | #define PLUGIN_MIN_API_VERSION 171 | 141 | #define PLUGIN_MIN_API_VERSION 172 |
142 | 142 | ||
143 | /* plugin return codes */ | 143 | /* plugin return codes */ |
144 | enum plugin_status { | 144 | enum plugin_status { |
@@ -596,7 +596,6 @@ struct plugin_api { | |||
596 | const char *src[], int count); | 596 | const char *src[], int count); |
597 | int (*dsp_input_count)(struct dsp_config *dsp, int count); | 597 | int (*dsp_input_count)(struct dsp_config *dsp, int count); |
598 | int (*dsp_output_count)(struct dsp_config *dsp, int count); | 598 | int (*dsp_output_count)(struct dsp_config *dsp, int count); |
599 | int (*dsp_flush_limiter_buffer)(char *dest); | ||
600 | #endif /* CONFIG_CODEC == SWCODC */ | 599 | #endif /* CONFIG_CODEC == SWCODC */ |
601 | 600 | ||
602 | /* playback control */ | 601 | /* playback control */ |
diff --git a/apps/plugins/test_codec.c b/apps/plugins/test_codec.c index b77611689b..b41f053571 100644 --- a/apps/plugins/test_codec.c +++ b/apps/plugins/test_codec.c | |||
@@ -810,34 +810,10 @@ show_menu: | |||
810 | 810 | ||
811 | rb->closedir(dir); | 811 | rb->closedir(dir); |
812 | } | 812 | } |
813 | /* process last samples */ | ||
814 | if (use_dsp) | ||
815 | rb->dsp_flush_limiter_buffer(dspbuffer); | ||
816 | } else { | 813 | } else { |
817 | /* Just test the file */ | 814 | /* Just test the file */ |
818 | res = test_track(parameter); | 815 | res = test_track(parameter); |
819 | 816 | ||
820 | /* process last samples */ | ||
821 | if (use_dsp) | ||
822 | { | ||
823 | int channels = (wavinfo.stereomode == STEREO_MONO) ? 1 : 2; | ||
824 | int count = rb->dsp_flush_limiter_buffer(dspbuffer); | ||
825 | if (channels == 1) | ||
826 | { | ||
827 | unsigned char *s = dspbuffer, *d = dspbuffer; | ||
828 | int c = count; | ||
829 | while (c-- > 0) | ||
830 | { | ||
831 | *d++ = *s++; | ||
832 | *d++ = *s++; | ||
833 | s++; | ||
834 | s++; | ||
835 | } | ||
836 | } | ||
837 | if (wavinfo.fd >= 0) | ||
838 | rb->write(wavinfo.fd, dspbuffer, count * 2 * channels); | ||
839 | } | ||
840 | |||
841 | /* Close WAV file (if there was one) */ | 817 | /* Close WAV file (if there was one) */ |
842 | if (wavinfo.fd >= 0) { | 818 | if (wavinfo.fd >= 0) { |
843 | close_wav(); | 819 | close_wav(); |
diff --git a/apps/settings.c b/apps/settings.c index 4c16c6a0ec..ce1ee07054 100644 --- a/apps/settings.c +++ b/apps/settings.c | |||
@@ -956,7 +956,11 @@ void settings_apply(bool read_disk) | |||
956 | 956 | ||
957 | dsp_dither_enable(global_settings.dithering_enabled); | 957 | dsp_dither_enable(global_settings.dithering_enabled); |
958 | dsp_timestretch_enable(global_settings.timestretch_enabled); | 958 | dsp_timestretch_enable(global_settings.timestretch_enabled); |
959 | dsp_set_limiter(global_settings.limiter_level); | 959 | dsp_set_compressor(global_settings.compressor_threshold, |
960 | global_settings.compressor_ratio, | ||
961 | global_settings.compressor_makeup_gain, | ||
962 | global_settings.compressor_knee, | ||
963 | global_settings.compressor_release_time); | ||
960 | #endif | 964 | #endif |
961 | 965 | ||
962 | #ifdef HAVE_SPDIF_POWER | 966 | #ifdef HAVE_SPDIF_POWER |
diff --git a/apps/settings.h b/apps/settings.h index e8ffe91471..ec92a81734 100644 --- a/apps/settings.h +++ b/apps/settings.h | |||
@@ -777,7 +777,11 @@ struct user_settings | |||
777 | #endif | 777 | #endif |
778 | 778 | ||
779 | #if CONFIG_CODEC == SWCODEC | 779 | #if CONFIG_CODEC == SWCODEC |
780 | int limiter_level; | 780 | int compressor_threshold; |
781 | int compressor_ratio; | ||
782 | int compressor_makeup_gain; | ||
783 | int compressor_knee; | ||
784 | int compressor_release_time; | ||
781 | #endif | 785 | #endif |
782 | 786 | ||
783 | }; | 787 | }; |
diff --git a/apps/settings_list.c b/apps/settings_list.c index 2a7bf9658f..2e3632b949 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c | |||
@@ -356,6 +356,34 @@ static void crossfeed_cross_set(int val) | |||
356 | global_settings.crossfeed_hf_cutoff); | 356 | global_settings.crossfeed_hf_cutoff); |
357 | } | 357 | } |
358 | 358 | ||
359 | static void compressor_set(int val) | ||
360 | { | ||
361 | (void)val; | ||
362 | dsp_set_compressor(global_settings.compressor_threshold, | ||
363 | global_settings.compressor_ratio, | ||
364 | global_settings.compressor_makeup_gain, | ||
365 | global_settings.compressor_knee, | ||
366 | global_settings.compressor_release_time); | ||
367 | } | ||
368 | |||
369 | static const char* auto_formatter(char *buffer, size_t buffer_size, | ||
370 | int val, const char *unit) | ||
371 | { | ||
372 | if (val == -1) | ||
373 | return str(LANG_AUTO); | ||
374 | else | ||
375 | snprintf(buffer, buffer_size, "%d %s", val, unit); | ||
376 | return buffer; | ||
377 | } | ||
378 | |||
379 | static int32_t auto_getlang(int value, int unit) | ||
380 | { | ||
381 | if (value == -1) | ||
382 | return LANG_AUTO; | ||
383 | else | ||
384 | return TALK_ID(value, unit); | ||
385 | } | ||
386 | |||
359 | static const char* db_format(char* buffer, size_t buffer_size, int value, | 387 | static const char* db_format(char* buffer, size_t buffer_size, int value, |
360 | const char* unit) | 388 | const char* unit) |
361 | { | 389 | { |
@@ -1256,11 +1284,29 @@ const struct settings_list settings[] = { | |||
1256 | OFFON_SETTING(F_SOUNDSETTING, timestretch_enabled, LANG_TIMESTRETCH, false, | 1284 | OFFON_SETTING(F_SOUNDSETTING, timestretch_enabled, LANG_TIMESTRETCH, false, |
1257 | "timestretch enabled", dsp_timestretch_enable), | 1285 | "timestretch enabled", dsp_timestretch_enable), |
1258 | 1286 | ||
1259 | /* limiter */ | 1287 | /* compressor */ |
1260 | INT_SETTING_NOWRAP(F_SOUNDSETTING, limiter_level, | 1288 | INT_SETTING_NOWRAP(F_SOUNDSETTING, compressor_threshold, |
1261 | LANG_COMPRESSOR, 0, | 1289 | LANG_COMPRESSOR_THRESHOLD, 0, |
1262 | "limiter level", UNIT_DB, 0, MAX_LIMITER_GAIN, | 1290 | "compressor threshold", UNIT_DB, 0, -24, |
1263 | 5, db_format, get_dec_talkid, dsp_set_limiter), | 1291 | -3, formatter_unit_0_is_off, getlang_unit_0_is_off, compressor_set), |
1292 | CHOICE_SETTING(F_SOUNDSETTING|F_NO_WRAP, compressor_ratio, | ||
1293 | LANG_COMPRESSOR_RATIO, 1, "compressor ratio", | ||
1294 | "2:1,4:1,6:1,10:1,limit", compressor_set, 5, | ||
1295 | ID2P(LANG_COMPRESSOR_RATIO_2), ID2P(LANG_COMPRESSOR_RATIO_4), | ||
1296 | ID2P(LANG_COMPRESSOR_RATIO_6), ID2P(LANG_COMPRESSOR_RATIO_10), | ||
1297 | ID2P(LANG_COMPRESSOR_RATIO_LIMIT)), | ||
1298 | INT_SETTING_NOWRAP(F_SOUNDSETTING, compressor_makeup_gain, | ||
1299 | LANG_COMPRESSOR_GAIN, -1, | ||
1300 | "compressor makeup gain", UNIT_DB, -1, 20, | ||
1301 | 1, auto_formatter, auto_getlang, compressor_set), | ||
1302 | CHOICE_SETTING(F_SOUNDSETTING|F_NO_WRAP, compressor_knee, | ||
1303 | LANG_COMPRESSOR_KNEE, 1, "compressor knee", | ||
1304 | "hard knee,soft knee", compressor_set, 2, | ||
1305 | ID2P(LANG_COMPRESSOR_HARD_KNEE), ID2P(LANG_COMPRESSOR_SOFT_KNEE)), | ||
1306 | INT_SETTING_NOWRAP(F_SOUNDSETTING, compressor_release_time, | ||
1307 | LANG_COMPRESSOR_RELEASE, 100, | ||
1308 | "compressor release time", UNIT_MS, 20, 200, | ||
1309 | 10, NULL, NULL, compressor_set), | ||
1264 | #endif | 1310 | #endif |
1265 | #ifdef HAVE_WM8758 | 1311 | #ifdef HAVE_WM8758 |
1266 | SOUND_SETTING(F_NO_WRAP, bass_cutoff, LANG_BASS_CUTOFF, | 1312 | SOUND_SETTING(F_NO_WRAP, bass_cutoff, LANG_BASS_CUTOFF, |