summaryrefslogtreecommitdiff
path: root/apps/dsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/dsp.c')
-rw-r--r--apps/dsp.c638
1 files changed, 236 insertions, 402 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
140struct 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. */ 267static struct compressor_menu c_menu;
260#define MAX_COUNT MAX(SMALL_SAMPLE_BUF_COUNT * RESAMPLE_RATIO / 2, LIMITER_BUFFER_SIZE) 268static int32_t comp_rel_slope IBSS_ATTR; /* S7.24 format */
261static int count_adjust; 269static int32_t comp_makeup_gain IBSS_ATTR; /* S7.24 format */
262static bool limiter_buffer_active; 270static int32_t comp_curve[65] IBSS_ATTR; /* S7.24 format */
263static bool limiter_buffer_full; 271static int32_t gain_buffer[MAX_COUNT] IBSS_ATTR;
264static bool limiter_buffer_emptying; 272static int32_t release_gain IBSS_ATTR;
265static int32_t limiter_buffer[2][LIMITER_BUFFER_SIZE] IBSS_ATTR; 273
266static int32_t *start_lim_buf[2] IBSS_ATTR, 274static int compressor_process(int count, int32_t *buf[]);
267 *end_lim_buf[2] IBSS_ATTR;
268static uint16_t lim_buf_peak[LIMITER_BUFFER_SIZE] IBSS_ATTR;
269static uint16_t *start_peak IBSS_ATTR,
270 *end_peak IBSS_ATTR;
271static uint16_t out_buf_peak[MAX_COUNT];
272static uint16_t *out_buf_peak_index IBSS_ATTR;
273static uint16_t release_peak IBSS_ATTR;
274static int32_t in_samp IBSS_ATTR,
275 samp0 IBSS_ATTR;
276
277static void reset_limiter_buffer(struct dsp_config *dsp);
278static int limiter_buffer_count(bool buf_count);
279static int limiter_process(int count, int32_t *buf[]);
280static 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. */
284const 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. */
297const 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 */
1376int dsp_input_count(struct dsp_config *dsp, int count) 1327int 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. */ 1539void dsp_set_compressor(int c_threshold, int c_ratio, int c_gain,
1594static 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. */
1611static 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 */
1742static 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 */
1757int 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 */
1778static 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 */
1815void 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 */
1857static int limiter_process(int count, int32_t *buf[]) 1709static 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 */
1735static 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}