1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */
3 
4 
5 #pragma once
6 
7 #include "openmpt/all/BuildSettings.hpp"
8 
9 #include "mpt/base/arithmetic_shift.hpp"
10 #include "mpt/base/macros.hpp"
11 #include "mpt/base/math.hpp"
12 #include "mpt/base/saturate_cast.hpp"
13 #include "openmpt/base/Int24.hpp"
14 #include "openmpt/base/Types.hpp"
15 #include "openmpt/soundbase/SampleConvert.hpp"
16 
17 #include <algorithm>
18 #include <limits>
19 #include <type_traits>
20 
21 #include <cmath>
22 
23 
24 
25 OPENMPT_NAMESPACE_BEGIN
26 
27 
28 
29 namespace SC
30 {  // SC = _S_ample_C_onversion
31 
32 
33 
34 #if MPT_COMPILER_MSVC
35 template <typename Tfloat>
fastround(Tfloat x)36 MPT_FORCEINLINE Tfloat fastround(Tfloat x)
37 {
38 	static_assert(std::is_floating_point<Tfloat>::value);
39 	return std::floor(x + static_cast<Tfloat>(0.5));
40 }
41 #else
42 template <typename Tfloat>
43 MPT_FORCEINLINE Tfloat fastround(Tfloat x)
44 {
45 	static_assert(std::is_floating_point<Tfloat>::value);
46 	return mpt::round(x);
47 }
48 #endif
49 
50 
51 
52 // Shift input_t down by shift and saturate to output_t.
53 template <typename Tdst, typename Tsrc, int shift>
54 struct ConvertShift
55 {
56 	using input_t = Tsrc;
57 	using output_t = Tdst;
operator ()SC::ConvertShift58 	MPT_FORCEINLINE output_t operator()(input_t val)
59 	{
60 		return mpt::saturate_cast<output_t>(mpt::rshift_signed(val, shift));
61 	}
62 };
63 
64 
65 
66 // Shift input_t up by shift and saturate to output_t.
67 template <typename Tdst, typename Tsrc, int shift>
68 struct ConvertShiftUp
69 {
70 	using input_t = Tsrc;
71 	using output_t = Tdst;
operator ()SC::ConvertShiftUp72 	MPT_FORCEINLINE output_t operator()(input_t val)
73 	{
74 		return mpt::saturate_cast<output_t>(mpt::lshift_signed(val, shift));
75 	}
76 };
77 
78 
79 
80 
81 // Every sample conversion functor has to typedef its input_t and output_t.
82 // The input_t argument is taken by value because we only deal with per-single-sample conversions here.
83 
84 
85 // straight forward type conversions, clamping when converting from floating point.
86 template <typename Tdst, typename Tsrc>
87 struct Convert;
88 
89 template <typename Tid>
90 struct Convert<Tid, Tid>
91 {
92 	using input_t = Tid;
93 	using output_t = Tid;
operator ()SC::Convert94 	MPT_FORCEINLINE output_t operator()(input_t val)
95 	{
96 		return val;
97 	}
98 };
99 
100 template <>
101 struct Convert<uint8, int8>
102 {
103 	using input_t = int8;
104 	using output_t = uint8;
operator ()SC::Convert105 	MPT_FORCEINLINE output_t operator()(input_t val)
106 	{
107 		return static_cast<uint8>(val + 0x80);
108 	}
109 };
110 
111 template <>
112 struct Convert<uint8, int16>
113 {
114 	using input_t = int16;
115 	using output_t = uint8;
operator ()SC::Convert116 	MPT_FORCEINLINE output_t operator()(input_t val)
117 	{
118 		return static_cast<uint8>(static_cast<int8>(mpt::rshift_signed(val, 8)) + 0x80);
119 	}
120 };
121 
122 template <>
123 struct Convert<uint8, int24>
124 {
125 	using input_t = int24;
126 	using output_t = uint8;
operator ()SC::Convert127 	MPT_FORCEINLINE output_t operator()(input_t val)
128 	{
129 		return static_cast<uint8>(static_cast<int8>(mpt::rshift_signed(static_cast<int>(val), 16)) + 0x80);
130 	}
131 };
132 
133 template <>
134 struct Convert<uint8, int32>
135 {
136 	using input_t = int32;
137 	using output_t = uint8;
operator ()SC::Convert138 	MPT_FORCEINLINE output_t operator()(input_t val)
139 	{
140 		return static_cast<uint8>(static_cast<int8>(mpt::rshift_signed(val, 24)) + 0x80);
141 	}
142 };
143 
144 template <>
145 struct Convert<uint8, int64>
146 {
147 	using input_t = int64;
148 	using output_t = uint8;
operator ()SC::Convert149 	MPT_FORCEINLINE output_t operator()(input_t val)
150 	{
151 		return static_cast<uint8>(static_cast<int8>(mpt::rshift_signed(val, 56)) + 0x80);
152 	}
153 };
154 
155 template <>
156 struct Convert<uint8, float32>
157 {
158 	using input_t = float32;
159 	using output_t = uint8;
operator ()SC::Convert160 	MPT_FORCEINLINE output_t operator()(input_t val)
161 	{
162 		val = mpt::safe_clamp(val, -1.0f, 1.0f);
163 		val *= 128.0f;
164 		return static_cast<uint8>(mpt::saturate_cast<int8>(static_cast<int>(SC::fastround(val))) + 0x80);
165 	}
166 };
167 
168 template <>
169 struct Convert<uint8, double>
170 {
171 	using input_t = double;
172 	using output_t = uint8;
operator ()SC::Convert173 	MPT_FORCEINLINE output_t operator()(input_t val)
174 	{
175 		val = std::clamp(val, -1.0, 1.0);
176 		val *= 128.0;
177 		return static_cast<uint8>(mpt::saturate_cast<int8>(static_cast<int>(SC::fastround(val))) + 0x80);
178 	}
179 };
180 
181 template <>
182 struct Convert<int8, uint8>
183 {
184 	using input_t = uint8;
185 	using output_t = int8;
operator ()SC::Convert186 	MPT_FORCEINLINE output_t operator()(input_t val)
187 	{
188 		return static_cast<int8>(static_cast<int>(val) - 0x80);
189 	}
190 };
191 
192 template <>
193 struct Convert<int8, int16>
194 {
195 	using input_t = int16;
196 	using output_t = int8;
operator ()SC::Convert197 	MPT_FORCEINLINE output_t operator()(input_t val)
198 	{
199 		return static_cast<int8>(mpt::rshift_signed(val, 8));
200 	}
201 };
202 
203 template <>
204 struct Convert<int8, int24>
205 {
206 	using input_t = int24;
207 	using output_t = int8;
operator ()SC::Convert208 	MPT_FORCEINLINE output_t operator()(input_t val)
209 	{
210 		return static_cast<int8>(mpt::rshift_signed(static_cast<int>(val), 16));
211 	}
212 };
213 
214 template <>
215 struct Convert<int8, int32>
216 {
217 	using input_t = int32;
218 	using output_t = int8;
operator ()SC::Convert219 	MPT_FORCEINLINE output_t operator()(input_t val)
220 	{
221 		return static_cast<int8>(mpt::rshift_signed(val, 24));
222 	}
223 };
224 
225 template <>
226 struct Convert<int8, int64>
227 {
228 	using input_t = int64;
229 	using output_t = int8;
operator ()SC::Convert230 	MPT_FORCEINLINE output_t operator()(input_t val)
231 	{
232 		return static_cast<int8>(mpt::rshift_signed(val, 56));
233 	}
234 };
235 
236 template <>
237 struct Convert<int8, float32>
238 {
239 	using input_t = float32;
240 	using output_t = int8;
operator ()SC::Convert241 	MPT_FORCEINLINE output_t operator()(input_t val)
242 	{
243 		val = mpt::safe_clamp(val, -1.0f, 1.0f);
244 		val *= 128.0f;
245 		return mpt::saturate_cast<int8>(static_cast<int>(SC::fastround(val)));
246 	}
247 };
248 
249 template <>
250 struct Convert<int8, double>
251 {
252 	using input_t = double;
253 	using output_t = int8;
operator ()SC::Convert254 	MPT_FORCEINLINE output_t operator()(input_t val)
255 	{
256 		val = std::clamp(val, -1.0, 1.0);
257 		val *= 128.0;
258 		return mpt::saturate_cast<int8>(static_cast<int>(SC::fastround(val)));
259 	}
260 };
261 
262 template <>
263 struct Convert<int16, uint8>
264 {
265 	using input_t = uint8;
266 	using output_t = int16;
operator ()SC::Convert267 	MPT_FORCEINLINE output_t operator()(input_t val)
268 	{
269 		return static_cast<int16>(mpt::lshift_signed(static_cast<int>(val) - 0x80, 8));
270 	}
271 };
272 
273 template <>
274 struct Convert<int16, int8>
275 {
276 	using input_t = int8;
277 	using output_t = int16;
operator ()SC::Convert278 	MPT_FORCEINLINE output_t operator()(input_t val)
279 	{
280 		return static_cast<int16>(mpt::lshift_signed(val, 8));
281 	}
282 };
283 
284 template <>
285 struct Convert<int16, int24>
286 {
287 	using input_t = int24;
288 	using output_t = int16;
operator ()SC::Convert289 	MPT_FORCEINLINE output_t operator()(input_t val)
290 	{
291 		return static_cast<int16>(mpt::rshift_signed(static_cast<int>(val), 8));
292 	}
293 };
294 
295 template <>
296 struct Convert<int16, int32>
297 {
298 	using input_t = int32;
299 	using output_t = int16;
operator ()SC::Convert300 	MPT_FORCEINLINE output_t operator()(input_t val)
301 	{
302 		return static_cast<int16>(mpt::rshift_signed(val, 16));
303 	}
304 };
305 
306 template <>
307 struct Convert<int16, int64>
308 {
309 	using input_t = int64;
310 	using output_t = int16;
operator ()SC::Convert311 	MPT_FORCEINLINE output_t operator()(input_t val)
312 	{
313 		return static_cast<int16>(mpt::rshift_signed(val, 48));
314 	}
315 };
316 
317 template <>
318 struct Convert<int16, float32>
319 {
320 	using input_t = float32;
321 	using output_t = int16;
operator ()SC::Convert322 	MPT_FORCEINLINE output_t operator()(input_t val)
323 	{
324 		val = mpt::safe_clamp(val, -1.0f, 1.0f);
325 		val *= 32768.0f;
326 		return mpt::saturate_cast<int16>(static_cast<int>(SC::fastround(val)));
327 	}
328 };
329 
330 template <>
331 struct Convert<int16, double>
332 {
333 	using input_t = double;
334 	using output_t = int16;
operator ()SC::Convert335 	MPT_FORCEINLINE output_t operator()(input_t val)
336 	{
337 		val = std::clamp(val, -1.0, 1.0);
338 		val *= 32768.0;
339 		return mpt::saturate_cast<int16>(static_cast<int>(SC::fastround(val)));
340 	}
341 };
342 
343 template <>
344 struct Convert<int24, uint8>
345 {
346 	using input_t = uint8;
347 	using output_t = int24;
operator ()SC::Convert348 	MPT_FORCEINLINE output_t operator()(input_t val)
349 	{
350 		return static_cast<int24>(mpt::lshift_signed(static_cast<int>(val) - 0x80, 16));
351 	}
352 };
353 
354 template <>
355 struct Convert<int24, int8>
356 {
357 	using input_t = int8;
358 	using output_t = int24;
operator ()SC::Convert359 	MPT_FORCEINLINE output_t operator()(input_t val)
360 	{
361 		return static_cast<int24>(mpt::lshift_signed(val, 16));
362 	}
363 };
364 
365 template <>
366 struct Convert<int24, int16>
367 {
368 	using input_t = int16;
369 	using output_t = int24;
operator ()SC::Convert370 	MPT_FORCEINLINE output_t operator()(input_t val)
371 	{
372 		return static_cast<int24>(mpt::lshift_signed(val, 8));
373 	}
374 };
375 
376 template <>
377 struct Convert<int24, int32>
378 {
379 	using input_t = int32;
380 	using output_t = int24;
operator ()SC::Convert381 	MPT_FORCEINLINE output_t operator()(input_t val)
382 	{
383 		return static_cast<int24>(mpt::rshift_signed(val, 8));
384 	}
385 };
386 
387 template <>
388 struct Convert<int24, int64>
389 {
390 	using input_t = int64;
391 	using output_t = int24;
operator ()SC::Convert392 	MPT_FORCEINLINE output_t operator()(input_t val)
393 	{
394 		return static_cast<int24>(mpt::rshift_signed(val, 40));
395 	}
396 };
397 
398 template <>
399 struct Convert<int24, float32>
400 {
401 	using input_t = float32;
402 	using output_t = int24;
operator ()SC::Convert403 	MPT_FORCEINLINE output_t operator()(input_t val)
404 	{
405 		val = mpt::safe_clamp(val, -1.0f, 1.0f);
406 		val *= 2147483648.0f;
407 		return static_cast<int24>(mpt::rshift_signed(mpt::saturate_cast<int32>(static_cast<int64>(SC::fastround(val))), 8));
408 	}
409 };
410 
411 template <>
412 struct Convert<int24, double>
413 {
414 	using input_t = double;
415 	using output_t = int24;
operator ()SC::Convert416 	MPT_FORCEINLINE output_t operator()(input_t val)
417 	{
418 		val = std::clamp(val, -1.0, 1.0);
419 		val *= 2147483648.0;
420 		return static_cast<int24>(mpt::rshift_signed(mpt::saturate_cast<int32>(static_cast<int64>(SC::fastround(val))), 8));
421 	}
422 };
423 
424 template <>
425 struct Convert<int32, uint8>
426 {
427 	using input_t = uint8;
428 	using output_t = int32;
operator ()SC::Convert429 	MPT_FORCEINLINE output_t operator()(input_t val)
430 	{
431 		return static_cast<int32>(mpt::lshift_signed(static_cast<int>(val) - 0x80, 24));
432 	}
433 };
434 
435 template <>
436 struct Convert<int32, int8>
437 {
438 	using input_t = int8;
439 	using output_t = int32;
operator ()SC::Convert440 	MPT_FORCEINLINE output_t operator()(input_t val)
441 	{
442 		return static_cast<int32>(mpt::lshift_signed(val, 24));
443 	}
444 };
445 
446 template <>
447 struct Convert<int32, int16>
448 {
449 	using input_t = int16;
450 	using output_t = int32;
operator ()SC::Convert451 	MPT_FORCEINLINE output_t operator()(input_t val)
452 	{
453 		return static_cast<int32>(mpt::lshift_signed(val, 16));
454 	}
455 };
456 
457 template <>
458 struct Convert<int32, int24>
459 {
460 	using input_t = int24;
461 	using output_t = int32;
operator ()SC::Convert462 	MPT_FORCEINLINE output_t operator()(input_t val)
463 	{
464 		return static_cast<int32>(mpt::lshift_signed(static_cast<int>(val), 8));
465 	}
466 };
467 
468 template <>
469 struct Convert<int32, int64>
470 {
471 	using input_t = int64;
472 	using output_t = int32;
operator ()SC::Convert473 	MPT_FORCEINLINE output_t operator()(input_t val)
474 	{
475 		return static_cast<int32>(mpt::rshift_signed(val, 32));
476 	}
477 };
478 
479 template <>
480 struct Convert<int32, float32>
481 {
482 	using input_t = float32;
483 	using output_t = int32;
operator ()SC::Convert484 	MPT_FORCEINLINE output_t operator()(input_t val)
485 	{
486 		val = mpt::safe_clamp(val, -1.0f, 1.0f);
487 		val *= 2147483648.0f;
488 		return mpt::saturate_cast<int32>(static_cast<int64>(SC::fastround(val)));
489 	}
490 };
491 
492 template <>
493 struct Convert<int32, double>
494 {
495 	using input_t = double;
496 	using output_t = int32;
operator ()SC::Convert497 	MPT_FORCEINLINE output_t operator()(input_t val)
498 	{
499 		val = std::clamp(val, -1.0, 1.0);
500 		val *= 2147483648.0;
501 		return mpt::saturate_cast<int32>(static_cast<int64>(SC::fastround(val)));
502 	}
503 };
504 
505 template <>
506 struct Convert<int64, uint8>
507 {
508 	using input_t = uint8;
509 	using output_t = int64;
operator ()SC::Convert510 	MPT_FORCEINLINE output_t operator()(input_t val)
511 	{
512 		return mpt::lshift_signed(static_cast<int64>(val) - 0x80, 56);
513 	}
514 };
515 
516 template <>
517 struct Convert<int64, int8>
518 {
519 	using input_t = int8;
520 	using output_t = int64;
operator ()SC::Convert521 	MPT_FORCEINLINE output_t operator()(input_t val)
522 	{
523 		return mpt::lshift_signed(static_cast<int64>(val), 56);
524 	}
525 };
526 
527 template <>
528 struct Convert<int64, int16>
529 {
530 	using input_t = int16;
531 	using output_t = int64;
operator ()SC::Convert532 	MPT_FORCEINLINE output_t operator()(input_t val)
533 	{
534 		return mpt::lshift_signed(static_cast<int64>(val), 48);
535 	}
536 };
537 
538 template <>
539 struct Convert<int64, int24>
540 {
541 	using input_t = int24;
542 	using output_t = int64;
operator ()SC::Convert543 	MPT_FORCEINLINE output_t operator()(input_t val)
544 	{
545 		return mpt::lshift_signed(static_cast<int64>(val), 40);
546 	}
547 };
548 
549 template <>
550 struct Convert<int64, int32>
551 {
552 	using input_t = int32;
553 	using output_t = int64;
operator ()SC::Convert554 	MPT_FORCEINLINE output_t operator()(input_t val)
555 	{
556 		return mpt::lshift_signed(static_cast<int64>(val), 32);
557 	}
558 };
559 
560 template <>
561 struct Convert<int64, float32>
562 {
563 	using input_t = float32;
564 	using output_t = int64;
operator ()SC::Convert565 	MPT_FORCEINLINE output_t operator()(input_t val)
566 	{
567 		val = mpt::safe_clamp(val, -1.0f, 1.0f);
568 		val *= static_cast<float>(uint64(1) << 63);
569 		return mpt::saturate_cast<int64>(SC::fastround(val));
570 	}
571 };
572 
573 template <>
574 struct Convert<int64, double>
575 {
576 	using input_t = double;
577 	using output_t = int64;
operator ()SC::Convert578 	MPT_FORCEINLINE output_t operator()(input_t val)
579 	{
580 		val = std::clamp(val, -1.0, 1.0);
581 		val *= static_cast<double>(uint64(1) << 63);
582 		return mpt::saturate_cast<int64>(SC::fastround(val));
583 	}
584 };
585 
586 template <>
587 struct Convert<float32, uint8>
588 {
589 	using input_t = uint8;
590 	using output_t = float32;
operator ()SC::Convert591 	MPT_FORCEINLINE output_t operator()(input_t val)
592 	{
593 		return (static_cast<int>(val) - 0x80) * (1.0f / static_cast<float32>(static_cast<unsigned int>(1) << 7));
594 	}
595 };
596 
597 template <>
598 struct Convert<float32, int8>
599 {
600 	using input_t = int8;
601 	using output_t = float32;
operator ()SC::Convert602 	MPT_FORCEINLINE output_t operator()(input_t val)
603 	{
604 		return val * (1.0f / static_cast<float>(static_cast<unsigned int>(1) << 7));
605 	}
606 };
607 
608 template <>
609 struct Convert<float32, int16>
610 {
611 	using input_t = int16;
612 	using output_t = float32;
operator ()SC::Convert613 	MPT_FORCEINLINE output_t operator()(input_t val)
614 	{
615 		return val * (1.0f / static_cast<float>(static_cast<unsigned int>(1) << 15));
616 	}
617 };
618 
619 template <>
620 struct Convert<float32, int24>
621 {
622 	using input_t = int24;
623 	using output_t = float32;
operator ()SC::Convert624 	MPT_FORCEINLINE output_t operator()(input_t val)
625 	{
626 		return val * (1.0f / static_cast<float>(static_cast<unsigned int>(1) << 23));
627 	}
628 };
629 
630 template <>
631 struct Convert<float32, int32>
632 {
633 	using input_t = int32;
634 	using output_t = float32;
operator ()SC::Convert635 	MPT_FORCEINLINE output_t operator()(input_t val)
636 	{
637 		return val * (1.0f / static_cast<float>(static_cast<unsigned int>(1) << 31));
638 	}
639 };
640 
641 template <>
642 struct Convert<float32, int64>
643 {
644 	using input_t = int64;
645 	using output_t = float32;
operator ()SC::Convert646 	MPT_FORCEINLINE output_t operator()(input_t val)
647 	{
648 		return val * (1.0f / static_cast<float>(static_cast<uint64>(1) << 63));
649 	}
650 };
651 
652 template <>
653 struct Convert<double, uint8>
654 {
655 	using input_t = uint8;
656 	using output_t = double;
operator ()SC::Convert657 	MPT_FORCEINLINE output_t operator()(input_t val)
658 	{
659 		return (static_cast<int>(val) - 0x80) * (1.0 / static_cast<double>(static_cast<unsigned int>(1) << 7));
660 	}
661 };
662 
663 template <>
664 struct Convert<double, int8>
665 {
666 	using input_t = int8;
667 	using output_t = double;
operator ()SC::Convert668 	MPT_FORCEINLINE output_t operator()(input_t val)
669 	{
670 		return val * (1.0 / static_cast<double>(static_cast<unsigned int>(1) << 7));
671 	}
672 };
673 
674 template <>
675 struct Convert<double, int16>
676 {
677 	using input_t = int16;
678 	using output_t = double;
operator ()SC::Convert679 	MPT_FORCEINLINE output_t operator()(input_t val)
680 	{
681 		return val * (1.0 / static_cast<double>(static_cast<unsigned int>(1) << 15));
682 	}
683 };
684 
685 template <>
686 struct Convert<double, int24>
687 {
688 	using input_t = int24;
689 	using output_t = double;
operator ()SC::Convert690 	MPT_FORCEINLINE output_t operator()(input_t val)
691 	{
692 		return val * (1.0 / static_cast<double>(static_cast<unsigned int>(1) << 23));
693 	}
694 };
695 
696 template <>
697 struct Convert<double, int32>
698 {
699 	using input_t = int32;
700 	using output_t = double;
operator ()SC::Convert701 	MPT_FORCEINLINE output_t operator()(input_t val)
702 	{
703 		return val * (1.0 / static_cast<double>(static_cast<unsigned int>(1) << 31));
704 	}
705 };
706 
707 template <>
708 struct Convert<double, int64>
709 {
710 	using input_t = int64;
711 	using output_t = double;
operator ()SC::Convert712 	MPT_FORCEINLINE output_t operator()(input_t val)
713 	{
714 		return val * (1.0 / static_cast<double>(static_cast<uint64>(1) << 63));
715 	}
716 };
717 
718 template <>
719 struct Convert<double, float>
720 {
721 	using input_t = float;
722 	using output_t = double;
operator ()SC::Convert723 	MPT_FORCEINLINE output_t operator()(input_t val)
724 	{
725 		return static_cast<double>(val);
726 	}
727 };
728 
729 template <>
730 struct Convert<float, double>
731 {
732 	using input_t = double;
733 	using output_t = float;
operator ()SC::Convert734 	MPT_FORCEINLINE output_t operator()(input_t val)
735 	{
736 		return static_cast<float>(val);
737 	}
738 };
739 
740 
741 
742 template <typename Tdst, typename Tsrc>
sample_cast(Tsrc src)743 MPT_FORCEINLINE Tdst sample_cast(Tsrc src)
744 {
745 	return SC::Convert<Tdst, Tsrc>{}(src);
746 }
747 
748 
749 
750 }  // namespace SC
751 
752 
753 
754 OPENMPT_NAMESPACE_END
755