src/audio/SDL_audiocvt.c
changeset 11632 385312bd6594
parent 11631 150b925ddfbb
child 11634 ced7925b7a95
equal deleted inserted replaced
11631:150b925ddfbb 11632:385312bd6594
  1081 {
  1081 {
  1082     SDL_AudioCVT cvt_before_resampling;
  1082     SDL_AudioCVT cvt_before_resampling;
  1083     SDL_AudioCVT cvt_after_resampling;
  1083     SDL_AudioCVT cvt_after_resampling;
  1084     SDL_DataQueue *queue;
  1084     SDL_DataQueue *queue;
  1085     SDL_bool first_run;
  1085     SDL_bool first_run;
       
  1086     Uint8 *staging_buffer;
       
  1087     int staging_buffer_size;
       
  1088     int staging_buffer_filled;
  1086     Uint8 *work_buffer_base;  /* maybe unaligned pointer from SDL_realloc(). */
  1089     Uint8 *work_buffer_base;  /* maybe unaligned pointer from SDL_realloc(). */
  1087     int work_buffer_len;
  1090     int work_buffer_len;
  1088     int src_sample_frame_size;
  1091     int src_sample_frame_size;
  1089     SDL_AudioFormat src_format;
  1092     SDL_AudioFormat src_format;
  1090     Uint8 src_channels;
  1093     Uint8 src_channels;
  1291         SDL_FreeAudioStream(retval);
  1294         SDL_FreeAudioStream(retval);
  1292         SDL_OutOfMemory();
  1295         SDL_OutOfMemory();
  1293         return NULL;
  1296         return NULL;
  1294     }
  1297     }
  1295 
  1298 
  1296     /* Not resampling? It's an easy conversion (and maybe not even that!). */
  1299     retval->staging_buffer_size = ((retval->resampler_padding_samples / retval->pre_resample_channels) * retval->src_sample_frame_size);
       
  1300     if (retval->staging_buffer_size > 0) {
       
  1301         retval->staging_buffer = (Uint8 *) SDL_malloc(retval->staging_buffer_size);
       
  1302         if (retval->resampler_padding == NULL) {
       
  1303             SDL_FreeAudioStream(retval);
       
  1304             SDL_OutOfMemory();
       
  1305             return NULL;
       
  1306         }
       
  1307     }
       
  1308 
       
  1309     /* Not resampling? It's an easy conversion (and maybe not even that!) */
  1297     if (src_rate == dst_rate) {
  1310     if (src_rate == dst_rate) {
  1298         retval->cvt_before_resampling.needed = SDL_FALSE;
  1311         retval->cvt_before_resampling.needed = SDL_FALSE;
  1299         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1312         if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
  1300             SDL_FreeAudioStream(retval);
  1313             SDL_FreeAudioStream(retval);
  1301             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1314             return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
  1346     }
  1359     }
  1347 
  1360 
  1348     return retval;
  1361     return retval;
  1349 }
  1362 }
  1350 
  1363 
  1351 int
  1364 static int
  1352 SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
  1365 SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len)
  1353 {
  1366 {
  1354     int buflen = len;
  1367     int buflen = len;
  1355     int workbuflen;
  1368     int workbuflen;
  1356     Uint8 *workbuf;
  1369     Uint8 *workbuf;
  1357     Uint8 *resamplebuf = NULL;
  1370     Uint8 *resamplebuf = NULL;
  1365        !!! FIXME:  converters will iterate over the data backwards if
  1378        !!! FIXME:  converters will iterate over the data backwards if
  1366        !!! FIXME:  the output grows, and this means we won't align if buflen
  1379        !!! FIXME:  the output grows, and this means we won't align if buflen
  1367        !!! FIXME:  isn't a multiple of 16. In these cases, we should chop off
  1380        !!! FIXME:  isn't a multiple of 16. In these cases, we should chop off
  1368        !!! FIXME:  a few samples at the end and convert them separately. */
  1381        !!! FIXME:  a few samples at the end and convert them separately. */
  1369 
  1382 
  1370     #if DEBUG_AUDIOSTREAM
       
  1371     printf("AUDIOSTREAM: wants to put %d preconverted bytes\n", buflen);
       
  1372     #endif
       
  1373 
       
  1374     if (!stream) {
       
  1375         return SDL_InvalidParamError("stream");
       
  1376     } else if (!buf) {
       
  1377         return SDL_InvalidParamError("buf");
       
  1378     } else if (buflen == 0) {
       
  1379         return 0;  /* nothing to do. */
       
  1380     } else if ((buflen % stream->src_sample_frame_size) != 0) {
       
  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");
       
  1384     }
       
  1385 
       
  1386     /* no padding prepended on first run. */
  1383     /* no padding prepended on first run. */
  1387     neededpaddingbytes = stream->resampler_padding_samples * sizeof (float);
  1384     neededpaddingbytes = stream->resampler_padding_samples * sizeof (float);
  1388     paddingbytes = stream->first_run ? 0 : neededpaddingbytes;
  1385     paddingbytes = stream->first_run ? 0 : neededpaddingbytes;
  1389     stream->first_run = SDL_FALSE;
  1386     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 
  1387 
  1400     /* Make sure the work buffer can hold all the data we need at once... */
  1388     /* Make sure the work buffer can hold all the data we need at once... */
  1401     workbuflen = buflen;
  1389     workbuflen = buflen;
  1402     if (stream->cvt_before_resampling.needed) {
  1390     if (stream->cvt_before_resampling.needed) {
  1403         workbuflen *= stream->cvt_before_resampling.len_mult;
  1391         workbuflen *= stream->cvt_before_resampling.len_mult;
  1493 
  1481 
  1494     /* resamplebuf holds the final output, even if we didn't resample. */
  1482     /* resamplebuf holds the final output, even if we didn't resample. */
  1495     return buflen ? SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen) : 0;
  1483     return buflen ? SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen) : 0;
  1496 }
  1484 }
  1497 
  1485 
       
  1486 int
       
  1487 SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
       
  1488 {
       
  1489     /* !!! FIXME: several converters can take advantage of SIMD, but only
       
  1490        !!! FIXME:  if the data is aligned to 16 bytes. EnsureStreamBufferSize()
       
  1491        !!! FIXME:  guarantees the buffer will align, but the
       
  1492        !!! FIXME:  converters will iterate over the data backwards if
       
  1493        !!! FIXME:  the output grows, and this means we won't align if buflen
       
  1494        !!! FIXME:  isn't a multiple of 16. In these cases, we should chop off
       
  1495        !!! FIXME:  a few samples at the end and convert them separately. */
       
  1496 
       
  1497     #if DEBUG_AUDIOSTREAM
       
  1498     printf("AUDIOSTREAM: wants to put %d preconverted bytes\n", buflen);
       
  1499     #endif
       
  1500 
       
  1501     if (!stream) {
       
  1502         return SDL_InvalidParamError("stream");
       
  1503     } else if (!buf) {
       
  1504         return SDL_InvalidParamError("buf");
       
  1505     } else if (len == 0) {
       
  1506         return 0;  /* nothing to do. */
       
  1507     } else if ((len % stream->src_sample_frame_size) != 0) {
       
  1508         return SDL_SetError("Can't add partial sample frames");
       
  1509     }
       
  1510 
       
  1511     if (!stream->cvt_before_resampling.needed &&
       
  1512         (stream->dst_rate == stream->src_rate) &&
       
  1513         !stream->cvt_after_resampling.needed) {
       
  1514         #if DEBUG_AUDIOSTREAM
       
  1515         printf("AUDIOSTREAM: no conversion needed at all, queueing %d bytes.\n", len);
       
  1516         #endif
       
  1517         return SDL_WriteToDataQueue(stream->queue, buf, len);
       
  1518     }
       
  1519 
       
  1520     while (len > 0) {
       
  1521         int amount;
       
  1522 
       
  1523         /* If we don't have a staging buffer or we're given enough data that
       
  1524            we don't need to store it for later, skip the staging process.
       
  1525          */
       
  1526         if (!stream->staging_buffer_filled && len >= stream->staging_buffer_size) {
       
  1527             return SDL_AudioStreamPutInternal(stream, buf, len);
       
  1528         }
       
  1529 
       
  1530         /* If there's not enough data to fill the staging buffer, just save it */
       
  1531         if ((stream->staging_buffer_filled + len) < stream->staging_buffer_size) {
       
  1532             SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, len);
       
  1533             stream->staging_buffer_filled += len;
       
  1534             return 0;
       
  1535         }
       
  1536  
       
  1537         /* Fill the staging buffer, process it, and continue */
       
  1538         amount = (stream->staging_buffer_size - stream->staging_buffer_filled);
       
  1539         SDL_assert(amount > 0);
       
  1540         SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, amount);
       
  1541         stream->staging_buffer_filled = 0;
       
  1542         if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size) < 0) {
       
  1543             return -1;
       
  1544         }
       
  1545         buf = (void *)((Uint8 *)buf + amount);
       
  1546         len -= amount;
       
  1547     }
       
  1548     return 0;
       
  1549 }
       
  1550 
  1498 /* get converted/resampled data from the stream */
  1551 /* get converted/resampled data from the stream */
  1499 int
  1552 int
  1500 SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len)
  1553 SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len)
  1501 {
  1554 {
  1502     #if DEBUG_AUDIOSTREAM
  1555     #if DEBUG_AUDIOSTREAM
  1544     if (stream) {
  1597     if (stream) {
  1545         if (stream->cleanup_resampler_func) {
  1598         if (stream->cleanup_resampler_func) {
  1546             stream->cleanup_resampler_func(stream);
  1599             stream->cleanup_resampler_func(stream);
  1547         }
  1600         }
  1548         SDL_FreeDataQueue(stream->queue);
  1601         SDL_FreeDataQueue(stream->queue);
       
  1602         SDL_free(stream->staging_buffer);
  1549         SDL_free(stream->work_buffer_base);
  1603         SDL_free(stream->work_buffer_base);
  1550         SDL_free(stream->resampler_padding);
  1604         SDL_free(stream->resampler_padding);
  1551         SDL_free(stream);
  1605         SDL_free(stream);
  1552     }
  1606     }
  1553 }
  1607 }