1 /*
2  * Copyright (c) 2009, The MilkyTracker Team.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright notice,
9  *   this list of conditions and the following disclaimer.
10  * - Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * - Neither the name of the <ORGANIZATION> nor the names of its contributors
14  *   may be used to endorse or promote products derived from this software
15  *   without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  *  ResamplerFast.h
32  *  MilkyPlay
33  *
34  *  Created by Peter Barth on 08.11.07.
35  *
36  *  The goal of the resamplers in this file is to be as fast as possible.
37  *  No compromises have been made for readability nor maintainability.
38  *  (hence the use of some evil macro templates)
39  */
40 
41 #ifndef __RESAMPLERFAST_H__
42 #define __RESAMPLERFAST_H__
43 
44 #include "ResamplerMacros.h"
45 
46 /*
47  * Resampler without interpolation or ramping
48  */
49 class ResamplerSimple : public ChannelMixer::ResamplerBase
50 {
51 public:
isRamping()52 	virtual bool isRamping() { return false; }
supportsFullChecking()53 	virtual bool supportsFullChecking() { return true; }
supportsNoChecking()54 	virtual bool supportsNoChecking() { return true; }
55 
addBlockFull(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)56 	virtual void addBlockFull(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count)
57 	{
58 		mp_sint32 voll = chn->finalvoll;
59 		mp_sint32 volr = chn->finalvolr;
60 		FULLMIXER_TEMPLATE(FULLMIXER_8BIT_NORMAL, FULLMIXER_16BIT_NORMAL, 16, 0);
61 	}
62 
addBlockNoCheck(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)63 	virtual void addBlockNoCheck(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count)
64 	{
65 		mp_sint32 voll = chn->finalvoll;
66 		mp_sint32 volr = chn->finalvolr;
67 
68 		mp_sint32 smppos = chn->smppos;
69 		const mp_sint32 smpadd = (chn->flags&ChannelMixer::MP_SAMPLE_BACKWARD) ? -chn->smpadd : chn->smpadd;
70 		const mp_sint32 basepos = smppos;
71 		mp_sint32 posfixed = chn->smpposfrac;
72 
73 		mp_sint32 fp = smpadd*count;
74 		MP_INCREASESMPPOS(chn->smppos,chn->smpposfrac,fp,16);
75 
76 		if ((voll == 0) && (volr == 0)) return;
77 
78 		mp_sint32 sd1,sd2;
79 
80 		NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_NORMAL, NOCHECKMIXER_16BIT_NORMAL);
81 	}
82 };
83 
84 /*
85  * Resampler without interpolation but with ramping.
86  */
87 class ResamplerSimpleRamp : public ChannelMixer::ResamplerBase
88 {
89 public:
isRamping()90 	virtual bool isRamping() { return true; }
supportsFullChecking()91 	virtual bool supportsFullChecking() { return true; }
supportsNoChecking()92 	virtual bool supportsNoChecking() { return true; }
93 
addBlockFull(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)94 	virtual void addBlockFull(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count)
95 	{
96 		mp_sint32 voll = chn->finalvoll;
97 		mp_sint32 volr = chn->finalvolr;
98 
99 		mp_sint32 rampFromVolStepL = chn->rampFromVolStepL;
100 		mp_sint32 rampFromVolStepR = chn->rampFromVolStepR;
101 
102 		if (rampFromVolStepL || rampFromVolStepR)
103 		{
104 			FULLMIXER_TEMPLATE(FULLMIXER_8BIT_NORMAL_RAMP(true), FULLMIXER_16BIT_NORMAL_RAMP(true), 16, 0);
105 		}
106 		else
107 		{
108 			FULLMIXER_TEMPLATE(FULLMIXER_8BIT_NORMAL_RAMP(false), FULLMIXER_16BIT_NORMAL_RAMP(false), 16, 1);
109 		}
110 
111 		chn->finalvoll = voll;
112 		chn->finalvolr = volr;
113 	}
114 
addBlockNoCheck(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)115 	virtual void addBlockNoCheck(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count)
116 	{
117 		mp_sint32 voll = chn->finalvoll;
118 		mp_sint32 volr = chn->finalvolr;
119 
120 		mp_sint32 rampFromVolStepL = chn->rampFromVolStepL;
121 		mp_sint32 rampFromVolStepR = chn->rampFromVolStepR;
122 
123 		mp_sint32 smppos = chn->smppos;
124 		const mp_sint32 smpadd = (chn->flags&ChannelMixer::MP_SAMPLE_BACKWARD) ? -chn->smpadd : chn->smpadd;
125 		const mp_sint32 basepos = smppos;
126 		mp_sint32 posfixed = chn->smpposfrac;
127 
128 		mp_sint32 fp = smpadd*count;
129 		MP_INCREASESMPPOS(chn->smppos,chn->smpposfrac, fp, 16);
130 
131 		if ((voll == 0 && rampFromVolStepL == 0) && (volr == 0 && rampFromVolStepR == 0)) return;
132 
133 		mp_sint32 sd1,sd2;
134 
135 		if (rampFromVolStepL || rampFromVolStepR)
136 		{
137 			NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_NORMAL_RAMP(true), NOCHECKMIXER_16BIT_NORMAL_RAMP(true));
138 		}
139 		else
140 		{
141 			NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_NORMAL_RAMP(false), NOCHECKMIXER_16BIT_NORMAL_RAMP(false));
142 		}
143 
144 		chn->finalvoll = voll;
145 		chn->finalvolr = volr;
146 	}
147 };
148 
149 /*
150  * Resampler using linear interpolation but without ramping.
151  */
152 class ResamplerLerp : public ChannelMixer::ResamplerBase
153 {
154 public:
isRamping()155 	virtual bool isRamping() { return false; }
supportsFullChecking()156 	virtual bool supportsFullChecking() { return true; }
supportsNoChecking()157 	virtual bool supportsNoChecking() { return true; }
158 
addBlockFull(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)159 	virtual void addBlockFull(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count)
160 	{
161 		mp_sint32 voll = chn->finalvoll;
162 		mp_sint32 volr = chn->finalvolr;
163 		FULLMIXER_TEMPLATE(FULLMIXER_8BIT_LERP, FULLMIXER_16BIT_LERP, 16, 0);
164 	}
165 
addBlockNoCheck(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)166 	virtual void addBlockNoCheck(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count)
167 	{
168 		mp_sint32 voll = chn->finalvoll;
169 		mp_sint32 volr = chn->finalvolr;
170 
171 		mp_sint32 smppos = chn->smppos;
172 		const mp_sint32 smpadd = (chn->flags&ChannelMixer::MP_SAMPLE_BACKWARD) ? -chn->smpadd : chn->smpadd;
173 		const mp_sint32 basepos = smppos;
174 		mp_sint32 posfixed = chn->smpposfrac;
175 
176 		mp_sint32 fp = smpadd*count;
177 		MP_INCREASESMPPOS(chn->smppos, chn->smpposfrac, fp, 16);
178 
179 		if ((voll == 0) && (volr == 0)) return;
180 
181 		mp_sint32 sd1,sd2;
182 
183 		NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP,NOCHECKMIXER_16BIT_LERP);
184 	}
185 };
186 
187 /*
188  * Resampler using linear interpolation and ramping.
189  * Also supports the low pass filter used by Impulse Tracker
190  */
191 class ResamplerLerpRampFilter : public ChannelMixer::ResamplerBase
192 {
193 public:
isRamping()194 	virtual bool isRamping() { return true; }
supportsFullChecking()195 	virtual bool supportsFullChecking() { return true; }
supportsNoChecking()196 	virtual bool supportsNoChecking() { return true; }
197 
addBlockFull(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)198 	virtual void addBlockFull(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count)
199 	{
200 		mp_sint32 voll = chn->finalvoll;
201 		mp_sint32 volr = chn->finalvolr;
202 
203 		mp_sint32 rampFromVolStepL = chn->rampFromVolStepL;
204 		mp_sint32 rampFromVolStepR = chn->rampFromVolStepR;
205 
206 		// filter in use?
207 		if (chn->cutoff != ChannelMixer::MP_INVALID_VALUE && chn->resonance != ChannelMixer::MP_INVALID_VALUE)
208 		{
209 			const mp_sint32 a = chn->a;
210 			const mp_sint32 b = chn->b;
211 			const mp_sint32 c = chn->c;
212 
213 			mp_sint32 currsample = chn->currsample;
214 			mp_sint32 prevsample = chn->prevsample;
215 
216 			if (rampFromVolStepL || rampFromVolStepR)
217 			{
218 				FULLMIXER_TEMPLATE(FULLMIXER_8BIT_LERP_RAMP_FILTER(true), FULLMIXER_16BIT_LERP_RAMP_FILTER(true), 16, 0);
219 			}
220 			else
221 			{
222 				FULLMIXER_TEMPLATE(FULLMIXER_8BIT_LERP_RAMP_FILTER(false), FULLMIXER_16BIT_LERP_RAMP_FILTER(false), 16, 1);
223 			}
224 
225 			chn->currsample = currsample;
226 			chn->prevsample = prevsample;
227 		}
228 		// no filter
229 		else
230 		{
231 			if (rampFromVolStepL || rampFromVolStepR)
232 			{
233 				FULLMIXER_TEMPLATE(FULLMIXER_8BIT_LERP_RAMP(true), FULLMIXER_16BIT_LERP_RAMP(true), 16, 2);
234 			}
235 			else
236 			{
237 				FULLMIXER_TEMPLATE(FULLMIXER_8BIT_LERP_RAMP(false), FULLMIXER_16BIT_LERP_RAMP(false), 16, 3);
238 			}
239 		}
240 
241 		chn->finalvoll = voll;
242 		chn->finalvolr = volr;
243 	}
244 
addBlockNoCheck(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)245 	virtual void addBlockNoCheck(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count)
246 	{
247 		mp_sint32 voll = chn->finalvoll;
248 		mp_sint32 volr = chn->finalvolr;
249 
250 		mp_sint32 rampFromVolStepL = chn->rampFromVolStepL;
251 		mp_sint32 rampFromVolStepR = chn->rampFromVolStepR;
252 
253 		mp_sint32 smppos = chn->smppos;
254 		const mp_sint32 smpadd = (chn->flags&ChannelMixer::MP_SAMPLE_BACKWARD) ? -chn->smpadd : chn->smpadd;
255 		const mp_sint32 basepos = smppos;
256 		mp_sint32 posfixed = chn->smpposfrac;
257 
258 		mp_sint32 fp = smpadd*count;
259 		MP_INCREASESMPPOS(chn->smppos, chn->smpposfrac, fp, 16);
260 
261 		mp_sint32 sd1,sd2;
262 
263 		// filter in use?
264 		if (chn->cutoff != ChannelMixer::MP_INVALID_VALUE && chn->resonance != ChannelMixer::MP_INVALID_VALUE)
265 		{
266 			const mp_sint32 a = chn->a;
267 			const mp_sint32 b = chn->b;
268 			const mp_sint32 c = chn->c;
269 
270 			mp_sint32 currsample = chn->currsample;
271 			mp_sint32 prevsample = chn->prevsample;
272 
273 			// check if ramping has to be performed
274 			if (rampFromVolStepL || rampFromVolStepR)
275 			{
276 				NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP_FILTER(true), NOCHECKMIXER_16BIT_LERP_RAMP_FILTER(true));
277 			}
278 			else
279 			{
280 				NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP_FILTER(false), NOCHECKMIXER_16BIT_LERP_RAMP_FILTER(false));
281 			}
282 
283 			chn->currsample = currsample;
284 			chn->prevsample = prevsample;
285 		}
286 		// no filter
287 		else
288 		{
289 			if ((voll == 0 && rampFromVolStepL == 0) && (volr == 0 && rampFromVolStepR == 0)) return;
290 
291 			// check if ramping has to be performed
292 			if (rampFromVolStepL || rampFromVolStepR)
293 			{
294 				NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP(true), NOCHECKMIXER_16BIT_LERP_RAMP(true));
295 			}
296 			else
297 			{
298 				NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP(false), NOCHECKMIXER_16BIT_LERP_RAMP(false));
299 			}
300 		}
301 
302 		chn->finalvoll = voll;
303 		chn->finalvolr = volr;
304 	}
305 };
306 
307 /*
308  * only for testing purpose, some dummy resampler that can be used to
309  * play around etc.
310  */
311 class ResamplerDummy : public ChannelMixer::ResamplerBase
312 {
313 public:
isRamping()314 	virtual bool isRamping() { return false; }
supportsFullChecking()315 	virtual bool supportsFullChecking() { return false; }
supportsNoChecking()316 	virtual bool supportsNoChecking() { return true; }
317 
addBlockNoCheck(mp_sint32 * buffer,ChannelMixer::TMixerChannel * chn,mp_uint32 count)318 	virtual void addBlockNoCheck(mp_sint32* buffer, ChannelMixer::TMixerChannel* chn, mp_uint32 count)
319 	{
320 		mp_sint32 voll = chn->finalvoll;
321 		mp_sint32 volr = chn->finalvolr;
322 
323 		//const mp_sint32 rampFromVolStepL = chn->rampFromVolStepL;
324 		//const mp_sint32 rampFromVolStepR = chn->rampFromVolStepR;
325 
326 		mp_sint32 smppos = chn->smppos;
327 		mp_sint32 smpposfrac = chn->smpposfrac;
328 		const mp_sint32 smpadd = (chn->flags&ChannelMixer::MP_SAMPLE_BACKWARD) ? -chn->smpadd : chn->smpadd;
329 
330 		mp_sint32 sd1,sd2;
331 
332 		const mp_sint32 flags = chn->flags;
333 		const mp_sint32 loopstart = chn->loopstart;
334 		const mp_sint32 loopend = chn->loopend;
335 		const mp_sint32 smplen = chn->smplen;
336 
337 		mp_sint32 fixedtimefrac = chn->fixedtimefrac;
338 		const mp_sint32 timeadd = chn->smpadd;
339 
340 		if (!(flags&4))
341 		{
342 			const mp_sbyte* sample = chn->sample;
343 			while (count--)
344 			{
345 				/*sd1 = sample[smppos] << 8;
346 				sd2 = sample[smppos+1] << 8;
347 
348 				sd1 = ((sd1<<12)+(smpposfrac>>4)*(sd2-sd1))>>12;
349 
350 				(*buffer++)+=((sd1*(voll>>15))>>15);
351 				(*buffer++)+=((sd1*(volr>>15))>>15);
352 
353 				voll+=rampFromVolStepL;
354 				volr+=rampFromVolStepR; */
355 
356 				mp_sint32 ofsf, v0, v1, v2, v3;
357 
358 				v1 = sample[smppos] << 8;
359 				v2 = sample[smppos + 1] << 8;
360 
361 				v0 = sample[smppos - 1] << 8;
362 				v3 = sample[smppos + 2] << 8;
363 				ofsf = smpposfrac + 65536;
364 				v3 += -3*v2 + 3*v1 - v0;
365 				v3 = ChannelMixer::fixedmul(v3, (ofsf - 2*65536) / 6);
366 				v3 += v2 - v1 - v1 + v0;
367 				v3 = ChannelMixer::fixedmul(v3, (ofsf - 65536) >> 1);
368 				v3 += v1 - v0;
369 				v3 = ChannelMixer::fixedmul(v3, ofsf);
370 				v3 += v0;
371 
372 				(*buffer++)+=((v3*(voll>>15))>>15);
373 				(*buffer++)+=((v3*(volr>>15))>>15);
374 
375 				//voll+=rampFromVolStepL;
376 				//volr+=rampFromVolStepR;
377 
378 				MP_INCREASESMPPOS(smppos, smpposfrac, smpadd, 16);
379 			}
380 		}
381 		else
382 		{
383 			const mp_sword* sample = (const mp_sword*)chn->sample;
384 			while (count--)
385 			{
386 				mp_sint32 ofsf, v0, v1, v2, v3;
387 
388 				v1 = sample[smppos];
389 				v2 = sample[smppos + 1];
390 
391 				v0 = sample[smppos - 1];
392 				v3 = sample[smppos + 2];
393 				ofsf = smpposfrac + 65536;
394 				v3 += -3*v2 + 3*v1 - v0;
395 				v3 = ChannelMixer::fixedmul(v3, (ofsf - 2*65536) / 6);
396 				v3 += v2 - v1 - v1 + v0;
397 				v3 = ChannelMixer::fixedmul(v3, (ofsf - 65536) >> 1);
398 				v3 += v1 - v0;
399 				v3 = ChannelMixer::fixedmul(v3, ofsf);
400 				v3 += v0;
401 
402 				(*buffer++)+=((v3*(voll>>15))>>15);
403 				(*buffer++)+=((v3*(volr>>15))>>15);
404 
405 				//voll+=rampFromVolStepL;
406 				//volr+=rampFromVolStepR;
407 
408 				MP_INCREASESMPPOS(smppos, smpposfrac, smpadd, 16);
409 			}
410 		}
411 
412 		chn->smppos = smppos;
413 		chn->smpposfrac = smpposfrac;
414 
415 		chn->fixedtimefrac = fixedtimefrac;
416 
417 		/*if (!(chn->flags&4))
418 		{
419 			const mp_sbyte* sample = chn->sample + basepos;
420 			while (count--)
421 			{
422 				sd1 = sample[posfixed>>16]<<8;
423 				sd2 = sample[(posfixed>>16)+1]<<8;
424 
425 				sd1 =((sd1<<12)+((posfixed>>4)&0xfff)*(sd2-sd1))>>12;
426 
427 				(*buffer++)+=((sd1*(voll>>15))>>15);
428 				(*buffer++)+=((sd1*(volr>>15))>>15);
429 
430 				voll+=rampFromVolStepL;
431 				volr+=rampFromVolStepR;
432 				posfixed+=smpadd;
433 			}
434 		}
435 		else
436 		{
437 			const mp_sword* sample = (const mp_sword*)chn->sample + basepos;
438 			while (count--)
439 			{
440 				sd1 = sample[posfixed>>16];
441 				sd2 = sample[(posfixed>>16)+1];
442 
443 				sd1 =((sd1<<12)+((posfixed>>4)&0xfff)*(sd2-sd1))>>12;
444 
445 				(*buffer++)+=((sd1*(voll>>15))>>15);
446 				(*buffer++)+=((sd1*(volr>>15))>>15);
447 
448 				voll+=rampFromVolStepL;
449 				volr+=rampFromVolStepR;
450 				posfixed+=smpadd;
451 			}
452 		} */
453 
454 /*
455 		if (chn->cutoff != MP_INVALID_VALUE && chn->resonance != MP_INVALID_VALUE)
456 		{
457 			const mp_sint32 a = chn->a;
458 			const mp_sint32 b = chn->b;
459 			const mp_sint32 c = chn->c;
460 
461 			mp_sint32 currsample = chn->currsample;
462 			mp_sint32 prevsample = chn->prevsample;
463 
464 			// check if ramping has to be performed
465 			if (rampFromVolStepL || rampFromVolStepR)
466 			{
467 				NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP_FILTER(true),NOCHECKMIXER_16BIT_LERP_RAMP_FILTER(true));
468 			}
469 			else
470 			{
471 				NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP_FILTER(false),NOCHECKMIXER_16BIT_LERP_RAMP_FILTER(false));
472 			}
473 
474 			chn->currsample = currsample;
475 			chn->prevsample = prevsample;
476 		}
477 		else
478 		{
479 			if ((voll == 0 && rampFromVolStepL == 0) && (volr == 0 && rampFromVolStepR == 0)) return;
480 
481 			// check if ramping has to be performed
482 			if (rampFromVolStepL || rampFromVolStepR)
483 			{
484 				NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP(true),NOCHECKMIXER_16BIT_LERP_RAMP(true));
485 			}
486 			else
487 			{
488 				NOCHECKMIXER_TEMPLATE(NOCHECKMIXER_8BIT_LERP_RAMP(false),NOCHECKMIXER_16BIT_LERP_RAMP(false));
489 			}
490 		}*/
491 
492 		//chn->finalvoll = voll;
493 		//chn->finalvolr = volr;
494 	}
495 };
496 
497 #endif
498