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