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_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
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst base endif endm macro PF ptr

◆ DEBUG_AUDIOSTREAM

#define DEBUG_AUDIOSTREAM   0

Definition at line 36 of file SDL_audiocvt.c.

◆ RESAMPLER_BITS_PER_SAMPLE

#define RESAMPLER_BITS_PER_SAMPLE   16

Definition at line 380 of file SDL_audiocvt.c.

◆ RESAMPLER_FILTER_SIZE

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

Definition at line 382 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 753 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 381 of file SDL_audiocvt.c.

◆ RESAMPLER_ZERO_CROSSINGS

#define RESAMPLER_ZERO_CROSSINGS   5

Definition at line 379 of file SDL_audiocvt.c.

Typedef Documentation

◆ SDL_CleanupAudioStreamResamplerFunc

typedef void(* SDL_CleanupAudioStreamResamplerFunc) (SDL_AudioStream *stream)

Definition at line 1090 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 1088 of file SDL_audiocvt.c.

◆ SDL_ResetAudioStreamResamplerFunc

typedef void(* SDL_ResetAudioStreamResamplerFunc) (SDL_AudioStream *stream)

Definition at line 1089 of file SDL_audiocvt.c.

Function Documentation

◆ bessel()

static double bessel ( const double  x)
static

Definition at line 386 of file SDL_audiocvt.c.

387 {
388  const double xdiv2 = x / 2.0;
389  double i0 = 1.0f;
390  double f = 1.0f;
391  int i = 1;
392 
393  while (SDL_TRUE) {
394  const double diff = SDL_pow(xdiv2, i * 2) / SDL_pow(f, 2);
395  if (diff < 1.0e-21f) {
396  break;
397  }
398  i0 += diff;
399  i++;
400  f *= (double) i;
401  }
402 
403  return i0;
404 }
#define SDL_pow
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
GLfloat f
@ SDL_TRUE
Definition: SDL_stdinc.h:170

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 766 of file SDL_audiocvt.c.

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

References NULL.

Referenced by SDL_BuildAudioResampleCVT().

◆ EnsureStreamBufferSize()

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

Definition at line 1123 of file SDL_audiocvt.c.

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

References NULL, ptr, 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 408 of file SDL_audiocvt.c.

409 {
410  const int lenm1 = tablelen - 1;
411  const int lenm1div2 = lenm1 / 2;
412  int i;
413 
414  table[0] = 1.0f;
415  for (i = 1; i < tablelen; i++) {
416  const double kaiser = bessel(beta * SDL_sqrt(1.0 - SDL_pow(((i - lenm1) / 2.0) / lenm1div2, 2.0))) / bessel(beta);
417  table[tablelen - i] = (float) kaiser;
418  }
419 
420  for (i = 1; i < tablelen; i++) {
421  const float x = (((float) i) / ((float) RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) * ((float) M_PI);
422  table[i] *= SDL_sinf(x) / x;
423  diffs[i - 1] = table[i] - table[i - 1];
424  }
425  diffs[lenm1] = 0.0f;
426 }
#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING
Definition: SDL_audiocvt.c:381
static double bessel(const double x)
Definition: SDL_audiocvt.c:386
#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 472 of file SDL_audiocvt.c.

473 {
474  if (inrate == outrate) {
475  return 0;
476  } else if (inrate > outrate) {
477  return (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate)));
478  }
480 }
#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 600 of file SDL_audiocvt.c.

601 {
603  return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS);
604  }
605  if (filter == NULL) {
606  return SDL_SetError("Audio filter pointer is NULL");
607  }
608  cvt->filters[cvt->filter_index++] = filter;
609  cvt->filters[cvt->filter_index] = NULL; /* Moving terminator */
610  return 0;
611 }
#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 1645 of file SDL_audiocvt.c.

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

References int(), and 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 1651 of file SDL_audiocvt.c.

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

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 1570 of file SDL_audiocvt.c.

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

References DEBUG_AUDIOSTREAM, int(), 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 1624 of file SDL_audiocvt.c.

1625 {
1626  #if DEBUG_AUDIOSTREAM
1627  printf("AUDIOSTREAM: want to get %d converted bytes\n", len);
1628  #endif
1629 
1630  if (!stream) {
1631  return SDL_InvalidParamError("stream");
1632  } else if (!buf) {
1633  return SDL_InvalidParamError("buf");
1634  } else if (len <= 0) {
1635  return 0; /* nothing to do. */
1636  } else if ((len % stream->dst_sample_frame_size) != 0) {
1637  return SDL_SetError("Can't request partial sample frames");
1638  }
1639 
1640  return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
1641 }
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 1506 of file SDL_audiocvt.c.

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

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

References EnsureStreamBufferSize(), frames, int(), 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 877 of file SDL_audiocvt.c.

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

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

References ChooseCVTResampler(), SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, int(), 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 661 of file SDL_audiocvt.c.

662 {
663  int retval = 0; /* 0 == no conversion necessary. */
664 
665  if (!SDL_AUDIO_ISFLOAT(dst_fmt)) {
666  const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
667  const Uint16 src_bitsize = 32;
669  switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
670  case AUDIO_S8: filter = SDL_Convert_F32_to_S8; break;
671  case AUDIO_U8: filter = SDL_Convert_F32_to_U8; break;
672  case AUDIO_S16: filter = SDL_Convert_F32_to_S16; break;
673  case AUDIO_U16: filter = SDL_Convert_F32_to_U16; break;
674  case AUDIO_S32: filter = SDL_Convert_F32_to_S32; break;
675  default: SDL_assert(!"Unexpected audio format!"); break;
676  }
677 
678  if (!filter) {
679  return SDL_SetError("No conversion from float to format 0x%.4x available", dst_fmt);
680  }
681 
682  if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
683  return -1;
684  }
685  if (src_bitsize < dst_bitsize) {
686  const int mult = (dst_bitsize / src_bitsize);
687  cvt->len_mult *= mult;
688  cvt->len_ratio *= mult;
689  } else if (src_bitsize > dst_bitsize) {
690  cvt->len_ratio /= (src_bitsize / dst_bitsize);
691  }
692  retval = 1; /* added a converter. */
693  }
694 
695  if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
697  return -1;
698  }
699  retval = 1; /* added a converter. */
700  }
701 
702  return retval;
703 }
#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:197
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 614 of file SDL_audiocvt.c.

615 {
616  int retval = 0; /* 0 == no conversion necessary. */
617 
618  if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
620  return -1;
621  }
622  retval = 1; /* added a converter. */
623  }
624 
625  if (!SDL_AUDIO_ISFLOAT(src_fmt)) {
626  const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
627  const Uint16 dst_bitsize = 32;
629 
630  switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
631  case AUDIO_S8: filter = SDL_Convert_S8_to_F32; break;
632  case AUDIO_U8: filter = SDL_Convert_U8_to_F32; break;
633  case AUDIO_S16: filter = SDL_Convert_S16_to_F32; break;
634  case AUDIO_U16: filter = SDL_Convert_U16_to_F32; break;
635  case AUDIO_S32: filter = SDL_Convert_S32_to_F32; break;
636  default: SDL_assert(!"Unexpected audio format!"); break;
637  }
638 
639  if (!filter) {
640  return SDL_SetError("No conversion from source format to float available");
641  }
642 
643  if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
644  return -1;
645  }
646  if (src_bitsize < dst_bitsize) {
647  const int mult = (dst_bitsize / src_bitsize);
648  cvt->len_mult *= mult;
649  cvt->len_ratio *= mult;
650  } else if (src_bitsize > dst_bitsize) {
651  cvt->len_ratio /= (src_bitsize / dst_bitsize);
652  }
653 
654  retval = 1; /* added a converter. */
655  }
656 
657  return retval;
658 }
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 1262 of file SDL_audiocvt.c.

1263 {
1264  SDL_free(stream->resampler_state);
1265 }
#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 334 of file SDL_audiocvt.c.

335 {
336  float lf, rf, lb, rb, ls, rs;
337  int i;
338  const float *src = (const float *) (cvt->buf + cvt->len_cvt);
339  float *dst = (float *) (cvt->buf + cvt->len_cvt * 4 / 3);
340 
341  LOG_DEBUG_CONVERT("5.1", "7.1");
343  SDL_assert(cvt->len_cvt % (sizeof(float) * 6) == 0);
344 
345  for (i = cvt->len_cvt / (sizeof(float) * 6); i; --i) {
346  dst -= 8;
347  src -= 6;
348  lf = src[0];
349  rf = src[1];
350  lb = src[4];
351  rb = src[5];
352  ls = (lf + lb) * 0.5f;
353  rs = (rf + rb) * 0.5f;
354  /* !!! FIXME: these four may clip */
355  lf += lf - ls;
356  rf += rf - ls;
357  lb += lb - ls;
358  rb += rb - ls;
359  dst[3] = src[3]; /* LFE */
360  dst[2] = src[2]; /* FC */
361  dst[7] = rs; /* SR */
362  dst[6] = ls; /* SL */
363  dst[5] = rb; /* BR */
364  dst[4] = lb; /* BL */
365  dst[1] = rf; /* FR */
366  dst[0] = lf; /* FL */
367  }
368 
369  cvt->len_cvt = cvt->len_cvt * 4 / 3;
370 
371  if (cvt->filters[++cvt->filter_index]) {
372  cvt->filters[cvt->filter_index] (cvt, format);
373  }
374 }
#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 180 of file SDL_audiocvt.c.

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

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 102 of file SDL_audiocvt.c.

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

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 150 of file SDL_audiocvt.c.

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

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 562 of file SDL_audiocvt.c.

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

540 {
541  /* !!! FIXME: (cvt) should be const; stack-copy it here. */
542  /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
543 
544  /* Make sure there's data to convert */
545  if (cvt->buf == NULL) {
546  return SDL_SetError("No buffer allocated for conversion");
547  }
548 
549  /* Return okay if no conversion is necessary */
550  cvt->len_cvt = cvt->len;
551  if (cvt->filters[0] == NULL) {
552  return 0;
553  }
554 
555  /* Set up the conversion and go! */
556  cvt->filter_index = 0;
557  cvt->filters[0] (cvt, cvt->src_format);
558  return 0;
559 }

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 209 of file SDL_audiocvt.c.

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

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 267 of file SDL_audiocvt.c.

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

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 127 of file SDL_audiocvt.c.

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

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 233 of file SDL_audiocvt.c.

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

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 80 of file SDL_audiocvt.c.

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

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 304 of file SDL_audiocvt.c.

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

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 1667 of file SDL_audiocvt.c.

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

References SDL_free, and SDL_FreeDataQueue().

Referenced by SDL_NewAudioStream().

◆ SDL_FreeResampleFilter()

void SDL_FreeResampleFilter ( void  )

Definition at line 463 of file SDL_audiocvt.c.

464 {
469 }
static float * ResamplerFilterDifference
Definition: SDL_audiocvt.c:431
static float * ResamplerFilter
Definition: SDL_audiocvt.c:430

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 1268 of file SDL_audiocvt.c.

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

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 434 of file SDL_audiocvt.c.

435 {
437  if (!ResamplerFilter) {
438  /* if dB > 50, beta=(0.1102 * (dB - 8.7)), according to Matlab. */
439  const double dB = 80.0;
440  const double beta = 0.1102 * (dB - 8.7);
441  const size_t alloclen = RESAMPLER_FILTER_SIZE * sizeof (float);
442 
443  ResamplerFilter = (float *) SDL_malloc(alloclen);
444  if (!ResamplerFilter) {
446  return SDL_OutOfMemory();
447  }
448 
449  ResamplerFilterDifference = (float *) SDL_malloc(alloclen);
454  return SDL_OutOfMemory();
455  }
457  }
459  return 0;
460 }
static void kaiser_and_sinc(float *table, float *diffs, const int tablelen, const double beta)
Definition: SDL_audiocvt.c:408
static SDL_SpinLock ResampleFilterSpinlock
Definition: SDL_audiocvt.c:429
#define RESAMPLER_FILTER_SIZE
Definition: SDL_audiocvt.c:382
#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 484 of file SDL_audiocvt.c.

488 {
489  const double finrate = (double) inrate;
490  const double outtimeincr = 1.0 / ((float) outrate);
491  const double ratio = ((float) outrate) / ((float) inrate);
492  const int paddinglen = ResamplerPadding(inrate, outrate);
493  const int framelen = chans * (int)sizeof (float);
494  const int inframes = inbuflen / framelen;
495  const int wantedoutframes = (int) ((inbuflen / framelen) * ratio); /* outbuflen isn't total to write, it's total available. */
496  const int maxoutframes = outbuflen / framelen;
497  const int outframes = SDL_min(wantedoutframes, maxoutframes);
498  float *dst = outbuf;
499  double outtime = 0.0;
500  int i, j, chan;
501 
502  for (i = 0; i < outframes; i++) {
503  const int srcindex = (int) (outtime * inrate);
504  const double intime = ((double) srcindex) / finrate;
505  const double innexttime = ((double) (srcindex + 1)) / finrate;
506  const double interpolation1 = 1.0 - ((innexttime - outtime) / (innexttime - intime));
507  const int filterindex1 = (int) (interpolation1 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
508  const double interpolation2 = 1.0 - interpolation1;
509  const int filterindex2 = (int) (interpolation2 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
510 
511  for (chan = 0; chan < chans; chan++) {
512  float outsample = 0.0f;
513 
514  /* do this twice to calculate the sample, once for the "left wing" and then same for the right. */
515  /* !!! FIXME: do both wings in one loop */
516  for (j = 0; (filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
517  const int srcframe = srcindex - j;
518  /* !!! FIXME: we can bubble this conditional out of here by doing a pre loop. */
519  const float insample = (srcframe < 0) ? lpadding[((paddinglen + srcframe) * chans) + chan] : inbuf[(srcframe * chans) + chan];
520  outsample += (float)(insample * (ResamplerFilter[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation1 * ResamplerFilterDifference[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
521  }
522 
523  for (j = 0; (filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
524  const int srcframe = srcindex + 1 + j;
525  /* !!! FIXME: we can bubble this conditional out of here by doing a post loop. */
526  const float insample = (srcframe >= inframes) ? rpadding[((srcframe - inframes) * chans) + chan] : inbuf[(srcframe * chans) + chan];
527  outsample += (float)(insample * (ResamplerFilter[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation2 * ResamplerFilterDifference[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
528  }
529  *(dst++) = outsample;
530  }
531 
532  outtime += outtimeincr;
533  }
534 
535  return outframes * chans * sizeof (float);
536 }
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, int(), 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 1229 of file SDL_audiocvt.c.

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

References int(), 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 706 of file SDL_audiocvt.c.

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

References AUDIO_F32SYS, SDL_AudioCVT::buf, SDL_AudioCVT::filter_index, SDL_AudioCVT::filters, int(), 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 1254 of file SDL_audiocvt.c.

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

References SDL_memset.

Referenced by SDL_NewAudioStream().

◆ SDL_SupportedAudioFormat()

static SDL_bool SDL_SupportedAudioFormat ( const SDL_AudioFormat  fmt)
static

Definition at line 830 of file SDL_audiocvt.c.

831 {
832  switch (fmt) {
833  case AUDIO_U8:
834  case AUDIO_S8:
835  case AUDIO_U16LSB:
836  case AUDIO_S16LSB:
837  case AUDIO_U16MSB:
838  case AUDIO_S16MSB:
839  case AUDIO_S32LSB:
840  case AUDIO_S32MSB:
841  case AUDIO_F32LSB:
842  case AUDIO_F32MSB:
843  return SDL_TRUE; /* supported. */
844 
845  default:
846  break;
847  }
848 
849  return SDL_FALSE; /* unsupported. */
850 }
#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 853 of file SDL_audiocvt.c.

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

References SDL_FALSE, and SDL_TRUE.

Referenced by SDL_BuildAudioCVT().

Variable Documentation

◆ ResampleFilterSpinlock

SDL_SpinLock ResampleFilterSpinlock = 0
static

Definition at line 429 of file SDL_audiocvt.c.

Referenced by SDL_PrepareResampleFilter().

◆ ResamplerFilter

float* ResamplerFilter = NULL
static

◆ ResamplerFilterDifference

float* ResamplerFilterDifference = NULL
static