platform ps2, handle audio similar to psp
[picodrive.git] / pico / sound / mix.c
CommitLineData
cff531af 1/*
2 * some code for sample mixing
3 * (C) notaz, 2006,2007
7bf552b5 4 * (C) irixxxx, 2019,2020 added filtering
cff531af 5 *
6 * This work is licensed under the terms of MAME license.
7 * See COPYING file in the top-level directory.
8 */
8b99ab90 9
f821bb70 10#include <string.h>
f7741cac 11#include "../pico_int.h"
2a942f0d 12
4f265db7 13#define MAXOUT (+32767)
14#define MINOUT (-32768)
15
16/* limitter */
8ac9ab7f 17#define Limit16(val) \
a5a230e0 18 val -= val >> 3; /* reduce level to avoid clipping */ \
f7741cac 19 if ((s16)val != val) val = (val < 0 ? MINOUT : MAXOUT)
4f265db7 20
70efc52d 21int mix_32_to_16_level;
4f265db7 22
30969671 23static struct iir {
24 int alpha; // alpha for EMA low pass
2a942f0d 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
30969671 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.
2a942f0d 34#define QB 12
30969671 35// NB alpha for DC filtering shouldn't be smaller than 1/(1<<QB) to avoid loss.
2a942f0d 36
37
30969671 38// exponential moving average combined DC filter and lowpass filter
39// y0[n] = (x[n]-y0[n-1])*alpha+y0[n-1], y1[n] = (y0[n] - y1[n-1])*(1-1/8192)
40static 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-1/8192 cutoff ~1HZ, for 1-1/1024 ~7Hz
46 fi2->y[1] += (fi2->y[0] - fi2->y[1]) >> QB;
47 return (fi2->y[0] - fi2->y[1]) >> QB;
48}
49
2a942f0d 50// exponential moving average filter for DC filtering
30969671 51// y[n] = (x[n]-y[n-1])*(1-1/8192) (corner approx. 1Hz, gain 1)
52static inline int filter_exp(struct iir *fi2, int x)
4f265db7 53{
30969671 54 fi2->y[1] += ((x << QB) - fi2->y[1]) >> QB;
55 return x - (fi2->y[1] >> QB);
2a942f0d 56}
4f265db7 57
2a942f0d 58// unfiltered (for testing)
30969671 59static inline int filter_null(struct iir *fi2, int x)
2a942f0d 60{
61 return x;
62}
63
30969671 64#define filter filter_band
65
70efc52d 66#define mix_32_to_16_stereo_core(dest, src, count, lv, fl) { \
2a942f0d 67 int l, r; \
30969671 68 struct iir lf = lfi2, rf = rfi2; \
2a942f0d 69 \
70 for (; count > 0; count--) \
71 { \
70efc52d 72 l = *dest; \
2a942f0d 73 l += *src++ >> lv; \
30969671 74 l = fl(&lf, l); \
2a942f0d 75 Limit16(l); \
2a942f0d 76 *dest++ = l; \
70efc52d 77 r = *dest; \
78 r += *src++ >> lv; \
79 r = fl(&rf, r); \
80 Limit16(r); \
2a942f0d 81 *dest++ = r; \
82 } \
30969671 83 lfi2 = lf, rfi2 = rf; \
4f265db7 84}
85
70efc52d 86void mix_32_to_16_stereo_lvl(s16 *dest, s32 *src, int count)
f5939109 87{
70efc52d 88 mix_32_to_16_stereo_core(dest, src, count, mix_32_to_16_level, filter);
f5939109 89}
90
70efc52d 91void mix_32_to_16_stereo(s16 *dest, s32 *src, int count)
f5939109 92{
70efc52d 93 mix_32_to_16_stereo_core(dest, src, count, 0, filter);
f5939109 94}
4f265db7 95
f7741cac 96void mix_32_to_16_mono(s16 *dest, s32 *src, int count)
4f265db7 97{
98 int l;
30969671 99 struct iir lf = lfi2;
4f265db7 100
101 for (; count > 0; count--)
102 {
103 l = *dest;
104 l += *src++;
30969671 105 l = filter(&lf, l);
2a942f0d 106 Limit16(l);
4f265db7 107 *dest++ = l;
108 }
30969671 109 lfi2 = lf;
4f265db7 110}
111
112
f7741cac 113void mix_16h_to_32(s32 *dest_buf, s16 *mp3_buf, int count)
cea65903 114{
4b167c12 115 while (count--)
116 {
2eeee072 117 *dest_buf++ += (*mp3_buf++ * 5) >> 3;
4b167c12 118 }
cea65903 119}
120
f7741cac 121void mix_16h_to_32_s1(s32 *dest_buf, s16 *mp3_buf, int count)
cea65903 122{
4b167c12 123 count >>= 1;
124 while (count--)
125 {
2eeee072 126 *dest_buf++ += (*mp3_buf++ * 5) >> 3;
127 *dest_buf++ += (*mp3_buf++ * 5) >> 3;
4b167c12 128 mp3_buf += 1*2;
129 }
cea65903 130}
131
f7741cac 132void mix_16h_to_32_s2(s32 *dest_buf, s16 *mp3_buf, int count)
cea65903 133{
4b167c12 134 count >>= 1;
135 while (count--)
136 {
2eeee072 137 *dest_buf++ += (*mp3_buf++ * 5) >> 3;
138 *dest_buf++ += (*mp3_buf++ * 5) >> 3;
4b167c12 139 mp3_buf += 3*2;
140 }
cea65903 141}
142
f7741cac 143// mixes cdda audio @44.1 KHz into dest_buf, resampling with nearest neighbour
144void 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);
2eeee072 149 *dest_buf++ += (cdda_buf[pos ] * 5) >> 3;
150 *dest_buf++ += (cdda_buf[pos+1] * 5) >> 3;
f7741cac 151 pos16 += fac16;
152 }
153}
154
155// mixes cdda audio @44.1 KHz into dest_buf, resampling with nearest neighbour
156void 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);
2eeee072 161 *dest_buf += (cdda_buf[pos ] * 5) >> 4;
162 *dest_buf++ += (cdda_buf[pos+1] * 5) >> 4;
f7741cac 163 pos16 += fac16;
164 }
165}
166
30969671 167void mix_reset(int alpha_q16)
2a942f0d 168{
169 memset(&lfi2, 0, sizeof(lfi2));
170 memset(&rfi2, 0, sizeof(rfi2));
30969671 171 lfi2.alpha = rfi2.alpha = (0x10000-alpha_q16) >> 4; // filter alpha, Q12
2a942f0d 172}