Atlas - SDL_audiocvt.c
Home / ext / SDL2 / src / audio Lines: 14 | Size: 58249 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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)"); 53 SDL_assert(format == AUDIO_F32SYS); 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 81SDL_ConvertStereoToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format) 82{ 83 float *dst = (float *) cvt->buf; 84 const float *src = dst; 85 int i; 86 87 LOG_DEBUG_CONVERT("stereo", "mono"); 88 SDL_assert(format == AUDIO_F32SYS); 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 103SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format) 104{ 105 float *dst = (float *) cvt->buf; 106 const float *src = dst; 107 int i; 108 109 LOG_DEBUG_CONVERT("5.1", "stereo"); 110 SDL_assert(format == AUDIO_F32SYS); 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 128SDL_ConvertQuadToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format) 129{ 130 float *dst = (float *) cvt->buf; 131 const float *src = dst; 132 int i; 133 134 LOG_DEBUG_CONVERT("quad", "stereo"); 135 SDL_assert(format == AUDIO_F32SYS); 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 151SDL_Convert71To51(SDL_AudioCVT * cvt, SDL_AudioFormat format) 152{ 153 float *dst = (float *) cvt->buf; 154 const float *src = dst; 155 int i; 156 157 LOG_DEBUG_CONVERT("7.1", "5.1"); 158 SDL_assert(format == AUDIO_F32SYS); 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 181SDL_Convert51ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format) 182{ 183 float *dst = (float *) cvt->buf; 184 const float *src = dst; 185 int i; 186 187 LOG_DEBUG_CONVERT("5.1", "quad"); 188 SDL_assert(format == AUDIO_F32SYS); 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 210SDL_ConvertMonoToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format) 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"); 217 SDL_assert(format == AUDIO_F32SYS); 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 234SDL_ConvertStereoTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format) 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"); 242 SDL_assert(format == AUDIO_F32SYS); 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 268SDL_ConvertQuadTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format) 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"); 276 SDL_assert(format == AUDIO_F32SYS); 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 305SDL_ConvertStereoToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format) 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"); 313 SDL_assert(format == AUDIO_F32SYS); 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 335SDL_Convert51To71(SDL_AudioCVT * cvt, SDL_AudioFormat format) 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"); 343 SDL_assert(format == AUDIO_F32SYS); 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 430static SDL_SpinLock ResampleFilterSpinlock = 0; 431static float *ResamplerFilter = NULL; 432static float *ResamplerFilterDifference = NULL; 433 434int 435SDL_PrepareResampleFilter(void) 436{ 437 SDL_AtomicLock(&ResampleFilterSpinlock); 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) { 446 SDL_AtomicUnlock(&ResampleFilterSpinlock); 447 return SDL_OutOfMemory(); 448 } 449 450 ResamplerFilterDifference = (float *) SDL_malloc(alloclen); 451 if (!ResamplerFilterDifference) { 452 SDL_free(ResamplerFilter); 453 ResamplerFilter = NULL; 454 SDL_AtomicUnlock(&ResampleFilterSpinlock); 455 return SDL_OutOfMemory(); 456 } 457 kaiser_and_sinc(ResamplerFilter, ResamplerFilterDifference, RESAMPLER_FILTER_SIZE, beta); 458 } 459 SDL_AtomicUnlock(&ResampleFilterSpinlock); 460 return 0; 461} 462 463void 464SDL_FreeResampleFilter(void) 465{ 466 SDL_free(ResamplerFilter); 467 SDL_free(ResamplerFilterDifference); 468 ResamplerFilter = NULL; 469 ResamplerFilterDifference = NULL; 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 } 480 return RESAMPLER_SAMPLES_PER_ZERO_CROSSING; 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 540SDL_ConvertAudio(SDL_AudioCVT * cvt) 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 563SDL_Convert_Byteswap(SDL_AudioCVT *cvt, SDL_AudioFormat format) 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. */ 591 if (format & SDL_AUDIO_MASK_ENDIAN) { 592 format &= ~SDL_AUDIO_MASK_ENDIAN; 593 } else { 594 format |= SDL_AUDIO_MASK_ENDIAN; 595 } 596 cvt->filters[cvt->filter_index](cvt, format); 597 } 598} 599 600static int 601SDL_AddAudioCVTFilter(SDL_AudioCVT *cvt, const SDL_AudioFilter filter) 602{ 603 if (cvt->filter_index >= SDL_AUDIOCVT_MAX_FILTERS) { 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 615SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt) 616{ 617 int retval = 0; /* 0 == no conversion necessary. */ 618 619 if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) { 620 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) { 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; 629 SDL_AudioFilter filter = NULL; 630 631 switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) { 632 case AUDIO_S8: filter = SDL_Convert_S8_to_F32; break; 633 case AUDIO_U8: filter = SDL_Convert_U8_to_F32; break; 634 case AUDIO_S16: filter = SDL_Convert_S16_to_F32; break; 635 case AUDIO_U16: filter = SDL_Convert_U16_to_F32; break; 636 case AUDIO_S32: filter = SDL_Convert_S32_to_F32; break; 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 662SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt) 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; 669 SDL_AudioFilter filter = NULL; 670 switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) { 671 case AUDIO_S8: filter = SDL_Convert_F32_to_S8; break; 672 case AUDIO_U8: filter = SDL_Convert_F32_to_U8; break; 673 case AUDIO_S16: filter = SDL_Convert_F32_to_S16; break; 674 case AUDIO_U16: filter = SDL_Convert_F32_to_U16; break; 675 case AUDIO_S32: filter = SDL_Convert_F32_to_S32; break; 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)) { 697 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) { 698 return -1; 699 } 700 retval = 1; /* added a converter. */ 701 } 702 703 return retval; 704} 705 706static void 707SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format) 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 paddingsamples = (ResamplerPadding(inrate, outrate) * chans); 722 float *padding; 723 724 SDL_assert(format == AUDIO_F32SYS); 725 726 /* we keep no streaming state here, so pad with silence on both ends. */ 727 padding = (float *) SDL_calloc(paddingsamples ? paddingsamples : 1, sizeof (float)); 728 if (!padding) { 729 SDL_OutOfMemory(); 730 return; 731 } 732 733 cvt->len_cvt = SDL_ResampleAudio(chans, inrate, outrate, padding, padding, src, srclen, dst, dstlen); 734 735 SDL_free(padding); 736 737 SDL_memmove(cvt->buf, dst, cvt->len_cvt); /* !!! FIXME: remove this if we can get the resampler to work in-place again. */ 738 739 if (cvt->filters[++cvt->filter_index]) { 740 cvt->filters[cvt->filter_index](cvt, format); 741 } 742} 743 744/* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't 745 !!! FIXME: store channel info, so we have to have function entry 746 !!! FIXME: points for each supported channel count and multiple 747 !!! FIXME: vs arbitrary. When we rev the ABI, clean this up. */ 748#define RESAMPLER_FUNCS(chans) \ 749 static void SDLCALL \ 750 SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \ 751 SDL_ResampleCVT(cvt, chans, format); \ 752 } 753RESAMPLER_FUNCS(1) 754RESAMPLER_FUNCS(2) 755RESAMPLER_FUNCS(4) 756RESAMPLER_FUNCS(6) 757RESAMPLER_FUNCS(8) 758#undef RESAMPLER_FUNCS 759 760static SDL_AudioFilter 761ChooseCVTResampler(const int dst_channels) 762{ 763 switch (dst_channels) { 764 case 1: return SDL_ResampleCVT_c1; 765 case 2: return SDL_ResampleCVT_c2; 766 case 4: return SDL_ResampleCVT_c4; 767 case 6: return SDL_ResampleCVT_c6; 768 case 8: return SDL_ResampleCVT_c8; 769 default: break; 770 } 771 772 return NULL; 773} 774 775static int 776SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels, 777 const int src_rate, const int dst_rate) 778{ 779 SDL_AudioFilter filter; 780 781 if (src_rate == dst_rate) { 782 return 0; /* no conversion necessary. */ 783 } 784 785 filter = ChooseCVTResampler(dst_channels); 786 if (filter == NULL) { 787 return SDL_SetError("No conversion available for these rates"); 788 } 789 790 if (SDL_PrepareResampleFilter() < 0) { 791 return -1; 792 } 793 794 /* Update (cvt) with filter details... */ 795 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) { 796 return -1; 797 } 798 799 /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator). 800 !!! FIXME in 2.1: We need to store data for this resampler, because the cvt structure doesn't store the original sample rates, 801 !!! FIXME in 2.1: so we steal the ninth and tenth slot. :( */ 802 if (cvt->filter_index >= (SDL_AUDIOCVT_MAX_FILTERS-2)) { 803 return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS-2); 804 } 805 cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1] = (SDL_AudioFilter) (size_t) src_rate; 806 cvt->filters[SDL_AUDIOCVT_MAX_FILTERS] = (SDL_AudioFilter) (size_t) dst_rate; 807 808 if (src_rate < dst_rate) { 809 const double mult = ((double) dst_rate) / ((double) src_rate); 810 cvt->len_mult *= (int) SDL_ceil(mult); 811 cvt->len_ratio *= mult; 812 } else { 813 cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate); 814 } 815 816 /* !!! FIXME: remove this if we can get the resampler to work in-place again. */ 817 /* the buffer is big enough to hold the destination now, but 818 we need it large enough to hold a separate scratch buffer. */ 819 cvt->len_mult *= 2; 820 821 return 1; /* added a converter. */ 822} 823 824static SDL_bool 825SDL_SupportedAudioFormat(const SDL_AudioFormat fmt) 826{ 827 switch (fmt) { 828 case AUDIO_U8: 829 case AUDIO_S8: 830 case AUDIO_U16LSB: 831 case AUDIO_S16LSB: 832 case AUDIO_U16MSB: 833 case AUDIO_S16MSB: 834 case AUDIO_S32LSB: 835 case AUDIO_S32MSB: 836 case AUDIO_F32LSB: 837 case AUDIO_F32MSB: 838 return SDL_TRUE; /* supported. */ 839 840 default: 841 break; 842 } 843 844 return SDL_FALSE; /* unsupported. */ 845} 846 847static SDL_bool 848SDL_SupportedChannelCount(const int channels) 849{ 850 switch (channels) { 851 case 1: /* mono */ 852 case 2: /* stereo */ 853 case 4: /* quad */ 854 case 6: /* 5.1 */ 855 case 8: /* 7.1 */ 856 return SDL_TRUE; /* supported. */ 857 858 default: 859 break; 860 } 861 862 return SDL_FALSE; /* unsupported. */ 863} 864 865 866/* Creates a set of audio filters to convert from one format to another. 867 Returns 0 if no conversion is needed, 1 if the audio filter is set up, 868 or -1 if an error like invalid parameter, unsupported format, etc. occurred. 869*/ 870 871int 872SDL_BuildAudioCVT(SDL_AudioCVT * cvt, 873 SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate, 874 SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate) 875{ 876 /* Sanity check target pointer */ 877 if (cvt == NULL) { 878 return SDL_InvalidParamError("cvt"); 879 } 880 881 /* Make sure we zero out the audio conversion before error checking */ 882 SDL_zerop(cvt); 883 884 if (!SDL_SupportedAudioFormat(src_fmt)) { 885 return SDL_SetError("Invalid source format"); 886 } else if (!SDL_SupportedAudioFormat(dst_fmt)) { 887 return SDL_SetError("Invalid destination format"); 888 } else if (!SDL_SupportedChannelCount(src_channels)) { 889 return SDL_SetError("Invalid source channels"); 890 } else if (!SDL_SupportedChannelCount(dst_channels)) { 891 return SDL_SetError("Invalid destination channels"); 892 } else if (src_rate == 0) { 893 return SDL_SetError("Source rate is zero"); 894 } else if (dst_rate == 0) { 895 return SDL_SetError("Destination rate is zero"); 896 } 897 898#if DEBUG_CONVERT 899 printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n", 900 src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate); 901#endif 902 903 /* Start off with no conversion necessary */ 904 cvt->src_format = src_fmt; 905 cvt->dst_format = dst_fmt; 906 cvt->needed = 0; 907 cvt->filter_index = 0; 908 SDL_zero(cvt->filters); 909 cvt->len_mult = 1; 910 cvt->len_ratio = 1.0; 911 cvt->rate_incr = ((double) dst_rate) / ((double) src_rate); 912 913 /* Make sure we've chosen audio conversion functions (MMX, scalar, etc.) */ 914 SDL_ChooseAudioConverters(); 915 916 /* Type conversion goes like this now: 917 - byteswap to CPU native format first if necessary. 918 - convert to native Float32 if necessary. 919 - resample and change channel count if necessary. 920 - convert back to native format. 921 - byteswap back to foreign format if necessary. 922 923 The expectation is we can process data faster in float32 924 (possibly with SIMD), and making several passes over the same 925 buffer is likely to be CPU cache-friendly, avoiding the 926 biggest performance hit in modern times. Previously we had 927 (script-generated) custom converters for every data type and 928 it was a bloat on SDL compile times and final library size. */ 929 930 /* see if we can skip float conversion entirely. */ 931 if (src_rate == dst_rate && src_channels == dst_channels) { 932 if (src_fmt == dst_fmt) { 933 return 0; 934 } 935 936 /* just a byteswap needed? */ 937 if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) { 938 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) { 939 return -1; 940 } 941 cvt->needed = 1; 942 return 1; 943 } 944 } 945 946 /* Convert data types, if necessary. Updates (cvt). */ 947 if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) { 948 return -1; /* shouldn't happen, but just in case... */ 949 } 950 951 /* Channel conversion */ 952 if (src_channels < dst_channels) { 953 /* Upmixing */ 954 /* Mono -> Stereo [-> ...] */ 955 if ((src_channels == 1) && (dst_channels > 1)) { 956 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertMonoToStereo) < 0) { 957 return -1; 958 } 959 cvt->len_mult *= 2; 960 src_channels = 2; 961 cvt->len_ratio *= 2; 962 } 963 /* [Mono ->] Stereo -> 5.1 [-> 7.1] */ 964 if ((src_channels == 2) && (dst_channels >= 6)) { 965 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoTo51) < 0) { 966 return -1; 967 } 968 src_channels = 6; 969 cvt->len_mult *= 3; 970 cvt->len_ratio *= 3; 971 } 972 /* Quad -> 5.1 [-> 7.1] */ 973 if ((src_channels == 4) && (dst_channels >= 6)) { 974 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadTo51) < 0) { 975 return -1; 976 } 977 src_channels = 6; 978 cvt->len_mult = (cvt->len_mult * 3 + 1) / 2; 979 cvt->len_ratio *= 1.5; 980 } 981 /* [[Mono ->] Stereo ->] 5.1 -> 7.1 */ 982 if ((src_channels == 6) && (dst_channels == 8)) { 983 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51To71) < 0) { 984 return -1; 985 } 986 src_channels = 8; 987 cvt->len_mult = (cvt->len_mult * 4 + 2) / 3; 988 /* Should be numerically exact with every valid input to this 989 function */ 990 cvt->len_ratio = cvt->len_ratio * 4 / 3; 991 } 992 /* [Mono ->] Stereo -> Quad */ 993 if ((src_channels == 2) && (dst_channels == 4)) { 994 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoToQuad) < 0) { 995 return -1; 996 } 997 src_channels = 4; 998 cvt->len_mult *= 2; 999 cvt->len_ratio *= 2; 1000 } 1001 } else if (src_channels > dst_channels) { 1002 /* Downmixing */ 1003 /* 7.1 -> 5.1 [-> Stereo [-> Mono]] */ 1004 /* 7.1 -> 5.1 [-> Quad] */ 1005 if ((src_channels == 8) && (dst_channels <= 6)) { 1006 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert71To51) < 0) { 1007 return -1; 1008 } 1009 src_channels = 6; 1010 cvt->len_ratio *= 0.75; 1011 } 1012 /* [7.1 ->] 5.1 -> Stereo [-> Mono] */ 1013 if ((src_channels == 6) && (dst_channels <= 2)) { 1014 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToStereo) < 0) { 1015 return -1; 1016 } 1017 src_channels = 2; 1018 cvt->len_ratio /= 3; 1019 } 1020 /* 5.1 -> Quad */ 1021 if ((src_channels == 6) && (dst_channels == 4)) { 1022 if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToQuad) < 0) { 1023 return -1; 1024 } 1025 src_channels = 4; 1026 cvt->len_ratio = cvt->len_ratio * 2 / 3; 1027 } 1028 /* Quad -> Stereo [-> Mono] */ 1029 if ((src_channels == 4) && (dst_channels <= 2)) { 1030 if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadToStereo) < 0) { 1031 return -1; 1032 } 1033 src_channels = 2; 1034 cvt->len_ratio /= 2; 1035 } 1036 /* [... ->] Stereo -> Mono */ 1037 if ((src_channels == 2) && (dst_channels == 1)) { 1038 SDL_AudioFilter filter = NULL; 1039 1040 #if HAVE_SSE3_INTRINSICS 1041 if (SDL_HasSSE3()) { 1042 filter = SDL_ConvertStereoToMono_SSE3; 1043 } 1044 #endif 1045 1046 if (!filter) { 1047 filter = SDL_ConvertStereoToMono; 1048 } 1049 1050 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) { 1051 return -1; 1052 } 1053 1054 src_channels = 1; 1055 cvt->len_ratio /= 2; 1056 } 1057 } 1058 1059 if (src_channels != dst_channels) { 1060 /* All combinations of supported channel counts should have been 1061 handled by now, but let's be defensive */ 1062 return SDL_SetError("Invalid channel combination"); 1063 } 1064 1065 /* Do rate conversion, if necessary. Updates (cvt). */ 1066 if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) { 1067 return -1; /* shouldn't happen, but just in case... */ 1068 } 1069 1070 /* Move to final data type. */ 1071 if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) { 1072 return -1; /* shouldn't happen, but just in case... */ 1073 } 1074 1075 cvt->needed = (cvt->filter_index != 0); 1076 return (cvt->needed); 1077} 1078 1079typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen); 1080typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream); 1081typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream); 1082 1083struct _SDL_AudioStream 1084{ 1085 SDL_AudioCVT cvt_before_resampling; 1086 SDL_AudioCVT cvt_after_resampling; 1087 SDL_DataQueue *queue; 1088 SDL_bool first_run; 1089 Uint8 *staging_buffer; 1090 int staging_buffer_size; 1091 int staging_buffer_filled; 1092 Uint8 *work_buffer_base; /* maybe unaligned pointer from SDL_realloc(). */ 1093 int work_buffer_len; 1094 int src_sample_frame_size; 1095 SDL_AudioFormat src_format; 1096 Uint8 src_channels; 1097 int src_rate; 1098 int dst_sample_frame_size; 1099 SDL_AudioFormat dst_format; 1100 Uint8 dst_channels; 1101 int dst_rate; 1102 double rate_incr; 1103 Uint8 pre_resample_channels; 1104 int packetlen; 1105 int resampler_padding_samples; 1106 float *resampler_padding; 1107 void *resampler_state; 1108 SDL_ResampleAudioStreamFunc resampler_func; 1109 SDL_ResetAudioStreamResamplerFunc reset_resampler_func; 1110 SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func; 1111}; 1112 1113static Uint8 * 1114EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen) 1115{ 1116 Uint8 *ptr; 1117 size_t offset; 1118 1119 if (stream->work_buffer_len >= newlen) { 1120 ptr = stream->work_buffer_base; 1121 } else { 1122 ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32); 1123 if (!ptr) { 1124 SDL_OutOfMemory(); 1125 return NULL; 1126 } 1127 /* Make sure we're aligned to 16 bytes for SIMD code. */ 1128 stream->work_buffer_base = ptr; 1129 stream->work_buffer_len = newlen; 1130 } 1131 1132 offset = ((size_t) ptr) & 15; 1133 return offset ? ptr + (16 - offset) : ptr; 1134} 1135 1136#ifdef HAVE_LIBSAMPLERATE_H 1137static int 1138SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen) 1139{ 1140 const float *inbuf = (const float *) _inbuf; 1141 float *outbuf = (float *) _outbuf; 1142 const int framelen = sizeof(float) * stream->pre_resample_channels; 1143 SRC_STATE *state = (SRC_STATE *)stream->resampler_state; 1144 SRC_DATA data; 1145 int result; 1146 1147 SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */ 1148 1149 data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */ 1150 data.input_frames = inbuflen / framelen; 1151 data.input_frames_used = 0; 1152 1153 data.data_out = outbuf; 1154 data.output_frames = outbuflen / framelen; 1155 1156 data.end_of_input = 0; 1157 data.src_ratio = stream->rate_incr; 1158 1159 result = SRC_src_process(state, &data); 1160 if (result != 0) { 1161 SDL_SetError("src_process() failed: %s", SRC_src_strerror(result)); 1162 return 0; 1163 } 1164 1165 /* If this fails, we need to store them off somewhere */ 1166 SDL_assert(data.input_frames_used == data.input_frames); 1167 1168 return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels); 1169} 1170 1171static void 1172SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream) 1173{ 1174 SRC_src_reset((SRC_STATE *)stream->resampler_state); 1175} 1176 1177static void 1178SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream) 1179{ 1180 SRC_STATE *state = (SRC_STATE *)stream->resampler_state; 1181 if (state) { 1182 SRC_src_delete(state); 1183 } 1184 1185 stream->resampler_state = NULL; 1186 stream->resampler_func = NULL; 1187 stream->reset_resampler_func = NULL; 1188 stream->cleanup_resampler_func = NULL; 1189} 1190 1191static SDL_bool 1192SetupLibSampleRateResampling(SDL_AudioStream *stream) 1193{ 1194 int result = 0; 1195 SRC_STATE *state = NULL; 1196 1197 if (SRC_available) { 1198 state = SRC_src_new(SRC_converter, stream->pre_resample_channels, &result); 1199 if (!state) { 1200 SDL_SetError("src_new() failed: %s", SRC_src_strerror(result)); 1201 } 1202 } 1203 1204 if (!state) { 1205 SDL_CleanupAudioStreamResampler_SRC(stream); 1206 return SDL_FALSE; 1207 } 1208 1209 stream->resampler_state = state; 1210 stream->resampler_func = SDL_ResampleAudioStream_SRC; 1211 stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC; 1212 stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC; 1213 1214 return SDL_TRUE; 1215} 1216#endif /* HAVE_LIBSAMPLERATE_H */ 1217 1218 1219static int 1220SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen) 1221{ 1222 const Uint8 *inbufend = ((const Uint8 *) _inbuf) + inbuflen; 1223 const float *inbuf = (const float *) _inbuf; 1224 float *outbuf = (float *) _outbuf; 1225 const int chans = (int) stream->pre_resample_channels; 1226 const int inrate = stream->src_rate; 1227 const int outrate = stream->dst_rate; 1228 const int paddingsamples = stream->resampler_padding_samples; 1229 const int paddingbytes = paddingsamples * sizeof (float); 1230 float *lpadding = (float *) stream->resampler_state; 1231 const float *rpadding = (const float *) inbufend; /* we set this up so there are valid padding samples at the end of the input buffer. */ 1232 const int cpy = SDL_min(inbuflen, paddingbytes); 1233 int retval; 1234 1235 SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */ 1236 1237 retval = SDL_ResampleAudio(chans, inrate, outrate, lpadding, rpadding, inbuf, inbuflen, outbuf, outbuflen); 1238 1239 /* update our left padding with end of current input, for next run. */ 1240 SDL_memcpy((lpadding + paddingsamples) - (cpy / sizeof (float)), inbufend - cpy, cpy); 1241 return retval; 1242} 1243 1244static void 1245SDL_ResetAudioStreamResampler(SDL_AudioStream *stream) 1246{ 1247 /* set all the padding to silence. */ 1248 const int len = stream->resampler_padding_samples; 1249 SDL_memset(stream->resampler_state, '\0', len * sizeof (float)); 1250} 1251 1252static void 1253SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream) 1254{ 1255 SDL_free(stream->resampler_state); 1256} 1257 1258SDL_AudioStream * 1259SDL_NewAudioStream(const SDL_AudioFormat src_format, 1260 const Uint8 src_channels, 1261 const int src_rate, 1262 const SDL_AudioFormat dst_format, 1263 const Uint8 dst_channels, 1264 const int dst_rate) 1265{ 1266 const int packetlen = 4096; /* !!! FIXME: good enough for now. */ 1267 Uint8 pre_resample_channels; 1268 SDL_AudioStream *retval; 1269 1270 retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream)); 1271 if (!retval) { 1272 return NULL; 1273 } 1274 1275 /* If increasing channels, do it after resampling, since we'd just 1276 do more work to resample duplicate channels. If we're decreasing, do 1277 it first so we resample the interpolated data instead of interpolating 1278 the resampled data (!!! FIXME: decide if that works in practice, though!). */ 1279 pre_resample_channels = SDL_min(src_channels, dst_channels); 1280 1281 retval->first_run = SDL_TRUE; 1282 retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels; 1283 retval->src_format = src_format; 1284 retval->src_channels = src_channels; 1285 retval->src_rate = src_rate; 1286 retval->dst_sample_frame_size = (SDL_AUDIO_BITSIZE(dst_format) / 8) * dst_channels; 1287 retval->dst_format = dst_format; 1288 retval->dst_channels = dst_channels; 1289 retval->dst_rate = dst_rate; 1290 retval->pre_resample_channels = pre_resample_channels; 1291 retval->packetlen = packetlen; 1292 retval->rate_incr = ((double) dst_rate) / ((double) src_rate); 1293 retval->resampler_padding_samples = ResamplerPadding(retval->src_rate, retval->dst_rate) * pre_resample_channels; 1294 retval->resampler_padding = (float *) SDL_calloc(retval->resampler_padding_samples ? retval->resampler_padding_samples : 1, sizeof (float)); 1295 1296 if (retval->resampler_padding == NULL) { 1297 SDL_FreeAudioStream(retval); 1298 SDL_OutOfMemory(); 1299 return NULL; 1300 } 1301 1302 retval->staging_buffer_size = ((retval->resampler_padding_samples / retval->pre_resample_channels) * retval->src_sample_frame_size); 1303 if (retval->staging_buffer_size > 0) { 1304 retval->staging_buffer = (Uint8 *) SDL_malloc(retval->staging_buffer_size); 1305 if (retval->staging_buffer == NULL) { 1306 SDL_FreeAudioStream(retval); 1307 SDL_OutOfMemory(); 1308 return NULL; 1309 } 1310 } 1311 1312 /* Not resampling? It's an easy conversion (and maybe not even that!) */ 1313 if (src_rate == dst_rate) { 1314 retval->cvt_before_resampling.needed = SDL_FALSE; 1315 if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) { 1316 SDL_FreeAudioStream(retval); 1317 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */ 1318 } 1319 } else { 1320 /* Don't resample at first. Just get us to Float32 format. */ 1321 /* !!! FIXME: convert to int32 on devices without hardware float. */ 1322 if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) { 1323 SDL_FreeAudioStream(retval); 1324 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */ 1325 } 1326 1327#ifdef HAVE_LIBSAMPLERATE_H 1328 SetupLibSampleRateResampling(retval); 1329#endif 1330 1331 if (!retval->resampler_func) { 1332 retval->resampler_state = SDL_calloc(retval->resampler_padding_samples, sizeof (float)); 1333 if (!retval->resampler_state) { 1334 SDL_FreeAudioStream(retval); 1335 SDL_OutOfMemory(); 1336 return NULL; 1337 } 1338 1339 if (SDL_PrepareResampleFilter() < 0) { 1340 SDL_free(retval->resampler_state); 1341 retval->resampler_state = NULL; 1342 SDL_FreeAudioStream(retval); 1343 return NULL; 1344 } 1345 1346 retval->resampler_func = SDL_ResampleAudioStream; 1347 retval->reset_resampler_func = SDL_ResetAudioStreamResampler; 1348 retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler; 1349 } 1350 1351 /* Convert us to the final format after resampling. */ 1352 if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) { 1353 SDL_FreeAudioStream(retval); 1354 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */ 1355 } 1356 } 1357 1358 retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2); 1359 if (!retval->queue) { 1360 SDL_FreeAudioStream(retval); 1361 return NULL; /* SDL_NewDataQueue should have called SDL_SetError. */ 1362 } 1363 1364 return retval; 1365} 1366 1367static int 1368SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len, int *maxputbytes) 1369{ 1370 int buflen = len; 1371 int workbuflen; 1372 Uint8 *workbuf; 1373 Uint8 *resamplebuf = NULL; 1374 int resamplebuflen = 0; 1375 int neededpaddingbytes; 1376 int paddingbytes; 1377 1378 /* !!! FIXME: several converters can take advantage of SIMD, but only 1379 !!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize() 1380 !!! FIXME: guarantees the buffer will align, but the 1381 !!! FIXME: converters will iterate over the data backwards if 1382 !!! FIXME: the output grows, and this means we won't align if buflen 1383 !!! FIXME: isn't a multiple of 16. In these cases, we should chop off 1384 !!! FIXME: a few samples at the end and convert them separately. */ 1385 1386 /* no padding prepended on first run. */ 1387 neededpaddingbytes = stream->resampler_padding_samples * sizeof (float); 1388 paddingbytes = stream->first_run ? 0 : neededpaddingbytes; 1389 stream->first_run = SDL_FALSE; 1390 1391 /* Make sure the work buffer can hold all the data we need at once... */ 1392 workbuflen = buflen; 1393 if (stream->cvt_before_resampling.needed) { 1394 workbuflen *= stream->cvt_before_resampling.len_mult; 1395 } 1396 1397 if (stream->dst_rate != stream->src_rate) { 1398 /* resamples can't happen in place, so make space for second buf. */ 1399 const int framesize = stream->pre_resample_channels * sizeof (float); 1400 const int frames = workbuflen / framesize; 1401 resamplebuflen = ((int) SDL_ceil(frames * stream->rate_incr)) * framesize; 1402 #if DEBUG_AUDIOSTREAM 1403 printf("AUDIOSTREAM: will resample %d bytes to %d (ratio=%.6f)\n", workbuflen, resamplebuflen, stream->rate_incr); 1404 #endif 1405 workbuflen += resamplebuflen; 1406 } 1407 1408 if (stream->cvt_after_resampling.needed) { 1409 /* !!! FIXME: buffer might be big enough already? */ 1410 workbuflen *= stream->cvt_after_resampling.len_mult; 1411 } 1412 1413 workbuflen += neededpaddingbytes; 1414 1415 #if DEBUG_AUDIOSTREAM 1416 printf("AUDIOSTREAM: Putting %d bytes of preconverted audio, need %d byte work buffer\n", buflen, workbuflen); 1417 #endif 1418 1419 workbuf = EnsureStreamBufferSize(stream, workbuflen); 1420 if (!workbuf) { 1421 return -1; /* probably out of memory. */ 1422 } 1423 1424 resamplebuf = workbuf; /* default if not resampling. */ 1425 1426 SDL_memcpy(workbuf + paddingbytes, buf, buflen); 1427 1428 if (stream->cvt_before_resampling.needed) { 1429 stream->cvt_before_resampling.buf = workbuf + paddingbytes; 1430 stream->cvt_before_resampling.len = buflen; 1431 if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) { 1432 return -1; /* uhoh! */ 1433 } 1434 buflen = stream->cvt_before_resampling.len_cvt; 1435 1436 #if DEBUG_AUDIOSTREAM 1437 printf("AUDIOSTREAM: After initial conversion we have %d bytes\n", buflen); 1438 #endif 1439 } 1440 1441 if (stream->dst_rate != stream->src_rate) { 1442 /* save off some samples at the end; they are used for padding now so 1443 the resampler is coherent and then used at the start of the next 1444 put operation. Prepend last put operation's padding, too. */ 1445 1446 /* prepend prior put's padding. :P */ 1447 if (paddingbytes) { 1448 SDL_memcpy(workbuf, stream->resampler_padding, paddingbytes); 1449 buflen += paddingbytes; 1450 } 1451 1452 /* save off the data at the end for the next run. */ 1453 SDL_memcpy(stream->resampler_padding, workbuf + (buflen - neededpaddingbytes), neededpaddingbytes); 1454 1455 resamplebuf = workbuf + buflen; /* skip to second piece of workbuf. */ 1456 SDL_assert(buflen >= neededpaddingbytes); 1457 if (buflen > neededpaddingbytes) { 1458 buflen = stream->resampler_func(stream, workbuf, buflen - neededpaddingbytes, resamplebuf, resamplebuflen); 1459 } else { 1460 buflen = 0; 1461 } 1462 1463 #if DEBUG_AUDIOSTREAM 1464 printf("AUDIOSTREAM: After resampling we have %d bytes\n", buflen); 1465 #endif 1466 } 1467 1468 if (stream->cvt_after_resampling.needed && (buflen > 0)) { 1469 stream->cvt_after_resampling.buf = resamplebuf; 1470 stream->cvt_after_resampling.len = buflen; 1471 if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) { 1472 return -1; /* uhoh! */ 1473 } 1474 buflen = stream->cvt_after_resampling.len_cvt; 1475 1476 #if DEBUG_AUDIOSTREAM 1477 printf("AUDIOSTREAM: After final conversion we have %d bytes\n", buflen); 1478 #endif 1479 } 1480 1481 #if DEBUG_AUDIOSTREAM 1482 printf("AUDIOSTREAM: Final output is %d bytes\n", buflen); 1483 #endif 1484 1485 if (maxputbytes) { 1486 const int maxbytes = *maxputbytes; 1487 if (buflen > maxbytes) 1488 buflen = maxbytes; 1489 *maxputbytes -= buflen; 1490 } 1491 1492 /* resamplebuf holds the final output, even if we didn't resample. */ 1493 return buflen ? SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen) : 0; 1494} 1495 1496int 1497SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len) 1498{ 1499 /* !!! FIXME: several converters can take advantage of SIMD, but only 1500 !!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize() 1501 !!! FIXME: guarantees the buffer will align, but the 1502 !!! FIXME: converters will iterate over the data backwards if 1503 !!! FIXME: the output grows, and this means we won't align if buflen 1504 !!! FIXME: isn't a multiple of 16. In these cases, we should chop off 1505 !!! FIXME: a few samples at the end and convert them separately. */ 1506 1507 #if DEBUG_AUDIOSTREAM 1508 printf("AUDIOSTREAM: wants to put %d preconverted bytes\n", buflen); 1509 #endif 1510 1511 if (!stream) { 1512 return SDL_InvalidParamError("stream"); 1513 } else if (!buf) { 1514 return SDL_InvalidParamError("buf"); 1515 } else if (len == 0) { 1516 return 0; /* nothing to do. */ 1517 } else if ((len % stream->src_sample_frame_size) != 0) { 1518 return SDL_SetError("Can't add partial sample frames"); 1519 } 1520 1521 if (!stream->cvt_before_resampling.needed && 1522 (stream->dst_rate == stream->src_rate) && 1523 !stream->cvt_after_resampling.needed) { 1524 #if DEBUG_AUDIOSTREAM 1525 printf("AUDIOSTREAM: no conversion needed at all, queueing %d bytes.\n", len); 1526 #endif 1527 return SDL_WriteToDataQueue(stream->queue, buf, len); 1528 } 1529 1530 while (len > 0) { 1531 int amount; 1532 1533 /* If we don't have a staging buffer or we're given enough data that 1534 we don't need to store it for later, skip the staging process. 1535 */ 1536 if (!stream->staging_buffer_filled && len >= stream->staging_buffer_size) { 1537 return SDL_AudioStreamPutInternal(stream, buf, len, NULL); 1538 } 1539 1540 /* If there's not enough data to fill the staging buffer, just save it */ 1541 if ((stream->staging_buffer_filled + len) < stream->staging_buffer_size) { 1542 SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, len); 1543 stream->staging_buffer_filled += len; 1544 return 0; 1545 } 1546 1547 /* Fill the staging buffer, process it, and continue */ 1548 amount = (stream->staging_buffer_size - stream->staging_buffer_filled); 1549 SDL_assert(amount > 0); 1550 SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, amount); 1551 stream->staging_buffer_filled = 0; 1552 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, NULL) < 0) { 1553 return -1; 1554 } 1555 buf = (void *)((Uint8 *)buf + amount); 1556 len -= amount; 1557 } 1558 return 0; 1559} 1560 1561int SDL_AudioStreamFlush(SDL_AudioStream *stream) 1562{ 1563 if (!stream) { 1564 return SDL_InvalidParamError("stream"); 1565 } 1566 1567 #if DEBUG_AUDIOSTREAM 1568 printf("AUDIOSTREAM: flushing! staging_buffer_filled=%d bytes\n", stream->staging_buffer_filled); 1569 #endif 1570 1571 /* shouldn't use a staging buffer if we're not resampling. */ 1572 SDL_assert((stream->dst_rate != stream->src_rate) || (stream->staging_buffer_filled == 0)); 1573 1574 if (stream->staging_buffer_filled > 0) { 1575 /* push the staging buffer + silence. We need to flush out not just 1576 the staging buffer, but the piece that the stream was saving off 1577 for right-side resampler padding. */ 1578 const SDL_bool first_run = stream->first_run; 1579 const int filled = stream->staging_buffer_filled; 1580 int actual_input_frames = filled / stream->src_sample_frame_size; 1581 if (!first_run) 1582 actual_input_frames += stream->resampler_padding_samples / stream->pre_resample_channels; 1583 1584 if (actual_input_frames > 0) { /* don't bother if nothing to flush. */ 1585 /* This is how many bytes we're expecting without silence appended. */ 1586 int flush_remaining = ((int) SDL_ceil(actual_input_frames * stream->rate_incr)) * stream->dst_sample_frame_size; 1587 1588 #if DEBUG_AUDIOSTREAM 1589 printf("AUDIOSTREAM: flushing with padding to get max %d bytes!\n", flush_remaining); 1590 #endif 1591 1592 SDL_memset(stream->staging_buffer + filled, '\0', stream->staging_buffer_size - filled); 1593 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) { 1594 return -1; 1595 } 1596 1597 /* we have flushed out (or initially filled) the pending right-side 1598 resampler padding, but we need to push more silence to guarantee 1599 the staging buffer is fully flushed out, too. */ 1600 SDL_memset(stream->staging_buffer, '\0', filled); 1601 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) { 1602 return -1; 1603 } 1604 } 1605 } 1606 1607 stream->staging_buffer_filled = 0; 1608 stream->first_run = SDL_TRUE; 1609 1610 return 0; 1611} 1612 1613/* get converted/resampled data from the stream */ 1614int 1615SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len) 1616{ 1617 #if DEBUG_AUDIOSTREAM 1618 printf("AUDIOSTREAM: want to get %d converted bytes\n", len); 1619 #endif 1620 1621 if (!stream) { 1622 return SDL_InvalidParamError("stream"); 1623 } else if (!buf) { 1624 return SDL_InvalidParamError("buf"); 1625 } else if (len <= 0) { 1626 return 0; /* nothing to do. */ 1627 } else if ((len % stream->dst_sample_frame_size) != 0) { 1628 return SDL_SetError("Can't request partial sample frames"); 1629 } 1630 1631 return (int) SDL_ReadFromDataQueue(stream->queue, buf, len); 1632} 1633 1634/* number of converted/resampled bytes available */ 1635int 1636SDL_AudioStreamAvailable(SDL_AudioStream *stream) 1637{ 1638 return stream ? (int) SDL_CountDataQueue(stream->queue) : 0; 1639} 1640 1641void 1642SDL_AudioStreamClear(SDL_AudioStream *stream) 1643{ 1644 if (!stream) { 1645 SDL_InvalidParamError("stream"); 1646 } else { 1647 SDL_ClearDataQueue(stream->queue, stream->packetlen * 2); 1648 if (stream->reset_resampler_func) { 1649 stream->reset_resampler_func(stream); 1650 } 1651 stream->first_run = SDL_TRUE; 1652 stream->staging_buffer_filled = 0; 1653 } 1654} 1655 1656/* dispose of a stream */ 1657void 1658SDL_FreeAudioStream(SDL_AudioStream *stream) 1659{ 1660 if (stream) { 1661 if (stream->cleanup_resampler_func) { 1662 stream->cleanup_resampler_func(stream); 1663 } 1664 SDL_FreeDataQueue(stream->queue); 1665 SDL_free(stream->staging_buffer); 1666 SDL_free(stream->work_buffer_base); 1667 SDL_free(stream->resampler_padding); 1668 SDL_free(stream); 1669 } 1670} 1671 1672/* vi: set ts=4 sw=4 expandtab: */ 1673 1674[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.