| | 1 | /* |
| | 2 | * some code for sample mixing |
| | 3 | * (C) notaz, 2006,2007 |
| | 4 | * (C) irixxxx, 2019,2020 added filtering |
| | 5 | * |
| | 6 | * This work is licensed under the terms of MAME license. |
| | 7 | * See COPYING file in the top-level directory. |
| | 8 | */ |
| | 9 | |
| | 10 | #include <string.h> |
| | 11 | #include "../pico_int.h" |
| | 12 | |
| | 13 | #define MAXOUT (+32767) |
| | 14 | #define MINOUT (-32768) |
| | 15 | |
| | 16 | /* limitter */ |
| | 17 | #define Limit16(val) \ |
| | 18 | val -= val >> 3; /* reduce level to avoid clipping */ \ |
| | 19 | if ((s16)val != val) val = (val < 0 ? MINOUT : MAXOUT) |
| | 20 | |
| | 21 | int mix_32_to_16_level; |
| | 22 | |
| | 23 | static struct iir { |
| | 24 | int alpha; // alpha for EMA low pass |
| | 25 | int y[2]; // filter intermediates |
| | 26 | } lfi2, rfi2; |
| | 27 | |
| | 28 | // NB ">>" rounds to -infinity, "/" to 0. To compensate the effect possibly use |
| | 29 | // "-(-y>>n)" (round to +infinity) instead of "y>>n" in places. |
| | 30 | |
| | 31 | // NB uses fixpoint; samples mustn't have more than (32-QB) bits. Adding the |
| | 32 | // outputs of the sound sources together yields a max. of 18 bits, restricting |
| | 33 | // QB to a maximum of 14. |
| | 34 | #define QB 12 |
| | 35 | // NB alpha for DC filtering shouldn't be smaller than 1/(1<<QB) to avoid loss. |
| | 36 | |
| | 37 | |
| | 38 | // exponential moving average combined DC filter and lowpass filter |
| | 39 | // y0[n] = y0[n-1]+(x[n]-y0[n-1])*alpha, y1[n] = y[n-1]+(y0[n]-y1[n-1])*(1/512) |
| | 40 | static inline int filter_band(struct iir *fi2, int x) |
| | 41 | { |
| | 42 | // low pass. alpha is Q8 to avoid loss by 32 bit overflow. |
| | 43 | // fi2->y[0] += ((x<<(QB-8)) - (fi2->y[0]>>8)) * fi2->alpha; |
| | 44 | fi2->y[0] += (x - (fi2->y[0]>>QB)) * fi2->alpha; |
| | 45 | // DC filter. for alpha=1/8192 cutoff ~1HZ, for 1/512 ~14Hz |
| | 46 | fi2->y[1] += (fi2->y[0] - fi2->y[1]) >> 9; |
| | 47 | return (fi2->y[0] - fi2->y[1]) >> QB; |
| | 48 | } |
| | 49 | |
| | 50 | // exponential moving average filter for DC filtering |
| | 51 | // y[n]= y[n-1] + (x[n]-y[n-1])*(1/512) (corner approx. 14Hz, gain 1) |
| | 52 | static inline int filter_exp(struct iir *fi2, int x) |
| | 53 | { |
| | 54 | fi2->y[1] += ((x << QB) - fi2->y[1]) >> 9; |
| | 55 | return x - (fi2->y[1] >> QB); |
| | 56 | } |
| | 57 | |
| | 58 | // unfiltered (for testing) |
| | 59 | static inline int filter_null(struct iir *fi2, int x) |
| | 60 | { |
| | 61 | return x; |
| | 62 | } |
| | 63 | |
| | 64 | #define filter filter_band |
| | 65 | |
| | 66 | #define mix_32_to_16_stereo_core(dest, src, count, lv, fl) { \ |
| | 67 | int l, r; \ |
| | 68 | struct iir lf = lfi2, rf = rfi2; \ |
| | 69 | \ |
| | 70 | for (; count > 0; count--) \ |
| | 71 | { \ |
| | 72 | l = *dest; \ |
| | 73 | l += *src++ >> lv; \ |
| | 74 | l = fl(&lf, l); \ |
| | 75 | Limit16(l); \ |
| | 76 | *dest++ = l; \ |
| | 77 | r = *dest; \ |
| | 78 | r += *src++ >> lv; \ |
| | 79 | r = fl(&rf, r); \ |
| | 80 | Limit16(r); \ |
| | 81 | *dest++ = r; \ |
| | 82 | } \ |
| | 83 | lfi2 = lf, rfi2 = rf; \ |
| | 84 | } |
| | 85 | |
| | 86 | void mix_32_to_16_stereo_lvl(s16 *dest, s32 *src, int count) |
| | 87 | { |
| | 88 | mix_32_to_16_stereo_core(dest, src, count, mix_32_to_16_level, filter); |
| | 89 | } |
| | 90 | |
| | 91 | void mix_32_to_16_stereo(s16 *dest, s32 *src, int count) |
| | 92 | { |
| | 93 | mix_32_to_16_stereo_core(dest, src, count, 0, filter); |
| | 94 | } |
| | 95 | |
| | 96 | void mix_32_to_16_mono(s16 *dest, s32 *src, int count) |
| | 97 | { |
| | 98 | int l; |
| | 99 | struct iir lf = lfi2; |
| | 100 | |
| | 101 | for (; count > 0; count--) |
| | 102 | { |
| | 103 | l = *dest; |
| | 104 | l += *src++; |
| | 105 | l = filter(&lf, l); |
| | 106 | Limit16(l); |
| | 107 | *dest++ = l; |
| | 108 | } |
| | 109 | lfi2 = lf; |
| | 110 | } |
| | 111 | |
| | 112 | |
| | 113 | void mix_16h_to_32(s32 *dest_buf, s16 *mp3_buf, int count) |
| | 114 | { |
| | 115 | while (count--) |
| | 116 | { |
| | 117 | *dest_buf++ += (*mp3_buf++ * 5) >> 3; |
| | 118 | } |
| | 119 | } |
| | 120 | |
| | 121 | void mix_16h_to_32_s1(s32 *dest_buf, s16 *mp3_buf, int count) |
| | 122 | { |
| | 123 | count >>= 1; |
| | 124 | while (count--) |
| | 125 | { |
| | 126 | *dest_buf++ += (*mp3_buf++ * 5) >> 3; |
| | 127 | *dest_buf++ += (*mp3_buf++ * 5) >> 3; |
| | 128 | mp3_buf += 1*2; |
| | 129 | } |
| | 130 | } |
| | 131 | |
| | 132 | void mix_16h_to_32_s2(s32 *dest_buf, s16 *mp3_buf, int count) |
| | 133 | { |
| | 134 | count >>= 1; |
| | 135 | while (count--) |
| | 136 | { |
| | 137 | *dest_buf++ += (*mp3_buf++ * 5) >> 3; |
| | 138 | *dest_buf++ += (*mp3_buf++ * 5) >> 3; |
| | 139 | mp3_buf += 3*2; |
| | 140 | } |
| | 141 | } |
| | 142 | |
| | 143 | // mixes cdda audio @44.1 KHz into dest_buf, resampling with nearest neighbour |
| | 144 | void mix_16h_to_32_resample_stereo(s32 *dest_buf, s16 *cdda_buf, int count, int fac16) |
| | 145 | { |
| | 146 | int pos16 = 0; |
| | 147 | while (count--) { |
| | 148 | int pos = 2 * (pos16>>16); |
| | 149 | *dest_buf++ += (cdda_buf[pos ] * 5) >> 3; |
| | 150 | *dest_buf++ += (cdda_buf[pos+1] * 5) >> 3; |
| | 151 | pos16 += fac16; |
| | 152 | } |
| | 153 | } |
| | 154 | |
| | 155 | // mixes cdda audio @44.1 KHz into dest_buf, resampling with nearest neighbour |
| | 156 | void mix_16h_to_32_resample_mono(s32 *dest_buf, s16 *cdda_buf, int count, int fac16) |
| | 157 | { |
| | 158 | int pos16 = 0; |
| | 159 | while (count--) { |
| | 160 | int pos = 2 * (pos16>>16); |
| | 161 | *dest_buf += (cdda_buf[pos ] * 5) >> 4; |
| | 162 | *dest_buf++ += (cdda_buf[pos+1] * 5) >> 4; |
| | 163 | pos16 += fac16; |
| | 164 | } |
| | 165 | } |
| | 166 | |
| | 167 | void mix_reset(int alpha_q16) |
| | 168 | { |
| | 169 | memset(&lfi2, 0, sizeof(lfi2)); |
| | 170 | memset(&rfi2, 0, sizeof(rfi2)); |
| | 171 | lfi2.alpha = rfi2.alpha = (0x10000-alpha_q16) >> 4; // filter alpha, Q12 |
| | 172 | } |