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