SDL 2.0
SDL_audiocvt.c File Reference
#include "../SDL_internal.h"
#include "SDL.h"
#include "SDL_audio.h"
#include "SDL_audio_c.h"
#include "SDL_loadso.h"
#include "SDL_assert.h"
#include "../SDL_dataqueue.h"
#include "SDL_cpuinfo.h"
+ Include dependency graph for SDL_audiocvt.c:

Go to the source code of this file.

Data Structures

struct  SDL_AudioStream
 

Macros

#define DEBUG_AUDIOSTREAM   0
 
#define RESAMPLER_ZERO_CROSSINGS   5
 
#define RESAMPLER_BITS_PER_SAMPLE   16
 
#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING   (1 << ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1))
 
#define RESAMPLER_FILTER_SIZE   ((RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS) + 1)
 
#define CASESWAP(b)
 
#define RESAMPLER_FUNCS(chans)
 

Typedefs

typedef int(* SDL_ResampleAudioStreamFunc) (SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen)
 
typedef void(* SDL_ResetAudioStreamResamplerFunc) (SDL_AudioStream *stream)
 
typedef void(* SDL_CleanupAudioStreamResamplerFunc) (SDL_AudioStream *stream)
 

Functions

static void SDL_ConvertStereoToMono (SDL_AudioCVT *cvt, SDL_AudioFormat format)
 
static void SDL_Convert51ToStereo (SDL_AudioCVT *cvt, SDL_AudioFormat format)
 
static void SDL_ConvertQuadToStereo (SDL_AudioCVT *cvt, SDL_AudioFormat format)
 
static void SDL_Convert71To51 (SDL_AudioCVT *cvt, SDL_AudioFormat format)
 
static void SDL_Convert51ToQuad (SDL_AudioCVT *cvt, SDL_AudioFormat format)
 
static void SDL_ConvertMonoToStereo (SDL_AudioCVT *cvt, SDL_AudioFormat format)
 
static void SDL_ConvertStereoTo51 (SDL_AudioCVT *cvt, SDL_AudioFormat format)
 
static void SDL_ConvertQuadTo51 (SDL_AudioCVT *cvt, SDL_AudioFormat format)
 
static void SDL_ConvertStereoToQuad (SDL_AudioCVT *cvt, SDL_AudioFormat format)
 
static void SDL_Convert51To71 (SDL_AudioCVT *cvt, SDL_AudioFormat format)
 
static double bessel (const double x)
 
static void kaiser_and_sinc (float *table, float *diffs, const int tablelen, const double beta)
 
int SDL_PrepareResampleFilter (void)
 
void SDL_FreeResampleFilter (void)
 
static int ResamplerPadding (const int inrate, const int outrate)
 
static int SDL_ResampleAudio (const int chans, const int inrate, const int outrate, const float *lpadding, const float *rpadding, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
 
int SDL_ConvertAudio (SDL_AudioCVT *cvt)
 
static void SDL_Convert_Byteswap (SDL_AudioCVT *cvt, SDL_AudioFormat format)
 
static int SDL_AddAudioCVTFilter (SDL_AudioCVT *cvt, const SDL_AudioFilter filter)
 
static int SDL_BuildAudioTypeCVTToFloat (SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
 
static int SDL_BuildAudioTypeCVTFromFloat (SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
 
static void SDL_ResampleCVT (SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
 
static SDL_AudioFilter ChooseCVTResampler (const int dst_channels)
 
static int SDL_BuildAudioResampleCVT (SDL_AudioCVT *cvt, const int dst_channels, const int src_rate, const int dst_rate)
 
static SDL_bool SDL_SupportedAudioFormat (const SDL_AudioFormat fmt)
 
static SDL_bool SDL_SupportedChannelCount (const int channels)
 
int SDL_BuildAudioCVT (SDL_AudioCVT *cvt, SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate, SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
 
static Uint8EnsureStreamBufferSize (SDL_AudioStream *stream, const int newlen)
 
static int SDL_ResampleAudioStream (SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
 
static void SDL_ResetAudioStreamResampler (SDL_AudioStream *stream)
 
static void SDL_CleanupAudioStreamResampler (SDL_AudioStream *stream)
 
SDL_AudioStream * SDL_NewAudioStream (const SDL_AudioFormat src_format, const Uint8 src_channels, const int src_rate, const SDL_AudioFormat dst_format, const Uint8 dst_channels, const int dst_rate)
 
static int SDL_AudioStreamPutInternal (SDL_AudioStream *stream, const void *buf, int len, int *maxputbytes)
 
int SDL_AudioStreamPut (SDL_AudioStream *stream, const void *buf, int len)
 
int SDL_AudioStreamFlush (SDL_AudioStream *stream)
 
int SDL_AudioStreamGet (SDL_AudioStream *stream, void *buf, int len)
 
int SDL_AudioStreamAvailable (SDL_AudioStream *stream)
 
void SDL_AudioStreamClear (SDL_AudioStream *stream)
 
void SDL_FreeAudioStream (SDL_AudioStream *stream)
 

Variables

static SDL_SpinLock ResampleFilterSpinlock = 0
 
static float * ResamplerFilter = NULL
 
static float * ResamplerFilterDifference = NULL
 

Macro Definition Documentation

◆ CASESWAP

#define CASESWAP (   b)
Value:
case b: { \
Uint##b *ptr = (Uint##b *) cvt->buf; \
int i; \
for (i = cvt->len_cvt / sizeof (*ptr); i; --i, ++ptr) { \
*ptr = SDL_Swap##b(*ptr); \
} \
break; \
}
GLboolean GLboolean GLboolean b
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50

◆ DEBUG_AUDIOSTREAM

#define DEBUG_AUDIOSTREAM   0

Definition at line 37 of file SDL_audiocvt.c.

◆ RESAMPLER_BITS_PER_SAMPLE

#define RESAMPLER_BITS_PER_SAMPLE   16

Definition at line 381 of file SDL_audiocvt.c.

◆ RESAMPLER_FILTER_SIZE

#define RESAMPLER_FILTER_SIZE   ((RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS) + 1)

Definition at line 383 of file SDL_audiocvt.c.

◆ RESAMPLER_FUNCS

#define RESAMPLER_FUNCS (   chans)
Value:
static void SDLCALL \
SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
SDL_ResampleCVT(cvt, chans, format); \
}
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
A structure to hold a set of audio conversion filters and buffers.
Definition: SDL_audio.h:227

Definition at line 754 of file SDL_audiocvt.c.

◆ RESAMPLER_SAMPLES_PER_ZERO_CROSSING

#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING   (1 << ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1))

Definition at line 382 of file SDL_audiocvt.c.

◆ RESAMPLER_ZERO_CROSSINGS

#define RESAMPLER_ZERO_CROSSINGS   5

Definition at line 380 of file SDL_audiocvt.c.

Typedef Documentation

◆ SDL_CleanupAudioStreamResamplerFunc

typedef void(* SDL_CleanupAudioStreamResamplerFunc) (SDL_AudioStream *stream)

Definition at line 1091 of file SDL_audiocvt.c.

◆ SDL_ResampleAudioStreamFunc

typedef int(* SDL_ResampleAudioStreamFunc) (SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen)

Definition at line 1089 of file SDL_audiocvt.c.

◆ SDL_ResetAudioStreamResamplerFunc

typedef void(* SDL_ResetAudioStreamResamplerFunc) (SDL_AudioStream *stream)

Definition at line 1090 of file SDL_audiocvt.c.

Function Documentation

◆ bessel()

static double bessel ( const double  x)
static

Definition at line 387 of file SDL_audiocvt.c.

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}
#define SDL_pow
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
GLfloat f
@ SDL_TRUE
Definition: SDL_stdinc.h:164

References i, SDL_pow, and SDL_TRUE.

Referenced by kaiser_and_sinc().

◆ ChooseCVTResampler()

static SDL_AudioFilter ChooseCVTResampler ( const int  dst_channels)
static

Definition at line 767 of file SDL_audiocvt.c.

768{
769 switch (dst_channels) {
770 case 1: return SDL_ResampleCVT_c1;
771 case 2: return SDL_ResampleCVT_c2;
772 case 4: return SDL_ResampleCVT_c4;
773 case 6: return SDL_ResampleCVT_c6;
774 case 8: return SDL_ResampleCVT_c8;
775 default: break;
776 }
777
778 return NULL;
779}
#define NULL
Definition: begin_code.h:167

References NULL.

Referenced by SDL_BuildAudioResampleCVT().

◆ EnsureStreamBufferSize()

static Uint8 * EnsureStreamBufferSize ( SDL_AudioStream *  stream,
const int  newlen 
)
static

Definition at line 1124 of file SDL_audiocvt.c.

1125{
1126 Uint8 *ptr;
1127 size_t offset;
1128
1129 if (stream->work_buffer_len >= newlen) {
1130 ptr = stream->work_buffer_base;
1131 } else {
1132 ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32);
1133 if (!ptr) {
1135 return NULL;
1136 }
1137 /* Make sure we're aligned to 16 bytes for SIMD code. */
1138 stream->work_buffer_base = ptr;
1139 stream->work_buffer_len = newlen;
1140 }
1141
1142 offset = ((size_t) ptr) & 15;
1143 return offset ? ptr + (16 - offset) : ptr;
1144}
unsigned int size_t
#define SDL_realloc
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
GLuint GLuint stream
GLintptr offset
uint8_t Uint8
Definition: SDL_stdinc.h:179

References NULL, SDL_OutOfMemory, and SDL_realloc.

Referenced by SDL_AudioStreamPutInternal().

◆ kaiser_and_sinc()

static void kaiser_and_sinc ( float *  table,
float *  diffs,
const int  tablelen,
const double  beta 
)
static

Definition at line 409 of file SDL_audiocvt.c.

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}
#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING
Definition: SDL_audiocvt.c:382
static double bessel(const double x)
Definition: SDL_audiocvt.c:387
#define SDL_sqrt
#define SDL_sinf
GLenum GLsizei GLenum GLenum const void * table

References bessel(), i, RESAMPLER_SAMPLES_PER_ZERO_CROSSING, SDL_pow, SDL_sinf, and SDL_sqrt.

Referenced by SDL_PrepareResampleFilter().

◆ ResamplerPadding()

static int ResamplerPadding ( const int  inrate,
const int  outrate 
)
static

Definition at line 473 of file SDL_audiocvt.c.

474{
475 if (inrate == outrate) {
476 return 0;
477 } else if (inrate > outrate) {
478 return (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate)));
479 }
481}
#define SDL_ceil

References RESAMPLER_SAMPLES_PER_ZERO_CROSSING, and SDL_ceil.

Referenced by SDL_NewAudioStream(), SDL_ResampleAudio(), and SDL_ResampleCVT().

◆ SDL_AddAudioCVTFilter()

static int SDL_AddAudioCVTFilter ( SDL_AudioCVT cvt,
const SDL_AudioFilter  filter 
)
static

Definition at line 601 of file SDL_audiocvt.c.

602{
604 return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS);
605 }
606 if (filter == NULL) {
607 return SDL_SetError("Audio filter pointer is NULL");
608 }
609 cvt->filters[cvt->filter_index++] = filter;
610 cvt->filters[cvt->filter_index] = NULL; /* Moving terminator */
611 return 0;
612}
#define SDL_AUDIOCVT_MAX_FILTERS
Upper limit of filters in SDL_AudioCVT.
Definition: SDL_audio.h:203
#define SDL_SetError
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
int filter_index
Definition: SDL_audio.h:238
SDL_AudioFilter filters[SDL_AUDIOCVT_MAX_FILTERS+1]
Definition: SDL_audio.h:237

References SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, NULL, SDL_AUDIOCVT_MAX_FILTERS, and SDL_SetError.

Referenced by SDL_BuildAudioCVT(), SDL_BuildAudioResampleCVT(), SDL_BuildAudioTypeCVTFromFloat(), and SDL_BuildAudioTypeCVTToFloat().

◆ SDL_AudioStreamAvailable()

int SDL_AudioStreamAvailable ( SDL_AudioStream *  stream)

Get the number of converted/resampled bytes available. The stream may be buffering data behind the scenes until it has enough to resample correctly, so this number might be lower than what you expect, or even be zero. Add more data or flush the stream if you need the data now.

See also
SDL_NewAudioStream
SDL_AudioStreamPut
SDL_AudioStreamGet
SDL_AudioStreamFlush
SDL_AudioStreamClear
SDL_FreeAudioStream

Definition at line 1646 of file SDL_audiocvt.c.

1647{
1648 return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
1649}
size_t SDL_CountDataQueue(SDL_DataQueue *queue)

References SDL_CountDataQueue().

◆ SDL_AudioStreamClear()

void SDL_AudioStreamClear ( SDL_AudioStream *  stream)

Clear any pending data in the stream without converting it

See also
SDL_NewAudioStream
SDL_AudioStreamPut
SDL_AudioStreamGet
SDL_AudioStreamAvailable
SDL_AudioStreamFlush
SDL_FreeAudioStream

Definition at line 1652 of file SDL_audiocvt.c.

1653{
1654 if (!stream) {
1655 SDL_InvalidParamError("stream");
1656 } else {
1657 SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
1658 if (stream->reset_resampler_func) {
1659 stream->reset_resampler_func(stream);
1660 }
1661 stream->first_run = SDL_TRUE;
1662 stream->staging_buffer_filled = 0;
1663 }
1664}
void SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack)
Definition: SDL_dataqueue.c:98
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54

References SDL_ClearDataQueue(), SDL_InvalidParamError, and SDL_TRUE.

◆ SDL_AudioStreamFlush()

int SDL_AudioStreamFlush ( SDL_AudioStream *  stream)

Tell the stream that you're done sending data, and anything being buffered should be converted/resampled and made available immediately.

It is legal to add more data to a stream after flushing, but there will be audio gaps in the output. Generally this is intended to signal the end of input, so the complete output becomes available.

See also
SDL_NewAudioStream
SDL_AudioStreamPut
SDL_AudioStreamGet
SDL_AudioStreamAvailable
SDL_AudioStreamClear
SDL_FreeAudioStream

Definition at line 1571 of file SDL_audiocvt.c.

1572{
1573 if (!stream) {
1574 return SDL_InvalidParamError("stream");
1575 }
1576
1577 #if DEBUG_AUDIOSTREAM
1578 printf("AUDIOSTREAM: flushing! staging_buffer_filled=%d bytes\n", stream->staging_buffer_filled);
1579 #endif
1580
1581 /* shouldn't use a staging buffer if we're not resampling. */
1582 SDL_assert((stream->dst_rate != stream->src_rate) || (stream->staging_buffer_filled == 0));
1583
1584 if (stream->staging_buffer_filled > 0) {
1585 /* push the staging buffer + silence. We need to flush out not just
1586 the staging buffer, but the piece that the stream was saving off
1587 for right-side resampler padding. */
1588 const SDL_bool first_run = stream->first_run;
1589 const int filled = stream->staging_buffer_filled;
1590 int actual_input_frames = filled / stream->src_sample_frame_size;
1591 if (!first_run)
1592 actual_input_frames += stream->resampler_padding_samples / stream->pre_resample_channels;
1593
1594 if (actual_input_frames > 0) { /* don't bother if nothing to flush. */
1595 /* This is how many bytes we're expecting without silence appended. */
1596 int flush_remaining = ((int) SDL_ceil(actual_input_frames * stream->rate_incr)) * stream->dst_sample_frame_size;
1597
1599 printf("AUDIOSTREAM: flushing with padding to get max %d bytes!\n", flush_remaining);
1600 #endif
1601
1602 SDL_memset(stream->staging_buffer + filled, '\0', stream->staging_buffer_size - filled);
1603 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
1604 return -1;
1605 }
1606
1607 /* we have flushed out (or initially filled) the pending right-side
1608 resampler padding, but we need to push more silence to guarantee
1609 the staging buffer is fully flushed out, too. */
1610 SDL_memset(stream->staging_buffer, '\0', filled);
1611 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
1612 return -1;
1613 }
1614 }
1615 }
1616
1617 stream->staging_buffer_filled = 0;
1618 stream->first_run = SDL_TRUE;
1619
1620 return 0;
1621}
#define SDL_assert(condition)
Definition: SDL_assert.h:169
static int SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len, int *maxputbytes)
#define DEBUG_AUDIOSTREAM
Definition: SDL_audiocvt.c:37
#define SDL_memset
SDL_bool
Definition: SDL_stdinc.h:162

References DEBUG_AUDIOSTREAM, SDL_assert, SDL_AudioStreamPutInternal(), SDL_ceil, SDL_InvalidParamError, SDL_memset, and SDL_TRUE.

◆ SDL_AudioStreamGet()

int SDL_AudioStreamGet ( SDL_AudioStream *  stream,
void buf,
int  len 
)

Get converted/resampled data from the stream

Parameters
streamThe stream the audio is being requested from
bufA buffer to fill with audio data
lenThe maximum number of bytes to fill
Returns
The number of bytes read from the stream, or -1 on error
See also
SDL_NewAudioStream
SDL_AudioStreamPut
SDL_AudioStreamAvailable
SDL_AudioStreamFlush
SDL_AudioStreamClear
SDL_FreeAudioStream

Definition at line 1625 of file SDL_audiocvt.c.

1626{
1627 #if DEBUG_AUDIOSTREAM
1628 printf("AUDIOSTREAM: want to get %d converted bytes\n", len);
1629 #endif
1630
1631 if (!stream) {
1632 return SDL_InvalidParamError("stream");
1633 } else if (!buf) {
1634 return SDL_InvalidParamError("buf");
1635 } else if (len <= 0) {
1636 return 0; /* nothing to do. */
1637 } else if ((len % stream->dst_sample_frame_size) != 0) {
1638 return SDL_SetError("Can't request partial sample frames");
1639 }
1640
1641 return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
1642}
size_t SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
GLenum GLsizei len
GLenum GLuint GLenum GLsizei const GLchar * buf

References SDL_InvalidParamError, SDL_ReadFromDataQueue(), and SDL_SetError.

◆ SDL_AudioStreamPut()

int SDL_AudioStreamPut ( SDL_AudioStream *  stream,
const void buf,
int  len 
)

Add data to be converted/resampled to the stream

Parameters
streamThe stream the audio data is being added to
bufA pointer to the audio data to add
lenThe number of bytes to write to the stream
Returns
0 on success, or -1 on error.
See also
SDL_NewAudioStream
SDL_AudioStreamGet
SDL_AudioStreamAvailable
SDL_AudioStreamFlush
SDL_AudioStreamClear
SDL_FreeAudioStream

Definition at line 1507 of file SDL_audiocvt.c.

1508{
1509 /* !!! FIXME: several converters can take advantage of SIMD, but only
1510 !!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
1511 !!! FIXME: guarantees the buffer will align, but the
1512 !!! FIXME: converters will iterate over the data backwards if
1513 !!! FIXME: the output grows, and this means we won't align if buflen
1514 !!! FIXME: isn't a multiple of 16. In these cases, we should chop off
1515 !!! FIXME: a few samples at the end and convert them separately. */
1516
1517 #if DEBUG_AUDIOSTREAM
1518 printf("AUDIOSTREAM: wants to put %d preconverted bytes\n", buflen);
1519 #endif
1520
1521 if (!stream) {
1522 return SDL_InvalidParamError("stream");
1523 } else if (!buf) {
1524 return SDL_InvalidParamError("buf");
1525 } else if (len == 0) {
1526 return 0; /* nothing to do. */
1527 } else if ((len % stream->src_sample_frame_size) != 0) {
1528 return SDL_SetError("Can't add partial sample frames");
1529 }
1530
1531 if (!stream->cvt_before_resampling.needed &&
1532 (stream->dst_rate == stream->src_rate) &&
1533 !stream->cvt_after_resampling.needed) {
1534 #if DEBUG_AUDIOSTREAM
1535 printf("AUDIOSTREAM: no conversion needed at all, queueing %d bytes.\n", len);
1536 #endif
1537 return SDL_WriteToDataQueue(stream->queue, buf, len);
1538 }
1539
1540 while (len > 0) {
1541 int amount;
1542
1543 /* If we don't have a staging buffer or we're given enough data that
1544 we don't need to store it for later, skip the staging process.
1545 */
1546 if (!stream->staging_buffer_filled && len >= stream->staging_buffer_size) {
1548 }
1549
1550 /* If there's not enough data to fill the staging buffer, just save it */
1551 if ((stream->staging_buffer_filled + len) < stream->staging_buffer_size) {
1552 SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, len);
1553 stream->staging_buffer_filled += len;
1554 return 0;
1555 }
1556
1557 /* Fill the staging buffer, process it, and continue */
1558 amount = (stream->staging_buffer_size - stream->staging_buffer_filled);
1559 SDL_assert(amount > 0);
1560 SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, amount);
1561 stream->staging_buffer_filled = 0;
1562 if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, NULL) < 0) {
1563 return -1;
1564 }
1565 buf = (void *)((Uint8 *)buf + amount);
1566 len -= amount;
1567 }
1568 return 0;
1569}
int SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *_data, const size_t _len)
#define SDL_memcpy

References NULL, SDL_assert, SDL_AudioStreamPutInternal(), SDL_InvalidParamError, SDL_memcpy, SDL_SetError, and SDL_WriteToDataQueue().

◆ SDL_AudioStreamPutInternal()

static int SDL_AudioStreamPutInternal ( SDL_AudioStream *  stream,
const void buf,
int  len,
int *  maxputbytes 
)
static

Definition at line 1378 of file SDL_audiocvt.c.

1379{
1380 int buflen = len;
1381 int workbuflen;
1382 Uint8 *workbuf;
1383 Uint8 *resamplebuf = NULL;
1384 int resamplebuflen = 0;
1385 int neededpaddingbytes;
1386 int paddingbytes;
1387
1388 /* !!! FIXME: several converters can take advantage of SIMD, but only
1389 !!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
1390 !!! FIXME: guarantees the buffer will align, but the
1391 !!! FIXME: converters will iterate over the data backwards if
1392 !!! FIXME: the output grows, and this means we won't align if buflen
1393 !!! FIXME: isn't a multiple of 16. In these cases, we should chop off
1394 !!! FIXME: a few samples at the end and convert them separately. */
1395
1396 /* no padding prepended on first run. */
1397 neededpaddingbytes = stream->resampler_padding_samples * sizeof (float);
1398 paddingbytes = stream->first_run ? 0 : neededpaddingbytes;
1399 stream->first_run = SDL_FALSE;
1400
1401 /* Make sure the work buffer can hold all the data we need at once... */
1402 workbuflen = buflen;
1403 if (stream->cvt_before_resampling.needed) {
1404 workbuflen *= stream->cvt_before_resampling.len_mult;
1405 }
1406
1407 if (stream->dst_rate != stream->src_rate) {
1408 /* resamples can't happen in place, so make space for second buf. */
1409 const int framesize = stream->pre_resample_channels * sizeof (float);
1410 const int frames = workbuflen / framesize;
1411 resamplebuflen = ((int) SDL_ceil(frames * stream->rate_incr)) * framesize;
1412 #if DEBUG_AUDIOSTREAM
1413 printf("AUDIOSTREAM: will resample %d bytes to %d (ratio=%.6f)\n", workbuflen, resamplebuflen, stream->rate_incr);
1414 #endif
1415 workbuflen += resamplebuflen;
1416 }
1417
1418 if (stream->cvt_after_resampling.needed) {
1419 /* !!! FIXME: buffer might be big enough already? */
1420 workbuflen *= stream->cvt_after_resampling.len_mult;
1421 }
1422
1423 workbuflen += neededpaddingbytes;
1424
1425 #if DEBUG_AUDIOSTREAM
1426 printf("AUDIOSTREAM: Putting %d bytes of preconverted audio, need %d byte work buffer\n", buflen, workbuflen);
1427 #endif
1428
1429 workbuf = EnsureStreamBufferSize(stream, workbuflen);
1430 if (!workbuf) {
1431 return -1; /* probably out of memory. */
1432 }
1433
1434 resamplebuf = workbuf; /* default if not resampling. */
1435
1436 SDL_memcpy(workbuf + paddingbytes, buf, buflen);
1437
1438 if (stream->cvt_before_resampling.needed) {
1439 stream->cvt_before_resampling.buf = workbuf + paddingbytes;
1440 stream->cvt_before_resampling.len = buflen;
1441 if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
1442 return -1; /* uhoh! */
1443 }
1444 buflen = stream->cvt_before_resampling.len_cvt;
1445
1446 #if DEBUG_AUDIOSTREAM
1447 printf("AUDIOSTREAM: After initial conversion we have %d bytes\n", buflen);
1448 #endif
1449 }
1450
1451 if (stream->dst_rate != stream->src_rate) {
1452 /* save off some samples at the end; they are used for padding now so
1453 the resampler is coherent and then used at the start of the next
1454 put operation. Prepend last put operation's padding, too. */
1455
1456 /* prepend prior put's padding. :P */
1457 if (paddingbytes) {
1458 SDL_memcpy(workbuf, stream->resampler_padding, paddingbytes);
1459 buflen += paddingbytes;
1460 }
1461
1462 /* save off the data at the end for the next run. */
1463 SDL_memcpy(stream->resampler_padding, workbuf + (buflen - neededpaddingbytes), neededpaddingbytes);
1464
1465 resamplebuf = workbuf + buflen; /* skip to second piece of workbuf. */
1466 SDL_assert(buflen >= neededpaddingbytes);
1467 if (buflen > neededpaddingbytes) {
1468 buflen = stream->resampler_func(stream, workbuf, buflen - neededpaddingbytes, resamplebuf, resamplebuflen);
1469 } else {
1470 buflen = 0;
1471 }
1472
1473 #if DEBUG_AUDIOSTREAM
1474 printf("AUDIOSTREAM: After resampling we have %d bytes\n", buflen);
1475 #endif
1476 }
1477
1478 if (stream->cvt_after_resampling.needed && (buflen > 0)) {
1479 stream->cvt_after_resampling.buf = resamplebuf;
1480 stream->cvt_after_resampling.len = buflen;
1481 if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
1482 return -1; /* uhoh! */
1483 }
1484 buflen = stream->cvt_after_resampling.len_cvt;
1485
1486 #if DEBUG_AUDIOSTREAM
1487 printf("AUDIOSTREAM: After final conversion we have %d bytes\n", buflen);
1488 #endif
1489 }
1490
1491 #if DEBUG_AUDIOSTREAM
1492 printf("AUDIOSTREAM: Final output is %d bytes\n", buflen);
1493 #endif
1494
1495 if (maxputbytes) {
1496 const int maxbytes = *maxputbytes;
1497 if (buflen > maxbytes)
1498 buflen = maxbytes;
1499 *maxputbytes -= buflen;
1500 }
1501
1502 /* resamplebuf holds the final output, even if we didn't resample. */
1503 return buflen ? SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen) : 0;
1504}
int SDL_ConvertAudio(SDL_AudioCVT *cvt)
Definition: SDL_audiocvt.c:540
static Uint8 * EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
@ SDL_FALSE
Definition: SDL_stdinc.h:163
static Uint32 frames
Definition: testsprite2.c:40

References EnsureStreamBufferSize(), frames, NULL, SDL_assert, SDL_ceil, SDL_ConvertAudio(), SDL_FALSE, SDL_memcpy, and SDL_WriteToDataQueue().

Referenced by SDL_AudioStreamFlush(), and SDL_AudioStreamPut().

◆ SDL_BuildAudioCVT()

int SDL_BuildAudioCVT ( SDL_AudioCVT cvt,
SDL_AudioFormat  src_format,
Uint8  src_channels,
int  src_rate,
SDL_AudioFormat  dst_format,
Uint8  dst_channels,
int  dst_rate 
)

This function takes a source format and rate and a destination format and rate, and initializes the cvt structure with information needed by SDL_ConvertAudio() to convert a buffer of audio data from one format to the other. An unsupported format causes an error and -1 will be returned.

Returns
0 if no conversion is needed, 1 if the audio filter is set up, or -1 on error.

Definition at line 878 of file SDL_audiocvt.c.

881{
882 /* Sanity check target pointer */
883 if (cvt == NULL) {
884 return SDL_InvalidParamError("cvt");
885 }
886
887 /* Make sure we zero out the audio conversion before error checking */
888 SDL_zerop(cvt);
889
890 if (!SDL_SupportedAudioFormat(src_fmt)) {
891 return SDL_SetError("Invalid source format");
892 } else if (!SDL_SupportedAudioFormat(dst_fmt)) {
893 return SDL_SetError("Invalid destination format");
894 } else if (!SDL_SupportedChannelCount(src_channels)) {
895 return SDL_SetError("Invalid source channels");
896 } else if (!SDL_SupportedChannelCount(dst_channels)) {
897 return SDL_SetError("Invalid destination channels");
898 } else if (src_rate <= 0) {
899 return SDL_SetError("Source rate is equal to or less than zero");
900 } else if (dst_rate <= 0) {
901 return SDL_SetError("Destination rate is equal to or less than zero");
902 } else if (src_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) {
903 return SDL_SetError("Source rate is too high");
904 } else if (dst_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) {
905 return SDL_SetError("Destination rate is too high");
906 }
907
908#if DEBUG_CONVERT
909 printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
910 src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
911#endif
912
913 /* Start off with no conversion necessary */
914 cvt->src_format = src_fmt;
915 cvt->dst_format = dst_fmt;
916 cvt->needed = 0;
917 cvt->filter_index = 0;
918 SDL_zero(cvt->filters);
919 cvt->len_mult = 1;
920 cvt->len_ratio = 1.0;
921 cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
922
923 /* Make sure we've chosen audio conversion functions (MMX, scalar, etc.) */
925
926 /* Type conversion goes like this now:
927 - byteswap to CPU native format first if necessary.
928 - convert to native Float32 if necessary.
929 - resample and change channel count if necessary.
930 - convert back to native format.
931 - byteswap back to foreign format if necessary.
932
933 The expectation is we can process data faster in float32
934 (possibly with SIMD), and making several passes over the same
935 buffer is likely to be CPU cache-friendly, avoiding the
936 biggest performance hit in modern times. Previously we had
937 (script-generated) custom converters for every data type and
938 it was a bloat on SDL compile times and final library size. */
939
940 /* see if we can skip float conversion entirely. */
941 if (src_rate == dst_rate && src_channels == dst_channels) {
942 if (src_fmt == dst_fmt) {
943 return 0;
944 }
945
946 /* just a byteswap needed? */
947 if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
949 return -1;
950 }
951 cvt->needed = 1;
952 return 1;
953 }
954 }
955
956 /* Convert data types, if necessary. Updates (cvt). */
957 if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) {
958 return -1; /* shouldn't happen, but just in case... */
959 }
960
961 /* Channel conversion */
962 if (src_channels < dst_channels) {
963 /* Upmixing */
964 /* Mono -> Stereo [-> ...] */
965 if ((src_channels == 1) && (dst_channels > 1)) {
967 return -1;
968 }
969 cvt->len_mult *= 2;
970 src_channels = 2;
971 cvt->len_ratio *= 2;
972 }
973 /* [Mono ->] Stereo -> 5.1 [-> 7.1] */
974 if ((src_channels == 2) && (dst_channels >= 6)) {
976 return -1;
977 }
978 src_channels = 6;
979 cvt->len_mult *= 3;
980 cvt->len_ratio *= 3;
981 }
982 /* Quad -> 5.1 [-> 7.1] */
983 if ((src_channels == 4) && (dst_channels >= 6)) {
985 return -1;
986 }
987 src_channels = 6;
988 cvt->len_mult = (cvt->len_mult * 3 + 1) / 2;
989 cvt->len_ratio *= 1.5;
990 }
991 /* [[Mono ->] Stereo ->] 5.1 -> 7.1 */
992 if ((src_channels == 6) && (dst_channels == 8)) {
994 return -1;
995 }
996 src_channels = 8;
997 cvt->len_mult = (cvt->len_mult * 4 + 2) / 3;
998 /* Should be numerically exact with every valid input to this
999 function */
1000 cvt->len_ratio = cvt->len_ratio * 4 / 3;
1001 }
1002 /* [Mono ->] Stereo -> Quad */
1003 if ((src_channels == 2) && (dst_channels == 4)) {
1005 return -1;
1006 }
1007 src_channels = 4;
1008 cvt->len_mult *= 2;
1009 cvt->len_ratio *= 2;
1010 }
1011 } else if (src_channels > dst_channels) {
1012 /* Downmixing */
1013 /* 7.1 -> 5.1 [-> Stereo [-> Mono]] */
1014 /* 7.1 -> 5.1 [-> Quad] */
1015 if ((src_channels == 8) && (dst_channels <= 6)) {
1017 return -1;
1018 }
1019 src_channels = 6;
1020 cvt->len_ratio *= 0.75;
1021 }
1022 /* [7.1 ->] 5.1 -> Stereo [-> Mono] */
1023 if ((src_channels == 6) && (dst_channels <= 2)) {
1025 return -1;
1026 }
1027 src_channels = 2;
1028 cvt->len_ratio /= 3;
1029 }
1030 /* 5.1 -> Quad */
1031 if ((src_channels == 6) && (dst_channels == 4)) {
1033 return -1;
1034 }
1035 src_channels = 4;
1036 cvt->len_ratio = cvt->len_ratio * 2 / 3;
1037 }
1038 /* Quad -> Stereo [-> Mono] */
1039 if ((src_channels == 4) && (dst_channels <= 2)) {
1041 return -1;
1042 }
1043 src_channels = 2;
1044 cvt->len_ratio /= 2;
1045 }
1046 /* [... ->] Stereo -> Mono */
1047 if ((src_channels == 2) && (dst_channels == 1)) {
1049
1050 #if HAVE_SSE3_INTRINSICS
1051 if (SDL_HasSSE3()) {
1052 filter = SDL_ConvertStereoToMono_SSE3;
1053 }
1054 #endif
1055
1056 if (!filter) {
1058 }
1059
1060 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
1061 return -1;
1062 }
1063
1064 src_channels = 1;
1065 cvt->len_ratio /= 2;
1066 }
1067 }
1068
1069 if (src_channels != dst_channels) {
1070 /* All combinations of supported channel counts should have been
1071 handled by now, but let's be defensive */
1072 return SDL_SetError("Invalid channel combination");
1073 }
1074
1075 /* Do rate conversion, if necessary. Updates (cvt). */
1076 if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
1077 return -1; /* shouldn't happen, but just in case... */
1078 }
1079
1080 /* Move to final data type. */
1081 if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) {
1082 return -1; /* shouldn't happen, but just in case... */
1083 }
1084
1085 cvt->needed = (cvt->filter_index != 0);
1086 return (cvt->needed);
1087}
void(* SDL_AudioFilter)(struct SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audio.h:193
#define SDL_AUDIO_MASK_ENDIAN
Definition: SDL_audio.h:73
void SDL_ChooseAudioConverters(void)
static int SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
Definition: SDL_audiocvt.c:662
static void SDL_Convert51To71(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:335
static void SDL_Convert71To51(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:151
static SDL_bool SDL_SupportedAudioFormat(const SDL_AudioFormat fmt)
Definition: SDL_audiocvt.c:831
static int SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
Definition: SDL_audiocvt.c:615
static void SDL_ConvertStereoToQuad(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:305
static SDL_bool SDL_SupportedChannelCount(const int channels)
Definition: SDL_audiocvt.c:854
static void SDL_Convert_Byteswap(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:563
static void SDL_Convert51ToQuad(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:181
static void SDL_ConvertStereoTo51(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:234
static void SDL_Convert51ToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:103
static int SDL_AddAudioCVTFilter(SDL_AudioCVT *cvt, const SDL_AudioFilter filter)
Definition: SDL_audiocvt.c:601
static void SDL_ConvertStereoToMono(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:81
static void SDL_ConvertQuadTo51(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:268
static int SDL_BuildAudioResampleCVT(SDL_AudioCVT *cvt, const int dst_channels, const int src_rate, const int dst_rate)
Definition: SDL_audiocvt.c:782
static void SDL_ConvertMonoToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:210
static void SDL_ConvertQuadToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
Definition: SDL_audiocvt.c:128
#define SDL_HasSSE3
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
#define SDL_MAX_SINT32
A signed 32-bit integer type.
Definition: SDL_stdinc.h:195
double len_ratio
Definition: SDL_audio.h:236
SDL_AudioFormat src_format
Definition: SDL_audio.h:229
SDL_AudioFormat dst_format
Definition: SDL_audio.h:230
double rate_incr
Definition: SDL_audio.h:231

References SDL_AudioCVT::dst_format, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, SDL_AudioCVT::len_mult, SDL_AudioCVT::len_ratio, SDL_AudioCVT::needed, NULL, SDL_AudioCVT::rate_incr, RESAMPLER_SAMPLES_PER_ZERO_CROSSING, SDL_AddAudioCVTFilter(), SDL_AUDIO_MASK_ENDIAN, SDL_BuildAudioResampleCVT(), SDL_BuildAudioTypeCVTFromFloat(), SDL_BuildAudioTypeCVTToFloat(), SDL_ChooseAudioConverters(), SDL_Convert51To71(), SDL_Convert51ToQuad(), SDL_Convert51ToStereo(), SDL_Convert71To51(), SDL_Convert_Byteswap(), SDL_ConvertMonoToStereo(), SDL_ConvertQuadTo51(), SDL_ConvertQuadToStereo(), SDL_ConvertStereoTo51(), SDL_ConvertStereoToMono(), SDL_ConvertStereoToQuad(), SDL_HasSSE3, SDL_InvalidParamError, SDL_MAX_SINT32, SDL_SetError, SDL_SupportedAudioFormat(), SDL_SupportedChannelCount(), SDL_zero, SDL_zerop, and SDL_AudioCVT::src_format.

Referenced by SDL_NewAudioStream().

◆ SDL_BuildAudioResampleCVT()

static int SDL_BuildAudioResampleCVT ( SDL_AudioCVT cvt,
const int  dst_channels,
const int  src_rate,
const int  dst_rate 
)
static

Definition at line 782 of file SDL_audiocvt.c.

784{
786
787 if (src_rate == dst_rate) {
788 return 0; /* no conversion necessary. */
789 }
790
791 filter = ChooseCVTResampler(dst_channels);
792 if (filter == NULL) {
793 return SDL_SetError("No conversion available for these rates");
794 }
795
796 if (SDL_PrepareResampleFilter() < 0) {
797 return -1;
798 }
799
800 /* Update (cvt) with filter details... */
801 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
802 return -1;
803 }
804
805 /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
806 !!! FIXME in 2.1: We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
807 !!! FIXME in 2.1: so we steal the ninth and tenth slot. :( */
808 if (cvt->filter_index >= (SDL_AUDIOCVT_MAX_FILTERS-2)) {
809 return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS-2);
810 }
811 cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1] = (SDL_AudioFilter) (size_t) src_rate;
812 cvt->filters[SDL_AUDIOCVT_MAX_FILTERS] = (SDL_AudioFilter) (size_t) dst_rate;
813
814 if (src_rate < dst_rate) {
815 const double mult = ((double) dst_rate) / ((double) src_rate);
816 cvt->len_mult *= (int) SDL_ceil(mult);
817 cvt->len_ratio *= mult;
818 } else {
819 cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
820 }
821
822 /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
823 /* the buffer is big enough to hold the destination now, but
824 we need it large enough to hold a separate scratch buffer. */
825 cvt->len_mult *= 2;
826
827 return 1; /* added a converter. */
828}
int SDL_PrepareResampleFilter(void)
Definition: SDL_audiocvt.c:435
static SDL_AudioFilter ChooseCVTResampler(const int dst_channels)
Definition: SDL_audiocvt.c:767

References ChooseCVTResampler(), SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, SDL_AudioCVT::len_mult, SDL_AudioCVT::len_ratio, NULL, SDL_AddAudioCVTFilter(), SDL_AUDIOCVT_MAX_FILTERS, SDL_ceil, SDL_PrepareResampleFilter(), and SDL_SetError.

Referenced by SDL_BuildAudioCVT().

◆ SDL_BuildAudioTypeCVTFromFloat()

static int SDL_BuildAudioTypeCVTFromFloat ( SDL_AudioCVT cvt,
const SDL_AudioFormat  dst_fmt 
)
static

Definition at line 662 of file SDL_audiocvt.c.

663{
664 int retval = 0; /* 0 == no conversion necessary. */
665
666 if (!SDL_AUDIO_ISFLOAT(dst_fmt)) {
667 const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
668 const Uint16 src_bitsize = 32;
670 switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
676 default: SDL_assert(!"Unexpected audio format!"); break;
677 }
678
679 if (!filter) {
680 return SDL_SetError("No conversion from float to destination format available");
681 }
682
683 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
684 return -1;
685 }
686 if (src_bitsize < dst_bitsize) {
687 const int mult = (dst_bitsize / src_bitsize);
688 cvt->len_mult *= mult;
689 cvt->len_ratio *= mult;
690 } else if (src_bitsize > dst_bitsize) {
691 cvt->len_ratio /= (src_bitsize / dst_bitsize);
692 }
693 retval = 1; /* added a converter. */
694 }
695
696 if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
698 return -1;
699 }
700 retval = 1; /* added a converter. */
701 }
702
703 return retval;
704}
#define SDL_AUDIO_ISBIGENDIAN(x)
Definition: SDL_audio.h:77
#define AUDIO_S16
Definition: SDL_audio.h:96
#define AUDIO_U8
Definition: SDL_audio.h:89
#define SDL_AUDIO_ISFLOAT(x)
Definition: SDL_audio.h:76
#define AUDIO_S8
Definition: SDL_audio.h:90
#define AUDIO_S32
Definition: SDL_audio.h:105
#define SDL_AUDIO_BITSIZE(x)
Definition: SDL_audio.h:75
#define AUDIO_U16
Definition: SDL_audio.h:95
SDL_AudioFilter SDL_Convert_F32_to_U16
SDL_AudioFilter SDL_Convert_F32_to_S32
SDL_AudioFilter SDL_Convert_F32_to_S16
SDL_AudioFilter SDL_Convert_F32_to_U8
SDL_AudioFilter SDL_Convert_F32_to_S8
#define SDL_BYTEORDER
#define SDL_LIL_ENDIAN
Definition: SDL_endian.h:37
uint16_t Uint16
Definition: SDL_stdinc.h:191
SDL_bool retval

References AUDIO_S16, AUDIO_S32, AUDIO_S8, AUDIO_U16, AUDIO_U8, SDL_AudioCVT::len_mult, SDL_AudioCVT::len_ratio, NULL, retval, SDL_AddAudioCVTFilter(), SDL_assert, SDL_AUDIO_BITSIZE, SDL_AUDIO_ISBIGENDIAN, SDL_AUDIO_ISFLOAT, SDL_AUDIO_MASK_ENDIAN, SDL_BYTEORDER, SDL_Convert_Byteswap(), SDL_Convert_F32_to_S16, SDL_Convert_F32_to_S32, SDL_Convert_F32_to_S8, SDL_Convert_F32_to_U16, SDL_Convert_F32_to_U8, SDL_LIL_ENDIAN, and SDL_SetError.

Referenced by SDL_BuildAudioCVT().

◆ SDL_BuildAudioTypeCVTToFloat()

static int SDL_BuildAudioTypeCVTToFloat ( SDL_AudioCVT cvt,
const SDL_AudioFormat  src_fmt 
)
static

Definition at line 615 of file SDL_audiocvt.c.

616{
617 int retval = 0; /* 0 == no conversion necessary. */
618
619 if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
621 return -1;
622 }
623 retval = 1; /* added a converter. */
624 }
625
626 if (!SDL_AUDIO_ISFLOAT(src_fmt)) {
627 const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
628 const Uint16 dst_bitsize = 32;
630
631 switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
637 default: SDL_assert(!"Unexpected audio format!"); break;
638 }
639
640 if (!filter) {
641 return SDL_SetError("No conversion from source format to float available");
642 }
643
644 if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
645 return -1;
646 }
647 if (src_bitsize < dst_bitsize) {
648 const int mult = (dst_bitsize / src_bitsize);
649 cvt->len_mult *= mult;
650 cvt->len_ratio *= mult;
651 } else if (src_bitsize > dst_bitsize) {
652 cvt->len_ratio /= (src_bitsize / dst_bitsize);
653 }
654
655 retval = 1; /* added a converter. */
656 }
657
658 return retval;
659}
SDL_AudioFilter SDL_Convert_U16_to_F32
SDL_AudioFilter SDL_Convert_S8_to_F32
SDL_AudioFilter SDL_Convert_S32_to_F32
SDL_AudioFilter SDL_Convert_S16_to_F32
SDL_AudioFilter SDL_Convert_U8_to_F32

References AUDIO_S16, AUDIO_S32, AUDIO_S8, AUDIO_U16, AUDIO_U8, SDL_AudioCVT::len_mult, SDL_AudioCVT::len_ratio, NULL, retval, SDL_AddAudioCVTFilter(), SDL_assert, SDL_AUDIO_BITSIZE, SDL_AUDIO_ISBIGENDIAN, SDL_AUDIO_ISFLOAT, SDL_AUDIO_MASK_ENDIAN, SDL_BYTEORDER, SDL_Convert_Byteswap(), SDL_Convert_S16_to_F32, SDL_Convert_S32_to_F32, SDL_Convert_S8_to_F32, SDL_Convert_U16_to_F32, SDL_Convert_U8_to_F32, SDL_LIL_ENDIAN, and SDL_SetError.

Referenced by SDL_BuildAudioCVT().

◆ SDL_CleanupAudioStreamResampler()

static void SDL_CleanupAudioStreamResampler ( SDL_AudioStream *  stream)
static

Definition at line 1263 of file SDL_audiocvt.c.

1264{
1265 SDL_free(stream->resampler_state);
1266}
#define SDL_free

References SDL_free.

Referenced by SDL_NewAudioStream().

◆ SDL_Convert51To71()

static void SDL_Convert51To71 ( SDL_AudioCVT cvt,
SDL_AudioFormat  format 
)
static

Definition at line 335 of file SDL_audiocvt.c.

336{
337 float lf, rf, lb, rb, ls, rs;
338 int i;
339 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
340 float *dst = (float *) (cvt->buf + cvt->len_cvt * 4 / 3);
341
342 LOG_DEBUG_CONVERT("5.1", "7.1");
344 SDL_assert(cvt->len_cvt % (sizeof(float) * 6) == 0);
345
346 for (i = cvt->len_cvt / (sizeof(float) * 6); i; --i) {
347 dst -= 8;
348 src -= 6;
349 lf = src[0];
350 rf = src[1];
351 lb = src[4];
352 rb = src[5];
353 ls = (lf + lb) * 0.5f;
354 rs = (rf + rb) * 0.5f;
355 /* !!! FIXME: these four may clip */
356 lf += lf - ls;
357 rf += rf - ls;
358 lb += lb - ls;
359 rb += rb - ls;
360 dst[3] = src[3]; /* LFE */
361 dst[2] = src[2]; /* FC */
362 dst[7] = rs; /* SR */
363 dst[6] = ls; /* SL */
364 dst[5] = rb; /* BR */
365 dst[4] = lb; /* BL */
366 dst[1] = rf; /* FR */
367 dst[0] = lf; /* FL */
368 }
369
370 cvt->len_cvt = cvt->len_cvt * 4 / 3;
371
372 if (cvt->filters[++cvt->filter_index]) {
373 cvt->filters[cvt->filter_index] (cvt, format);
374 }
375}
#define AUDIO_F32SYS
Definition: SDL_audio.h:125
#define LOG_DEBUG_CONVERT(from, to)
Definition: SDL_audio_c.h:34
GLenum src
GLenum GLenum dst
Uint8 * buf
Definition: SDL_audio.h:232

References AUDIO_F32SYS, SDL_AudioCVT::buf, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, i, SDL_AudioCVT::len_cvt, LOG_DEBUG_CONVERT, and SDL_assert.

Referenced by SDL_BuildAudioCVT().

◆ SDL_Convert51ToQuad()

static void SDL_Convert51ToQuad ( SDL_AudioCVT cvt,
SDL_AudioFormat  format 
)
static

Definition at line 181 of file SDL_audiocvt.c.

182{
183 float *dst = (float *) cvt->buf;
184 const float *src = dst;
185 int i;
186
187 LOG_DEBUG_CONVERT("5.1", "quad");
189
190 /* SDL's 4.0 layout: FL+FR+BL+BR */
191 /* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
192 for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 4) {
193 const float front_center_distributed = src[2] * 0.5f;
194 dst[0] = (src[0] + front_center_distributed) / 1.5f; /* FL */
195 dst[1] = (src[1] + front_center_distributed) / 1.5f; /* FR */
196 dst[2] = src[4] / 1.5f; /* BL */
197 dst[3] = src[5] / 1.5f; /* BR */
198 }
199
200 cvt->len_cvt /= 6;
201 cvt->len_cvt *= 4;
202 if (cvt->filters[++cvt->filter_index]) {
203 cvt->filters[cvt->filter_index] (cvt, format);
204 }
205}

References AUDIO_F32SYS, SDL_AudioCVT::buf, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, i, SDL_AudioCVT::len_cvt, LOG_DEBUG_CONVERT, and SDL_assert.

Referenced by SDL_BuildAudioCVT().

◆ SDL_Convert51ToStereo()

static void SDL_Convert51ToStereo ( SDL_AudioCVT cvt,
SDL_AudioFormat  format 
)
static

Definition at line 103 of file SDL_audiocvt.c.

104{
105 float *dst = (float *) cvt->buf;
106 const float *src = dst;
107 int i;
108
109 LOG_DEBUG_CONVERT("5.1", "stereo");
111
112 /* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
113 for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 2) {
114 const float front_center_distributed = src[2] * 0.5f;
115 dst[0] = (src[0] + front_center_distributed + src[4]) / 2.5f; /* left */
116 dst[1] = (src[1] + front_center_distributed + src[5]) / 2.5f; /* right */
117 }
118
119 cvt->len_cvt /= 3;
120 if (cvt->filters[++cvt->filter_index]) {
121 cvt->filters[cvt->filter_index] (cvt, format);
122 }
123}

References AUDIO_F32SYS, SDL_AudioCVT::buf, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, i, SDL_AudioCVT::len_cvt, LOG_DEBUG_CONVERT, and SDL_assert.

Referenced by SDL_BuildAudioCVT().

◆ SDL_Convert71To51()

static void SDL_Convert71To51 ( SDL_AudioCVT cvt,
SDL_AudioFormat  format 
)
static

Definition at line 151 of file SDL_audiocvt.c.

152{
153 float *dst = (float *) cvt->buf;
154 const float *src = dst;
155 int i;
156
157 LOG_DEBUG_CONVERT("7.1", "5.1");
159
160 for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8, dst += 6) {
161 const float surround_left_distributed = src[6] * 0.5f;
162 const float surround_right_distributed = src[7] * 0.5f;
163 dst[0] = (src[0] + surround_left_distributed) / 1.5f; /* FL */
164 dst[1] = (src[1] + surround_right_distributed) / 1.5f; /* FR */
165 dst[2] = src[2] / 1.5f; /* CC */
166 dst[3] = src[3] / 1.5f; /* LFE */
167 dst[4] = (src[4] + surround_left_distributed) / 1.5f; /* BL */
168 dst[5] = (src[5] + surround_right_distributed) / 1.5f; /* BR */
169 }
170
171 cvt->len_cvt /= 8;
172 cvt->len_cvt *= 6;
173 if (cvt->filters[++cvt->filter_index]) {
174 cvt->filters[cvt->filter_index] (cvt, format);
175 }
176}

References AUDIO_F32SYS, SDL_AudioCVT::buf, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, i, SDL_AudioCVT::len_cvt, LOG_DEBUG_CONVERT, and SDL_assert.

Referenced by SDL_BuildAudioCVT().

◆ SDL_Convert_Byteswap()

static void SDL_Convert_Byteswap ( SDL_AudioCVT cvt,
SDL_AudioFormat  format 
)
static

Definition at line 563 of file SDL_audiocvt.c.

564{
565#if DEBUG_CONVERT
566 printf("Converting byte order\n");
567#endif
568
569 switch (SDL_AUDIO_BITSIZE(format)) {
570 #define CASESWAP(b) \
571 case b: { \
572 Uint##b *ptr = (Uint##b *) cvt->buf; \
573 int i; \
574 for (i = cvt->len_cvt / sizeof (*ptr); i; --i, ++ptr) { \
575 *ptr = SDL_Swap##b(*ptr); \
576 } \
577 break; \
578 }
579
580 CASESWAP(16);
581 CASESWAP(32);
582 CASESWAP(64);
583
584 #undef CASESWAP
585
586 default: SDL_assert(!"unhandled byteswap datatype!"); break;
587 }
588
589 if (cvt->filters[++cvt->filter_index]) {
590 /* flip endian flag for data. */
592 format &= ~SDL_AUDIO_MASK_ENDIAN;
593 } else {
595 }
596 cvt->filters[cvt->filter_index](cvt, format);
597 }
598}
#define CASESWAP(b)

References CASESWAP, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, SDL_assert, SDL_AUDIO_BITSIZE, and SDL_AUDIO_MASK_ENDIAN.

Referenced by SDL_BuildAudioCVT(), SDL_BuildAudioTypeCVTFromFloat(), and SDL_BuildAudioTypeCVTToFloat().

◆ SDL_ConvertAudio()

int SDL_ConvertAudio ( SDL_AudioCVT cvt)

Once you have initialized the cvt structure using SDL_BuildAudioCVT(), created an audio buffer cvt->buf, and filled it with cvt->len bytes of audio data in the source format, this function will convert it in-place to the desired format.

The data conversion may expand the size of the audio data, so the buffer cvt->buf should be allocated after the cvt structure is initialized by SDL_BuildAudioCVT(), and should be cvt->len*cvt->len_mult bytes long.

Returns
0 on success or -1 if cvt->buf is NULL.

Definition at line 540 of file SDL_audiocvt.c.

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}

References SDL_AudioCVT::buf, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, SDL_AudioCVT::len, SDL_AudioCVT::len_cvt, NULL, SDL_SetError, and SDL_AudioCVT::src_format.

Referenced by SDL_AudioStreamPutInternal().

◆ SDL_ConvertMonoToStereo()

static void SDL_ConvertMonoToStereo ( SDL_AudioCVT cvt,
SDL_AudioFormat  format 
)
static

Definition at line 210 of file SDL_audiocvt.c.

211{
212 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
213 float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
214 int i;
215
216 LOG_DEBUG_CONVERT("mono", "stereo");
218
219 for (i = cvt->len_cvt / sizeof (float); i; --i) {
220 src--;
221 dst -= 2;
222 dst[0] = dst[1] = *src;
223 }
224
225 cvt->len_cvt *= 2;
226 if (cvt->filters[++cvt->filter_index]) {
227 cvt->filters[cvt->filter_index] (cvt, format);
228 }
229}

References AUDIO_F32SYS, SDL_AudioCVT::buf, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, i, SDL_AudioCVT::len_cvt, LOG_DEBUG_CONVERT, and SDL_assert.

Referenced by SDL_BuildAudioCVT().

◆ SDL_ConvertQuadTo51()

static void SDL_ConvertQuadTo51 ( SDL_AudioCVT cvt,
SDL_AudioFormat  format 
)
static

Definition at line 268 of file SDL_audiocvt.c.

269{
270 int i;
271 float lf, rf, lb, rb, ce;
272 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
273 float *dst = (float *) (cvt->buf + cvt->len_cvt * 3 / 2);
274
275 LOG_DEBUG_CONVERT("quad", "5.1");
277 SDL_assert(cvt->len_cvt % (sizeof(float) * 4) == 0);
278
279 for (i = cvt->len_cvt / (sizeof(float) * 4); i; --i) {
280 dst -= 6;
281 src -= 4;
282 lf = src[0];
283 rf = src[1];
284 lb = src[2];
285 rb = src[3];
286 ce = (lf + rf) * 0.5f;
287 /* !!! FIXME: FL and FR may clip */
288 dst[0] = lf + (lf - ce); /* FL */
289 dst[1] = rf + (rf - ce); /* FR */
290 dst[2] = ce; /* FC */
291 dst[3] = 0; /* LFE (only meant for special LFE effects) */
292 dst[4] = lb; /* BL */
293 dst[5] = rb; /* BR */
294 }
295
296 cvt->len_cvt = cvt->len_cvt * 3 / 2;
297 if (cvt->filters[++cvt->filter_index]) {
298 cvt->filters[cvt->filter_index] (cvt, format);
299 }
300}

References AUDIO_F32SYS, SDL_AudioCVT::buf, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, i, SDL_AudioCVT::len_cvt, LOG_DEBUG_CONVERT, and SDL_assert.

Referenced by SDL_BuildAudioCVT().

◆ SDL_ConvertQuadToStereo()

static void SDL_ConvertQuadToStereo ( SDL_AudioCVT cvt,
SDL_AudioFormat  format 
)
static

Definition at line 128 of file SDL_audiocvt.c.

129{
130 float *dst = (float *) cvt->buf;
131 const float *src = dst;
132 int i;
133
134 LOG_DEBUG_CONVERT("quad", "stereo");
136
137 for (i = cvt->len_cvt / (sizeof (float) * 4); i; --i, src += 4, dst += 2) {
138 dst[0] = (src[0] + src[2]) * 0.5f; /* left */
139 dst[1] = (src[1] + src[3]) * 0.5f; /* right */
140 }
141
142 cvt->len_cvt /= 2;
143 if (cvt->filters[++cvt->filter_index]) {
144 cvt->filters[cvt->filter_index] (cvt, format);
145 }
146}

References AUDIO_F32SYS, SDL_AudioCVT::buf, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, i, SDL_AudioCVT::len_cvt, LOG_DEBUG_CONVERT, and SDL_assert.

Referenced by SDL_BuildAudioCVT().

◆ SDL_ConvertStereoTo51()

static void SDL_ConvertStereoTo51 ( SDL_AudioCVT cvt,
SDL_AudioFormat  format 
)
static

Definition at line 234 of file SDL_audiocvt.c.

235{
236 int i;
237 float lf, rf, ce;
238 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
239 float *dst = (float *) (cvt->buf + cvt->len_cvt * 3);
240
241 LOG_DEBUG_CONVERT("stereo", "5.1");
243
244 for (i = cvt->len_cvt / (sizeof(float) * 2); i; --i) {
245 dst -= 6;
246 src -= 2;
247 lf = src[0];
248 rf = src[1];
249 ce = (lf + rf) * 0.5f;
250 /* !!! FIXME: FL and FR may clip */
251 dst[0] = lf + (lf - ce); /* FL */
252 dst[1] = rf + (rf - ce); /* FR */
253 dst[2] = ce; /* FC */
254 dst[3] = 0; /* LFE (only meant for special LFE effects) */
255 dst[4] = lf; /* BL */
256 dst[5] = rf; /* BR */
257 }
258
259 cvt->len_cvt *= 3;
260 if (cvt->filters[++cvt->filter_index]) {
261 cvt->filters[cvt->filter_index] (cvt, format);
262 }
263}

References AUDIO_F32SYS, SDL_AudioCVT::buf, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, i, SDL_AudioCVT::len_cvt, LOG_DEBUG_CONVERT, and SDL_assert.

Referenced by SDL_BuildAudioCVT().

◆ SDL_ConvertStereoToMono()

static void SDL_ConvertStereoToMono ( SDL_AudioCVT cvt,
SDL_AudioFormat  format 
)
static

Definition at line 81 of file SDL_audiocvt.c.

82{
83 float *dst = (float *) cvt->buf;
84 const float *src = dst;
85 int i;
86
87 LOG_DEBUG_CONVERT("stereo", "mono");
89
90 for (i = cvt->len_cvt / 8; i; --i, src += 2) {
91 *(dst++) = (src[0] + src[1]) * 0.5f;
92 }
93
94 cvt->len_cvt /= 2;
95 if (cvt->filters[++cvt->filter_index]) {
96 cvt->filters[cvt->filter_index] (cvt, format);
97 }
98}

References AUDIO_F32SYS, SDL_AudioCVT::buf, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, i, SDL_AudioCVT::len_cvt, LOG_DEBUG_CONVERT, and SDL_assert.

Referenced by SDL_BuildAudioCVT().

◆ SDL_ConvertStereoToQuad()

static void SDL_ConvertStereoToQuad ( SDL_AudioCVT cvt,
SDL_AudioFormat  format 
)
static

Definition at line 305 of file SDL_audiocvt.c.

306{
307 const float *src = (const float *) (cvt->buf + cvt->len_cvt);
308 float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
309 float lf, rf;
310 int i;
311
312 LOG_DEBUG_CONVERT("stereo", "quad");
314
315 for (i = cvt->len_cvt / (sizeof(float) * 2); i; --i) {
316 dst -= 4;
317 src -= 2;
318 lf = src[0];
319 rf = src[1];
320 dst[0] = lf; /* FL */
321 dst[1] = rf; /* FR */
322 dst[2] = lf; /* BL */
323 dst[3] = rf; /* BR */
324 }
325
326 cvt->len_cvt *= 2;
327 if (cvt->filters[++cvt->filter_index]) {
328 cvt->filters[cvt->filter_index] (cvt, format);
329 }
330}

References AUDIO_F32SYS, SDL_AudioCVT::buf, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, i, SDL_AudioCVT::len_cvt, LOG_DEBUG_CONVERT, and SDL_assert.

Referenced by SDL_BuildAudioCVT().

◆ SDL_FreeAudioStream()

void SDL_FreeAudioStream ( SDL_AudioStream *  stream)

Free an audio stream

See also
SDL_NewAudioStream
SDL_AudioStreamPut
SDL_AudioStreamGet
SDL_AudioStreamAvailable
SDL_AudioStreamFlush
SDL_AudioStreamClear

Definition at line 1668 of file SDL_audiocvt.c.

1669{
1670 if (stream) {
1671 if (stream->cleanup_resampler_func) {
1672 stream->cleanup_resampler_func(stream);
1673 }
1674 SDL_FreeDataQueue(stream->queue);
1675 SDL_free(stream->staging_buffer);
1676 SDL_free(stream->work_buffer_base);
1677 SDL_free(stream->resampler_padding);
1679 }
1680}
void SDL_FreeDataQueue(SDL_DataQueue *queue)
Definition: SDL_dataqueue.c:88

References SDL_free, and SDL_FreeDataQueue().

Referenced by SDL_NewAudioStream().

◆ SDL_FreeResampleFilter()

void SDL_FreeResampleFilter ( void  )

Definition at line 464 of file SDL_audiocvt.c.

465{
470}
static float * ResamplerFilterDifference
Definition: SDL_audiocvt.c:432
static float * ResamplerFilter
Definition: SDL_audiocvt.c:431

References NULL, ResamplerFilter, ResamplerFilterDifference, and SDL_free.

Referenced by SDL_AudioQuit().

◆ SDL_NewAudioStream()

SDL_AudioStream * SDL_NewAudioStream ( const SDL_AudioFormat  src_format,
const Uint8  src_channels,
const int  src_rate,
const SDL_AudioFormat  dst_format,
const Uint8  dst_channels,
const int  dst_rate 
)

Create a new audio stream

Parameters
src_formatThe format of the source audio
src_channelsThe number of channels of the source audio
src_rateThe sampling rate of the source audio
dst_formatThe format of the desired audio output
dst_channelsThe number of channels of the desired audio output
dst_rateThe sampling rate of the desired audio output
Returns
0 on success, or -1 on error.
See also
SDL_AudioStreamPut
SDL_AudioStreamGet
SDL_AudioStreamAvailable
SDL_AudioStreamFlush
SDL_AudioStreamClear
SDL_FreeAudioStream

Definition at line 1269 of file SDL_audiocvt.c.

1275{
1276 const int packetlen = 4096; /* !!! FIXME: good enough for now. */
1277 Uint8 pre_resample_channels;
1278 SDL_AudioStream *retval;
1279
1280 retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
1281 if (!retval) {
1282 return NULL;
1283 }
1284
1285 /* If increasing channels, do it after resampling, since we'd just
1286 do more work to resample duplicate channels. If we're decreasing, do
1287 it first so we resample the interpolated data instead of interpolating
1288 the resampled data (!!! FIXME: decide if that works in practice, though!). */
1289 pre_resample_channels = SDL_min(src_channels, dst_channels);
1290
1291 retval->first_run = SDL_TRUE;
1292 retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels;
1293 retval->src_format = src_format;
1294 retval->src_channels = src_channels;
1295 retval->src_rate = src_rate;
1296 retval->dst_sample_frame_size = (SDL_AUDIO_BITSIZE(dst_format) / 8) * dst_channels;
1297 retval->dst_format = dst_format;
1298 retval->dst_channels = dst_channels;
1299 retval->dst_rate = dst_rate;
1300 retval->pre_resample_channels = pre_resample_channels;
1301 retval->packetlen = packetlen;
1302 retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
1303 retval->resampler_padding_samples = ResamplerPadding(retval->src_rate, retval->dst_rate) * pre_resample_channels;
1304 retval->resampler_padding = (float *) SDL_calloc(retval->resampler_padding_samples ? retval->resampler_padding_samples : 1, sizeof (float));
1305
1306 if (retval->resampler_padding == NULL) {
1309 return NULL;
1310 }
1311
1312 retval->staging_buffer_size = ((retval->resampler_padding_samples / retval->pre_resample_channels) * retval->src_sample_frame_size);
1313 if (retval->staging_buffer_size > 0) {
1314 retval->staging_buffer = (Uint8 *) SDL_malloc(retval->staging_buffer_size);
1315 if (retval->staging_buffer == NULL) {
1318 return NULL;
1319 }
1320 }
1321
1322 /* Not resampling? It's an easy conversion (and maybe not even that!) */
1323 if (src_rate == dst_rate) {
1324 retval->cvt_before_resampling.needed = SDL_FALSE;
1325 if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
1327 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
1328 }
1329 } else {
1330 /* Don't resample at first. Just get us to Float32 format. */
1331 /* !!! FIXME: convert to int32 on devices without hardware float. */
1332 if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
1334 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
1335 }
1336
1337#ifdef HAVE_LIBSAMPLERATE_H
1338 SetupLibSampleRateResampling(retval);
1339#endif
1340
1341 if (!retval->resampler_func) {
1342 retval->resampler_state = SDL_calloc(retval->resampler_padding_samples, sizeof (float));
1343 if (!retval->resampler_state) {
1346 return NULL;
1347 }
1348
1349 if (SDL_PrepareResampleFilter() < 0) {
1350 SDL_free(retval->resampler_state);
1351 retval->resampler_state = NULL;
1353 return NULL;
1354 }
1355
1356 retval->resampler_func = SDL_ResampleAudioStream;
1357 retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
1358 retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
1359 }
1360
1361 /* Convert us to the final format after resampling. */
1362 if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
1364 return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
1365 }
1366 }
1367
1368 retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
1369 if (!retval->queue) {
1371 return NULL; /* SDL_NewDataQueue should have called SDL_SetError. */
1372 }
1373
1374 return retval;
1375}
int SDL_BuildAudioCVT(SDL_AudioCVT *cvt, SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate, SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
Definition: SDL_audiocvt.c:878
static int SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
static void SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
static void SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
static int ResamplerPadding(const int inrate, const int outrate)
Definition: SDL_audiocvt.c:473
void SDL_FreeAudioStream(SDL_AudioStream *stream)
SDL_DataQueue * SDL_NewDataQueue(const size_t _packetlen, const size_t initialslack)
Definition: SDL_dataqueue.c:58
#define SDL_malloc
#define SDL_calloc
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406

References AUDIO_F32SYS, NULL, ResamplerPadding(), retval, SDL_AUDIO_BITSIZE, SDL_BuildAudioCVT(), SDL_calloc, SDL_CleanupAudioStreamResampler(), SDL_FALSE, SDL_free, SDL_FreeAudioStream(), SDL_malloc, SDL_min, SDL_NewDataQueue(), SDL_OutOfMemory, SDL_PrepareResampleFilter(), SDL_ResampleAudioStream(), SDL_ResetAudioStreamResampler(), and SDL_TRUE.

◆ SDL_PrepareResampleFilter()

int SDL_PrepareResampleFilter ( void  )

Definition at line 435 of file SDL_audiocvt.c.

436{
438 if (!ResamplerFilter) {
439 /* if dB > 50, beta=(0.1102 * (dB - 8.7)), according to Matlab. */
440 const double dB = 80.0;
441 const double beta = 0.1102 * (dB - 8.7);
442 const size_t alloclen = RESAMPLER_FILTER_SIZE * sizeof (float);
443
444 ResamplerFilter = (float *) SDL_malloc(alloclen);
445 if (!ResamplerFilter) {
447 return SDL_OutOfMemory();
448 }
449
450 ResamplerFilterDifference = (float *) SDL_malloc(alloclen);
455 return SDL_OutOfMemory();
456 }
458 }
460 return 0;
461}
static void kaiser_and_sinc(float *table, float *diffs, const int tablelen, const double beta)
Definition: SDL_audiocvt.c:409
static SDL_SpinLock ResampleFilterSpinlock
Definition: SDL_audiocvt.c:430
#define RESAMPLER_FILTER_SIZE
Definition: SDL_audiocvt.c:383
#define SDL_AtomicLock
#define SDL_AtomicUnlock

References kaiser_and_sinc(), NULL, ResampleFilterSpinlock, RESAMPLER_FILTER_SIZE, ResamplerFilter, ResamplerFilterDifference, SDL_AtomicLock, SDL_AtomicUnlock, SDL_free, SDL_malloc, and SDL_OutOfMemory.

Referenced by SDL_BuildAudioResampleCVT(), and SDL_NewAudioStream().

◆ SDL_ResampleAudio()

static int SDL_ResampleAudio ( const int  chans,
const int  inrate,
const int  outrate,
const float *  lpadding,
const float *  rpadding,
const float *  inbuf,
const int  inbuflen,
float *  outbuf,
const int  outbuflen 
)
static

Definition at line 485 of file SDL_audiocvt.c.

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}
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50

References i, j, RESAMPLER_FILTER_SIZE, RESAMPLER_SAMPLES_PER_ZERO_CROSSING, ResamplerFilter, ResamplerFilterDifference, ResamplerPadding(), and SDL_min.

Referenced by SDL_ResampleAudioStream(), and SDL_ResampleCVT().

◆ SDL_ResampleAudioStream()

static int SDL_ResampleAudioStream ( SDL_AudioStream *  stream,
const void _inbuf,
const int  inbuflen,
void _outbuf,
const int  outbuflen 
)
static

Definition at line 1230 of file SDL_audiocvt.c.

1231{
1232 const Uint8 *inbufend = ((const Uint8 *) _inbuf) + inbuflen;
1233 const float *inbuf = (const float *) _inbuf;
1234 float *outbuf = (float *) _outbuf;
1235 const int chans = (int) stream->pre_resample_channels;
1236 const int inrate = stream->src_rate;
1237 const int outrate = stream->dst_rate;
1238 const int paddingsamples = stream->resampler_padding_samples;
1239 const int paddingbytes = paddingsamples * sizeof (float);
1240 float *lpadding = (float *) stream->resampler_state;
1241 const float *rpadding = (const float *) inbufend; /* we set this up so there are valid padding samples at the end of the input buffer. */
1242 const int cpy = SDL_min(inbuflen, paddingbytes);
1243 int retval;
1244
1245 SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */
1246
1247 retval = SDL_ResampleAudio(chans, inrate, outrate, lpadding, rpadding, inbuf, inbuflen, outbuf, outbuflen);
1248
1249 /* update our left padding with end of current input, for next run. */
1250 SDL_memcpy((lpadding + paddingsamples) - (cpy / sizeof (float)), inbufend - cpy, cpy);
1251 return retval;
1252}
static int SDL_ResampleAudio(const int chans, const int inrate, const int outrate, const float *lpadding, const float *rpadding, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
Definition: SDL_audiocvt.c:485

References retval, SDL_assert, SDL_memcpy, SDL_min, and SDL_ResampleAudio().

Referenced by SDL_NewAudioStream().

◆ SDL_ResampleCVT()

static void SDL_ResampleCVT ( SDL_AudioCVT cvt,
const int  chans,
const SDL_AudioFormat  format 
)
static

Definition at line 707 of file SDL_audiocvt.c.

708{
709 /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
710 !!! FIXME in 2.1: We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
711 !!! FIXME in 2.1: so we steal the ninth and tenth slot. :( */
712 const int inrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1];
713 const int outrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS];
714 const float *src = (const float *) cvt->buf;
715 const int srclen = cvt->len_cvt;
716 /*float *dst = (float *) cvt->buf;
717 const int dstlen = (cvt->len * cvt->len_mult);*/
718 /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
719 float *dst = (float *) (cvt->buf + srclen);
720 const int dstlen = (cvt->len * cvt->len_mult) - srclen;
721 const int requestedpadding = ResamplerPadding(inrate, outrate);
722 int paddingsamples;
723 float *padding;
724
725 if (requestedpadding < SDL_MAX_SINT32 / chans) {
726 paddingsamples = requestedpadding * chans;
727 } else {
728 paddingsamples = 0;
729 }
731
732 /* we keep no streaming state here, so pad with silence on both ends. */
733 padding = (float *) SDL_calloc(paddingsamples ? paddingsamples : 1, sizeof (float));
734 if (!padding) {
736 return;
737 }
738
739 cvt->len_cvt = SDL_ResampleAudio(chans, inrate, outrate, padding, padding, src, srclen, dst, dstlen);
740
741 SDL_free(padding);
742
743 SDL_memmove(cvt->buf, dst, cvt->len_cvt); /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
744
745 if (cvt->filters[++cvt->filter_index]) {
746 cvt->filters[cvt->filter_index](cvt, format);
747 }
748}
#define SDL_memmove

References AUDIO_F32SYS, SDL_AudioCVT::buf, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, SDL_AudioCVT::len, SDL_AudioCVT::len_cvt, SDL_AudioCVT::len_mult, ResamplerPadding(), SDL_assert, SDL_AUDIOCVT_MAX_FILTERS, SDL_calloc, SDL_free, SDL_MAX_SINT32, SDL_memmove, SDL_OutOfMemory, and SDL_ResampleAudio().

◆ SDL_ResetAudioStreamResampler()

static void SDL_ResetAudioStreamResampler ( SDL_AudioStream *  stream)
static

Definition at line 1255 of file SDL_audiocvt.c.

1256{
1257 /* set all the padding to silence. */
1258 const int len = stream->resampler_padding_samples;
1259 SDL_memset(stream->resampler_state, '\0', len * sizeof (float));
1260}

References SDL_memset.

Referenced by SDL_NewAudioStream().

◆ SDL_SupportedAudioFormat()

static SDL_bool SDL_SupportedAudioFormat ( const SDL_AudioFormat  fmt)
static

Definition at line 831 of file SDL_audiocvt.c.

832{
833 switch (fmt) {
834 case AUDIO_U8:
835 case AUDIO_S8:
836 case AUDIO_U16LSB:
837 case AUDIO_S16LSB:
838 case AUDIO_U16MSB:
839 case AUDIO_S16MSB:
840 case AUDIO_S32LSB:
841 case AUDIO_S32MSB:
842 case AUDIO_F32LSB:
843 case AUDIO_F32MSB:
844 return SDL_TRUE; /* supported. */
845
846 default:
847 break;
848 }
849
850 return SDL_FALSE; /* unsupported. */
851}
#define AUDIO_U16LSB
Definition: SDL_audio.h:91
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
#define AUDIO_F32MSB
Definition: SDL_audio.h:113
#define AUDIO_S32MSB
Definition: SDL_audio.h:104
#define AUDIO_S16MSB
Definition: SDL_audio.h:94
#define AUDIO_U16MSB
Definition: SDL_audio.h:93
#define AUDIO_S32LSB
Definition: SDL_audio.h:103
#define AUDIO_F32LSB
Definition: SDL_audio.h:112

References AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_S8, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, SDL_FALSE, and SDL_TRUE.

Referenced by SDL_BuildAudioCVT().

◆ SDL_SupportedChannelCount()

static SDL_bool SDL_SupportedChannelCount ( const int  channels)
static

Definition at line 854 of file SDL_audiocvt.c.

855{
856 switch (channels) {
857 case 1: /* mono */
858 case 2: /* stereo */
859 case 4: /* quad */
860 case 6: /* 5.1 */
861 case 8: /* 7.1 */
862 return SDL_TRUE; /* supported. */
863
864 default:
865 break;
866 }
867
868 return SDL_FALSE; /* unsupported. */
869}

References SDL_FALSE, and SDL_TRUE.

Referenced by SDL_BuildAudioCVT().

Variable Documentation

◆ ResampleFilterSpinlock

SDL_SpinLock ResampleFilterSpinlock = 0
static

Definition at line 430 of file SDL_audiocvt.c.

Referenced by SDL_PrepareResampleFilter().

◆ ResamplerFilter

float* ResamplerFilter = NULL
static

◆ ResamplerFilterDifference

float* ResamplerFilterDifference = NULL
static