Skip to content

Commit

Permalink
audio: libsamplerate can't resample in-place; make space for a copy i…
Browse files Browse the repository at this point in the history
…f needed.
  • Loading branch information
icculus committed Jan 25, 2017
1 parent 1b3327e commit 47e2f4e
Showing 1 changed file with 41 additions and 23 deletions.
64 changes: 41 additions & 23 deletions src/audio/SDL_audiocvt.c
Expand Up @@ -867,7 +867,6 @@ struct SDL_AudioStream
SDL_AudioCVT cvt_before_resampling;
SDL_AudioCVT cvt_after_resampling;
SDL_DataQueue *queue;
Uint8 *work_buffer; /* always aligned to 16 bytes. */
Uint8 *work_buffer_base; /* maybe unaligned pointer from SDL_realloc(). */
int work_buffer_len;
int src_sample_frame_size;
Expand All @@ -887,6 +886,29 @@ struct SDL_AudioStream
SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
};

static Uint8 *
EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
{
Uint8 *ptr;
size_t offset;

if (stream->work_buffer_len >= newlen) {
ptr = stream->work_buffer_base;
} else {
ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32);
if (!ptr) {
SDL_OutOfMemory();
return NULL;
}
/* Make sure we're aligned to 16 bytes for SIMD code. */
stream->work_buffer_base = ptr;
stream->work_buffer_len = newlen;
}

offset = ((size_t) ptr) & 15;
return offset ? ptr + (16 - offset) : ptr;
}

#ifdef HAVE_LIBSAMPLERATE_H
static int
SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
Expand All @@ -898,6 +920,17 @@ SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const i
SRC_DATA data;
int result;

if (inbuf == ((const float *) outbuf)) { /* libsamplerate can't work in-place. */
Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
if (ptr == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
inbuf = (const float *) (ptr + outbuflen);
outbuf = (float *) ptr;
}

data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
data.input_frames = inbuflen / framelen;
data.input_frames_used = 0;
Expand Down Expand Up @@ -1125,24 +1158,6 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format,
return retval;
}

static Uint8 *
EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
{
if (stream->work_buffer_len < newlen) {
Uint8 *ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32);
const size_t offset = ((size_t) ptr) & 15;
if (!ptr) {
SDL_OutOfMemory();
return NULL;
}
/* Make sure we're aligned to 16 bytes for SIMD code. */
stream->work_buffer = offset ? ptr + (16 - offset) : ptr;
stream->work_buffer_base = ptr;
stream->work_buffer_len = newlen;
}
return stream->work_buffer;
}

int
SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
{
Expand Down Expand Up @@ -1190,11 +1205,14 @@ SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _bufle
if (workbuf == NULL) {
return -1; /* probably out of memory. */
}
if (buf == origbuf) { /* copy if we haven't before. */
SDL_memcpy(workbuf, buf, buflen);
/* don't SDL_memcpy(workbuf, buf, buflen) here; our resampler can work inplace or not,
libsamplerate needs buffers to be separate; either way, avoid a copy here if possible. */
if (buf != origbuf) {
buf = workbuf; /* in case we realloc()'d the pointer. */
}
buflen = stream->resampler_func(stream, workbuf, buflen, workbuf, workbuflen);
buf = workbuf;
buflen = stream->resampler_func(stream, buf, buflen, workbuf, workbuflen);
buf = EnsureStreamBufferSize(stream, workbuflen);
SDL_assert(buf != NULL); /* shouldn't be growing, just aligning. */
}

if (stream->cvt_after_resampling.needed) {
Expand Down

0 comments on commit 47e2f4e

Please sign in to comment.