comparison src/audio/sdlgenaudiocvt.pl @ 1982:3b4ce57c6215

First shot at new audio data types (int32 and float32). Notable changes: - Converters between types are autogenerated. Instead of making multiple passes over the data with seperate filters for endianess, size, signedness, etc, converting between data types is always one specialized filter. This simplifies SDL_BuildAudioCVT(), which otherwise had a million edge cases with the new types, and makes the actually conversions more CPU cache friendly. Left a stub for adding specific optimized versions of these routines (SSE/MMX/Altivec, assembler, etc) - Autogenerated converters are built by SDL/src/audio/sdlgenaudiocvt.pl. This does not need to be run unless tweaking the code, and thus doesn't need integration into the build system. - Went through all the drivers and tried to weed out all the "Uint16" references that are better specified with the new SDL_AudioFormat typedef. - Cleaned out a bunch of hardcoded bitwise magic numbers and replaced them with new SDL_AUDIO_* macros. - Added initial float32 and int32 support code. Theoretically, existing drivers will push these through converters to get the data they want to feed to the hardware. Still TODO: - Optimize and debug new converters. - Update the CoreAudio backend to accept float32 data directly. - Other backends, too? - SDL_LoadWAV() needs to be updated to support int32 and float32 .wav files (both of which exist and can be generated by 'sox' for testing purposes). - Update the mixer to handle new datatypes. - Optionally update SDL_sound and SDL_mixer, etc.
author Ryan C. Gordon <icculus@icculus.org>
date Thu, 24 Aug 2006 12:10:46 +0000
parents
children 8055185ae4ed
comparison
equal deleted inserted replaced
1981:3f21778e7433 1982:3b4ce57c6215
1 #!/usr/bin/perl -w
2
3 use warnings;
4 use strict;
5
6 my @audiotypes = qw(
7 U8
8 S8
9 U16LSB
10 S16LSB
11 U16MSB
12 S16MSB
13 S32LSB
14 S32MSB
15 F32LSB
16 F32MSB
17 );
18
19 my %funcs;
20
21 my $custom_converters = 0;
22
23
24 sub outputHeader {
25 print <<EOF;
26 /* DO NOT EDIT THIS FILE! It is generated code. */
27 /* Please modify SDL/src/audio/sdlgenaudiocvt.pl instead. */
28
29 /*
30 SDL - Simple DirectMedia Layer
31 Copyright (C) 1997-2006 Sam Lantinga
32
33 This library is free software; you can redistribute it and/or
34 modify it under the terms of the GNU Lesser General Public
35 License as published by the Free Software Foundation; either
36 version 2.1 of the License, or (at your option) any later version.
37
38 This library is distributed in the hope that it will be useful,
39 but WITHOUT ANY WARRANTY; without even the implied warranty of
40 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41 Lesser General Public License for more details.
42
43 You should have received a copy of the GNU Lesser General Public
44 License along with this library; if not, write to the Free Software
45 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
46
47 Sam Lantinga
48 slouken\@libsdl.org
49 */
50
51 #include "SDL_config.h"
52 #include "SDL_audio.h"
53 #include "SDL_audio_c.h"
54
55 /* Now the generated code... */
56
57 EOF
58
59 my @vals = ( 127, 255, 32767, 65535, 2147483647 );
60 foreach (@vals) {
61 my $val = $_;
62 my $fval = 1.0 / $val;
63 print("#define DIVBY${val} ${fval}f\n");
64 }
65
66 print("\n");
67 }
68
69
70 sub splittype {
71 my $t = shift;
72 my ($signed, $size, $endian) = $t =~ /([USF])(\d+)([LM]SB|)/;
73 my $float = ($signed eq 'F') ? 1 : 0;
74 $signed = (($float) or ($signed eq 'S')) ? 1 : 0;
75 $endian = 'NONE' if ($endian eq '');
76
77 my $ctype = '';
78 if ($float) {
79 $ctype = (($size == 32) ? 'float' : 'double');
80 } else {
81 $ctype = (($signed) ? 'S' : 'U') . "int${size}";
82 }
83
84 return ($signed, $float, $size, $endian, $ctype);
85 }
86
87 sub getSwapFunc {
88 my ($size, $signed, $float, $endian, $val) = @_;
89 my $BEorLE = (($endian eq 'MSB') ? 'BE' : 'LE');
90 my $code = '';
91
92 if ($float) {
93 $code = "SDL_SwapFloat${BEorLE}($val)";
94 } else {
95 if ($size > 8) {
96 $code = "SDL_Swap${BEorLE}${size}($val)";
97 } else {
98 $code = $val;
99 }
100
101 if (($signed) and (!$float)) {
102 $code = "((Sint${size}) $code)";
103 }
104 }
105
106 return "${code}";
107 }
108
109
110 sub maxIntVal {
111 my ($signed, $size) = @_;
112 if ($signed) {
113 if ($size == 8) {
114 return 0x7F;
115 } elsif ($size == 16) {
116 return 0x7FFF;
117 } elsif ($size == 32) {
118 return 0x7FFFFFFF;
119 }
120 } else {
121 if ($size == 8) {
122 return 0xFF;
123 } elsif ($size == 16) {
124 return 0xFFFF;
125 } elsif ($size == 32) {
126 return 0xFFFFFFFF;
127 }
128 }
129
130 die("bug in script.\n");
131 }
132
133 sub getFloatToIntMult {
134 my ($signed, $size) = @_;
135 my $val = maxIntVal($signed, $size) . '.0';
136 $val .= 'f' if ($size < 32);
137 return $val;
138 }
139
140 sub getIntToFloatDivBy {
141 my ($signed, $size) = @_;
142 return 'DIVBY' . maxIntVal($signed, $size);
143 }
144
145 sub getSignFlipVal {
146 my $size = shift;
147 if ($size == 8) {
148 return '0x80';
149 } elsif ($size == 16) {
150 return '0x8000';
151 } elsif ($size == 32) {
152 return '0x80000000';
153 }
154
155 die("bug in script.\n");
156 }
157
158 sub buildCvtFunc {
159 my ($from, $to) = @_;
160 my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
161 my ($tsigned, $tfloat, $tsize, $tendian, $tctype) = splittype($to);
162 my $diffs = 0;
163 $diffs++ if ($fsize != $tsize);
164 $diffs++ if ($fsigned != $tsigned);
165 $diffs++ if ($ffloat != $tfloat);
166 $diffs++ if ($fendian ne $tendian);
167
168 return if ($diffs == 0);
169
170 my $hashid = "$from/$to";
171 if (1) { # !!! FIXME: if ($diffs > 1) {
172 my $sym = "SDL_Convert_${from}_to_${to}";
173 $funcs{$hashid} = $sym;
174 $custom_converters++;
175
176 # Always unsigned for ints, for possible byteswaps.
177 my $srctype = (($ffloat) ? 'float' : "Uint${fsize}");
178
179 print <<EOF;
180 static void SDLCALL
181 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
182 {
183 int i;
184 const $srctype *src;
185 $tctype *dst;
186
187 #ifdef DEBUG_CONVERT
188 fprintf(stderr, "Converting AUDIO_${from} to AUDIO_${to}.\\n");
189 #endif
190
191 EOF
192
193 if ($fsize < $tsize) {
194 my $mult = $tsize / $fsize;
195 print <<EOF;
196 src = (const $srctype *) (cvt->buf + cvt->len_cvt);
197 dst = ($tctype *) (cvt->buf + cvt->len_cvt * $mult);
198 for (i = cvt->len_cvt / sizeof ($srctype); i; --i, --src, --dst) {
199 EOF
200 } else {
201 print <<EOF;
202 src = (const $srctype *) cvt->buf;
203 dst = ($tctype *) cvt->buf;
204 for (i = cvt->len_cvt / sizeof ($srctype); i; --i, ++src, ++dst) {
205 EOF
206 }
207
208 # Have to convert to/from float/int.
209 # !!! FIXME: cast through double for int32<->float?
210 my $code = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, '*src');
211 if ($ffloat != $tfloat) {
212 if ($ffloat) {
213 my $mult = getFloatToIntMult($tsigned, $tsize);
214 $code = "(($tctype) ($code * $mult))";
215 } else {
216 # $divby will be the reciprocal, to avoid pipeline stalls
217 # from floating point division...so multiply it.
218 my $divby = getIntToFloatDivBy($fsigned, $fsize);
219 $code = "(((float) $code) * $divby)";
220 }
221 } else {
222 # All integer conversions here.
223 if ($fsigned != $tsigned) {
224 my $signflipval = getSignFlipVal($fsize);
225 $code = "(($code) ^ $signflipval)";
226 }
227
228 my $shiftval = abs($fsize - $tsize);
229 if ($fsize < $tsize) {
230 $code = "((($tctype) $code) << $shiftval)";
231 } elsif ($fsize > $tsize) {
232 $code = "(($tctype) ($code >> $shiftval))";
233 }
234 }
235
236 my $swap = getSwapFunc($tsize, $tsigned, $tfloat, $tendian, 'val');
237
238 print <<EOF;
239 const $tctype val = $code;
240 *dst = ${swap};
241 }
242
243 EOF
244
245 if ($fsize > $tsize) {
246 my $divby = $fsize / $tsize;
247 print(" cvt->len_cvt /= $divby;\n");
248 } elsif ($fsize < $tsize) {
249 my $mult = $tsize / $fsize;
250 print(" cvt->len_cvt *= $mult;\n");
251 }
252
253 print <<EOF;
254 format = AUDIO_$to;
255 if (cvt->filters[++cvt->filter_index]) {
256 cvt->filters[cvt->filter_index] (cvt, format);
257 }
258 }
259
260 EOF
261
262 } else {
263 if ($fsigned != $tsigned) {
264 $funcs{$hashid} = 'SDL_ConvertSigned';
265 } elsif ($ffloat != $tfloat) {
266 $funcs{$hashid} = 'SDL_ConvertFloat';
267 } elsif ($fsize != $tsize) {
268 $funcs{$hashid} = 'SDL_ConvertSize';
269 } elsif ($fendian ne $tendian) {
270 $funcs{$hashid} = 'SDL_ConvertEndian';
271 } else {
272 die("error in script.\n");
273 }
274 }
275 }
276
277 outputHeader();
278
279 foreach (@audiotypes) {
280 my $from = $_;
281 foreach (@audiotypes) {
282 my $to = $_;
283 buildCvtFunc($from, $to);
284 }
285 }
286
287 print <<EOF;
288 const SDL_AudioTypeFilters sdl_audio_type_filters[] =
289 {
290 EOF
291
292 foreach (@audiotypes) {
293 my $from = $_;
294 foreach (@audiotypes) {
295 my $to = $_;
296 if ($from ne $to) {
297 my $hashid = "$from/$to";
298 my $sym = $funcs{$hashid};
299 print(" { AUDIO_$from, AUDIO_$to, $sym },\n");
300 }
301 }
302 }
303
304 print <<EOF;
305 };
306
307
308 EOF
309
310 exit 0;
311
312 # end of sdlaudiocvt.pl ...
313