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