summaryrefslogtreecommitdiff
path: root/apps/dsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/dsp.c')
-rw-r--r--apps/dsp.c371
1 files changed, 15 insertions, 356 deletions
diff --git a/apps/dsp.c b/apps/dsp.c
index 00de511dd0..4017f6afc0 100644
--- a/apps/dsp.c
+++ b/apps/dsp.c
@@ -24,6 +24,7 @@
24#include "dsp.h" 24#include "dsp.h"
25#include "dsp-util.h" 25#include "dsp-util.h"
26#include "eq.h" 26#include "eq.h"
27#include "compressor.h"
27#include "kernel.h" 28#include "kernel.h"
28#include "settings.h" 29#include "settings.h"
29#include "replaygain.h" 30#include "replaygain.h"
@@ -66,42 +67,6 @@ enum
66 SAMPLE_OUTPUT_DITHERED_STEREO 67 SAMPLE_OUTPUT_DITHERED_STEREO
67}; 68};
68 69
69/****************************************************************************
70 * NOTE: Any assembly routines that use these structures must be updated
71 * if current data members are moved or changed.
72 */
73struct resample_data
74{
75 uint32_t delta; /* 00h */
76 uint32_t phase; /* 04h */
77 int32_t last_sample[2]; /* 08h */
78 /* 10h */
79};
80
81/* This is for passing needed data to assembly dsp routines. If another
82 * dsp parameter needs to be passed, add to the end of the structure
83 * and remove from dsp_config.
84 * If another function type becomes assembly optimized and requires dsp
85 * config info, add a pointer paramter of type "struct dsp_data *".
86 * If removing something from other than the end, reserve the spot or
87 * else update every implementation for every target.
88 * Be sure to add the offset of the new member for easy viewing as well. :)
89 * It is the first member of dsp_config and all members can be accessesed
90 * through the main aggregate but this is intended to make a safe haven
91 * for these items whereas the c part can be rearranged at will. dsp_data
92 * could even moved within dsp_config without disurbing the order.
93 */
94struct dsp_data
95{
96 int output_scale; /* 00h */
97 int num_channels; /* 04h */
98 struct resample_data resample_data; /* 08h */
99 int32_t clip_min; /* 18h */
100 int32_t clip_max; /* 1ch */
101 int32_t gain; /* 20h - Note that this is in S8.23 format. */
102 /* 24h */
103};
104
105/* No asm...yet */ 70/* No asm...yet */
106struct dither_data 71struct dither_data
107{ 72{
@@ -154,7 +119,7 @@ typedef void (*channels_process_dsp_fn_type)(int count, struct dsp_data *data,
154 119
155struct dsp_config 120struct dsp_config
156{ 121{
157 struct dsp_data data; /* Config members for use in asm routines */ 122 struct dsp_data data; /* Config members for use in external routines */
158 long codec_frequency; /* Sample rate of data coming from the codec */ 123 long codec_frequency; /* Sample rate of data coming from the codec */
159 long frequency; /* Effective sample rate after pitch shift (if any) */ 124 long frequency; /* Effective sample rate after pitch shift (if any) */
160 int sample_depth; 125 int sample_depth;
@@ -164,7 +129,6 @@ struct dsp_config
164#ifdef HAVE_PITCHSCREEN 129#ifdef HAVE_PITCHSCREEN
165 bool tdspeed_active; /* Timestretch is in use */ 130 bool tdspeed_active; /* Timestretch is in use */
166#endif 131#endif
167 int frac_bits;
168#ifdef HAVE_SW_TONE_CONTROLS 132#ifdef HAVE_SW_TONE_CONTROLS
169 /* Filter struct for software bass/treble controls */ 133 /* Filter struct for software bass/treble controls */
170 struct eqfilter tone_filter; 134 struct eqfilter tone_filter;
@@ -180,7 +144,7 @@ struct dsp_config
180 channels_process_fn_type apply_crossfeed; 144 channels_process_fn_type apply_crossfeed;
181 channels_process_fn_type eq_process; 145 channels_process_fn_type eq_process;
182 channels_process_fn_type channels_process; 146 channels_process_fn_type channels_process;
183 channels_process_fn_type compressor_process; 147 channels_process_dsp_fn_type compressor_process;
184}; 148};
185 149
186/* General DSP config */ 150/* General DSP config */
@@ -249,15 +213,6 @@ static int32_t *sample_buf[2] = { small_sample_buf[0], small_sample_buf[1] };
249static int resample_buf_count = SMALL_RESAMPLE_BUF_COUNT; 213static int resample_buf_count = SMALL_RESAMPLE_BUF_COUNT;
250static int32_t *resample_buf[2] = { small_resample_buf[0], small_resample_buf[1] }; 214static int32_t *resample_buf[2] = { small_resample_buf[0], small_resample_buf[1] };
251 215
252/* compressor */
253static int32_t comp_rel_slope IBSS_ATTR; /* S7.24 format */
254static int32_t comp_makeup_gain IBSS_ATTR; /* S7.24 format */
255static int32_t comp_curve[66] IBSS_ATTR; /* S7.24 format */
256static int32_t release_gain IBSS_ATTR; /* S7.24 format */
257#define UNITY (1L << 24) /* unity gain in S7.24 format */
258static void compressor_process(int count, int32_t *buf[]);
259
260
261#ifdef HAVE_PITCHSCREEN 216#ifdef HAVE_PITCHSCREEN
262int32_t sound_get_pitch(void) 217int32_t sound_get_pitch(void)
263{ 218{
@@ -813,8 +768,8 @@ static inline int resample(struct dsp_config *dsp, int count, int32_t *src[])
813static void dither_init(struct dsp_config *dsp) 768static void dither_init(struct dsp_config *dsp)
814{ 769{
815 memset(dither_data, 0, sizeof (dither_data)); 770 memset(dither_data, 0, sizeof (dither_data));
816 dither_bias = (1L << (dsp->frac_bits - NATIVE_DEPTH)); 771 dither_bias = (1L << (dsp->data.frac_bits - NATIVE_DEPTH));
817 dither_mask = (1L << (dsp->frac_bits + 1 - NATIVE_DEPTH)) - 1; 772 dither_mask = (1L << (dsp->data.frac_bits + 1 - NATIVE_DEPTH)) - 1;
818} 773}
819 774
820void dsp_dither_enable(bool enable) 775void dsp_dither_enable(bool enable)
@@ -1319,7 +1274,7 @@ int dsp_process(struct dsp_config *dsp, char *dst, const char *src[], int count)
1319 dsp->channels_process(chunk, t2); 1274 dsp->channels_process(chunk, t2);
1320 1275
1321 if (dsp->compressor_process) 1276 if (dsp->compressor_process)
1322 dsp->compressor_process(chunk, t2); 1277 dsp->compressor_process(chunk, &dsp->data, t2);
1323 1278
1324 dsp->output_samples(chunk, &dsp->data, (const int32_t **)t2, (int16_t *)dst); 1279 dsp->output_samples(chunk, &dsp->data, (const int32_t **)t2, (int16_t *)dst);
1325 1280
@@ -1453,20 +1408,20 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value)
1453 1408
1454 if (dsp->sample_depth <= NATIVE_DEPTH) 1409 if (dsp->sample_depth <= NATIVE_DEPTH)
1455 { 1410 {
1456 dsp->frac_bits = WORD_FRACBITS; 1411 dsp->data.frac_bits = WORD_FRACBITS;
1457 dsp->sample_bytes = sizeof (int16_t); /* samples are 16 bits */ 1412 dsp->sample_bytes = sizeof (int16_t); /* samples are 16 bits */
1458 dsp->data.clip_max = ((1 << WORD_FRACBITS) - 1); 1413 dsp->data.clip_max = ((1 << WORD_FRACBITS) - 1);
1459 dsp->data.clip_min = -((1 << WORD_FRACBITS)); 1414 dsp->data.clip_min = -((1 << WORD_FRACBITS));
1460 } 1415 }
1461 else 1416 else
1462 { 1417 {
1463 dsp->frac_bits = value; 1418 dsp->data.frac_bits = value;
1464 dsp->sample_bytes = sizeof (int32_t); /* samples are 32 bits */ 1419 dsp->sample_bytes = sizeof (int32_t); /* samples are 32 bits */
1465 dsp->data.clip_max = (1 << value) - 1; 1420 dsp->data.clip_max = (1 << value) - 1;
1466 dsp->data.clip_min = -(1 << value); 1421 dsp->data.clip_min = -(1 << value);
1467 } 1422 }
1468 1423
1469 dsp->data.output_scale = dsp->frac_bits + 1 - NATIVE_DEPTH; 1424 dsp->data.output_scale = dsp->data.frac_bits + 1 - NATIVE_DEPTH;
1470 sample_input_new_format(dsp); 1425 sample_input_new_format(dsp);
1471 dither_init(dsp); 1426 dither_init(dsp);
1472 break; 1427 break;
@@ -1484,9 +1439,9 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value)
1484 dsp->stereo_mode = STEREO_NONINTERLEAVED; 1439 dsp->stereo_mode = STEREO_NONINTERLEAVED;
1485 dsp->data.num_channels = 2; 1440 dsp->data.num_channels = 2;
1486 dsp->sample_depth = NATIVE_DEPTH; 1441 dsp->sample_depth = NATIVE_DEPTH;
1487 dsp->frac_bits = WORD_FRACBITS; 1442 dsp->data.frac_bits = WORD_FRACBITS;
1488 dsp->sample_bytes = sizeof (int16_t); 1443 dsp->sample_bytes = sizeof (int16_t);
1489 dsp->data.output_scale = dsp->frac_bits + 1 - NATIVE_DEPTH; 1444 dsp->data.output_scale = dsp->data.frac_bits + 1 - NATIVE_DEPTH;
1490 dsp->data.clip_max = ((1 << WORD_FRACBITS) - 1); 1445 dsp->data.clip_max = ((1 << WORD_FRACBITS) - 1);
1491 dsp->data.clip_min = -((1 << WORD_FRACBITS)); 1446 dsp->data.clip_min = -((1 << WORD_FRACBITS));
1492 dsp->codec_frequency = dsp->frequency = NATIVE_FREQUENCY; 1447 dsp->codec_frequency = dsp->frequency = NATIVE_FREQUENCY;
@@ -1506,7 +1461,7 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value)
1506 tdspeed_setup(dsp); 1461 tdspeed_setup(dsp);
1507#endif 1462#endif
1508 if (dsp == &AUDIO_DSP) 1463 if (dsp == &AUDIO_DSP)
1509 release_gain = UNITY; 1464 compressor_reset();
1510 break; 1465 break;
1511 1466
1512 case DSP_FLUSH: 1467 case DSP_FLUSH:
@@ -1518,7 +1473,7 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value)
1518 tdspeed_setup(dsp); 1473 tdspeed_setup(dsp);
1519#endif 1474#endif
1520 if (dsp == &AUDIO_DSP) 1475 if (dsp == &AUDIO_DSP)
1521 release_gain = UNITY; 1476 compressor_reset();
1522 break; 1477 break;
1523 1478
1524 case DSP_SET_TRACK_GAIN: 1479 case DSP_SET_TRACK_GAIN:
@@ -1616,303 +1571,7 @@ void dsp_set_replaygain(void)
1616 * Called by the menu system to configure the compressor process */ 1571 * Called by the menu system to configure the compressor process */
1617void dsp_set_compressor(void) 1572void dsp_set_compressor(void)
1618{ 1573{
1619 static int curr_set[5];
1620 int new_set[5] = {
1621 global_settings.compressor_threshold,
1622 global_settings.compressor_makeup_gain,
1623 global_settings.compressor_ratio,
1624 global_settings.compressor_knee,
1625 global_settings.compressor_release_time};
1626
1627 /* make menu values useful */
1628 int threshold = new_set[0];
1629 bool auto_gain = (new_set[1] == 1);
1630 const int comp_ratios[] = {2, 4, 6, 10, 0};
1631 int ratio = comp_ratios[new_set[2]];
1632 bool soft_knee = (new_set[3] == 1);
1633 int release = new_set[4] * NATIVE_FREQUENCY / 1000;
1634
1635 bool changed = false;
1636 bool active = (threshold < 0);
1637
1638 for (int i = 0; i < 5; i++)
1639 {
1640 if (curr_set[i] != new_set[i])
1641 {
1642 changed = true;
1643 curr_set[i] = new_set[i];
1644
1645#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
1646 switch (i)
1647 {
1648 case 0:
1649 logf(" Compressor Threshold: %d dB\tEnabled: %s",
1650 threshold, active ? "Yes" : "No");
1651 break;
1652 case 1:
1653 logf(" Compressor Makeup Gain: %s",
1654 auto_gain ? "Auto" : "Off");
1655 break;
1656 case 2:
1657 if (ratio)
1658 { logf(" Compressor Ratio: %d:1", ratio); }
1659 else
1660 { logf(" Compressor Ratio: Limit"); }
1661 break;
1662 case 3:
1663 logf(" Compressor Knee: %s", soft_knee?"Soft":"Hard");
1664 break;
1665 case 4:
1666 logf(" Compressor Release: %d", release);
1667 break;
1668 }
1669#endif
1670 }
1671 }
1672
1673 if (changed && active)
1674 {
1675 /* configure variables for compressor operation */
1676 const int32_t db[] ={0x000000, /* positive db equivalents in S15.16 format */
1677 0x241FA4, 0x1E1A5E, 0x1A94C8, 0x181518, 0x1624EA, 0x148F82, 0x1338BD, 0x120FD2,
1678 0x1109EB, 0x101FA4, 0x0F4BB6, 0x0E8A3C, 0x0DD840, 0x0D3377, 0x0C9A0E, 0x0C0A8C,
1679 0x0B83BE, 0x0B04A5, 0x0A8C6C, 0x0A1A5E, 0x09ADE1, 0x094670, 0x08E398, 0x0884F6,
1680 0x082A30, 0x07D2FA, 0x077F0F, 0x072E31, 0x06E02A, 0x0694C8, 0x064BDF, 0x060546,
1681 0x05C0DA, 0x057E78, 0x053E03, 0x04FF5F, 0x04C273, 0x048726, 0x044D64, 0x041518,
1682 0x03DE30, 0x03A89B, 0x037448, 0x03412A, 0x030F32, 0x02DE52, 0x02AE80, 0x027FB0,
1683 0x0251D6, 0x0224EA, 0x01F8E2, 0x01CDB4, 0x01A359, 0x0179C9, 0x0150FC, 0x0128EB,
1684 0x010190, 0x00DAE4, 0x00B4E1, 0x008F82, 0x006AC1, 0x004699, 0x002305};
1685
1686 struct curve_point
1687 {
1688 int32_t db; /* S15.16 format */
1689 int32_t offset; /* S15.16 format */
1690 } db_curve[5];
1691
1692 /** Set up the shape of the compression curve first as decibel values*/
1693 /* db_curve[0] = bottom of knee
1694 [1] = threshold
1695 [2] = top of knee
1696 [3] = 0 db input
1697 [4] = ~+12db input (2 bits clipping overhead) */
1698
1699 db_curve[1].db = threshold << 16;
1700 if (soft_knee)
1701 {
1702 /* bottom of knee is 3dB below the threshold for soft knee*/
1703 db_curve[0].db = db_curve[1].db - (3 << 16);
1704 /* top of knee is 3dB above the threshold for soft knee */
1705 db_curve[2].db = db_curve[1].db + (3 << 16);
1706 if (ratio)
1707 /* offset = -3db * (ratio - 1) / ratio */
1708 db_curve[2].offset = (int32_t)((long long)(-3 << 16)
1709 * (ratio - 1) / ratio);
1710 else
1711 /* offset = -3db for hard limit */
1712 db_curve[2].offset = (-3 << 16);
1713 }
1714 else
1715 {
1716 /* bottom of knee is at the threshold for hard knee */
1717 db_curve[0].db = threshold << 16;
1718 /* top of knee is at the threshold for hard knee */
1719 db_curve[2].db = threshold << 16;
1720 db_curve[2].offset = 0;
1721 }
1722
1723 /* Calculate 0db and ~+12db offsets */
1724 db_curve[4].db = 0xC0A8C; /* db of 2 bits clipping */
1725 if (ratio)
1726 {
1727 /* offset = threshold * (ratio - 1) / ratio */
1728 db_curve[3].offset = (int32_t)((long long)(threshold << 16)
1729 * (ratio - 1) / ratio);
1730 db_curve[4].offset = (int32_t)((long long)-db_curve[4].db
1731 * (ratio - 1) / ratio) + db_curve[3].offset;
1732 }
1733 else
1734 {
1735 /* offset = threshold for hard limit */
1736 db_curve[3].offset = (threshold << 16);
1737 db_curve[4].offset = -db_curve[4].db + db_curve[3].offset;
1738 }
1739
1740 /** Now set up the comp_curve table with compression offsets in the form
1741 of gain factors in S7.24 format */
1742 /* comp_curve[0] is 0 (-infinity db) input */
1743 comp_curve[0] = UNITY;
1744 /* comp_curve[1 to 63] are intermediate compression values corresponding
1745 to the 6 MSB of the input values of a non-clipped signal */
1746 for (int i = 1; i < 64; i++)
1747 {
1748 /* db constants are stored as positive numbers;
1749 make them negative here */
1750 int32_t this_db = -db[i];
1751
1752 /* no compression below the knee */
1753 if (this_db <= db_curve[0].db)
1754 comp_curve[i] = UNITY;
1755
1756 /* if soft knee and below top of knee,
1757 interpolate along soft knee slope */
1758 else if (soft_knee && (this_db <= db_curve[2].db))
1759 comp_curve[i] = fp_factor(fp_mul(
1760 ((this_db - db_curve[0].db) / 6),
1761 db_curve[2].offset, 16), 16) << 8;
1762
1763 /* interpolate along ratio slope above the knee */
1764 else
1765 comp_curve[i] = fp_factor(fp_mul(
1766 fp_div((db_curve[1].db - this_db), db_curve[1].db, 16),
1767 db_curve[3].offset, 16), 16) << 8;
1768 }
1769 /* comp_curve[64] is the compression level of a maximum level,
1770 non-clipped signal */
1771 comp_curve[64] = fp_factor(db_curve[3].offset, 16) << 8;
1772
1773 /* comp_curve[65] is the compression level of a maximum level,
1774 clipped signal */
1775 comp_curve[65] = fp_factor(db_curve[4].offset, 16) << 8;
1776
1777#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
1778 logf("\n *** Compression Offsets ***");
1779 /* some settings for display only, not used in calculations */
1780 db_curve[0].offset = 0;
1781 db_curve[1].offset = 0;
1782 db_curve[3].db = 0;
1783
1784 for (int i = 0; i <= 4; i++)
1785 {
1786 logf("Curve[%d]: db: % 6.2f\toffset: % 6.2f", i,
1787 (float)db_curve[i].db / (1 << 16),
1788 (float)db_curve[i].offset / (1 << 16));
1789 }
1790
1791 logf("\nGain factors:");
1792 for (int i = 1; i <= 65; i++)
1793 {
1794 debugf("%02d: %.6f ", i, (float)comp_curve[i] / UNITY);
1795 if (i % 4 == 0) debugf("\n");
1796 }
1797 debugf("\n");
1798#endif
1799
1800 /* if using auto peak, then makeup gain is max offset - .1dB headroom */
1801 comp_makeup_gain = auto_gain ?
1802 fp_factor(-(db_curve[3].offset) - 0x199A, 16) << 8 : UNITY;
1803 logf("Makeup gain:\t%.6f", (float)comp_makeup_gain / UNITY);
1804
1805 /* calculate per-sample gain change a rate of 10db over release time */
1806 comp_rel_slope = 0xAF0BB2 / release;
1807 logf("Release slope:\t%.6f", (float)comp_rel_slope / UNITY);
1808
1809 release_gain = UNITY;
1810 }
1811
1812 /* enable/disable the compressor */ 1574 /* enable/disable the compressor */
1813 AUDIO_DSP.compressor_process = active ? compressor_process : NULL; 1575 AUDIO_DSP.compressor_process = compressor_update() ?
1814} 1576 compressor_process : NULL;
1815
1816/** GET COMPRESSION GAIN
1817 * Returns the required gain factor in S7.24 format in order to compress the
1818 * sample in accordance with the compression curve. Always 1 or less.
1819 */
1820static inline int32_t get_compression_gain(int32_t sample)
1821{
1822 const int frac_bits_offset = AUDIO_DSP.frac_bits - 15;
1823
1824 /* sample must be positive */
1825 if (sample < 0)
1826 sample = -(sample + 1);
1827
1828 /* shift sample into 15 frac bit range */
1829 if (frac_bits_offset > 0)
1830 sample >>= frac_bits_offset;
1831 if (frac_bits_offset < 0)
1832 sample <<= -frac_bits_offset;
1833
1834 /* normal case: sample isn't clipped */
1835 if (sample < (1 << 15))
1836 {
1837 /* index is 6 MSB, rem is 9 LSB */
1838 int index = sample >> 9;
1839 int32_t rem = (sample & 0x1FF) << 22;
1840
1841 /* interpolate from the compression curve:
1842 higher gain - ((rem / (1 << 31)) * (higher gain - lower gain)) */
1843 return comp_curve[index] - (FRACMUL(rem,
1844 (comp_curve[index] - comp_curve[index + 1])));
1845 }
1846 /* sample is somewhat clipped, up to 2 bits of overhead */
1847 if (sample < (1 << 17))
1848 {
1849 /* straight interpolation:
1850 higher gain - ((clipped portion of sample * 4/3
1851 / (1 << 31)) * (higher gain - lower gain)) */
1852 return comp_curve[64] - (FRACMUL(((sample - (1 << 15)) / 3) << 16,
1853 (comp_curve[64] - comp_curve[65])));
1854 }
1855
1856 /* sample is too clipped, return invalid value */
1857 return -1;
1858}
1859
1860/** COMPRESSOR PROCESS
1861 * Changes the gain of the samples according to the compressor curve
1862 */
1863static void compressor_process(int count, int32_t *buf[])
1864{
1865 const int num_chan = AUDIO_DSP.data.num_channels;
1866 int32_t *in_buf[2] = {buf[0], buf[1]};
1867
1868 while (count-- > 0)
1869 {
1870 int ch;
1871 /* use lowest (most compressed) gain factor of the output buffer
1872 sample pair for both samples (mono is also handled correctly here) */
1873 int32_t sample_gain = UNITY;
1874 for (ch = 0; ch < num_chan; ch++)
1875 {
1876 int32_t this_gain = get_compression_gain(*in_buf[ch]);
1877 if (this_gain < sample_gain)
1878 sample_gain = this_gain;
1879 }
1880
1881 /* perform release slope; skip if no compression and no release slope */
1882 if ((sample_gain != UNITY) || (release_gain != UNITY))
1883 {
1884 /* if larger offset than previous slope, start new release slope */
1885 if ((sample_gain <= release_gain) && (sample_gain > 0))
1886 {
1887 release_gain = sample_gain;
1888 }
1889 else
1890 /* keep sloping towards unity gain (and ignore invalid value) */
1891 {
1892 release_gain += comp_rel_slope;
1893 if (release_gain > UNITY)
1894 {
1895 release_gain = UNITY;
1896 }
1897 }
1898 }
1899
1900 /* total gain factor is the product of release gain and makeup gain,
1901 but avoid computation if possible */
1902 int32_t total_gain = ((release_gain == UNITY) ? comp_makeup_gain :
1903 (comp_makeup_gain == UNITY) ? release_gain :
1904 FRACMUL_SHL(release_gain, comp_makeup_gain, 7));
1905
1906 /* Implement the compressor: apply total gain factor (if any) to the
1907 output buffer sample pair/mono sample */
1908 if (total_gain != UNITY)
1909 {
1910 for (ch = 0; ch < num_chan; ch++)
1911 {
1912 *in_buf[ch] = FRACMUL_SHL(total_gain, *in_buf[ch], 7);
1913 }
1914 }
1915 in_buf[0]++;
1916 in_buf[1]++;
1917 }
1918} 1577}