xref: /haiku/src/add-ons/media/media-add-ons/mixer/Resampler.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
1 /* Copyright (C) 2003 Marcus Overhagen
2  * Released under terms of the MIT license.
3  *
4  * A simple resampling class for the audio mixer.
5  * You pick the conversion function on object creation,
6  * and then call the Resample() function, specifying data pointer,
7  * offset (in bytes) to the next sample, and count of samples for
8  * both source and destination.
9  *
10  */
11 
12 #include <MediaDefs.h>
13 #include "Resampler.h"
14 #include "MixerDebug.h"
15 
16 Resampler::Resampler(uint32 src_format, uint32 dst_format, int16 dst_valid_bits)
17  :	fFunc(0)
18 {
19 	if (dst_format == media_raw_audio_format::B_AUDIO_FLOAT) {
20 		switch (src_format) {
21 			case media_raw_audio_format::B_AUDIO_FLOAT:
22 				fFunc = &Resampler::float_to_float;
23 				return;
24 			case media_raw_audio_format::B_AUDIO_INT:
25 				fFunc = &Resampler::int32_to_float;
26 				return;
27 			case media_raw_audio_format::B_AUDIO_SHORT:
28 				fFunc = &Resampler::int16_to_float;
29 				return;
30 			case media_raw_audio_format::B_AUDIO_CHAR:
31 				fFunc = &Resampler::int8_to_float;
32 				return;
33 			case media_raw_audio_format::B_AUDIO_UCHAR:
34 				fFunc = &Resampler::uint8_to_float;
35 				return;
36 			default:
37 				ERROR("Resampler::Resampler: unknown source format 0x%x\n", src_format);
38 				return;
39 		}
40 	}
41 
42 	if (src_format == media_raw_audio_format::B_AUDIO_FLOAT) {
43 		switch (dst_format) {
44 			// float=>float already handled above
45 			case media_raw_audio_format::B_AUDIO_INT:
46 				fFunc = &Resampler::float_to_int32_32;
47 				if (dst_valid_bits == 24)
48 					fFunc = &Resampler::float_to_int32_24;
49 				else if (dst_valid_bits == 20)
50 					fFunc = &Resampler::float_to_int32_20;
51 				return;
52 			case media_raw_audio_format::B_AUDIO_SHORT:
53 				fFunc = &Resampler::float_to_int16;
54 				return;
55 			case media_raw_audio_format::B_AUDIO_CHAR:
56 				fFunc = &Resampler::float_to_int8;
57 				return;
58 			case media_raw_audio_format::B_AUDIO_UCHAR:
59 				fFunc = &Resampler::float_to_uint8;
60 				return;
61 			default:
62 				ERROR("Resampler::Resampler: unknown destination format 0x%x\n", dst_format);
63 				return;
64 		}
65 	}
66 
67 	ERROR("Resampler::Resampler: source or destination format must be B_AUDIO_FLOAT\n");
68 }
69 
70 Resampler::~Resampler()
71 {
72 }
73 
74 status_t
75 Resampler::InitCheck()
76 {
77 	return (fFunc != 0) ? B_OK : B_ERROR;
78 }
79 
80 void
81 Resampler::float_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count,
82 						  void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
83 {
84 	register const char * src = (const char *) _src;
85 	register char * dst = (char *) _dst;
86 	register int32 count = dst_sample_count;
87 	register float gain = _gain;
88 
89 	if (src_sample_count == dst_sample_count) {
90 		// optimized case for no resampling
91 		while (count--) {
92 			*(float *)dst = *(const float *)src * gain;
93 			src += src_sample_offset;
94 			dst += dst_sample_offset;
95 		}
96 		return;
97 	}
98 
99 	register float delta = float(src_sample_count) / float(dst_sample_count);
100 	register float current = 0.0f;
101 
102 	if (delta < 1.0) {
103 		// upsample
104 		while (count--) {
105 			*(float *)dst = *(const float *)src * gain;
106 			dst += dst_sample_offset;
107 			current += delta;
108 			if (current >= 1.0f) {
109 				current -= 1.0f;
110 				src += src_sample_offset;
111 			}
112 		}
113 	} else {
114 		// downsample
115 		while (count--) {
116 			*(float *)dst = *(const float *)src * gain;
117 			dst += dst_sample_offset;
118 			current += delta;
119 			register int32 skipcount = (int32)current;
120 			current -= skipcount;
121 			src += skipcount * src_sample_offset;
122 		}
123 	}
124 }
125 
126 void
127 Resampler::int32_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count,
128 						  void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
129 {
130 	register const char * src = (const char *) _src;
131 	register char * dst = (char *) _dst;
132 	register int32 count = dst_sample_count;
133 	register float gain = _gain / 2147483647.0;
134 
135 	if (src_sample_count == dst_sample_count) {
136 		// optimized case for no resampling
137 		while (count--) {
138 			*(float *)dst = *(const int32 *)src * gain;
139 			src += src_sample_offset;
140 			dst += dst_sample_offset;
141 		}
142 		return;
143 	}
144 
145 	register float delta = float(src_sample_count) / float(dst_sample_count);
146 	register float current = 0.0f;
147 
148 	if (delta < 1.0) {
149 		// upsample
150 		while (count--) {
151 			*(float *)dst = *(const int32 *)src * gain;
152 			dst += dst_sample_offset;
153 			current += delta;
154 			if (current >= 1.0f) {
155 				current -= 1.0f;
156 				src += src_sample_offset;
157 			}
158 		}
159 	} else {
160 		// downsample
161 		while (count--) {
162 			*(float *)dst = *(const int32 *)src * gain;
163 			dst += dst_sample_offset;
164 			current += delta;
165 			register int32 skipcount = (int32)current;
166 			current -= skipcount;
167 			src += skipcount * src_sample_offset;
168 		}
169 	}
170 }
171 
172 void
173 Resampler::int16_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count,
174 						  void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
175 {
176 	register const char * src = (const char *) _src;
177 	register char * dst = (char *) _dst;
178 	register int32 count = dst_sample_count;
179 	register float gain = _gain / 32767.0;
180 
181 	if (src_sample_count == dst_sample_count) {
182 		// optimized case for no resampling
183 		while (count--) {
184 			*(float *)dst = *(const int16 *)src * gain;
185 			src += src_sample_offset;
186 			dst += dst_sample_offset;
187 		}
188 		return;
189 	}
190 
191 	register float delta = float(src_sample_count) / float(dst_sample_count);
192 	register float current = 0.0f;
193 
194 	if (delta < 1.0) {
195 		// upsample
196 		while (count--) {
197 			*(float *)dst = *(const int16 *)src * gain;
198 			dst += dst_sample_offset;
199 			current += delta;
200 			if (current >= 1.0f) {
201 				current -= 1.0f;
202 				src += src_sample_offset;
203 			}
204 		}
205 	} else {
206 		// downsample
207 		while (count--) {
208 			*(float *)dst = *(const int16 *)src * gain;
209 			dst += dst_sample_offset;
210 			current += delta;
211 			register int32 skipcount = (int32)current;
212 			current -= skipcount;
213 			src += skipcount * src_sample_offset;
214 		}
215 	}
216 }
217 
218 void
219 Resampler::int8_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count,
220 				  		 void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
221 {
222 	register const char * src = (const char *) _src;
223 	register char * dst = (char *) _dst;
224 	register int32 count = dst_sample_count;
225 	register float gain = _gain / 127.0;
226 
227 	if (src_sample_count == dst_sample_count) {
228 		// optimized case for no resampling
229 		while (count--) {
230 			*(float *)dst = *(const int8 *)src * gain;
231 			src += src_sample_offset;
232 			dst += dst_sample_offset;
233 		}
234 		return;
235 	}
236 
237 	register float delta = float(src_sample_count) / float(dst_sample_count);
238 	register float current = 0.0f;
239 
240 	if (delta < 1.0) {
241 		// upsample
242 		while (count--) {
243 			*(float *)dst = *(const int8 *)src * gain;
244 			dst += dst_sample_offset;
245 			current += delta;
246 			if (current >= 1.0f) {
247 				current -= 1.0f;
248 				src += src_sample_offset;
249 			}
250 		}
251 	} else {
252 		// downsample
253 		while (count--) {
254 			*(float *)dst = *(const int8 *)src * gain;
255 			dst += dst_sample_offset;
256 			current += delta;
257 			register int32 skipcount = (int32)current;
258 			current -= skipcount;
259 			src += skipcount * src_sample_offset;
260 		}
261 	}
262 }
263 
264 void
265 Resampler::uint8_to_float(const void *_src, int32 src_sample_offset, int32 src_sample_count,
266 						  void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
267 {
268 	register const char * src = (const char *) _src;
269 	register char * dst = (char *) _dst;
270 	register int32 count = dst_sample_count;
271 	register float gain = _gain / 127.0;
272 
273 	if (src_sample_count == dst_sample_count) {
274 		// optimized case for no resampling
275 		while (count--) {
276 			*(float *)dst = (((int32) *(const uint8 *)src) - 128) * gain;
277 			src += src_sample_offset;
278 			dst += dst_sample_offset;
279 		}
280 		return;
281 	}
282 
283 	register float delta = float(src_sample_count) / float(dst_sample_count);
284 	register float current = 0.0f;
285 
286 	if (delta < 1.0) {
287 		// upsample
288 		while (count--) {
289 			*(float *)dst = (((int32) *(const uint8 *)src) - 128) * gain;
290 			dst += dst_sample_offset;
291 			current += delta;
292 			if (current >= 1.0f) {
293 				current -= 1.0f;
294 				src += src_sample_offset;
295 			}
296 		}
297 	} else {
298 		// downsample
299 		while (count--) {
300 			*(float *)dst = (((int32) *(const uint8 *)src) - 128) * gain;
301 			dst += dst_sample_offset;
302 			current += delta;
303 			register int32 skipcount = (int32)current;
304 			current -= skipcount;
305 			src += skipcount * src_sample_offset;
306 		}
307 	}
308 }
309 
310 void
311 Resampler::float_to_int32_32(const void *_src, int32 src_sample_offset, int32 src_sample_count,
312 						  void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
313 {
314 	register const char * src = (const char *) _src;
315 	register char * dst = (char *) _dst;
316 	register int32 count = dst_sample_count;
317 	register float gain = _gain * 2147483647.0;
318 
319 	if (src_sample_count == dst_sample_count) {
320 		// optimized case for no resampling
321 		while (count--) {
322 			register float sample = *(const float *)src * gain;
323 			if (sample > 2147483647.0f)
324 				*(int32 *)dst = 2147483647L;
325 			else if (sample < -2147483647.0f)
326 				*(int32 *)dst = -2147483647L;
327 			else
328 				*(int32 *)dst = (int32)sample;
329 			src += src_sample_offset;
330 			dst += dst_sample_offset;
331 		}
332 		return;
333 	}
334 
335 	register float delta = float(src_sample_count) / float(dst_sample_count);
336 	register float current = 0.0f;
337 
338 	if (delta < 1.0) {
339 		// upsample
340 		while (count--) {
341 			register float sample = *(const float *)src * gain;
342 			if (sample > 2147483647.0f)
343 				*(int32 *)dst = 2147483647L;
344 			else if (sample < -2147483647.0f)
345 				*(int32 *)dst = -2147483647L;
346 			else
347 				*(int32 *)dst = (int32)sample;
348 			dst += dst_sample_offset;
349 			current += delta;
350 			if (current >= 1.0f) {
351 				current -= 1.0f;
352 				src += src_sample_offset;
353 			}
354 		}
355 	} else {
356 		// downsample
357 		while (count--) {
358 			register float sample = *(const float *)src * gain;
359 			if (sample > 2147483647.0f)
360 				*(int32 *)dst = 2147483647L;
361 			else if (sample < -2147483647.0f)
362 				*(int32 *)dst = -2147483647L;
363 			else
364 				*(int32 *)dst = (int32)sample;
365 			dst += dst_sample_offset;
366 			current += delta;
367 			register int32 skipcount = (int32)current;
368 			current -= skipcount;
369 			src += skipcount * src_sample_offset;
370 		}
371 	}
372 }
373 
374 
375 void
376 Resampler::float_to_int32_24(const void *_src, int32 src_sample_offset, int32 src_sample_count,
377 						  void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
378 {
379 	register const char * src = (const char *) _src;
380 	register char * dst = (char *) _dst;
381 	register int32 count = dst_sample_count;
382 	register float gain = _gain * 8388607.0;
383 
384 	if (src_sample_count == dst_sample_count) {
385 		// optimized case for no resampling
386 		while (count--) {
387 			register float sample = *(const float *)src * gain;
388 			if (sample > 8388607.0f)
389 				*(int32 *)dst = 8388607L;
390 			else if (sample < -8388607.0f)
391 				*(int32 *)dst = -8388607L;
392 			else
393 				*(int32 *)dst = (int32)sample;
394 			src += src_sample_offset;
395 			dst += dst_sample_offset;
396 		}
397 		return;
398 	}
399 
400 	register float delta = float(src_sample_count) / float(dst_sample_count);
401 	register float current = 0.0f;
402 
403 	if (delta < 1.0) {
404 		// upsample
405 		while (count--) {
406 			register float sample = *(const float *)src * gain;
407 			if (sample > 8388607.0f)
408 				*(int32 *)dst = 8388607L;
409 			else if (sample < -8388607.0f)
410 				*(int32 *)dst = -8388607L;
411 			else
412 				*(int32 *)dst = (int32)sample;
413 			dst += dst_sample_offset;
414 			current += delta;
415 			if (current >= 1.0f) {
416 				current -= 1.0f;
417 				src += src_sample_offset;
418 			}
419 		}
420 	} else {
421 		// downsample
422 		while (count--) {
423 			register float sample = *(const float *)src * gain;
424 			if (sample > 8388607.0f)
425 				*(int32 *)dst = 8388607L;
426 			else if (sample < -8388607.0f)
427 				*(int32 *)dst = -8388607L;
428 			else
429 				*(int32 *)dst = (int32)sample;
430 			dst += dst_sample_offset;
431 			current += delta;
432 			register int32 skipcount = (int32)current;
433 			current -= skipcount;
434 			src += skipcount * src_sample_offset;
435 		}
436 	}
437 }
438 
439 
440 void
441 Resampler::float_to_int32_20(const void *_src, int32 src_sample_offset, int32 src_sample_count,
442 						  void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
443 {
444 	register const char * src = (const char *) _src;
445 	register char * dst = (char *) _dst;
446 	register int32 count = dst_sample_count;
447 	register float gain = _gain * 524287.0;
448 
449 	if (src_sample_count == dst_sample_count) {
450 		// optimized case for no resampling
451 		while (count--) {
452 			register float sample = *(const float *)src * gain;
453 			if (sample > 524287.0f)
454 				*(int32 *)dst = 524287L;
455 			else if (sample < -524287.0f)
456 				*(int32 *)dst = -524287L;
457 			else
458 				*(int32 *)dst = (int32)sample;
459 			src += src_sample_offset;
460 			dst += dst_sample_offset;
461 		}
462 		return;
463 	}
464 
465 	register float delta = float(src_sample_count) / float(dst_sample_count);
466 	register float current = 0.0f;
467 
468 	if (delta < 1.0) {
469 		// upsample
470 		while (count--) {
471 			register float sample = *(const float *)src * gain;
472 			if (sample > 524287.0f)
473 				*(int32 *)dst = 524287L;
474 			else if (sample < -524287.0f)
475 				*(int32 *)dst = -524287L;
476 			else
477 				*(int32 *)dst = (int32)sample;
478 			dst += dst_sample_offset;
479 			current += delta;
480 			if (current >= 1.0f) {
481 				current -= 1.0f;
482 				src += src_sample_offset;
483 			}
484 		}
485 	} else {
486 		// downsample
487 		while (count--) {
488 			register float sample = *(const float *)src * gain;
489 			if (sample > 524287.0f)
490 				*(int32 *)dst = 524287L;
491 			else if (sample < -524287.0f)
492 				*(int32 *)dst = -524287L;
493 			else
494 				*(int32 *)dst = (int32)sample;
495 			dst += dst_sample_offset;
496 			current += delta;
497 			register int32 skipcount = (int32)current;
498 			current -= skipcount;
499 			src += skipcount * src_sample_offset;
500 		}
501 	}
502 }
503 
504 
505 void
506 Resampler::float_to_int16(const void *_src, int32 src_sample_offset, int32 src_sample_count,
507 				  		  void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
508 {
509 	register const char * src = (const char *) _src;
510 	register char * dst = (char *) _dst;
511 	register int32 count = dst_sample_count;
512 	register float gain = _gain * 32767.0;
513 
514 	if (src_sample_count == dst_sample_count) {
515 		// optimized case for no resampling
516 		while (count--) {
517 			register float sample = *(const float *)src * gain;
518 			if (sample > 32767.0f)
519 				*(int16 *)dst = 32767;
520 			else if (sample < -32767.0f)
521 				*(int16 *)dst = -32767;
522 			else
523 				*(int16 *)dst = (int16)sample;
524 			src += src_sample_offset;
525 			dst += dst_sample_offset;
526 		}
527 		return;
528 	}
529 
530 	register float delta = float(src_sample_count) / float(dst_sample_count);
531 	register float current = 0.0f;
532 
533 	if (delta < 1.0) {
534 		// upsample
535 		while (count--) {
536 			register float sample = *(const float *)src * gain;
537 			if (sample > 32767.0f)
538 				*(int16 *)dst = 32767;
539 			else if (sample < -32767.0f)
540 				*(int16 *)dst = -32767;
541 			else
542 				*(int16 *)dst = (int16)sample;
543 			dst += dst_sample_offset;
544 			current += delta;
545 			if (current >= 1.0f) {
546 				current -= 1.0f;
547 				src += src_sample_offset;
548 			}
549 		}
550 	} else {
551 		// downsample
552 		while (count--) {
553 			register float sample = *(const float *)src * gain;
554 			if (sample > 32767.0f)
555 				*(int16 *)dst = 32767;
556 			else if (sample < -32767.0f)
557 				*(int16 *)dst = -32767;
558 			else
559 				*(int16 *)dst = (int16)sample;
560 			dst += dst_sample_offset;
561 			current += delta;
562 			register int32 skipcount = (int32)current;
563 			current -= skipcount;
564 			src += skipcount * src_sample_offset;
565 		}
566 	}
567 }
568 
569 void
570 Resampler::float_to_int8(const void *_src, int32 src_sample_offset, int32 src_sample_count,
571 			 			 void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
572 {
573 	register const char * src = (const char *) _src;
574 	register char * dst = (char *) _dst;
575 	register int32 count = dst_sample_count;
576 	register float gain = _gain * 127.0;
577 
578 	if (src_sample_count == dst_sample_count) {
579 		// optimized case for no resampling
580 		while (count--) {
581 			register float sample = *(const float *)src * gain;
582 			if (sample > 127.0f)
583 				*(int8 *)dst = 127;
584 			else if (sample < -127.0f)
585 				*(int8 *)dst = -127;
586 			else
587 				*(int8 *)dst = (int8)sample;
588 			src += src_sample_offset;
589 			dst += dst_sample_offset;
590 		}
591 		return;
592 	}
593 
594 	register float delta = float(src_sample_count) / float(dst_sample_count);
595 	register float current = 0.0f;
596 
597 	if (delta < 1.0) {
598 		// upsample
599 		while (count--) {
600 			register float sample = *(const float *)src * gain;
601 			if (sample > 127.0f)
602 				*(int8 *)dst = 127;
603 			else if (sample < -127.0f)
604 				*(int8 *)dst = -127;
605 			else
606 				*(int8 *)dst = (int8)sample;
607 			dst += dst_sample_offset;
608 			current += delta;
609 			if (current >= 1.0f) {
610 				current -= 1.0f;
611 				src += src_sample_offset;
612 			}
613 		}
614 	} else {
615 		// downsample
616 		while (count--) {
617 			register float sample = *(const float *)src * gain;
618 			if (sample > 127.0f)
619 				*(int8 *)dst = 127;
620 			else if (sample < -127.0f)
621 				*(int8 *)dst = -127;
622 			else
623 				*(int8 *)dst = (int8)sample;
624 			dst += dst_sample_offset;
625 			current += delta;
626 			register int32 skipcount = (int32)current;
627 			current -= skipcount;
628 			src += skipcount * src_sample_offset;
629 		}
630 	}
631 }
632 
633 void
634 Resampler::float_to_uint8(const void *_src, int32 src_sample_offset, int32 src_sample_count,
635 						  void *_dst, int32 dst_sample_offset, int32 dst_sample_count, float _gain)
636 {
637 	register const char * src = (const char *) _src;
638 	register char * dst = (char *) _dst;
639 	register int32 count = dst_sample_count;
640 	register float gain = _gain * 127.0;
641 
642 	if (src_sample_count == dst_sample_count) {
643 		// optimized case for no resampling
644 		while (count--) {
645 			register float sample = 128.0f + *(const float *)src * gain;
646 			if (sample > 255.0f)
647 				*(uint8 *)dst = 255;
648 			else if (sample < 1.0f)
649 				*(uint8 *)dst = 1;
650 			else
651 				*(uint8 *)dst = (uint8)sample;
652 			src += src_sample_offset;
653 			dst += dst_sample_offset;
654 		}
655 		return;
656 	}
657 
658 	register float delta = float(src_sample_count) / float(dst_sample_count);
659 	register float current = 0.0f;
660 
661 	if (delta < 1.0) {
662 		// upsample
663 		while (count--) {
664 			register float sample = 128.0f + *(const float *)src * gain;
665 			if (sample > 255.0f)
666 				*(uint8 *)dst = 255;
667 			else if (sample < 1.0f)
668 				*(uint8 *)dst = 1;
669 			else
670 				*(uint8 *)dst = (uint8)sample;
671 			dst += dst_sample_offset;
672 			current += delta;
673 			if (current >= 1.0f) {
674 				current -= 1.0f;
675 				src += src_sample_offset;
676 			}
677 		}
678 	} else {
679 		// downsample
680 		while (count--) {
681 			register float sample = 128.0f + *(const float *)src * gain;
682 			if (sample > 255.0f)
683 				*(uint8 *)dst = 255;
684 			else if (sample < 1.0f)
685 				*(uint8 *)dst = 1;
686 			else
687 				*(uint8 *)dst = (uint8)sample;
688 			dst += dst_sample_offset;
689 			current += delta;
690 			register int32 skipcount = (int32)current;
691 			current -= skipcount;
692 			src += skipcount * src_sample_offset;
693 		}
694 	}
695 }
696