diff options
Diffstat (limited to 'apps/dsp.c')
-rw-r--r-- | apps/dsp.c | 464 |
1 files changed, 459 insertions, 5 deletions
diff --git a/apps/dsp.c b/apps/dsp.c index 61fc027e4c..c8c8ddee75 100644 --- a/apps/dsp.c +++ b/apps/dsp.c | |||
@@ -35,6 +35,11 @@ | |||
35 | #include "buffer.h" | 35 | #include "buffer.h" |
36 | #include "fixedpoint.h" | 36 | #include "fixedpoint.h" |
37 | #include "fracmul.h" | 37 | #include "fracmul.h" |
38 | #include "pcmbuf.h" | ||
39 | |||
40 | /* Define LOGF_ENABLE to enable logf output in this file */ | ||
41 | /*#define LOGF_ENABLE*/ | ||
42 | #include "logf.h" | ||
38 | 43 | ||
39 | /* 16-bit samples are scaled based on these constants. The shift should be | 44 | /* 16-bit samples are scaled based on these constants. The shift should be |
40 | * no more than 15. | 45 | * no more than 15. |
@@ -149,7 +154,8 @@ typedef void (*channels_process_fn_type)(int count, int32_t *buf[]); | |||
149 | /* DSP local channel processing in place */ | 154 | /* DSP local channel processing in place */ |
150 | typedef void (*channels_process_dsp_fn_type)(int count, struct dsp_data *data, | 155 | typedef void (*channels_process_dsp_fn_type)(int count, struct dsp_data *data, |
151 | int32_t *buf[]); | 156 | int32_t *buf[]); |
152 | 157 | /* DSP processes that return a value */ | |
158 | typedef int (*return_fn_type)(int count, int32_t *buf[]); | ||
153 | 159 | ||
154 | /* | 160 | /* |
155 | ***************************************************************************/ | 161 | ***************************************************************************/ |
@@ -165,6 +171,7 @@ struct dsp_config | |||
165 | int32_t tdspeed_percent; /* Speed% * PITCH_SPEED_PRECISION */ | 171 | int32_t tdspeed_percent; /* Speed% * PITCH_SPEED_PRECISION */ |
166 | bool tdspeed_active; /* Timestretch is in use */ | 172 | bool tdspeed_active; /* Timestretch is in use */ |
167 | int frac_bits; | 173 | int frac_bits; |
174 | long limiter_preamp; /* limiter amp gain in S7.24 format */ | ||
168 | #ifdef HAVE_SW_TONE_CONTROLS | 175 | #ifdef HAVE_SW_TONE_CONTROLS |
169 | /* Filter struct for software bass/treble controls */ | 176 | /* Filter struct for software bass/treble controls */ |
170 | struct eqfilter tone_filter; | 177 | struct eqfilter tone_filter; |
@@ -180,6 +187,7 @@ struct dsp_config | |||
180 | channels_process_fn_type apply_crossfeed; | 187 | channels_process_fn_type apply_crossfeed; |
181 | channels_process_fn_type eq_process; | 188 | channels_process_fn_type eq_process; |
182 | channels_process_fn_type channels_process; | 189 | channels_process_fn_type channels_process; |
190 | return_fn_type limiter_process; | ||
183 | }; | 191 | }; |
184 | 192 | ||
185 | /* General DSP config */ | 193 | /* General DSP config */ |
@@ -219,6 +227,55 @@ static long album_peak; | |||
219 | static long replaygain; | 227 | static long replaygain; |
220 | static bool crossfeed_enabled; | 228 | static bool crossfeed_enabled; |
221 | 229 | ||
230 | /* limiter */ | ||
231 | static int count_adjust; | ||
232 | static bool limiter_buffer_active; | ||
233 | static bool limiter_buffer_full; | ||
234 | static bool limiter_buffer_emptying; | ||
235 | static int32_t limiter_buffer[2][LIMITER_BUFFER_SIZE] IBSS_ATTR; | ||
236 | static int32_t *start_lim_buf[2] IBSS_ATTR, | ||
237 | *end_lim_buf[2] IBSS_ATTR; | ||
238 | static uint16_t lim_buf_peak[LIMITER_BUFFER_SIZE] IBSS_ATTR; | ||
239 | static uint16_t *start_peak IBSS_ATTR, | ||
240 | *end_peak IBSS_ATTR; | ||
241 | static uint16_t out_buf_peak[LIMITER_BUFFER_SIZE] IBSS_ATTR; | ||
242 | static uint16_t *out_buf_peak_index IBSS_ATTR; | ||
243 | static uint16_t release_peak IBSS_ATTR; | ||
244 | static int32_t in_samp IBSS_ATTR, | ||
245 | samp0 IBSS_ATTR; | ||
246 | |||
247 | static void reset_limiter_buffer(struct dsp_config *dsp); | ||
248 | static int limiter_buffer_count(bool buf_count); | ||
249 | static int limiter_process(int count, int32_t *buf[]); | ||
250 | static uint16_t get_peak_value(int32_t sample); | ||
251 | |||
252 | /* The clip_steps array essentially stores the results of fp_factor from | ||
253 | * 0 to 12 dB, in 48 equal steps, in S3.28 format. */ | ||
254 | const long clip_steps[49] ICONST_ATTR = { 0x10000000, | ||
255 | 0x10779AFA, 0x10F2B409, 0x1171654C, 0x11F3C9A0, 0x1279FCAD, | ||
256 | 0x13041AE9, 0x139241A2, 0x14248EF9, 0x14BB21F9, 0x15561A92, | ||
257 | 0x15F599A0, 0x1699C0F9, 0x1742B36B, 0x17F094CE, 0x18A38A01, | ||
258 | 0x195BB8F9, 0x1A1948C5, 0x1ADC619B, 0x1BA52CDC, 0x1C73D51D, | ||
259 | 0x1D488632, 0x1E236D3A, 0x1F04B8A1, 0x1FEC982C, 0x20DB3D0E, | ||
260 | 0x21D0D9E2, 0x22CDA2BE, 0x23D1CD41, 0x24DD9099, 0x25F12590, | ||
261 | 0x270CC693, 0x2830AFD3, 0x295D1F37, 0x2A925471, 0x2BD0911F, | ||
262 | 0x2D1818B3, 0x2E6930AD, 0x2FC42095, 0x312931EC, 0x3298B072, | ||
263 | 0x3412EA24, 0x35982F3A, 0x3728D22E, 0x38C52808, 0x3A6D8847, | ||
264 | 0x3C224CD9, 0x3DE3D264, 0x3FB2783F}; | ||
265 | /* The gain_steps array essentially stores the results of fp_factor from | ||
266 | * 0 to -12 dB, in 48 equal steps, in S3.28 format. */ | ||
267 | const long gain_steps[49] ICONST_ATTR = { 0x10000000, | ||
268 | 0xF8BC9C0, 0xF1ADF94, 0xEAD2988, 0xE429058, 0xDDAFD68, | ||
269 | 0xD765AC1, 0xD149309, 0xCB59186, 0xC594210, 0xBFF9112, | ||
270 | 0xBA86B88, 0xB53BEF5, 0xB017965, 0xAB18964, 0xA63DDFE, | ||
271 | 0xA1866BA, 0x9CF1397, 0x987D507, 0x9429BEE, 0x8FF599E, | ||
272 | 0x8BDFFD3, 0x87E80B0, 0x840CEBE, 0x804DCE8, 0x7CA9E76, | ||
273 | 0x792070E, 0x75B0AB0, 0x7259DB2, 0x6F1B4BF, 0x6BF44D5, | ||
274 | 0x68E4342, 0x65EA5A0, 0x63061D6, 0x6036E15, 0x5D7C0D3, | ||
275 | 0x5AD50CE, 0x5841505, 0x55C04B8, 0x535176A, 0x50F44D9, | ||
276 | 0x4EA84FE, 0x4C6D00E, 0x4A41E78, 0x48268DF, 0x461A81C, | ||
277 | 0x441D53E, 0x422E985, 0x404DE62}; | ||
278 | |||
222 | #define AUDIO_DSP (dsp_conf[CODEC_IDX_AUDIO]) | 279 | #define AUDIO_DSP (dsp_conf[CODEC_IDX_AUDIO]) |
223 | #define VOICE_DSP (dsp_conf[CODEC_IDX_VOICE]) | 280 | #define VOICE_DSP (dsp_conf[CODEC_IDX_VOICE]) |
224 | 281 | ||
@@ -869,6 +926,7 @@ static void dsp_apply_gain(int count, struct dsp_data *data, int32_t *buf[]) | |||
869 | /* Combine all gains to a global gain. */ | 926 | /* Combine all gains to a global gain. */ |
870 | static void set_gain(struct dsp_config *dsp) | 927 | static void set_gain(struct dsp_config *dsp) |
871 | { | 928 | { |
929 | /* gains are in S7.24 format */ | ||
872 | dsp->data.gain = DEFAULT_GAIN; | 930 | dsp->data.gain = DEFAULT_GAIN; |
873 | 931 | ||
874 | /* Replay gain not relevant to voice */ | 932 | /* Replay gain not relevant to voice */ |
@@ -879,8 +937,14 @@ static void set_gain(struct dsp_config *dsp) | |||
879 | 937 | ||
880 | if (dsp->eq_process && eq_precut) | 938 | if (dsp->eq_process && eq_precut) |
881 | { | 939 | { |
882 | dsp->data.gain = | 940 | dsp->data.gain = fp_mul(dsp->data.gain, eq_precut, 24); |
883 | (long) (((int64_t) dsp->data.gain * eq_precut) >> 24); | 941 | } |
942 | |||
943 | /* only preamp for the limiter if limiter is active and sample depth | ||
944 | * allows safe pre-amping (12 dB is OK with 29 or less frac bits) */ | ||
945 | if ((dsp->limiter_preamp) && (dsp->frac_bits <= 29)) | ||
946 | { | ||
947 | dsp->data.gain = fp_mul(dsp->data.gain, dsp->limiter_preamp, 24); | ||
884 | } | 948 | } |
885 | 949 | ||
886 | #ifdef HAVE_SW_VOLUME_CONTROL | 950 | #ifdef HAVE_SW_VOLUME_CONTROL |
@@ -898,7 +962,7 @@ static void set_gain(struct dsp_config *dsp) | |||
898 | } | 962 | } |
899 | else | 963 | else |
900 | { | 964 | { |
901 | dsp->data.gain >>= 1; | 965 | dsp->data.gain >>= 1; /* convert gain to S8.23 format */ |
902 | } | 966 | } |
903 | 967 | ||
904 | dsp->apply_gain = dsp->data.gain != 0 ? dsp_apply_gain : NULL; | 968 | dsp->apply_gain = dsp->data.gain != 0 ? dsp_apply_gain : NULL; |
@@ -1207,7 +1271,7 @@ int dsp_process(struct dsp_config *dsp, char *dst, const char *src[], int count) | |||
1207 | 1271 | ||
1208 | if (dsp->tdspeed_active) | 1272 | if (dsp->tdspeed_active) |
1209 | samples = tdspeed_doit(tmp, samples); | 1273 | samples = tdspeed_doit(tmp, samples); |
1210 | 1274 | ||
1211 | int chunk_offset = 0; | 1275 | int chunk_offset = 0; |
1212 | while (samples > 0) | 1276 | while (samples > 0) |
1213 | { | 1277 | { |
@@ -1239,6 +1303,9 @@ int dsp_process(struct dsp_config *dsp, char *dst, const char *src[], int count) | |||
1239 | 1303 | ||
1240 | if (dsp->channels_process) | 1304 | if (dsp->channels_process) |
1241 | dsp->channels_process(chunk, t2); | 1305 | dsp->channels_process(chunk, t2); |
1306 | |||
1307 | if (dsp->limiter_process) | ||
1308 | chunk = dsp->limiter_process(chunk, t2); | ||
1242 | 1309 | ||
1243 | dsp->output_samples(chunk, &dsp->data, (const int32_t **)t2, (int16_t *)dst); | 1310 | dsp->output_samples(chunk, &dsp->data, (const int32_t **)t2, (int16_t *)dst); |
1244 | 1311 | ||
@@ -1286,6 +1353,15 @@ int dsp_output_count(struct dsp_config *dsp, int count) | |||
1286 | */ | 1353 | */ |
1287 | if (count > RESAMPLE_BUF_RIGHT_CHANNEL) | 1354 | if (count > RESAMPLE_BUF_RIGHT_CHANNEL) |
1288 | count = RESAMPLE_BUF_RIGHT_CHANNEL; | 1355 | count = RESAMPLE_BUF_RIGHT_CHANNEL; |
1356 | |||
1357 | /* If the limiter buffer is filling, some or all samples will | ||
1358 | * be captured by it, so expect fewer samples coming out. */ | ||
1359 | if (limiter_buffer_active && !limiter_buffer_full) | ||
1360 | { | ||
1361 | int empty_space = limiter_buffer_count(false); | ||
1362 | count_adjust = MIN(empty_space, count); | ||
1363 | count -= count_adjust; | ||
1364 | } | ||
1289 | 1365 | ||
1290 | return count; | 1366 | return count; |
1291 | } | 1367 | } |
@@ -1295,6 +1371,13 @@ int dsp_output_count(struct dsp_config *dsp, int count) | |||
1295 | */ | 1371 | */ |
1296 | int dsp_input_count(struct dsp_config *dsp, int count) | 1372 | int dsp_input_count(struct dsp_config *dsp, int count) |
1297 | { | 1373 | { |
1374 | /* If the limiter buffer is filling, the output count was | ||
1375 | * adjusted downward. This adjusts it back so that input | ||
1376 | * count is not affected. | ||
1377 | */ | ||
1378 | if (limiter_buffer_active && !limiter_buffer_full) | ||
1379 | count += count_adjust; | ||
1380 | |||
1298 | /* count is now the number of resampled input samples. Convert to | 1381 | /* count is now the number of resampled input samples. Convert to |
1299 | original input samples. */ | 1382 | original input samples. */ |
1300 | if (dsp->resample) | 1383 | if (dsp->resample) |
@@ -1412,6 +1495,7 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) | |||
1412 | dsp_update_functions(dsp); | 1495 | dsp_update_functions(dsp); |
1413 | resampler_new_delta(dsp); | 1496 | resampler_new_delta(dsp); |
1414 | tdspeed_setup(dsp); | 1497 | tdspeed_setup(dsp); |
1498 | reset_limiter_buffer(dsp); | ||
1415 | break; | 1499 | break; |
1416 | 1500 | ||
1417 | case DSP_FLUSH: | 1501 | case DSP_FLUSH: |
@@ -1420,6 +1504,7 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) | |||
1420 | resampler_new_delta(dsp); | 1504 | resampler_new_delta(dsp); |
1421 | dither_init(dsp); | 1505 | dither_init(dsp); |
1422 | tdspeed_setup(dsp); | 1506 | tdspeed_setup(dsp); |
1507 | reset_limiter_buffer(dsp); | ||
1423 | break; | 1508 | break; |
1424 | 1509 | ||
1425 | case DSP_SET_TRACK_GAIN: | 1510 | case DSP_SET_TRACK_GAIN: |
@@ -1498,3 +1583,372 @@ void dsp_set_replaygain(void) | |||
1498 | replaygain = gain; | 1583 | replaygain = gain; |
1499 | set_gain(&AUDIO_DSP); | 1584 | set_gain(&AUDIO_DSP); |
1500 | } | 1585 | } |
1586 | |||
1587 | /** RESET THE LIMITER BUFFER | ||
1588 | * Force the limiter buffer to its initial state and discard | ||
1589 | * any samples held there. */ | ||
1590 | static void reset_limiter_buffer(struct dsp_config *dsp) | ||
1591 | { | ||
1592 | if (dsp == &AUDIO_DSP) | ||
1593 | { | ||
1594 | int i; | ||
1595 | logf(" reset_limiter_buffer"); | ||
1596 | for (i = 0; i < 2; i++) | ||
1597 | start_lim_buf[i] = end_lim_buf[i] = limiter_buffer[i]; | ||
1598 | start_peak = end_peak = lim_buf_peak; | ||
1599 | limiter_buffer_full = false; | ||
1600 | limiter_buffer_emptying = false; | ||
1601 | release_peak = 0; | ||
1602 | } | ||
1603 | } | ||
1604 | |||
1605 | /** OPERATE THE LIMITER BUFFER | ||
1606 | * Handle all samples entering or exiting the limiter buffer. */ | ||
1607 | static inline int set_limiter_buffer(int count, int32_t *buf[]) | ||
1608 | { | ||
1609 | int32_t *in_buf[] = {buf[0], buf[1]}, | ||
1610 | *out_buf[] = {buf[0], buf[1]}; | ||
1611 | int empty_space, i, out_count; | ||
1612 | const long clip_max = AUDIO_DSP.data.clip_max; | ||
1613 | const int ch = AUDIO_DSP.data.num_channels - 1; | ||
1614 | out_buf_peak_index = out_buf_peak; | ||
1615 | |||
1616 | if (limiter_buffer_emptying) | ||
1617 | /** EMPTY THE BUFFER | ||
1618 | * since the empty flag has been set, assume no inbound samples and | ||
1619 | return all samples in the limiter buffer to the outbound buffer */ | ||
1620 | { | ||
1621 | count = limiter_buffer_count(true); | ||
1622 | out_count = count; | ||
1623 | logf(" Emptying limiter buffer: %d", count); | ||
1624 | while (count-- > 0) | ||
1625 | { | ||
1626 | for (i = 0; i <= ch; i++) | ||
1627 | { | ||
1628 | /* move samples in limiter buffer to output buffer */ | ||
1629 | *out_buf[i]++ = *start_lim_buf[i]++; | ||
1630 | if (start_lim_buf[i] == &limiter_buffer[i][LIMITER_BUFFER_SIZE]) | ||
1631 | start_lim_buf[i] = limiter_buffer[i]; | ||
1632 | /* move limiter buffer peak values to output peak values */ | ||
1633 | if (i == 0) | ||
1634 | { | ||
1635 | *out_buf_peak_index++ = *start_peak++; | ||
1636 | if (start_peak == &lim_buf_peak[LIMITER_BUFFER_SIZE]) | ||
1637 | start_peak = lim_buf_peak; | ||
1638 | } | ||
1639 | } | ||
1640 | } | ||
1641 | reset_limiter_buffer(&AUDIO_DSP); | ||
1642 | } | ||
1643 | else /* limiter buffer NOT emptying */ | ||
1644 | { | ||
1645 | if (count <= 0) return 0; | ||
1646 | |||
1647 | empty_space = limiter_buffer_count(false); | ||
1648 | |||
1649 | if (empty_space > 0) | ||
1650 | /** FILL BUFFER | ||
1651 | * use as many inbound samples as necessary to fill the buffer */ | ||
1652 | { | ||
1653 | /* don't try to fill with more samples than available */ | ||
1654 | if (empty_space > count) | ||
1655 | empty_space = count; | ||
1656 | logf(" Filling limiter buffer: %d", empty_space); | ||
1657 | while (empty_space-- > 0) | ||
1658 | { | ||
1659 | for (i = 0; i <= ch; i++) | ||
1660 | { | ||
1661 | /* put inbound samples in the limiter buffer */ | ||
1662 | in_samp = *in_buf[i]++; | ||
1663 | *end_lim_buf[i]++ = in_samp; | ||
1664 | if (end_lim_buf[i] == &limiter_buffer[i][LIMITER_BUFFER_SIZE]) | ||
1665 | end_lim_buf[i] = limiter_buffer[i]; | ||
1666 | if (in_samp < 0) /* make positive for comparison */ | ||
1667 | in_samp = -in_samp - 1; | ||
1668 | if (in_samp <= clip_max) | ||
1669 | in_samp = 0; /* disregard if not clipped */ | ||
1670 | if (i == 0) | ||
1671 | samp0 = in_samp; | ||
1672 | if (i == ch) | ||
1673 | { | ||
1674 | /* assign peak value for each inbound sample pair */ | ||
1675 | *end_peak++ = ((samp0 > 0) || (in_samp > 0)) ? | ||
1676 | get_peak_value(MAX(samp0, in_samp)) : 0; | ||
1677 | if (end_peak == &lim_buf_peak[LIMITER_BUFFER_SIZE]) | ||
1678 | end_peak = lim_buf_peak; | ||
1679 | } | ||
1680 | } | ||
1681 | count--; | ||
1682 | } | ||
1683 | /* after buffer fills, the remaining inbound samples are cycled */ | ||
1684 | } | ||
1685 | |||
1686 | limiter_buffer_full = (end_lim_buf[0] == start_lim_buf[0]); | ||
1687 | out_count = count; | ||
1688 | |||
1689 | /** CYCLE BUFFER | ||
1690 | * return buffered samples and backfill limiter buffer with new ones. | ||
1691 | * The buffer is always full when cycling. */ | ||
1692 | while (count-- > 0) | ||
1693 | { | ||
1694 | for (i = 0; i <= ch; i++) | ||
1695 | { | ||
1696 | /* copy incoming sample */ | ||
1697 | in_samp = *in_buf[i]++; | ||
1698 | /* put limiter buffer sample into outbound buffer */ | ||
1699 | *out_buf[i]++ = *start_lim_buf[i]++; | ||
1700 | /* put incoming sample on the end of the limiter buffer */ | ||
1701 | *end_lim_buf[i]++ = in_samp; | ||
1702 | /* ring buffer pointer wrap */ | ||
1703 | if (start_lim_buf[i] == &limiter_buffer[i][LIMITER_BUFFER_SIZE]) | ||
1704 | start_lim_buf[i] = limiter_buffer[i]; | ||
1705 | if (end_lim_buf[i] == &limiter_buffer[i][LIMITER_BUFFER_SIZE]) | ||
1706 | end_lim_buf[i] = limiter_buffer[i]; | ||
1707 | if (in_samp < 0) /* make positive for comparison */ | ||
1708 | in_samp = -in_samp - 1; | ||
1709 | if (in_samp <= clip_max) | ||
1710 | in_samp = 0; /* disregard if not clipped */ | ||
1711 | if (i == 0) | ||
1712 | { | ||
1713 | samp0 = in_samp; | ||
1714 | /* assign outgoing sample its associated peak value */ | ||
1715 | *out_buf_peak_index++ = *start_peak++; | ||
1716 | if (start_peak == &lim_buf_peak[LIMITER_BUFFER_SIZE]) | ||
1717 | start_peak = lim_buf_peak; | ||
1718 | } | ||
1719 | if (i == ch) | ||
1720 | { | ||
1721 | /* assign peak value for each inbound sample pair */ | ||
1722 | *end_peak++ = ((samp0 > 0) || (in_samp > 0)) ? | ||
1723 | get_peak_value(MAX(samp0, in_samp)) : 0; | ||
1724 | if (end_peak == &lim_buf_peak[LIMITER_BUFFER_SIZE]) | ||
1725 | end_peak = lim_buf_peak; | ||
1726 | } | ||
1727 | } | ||
1728 | } | ||
1729 | } | ||
1730 | |||
1731 | return out_count; | ||
1732 | } | ||
1733 | |||
1734 | /** RETURN LIMITER BUFFER COUNT | ||
1735 | * If argument is true, returns number of samples in the buffer, | ||
1736 | * otherwise, returns empty space remaining */ | ||
1737 | static int limiter_buffer_count(bool buf_count) | ||
1738 | { | ||
1739 | int count; | ||
1740 | if (limiter_buffer_full) | ||
1741 | count = LIMITER_BUFFER_SIZE; | ||
1742 | else if (end_lim_buf[0] >= start_lim_buf[0]) | ||
1743 | count = (end_lim_buf[0] - start_lim_buf[0]); | ||
1744 | else | ||
1745 | count = (end_lim_buf[0] - start_lim_buf[0]) + LIMITER_BUFFER_SIZE; | ||
1746 | return buf_count ? count : (LIMITER_BUFFER_SIZE - count); | ||
1747 | } | ||
1748 | |||
1749 | /** FLUSH THE LIMITER BUFFER | ||
1750 | * Empties the limiter buffer into the buffer pointed to by the argument | ||
1751 | * and returns the number of samples in that buffer */ | ||
1752 | int dsp_flush_limiter_buffer(char *dest) | ||
1753 | { | ||
1754 | if ((!limiter_buffer_active) || (limiter_buffer_count(true) <= 0)) | ||
1755 | return 0; | ||
1756 | |||
1757 | logf(" dsp_flush_limiter_buffer"); | ||
1758 | int32_t flush_buf[2][LIMITER_BUFFER_SIZE]; | ||
1759 | int32_t *src[2] = {flush_buf[0], flush_buf[1]}; | ||
1760 | |||
1761 | limiter_buffer_emptying = true; | ||
1762 | int count = limiter_process(0, src); | ||
1763 | AUDIO_DSP.output_samples(count, &AUDIO_DSP.data, | ||
1764 | (const int32_t **)src, (int16_t *)dest); | ||
1765 | return count; | ||
1766 | } | ||
1767 | |||
1768 | /** GET PEAK VALUE | ||
1769 | * Return a small value representing how much the sample is clipped. This | ||
1770 | * should only be called if a sample is actually clipped. Sample is a | ||
1771 | * positive value. | ||
1772 | */ | ||
1773 | static uint16_t get_peak_value(int32_t sample) | ||
1774 | { | ||
1775 | const int frac_bits = AUDIO_DSP.frac_bits; | ||
1776 | int mid, | ||
1777 | hi = 48, | ||
1778 | lo = 0; | ||
1779 | |||
1780 | /* shift sample into 28 frac bit range for comparison */ | ||
1781 | if (frac_bits > 28) | ||
1782 | sample >>= (frac_bits - 28); | ||
1783 | if (frac_bits < 28) | ||
1784 | sample <<= (28 - frac_bits); | ||
1785 | |||
1786 | /* if clipped out of range, return maximum value */ | ||
1787 | if (sample >= clip_steps[48]) | ||
1788 | return 48 * 90; | ||
1789 | |||
1790 | /* find amount of sample clipping on the table */ | ||
1791 | do | ||
1792 | { | ||
1793 | mid = (hi + lo) / 2; | ||
1794 | if (sample < clip_steps[mid]) | ||
1795 | hi = mid; | ||
1796 | else if (sample > clip_steps[mid]) | ||
1797 | lo = mid; | ||
1798 | else | ||
1799 | return mid * 90; | ||
1800 | } | ||
1801 | while (hi > (lo + 1)); | ||
1802 | |||
1803 | /* interpolate linearly between steps (less accurate but faster) */ | ||
1804 | return ((hi-1) * 90) + (((sample - clip_steps[hi-1]) * 90) / | ||
1805 | (clip_steps[hi] - clip_steps[hi-1])); | ||
1806 | } | ||
1807 | |||
1808 | /** SET LIMITER | ||
1809 | * Called by the menu system to configure the limiter process */ | ||
1810 | void dsp_set_limiter(int limiter_level) | ||
1811 | { | ||
1812 | if (limiter_level > 0) | ||
1813 | { | ||
1814 | if (!limiter_buffer_active) | ||
1815 | { | ||
1816 | /* enable limiter process */ | ||
1817 | AUDIO_DSP.limiter_process = limiter_process; | ||
1818 | limiter_buffer_active = true; | ||
1819 | } | ||
1820 | /* limiter preamp is a gain factor in S7.24 format */ | ||
1821 | long old_preamp = AUDIO_DSP.limiter_preamp; | ||
1822 | long new_preamp = fp_factor((((long)limiter_level << 24) / 10), 24); | ||
1823 | if (old_preamp != new_preamp) | ||
1824 | { | ||
1825 | AUDIO_DSP.limiter_preamp = new_preamp; | ||
1826 | set_gain(&AUDIO_DSP); | ||
1827 | logf(" Limiter enable: Yes\tLimiter amp: %.8f", | ||
1828 | (float)AUDIO_DSP.limiter_preamp / (1 << 24)); | ||
1829 | } | ||
1830 | } | ||
1831 | else | ||
1832 | { | ||
1833 | /* disable limiter process*/ | ||
1834 | if (limiter_buffer_active) | ||
1835 | { | ||
1836 | AUDIO_DSP.limiter_preamp = (1 << 24); | ||
1837 | set_gain(&AUDIO_DSP); | ||
1838 | /* pcmbuf_flush_limiter_buffer(); */ | ||
1839 | limiter_buffer_active = false; | ||
1840 | AUDIO_DSP.limiter_process = NULL; | ||
1841 | reset_limiter_buffer(&AUDIO_DSP); | ||
1842 | logf(" Limiter enable: No\tLimiter amp: %.8f", | ||
1843 | (float)AUDIO_DSP.limiter_preamp / (1 << 24)); | ||
1844 | } | ||
1845 | } | ||
1846 | } | ||
1847 | |||
1848 | /** LIMITER PROCESS | ||
1849 | * Checks pre-amplified signal for clipped samples and smoothly reduces gain | ||
1850 | * around the clipped samples using a preset attack/release schedule. | ||
1851 | */ | ||
1852 | static int limiter_process(int count, int32_t *buf[]) | ||
1853 | { | ||
1854 | /* Limiter process passes through if limiter buffer isn't active, or the | ||
1855 | * sample depth is too large for safe pre-amping */ | ||
1856 | if ((!limiter_buffer_active) || (AUDIO_DSP.frac_bits > 29)) | ||
1857 | return count; | ||
1858 | |||
1859 | count = set_limiter_buffer(count, buf); | ||
1860 | |||
1861 | if (count <= 0) | ||
1862 | return 0; | ||
1863 | |||
1864 | const int attack_slope = 15; /* 15:1 ratio between attack and release */ | ||
1865 | const int buffer_count = limiter_buffer_count(true); | ||
1866 | |||
1867 | int i, ch; | ||
1868 | uint16_t max_peak = 0, | ||
1869 | gain_peak, | ||
1870 | gain_rem; | ||
1871 | long gain; | ||
1872 | |||
1873 | /* step through limiter buffer in reverse order, in order to find the | ||
1874 | * appropriate max_peak for modifying the output buffer */ | ||
1875 | for (i = buffer_count - 1; i >= 0; i--) | ||
1876 | { | ||
1877 | const uint16_t peak_i = lim_buf_peak[(start_peak - lim_buf_peak + i) % | ||
1878 | LIMITER_BUFFER_SIZE]; | ||
1879 | /* if no attack slope, nothing to do */ | ||
1880 | if ((peak_i == 0) && (max_peak == 0)) continue; | ||
1881 | /* if new peak, start attack slope */ | ||
1882 | if (peak_i >= max_peak) | ||
1883 | { | ||
1884 | max_peak = peak_i; | ||
1885 | } | ||
1886 | /* keep sloping */ | ||
1887 | else | ||
1888 | { | ||
1889 | if (max_peak > attack_slope) | ||
1890 | max_peak -= attack_slope; | ||
1891 | else | ||
1892 | max_peak = 0; | ||
1893 | } | ||
1894 | } | ||
1895 | /* step through output buffer the same way, but this time modifying peak | ||
1896 | * values to create a smooth attack slope. */ | ||
1897 | for (i = count - 1; i >= 0; i--) | ||
1898 | { | ||
1899 | /* if no attack slope, nothing to do */ | ||
1900 | if ((out_buf_peak[i] == 0) && (max_peak == 0)) continue; | ||
1901 | /* if new peak, start attack slope */ | ||
1902 | if (out_buf_peak[i] >= max_peak) | ||
1903 | { | ||
1904 | max_peak = out_buf_peak[i]; | ||
1905 | } | ||
1906 | /* keep sloping */ | ||
1907 | else | ||
1908 | { | ||
1909 | if (max_peak > attack_slope) | ||
1910 | max_peak -= attack_slope; | ||
1911 | else | ||
1912 | max_peak = 0; | ||
1913 | out_buf_peak[i] = max_peak; | ||
1914 | } | ||
1915 | } | ||
1916 | /* Now step forward through the output buffer, and modify the peak values | ||
1917 | * to establish a smooth, slow release slope.*/ | ||
1918 | for (i = 0; i < count; i++) | ||
1919 | { | ||
1920 | /* if no release slope, nothing to do */ | ||
1921 | if ((out_buf_peak[i] == 0) && (release_peak == 0)) continue; | ||
1922 | /* if new peak, start release slope */ | ||
1923 | if (out_buf_peak[i] >= release_peak) | ||
1924 | { | ||
1925 | release_peak = out_buf_peak[i]; | ||
1926 | } | ||
1927 | /* keep sloping */ | ||
1928 | else | ||
1929 | { | ||
1930 | release_peak--; | ||
1931 | out_buf_peak[i] = release_peak; | ||
1932 | } | ||
1933 | } | ||
1934 | /* Implement the limiter: adjust gain of the outbound samples by the gain | ||
1935 | * amounts in the gain steps array corresponding to the peak values. */ | ||
1936 | for (ch = 0; ch < AUDIO_DSP.data.num_channels; ch++) | ||
1937 | { | ||
1938 | int32_t *d = buf[ch]; | ||
1939 | for (i = 0; i < count; i++) | ||
1940 | { | ||
1941 | if (out_buf_peak[i] > 0) | ||
1942 | { | ||
1943 | gain_peak = (out_buf_peak[i] + 1) / 90; | ||
1944 | gain_rem = (out_buf_peak[i] + 1) % 90; | ||
1945 | gain = gain_steps[gain_peak]; | ||
1946 | if ((gain_peak < 48) && (gain_rem > 0)) | ||
1947 | gain -= gain_rem * ((gain_steps[gain_peak] - | ||
1948 | gain_steps[gain_peak + 1]) / 90); | ||
1949 | d[i] = FRACMUL_SHL(d[i], gain, 3); | ||
1950 | } | ||
1951 | } | ||
1952 | } | ||
1953 | return count; | ||
1954 | } | ||