1 static int16_t (*myvoltab)[2][256];
2 static int16_t (*myinterpoltabq)[32][256][2];
3 static int16_t (*myinterpoltabq2)[16][256][4];
4
mixqSetupAddresses(int16_t (* voltab)[2][256],int16_t (* interpoltabq)[32][256][2],int16_t (* interpoltabq2)[16][256][4])5 void mixqSetupAddresses(int16_t (*voltab)[2][256], int16_t (*interpoltabq)[32][256][2], int16_t (*interpoltabq2)[16][256][4])
6 {
7 myvoltab=voltab;
8 myinterpoltabq=interpoltabq;
9 myinterpoltabq2=interpoltabq2;
10 }
11
playquiet(int16_t * buf,uint32_t len,struct channel * chan)12 static void playquiet(int16_t *buf, uint32_t len, struct channel *chan)
13 {
14 }
15
interp_none8(const struct channel * chan,const uint32_t pos,uint32_t fpos)16 static inline int32_t interp_none8(const struct channel *chan, const uint32_t pos, uint32_t fpos)
17 {
18 return chan->realsamp.bit8[pos]<<8;
19 }
20
interp_none16(const struct channel * chan,const uint32_t pos,uint32_t fpos)21 static inline int32_t interp_none16(const struct channel *chan, const uint32_t pos, uint32_t fpos)
22 {
23 return chan->realsamp.bit16[pos];
24 }
25
interp_i8(const struct channel * chan,const uint32_t pos,uint32_t fpos)26 static inline int32_t interp_i8(const struct channel *chan, const uint32_t pos, uint32_t fpos)
27 {
28 uint8_t cache = fpos>>11;
29 return myinterpoltabq[0][cache][(uint8_t)chan->realsamp.bit8[pos]][0]
30 +
31 myinterpoltabq[0][cache][(uint8_t)chan->realsamp.bit8[pos+1]][1];
32 }
33
interp_i16(const struct channel * chan,const uint32_t pos,uint32_t fpos)34 static inline int32_t interp_i16(const struct channel *chan, const uint32_t pos, uint32_t fpos)
35 {
36 uint8_t cache = fpos>>11;
37
38 return myinterpoltabq[0][cache][(uint8_t)(chan->realsamp.bit16[pos]>>8)][0]
39 +
40 myinterpoltabq[0][cache][(uint8_t)(chan->realsamp.bit16[pos+1]>>8)][1]
41 +
42 myinterpoltabq[1][cache][(uint8_t)(chan->realsamp.bit16[pos]&0xff)][0]
43 +
44 myinterpoltabq[1][cache][(uint8_t)(chan->realsamp.bit16[pos+1]&0xff)][1];
45 }
46
interp_i28(const struct channel * chan,const uint32_t pos,uint32_t fpos)47 static inline int32_t interp_i28(const struct channel *chan, const uint32_t pos, uint32_t fpos)
48 {
49 uint8_t cache = fpos>>12;
50
51 return myinterpoltabq2[0][cache][(uint8_t)(chan->realsamp.bit8[pos])][0]
52 +
53 myinterpoltabq2[0][cache][(uint8_t)(chan->realsamp.bit8[pos+1])][1]
54 +
55 myinterpoltabq2[0][cache][(uint8_t)(chan->realsamp.bit8[pos+2])][2];
56 }
57
interp_i216(const struct channel * chan,const uint32_t pos,uint32_t fpos)58 static inline int32_t interp_i216(const struct channel *chan, const uint32_t pos, uint32_t fpos)
59 {
60 uint8_t cache = fpos>>12;
61
62 return myinterpoltabq2[0][cache][(uint8_t)(chan->realsamp.bit16[pos]>>8)][0]
63 +
64 myinterpoltabq2[0][cache][(uint8_t)(chan->realsamp.bit16[pos+1]>>8)][1]
65 +
66 myinterpoltabq2[0][cache][(uint8_t)(chan->realsamp.bit16[pos+2]>>8)][2]
67 +
68 myinterpoltabq2[1][cache][(uint8_t)(chan->realsamp.bit16[pos]&0xff)][0]
69 +
70 myinterpoltabq2[1][cache][(uint8_t)(chan->realsamp.bit16[pos+1]&0xff)][1]
71 +
72 myinterpoltabq2[1][cache][(uint8_t)(chan->realsamp.bit16[pos+2]&0xff)][2];
73 }
74
75 #define MIX_TEMPLATE(NAME, INTERP) \
76 static void \
77 NAME(int16_t *buf, \
78 uint32_t len, \
79 struct channel *chan) \
80 { \
81 uint32_t pos=chan->pos; \
82 uint32_t fpos=chan->fpos; \
83 uint32_t fadd=chan->step&0xffff; \
84 uint32_t posadd=(int16_t)(chan->step>>16); \
85 \
86 while (len) \
87 { \
88 *(buf++) = interp_##INTERP(chan, pos, fpos); \
89 fpos+=fadd; \
90 if (fpos&0xffff0000) \
91 { \
92 pos++; \
93 fpos&=0xffff; \
94 } \
95 pos+=posadd; \
96 len--; \
97 } \
98 }
99
100 //#pragma GCC diagnostic push
101 #pragma GCC diagnostic ignored "-Wunused"
MIX_TEMPLATE(playmono,none8)102 MIX_TEMPLATE(playmono, none8)
103 MIX_TEMPLATE(playmono16, none16)
104 MIX_TEMPLATE(playmonoi, i8)
105 MIX_TEMPLATE(playmonoi16, i16)
106 MIX_TEMPLATE(playmonoi2, i28)
107 MIX_TEMPLATE(playmonoi216, i216)
108 //#pragma GCC diagnostic pop
109
110 void mixqPlayChannel(int16_t *buf, uint32_t len, struct channel *chan, int quiet)
111 {
112 uint32_t fillen=0;
113 uint32_t mixlen;
114 int inloop;
115
116 void (*playrout)(int16_t *buf, uint32_t len, struct channel *chan);
117
118 if (quiet)
119 {
120 playrout=playquiet;
121 } else {
122 if (chan->status&MIXQ_INTERPOLATE)
123 {
124 if (chan->status&MIXQ_INTERPOLATEMAX)
125 {
126 if (chan->status&MIXQ_PLAY16BIT)
127 {
128 playrout=playmonoi216;
129 } else {
130 playrout=playmonoi2;
131 }
132 } else {
133 if (chan->status&MIXQ_PLAY16BIT)
134 {
135 playrout=playmonoi16;
136 } else {
137 playrout=playmonoi;
138 }
139 }
140 } else {
141 if (chan->status&MIXQ_PLAY16BIT)
142 {
143 playrout=playmono16;
144 } else {
145 playrout=playmono;
146 }
147 }
148 }
149
150 mixqPlayChannel_bigloop:
151 inloop=0;
152 mixlen=len;
153
154 if (chan->step)
155 {
156 uint32_t abs_step; /* abs of chan->step */
157 uint32_t data_left;
158 uint16_t data_left_fraction;
159
160 if (chan->step<0)
161 {
162 abs_step=-chan->step;
163 data_left = chan->pos;
164 data_left_fraction = chan->fpos;
165 if (chan->status&MIXQ_LOOPED)
166 {
167 if (chan->pos >= chan->loopstart)
168 {
169 data_left -= chan->loopstart;
170 inloop = 1;
171 }
172 }
173 } else {
174 abs_step=chan->step;
175 data_left = chan->length - chan->pos - (!chan->fpos);
176 data_left_fraction = -chan->fpos;
177 if (chan->status&MIXQ_LOOPED)
178 {
179 if (chan->pos < chan->loopend)
180 {
181 data_left -= chan->length - chan->loopend;
182 inloop = 1;
183 }
184 }
185 }
186 /* data_left should now be the end of the loop envelope */
187 {
188 /* fprintf(stderr, "Samples available to use: %d/0x%08x\n", data_left, data_left_fraction); */
189 uint64_t tmppos=((((uint64_t)data_left)<<16)|data_left_fraction)+((uint32_t)abs_step)-1;
190 /* fprintf(stderr, "Samples available to use hidef: %lld/0x%012llx\n", tmppos, tmppos);*/
191 if ((tmppos>>32)<abs_step)
192 {/* this is the safe check to avoid overflow in div */
193 uint32_t tmplen;
194 tmplen=tmppos/abs_step;
195 /* fprintf(stderr, "Samples at current playrate would be output into %d samples\n", tmplen); */
196 if (mixlen>=tmplen)
197 {
198 /* fprintf(stderr, "world wants more data than we can provide, limit output\n");*/
199 mixlen=tmplen;
200 if (!inloop)
201 {
202 /* fprintf(stderr, "We are not in loop, configure fillen\n");*/
203 chan->status&=~MIXQ_PLAYING;
204 fillen=(len-tmplen); /* the gap that is left */
205 len=mixlen;
206 }
207 }
208 }
209 }
210 }
211 playrout(buf, mixlen, chan);
212 buf+=mixlen;
213 len-=mixlen;
214 {
215 int64_t tmp64=((int64_t)chan->step)*mixlen + (uint16_t)chan->fpos;
216 chan->fpos=tmp64&0xffff;
217 chan->pos+=(tmp64>>16);
218 }
219
220 if (inloop)
221 {
222 int32_t mypos = chan->pos; /* eax */
223 if (chan->step<0)
224 {
225 if (mypos>=(int32_t)chan->loopstart)
226 return;
227 if (!(chan->status&MIXQ_PINGPONGLOOP))
228 {
229 mypos+=chan->replen;
230 } else {
231 chan->step=-chan->step;
232 if ((chan->fpos=-chan->fpos))
233 mypos++;
234 mypos=chan->loopstart+chan->loopstart-mypos;
235 }
236 } else {
237 if (mypos<chan->loopend)
238 return;
239 if (!(chan->status&MIXQ_PINGPONGLOOP))
240 {
241 mypos-=chan->replen;
242 } else {
243 chan->step=-chan->step;
244 if ((chan->fpos=-chan->fpos))
245 mypos++;
246 mypos=chan->loopend+chan->loopend-mypos;
247 }
248 }
249 chan->pos=mypos;
250 if (len)
251 goto mixqPlayChannel_bigloop;
252 }
253 if (fillen)
254 {
255 int16_t sample;
256 int count;
257 chan->pos=chan->length;
258 if (!(chan->status&MIXQ_PLAY16BIT))
259 {
260 sample=chan->realsamp.bit8[chan->pos]<<8;
261 } else {
262 sample=chan->realsamp.bit16[chan->pos];
263 }
264 for (count=0;count<fillen;count++)
265 *(buf++)=sample;
266 }
267 }
268
mixqAmplifyChannel(int32_t * buf,int16_t * src,uint32_t len,int32_t vol,uint32_t step)269 void mixqAmplifyChannel(int32_t *buf, int16_t *src, uint32_t len, int32_t vol, uint32_t step)
270 {
271 while (len)
272 {
273 (*buf) += myvoltab[vol][0][(uint8_t)((*src)>>8)] + myvoltab[vol][1][(uint8_t)((*src)&0xff)];
274 src++;
275 len--;
276 buf+=step/sizeof(uint32_t);
277 }
278 }
279
mixqAmplifyChannelUp(int32_t * buf,int16_t * src,uint32_t len,int32_t vol,uint32_t step)280 void mixqAmplifyChannelUp(int32_t *buf, int16_t *src, uint32_t len, int32_t vol, uint32_t step)
281 {
282 while (len)
283 {
284 (*buf) += myvoltab[vol][0][(uint8_t)((*src)>>8)] + myvoltab[vol][1][(uint8_t)((*src)&0xff)];
285 src++;
286 vol++;
287 len--;
288 buf+=step/sizeof(uint32_t);
289 }
290 }
291
mixqAmplifyChannelDown(int32_t * buf,int16_t * src,uint32_t len,int32_t vol,uint32_t step)292 void mixqAmplifyChannelDown(int32_t *buf, int16_t *src, uint32_t len, int32_t vol, uint32_t step)
293 {
294 while (len)
295 {
296 (*buf) += myvoltab[vol][0][(uint8_t)((*src)>>8)] + myvoltab[vol][1][(uint8_t)((*src)&0xff)];
297 src++;
298 vol--;
299 len--;
300 buf+=step/sizeof(uint32_t);
301 }
302 }
303
304