SDL 2.0
SDL_audiocvt.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "../SDL_internal.h"
22
23/* Functions for audio drivers to perform runtime conversion of audio format */
24
25/* FIXME: Channel weights when converting from more channels to fewer may need to be adjusted, see https://msdn.microsoft.com/en-us/library/windows/desktop/ff819070(v=vs.85).aspx
26*/
27
28#include "SDL.h"
29#include "SDL_audio.h"
30#include "SDL_audio_c.h"
31
32#include "SDL_loadso.h"
33#include "SDL_assert.h"
34#include "../SDL_dataqueue.h"
35#include "SDL_cpuinfo.h"
36
37#define DEBUG_AUDIOSTREAM 0
38
39#ifdef __SSE3__
40#define HAVE_SSE3_INTRINSICS 1
41#endif
42
43#if HAVE_SSE3_INTRINSICS
44/* Convert from stereo to mono. Average left and right. */
45static void SDLCALL
46SDL_ConvertStereoToMono_SSE3(SDL_AudioCVT * cvt, SDL_AudioFormat format)
47{
48 float *dst = (float *) cvt->buf;
49 const float *src = dst;
50 int i = cvt->len_cvt / 8;
51
52 LOG_DEBUG_CONVERT("stereo", "mono (using SSE3)");
54
55 /* We can only do this if dst is aligned to 16 bytes; since src is the
56 same pointer and it moves by 2, it can't be forcibly aligned. */
57 if ((((size_t) dst) & 15) == 0) {
58 /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
59 const __m128 divby2 = _mm_set1_ps(0.5f);
60 while (i >= 4) { /* 4 * float32 */
61 _mm_store_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_load_ps(src), _mm_load_ps(src+4)), divby2));
62 i -= 4; src += 8; dst += 4;
63 }
64 }
65
66 /* Finish off any leftovers with scalar operations. */
67 while (i) {
68 *dst = (src[0] + src[1]) * 0.5f;
69 dst++; i--; src += 2;
70 }
71
72 cvt->len_cvt /= 2;
73 if (cvt->filters[++cvt->filter_index]) {
74 cvt->filters[cvt->filter_index] (cvt, format);
75 }
76}
77#endif
78
79/* Convert from stereo to mono. Average left and right. */
80static void SDLCALL
82{
83 float *dst = (float *) cvt->buf;
84 const float *src = dst;
85 int i;
86
87 LOG_DEBUG_CONVERT("stereo", "mono");
89
90 for (i = cvt->len_cvt / 8; i; --i, src += 2) {
91 *(dst++) = (src[0] + src[1]) * 0.5f;
92 }
93
94 cvt->len_cvt /= 2;
95 if (cvt->filters[++cvt->filter_index]) {
96 cvt->filters[cvt->filter_index] (cvt, format);
97 }
98}
99
100
101/* Convert from 5.1 to stereo. Average left and right, distribute center, discard LFE. */
102static void SDLCALL
104{
105 float *dst = (float *) cvt->buf;
106 const float *src = dst;
107 int i;
108
109 LOG_DEBUG_CONVERT("5.1", "stereo");
111
112 /* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
113 for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 2) {
114 const float front_center_distributed = src[2] * 0.5f;
115 dst[0] = (src[0] + front_center_distributed + src[4]) / 2.5f; /* left */
116 dst[1] = (src[1] + front_center_distributed + src[5]) / 2.5f; /* right */
117 }
118
119 cvt->len_cvt /= 3;
120 if (cvt->filters[++cvt->filter_index]) {
121 cvt->filters[cvt->filter_index] (cvt, format);
122 }
123}
124
125
126/* Convert from quad to stereo. Average left and right. */
127static void SDLCALL
129{
130 float *dst = (float *) cvt->buf;
131 const float *src = dst;
132 int i;
133
134 LOG_DEBUG_CONVERT("quad", "stereo");
136
137 for (i = cvt->len_cvt / (sizeof (float) * 4); i; --i, src += 4, dst += 2) {
138 dst[0] = (src[0] + src[2]) * 0.5f; /* left */
139 dst[1] = (src[1] + src[3]) * 0.5f; /* right */
140 }
141
142 cvt->len_cvt /= 2;
143 if (cvt->filters[++cvt->filter_index]) {
144 cvt->filters[cvt->filter_index] (cvt, format);
145 }
146}
147
148
149/* Convert from 7.1 to 5.1. Distribute sides across front and back. */
150static void SDLCALL
152{
153 float *dst = (float *) cvt->buf;
154 const float *src = dst;
155 int i;
156
157 LOG_DEBUG_CONVERT("7.1", "5.1");
159
160 for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8, dst += 6) {
161 const float surround_left_distributed = src[6] * 0.5f;
162 const float surround_right_distributed = src[7] * 0.5f;
163 dst[0] = (src[0] + surround_left_distributed) / 1.5f; /* FL */
164 dst[1] = (src[1] + surround_right_distributed) / 1.5f; /* FR */
165 dst[2] = src[2] / 1.5f; /* CC */
166 dst[3] = src[3] / 1.5f; /* LFE */
167 dst[4] = (src[4] + surround_left_distributed) / 1.5f; /* BL */
168 dst[5] = (src[5] + surround_right_distributed) / 1.5f; /* BR */
169 }
170
171 cvt->len_cvt /= 8;
172 cvt->len_cvt *= 6;
173 if (cvt->filters[++cvt->filter_index]) {
174 cvt->filters[cvt->filter_index] (cvt, format);
175 }
176}
177
178
179/* Convert from 5.1 to quad. Distribute center across front, discard LFE. */
180static void SDLCALL
182{
183 float *dst = (float *) cvt->buf;
184 const float *src = dst;
185 int i;
186
187 LOG_DEBUG_CONVERT("5.1", "quad");
189
190 /* SDL's 4.0 layout: FL+FR+BL+BR */
191 /* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
192 for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 4) {
193 const float front_center_distributed = src[2] * 0.5f;
194 dst[0] = (src[0] + front_center_distributed) / 1.5f; /* FL */
195 dst[1] = (src[1] + front_center_distributed) / 1.5f; /* FR */
196 dst[2] = src[4] / 1.5f; /* BL */
197 dst[3] = src[5] / 1.5f; /* BR */
198 }
199
200 cvt->len_cvt /= 6;
201 cvt->len_cvt *= 4;
202 if (cvt->filters[++cvt->filter_index]) {
203 cvt->filters[cvt->filter_index] (cvt, format);
204 }
205}
206
207
208/* Upmix mono to stereo (by duplication) */
209static void SDLCALL
211{
212 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
213 float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
214 int i;
215
216 LOG_DEBUG_CONVERT("mono", "stereo");
218
219 for (i = cvt->len_cvt / sizeof (float); i; --i) {
220 src--;
221 dst -= 2;
222 dst[0] = dst[1] = *src;
223 }
224
225 cvt->len_cvt *= 2;
226 if (cvt->filters[++cvt->filter_index]) {
227 cvt->filters[cvt->filter_index] (cvt, format);
228 }
229}
230
231
232/* Upmix stereo to a pseudo-5.1 stream */
233static void SDLCALL
235{
236 int i;
237 float lf, rf, ce;
238 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
239 float *dst = (float *) (cvt->buf + cvt->len_cvt * 3);
240
241 LOG_DEBUG_CONVERT("stereo", "5.1");
243
244 for (i = cvt->len_cvt / (sizeof(float) * 2); i; --i) {
245 dst -= 6;
246 src -= 2;
247 lf = src[0];
248 rf = src[1];
249 ce = (lf + rf) * 0.5f;
250 /* !!! FIXME: FL and FR may clip */
251 dst[0] = lf + (lf - ce); /* FL */
252 dst[1] = rf + (rf - ce); /* FR */
253 dst[2] = ce; /* FC */
254 dst[3] = 0; /* LFE (only meant for special LFE effects) */
255 dst[4] = lf; /* BL */
256 dst[5] = rf; /* BR */
257 }
258
259 cvt->len_cvt *= 3;
260 if (cvt->filters[++cvt->filter_index]) {
261 cvt->filters[cvt->filter_index] (cvt, format);
262 }
263}
264
265
266/* Upmix quad to a pseudo-5.1 stream */
267static void SDLCALL
269{
270 int i;
271 float lf, rf, lb, rb, ce;
272 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
273 float *dst = (float *) (cvt->buf + cvt->len_cvt * 3 / 2);
274
275 LOG_DEBUG_CONVERT("quad", "5.1");
277 SDL_assert(cvt->len_cvt % (sizeof(float) * 4) == 0);
278
279 for (i = cvt->len_cvt / (sizeof(float) * 4); i; --i) {
280 dst -= 6;
281 src -= 4;
282 lf = src[0];
283 rf = src[1];
284 lb = src[2];
285 rb = src[3];
286 ce = (lf + rf) * 0.5f;
287 /* !!! FIXME: FL and FR may clip */
288 dst[0] = lf + (lf - ce); /* FL */
289 dst[1] = rf + (rf - ce); /* FR */
290 dst[2] = ce; /* FC */
291 dst[3] = 0; /* LFE (only meant for special LFE effects) */
292 dst[4] = lb; /* BL */
293 dst[5] = rb; /* BR */
294 }
295
296 cvt->len_cvt = cvt->len_cvt * 3 / 2;
297 if (cvt->filters[++cvt->filter_index]) {
298 cvt->filters[cvt->filter_index] (cvt, format);
299 }
300}
301
302
303/* Upmix stereo to a pseudo-4.0 stream (by duplication) */
304static void SDLCALL
306{
307 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
308 float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
309 float lf, rf;
310 int i;
311
312 LOG_DEBUG_CONVERT("stereo", "quad");
314
315 for (i = cvt->len_cvt / (sizeof(float) * 2); i; --i) {
316 dst -= 4;
317 src -= 2;
318 lf = src[0];
319 rf = src[1];
320 dst[0] = lf; /* FL */
321 dst[1] = rf; /* FR */
322 dst[2] = lf; /* BL */
323 dst[3] = rf; /* BR */
324 }
325
326 cvt->len_cvt *= 2;
327 if (cvt->filters[++cvt->filter_index]) {
328 cvt->filters[cvt->filter_index] (cvt, format);
329 }
330}
331
332
333/* Upmix 5.1 to 7.1 */
334static void SDLCALL
336{
337 float lf, rf, lb, rb, ls, rs;
338 int i;
339 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
340 float *dst = (float *) (cvt->buf + cvt->len_cvt * 4 / 3);
341
342 LOG_DEBUG_CONVERT("5.1", "7.1");
344 SDL_assert(cvt->len_cvt % (sizeof(float) * 6) == 0);
345
346 for (i = cvt->len_cvt / (sizeof(float) * 6); i; --i) {
347 dst -= 8;
348 src -= 6;
349 lf = src[0];
350 rf = src[1];
351 lb = src[4];
352 rb = src[5];
353 ls = (lf + lb) * 0.5f;
354 rs = (rf + rb) * 0.5f;
355 /* !!! FIXME: these four may clip */
356 lf += lf - ls;
357 rf += rf - ls;
358 lb += lb - ls;
359 rb += rb - ls;
360 dst[3] = src[3]; /* LFE */
361 dst[2] = src[2]; /* FC */
362 dst[7] = rs; /* SR */
363 dst[6] = ls; /* SL */
364 dst[5] = rb; /* BR */
365 dst[4] = lb; /* BL */
366 dst[1] = rf; /* FR */
367 dst[0] = lf; /* FL */
368 }
369
370 cvt->len_cvt = cvt->len_cvt * 4 / 3;
371
372 if (cvt->filters[++cvt->filter_index]) {
373 cvt->filters[cvt->filter_index] (cvt, format);
374 }
375}
376
377/* SDL's resampler uses a "bandlimited interpolation" algorithm:
378 https://ccrma.stanford.edu/~jos/resample/ */
379
380#define RESAMPLER_ZERO_CROSSINGS 5
381#define RESAMPLER_BITS_PER_SAMPLE 16
382#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING (1 << ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1))
383#define RESAMPLER_FILTER_SIZE ((RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS) + 1)
384
385/* This is a "modified" bessel function, so you can't use POSIX j0() */
386static double
387bessel(const double x)
388{
389 const double xdiv2 = x / 2.0;
390 double i0 = 1.0f;
391 double f = 1.0f;
392 int i = 1;
393
394 while (SDL_TRUE) {
395 const double diff = SDL_pow(xdiv2, i * 2) / SDL_pow(f, 2);
396 if (diff < 1.0e-21f) {
397 break;
398 }
399 i0 += diff;
400 i++;
401 f *= (double) i;
402 }
403
404 return i0;
405}
406
407/* build kaiser table with cardinal sine applied to it, and array of differences between elements. */
408static void
409kaiser_and_sinc(float *table, float *diffs, const int tablelen, const double beta)
410{
411 const int lenm1 = tablelen - 1;
412 const int lenm1div2 = lenm1 / 2;
413 int i;
414
415 table[0] = 1.0f;
416 for (i = 1; i < tablelen; i++) {
417 const double kaiser = bessel(beta * SDL_sqrt(1.0 - SDL_pow(((i - lenm1) / 2.0) / lenm1div2, 2.0))) / bessel(beta);
418 table[tablelen - i] = (float) kaiser;
419 }
420
421 for (i = 1; i < tablelen; i++) {
422 const float x = (((float) i) / ((float) RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) * ((float) M_PI);
423 table[i] *= SDL_sinf(x) / x;
424 diffs[i - 1] = table[i] - table[i - 1];
425 }
426 diffs[lenm1] = 0.0f;
427}
428
429
431static float *ResamplerFilter = NULL;
433
434int
436{
438 if (!ResamplerFilter) {
439 /* if dB > 50, beta=(0.1102 * (dB - 8.7)), according to Matlab. */
440 const double dB = 80.0;
441 const double beta = 0.1102 * (dB - 8.7);
442 const size_t alloclen = RESAMPLER_FILTER_SIZE * sizeof (float);
443
444 ResamplerFilter = (float *) SDL_malloc(alloclen);
445 if (!ResamplerFilter) {
447 return SDL_OutOfMemory();
448 }
449
450 ResamplerFilterDifference = (float *) SDL_malloc(alloclen);
455 return SDL_OutOfMemory();
456 }
458 }
460 return 0;
461}
462
463void
465{
470}
471
472static int
473ResamplerPadding(const int inrate, const int outrate)
474{
475 if (inrate == outrate) {
476 return 0;
477 } else if (inrate > outrate) {
478 return (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate)));
479 }
481}
482
483/* lpadding and rpadding are expected to be buffers of (ResamplePadding(inrate, outrate) * chans * sizeof (float)) bytes. */
484static int
485SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
486 const float *lpadding, const float *rpadding,
487 const float *inbuf, const int inbuflen,
488 float *outbuf, const int outbuflen)
489{
490 const double finrate = (double) inrate;
491 const double outtimeincr = 1.0 / ((float) outrate);
492 const double ratio = ((float) outrate) / ((float) inrate);
493 const int paddinglen = ResamplerPadding(inrate, outrate);
494 const int framelen = chans * (int)sizeof (float);
495 const int inframes = inbuflen / framelen;
496 const int wantedoutframes = (int) ((inbuflen / framelen) * ratio); /* outbuflen isn't total to write, it's total available. */
497 const int maxoutframes = outbuflen / framelen;
498 const int outframes = SDL_min(wantedoutframes, maxoutframes);
499 float *dst = outbuf;
500 double outtime = 0.0;
501 int i, j, chan;
502
503 for (i = 0; i < outframes; i++) {
504 const int srcindex = (int) (outtime * inrate);
505 const double intime = ((double) srcindex) / finrate;
506 const double innexttime = ((double) (srcindex + 1)) / finrate;
507 const double interpolation1 = 1.0 - ((innexttime - outtime) / (innexttime - intime));
508 const int filterindex1 = (int) (interpolation1 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
509 const double interpolation2 = 1.0 - interpolation1;
510 const int filterindex2 = (int) (interpolation2 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
511
512 for (chan = 0; chan < chans; chan++) {
513 float outsample = 0.0f;
514
515 /* do this twice to calculate the sample, once for the "left wing" and then same for the right. */
516 /* !!! FIXME: do both wings in one loop */
517 for (j = 0; (filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
518 const int srcframe = srcindex - j;
519 /* !!! FIXME: we can bubble this conditional out of here by doing a pre loop. */
520 const float insample = (srcframe < 0) ? lpadding[((paddinglen + srcframe) * chans) + chan] : inbuf[(srcframe * chans) + chan];
521 outsample += (float)(insample * (ResamplerFilter[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation1 * ResamplerFilterDifference[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
522 }
523
524 for (j = 0; (filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
525 const int srcframe = srcindex + 1 + j;
526 /* !!! FIXME: we can bubble this conditional out of here by doing a post loop. */
527 const float insample = (srcframe >= inframes) ? rpadding[((srcframe - inframes) * chans) + chan] : inbuf[(srcframe * chans) + chan];
528 outsample += (float)(insample * (ResamplerFilter[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation2 * ResamplerFilterDifference[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
529 }
530 *(dst++) = outsample;
531 }
532
533 outtime += outtimeincr;
534 }
535
536 return outframes * chans * sizeof (float);
537}
538
539int
541{
542 /* !!! FIXME: (cvt) should be const; stack-copy it here. */
543 /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
544
545 /* Make sure there's data to convert */
546 if (cvt->buf == NULL) {
547 return SDL_SetError("No buffer allocated for conversion");
548 }
549
550 /* Return okay if no conversion is necessary */
551 cvt->len_cvt = cvt->len;
552 if (cvt->filters[0] == NULL) {
553 return 0;
554 }
555
556 /* Set up the conversion and go! */
557 cvt->filter_index = 0;
558 cvt->filters[0] (cvt, cvt->src_format);
559 return 0;
560}
561
562static void SDLCALL
564{
565#if DEBUG_CONVERT
566 printf("Converting byte order\n");
567#endif
568
569 switch (SDL_AUDIO_BITSIZE(format)) {
570 #define CASESWAP(b) \
571 case b: { \
572 Uint##b *ptr = (Uint##b *) cvt->buf; \
573 int i; \
574 for (i = cvt->len_cvt / sizeof (*ptr); i; --i, ++ptr) { \
575 *ptr = SDL_Swap##b(*ptr); \
576 } \
577 break; \
578 }
579
580 CASESWAP(16);
581 CASESWAP(32);
582 CASESWAP(64);
583
584 #undef CASESWAP
585
586 default: SDL_assert(!"unhandled byteswap datatype!"); break;
587 }
588
589 if (cvt->filters[++cvt->filter_index]) {
590 /* flip endian flag for data. */
592 format &= ~SDL_AUDIO_MASK_ENDIAN;
593 } else {
595 }
596 cvt->filters[cvt->filter_index](cvt, format);
597 }
598}
599
600static int
602{
604 return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS);
605 }
606 if (filter == NULL) {
607 return SDL_SetError("Audio filter pointer is NULL");
608 }
609 cvt->filters[cvt->filter_index++] = filter;
610 cvt->filters[cvt->filter_index] = NULL; /* Moving terminator */
611 return 0;
612}
613
614static int
616{
617 int retval = 0; /* 0 == no conversion necessary. */
618
619 if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
621 return -1;
622 }
623 retval = 1; /* added a converter. */
624 }
625
626 if (!SDL_AUDIO_ISFLOAT(src_fmt)) {
627 const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
628 const Uint16 dst_bitsize = 32;
630
631 switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
637 default: SDL_assert(!"Unexpected audio format!"); break;
638 }
639
640 if (!filter) {
641 return SDL_SetError("No conversion from source format to float available");
642 }
643
644 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
645 return -1;
646 }
647 if (src_bitsize < dst_bitsize) {
648 const int mult = (dst_bitsize / src_bitsize);
649 cvt->len_mult *= mult;
650 cvt->len_ratio *= mult;
651 } else if (src_bitsize > dst_bitsize) {
652 cvt->len_ratio /= (src_bitsize / dst_bitsize);
653 }
654
655 retval = 1; /* added a converter. */
656 }
657
658 return retval;
659}
660
661static int
663{
664 int retval = 0; /* 0 == no conversion necessary. */
665
666 if (!SDL_AUDIO_ISFLOAT(dst_fmt)) {
667 const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
668 const Uint16 src_bitsize = 32;
670 switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
676 default: SDL_assert(!"Unexpected audio format!"); break;
677 }
678
679 if (!filter) {
680 return SDL_SetError("No conversion from float to destination format available");
681 }
682
683 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
684 return -1;
685 }
686 if (src_bitsize < dst_bitsize) {
687 const int mult = (dst_bitsize / src_bitsize);
688 cvt->len_mult *= mult;
689 cvt->len_ratio *= mult;
690 } else if (src_bitsize > dst_bitsize) {
691 cvt->len_ratio /= (src_bitsize / dst_bitsize);
692 }
693 retval = 1; /* added a converter. */
694 }
695
696 if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
698 return -1;
699 }
700 retval = 1; /* added a converter. */
701 }
702
703 return retval;
704}
705
706static void
708{
709 /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
710 !!! FIXME in 2.1: We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
711 !!! FIXME in 2.1: so we steal the ninth and tenth slot. :( */
712 const int inrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1];
713 const int outrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS];
714 const float *src = (const float *) cvt->buf;
715 const int srclen = cvt->len_cvt;
716 /*float *dst = (float *) cvt->buf;
717 const int dstlen = (cvt->len * cvt->len_mult);*/
718 /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
719 float *dst = (float *) (cvt->buf + srclen);
720 const int dstlen = (cvt->len * cvt->len_mult) - srclen;
721 const int requestedpadding = ResamplerPadding(inrate, outrate);
722 int paddingsamples;
723 float *padding;
724
725 if (requestedpadding < SDL_MAX_SINT32 / chans) {
726 paddingsamples = requestedpadding * chans;
727 } else {
728 paddingsamples = 0;
729 }
731
732 /* we keep no streaming state here, so pad with silence on both ends. */
733 padding = (float *) SDL_calloc(paddingsamples ? paddingsamples : 1, sizeof (float));
734 if (!padding) {
736 return;
737 }
738
739 cvt->len_cvt = SDL_ResampleAudio(chans, inrate, outrate, padding, padding, src, srclen, dst, dstlen);
740
741 SDL_free(padding);
742
743 SDL_memmove(cvt->buf, dst, cvt->len_cvt); /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
744
745 if (cvt->filters[++cvt->filter_index]) {
746 cvt->filters[cvt->filter_index](cvt, format);
747 }
748}
749
750/* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
751 !!! FIXME: store channel info, so we have to have function entry
752 !!! FIXME: points for each supported channel count and multiple
753 !!! FIXME: vs arbitrary. When we rev the ABI, clean this up. */
754#define RESAMPLER_FUNCS(chans) \
755 static void SDLCALL \
756 SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
757 SDL_ResampleCVT(cvt, chans, format); \
758 }
764#undef RESAMPLER_FUNCS
765
766static SDL_AudioFilter
767ChooseCVTResampler(const int dst_channels)
768{
769 switch (dst_channels) {
770 case 1: return SDL_ResampleCVT_c1;
771 case 2: return SDL_ResampleCVT_c2;
772 case 4: return SDL_ResampleCVT_c4;
773 case 6: return SDL_ResampleCVT_c6;
774 case 8: return SDL_ResampleCVT_c8;
775 default: break;
776 }
777
778 return NULL;
779}
780
781static int
782SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
783 const int src_rate, const int dst_rate)
784{
786
787 if (src_rate == dst_rate) {
788 return 0; /* no conversion necessary. */
789 }
790
791 filter = ChooseCVTResampler(dst_channels);
792 if (filter == NULL) {
793 return SDL_SetError("No conversion available for these rates");
794 }
795
796 if (SDL_PrepareResampleFilter() < 0) {
797 return -1;
798 }
799
800 /* Update (cvt) with filter details... */
801 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
802 return -1;
803 }
804
805 /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
806 !!! FIXME in 2.1: We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
807 !!! FIXME in 2.1: so we steal the ninth and tenth slot. :( */
808 if (cvt->filter_index >= (SDL_AUDIOCVT_MAX_FILTERS-2)) {
809 return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS-2);
810 }
811 cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1] = (SDL_AudioFilter) (size_t) src_rate;
812 cvt->filters[SDL_AUDIOCVT_MAX_FILTERS] = (SDL_AudioFilter) (size_t) dst_rate;
813
814 if (src_rate < dst_rate) {
815 const double mult = ((double) dst_rate) / ((double) src_rate);
816 cvt->len_mult *= (int) SDL_ceil(mult);
817 cvt->len_ratio *= mult;
818 } else {
819 cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
820 }
821
822 /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
823 /* the buffer is big enough to hold the destination now, but
824 we need it large enough to hold a separate scratch buffer. */
825 cvt->len_mult *= 2;
826
827 return 1; /* added a converter. */
828}
829
830static SDL_bool
832{
833 switch (fmt) {
834 case AUDIO_U8:
835 case AUDIO_S8:
836 case AUDIO_U16LSB:
837 case AUDIO_S16LSB:
838 case AUDIO_U16MSB:
839 case AUDIO_S16MSB:
840 case AUDIO_S32LSB:
841 case AUDIO_S32MSB:
842 case AUDIO_F32LSB:
843 case AUDIO_F32MSB:
844 return SDL_TRUE; /* supported. */
845
846 default:
847 break;
848 }
849
850 return SDL_FALSE; /* unsupported. */
851}
852
853static SDL_bool
854SDL_SupportedChannelCount(const int channels)
855{
856 switch (channels) {
857 case 1: /* mono */
858 case 2: /* stereo */
859 case 4: /* quad */
860 case 6: /* 5.1 */
861 case 8: /* 7.1 */
862 return SDL_TRUE; /* supported. */
863
864 default:
865 break;
866 }
867
868 return SDL_FALSE; /* unsupported. */
869}
870
871
872/* Creates a set of audio filters to convert from one format to another.
873 Returns 0 if no conversion is needed, 1 if the audio filter is set up,
874 or -1 if an error like invalid parameter, unsupported format, etc. occurred.
875*/
876
877int
879 SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
880 SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
881{
882 /* Sanity check target pointer */
883 if (cvt == NULL) {
884 return SDL_InvalidParamError("cvt");
885 }
886
887 /* Make sure we zero out the audio conversion before error checking */
888 SDL_zerop(cvt);
889
890 if (!SDL_SupportedAudioFormat(src_fmt)) {
891 return SDL_SetError("Invalid source format");
892 } else if (!SDL_SupportedAudioFormat(dst_fmt)) {
893 return SDL_SetError("Invalid destination format");
894 } else if (!SDL_SupportedChannelCount(src_channels)) {
895 return SDL_SetError("Invalid source channels");
896 } else if (!SDL_SupportedChannelCount(dst_channels)) {
897 return SDL_SetError("Invalid destination channels");
898 } else if (src_rate <= 0) {
899 return SDL_SetError("Source rate is equal to or less than zero");
900 } else if (dst_rate <= 0) {
901 return SDL_SetError("Destination rate is equal to or less than zero");
902 } else if (src_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) {
903 return SDL_SetError("Source rate is too high");
904 } else if (dst_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) {
905 return SDL_SetError("Destination rate is too high");
906 }
907
908#if DEBUG_CONVERT
909 printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
910 src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
911#endif
912
913 /* Start off with no conversion necessary */
914 cvt->src_format = src_fmt;
915 cvt->dst_format = dst_fmt;
916 cvt->needed = 0;
917 cvt->filter_index = 0;
918 SDL_zero(cvt->filters);
919 cvt->len_mult = 1;
920 cvt->len_ratio = 1.0;
921 cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
922
923 /* Make sure we've chosen audio conversion functions (MMX, scalar, etc.) */
925
926 /* Type conversion goes like this now:
927 - byteswap to CPU native format first if necessary.
928 - convert to native Float32 if necessary.
929 - resample and change channel count if necessary.
930 - convert back to native format.
931 - byteswap back to foreign format if necessary.
932
933 The expectation is we can process data faster in float32
934 (possibly with SIMD), and making several passes over the same
935 buffer is likely to be CPU cache-friendly, avoiding the
936 biggest performance hit in modern times. Previously we had
937 (script-generated) custom converters for every data type and
938 it was a bloat on SDL compile times and final library size. */
939
940 /* see if we can skip float conversion entirely. */
941 if (src_rate == dst_rate && src_channels == dst_channels) {
942 if (src_fmt == dst_fmt) {
943 return 0;
944 }
945
946 /* just a byteswap needed? */
947 if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
949 return -1;
950 }
951 cvt->needed = 1;
952 return 1;
953 }
954 }
955
956 /* Convert data types, if necessary. Updates (cvt). */
957 if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) {
958 return -1; /* shouldn't happen, but just in case... */
959 }
960
961 /* Channel conversion */
962 if (src_channels < dst_channels) {
963 /* Upmixing */
964 /* Mono -> Stereo [-> ...] */
965 if ((src_channels == 1) && (dst_channels > 1)) {
967 return -1;
968 }
969 cvt->len_mult *= 2;
970 src_channels = 2;
971 cvt->len_ratio *= 2;
972 }
973 /* [Mono ->] Stereo -> 5.1 [-> 7.1] */
974 if ((src_channels == 2) && (dst_channels >= 6)) {
976 return -1;
977 }
978 src_channels = 6;
979 cvt->len_mult *= 3;
980 cvt->len_ratio *= 3;
981 }
982 /* Quad -> 5.1 [-> 7.1] */
983 if ((src_channels == 4) && (dst_channels >= 6)) {
985 return -1;
986 }
987 src_channels = 6;
988 cvt->len_mult = (cvt->len_mult * 3 + 1) / 2;
989 cvt->len_ratio *= 1.5;
990 }
991 /* [[Mono ->] Stereo ->] 5.1 -> 7.1 */
992 if ((src_channels == 6) && (dst_channels == 8)) {
994 return -1;
995 }
996 src_channels = 8;
997 cvt->len_mult = (cvt->len_mult * 4 + 2) / 3;
998 /* Should be numerically exact with every valid input to this
999 function */
1000 cvt->len_ratio = cvt->len_ratio * 4 / 3;
1001 }
1002 /* [Mono ->] Stereo -> Quad */
1003 if ((src_channels == 2) && (dst_channels == 4)) {
1005 return -1;
1006 }
1007 src_channels = 4;
1008 cvt->len_mult *= 2;
1009 cvt->len_ratio *= 2;
1010 }
1011 } else if (src_channels > dst_channels) {
1012 /* Downmixing */
1013 /* 7.1 -> 5.1 [-> Stereo [-> Mono]] */
1014 /* 7.1 -> 5.1 [-> Quad] */
1015 if ((src_channels == 8) && (dst_channels <= 6)) {
1017 return -1;
1018 }
1019 src_channels = 6;
1020 cvt->len_ratio *= 0.75;
1021 }
1022 /* [7.1 ->] 5.1 -> Stereo [-> Mono] */
1023 if ((src_channels == 6) && (dst_channels <= 2)) {
1025 return -1;
1026 }
1027 src_channels = 2;
1028 cvt->len_ratio /= 3;
1029 }
1030 /* 5.1 -> Quad */
1031 if ((src_channels == 6) && (dst_channels == 4)) {
1033 return -1;
1034 }
1035 src_channels = 4;
1036 cvt->len_ratio = cvt->len_ratio * 2 / 3;
1037 }
1038 /* Quad -> Stereo [-> Mono] */
1039 if ((src_channels == 4) && (dst_channels <= 2)) {
1041 return -1;
1042 }
1043 src_channels = 2;
1044 cvt->len_ratio /= 2;
1045 }
1046 /* [... ->] Stereo -> Mono */
1047 if ((src_channels == 2) && (dst_channels == 1)) {
1049
1050 #if HAVE_SSE3_INTRINSICS
1051 if (SDL_HasSSE3()) {
1052 filter = SDL_ConvertStereoToMono_SSE3;
1053 }
1054 #endif
1055
1056 if (!filter) {
1058 }
1059
1060 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
1061 return -1;
1062 }
1063
1064 src_channels = 1;
1065 cvt->len_ratio /= 2;
1066 }
1067 }
1068
1069 if (src_channels != dst_channels) {
1070 /* All combinations of supported channel counts should have been
1071 handled by now, but let's be defensive */
1072 return SDL_SetError("Invalid channel combination");
1073 }
1074
1075 /* Do rate conversion, if necessary. Updates (cvt). */
1076 if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
1077 return -1; /* shouldn't happen, but just in case... */
1078 }
1079
1080 /* Move to final data type. */
1081 if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) {
1082 return -1; /* shouldn't happen, but just in case... */
1083 }
1084
1085 cvt->needed = (cvt->filter_index != 0);
1086 return (cvt->needed);
1087}
1088
1089typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen);
1090typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream);
1092
1094{
1102 Uint8 *work_buffer_base; /* maybe unaligned pointer from SDL_realloc(). */
1121};
1122
1123static Uint8 *
1124EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
1125{
1126 Uint8 *ptr;
1127 size_t offset;
1128
1129 if (stream->work_buffer_len >= newlen) {
1130 ptr = stream->work_buffer_base;
1131 } else {
1132 ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32);
1133 if (!ptr) {
1135 return NULL;
1136 }
1137 /* Make sure we're aligned to 16 bytes for SIMD code. */
1138 stream->work_buffer_base = ptr;
1139 stream->work_buffer_len = newlen;
1140 }
1141
1142 offset = ((size_t) ptr) & 15;
1143 return offset ? ptr + (16 - offset) : ptr;
1144}
1145
1146#ifdef HAVE_LIBSAMPLERATE_H
1147static int
1148SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
1149{
1150 const float *inbuf = (const float *) _inbuf;
1151 float *outbuf = (float *) _outbuf;
1152 const int framelen = sizeof(float) * stream->pre_resample_channels;
1153 SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
1154 SRC_DATA data;
1155 int result;
1156
1157 SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */
1158
1159 data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
1160 data.input_frames = inbuflen / framelen;
1161 data.input_frames_used = 0;
1162
1163 data.data_out = outbuf;
1164 data.output_frames = outbuflen / framelen;
1165
1166 data.end_of_input = 0;
1167 data.src_ratio = stream->rate_incr;
1168
1169 result = SRC_src_process(state, &data);
1170 if (result != 0) {
1171 SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
1172 return 0;
1173 }
1174
1175 /* If this fails, we need to store them off somewhere */
1176 SDL_assert(data.input_frames_used == data.input_frames);
1177
1178 return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels);
1179}
1180
1181static void
1182SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
1183{
1184 SRC_src_reset((SRC_STATE *)stream->resampler_state);
1185}
1186
1187static void
1188SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
1189{
1190 SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
1191 if (state) {
1192 SRC_src_delete(state);
1193 }
1194
1195 stream->resampler_state = NULL;
1196 stream->resampler_func = NULL;
1197 stream->reset_resampler_func = NULL;
1198 stream->cleanup_resampler_func = NULL;
1199}
1200
1201static SDL_bool
1202SetupLibSampleRateResampling(SDL_AudioStream *stream)
1203{
1204 int result = 0;
1205 SRC_STATE *state = NULL;
1206
1207 if (SRC_available) {
1208 state = SRC_src_new(SRC_converter, stream->pre_resample_channels, &result);
1209 if (!state) {
1210 SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
1211 }
1212 }
1213
1214 if (!state) {
1215 SDL_CleanupAudioStreamResampler_SRC(stream);
1216 return SDL_FALSE;
1217 }
1218
1219 stream->resampler_state = state;
1220 stream->resampler_func = SDL_ResampleAudioStream_SRC;
1221 stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
1222 stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
1223
1224 return SDL_TRUE;
1225}
1226#endif /* HAVE_LIBSAMPLERATE_H */
1227
1228
1229static int
1230SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
1231{
1232 const Uint8 *inbufend = ((const Uint8 *) _inbuf) + inbuflen;
1233 const float *inbuf = (const float *) _inbuf;
1234 float *outbuf = (float *) _outbuf;
1235 const int chans = (int) stream->pre_resample_channels;
1236 const int inrate = stream->src_rate;
1237 const int outrate = stream->dst_rate;
1238 const int paddingsamples = stream->resampler_padding_samples;
1239 const int paddingbytes = paddingsamples * sizeof (float);
1240 float *lpadding = (float *) stream->resampler_state;
1241 const float *rpadding = (const float *) inbufend; /* we set this up so there are valid padding samples at the end of the input buffer. */
1242 const int cpy = SDL_min(inbuflen, paddingbytes);
1243 int retval;
1244
1245 SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */
1246
1247 retval = SDL_ResampleAudio(chans, inrate, outrate, lpadding, rpadding, inbuf, inbuflen, outbuf, outbuflen);
1248
1249 /* update our left padding with end of current input, for next run. */
1250 SDL_memcpy((lpadding + paddingsamples) - (cpy / sizeof (float)), inbufend - cpy, cpy);
1251 return retval;
1252}
1253
1254static void
1256{
1257 /* set all the padding to silence. */
1258 const int len = stream->resampler_padding_samples;
1259 SDL_memset(stream->resampler_state, '\0', len * sizeof (float));
1260}
1261
1262static void
1264{
1265 SDL_free(stream->resampler_state);
1266}
1267
1268SDL_AudioStream *
1270 const Uint8 src_channels,
1271 const int src_rate,
1272 const SDL_AudioFormat dst_format,
1273 const Uint8 dst_channels,
1274 const int dst_rate)
1275{
1276 const int packetlen = 4096; /* !!! FIXME: good enough for now. */
1277 Uint8 pre_resample_channels;
1278 SDL_AudioStream *retval;
1279
1280 retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
1281 if (!retval) {
1282 return NULL;
1283 }
1284
1285 /* If increasing channels, do it after resampling, since we'd just
1286 do more work to resample duplicate channels. If we're decreasing, do
1287 it first so we resample the interpolated data instead of interpolating
1288 the resampled data (!!! FIXME: decide if that works in practice, though!). */
1289 pre_resample_channels = SDL_min(src_channels, dst_channels);
1290
1291 retval->first_run = SDL_TRUE;
1292 retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels;
1293 retval->src_format = src_format;
1294 retval->src_channels = src_channels;
1295 retval->src_rate = src_rate;
1296 retval->dst_sample_frame_size = (SDL_AUDIO_BITSIZE(dst_format) / 8) * dst_channels;
1297 retval->dst_format = dst_format;
1298 retval->dst_channels = dst_channels;
1299 retval->dst_rate = dst_rate;
1300 retval->pre_resample_channels = pre_resample_channels;
1301 retval->packetlen = packetlen;
1302 retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
1303 retval->resampler_padding_samples = ResamplerPadding(retval->src_rate, retval->dst_rate) * pre_resample_channels;
1304 retval->resampler_padding = (float *) SDL_calloc(retval->resampler_padding_samples ? retval->resampler_padding_samples : 1, sizeof (float));
1305
1306 if (retval->resampler_padding == NULL) {
1309 return NULL;
1310 }
1311
1312 retval->staging_buffer_size = ((retval->resampler_padding_samples / retval->pre_resample_channels) * retval->src_sample_frame_size);
1313 if (retval->staging_buffer_size > 0) {
1314 retval->staging_buffer = (Uint8 *) SDL_malloc(retval->staging_buffer_size);
1315 if (retval->staging_buffer == NULL) {
1318 return NULL;
1319 }
1320 }
1321
1322 /* Not resampling? It's an easy conversion (and maybe not even that!) */
1323 if (src_rate == dst_rate) {
1324 retval->cvt_before_resampling.needed = SDL_FALSE;
1325 if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
1327 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
1328 }
1329 } else {
1330 /* Don't resample at first. Just get us to Float32 format. */
1331 /* !!! FIXME: convert to int32 on devices without hardware float. */
1332 if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
1334 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
1335 }
1336
1337#ifdef HAVE_LIBSAMPLERATE_H
1338 SetupLibSampleRateResampling(retval);
1339#endif
1340
1341 if (!retval->resampler_func) {
1342 retval->resampler_state = SDL_calloc(retval->resampler_padding_samples, sizeof (float));
1343 if (!retval->resampler_state) {
1346 return NULL;
1347 }
1348
1349 if (SDL_PrepareResampleFilter() < 0) {
1350 SDL_free(retval->resampler_state);
1351 retval->resampler_state = NULL;
1353 return NULL;
1354 }
1355
1356 retval->resampler_func = SDL_ResampleAudioStream;
1357 retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
1358 retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
1359 }
1360
1361 /* Convert us to the final format after resampling. */
1362 if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
1364 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
1365 }
1366 }
1367
1368 retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
1369 if (!retval->queue) {
1371 return NULL; /* SDL_NewDataQueue should have called SDL_SetError. */
1372 }
1373
1374 return retval;
1375}
1376
1377static int
1378SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len, int *maxputbytes)
1379{
1380 int buflen = len;
1381 int workbuflen;
1382 Uint8 *workbuf;
1383 Uint8 *resamplebuf = NULL;
1384 int resamplebuflen = 0;
1385 int neededpaddingbytes;
1386 int paddingbytes;
1387
1388 /* !!! FIXME: several converters can take advantage of SIMD, but only
1389 !!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
1390 !!! FIXME: guarantees the buffer will align, but the
1391 !!! FIXME: converters will iterate over the data backwards if
1392 !!! FIXME: the output grows, and this means we won't align if buflen
1393 !!! FIXME: isn't a multiple of 16. In these cases, we should chop off
1394 !!! FIXME: a few samples at the end and convert them separately. */
1395
1396 /* no padding prepended on first run. */
1397 neededpaddingbytes = stream->resampler_padding_samples * sizeof (float);
1398 paddingbytes = stream->first_run ? 0 : neededpaddingbytes;
1399 stream->first_run = SDL_FALSE;
1400
1401 /* Make sure the work buffer can hold all the data we need at once... */
1402 workbuflen = buflen;
1403 if (stream->cvt_before_resampling.needed) {
1404 workbuflen *= stream->cvt_before_resampling.len_mult;
1405 }
1406
1407 if (stream->dst_rate != stream->src_rate) {
1408 /* resamples can't happen in place, so make space for second buf. */
1409 const int framesize = stream->pre_resample_channels * sizeof (float);
1410 const int frames = workbuflen / framesize;
1411 resamplebuflen = ((int) SDL_ceil(frames * stream->rate_incr)) * framesize;
1412 #if DEBUG_AUDIOSTREAM
1413 printf("AUDIOSTREAM: will resample %d bytes to %d (ratio=%.6f)\n", workbuflen, resamplebuflen, stream->rate_incr);
1414 #endif
1415 workbuflen += resamplebuflen;
1416 }
1417
1418 if (stream->cvt_after_resampling.needed) {
1419 /* !!! FIXME: buffer might be big enough already? */
1420 workbuflen *= stream->cvt_after_resampling.len_mult;
1421 }
1422
1423 workbuflen += neededpaddingbytes;
1424
1425 #if DEBUG_AUDIOSTREAM
1426 printf("AUDIOSTREAM: Putting %d bytes of preconverted audio, need %d byte work buffer\n", buflen, workbuflen);
1427 #endif
1428
1429 workbuf = EnsureStreamBufferSize(stream, workbuflen);
1430 if (!workbuf) {
1431 return -1; /* probably out of memory. */
1432 }
1433
1434 resamplebuf = workbuf; /* default if not resampling. */
1435
1436 SDL_memcpy(workbuf + paddingbytes, buf, buflen);
1437
1438 if (stream->cvt_before_resampling.needed) {
1439 stream->cvt_before_resampling.buf = workbuf + paddingbytes;
1440 stream->cvt_before_resampling.len = buflen;
1441 if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
1442 return -1; /* uhoh! */
1443 }
1444 buflen = stream->cvt_before_resampling.len_cvt;
1445
1446 #if DEBUG_AUDIOSTREAM
1447 printf("AUDIOSTREAM: After initial conversion we have %d bytes\n", buflen);
1448 #endif
1449 }
1450
1451 if (stream->dst_rate != stream->src_rate) {
1452 /* save off some samples at the end; they are used for padding now so
1453 the resampler is coherent and then used at the start of the next
1454 put operation. Prepend last put operation's padding, too. */
1455
1456 /* prepend prior put's padding. :P */
1457 if (paddingbytes) {
1458 SDL_memcpy(workbuf, stream->resampler_padding, paddingbytes);
1459 buflen += paddingbytes;
1460 }
1461
1462 /* save off the data at the end for the next run. */
1463 SDL_memcpy(stream->resampler_padding, workbuf + (buflen - neededpaddingbytes), neededpaddingbytes);
1464
1465 resamplebuf = workbuf + buflen; /* skip to second piece of workbuf. */
1466 SDL_assert(buflen >= neededpaddingbytes);
1467 if (buflen > neededpaddingbytes) {
1468 buflen = stream->resampler_func(stream, workbuf, buflen - neededpaddingbytes, resamplebuf, resamplebuflen);
1469 } else {
1470 buflen = 0;
1471 }
1472
1473 #if DEBUG_AUDIOSTREAM
1474 printf("AUDIOSTREAM: After resampling we have %d bytes\n", buflen);
1475 #endif
1476 }
1477
1478 if (stream->cvt_after_resampling.needed && (buflen > 0)) {
1479 stream->cvt_after_resampling.buf = resamplebuf;
1480 stream->cvt_after_resampling.len = buflen;
1481 if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
1482 return -1; /* uhoh! */
1483 }
1484 buflen = stream->cvt_after_resampling.len_cvt;
1485
1486 #if DEBUG_AUDIOSTREAM
1487 printf("AUDIOSTREAM: After final conversion we have %d bytes\n", buflen);
1488 #endif
1489 }
1490
1491 #if DEBUG_AUDIOSTREAM
1492 printf("AUDIOSTREAM: Final output is %d bytes\n", buflen);
1493 #endif
1494
1495 if (maxputbytes) {
1496 const int maxbytes = *maxputbytes;
1497 if (buflen > maxbytes)
1498 buflen = maxbytes;
1499 *maxputbytes -= buflen;
1500 }
1501
1502 /* resamplebuf holds the final output, even if we didn't resample. */
1503 return buflen ? SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen) : 0;
1504}
1505
1506int
1507SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
1508{
1509 /* !!! FIXME: several converters can take advantage of SIMD, but only
1510 !!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
1511 !!! FIXME: guarantees the buffer will align, but the
1512 !!! FIXME: converters will iterate over the data backwards if
1513 !!! FIXME: the output grows, and this means we won't align if buflen
1514 !!! FIXME: isn't a multiple of 16. In these cases, we should chop off
1515 !!! FIXME: a few samples at the end and convert them separately. */
1516
1517 #if DEBUG_AUDIOSTREAM
1518 printf("AUDIOSTREAM: wants to put %d preconverted bytes\n", buflen);
1519 #endif
1520
1521 if (!stream) {
1522 return SDL_InvalidParamError("stream");
1523 } else if (!buf) {
1524 return SDL_InvalidParamError("buf");
1525 } else if (len == 0) {
1526 return 0; /* nothing to do. */
1527 } else if ((len % stream->src_sample_frame_size) != 0) {
1528 return SDL_SetError("Can't add partial sample frames");
1529 }
1530
1531 if (!stream->cvt_before_resampling.needed &&
1532 (stream->dst_rate == stream->src_rate) &&
1533 !stream->cvt_after_resampling.needed) {
1534 #if DEBUG_AUDIOSTREAM
1535 printf("AUDIOSTREAM: no conversion needed at all, queueing %d bytes.\n", len);
1536 #endif
1537 return SDL_WriteToDataQueue(stream->queue, buf, len);
1538 }
1539
1540 while (len > 0) {
1541 int amount;
1542
1543 /* If we don't have a staging buffer or we're given enough data that
1544 we don't need to store it for later, skip the staging process.
1545 */
1546 if (!stream->staging_buffer_filled && len >= stream->staging_buffer_size) {
1548 }
1549
1550 /* If there's not enough data to fill the staging buffer, just save it */
1551 if ((stream->staging_buffer_filled + len) < stream->staging_buffer_size) {
1552 SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, len);
1553 stream->staging_buffer_filled += len;
1554 return 0;
1555 }
1556
1557 /* Fill the staging buffer, process it, and continue */
1558 amount = (stream->staging_buffer_size - stream->staging_buffer_filled);
1559 SDL_assert(amount > 0);
1560 SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, amount);
1561 stream->staging_buffer_filled = 0;
1562 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, NULL) < 0) {
1563 return -1;
1564 }
1565 buf = (void *)((Uint8 *)buf + amount);
1566 len -= amount;
1567 }
1568 return 0;
1569}
1570
1571int SDL_AudioStreamFlush(SDL_AudioStream *stream)
1572{
1573 if (!stream) {
1574 return SDL_InvalidParamError("stream");
1575 }
1576
1577 #if DEBUG_AUDIOSTREAM
1578 printf("AUDIOSTREAM: flushing! staging_buffer_filled=%d bytes\n", stream->staging_buffer_filled);
1579 #endif
1580
1581 /* shouldn't use a staging buffer if we're not resampling. */
1582 SDL_assert((stream->dst_rate != stream->src_rate) || (stream->staging_buffer_filled == 0));
1583
1584 if (stream->staging_buffer_filled > 0) {
1585 /* push the staging buffer + silence. We need to flush out not just
1586 the staging buffer, but the piece that the stream was saving off
1587 for right-side resampler padding. */
1588 const SDL_bool first_run = stream->first_run;
1589 const int filled = stream->staging_buffer_filled;
1590 int actual_input_frames = filled / stream->src_sample_frame_size;
1591 if (!first_run)
1592 actual_input_frames += stream->resampler_padding_samples / stream->pre_resample_channels;
1593
1594 if (actual_input_frames > 0) { /* don't bother if nothing to flush. */
1595 /* This is how many bytes we're expecting without silence appended. */
1596 int flush_remaining = ((int) SDL_ceil(actual_input_frames * stream->rate_incr)) * stream->dst_sample_frame_size;
1597
1599 printf("AUDIOSTREAM: flushing with padding to get max %d bytes!\n", flush_remaining);
1600 #endif
1601
1602 SDL_memset(stream->staging_buffer + filled, '\0', stream->staging_buffer_size - filled);
1603 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
1604 return -1;
1605 }
1606
1607 /* we have flushed out (or initially filled) the pending right-side
1608 resampler padding, but we need to push more silence to guarantee
1609 the staging buffer is fully flushed out, too. */
1610 SDL_memset(stream->staging_buffer, '\0', filled);
1611 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
1612 return -1;
1613 }
1614 }
1615 }
1616
1617 stream->staging_buffer_filled = 0;
1618 stream->first_run = SDL_TRUE;
1619
1620 return 0;
1621}
1622
1623/* get converted/resampled data from the stream */
1624int
1625SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len)
1626{
1627 #if DEBUG_AUDIOSTREAM
1628 printf("AUDIOSTREAM: want to get %d converted bytes\n", len);
1629 #endif
1630
1631 if (!stream) {
1632 return SDL_InvalidParamError("stream");
1633 } else if (!buf) {
1634 return SDL_InvalidParamError("buf");
1635 } else if (len <= 0) {
1636 return 0; /* nothing to do. */
1637 } else if ((len % stream->dst_sample_frame_size) != 0) {
1638 return SDL_SetError("Can't request partial sample frames");
1639 }
1640
1641 return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
1642}
1643
1644/* number of converted/resampled bytes available */
1645int
1647{
1648 return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
1649}
1650
1651void
1653{
1654 if (!stream) {
1655 SDL_InvalidParamError("stream");
1656 } else {
1657 SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
1658 if (stream->reset_resampler_func) {
1659 stream->reset_resampler_func(stream);
1660 }
1661 stream->first_run = SDL_TRUE;
1662 stream->staging_buffer_filled = 0;
1663 }
1664}
1665
1666/* dispose of a stream */
1667void
1669{
1670 if (stream) {
1671 if (stream->cleanup_resampler_func) {
1672 stream->cleanup_resampler_func(stream);
1673 }
1674 SDL_FreeDataQueue(stream->queue);
1675 SDL_free(stream->staging_buffer);
1676 SDL_free(stream->work_buffer_base);
1677 SDL_free(stream->resampler_padding);
1679 }
1680}
1681
1682/* vi: set ts=4 sw=4 expandtab: */
1683
#define SDL_assert(condition)
Definition: SDL_assert.h:169
int SDL_SpinLock
Definition: SDL_atomic.h:89
#define AUDIO_U16LSB
Definition: SDL_audio.h:91
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
#define SDL_AUDIO_ISBIGENDIAN(x)
Definition: SDL_audio.h:77
#define AUDIO_F32MSB
Definition: SDL_audio.h:113
#define AUDIO_S32MSB
Definition: SDL_audio.h:104
#define AUDIO_S16MSB
Definition: SDL_audio.h:94
#define AUDIO_U16MSB
Definition: SDL_audio.h:93
#define SDL_AUDIOCVT_MAX_FILTERS
Upper limit of filters in SDL_AudioCVT.
Definition: SDL_audio.h:203
void(* SDL_AudioFilter)(struct SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audio.h:193
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
#define AUDIO_S16
Definition: SDL_audio.h:96
#define AUDIO_U8
Definition: SDL_audio.h:89
#define SDL_AUDIO_ISFLOAT(x)
Definition: SDL_audio.h:76
#define AUDIO_S8
Definition: SDL_audio.h:90
#define AUDIO_S32
Definition: SDL_audio.h:105
#define SDL_AUDIO_MASK_ENDIAN
Definition: SDL_audio.h:73
#define SDL_AUDIO_BITSIZE(x)
Definition: SDL_audio.h:75
#define AUDIO_S32LSB
Definition: SDL_audio.h:103
#define AUDIO_U16
Definition: SDL_audio.h:95
#define AUDIO_F32SYS
Definition: SDL_audio.h:125
#define AUDIO_F32LSB
Definition: SDL_audio.h:112
SDL_AudioFilter SDL_Convert_F32_to_U16
SDL_AudioFilter SDL_Convert_U16_to_F32
SDL_AudioFilter SDL_Convert_F32_to_S32
#define LOG_DEBUG_CONVERT(from, to)
Definition: SDL_audio_c.h:34
SDL_AudioFilter SDL_Convert_F32_to_S16
SDL_AudioFilter SDL_Convert_F32_to_U8
SDL_AudioFilter SDL_Convert_F32_to_S8
SDL_AudioFilter SDL_Convert_S8_to_F32
void SDL_ChooseAudioConverters(void)
SDL_AudioFilter SDL_Convert_S32_to_F32
SDL_AudioFilter SDL_Convert_S16_to_F32
SDL_AudioFilter SDL_Convert_U8_to_F32
#define CASESWAP(b)
int SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
static int SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
Definition: SDL_audiocvt.c:662
int SDL_BuildAudioCVT(SDL_AudioCVT *cvt, SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate, SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
Definition: SDL_audiocvt.c:878
static void SDL_Convert51To71(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:335
static void kaiser_and_sinc(float *table, float *diffs, const int tablelen, const double beta)
Definition: SDL_audiocvt.c:409
static int SDL_ResampleAudio(const int chans, const int inrate, const int outrate, const float *lpadding, const float *rpadding, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
Definition: SDL_audiocvt.c:485
void(* SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream)
#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING
Definition: SDL_audiocvt.c:382
SDL_AudioStream * SDL_NewAudioStream(const SDL_AudioFormat src_format, const Uint8 src_channels, const int src_rate, const SDL_AudioFormat dst_format, const Uint8 dst_channels, const int dst_rate)
static void SDL_Convert71To51(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:151
void SDL_AudioStreamClear(SDL_AudioStream *stream)
int SDL_PrepareResampleFilter(void)
Definition: SDL_audiocvt.c:435
static int SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len, int *maxputbytes)
#define RESAMPLER_FUNCS(chans)
Definition: SDL_audiocvt.c:754
static SDL_AudioFilter ChooseCVTResampler(const int dst_channels)
Definition: SDL_audiocvt.c:767
static SDL_bool SDL_SupportedAudioFormat(const SDL_AudioFormat fmt)
Definition: SDL_audiocvt.c:831
static int SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
#define DEBUG_AUDIOSTREAM
Definition: SDL_audiocvt.c:37
static int SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
Definition: SDL_audiocvt.c:615
int SDL_AudioStreamFlush(SDL_AudioStream *stream)
void SDL_FreeResampleFilter(void)
Definition: SDL_audiocvt.c:464
static void SDL_ConvertStereoToQuad(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:305
static SDL_bool SDL_SupportedChannelCount(const int channels)
Definition: SDL_audiocvt.c:854
static void SDL_Convert_Byteswap(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:563
void(* SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream)
static void SDL_Convert51ToQuad(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:181
static void SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
Definition: SDL_audiocvt.c:707
static void SDL_ConvertStereoTo51(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:234
static float * ResamplerFilterDifference
Definition: SDL_audiocvt.c:432
static void SDL_Convert51ToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:103
static int SDL_AddAudioCVTFilter(SDL_AudioCVT *cvt, const SDL_AudioFilter filter)
Definition: SDL_audiocvt.c:601
static void SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
static void SDL_ConvertStereoToMono(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:81
static double bessel(const double x)
Definition: SDL_audiocvt.c:387
static float * ResamplerFilter
Definition: SDL_audiocvt.c:431
static void SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
static int ResamplerPadding(const int inrate, const int outrate)
Definition: SDL_audiocvt.c:473
int(* SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen)
int SDL_ConvertAudio(SDL_AudioCVT *cvt)
Definition: SDL_audiocvt.c:540
static void SDL_ConvertQuadTo51(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:268
static int SDL_BuildAudioResampleCVT(SDL_AudioCVT *cvt, const int dst_channels, const int src_rate, const int dst_rate)
Definition: SDL_audiocvt.c:782
int SDL_AudioStreamAvailable(SDL_AudioStream *stream)
int SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len)
void SDL_FreeAudioStream(SDL_AudioStream *stream)
static void SDL_ConvertMonoToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:210
static Uint8 * EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
static void SDL_ConvertQuadToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:128
static SDL_SpinLock ResampleFilterSpinlock
Definition: SDL_audiocvt.c:430
#define RESAMPLER_FILTER_SIZE
Definition: SDL_audiocvt.c:383
#define SDL_BYTEORDER
unsigned int size_t
size_t SDL_CountDataQueue(SDL_DataQueue *queue)
void SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack)
Definition: SDL_dataqueue.c:98
int SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *_data, const size_t _len)
SDL_DataQueue * SDL_NewDataQueue(const size_t _packetlen, const size_t initialslack)
Definition: SDL_dataqueue.c:58
size_t SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
void SDL_FreeDataQueue(SDL_DataQueue *queue)
Definition: SDL_dataqueue.c:88
#define SDL_sqrt
#define SDL_SetError
#define SDL_memset
#define SDL_AtomicLock
#define SDL_malloc
#define SDL_realloc
#define SDL_AtomicUnlock
#define SDL_free
#define SDL_pow
#define SDL_sinf
#define SDL_memcpy
#define SDL_HasSSE3
#define SDL_memmove
#define SDL_calloc
#define SDL_ceil
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
#define SDL_LIL_ENDIAN
Definition: SDL_endian.h:37
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54
#define SDLCALL
Definition: SDL_internal.h:49
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
GLuint GLuint stream
GLfloat f
GLenum src
GLuint64EXT * result
GLintptr offset
GLenum GLsizei len
GLenum GLenum dst
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLsizei GLenum GLenum const void * table
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
#define SDL_MAX_SINT32
A signed 32-bit integer type.
Definition: SDL_stdinc.h:195
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
uint16_t Uint16
Definition: SDL_stdinc.h:191
uint8_t Uint8
Definition: SDL_stdinc.h:179
struct xkb_state * state
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:167
SDL_ResampleAudioStreamFunc resampler_func
SDL_DataQueue * queue
Uint8 * work_buffer_base
Uint8 pre_resample_channels
SDL_AudioCVT cvt_after_resampling
Uint8 * staging_buffer
float * resampler_padding
SDL_AudioFormat src_format
SDL_ResetAudioStreamResamplerFunc reset_resampler_func
SDL_AudioFormat dst_format
SDL_AudioCVT cvt_before_resampling
SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func
A structure to hold a set of audio conversion filters and buffers.
Definition: SDL_audio.h:227
Uint8 * buf
Definition: SDL_audio.h:232
int filter_index
Definition: SDL_audio.h:238
double len_ratio
Definition: SDL_audio.h:236
SDL_AudioFormat src_format
Definition: SDL_audio.h:229
SDL_AudioFormat dst_format
Definition: SDL_audio.h:230
double rate_incr
Definition: SDL_audio.h:231
SDL_AudioFilter filters[SDL_AUDIOCVT_MAX_FILTERS+1]
Definition: SDL_audio.h:237
SDL_bool retval
static Uint32 frames
Definition: testsprite2.c:40