19 my @channels = ( 1, 2, 4, 6, 8 );
21 my $custom_converters = 0;
24 sub getTypeConvertHashId {
26 return "TYPECONVERTER $from/$to";
30 sub getResamplerHashId {
31 my ($from, $channels, $upsample, $multiple) = @_;
32 return "RESAMPLER $from/$channels/$upsample/$multiple";
38 /* DO NOT EDIT! This file is generated by sdlgenaudiocvt.pl */
40 Simple DirectMedia Layer
41 Copyright (C) 1997-2016 Sam Lantinga <slouken\@libsdl.org>
43 This software is provided 'as-is', without any express or implied
44 warranty. In no event will the authors be held liable for any damages
45 arising from the use of this software.
47 Permission is granted to anyone to use this software for any purpose,
48 including commercial applications, and to alter it and redistribute it
49 freely, subject to the following restrictions:
51 1. The origin of this software must not be misrepresented; you must not
52 claim that you wrote the original software. If you use this software
53 in a product, an acknowledgment in the product documentation would be
54 appreciated but is not required.
55 2. Altered source versions must be plainly marked as such, and must not be
56 misrepresented as being the original software.
57 3. This notice may not be removed or altered from any source distribution.
60 #include "../SDL_internal.h"
61 #include "SDL_audio.h"
62 #include "SDL_audio_c.h"
65 #define DEBUG_CONVERT 0
69 /* If you can guarantee your data and need space, you can eliminate code... */
71 /* Just build the arbitrary resamplers if you're saving code space. */
72 #ifndef LESS_RESAMPLERS
73 #define LESS_RESAMPLERS 0
76 /* Don't build any resamplers if you're REALLY saving code space. */
78 #define NO_RESAMPLERS 0
81 /* Don't build any type converters if you're saving code space. */
83 #define NO_CONVERTERS 0
91 my @vals = ( 127, 32767, 2147483647 );
94 my $fval = 1.0 / $val;
95 print("#define DIVBY${val} ${fval}f\n");
103 /* $custom_converters converters generated. */
107 /* vi: set ts=4 sw=4 expandtab: */
113 my ($signed, $size, $endian) = $t =~ /([USF])(\d+)([LM]SB|)/;
114 my $float = ($signed eq 'F') ? 1 : 0;
115 $signed = (($float) or ($signed eq 'S')) ? 1 : 0;
116 $endian = 'NONE' if ($endian eq '');
120 $ctype = (($size == 32) ? 'float' : 'double');
122 $ctype = (($signed) ? 'S' : 'U') . "int${size}";
125 return ($signed, $float, $size, $endian, $ctype);
129 my ($size, $signed, $float, $endian, $val) = @_;
130 my $BEorLE = (($endian eq 'MSB') ? 'BE' : 'LE');
134 $code = "SDL_SwapFloat${BEorLE}($val)";
137 $code = "SDL_Swap${BEorLE}${size}($val)";
142 if (($signed) and (!$float)) {
143 $code = "((Sint${size}) $code)";
155 } elsif ($size == 16) {
157 } elsif ($size == 32) {
161 die("bug in script.\n");
164 sub getFloatToIntMult {
166 my $val = maxIntVal($size) . '.0';
167 $val .= 'f' if ($size < 32);
171 sub getIntToFloatDivBy {
173 return 'DIVBY' . maxIntVal($size);
180 } elsif ($size == 16) {
182 } elsif ($size == 32) {
186 die("bug in script.\n");
190 my ($from, $to) = @_;
191 my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
192 my ($tsigned, $tfloat, $tsize, $tendian, $tctype) = splittype($to);
194 $diffs++ if ($fsize != $tsize);
195 $diffs++ if ($fsigned != $tsigned);
196 $diffs++ if ($ffloat != $tfloat);
197 $diffs++ if ($fendian ne $tendian);
199 return if ($diffs == 0);
201 my $hashid = getTypeConvertHashId($from, $to);
202 if (1) { # !!! FIXME: if ($diffs > 1) {
203 my $sym = "SDL_Convert_${from}_to_${to}";
204 $funcs{$hashid} = $sym;
205 $custom_converters++;
207 # Always unsigned for ints, for possible byteswaps.
208 my $srctype = (($ffloat) ? 'float' : "Uint${fsize}");
212 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
219 fprintf(stderr, "Converting AUDIO_${from} to AUDIO_${to}.\\n");
224 if ($fsize < $tsize) {
225 my $mult = $tsize / $fsize;
227 src = ((const $srctype *) (cvt->buf + cvt->len_cvt)) - 1;
228 dst = (($tctype *) (cvt->buf + cvt->len_cvt * $mult)) - 1;
229 for (i = cvt->len_cvt / sizeof ($srctype); i; --i, --src, --dst) {
233 src = (const $srctype *) cvt->buf;
234 dst = ($tctype *) cvt->buf;
235 for (i = cvt->len_cvt / sizeof ($srctype); i; --i, ++src, ++dst) {
239 # Have to convert to/from float/int.
240 # !!! FIXME: cast through double for int32<->float?
241 my $code = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, '*src');
242 if ($ffloat != $tfloat) {
244 my $mult = getFloatToIntMult($tsize);
245 if (!$tsigned) { # bump from -1.0f/1.0f to 0.0f/2.0f
246 $code = "($code + 1.0f)";
248 $code = "(($tctype) ($code * $mult))";
250 # $divby will be the reciprocal, to avoid pipeline stalls
251 # from floating point division...so multiply it.
252 my $divby = getIntToFloatDivBy($fsize);
253 $code = "(((float) $code) * $divby)";
254 if (!$fsigned) { # bump from 0.0f/2.0f to -1.0f/1.0f.
255 $code = "($code - 1.0f)";
259 # All integer conversions here.
260 if ($fsigned != $tsigned) {
261 my $signflipval = getSignFlipVal($fsize);
262 $code = "(($code) ^ $signflipval)";
265 my $shiftval = abs($fsize - $tsize);
266 if ($fsize < $tsize) {
267 $code = "((($tctype) $code) << $shiftval)";
268 } elsif ($fsize > $tsize) {
269 $code = "(($tctype) ($code >> $shiftval))";
273 my $swap = getSwapFunc($tsize, $tsigned, $tfloat, $tendian, 'val');
276 const $tctype val = $code;
282 if ($fsize > $tsize) {
283 my $divby = $fsize / $tsize;
284 print(" cvt->len_cvt /= $divby;\n");
285 } elsif ($fsize < $tsize) {
286 my $mult = $tsize / $fsize;
287 print(" cvt->len_cvt *= $mult;\n");
291 if (cvt->filters[++cvt->filter_index]) {
292 cvt->filters[cvt->filter_index] (cvt, AUDIO_$to);
299 if ($fsigned != $tsigned) {
300 $funcs{$hashid} = 'SDL_ConvertSigned';
301 } elsif ($ffloat != $tfloat) {
302 $funcs{$hashid} = 'SDL_ConvertFloat';
303 } elsif ($fsize != $tsize) {
304 $funcs{$hashid} = 'SDL_ConvertSize';
305 } elsif ($fendian ne $tendian) {
306 $funcs{$hashid} = 'SDL_ConvertEndian';
308 die("error in script.\n");
314 sub buildTypeConverters {
315 print "#if !NO_CONVERTERS\n\n";
316 foreach (@audiotypes) {
318 foreach (@audiotypes) {
320 buildCvtFunc($from, $to);
323 print "#endif /* !NO_CONVERTERS */\n\n\n";
325 print "const SDL_AudioTypeFilters sdl_audio_type_filters[] =\n{\n";
326 print "#if !NO_CONVERTERS\n";
327 foreach (@audiotypes) {
329 foreach (@audiotypes) {
332 my $hashid = getTypeConvertHashId($from, $to);
333 my $sym = $funcs{$hashid};
334 print(" { AUDIO_$from, AUDIO_$to, $sym },\n");
338 print "#endif /* !NO_CONVERTERS */\n";
340 print(" { 0, 0, NULL }\n");
345 my ($isfloat, $size) = @_;
351 die("bug in script.\n");
356 } elsif ($size == 16) {
358 } elsif ($size == 32) {
362 die("bug in script.\n");
366 # These handle arbitrary resamples...44100Hz to 48000Hz, for example.
367 # Man, this code is skanky.
368 sub buildArbitraryResampleFunc {
369 # !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc().
370 my ($from, $channels, $upsample) = @_;
371 my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
373 my $bigger = getBiggerCtype($ffloat, $fsize);
374 my $interp = ($ffloat) ? '* 0.5' : '>> 1';
376 my $resample = ($upsample) ? 'Upsample' : 'Downsample';
377 my $hashid = getResamplerHashId($from, $channels, $upsample, 0);
378 my $sym = "SDL_${resample}_${from}_${channels}c";
379 $funcs{$hashid} = $sym;
380 $custom_converters++;
382 my $fudge = $fsize * $channels * 2; # !!! FIXME
383 my $eps_adjust = ($upsample) ? 'dstsize' : 'srcsize';
386 my $block_align = $channels * $fsize/8;
389 # !!! FIXME: DEBUG_CONVERT should report frequencies.
392 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
395 fprintf(stderr, "$resample arbitrary (x%f) AUDIO_${from}, ${channels} channels.\\n", cvt->rate_incr);
398 const int srcsize = cvt->len_cvt - $fudge;
399 const int dstsize = (int) (((double)(cvt->len_cvt/${block_align})) * cvt->rate_incr) * ${block_align};
400 register int eps = 0;
403 my $endcomparison = '!=';
405 # Upsampling (growing the buffer) needs to work backwards, since we
406 # overwrite the buffer as we go.
408 $endcomparison = '>='; # dst > target
410 $fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels;
411 const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
412 const $fctype *target = ((const $fctype *) cvt->buf);
415 $endcomparison = '<'; # dst < target
417 $fctype *dst = ($fctype *) cvt->buf;
418 const $fctype *src = ($fctype *) cvt->buf;
419 const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
423 for (my $i = 0; $i < $channels; $i++) {
424 my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
425 my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
427 $fctype sample${idx} = $val;
431 for (my $i = 0; $i < $channels; $i++) {
432 my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
434 $fctype last_sample${idx} = sample${idx};
439 while (dst $endcomparison target) {
443 for (my $i = 0; $i < $channels; $i++) {
444 # !!! FIXME: don't do this swap every write, just when the samples change.
445 my $idx = (($channels - $i) - 1);
446 my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${idx}");
452 $incr = ($channels == 1) ? 'dst--' : "dst -= $channels";
453 $incr2 = ($channels == 1) ? 'src--' : "src -= $channels";
458 if ((eps << 1) >= dstsize) {
461 } else { # downsample.
462 $incr = ($channels == 1) ? 'src++' : "src += $channels";
466 if ((eps << 1) >= srcsize) {
468 for (my $i = 0; $i < $channels; $i++) {
469 my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${i}");
475 $incr = ($channels == 1) ? 'dst++' : "dst += $channels";
481 for (my $i = 0; $i < $channels; $i++) {
482 my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
483 my $swapped = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
485 sample${idx} = ($fctype) (((($bigger) $swapped) + (($bigger) last_sample${idx})) $interp);
489 for (my $i = 0; $i < $channels; $i++) {
490 my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
492 last_sample${idx} = sample${idx};
503 cvt->len_cvt = dstsize;
504 if (cvt->filters[++cvt->filter_index]) {
505 cvt->filters[cvt->filter_index] (cvt, format);
513 # These handle clean resamples...doubling and quadrupling the sample rate, etc.
514 sub buildMultipleResampleFunc {
515 # !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc().
516 my ($from, $channels, $upsample, $multiple) = @_;
517 my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
519 my $bigger = getBiggerCtype($ffloat, $fsize);
520 my $interp = ($ffloat) ? '* 0.5' : '>> 1';
521 my $interp2 = ($ffloat) ? '* 0.25' : '>> 2';
522 my $mult3 = ($ffloat) ? '3.0' : '3';
523 my $lencvtop = ($upsample) ? '*' : '/';
525 my $resample = ($upsample) ? 'Upsample' : 'Downsample';
526 my $hashid = getResamplerHashId($from, $channels, $upsample, $multiple);
527 my $sym = "SDL_${resample}_${from}_${channels}c_x${multiple}";
528 $funcs{$hashid} = $sym;
529 $custom_converters++;
531 # !!! FIXME: DEBUG_CONVERT should report frequencies.
534 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
537 fprintf(stderr, "$resample (x${multiple}) AUDIO_${from}, ${channels} channels.\\n");
540 const int dstsize = cvt->len_cvt $lencvtop $multiple;
543 my $endcomparison = '!=';
545 # Upsampling (growing the buffer) needs to work backwards, since we
546 # overwrite the buffer as we go.
548 $endcomparison = '>='; # dst > target
550 $fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels * $multiple;
551 const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
552 const $fctype *target = ((const $fctype *) cvt->buf);
555 $endcomparison = '<'; # dst < target
557 $fctype *dst = ($fctype *) cvt->buf;
558 const $fctype *src = ($fctype *) cvt->buf;
559 const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
563 for (my $i = 0; $i < $channels; $i++) {
564 my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
565 my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
567 $bigger last_sample${idx} = ($bigger) $val;
572 while (dst $endcomparison target) {
575 for (my $i = 0; $i < $channels; $i++) {
576 my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
577 my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
579 const $bigger sample${idx} = ($bigger) $val;
585 $incr = ($channels == 1) ? 'src--' : "src -= $channels";
587 my $amount = $channels * $multiple;
588 $incr = "src += $amount"; # can't ever be 1, so no "++" version.
596 # !!! FIXME: This really begs for some Altivec or SSE, etc.
598 if ($multiple == 2) {
599 for (my $i = $channels-1; $i >= 0; $i--) {
600 my $dsti = $i + $channels;
602 dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
605 for (my $i = $channels-1; $i >= 0; $i--) {
608 dst[$dsti] = ($fctype) sample${i};
611 } elsif ($multiple == 4) {
612 for (my $i = $channels-1; $i >= 0; $i--) {
613 my $dsti = $i + ($channels * 3);
615 dst[$dsti] = ($fctype) ((sample${i} + ($mult3 * last_sample${i})) $interp2);
619 for (my $i = $channels-1; $i >= 0; $i--) {
620 my $dsti = $i + ($channels * 2);
622 dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
626 for (my $i = $channels-1; $i >= 0; $i--) {
627 my $dsti = $i + ($channels * 1);
629 dst[$dsti] = ($fctype) ((($mult3 * sample${i}) + last_sample${i}) $interp2);
633 for (my $i = $channels-1; $i >= 0; $i--) {
634 my $dsti = $i + ($channels * 0);
636 dst[$dsti] = ($fctype) sample${i};
640 die('bug in program.'); # we only handle x2 and x4.
642 } else { # downsample.
643 if ($multiple == 2) {
644 for (my $i = 0; $i < $channels; $i++) {
646 dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp);
649 } elsif ($multiple == 4) {
650 # !!! FIXME: interpolate all 4 samples?
651 for (my $i = 0; $i < $channels; $i++) {
653 dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp);
657 die('bug in program.'); # we only handle x2 and x4.
661 for (my $i = 0; $i < $channels; $i++) {
662 my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
664 last_sample${idx} = sample${idx};
669 my $amount = $channels * $multiple;
670 $incr = "dst -= $amount"; # can't ever be 1, so no "--" version.
672 $incr = ($channels == 1) ? 'dst++' : "dst += $channels";
679 cvt->len_cvt = dstsize;
680 if (cvt->filters[++cvt->filter_index]) {
681 cvt->filters[cvt->filter_index] (cvt, format);
689 sub buildResamplers {
690 print "#if !NO_RESAMPLERS\n\n";
691 foreach (@audiotypes) {
693 foreach (@channels) {
695 buildArbitraryResampleFunc($from, $channel, 1);
696 buildArbitraryResampleFunc($from, $channel, 0);
700 print "\n#if !LESS_RESAMPLERS\n\n";
701 foreach (@audiotypes) {
703 foreach (@channels) {
705 for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
706 buildMultipleResampleFunc($from, $channel, 1, $multiple);
707 buildMultipleResampleFunc($from, $channel, 0, $multiple);
712 print "#endif /* !LESS_RESAMPLERS */\n";
713 print "#endif /* !NO_RESAMPLERS */\n\n\n";
715 print "const SDL_AudioRateFilters sdl_audio_rate_filters[] =\n{\n";
716 print "#if !NO_RESAMPLERS\n";
717 foreach (@audiotypes) {
719 foreach (@channels) {
721 for (my $upsample = 0; $upsample <= 1; $upsample++) {
722 my $hashid = getResamplerHashId($from, $channel, $upsample, 0);
723 my $sym = $funcs{$hashid};
724 print(" { AUDIO_$from, $channel, $upsample, 0, $sym },\n");
729 print "#if !LESS_RESAMPLERS\n";
730 foreach (@audiotypes) {
732 foreach (@channels) {
734 for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
735 for (my $upsample = 0; $upsample <= 1; $upsample++) {
736 my $hashid = getResamplerHashId($from, $channel, $upsample, $multiple);
737 my $sym = $funcs{$hashid};
738 print(" { AUDIO_$from, $channel, $upsample, $multiple, $sym },\n");
744 print "#endif /* !LESS_RESAMPLERS */\n";
745 print "#endif /* !NO_RESAMPLERS */\n";
746 print(" { 0, 0, 0, 0, NULL }\n");
754 buildTypeConverters();
760 # end of sdlgenaudiocvt.pl ...