Lines 31-36
Link Here
|
31 |
#include "../SDL_dataqueue.h" |
31 |
#include "../SDL_dataqueue.h" |
32 |
#include "SDL_cpuinfo.h" |
32 |
#include "SDL_cpuinfo.h" |
33 |
|
33 |
|
|
|
34 |
#define DEBUG_AUDIOSTREAM 0 |
35 |
|
34 |
#ifdef __SSE3__ |
36 |
#ifdef __SSE3__ |
35 |
#define HAVE_SSE3_INTRINSICS 1 |
37 |
#define HAVE_SSE3_INTRINSICS 1 |
36 |
#endif |
38 |
#endif |
Lines 467-503
SDL_FreeResampleFilter(void)
Link Here
|
467 |
static int |
469 |
static int |
468 |
ResamplerPadding(const int inrate, const int outrate) |
470 |
ResamplerPadding(const int inrate, const int outrate) |
469 |
{ |
471 |
{ |
470 |
return (inrate > outrate) ? (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate))) : RESAMPLER_SAMPLES_PER_ZERO_CROSSING; |
472 |
if (inrate == outrate) { |
|
|
473 |
return 0; |
474 |
} else if (inrate > outrate) { |
475 |
return (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate))); |
476 |
} |
477 |
return RESAMPLER_SAMPLES_PER_ZERO_CROSSING; |
471 |
} |
478 |
} |
472 |
|
479 |
|
473 |
/* lpadding and rpadding are expected to be buffers of (ResamplePadding(inrate, outrate) * chans * sizeof (float)) bytes. */ |
480 |
/* lpadding and rpadding are expected to be buffers of (ResamplePadding(inrate, outrate) * chans * sizeof (float)) bytes. */ |
474 |
static int |
481 |
static int |
475 |
SDL_ResampleAudio(const int chans, const int inrate, const int outrate, |
482 |
SDL_ResampleAudio(const int chans, const int inrate, const int outrate, |
476 |
float *lpadding, float *rpadding, const float *inbuf, |
483 |
const float *lpadding, const float *rpadding, |
477 |
const int inbuflen, float *outbuf, const int outbuflen) |
484 |
const float *inbuf, const int inbuflen, |
|
|
485 |
float *outbuf, const int outbuflen) |
478 |
{ |
486 |
{ |
479 |
const float outtimeincr = 1.0f / ((float) outrate); |
487 |
const double finrate = (double) inrate; |
480 |
const float ratio = ((float) outrate) / ((float) inrate); |
488 |
const double outtimeincr = 1.0 / ((float) outrate); |
|
|
489 |
const double ratio = ((float) outrate) / ((float) inrate); |
481 |
const int paddinglen = ResamplerPadding(inrate, outrate); |
490 |
const int paddinglen = ResamplerPadding(inrate, outrate); |
482 |
const int framelen = chans * (int)sizeof (float); |
491 |
const int framelen = chans * (int)sizeof (float); |
483 |
const int inframes = inbuflen / framelen; |
492 |
const int inframes = inbuflen / framelen; |
484 |
const int wantedoutframes = (int) ((inbuflen / framelen) * ratio); /* outbuflen isn't total to write, it's total available. */ |
493 |
const int wantedoutframes = (int) ((inbuflen / framelen) * ratio); /* outbuflen isn't total to write, it's total available. */ |
485 |
const int maxoutframes = outbuflen / framelen; |
494 |
const int maxoutframes = outbuflen / framelen; |
486 |
const int outframes = (wantedoutframes < maxoutframes) ? wantedoutframes : maxoutframes; |
495 |
const int outframes = SDL_min(wantedoutframes, maxoutframes); |
487 |
float *dst = outbuf; |
496 |
float *dst = outbuf; |
488 |
float outtime = 0.0f; |
497 |
double outtime = 0.0; |
489 |
int i, j, chan; |
498 |
int i, j, chan; |
490 |
|
499 |
|
491 |
for (i = 0; i < outframes; i++) { |
500 |
for (i = 0; i < outframes; i++) { |
492 |
const int srcindex = (int) (outtime * inrate); |
501 |
const int srcindex = (int) (outtime * inrate); |
493 |
const float finrate = (float) inrate; |
502 |
const double intime = ((double) srcindex) / finrate; |
494 |
const float intime = ((float) srcindex) / finrate; |
503 |
const double innexttime = ((double) (srcindex + 1)) / finrate; |
495 |
const float innexttime = ((float) (srcindex + 1)) / finrate; |
504 |
const double interpolation1 = 1.0 - ((innexttime - outtime) / (innexttime - intime)); |
496 |
|
|
|
497 |
const float interpolation1 = 1.0f - (innexttime - outtime) / (innexttime - intime); |
498 |
const int filterindex1 = (int) (interpolation1 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING); |
505 |
const int filterindex1 = (int) (interpolation1 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING); |
499 |
const float interpolation2 = 1.0f - interpolation1; |
506 |
const double interpolation2 = 1.0 - interpolation1; |
500 |
const int filterindex2 = interpolation2 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING; |
507 |
const int filterindex2 = (int) (interpolation2 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING); |
501 |
|
508 |
|
502 |
for (chan = 0; chan < chans; chan++) { |
509 |
for (chan = 0; chan < chans; chan++) { |
503 |
float outsample = 0.0f; |
510 |
float outsample = 0.0f; |
Lines 714-731
SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, co
Link Here
|
714 |
SDL_assert(format == AUDIO_F32SYS); |
721 |
SDL_assert(format == AUDIO_F32SYS); |
715 |
|
722 |
|
716 |
/* we keep no streaming state here, so pad with silence on both ends. */ |
723 |
/* we keep no streaming state here, so pad with silence on both ends. */ |
717 |
padding = SDL_stack_alloc(float, paddingsamples); |
724 |
padding = (float *) SDL_calloc(paddingsamples, sizeof (float)); |
718 |
if (!padding) { |
725 |
if (!padding) { |
719 |
SDL_OutOfMemory(); |
726 |
SDL_OutOfMemory(); |
720 |
return; |
727 |
return; |
721 |
} |
728 |
} |
722 |
SDL_memset(padding, '\0', paddingsamples * sizeof (float)); |
|
|
723 |
|
729 |
|
724 |
cvt->len_cvt = SDL_ResampleAudio(chans, inrate, outrate, padding, padding, src, srclen, dst, dstlen); |
730 |
cvt->len_cvt = SDL_ResampleAudio(chans, inrate, outrate, padding, padding, src, srclen, dst, dstlen); |
725 |
|
731 |
|
726 |
SDL_stack_free(padding); |
732 |
SDL_free(padding); |
727 |
|
733 |
|
728 |
SDL_memcpy(cvt->buf, dst, cvt->len_cvt); /* !!! FIXME: remove this if we can get the resampler to work in-place again. */ |
734 |
SDL_memmove(cvt->buf, dst, cvt->len_cvt); /* !!! FIXME: remove this if we can get the resampler to work in-place again. */ |
729 |
|
735 |
|
730 |
if (cvt->filters[++cvt->filter_index]) { |
736 |
if (cvt->filters[++cvt->filter_index]) { |
731 |
cvt->filters[cvt->filter_index](cvt, format); |
737 |
cvt->filters[cvt->filter_index](cvt, format); |
Lines 1076-1081
struct SDL_AudioStream
Link Here
|
1076 |
SDL_AudioCVT cvt_before_resampling; |
1082 |
SDL_AudioCVT cvt_before_resampling; |
1077 |
SDL_AudioCVT cvt_after_resampling; |
1083 |
SDL_AudioCVT cvt_after_resampling; |
1078 |
SDL_DataQueue *queue; |
1084 |
SDL_DataQueue *queue; |
|
|
1085 |
SDL_bool first_run; |
1079 |
Uint8 *work_buffer_base; /* maybe unaligned pointer from SDL_realloc(). */ |
1086 |
Uint8 *work_buffer_base; /* maybe unaligned pointer from SDL_realloc(). */ |
1080 |
int work_buffer_len; |
1087 |
int work_buffer_len; |
1081 |
int src_sample_frame_size; |
1088 |
int src_sample_frame_size; |
Lines 1089-1094
struct SDL_AudioStream
Link Here
|
1089 |
double rate_incr; |
1096 |
double rate_incr; |
1090 |
Uint8 pre_resample_channels; |
1097 |
Uint8 pre_resample_channels; |
1091 |
int packetlen; |
1098 |
int packetlen; |
|
|
1099 |
int resampler_padding_samples; |
1100 |
float *resampler_padding; |
1092 |
void *resampler_state; |
1101 |
void *resampler_state; |
1093 |
SDL_ResampleAudioStreamFunc resampler_func; |
1102 |
SDL_ResampleAudioStreamFunc resampler_func; |
1094 |
SDL_ResetAudioStreamResamplerFunc reset_resampler_func; |
1103 |
SDL_ResetAudioStreamResamplerFunc reset_resampler_func; |
Lines 1129-1144
SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, c
Link Here
|
1129 |
SRC_DATA data; |
1138 |
SRC_DATA data; |
1130 |
int result; |
1139 |
int result; |
1131 |
|
1140 |
|
1132 |
if (inbuf == ((const float *) outbuf)) { /* libsamplerate can't work in-place. */ |
1141 |
SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */ |
1133 |
Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen); |
|
|
1134 |
if (ptr == NULL) { |
1135 |
SDL_OutOfMemory(); |
1136 |
return 0; |
1137 |
} |
1138 |
SDL_memcpy(ptr + outbuflen, ptr, inbuflen); |
1139 |
inbuf = (const float *) (ptr + outbuflen); |
1140 |
outbuf = (float *) ptr; |
1141 |
} |
1142 |
|
1142 |
|
1143 |
data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */ |
1143 |
data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */ |
1144 |
data.input_frames = inbuflen / framelen; |
1144 |
data.input_frames = inbuflen / framelen; |
Lines 1213-1266
SetupLibSampleRateResampling(SDL_AudioStream *stream)
Link Here
|
1213 |
static int |
1213 |
static int |
1214 |
SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen) |
1214 |
SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen) |
1215 |
{ |
1215 |
{ |
|
|
1216 |
const Uint8 *inbufend = ((const Uint8 *) _inbuf) + inbuflen; |
1216 |
const float *inbuf = (const float *) _inbuf; |
1217 |
const float *inbuf = (const float *) _inbuf; |
1217 |
float *outbuf = (float *) _outbuf; |
1218 |
float *outbuf = (float *) _outbuf; |
1218 |
const int chans = (int) stream->pre_resample_channels; |
1219 |
const int chans = (int) stream->pre_resample_channels; |
1219 |
const int inrate = stream->src_rate; |
1220 |
const int inrate = stream->src_rate; |
1220 |
const int outrate = stream->dst_rate; |
1221 |
const int outrate = stream->dst_rate; |
1221 |
const int paddingsamples = ResamplerPadding(inrate, outrate) * chans; |
1222 |
const int paddingsamples = stream->resampler_padding_samples; |
1222 |
const int paddingbytes = paddingsamples * sizeof (float); |
1223 |
const int paddingbytes = paddingsamples * sizeof (float); |
1223 |
float *lpadding = (float *) stream->resampler_state; |
1224 |
float *lpadding = (float *) stream->resampler_state; |
1224 |
float *rpadding; |
1225 |
const float *rpadding = (const float *) inbufend; /* we set this up so there are valid padding samples at the end of the input buffer. */ |
|
|
1226 |
const int cpy = SDL_min(inbuflen, paddingbytes); |
1225 |
int retval; |
1227 |
int retval; |
1226 |
|
1228 |
|
1227 |
if (inbuf == ((const float *) outbuf)) { /* !!! FIXME can't work in-place (for now!). */ |
1229 |
SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */ |
1228 |
Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen); |
|
|
1229 |
if (ptr == NULL) { |
1230 |
SDL_OutOfMemory(); |
1231 |
return 0; |
1232 |
} |
1233 |
SDL_memcpy(ptr + outbuflen, ptr, inbuflen); |
1234 |
inbuf = (const float *) (ptr + outbuflen); |
1235 |
outbuf = (float *) ptr; |
1236 |
} |
1237 |
|
1230 |
|
1238 |
/* !!! FIXME: streaming current resamples on Put, because of probably good reasons I can't remember right now, but if we resample on Get, we'd be able to access legit right padding values. */ |
|
|
1239 |
rpadding = SDL_stack_alloc(float, paddingsamples); |
1240 |
if (!rpadding) { |
1241 |
SDL_OutOfMemory(); |
1242 |
return 0; |
1243 |
} |
1244 |
SDL_memset(rpadding, '\0', paddingbytes); |
1245 |
|
1246 |
retval = SDL_ResampleAudio(chans, inrate, outrate, lpadding, rpadding, inbuf, inbuflen, outbuf, outbuflen); |
1231 |
retval = SDL_ResampleAudio(chans, inrate, outrate, lpadding, rpadding, inbuf, inbuflen, outbuf, outbuflen); |
1247 |
|
1232 |
|
1248 |
SDL_stack_free(rpadding); |
|
|
1249 |
|
1250 |
/* update our left padding with end of current input, for next run. */ |
1233 |
/* update our left padding with end of current input, for next run. */ |
1251 |
SDL_memcpy(lpadding, ((const Uint8 *) inbuf) + (inbuflen - paddingbytes), paddingbytes); |
1234 |
SDL_memcpy((lpadding + paddingsamples) - (cpy / sizeof (float)), inbufend - cpy, cpy); |
1252 |
|
|
|
1253 |
return retval; |
1235 |
return retval; |
1254 |
} |
1236 |
} |
1255 |
|
1237 |
|
1256 |
static void |
1238 |
static void |
1257 |
SDL_ResetAudioStreamResampler(SDL_AudioStream *stream) |
1239 |
SDL_ResetAudioStreamResampler(SDL_AudioStream *stream) |
1258 |
{ |
1240 |
{ |
1259 |
/* set all the left padding to silence. */ |
1241 |
/* set all the padding to silence. */ |
1260 |
const int inrate = stream->src_rate; |
1242 |
const int len = stream->resampler_padding_samples; |
1261 |
const int outrate = stream->dst_rate; |
|
|
1262 |
const int chans = (int) stream->pre_resample_channels; |
1263 |
const int len = ResamplerPadding(inrate, outrate) * chans; |
1264 |
SDL_memset(stream->resampler_state, '\0', len * sizeof (float)); |
1243 |
SDL_memset(stream->resampler_state, '\0', len * sizeof (float)); |
1265 |
} |
1244 |
} |
1266 |
|
1245 |
|
Lines 1293-1298
SDL_NewAudioStream(const SDL_AudioFormat src_format,
Link Here
|
1293 |
the resampled data (!!! FIXME: decide if that works in practice, though!). */ |
1272 |
the resampled data (!!! FIXME: decide if that works in practice, though!). */ |
1294 |
pre_resample_channels = SDL_min(src_channels, dst_channels); |
1273 |
pre_resample_channels = SDL_min(src_channels, dst_channels); |
1295 |
|
1274 |
|
|
|
1275 |
retval->first_run = SDL_TRUE; |
1296 |
retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels; |
1276 |
retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels; |
1297 |
retval->src_format = src_format; |
1277 |
retval->src_format = src_format; |
1298 |
retval->src_channels = src_channels; |
1278 |
retval->src_channels = src_channels; |
Lines 1304-1310
SDL_NewAudioStream(const SDL_AudioFormat src_format,
Link Here
|
1304 |
retval->pre_resample_channels = pre_resample_channels; |
1284 |
retval->pre_resample_channels = pre_resample_channels; |
1305 |
retval->packetlen = packetlen; |
1285 |
retval->packetlen = packetlen; |
1306 |
retval->rate_incr = ((double) dst_rate) / ((double) src_rate); |
1286 |
retval->rate_incr = ((double) dst_rate) / ((double) src_rate); |
|
|
1287 |
retval->resampler_padding_samples = ResamplerPadding(retval->src_rate, retval->dst_rate) * pre_resample_channels; |
1288 |
retval->resampler_padding = (float *) SDL_calloc(retval->resampler_padding_samples, sizeof (float)); |
1307 |
|
1289 |
|
|
|
1290 |
if (retval->resampler_padding == NULL) { |
1291 |
SDL_FreeAudioStream(retval); |
1292 |
SDL_OutOfMemory(); |
1293 |
return NULL; |
1294 |
} |
1295 |
|
1308 |
/* Not resampling? It's an easy conversion (and maybe not even that!). */ |
1296 |
/* Not resampling? It's an easy conversion (and maybe not even that!). */ |
1309 |
if (src_rate == dst_rate) { |
1297 |
if (src_rate == dst_rate) { |
1310 |
retval->cvt_before_resampling.needed = SDL_FALSE; |
1298 |
retval->cvt_before_resampling.needed = SDL_FALSE; |
Lines 1325-1333
SDL_NewAudioStream(const SDL_AudioFormat src_format,
Link Here
|
1325 |
#endif |
1313 |
#endif |
1326 |
|
1314 |
|
1327 |
if (!retval->resampler_func) { |
1315 |
if (!retval->resampler_func) { |
1328 |
const int chans = (int) pre_resample_channels; |
1316 |
retval->resampler_state = SDL_calloc(retval->resampler_padding_samples, sizeof (float)); |
1329 |
const int len = ResamplerPadding(src_rate, dst_rate) * chans; |
|
|
1330 |
retval->resampler_state = SDL_calloc(len, sizeof (float)); |
1331 |
if (!retval->resampler_state) { |
1317 |
if (!retval->resampler_state) { |
1332 |
SDL_FreeAudioStream(retval); |
1318 |
SDL_FreeAudioStream(retval); |
1333 |
SDL_OutOfMemory(); |
1319 |
SDL_OutOfMemory(); |
Lines 1366-1372
int
Link Here
|
1366 |
SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen) |
1352 |
SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen) |
1367 |
{ |
1353 |
{ |
1368 |
int buflen = (int) _buflen; |
1354 |
int buflen = (int) _buflen; |
1369 |
const void *origbuf = buf; |
1355 |
int workbuflen; |
|
|
1356 |
Uint8 *workbuf; |
1357 |
Uint8 *resamplebuf = NULL; |
1358 |
int resamplebuflen = 0; |
1359 |
int neededpaddingbytes; |
1360 |
int paddingbytes; |
1370 |
|
1361 |
|
1371 |
/* !!! FIXME: several converters can take advantage of SIMD, but only |
1362 |
/* !!! FIXME: several converters can take advantage of SIMD, but only |
1372 |
!!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize() |
1363 |
!!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize() |
Lines 1376-1381
SDL_AudioStreamPut(SDL_AudioStream *stream, const void
Link Here
|
1376 |
!!! FIXME: isn't a multiple of 16. In these cases, we should chop off |
1367 |
!!! FIXME: isn't a multiple of 16. In these cases, we should chop off |
1377 |
!!! FIXME: a few samples at the end and convert them separately. */ |
1368 |
!!! FIXME: a few samples at the end and convert them separately. */ |
1378 |
|
1369 |
|
|
|
1370 |
#if DEBUG_AUDIOSTREAM |
1371 |
printf("AUDIOSTREAM: wants to put %d preconverted bytes\n", buflen); |
1372 |
#endif |
1373 |
|
1379 |
if (!stream) { |
1374 |
if (!stream) { |
1380 |
return SDL_InvalidParamError("stream"); |
1375 |
return SDL_InvalidParamError("stream"); |
1381 |
} else if (!buf) { |
1376 |
} else if (!buf) { |
Lines 1384-1443
SDL_AudioStreamPut(SDL_AudioStream *stream, const void
Link Here
|
1384 |
return 0; /* nothing to do. */ |
1379 |
return 0; /* nothing to do. */ |
1385 |
} else if ((buflen % stream->src_sample_frame_size) != 0) { |
1380 |
} else if ((buflen % stream->src_sample_frame_size) != 0) { |
1386 |
return SDL_SetError("Can't add partial sample frames"); |
1381 |
return SDL_SetError("Can't add partial sample frames"); |
|
|
1382 |
} else if (buflen < ((stream->resampler_padding_samples / stream->pre_resample_channels) * stream->src_sample_frame_size)) { |
1383 |
return SDL_SetError("Need to put a larger buffer"); |
1387 |
} |
1384 |
} |
1388 |
|
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 |
if (!stream->cvt_before_resampling.needed && |
1392 |
(stream->dst_rate == stream->src_rate) && |
1393 |
!stream->cvt_after_resampling.needed) { |
1394 |
#if DEBUG_AUDIOSTREAM |
1395 |
printf("AUDIOSTREAM: no conversion needed at all, queueing %d bytes.\n", buflen); |
1396 |
#endif |
1397 |
return SDL_WriteToDataQueue(stream->queue, buf, buflen); |
1398 |
} |
1399 |
|
1400 |
/* Make sure the work buffer can hold all the data we need at once... */ |
1401 |
workbuflen = buflen; |
1389 |
if (stream->cvt_before_resampling.needed) { |
1402 |
if (stream->cvt_before_resampling.needed) { |
1390 |
const int workbuflen = buflen * stream->cvt_before_resampling.len_mult; /* will be "* 1" if not needed */ |
1403 |
workbuflen *= stream->cvt_before_resampling.len_mult; |
1391 |
Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen); |
1404 |
} |
1392 |
if (workbuf == NULL) { |
1405 |
|
1393 |
return -1; /* probably out of memory. */ |
1406 |
if (stream->dst_rate != stream->src_rate) { |
1394 |
} |
1407 |
/* resamples can't happen in place, so make space for second buf. */ |
1395 |
SDL_assert(buf == origbuf); |
1408 |
const int framesize = stream->pre_resample_channels * sizeof (float); |
1396 |
SDL_memcpy(workbuf, buf, buflen); |
1409 |
const int frames = workbuflen / framesize; |
1397 |
stream->cvt_before_resampling.buf = workbuf; |
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; |
1398 |
stream->cvt_before_resampling.len = buflen; |
1439 |
stream->cvt_before_resampling.len = buflen; |
1399 |
if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) { |
1440 |
if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) { |
1400 |
return -1; /* uhoh! */ |
1441 |
return -1; /* uhoh! */ |
1401 |
} |
1442 |
} |
1402 |
buf = workbuf; |
|
|
1403 |
buflen = stream->cvt_before_resampling.len_cvt; |
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 |
1404 |
} |
1448 |
} |
1405 |
|
1449 |
|
1406 |
if (stream->dst_rate != stream->src_rate) { |
1450 |
if (stream->dst_rate != stream->src_rate) { |
1407 |
const int workbuflen = buflen * ((int) SDL_ceil(stream->rate_incr)); |
1451 |
/* save off some samples at the end; they are used for padding now so |
1408 |
Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen); |
1452 |
the resampler is coherent and then used at the start of the next |
1409 |
if (workbuf == NULL) { |
1453 |
put operation. Prepend last put operation's padding, too. */ |
1410 |
return -1; /* probably out of memory. */ |
1454 |
|
|
|
1455 |
/* prepend prior put's padding. :P */ |
1456 |
if (paddingbytes) { |
1457 |
SDL_memcpy(workbuf, stream->resampler_padding, paddingbytes); |
1458 |
buflen += paddingbytes; |
1411 |
} |
1459 |
} |
1412 |
/* don't SDL_memcpy(workbuf, buf, buflen) here; our resampler can work inplace or not, |
1460 |
|
1413 |
libsamplerate needs buffers to be separate; either way, avoid a copy here if possible. */ |
1461 |
/* save off the data at the end for the next run. */ |
1414 |
if (buf != origbuf) { |
1462 |
SDL_memcpy(stream->resampler_padding, workbuf + (buflen - neededpaddingbytes), neededpaddingbytes); |
1415 |
buf = workbuf; /* in case we realloc()'d the pointer. */ |
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; |
1416 |
} |
1470 |
} |
1417 |
buflen = stream->resampler_func(stream, buf, buflen, workbuf, workbuflen); |
1471 |
|
1418 |
buf = EnsureStreamBufferSize(stream, workbuflen); |
1472 |
#if DEBUG_AUDIOSTREAM |
1419 |
SDL_assert(buf != NULL); /* shouldn't be growing, just aligning. */ |
1473 |
printf("AUDIOSTREAM: After resampling we have %d bytes\n", buflen); |
|
|
1474 |
#endif |
1420 |
} |
1475 |
} |
1421 |
|
1476 |
|
1422 |
if (stream->cvt_after_resampling.needed) { |
1477 |
if (stream->cvt_after_resampling.needed && (buflen > 0)) { |
1423 |
const int workbuflen = buflen * stream->cvt_after_resampling.len_mult; /* will be "* 1" if not needed */ |
1478 |
stream->cvt_after_resampling.buf = resamplebuf; |
1424 |
Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen); |
|
|
1425 |
if (workbuf == NULL) { |
1426 |
return -1; /* probably out of memory. */ |
1427 |
} |
1428 |
if (buf == origbuf) { /* copy if we haven't before. */ |
1429 |
SDL_memcpy(workbuf, origbuf, buflen); |
1430 |
} |
1431 |
stream->cvt_after_resampling.buf = workbuf; |
1432 |
stream->cvt_after_resampling.len = buflen; |
1479 |
stream->cvt_after_resampling.len = buflen; |
1433 |
if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) { |
1480 |
if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) { |
1434 |
return -1; /* uhoh! */ |
1481 |
return -1; /* uhoh! */ |
1435 |
} |
1482 |
} |
1436 |
buf = workbuf; |
|
|
1437 |
buflen = stream->cvt_after_resampling.len_cvt; |
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 |
1438 |
} |
1488 |
} |
1439 |
|
1489 |
|
1440 |
return SDL_WriteToDataQueue(stream->queue, buf, buflen); |
1490 |
#if DEBUG_AUDIOSTREAM |
|
|
1491 |
printf("AUDIOSTREAM: Final output is %d bytes\n", buflen); |
1492 |
#endif |
1493 |
|
1494 |
/* resamplebuf holds the final output, even if we didn't resample. */ |
1495 |
return buflen ? SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen) : 0; |
1441 |
} |
1496 |
} |
1442 |
|
1497 |
|
1443 |
void |
1498 |
void |
Lines 1450-1455
SDL_AudioStreamClear(SDL_AudioStream *stream)
Link Here
|
1450 |
if (stream->reset_resampler_func) { |
1505 |
if (stream->reset_resampler_func) { |
1451 |
stream->reset_resampler_func(stream); |
1506 |
stream->reset_resampler_func(stream); |
1452 |
} |
1507 |
} |
|
|
1508 |
stream->first_run = SDL_TRUE; |
1453 |
} |
1509 |
} |
1454 |
} |
1510 |
} |
1455 |
|
1511 |
|
Lines 1458-1463
SDL_AudioStreamClear(SDL_AudioStream *stream)
Link Here
|
1458 |
int |
1514 |
int |
1459 |
SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len) |
1515 |
SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len) |
1460 |
{ |
1516 |
{ |
|
|
1517 |
#if DEBUG_AUDIOSTREAM |
1518 |
printf("AUDIOSTREAM: want to get %u converted bytes\n", (unsigned int) len); |
1519 |
#endif |
1520 |
|
1461 |
if (!stream) { |
1521 |
if (!stream) { |
1462 |
return SDL_InvalidParamError("stream"); |
1522 |
return SDL_InvalidParamError("stream"); |
1463 |
} else if (!buf) { |
1523 |
} else if (!buf) { |
Lines 1488-1493
SDL_FreeAudioStream(SDL_AudioStream *stream)
Link Here
|
1488 |
} |
1548 |
} |
1489 |
SDL_FreeDataQueue(stream->queue); |
1549 |
SDL_FreeDataQueue(stream->queue); |
1490 |
SDL_free(stream->work_buffer_base); |
1550 |
SDL_free(stream->work_buffer_base); |
|
|
1551 |
SDL_free(stream->resampler_padding); |
1491 |
SDL_free(stream); |
1552 |
SDL_free(stream); |
1492 |
} |
1553 |
} |
1493 |
} |
1554 |
} |