summaryrefslogtreecommitdiff
path: root/macosx/plugins/Common/SDL/src/audio/SDL_audiocvt.c
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/plugins/Common/SDL/src/audio/SDL_audiocvt.c')
-rw-r--r--macosx/plugins/Common/SDL/src/audio/SDL_audiocvt.c1080
1 files changed, 1080 insertions, 0 deletions
diff --git a/macosx/plugins/Common/SDL/src/audio/SDL_audiocvt.c b/macosx/plugins/Common/SDL/src/audio/SDL_audiocvt.c
new file mode 100644
index 00000000..3af35f13
--- /dev/null
+++ b/macosx/plugins/Common/SDL/src/audio/SDL_audiocvt.c
@@ -0,0 +1,1080 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2010 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Functions for audio drivers to perform runtime conversion of audio format */
+
+#include "SDL_audio.h"
+#include "SDL_audio_c.h"
+
+/* #define DEBUG_CONVERT */
+
+/* !!! FIXME */
+#ifndef assert
+#define assert(x)
+#endif
+
+/* Effectively mix right and left channels into a single channel */
+static void SDLCALL
+SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ int i;
+ Sint32 sample;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting to mono\n");
+#endif
+ switch (format & (SDL_AUDIO_MASK_SIGNED | SDL_AUDIO_MASK_BITSIZE)) {
+ case AUDIO_U8:
+ {
+ Uint8 *src, *dst;
+
+ src = cvt->buf;
+ dst = cvt->buf;
+ for (i = cvt->len_cvt / 2; i; --i) {
+ sample = src[0] + src[1];
+ *dst = (Uint8) (sample / 2);
+ src += 2;
+ dst += 1;
+ }
+ }
+ break;
+
+ case AUDIO_S8:
+ {
+ Sint8 *src, *dst;
+
+ src = (Sint8 *) cvt->buf;
+ dst = (Sint8 *) cvt->buf;
+ for (i = cvt->len_cvt / 2; i; --i) {
+ sample = src[0] + src[1];
+ *dst = (Sint8) (sample / 2);
+ src += 2;
+ dst += 1;
+ }
+ }
+ break;
+
+ case AUDIO_U16:
+ {
+ Uint8 *src, *dst;
+
+ src = cvt->buf;
+ dst = cvt->buf;
+ if (SDL_AUDIO_ISBIGENDIAN(format)) {
+ for (i = cvt->len_cvt / 4; i; --i) {
+ sample = (Uint16) ((src[0] << 8) | src[1]) +
+ (Uint16) ((src[2] << 8) | src[3]);
+ sample /= 2;
+ dst[1] = (sample & 0xFF);
+ sample >>= 8;
+ dst[0] = (sample & 0xFF);
+ src += 4;
+ dst += 2;
+ }
+ } else {
+ for (i = cvt->len_cvt / 4; i; --i) {
+ sample = (Uint16) ((src[1] << 8) | src[0]) +
+ (Uint16) ((src[3] << 8) | src[2]);
+ sample /= 2;
+ dst[0] = (sample & 0xFF);
+ sample >>= 8;
+ dst[1] = (sample & 0xFF);
+ src += 4;
+ dst += 2;
+ }
+ }
+ }
+ break;
+
+ case AUDIO_S16:
+ {
+ Uint8 *src, *dst;
+
+ src = cvt->buf;
+ dst = cvt->buf;
+ if (SDL_AUDIO_ISBIGENDIAN(format)) {
+ for (i = cvt->len_cvt / 4; i; --i) {
+ sample = (Sint16) ((src[0] << 8) | src[1]) +
+ (Sint16) ((src[2] << 8) | src[3]);
+ sample /= 2;
+ dst[1] = (sample & 0xFF);
+ sample >>= 8;
+ dst[0] = (sample & 0xFF);
+ src += 4;
+ dst += 2;
+ }
+ } else {
+ for (i = cvt->len_cvt / 4; i; --i) {
+ sample = (Sint16) ((src[1] << 8) | src[0]) +
+ (Sint16) ((src[3] << 8) | src[2]);
+ sample /= 2;
+ dst[0] = (sample & 0xFF);
+ sample >>= 8;
+ dst[1] = (sample & 0xFF);
+ src += 4;
+ dst += 2;
+ }
+ }
+ }
+ break;
+
+ case AUDIO_S32:
+ {
+ const Uint32 *src = (const Uint32 *) cvt->buf;
+ Uint32 *dst = (Uint32 *) cvt->buf;
+ if (SDL_AUDIO_ISBIGENDIAN(format)) {
+ for (i = cvt->len_cvt / 8; i; --i, src += 2) {
+ const Sint64 added =
+ (((Sint64) (Sint32) SDL_SwapBE32(src[0])) +
+ ((Sint64) (Sint32) SDL_SwapBE32(src[1])));
+ *(dst++) = SDL_SwapBE32((Uint32) ((Sint32) (added / 2)));
+ }
+ } else {
+ for (i = cvt->len_cvt / 8; i; --i, src += 2) {
+ const Sint64 added =
+ (((Sint64) (Sint32) SDL_SwapLE32(src[0])) +
+ ((Sint64) (Sint32) SDL_SwapLE32(src[1])));
+ *(dst++) = SDL_SwapLE32((Uint32) ((Sint32) (added / 2)));
+ }
+ }
+ }
+ break;
+
+ case AUDIO_F32:
+ {
+ const float *src = (const float *) cvt->buf;
+ float *dst = (float *) cvt->buf;
+ if (SDL_AUDIO_ISBIGENDIAN(format)) {
+ for (i = cvt->len_cvt / 8; i; --i, src += 2) {
+ const float src1 = SDL_SwapFloatBE(src[0]);
+ const float src2 = SDL_SwapFloatBE(src[1]);
+ const double added = ((double) src1) + ((double) src2);
+ const float halved = (float) (added * 0.5);
+ *(dst++) = SDL_SwapFloatBE(halved);
+ }
+ } else {
+ for (i = cvt->len_cvt / 8; i; --i, src += 2) {
+ const float src1 = SDL_SwapFloatLE(src[0]);
+ const float src2 = SDL_SwapFloatLE(src[1]);
+ const double added = ((double) src1) + ((double) src2);
+ const float halved = (float) (added * 0.5);
+ *(dst++) = SDL_SwapFloatLE(halved);
+ }
+ }
+ }
+ break;
+ }
+
+ cvt->len_cvt /= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+/* Discard top 4 channels */
+static void SDLCALL
+SDL_ConvertStrip(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ int i;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting down from 6 channels to stereo\n");
+#endif
+
+#define strip_chans_6_to_2(type) \
+ { \
+ const type *src = (const type *) cvt->buf; \
+ type *dst = (type *) cvt->buf; \
+ for (i = cvt->len_cvt / (sizeof (type) * 6); i; --i) { \
+ dst[0] = src[0]; \
+ dst[1] = src[1]; \
+ src += 6; \
+ dst += 2; \
+ } \
+ }
+
+ /* this function only cares about typesize, and data as a block of bits. */
+ switch (SDL_AUDIO_BITSIZE(format)) {
+ case 8:
+ strip_chans_6_to_2(Uint8);
+ break;
+ case 16:
+ strip_chans_6_to_2(Uint16);
+ break;
+ case 32:
+ strip_chans_6_to_2(Uint32);
+ break;
+ }
+
+#undef strip_chans_6_to_2
+
+ cvt->len_cvt /= 3;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+/* Discard top 2 channels of 6 */
+static void SDLCALL
+SDL_ConvertStrip_2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ int i;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting 6 down to quad\n");
+#endif
+
+#define strip_chans_6_to_4(type) \
+ { \
+ const type *src = (const type *) cvt->buf; \
+ type *dst = (type *) cvt->buf; \
+ for (i = cvt->len_cvt / (sizeof (type) * 6); i; --i) { \
+ dst[0] = src[0]; \
+ dst[1] = src[1]; \
+ dst[2] = src[2]; \
+ dst[3] = src[3]; \
+ src += 6; \
+ dst += 4; \
+ } \
+ }
+
+ /* this function only cares about typesize, and data as a block of bits. */
+ switch (SDL_AUDIO_BITSIZE(format)) {
+ case 8:
+ strip_chans_6_to_4(Uint8);
+ break;
+ case 16:
+ strip_chans_6_to_4(Uint16);
+ break;
+ case 32:
+ strip_chans_6_to_4(Uint32);
+ break;
+ }
+
+#undef strip_chans_6_to_4
+
+ cvt->len_cvt /= 6;
+ cvt->len_cvt *= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+/* Duplicate a mono channel to both stereo channels */
+static void SDLCALL
+SDL_ConvertStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ int i;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting to stereo\n");
+#endif
+
+#define dup_chans_1_to_2(type) \
+ { \
+ const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
+ type *dst = (type *) (cvt->buf + cvt->len_cvt * 2); \
+ for (i = cvt->len_cvt / 2; i; --i, --src) { \
+ const type val = *src; \
+ dst -= 2; \
+ dst[0] = dst[1] = val; \
+ } \
+ }
+
+ /* this function only cares about typesize, and data as a block of bits. */
+ switch (SDL_AUDIO_BITSIZE(format)) {
+ case 8:
+ dup_chans_1_to_2(Uint8);
+ break;
+ case 16:
+ dup_chans_1_to_2(Uint16);
+ break;
+ case 32:
+ dup_chans_1_to_2(Uint32);
+ break;
+ }
+
+#undef dup_chans_1_to_2
+
+ cvt->len_cvt *= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+/* Duplicate a stereo channel to a pseudo-5.1 stream */
+static void SDLCALL
+SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ int i;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting stereo to surround\n");
+#endif
+
+ switch (format & (SDL_AUDIO_MASK_SIGNED | SDL_AUDIO_MASK_BITSIZE)) {
+ case AUDIO_U8:
+ {
+ Uint8 *src, *dst, lf, rf, ce;
+
+ src = (Uint8 *) (cvt->buf + cvt->len_cvt);
+ dst = (Uint8 *) (cvt->buf + cvt->len_cvt * 3);
+ for (i = cvt->len_cvt; i; --i) {
+ dst -= 6;
+ src -= 2;
+ lf = src[0];
+ rf = src[1];
+ ce = (lf / 2) + (rf / 2);
+ dst[0] = lf;
+ dst[1] = rf;
+ dst[2] = lf - ce;
+ dst[3] = rf - ce;
+ dst[4] = ce;
+ dst[5] = ce;
+ }
+ }
+ break;
+
+ case AUDIO_S8:
+ {
+ Sint8 *src, *dst, lf, rf, ce;
+
+ src = (Sint8 *) cvt->buf + cvt->len_cvt;
+ dst = (Sint8 *) cvt->buf + cvt->len_cvt * 3;
+ for (i = cvt->len_cvt; i; --i) {
+ dst -= 6;
+ src -= 2;
+ lf = src[0];
+ rf = src[1];
+ ce = (lf / 2) + (rf / 2);
+ dst[0] = lf;
+ dst[1] = rf;
+ dst[2] = lf - ce;
+ dst[3] = rf - ce;
+ dst[4] = ce;
+ dst[5] = ce;
+ }
+ }
+ break;
+
+ case AUDIO_U16:
+ {
+ Uint8 *src, *dst;
+ Uint16 lf, rf, ce, lr, rr;
+
+ src = cvt->buf + cvt->len_cvt;
+ dst = cvt->buf + cvt->len_cvt * 3;
+
+ if (SDL_AUDIO_ISBIGENDIAN(format)) {
+ for (i = cvt->len_cvt / 4; i; --i) {
+ dst -= 12;
+ src -= 4;
+ lf = (Uint16) ((src[0] << 8) | src[1]);
+ rf = (Uint16) ((src[2] << 8) | src[3]);
+ ce = (lf / 2) + (rf / 2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[1] = (lf & 0xFF);
+ dst[0] = ((lf >> 8) & 0xFF);
+ dst[3] = (rf & 0xFF);
+ dst[2] = ((rf >> 8) & 0xFF);
+
+ dst[1 + 4] = (lr & 0xFF);
+ dst[0 + 4] = ((lr >> 8) & 0xFF);
+ dst[3 + 4] = (rr & 0xFF);
+ dst[2 + 4] = ((rr >> 8) & 0xFF);
+
+ dst[1 + 8] = (ce & 0xFF);
+ dst[0 + 8] = ((ce >> 8) & 0xFF);
+ dst[3 + 8] = (ce & 0xFF);
+ dst[2 + 8] = ((ce >> 8) & 0xFF);
+ }
+ } else {
+ for (i = cvt->len_cvt / 4; i; --i) {
+ dst -= 12;
+ src -= 4;
+ lf = (Uint16) ((src[1] << 8) | src[0]);
+ rf = (Uint16) ((src[3] << 8) | src[2]);
+ ce = (lf / 2) + (rf / 2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[0] = (lf & 0xFF);
+ dst[1] = ((lf >> 8) & 0xFF);
+ dst[2] = (rf & 0xFF);
+ dst[3] = ((rf >> 8) & 0xFF);
+
+ dst[0 + 4] = (lr & 0xFF);
+ dst[1 + 4] = ((lr >> 8) & 0xFF);
+ dst[2 + 4] = (rr & 0xFF);
+ dst[3 + 4] = ((rr >> 8) & 0xFF);
+
+ dst[0 + 8] = (ce & 0xFF);
+ dst[1 + 8] = ((ce >> 8) & 0xFF);
+ dst[2 + 8] = (ce & 0xFF);
+ dst[3 + 8] = ((ce >> 8) & 0xFF);
+ }
+ }
+ }
+ break;
+
+ case AUDIO_S16:
+ {
+ Uint8 *src, *dst;
+ Sint16 lf, rf, ce, lr, rr;
+
+ src = cvt->buf + cvt->len_cvt;
+ dst = cvt->buf + cvt->len_cvt * 3;
+
+ if (SDL_AUDIO_ISBIGENDIAN(format)) {
+ for (i = cvt->len_cvt / 4; i; --i) {
+ dst -= 12;
+ src -= 4;
+ lf = (Sint16) ((src[0] << 8) | src[1]);
+ rf = (Sint16) ((src[2] << 8) | src[3]);
+ ce = (lf / 2) + (rf / 2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[1] = (lf & 0xFF);
+ dst[0] = ((lf >> 8) & 0xFF);
+ dst[3] = (rf & 0xFF);
+ dst[2] = ((rf >> 8) & 0xFF);
+
+ dst[1 + 4] = (lr & 0xFF);
+ dst[0 + 4] = ((lr >> 8) & 0xFF);
+ dst[3 + 4] = (rr & 0xFF);
+ dst[2 + 4] = ((rr >> 8) & 0xFF);
+
+ dst[1 + 8] = (ce & 0xFF);
+ dst[0 + 8] = ((ce >> 8) & 0xFF);
+ dst[3 + 8] = (ce & 0xFF);
+ dst[2 + 8] = ((ce >> 8) & 0xFF);
+ }
+ } else {
+ for (i = cvt->len_cvt / 4; i; --i) {
+ dst -= 12;
+ src -= 4;
+ lf = (Sint16) ((src[1] << 8) | src[0]);
+ rf = (Sint16) ((src[3] << 8) | src[2]);
+ ce = (lf / 2) + (rf / 2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[0] = (lf & 0xFF);
+ dst[1] = ((lf >> 8) & 0xFF);
+ dst[2] = (rf & 0xFF);
+ dst[3] = ((rf >> 8) & 0xFF);
+
+ dst[0 + 4] = (lr & 0xFF);
+ dst[1 + 4] = ((lr >> 8) & 0xFF);
+ dst[2 + 4] = (rr & 0xFF);
+ dst[3 + 4] = ((rr >> 8) & 0xFF);
+
+ dst[0 + 8] = (ce & 0xFF);
+ dst[1 + 8] = ((ce >> 8) & 0xFF);
+ dst[2 + 8] = (ce & 0xFF);
+ dst[3 + 8] = ((ce >> 8) & 0xFF);
+ }
+ }
+ }
+ break;
+
+ case AUDIO_S32:
+ {
+ Sint32 lf, rf, ce;
+ const Uint32 *src = (const Uint32 *) cvt->buf + cvt->len_cvt;
+ Uint32 *dst = (Uint32 *) cvt->buf + cvt->len_cvt * 3;
+
+ if (SDL_AUDIO_ISBIGENDIAN(format)) {
+ for (i = cvt->len_cvt / 8; i; --i) {
+ dst -= 6;
+ src -= 2;
+ lf = (Sint32) SDL_SwapBE32(src[0]);
+ rf = (Sint32) SDL_SwapBE32(src[1]);
+ ce = (lf / 2) + (rf / 2);
+ dst[0] = SDL_SwapBE32((Uint32) lf);
+ dst[1] = SDL_SwapBE32((Uint32) rf);
+ dst[2] = SDL_SwapBE32((Uint32) (lf - ce));
+ dst[3] = SDL_SwapBE32((Uint32) (rf - ce));
+ dst[4] = SDL_SwapBE32((Uint32) ce);
+ dst[5] = SDL_SwapBE32((Uint32) ce);
+ }
+ } else {
+ for (i = cvt->len_cvt / 8; i; --i) {
+ dst -= 6;
+ src -= 2;
+ lf = (Sint32) SDL_SwapLE32(src[0]);
+ rf = (Sint32) SDL_SwapLE32(src[1]);
+ ce = (lf / 2) + (rf / 2);
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = SDL_SwapLE32((Uint32) (lf - ce));
+ dst[3] = SDL_SwapLE32((Uint32) (rf - ce));
+ dst[4] = SDL_SwapLE32((Uint32) ce);
+ dst[5] = SDL_SwapLE32((Uint32) ce);
+ }
+ }
+ }
+ break;
+
+ case AUDIO_F32:
+ {
+ float lf, rf, ce;
+ const float *src = (const float *) cvt->buf + cvt->len_cvt;
+ float *dst = (float *) cvt->buf + cvt->len_cvt * 3;
+
+ if (SDL_AUDIO_ISBIGENDIAN(format)) {
+ for (i = cvt->len_cvt / 8; i; --i) {
+ dst -= 6;
+ src -= 2;
+ lf = SDL_SwapFloatBE(src[0]);
+ rf = SDL_SwapFloatBE(src[1]);
+ ce = (lf * 0.5f) + (rf * 0.5f);
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = SDL_SwapFloatBE(lf - ce);
+ dst[3] = SDL_SwapFloatBE(rf - ce);
+ dst[4] = dst[5] = SDL_SwapFloatBE(ce);
+ }
+ } else {
+ for (i = cvt->len_cvt / 8; i; --i) {
+ dst -= 6;
+ src -= 2;
+ lf = SDL_SwapFloatLE(src[0]);
+ rf = SDL_SwapFloatLE(src[1]);
+ ce = (lf * 0.5f) + (rf * 0.5f);
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = SDL_SwapFloatLE(lf - ce);
+ dst[3] = SDL_SwapFloatLE(rf - ce);
+ dst[4] = dst[5] = SDL_SwapFloatLE(ce);
+ }
+ }
+ }
+ break;
+
+ }
+ cvt->len_cvt *= 3;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+/* Duplicate a stereo channel to a pseudo-4.0 stream */
+static void SDLCALL
+SDL_ConvertSurround_4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ int i;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting stereo to quad\n");
+#endif
+
+ switch (format & (SDL_AUDIO_MASK_SIGNED | SDL_AUDIO_MASK_BITSIZE)) {
+ case AUDIO_U8:
+ {
+ Uint8 *src, *dst, lf, rf, ce;
+
+ src = (Uint8 *) (cvt->buf + cvt->len_cvt);
+ dst = (Uint8 *) (cvt->buf + cvt->len_cvt * 2);
+ for (i = cvt->len_cvt; i; --i) {
+ dst -= 4;
+ src -= 2;
+ lf = src[0];
+ rf = src[1];
+ ce = (lf / 2) + (rf / 2);
+ dst[0] = lf;
+ dst[1] = rf;
+ dst[2] = lf - ce;
+ dst[3] = rf - ce;
+ }
+ }
+ break;
+
+ case AUDIO_S8:
+ {
+ Sint8 *src, *dst, lf, rf, ce;
+
+ src = (Sint8 *) cvt->buf + cvt->len_cvt;
+ dst = (Sint8 *) cvt->buf + cvt->len_cvt * 2;
+ for (i = cvt->len_cvt; i; --i) {
+ dst -= 4;
+ src -= 2;
+ lf = src[0];
+ rf = src[1];
+ ce = (lf / 2) + (rf / 2);
+ dst[0] = lf;
+ dst[1] = rf;
+ dst[2] = lf - ce;
+ dst[3] = rf - ce;
+ }
+ }
+ break;
+
+ case AUDIO_U16:
+ {
+ Uint8 *src, *dst;
+ Uint16 lf, rf, ce, lr, rr;
+
+ src = cvt->buf + cvt->len_cvt;
+ dst = cvt->buf + cvt->len_cvt * 2;
+
+ if (SDL_AUDIO_ISBIGENDIAN(format)) {
+ for (i = cvt->len_cvt / 4; i; --i) {
+ dst -= 8;
+ src -= 4;
+ lf = (Uint16) ((src[0] << 8) | src[1]);
+ rf = (Uint16) ((src[2] << 8) | src[3]);
+ ce = (lf / 2) + (rf / 2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[1] = (lf & 0xFF);
+ dst[0] = ((lf >> 8) & 0xFF);
+ dst[3] = (rf & 0xFF);
+ dst[2] = ((rf >> 8) & 0xFF);
+
+ dst[1 + 4] = (lr & 0xFF);
+ dst[0 + 4] = ((lr >> 8) & 0xFF);
+ dst[3 + 4] = (rr & 0xFF);
+ dst[2 + 4] = ((rr >> 8) & 0xFF);
+ }
+ } else {
+ for (i = cvt->len_cvt / 4; i; --i) {
+ dst -= 8;
+ src -= 4;
+ lf = (Uint16) ((src[1] << 8) | src[0]);
+ rf = (Uint16) ((src[3] << 8) | src[2]);
+ ce = (lf / 2) + (rf / 2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[0] = (lf & 0xFF);
+ dst[1] = ((lf >> 8) & 0xFF);
+ dst[2] = (rf & 0xFF);
+ dst[3] = ((rf >> 8) & 0xFF);
+
+ dst[0 + 4] = (lr & 0xFF);
+ dst[1 + 4] = ((lr >> 8) & 0xFF);
+ dst[2 + 4] = (rr & 0xFF);
+ dst[3 + 4] = ((rr >> 8) & 0xFF);
+ }
+ }
+ }
+ break;
+
+ case AUDIO_S16:
+ {
+ Uint8 *src, *dst;
+ Sint16 lf, rf, ce, lr, rr;
+
+ src = cvt->buf + cvt->len_cvt;
+ dst = cvt->buf + cvt->len_cvt * 2;
+
+ if (SDL_AUDIO_ISBIGENDIAN(format)) {
+ for (i = cvt->len_cvt / 4; i; --i) {
+ dst -= 8;
+ src -= 4;
+ lf = (Sint16) ((src[0] << 8) | src[1]);
+ rf = (Sint16) ((src[2] << 8) | src[3]);
+ ce = (lf / 2) + (rf / 2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[1] = (lf & 0xFF);
+ dst[0] = ((lf >> 8) & 0xFF);
+ dst[3] = (rf & 0xFF);
+ dst[2] = ((rf >> 8) & 0xFF);
+
+ dst[1 + 4] = (lr & 0xFF);
+ dst[0 + 4] = ((lr >> 8) & 0xFF);
+ dst[3 + 4] = (rr & 0xFF);
+ dst[2 + 4] = ((rr >> 8) & 0xFF);
+ }
+ } else {
+ for (i = cvt->len_cvt / 4; i; --i) {
+ dst -= 8;
+ src -= 4;
+ lf = (Sint16) ((src[1] << 8) | src[0]);
+ rf = (Sint16) ((src[3] << 8) | src[2]);
+ ce = (lf / 2) + (rf / 2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[0] = (lf & 0xFF);
+ dst[1] = ((lf >> 8) & 0xFF);
+ dst[2] = (rf & 0xFF);
+ dst[3] = ((rf >> 8) & 0xFF);
+
+ dst[0 + 4] = (lr & 0xFF);
+ dst[1 + 4] = ((lr >> 8) & 0xFF);
+ dst[2 + 4] = (rr & 0xFF);
+ dst[3 + 4] = ((rr >> 8) & 0xFF);
+ }
+ }
+ }
+ break;
+
+ case AUDIO_S32:
+ {
+ const Uint32 *src = (const Uint32 *) (cvt->buf + cvt->len_cvt);
+ Uint32 *dst = (Uint32 *) (cvt->buf + cvt->len_cvt * 2);
+ Sint32 lf, rf, ce;
+
+ if (SDL_AUDIO_ISBIGENDIAN(format)) {
+ for (i = cvt->len_cvt / 8; i; --i) {
+ dst -= 4;
+ src -= 2;
+ lf = (Sint32) SDL_SwapBE32(src[0]);
+ rf = (Sint32) SDL_SwapBE32(src[1]);
+ ce = (lf / 2) + (rf / 2);
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = SDL_SwapBE32((Uint32) (lf - ce));
+ dst[3] = SDL_SwapBE32((Uint32) (rf - ce));
+ }
+ } else {
+ for (i = cvt->len_cvt / 8; i; --i) {
+ dst -= 4;
+ src -= 2;
+ lf = (Sint32) SDL_SwapLE32(src[0]);
+ rf = (Sint32) SDL_SwapLE32(src[1]);
+ ce = (lf / 2) + (rf / 2);
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = SDL_SwapLE32((Uint32) (lf - ce));
+ dst[3] = SDL_SwapLE32((Uint32) (rf - ce));
+ }
+ }
+ }
+ break;
+ }
+ cvt->len_cvt *= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+int
+SDL_ConvertAudio(SDL_AudioCVT * cvt)
+{
+ /* !!! FIXME: (cvt) should be const; stack-copy it here. */
+ /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
+
+ /* Make sure there's data to convert */
+ if (cvt->buf == NULL) {
+ SDL_SetError("No buffer allocated for conversion");
+ return (-1);
+ }
+ /* Return okay if no conversion is necessary */
+ cvt->len_cvt = cvt->len;
+ if (cvt->filters[0] == NULL) {
+ return (0);
+ }
+
+ /* Set up the conversion and go! */
+ cvt->filter_index = 0;
+ cvt->filters[0] (cvt, cvt->src_format);
+ return (0);
+}
+
+
+static SDL_AudioFilter
+SDL_HandTunedTypeCVT(SDL_AudioFormat src_fmt, SDL_AudioFormat dst_fmt)
+{
+ /*
+ * Fill in any future conversions that are specialized to a
+ * processor, platform, compiler, or library here.
+ */
+
+ return NULL; /* no specialized converter code available. */
+}
+
+
+/*
+ * Find a converter between two data types. We try to select a hand-tuned
+ * asm/vectorized/optimized function first, and then fallback to an
+ * autogenerated function that is customized to convert between two
+ * specific data types.
+ */
+static int
+SDL_BuildAudioTypeCVT(SDL_AudioCVT * cvt,
+ SDL_AudioFormat src_fmt, SDL_AudioFormat dst_fmt)
+{
+ if (src_fmt != dst_fmt) {
+ const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
+ const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
+ SDL_AudioFilter filter = SDL_HandTunedTypeCVT(src_fmt, dst_fmt);
+
+ /* No hand-tuned converter? Try the autogenerated ones. */
+ if (filter == NULL) {
+ int i;
+ for (i = 0; sdl_audio_type_filters[i].filter != NULL; i++) {
+ const SDL_AudioTypeFilters *filt = &sdl_audio_type_filters[i];
+ if ((filt->src_fmt == src_fmt) && (filt->dst_fmt == dst_fmt)) {
+ filter = filt->filter;
+ break;
+ }
+ }
+
+ if (filter == NULL) {
+ SDL_SetError("No conversion available for these formats");
+ return -1;
+ }
+ }
+
+ /* Update (cvt) with filter details... */
+ cvt->filters[cvt->filter_index++] = filter;
+ if (src_bitsize < dst_bitsize) {
+ const int mult = (dst_bitsize / src_bitsize);
+ cvt->len_mult *= mult;
+ cvt->len_ratio *= mult;
+ } else if (src_bitsize > dst_bitsize) {
+ cvt->len_ratio /= (src_bitsize / dst_bitsize);
+ }
+
+ return 1; /* added a converter. */
+ }
+
+ return 0; /* no conversion necessary. */
+}
+
+
+static SDL_AudioFilter
+SDL_HandTunedResampleCVT(SDL_AudioCVT * cvt, int dst_channels,
+ int src_rate, int dst_rate)
+{
+ /*
+ * Fill in any future conversions that are specialized to a
+ * processor, platform, compiler, or library here.
+ */
+
+ return NULL; /* no specialized converter code available. */
+}
+
+static int
+SDL_FindFrequencyMultiple(const int src_rate, const int dst_rate)
+{
+ int retval = 0;
+
+ /* If we only built with the arbitrary resamplers, ignore multiples. */
+#if !LESS_RESAMPLERS
+ int lo, hi;
+ int div;
+
+ assert(src_rate != 0);
+ assert(dst_rate != 0);
+ assert(src_rate != dst_rate);
+
+ if (src_rate < dst_rate) {
+ lo = src_rate;
+ hi = dst_rate;
+ } else {
+ lo = dst_rate;
+ hi = src_rate;
+ }
+
+ /* zero means "not a supported multiple" ... we only do 2x and 4x. */
+ if ((hi % lo) != 0)
+ return 0; /* not a multiple. */
+
+ div = hi / lo;
+ retval = ((div == 2) || (div == 4)) ? div : 0;
+#endif
+
+ return retval;
+}
+
+static int
+SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, int dst_channels,
+ int src_rate, int dst_rate)
+{
+ if (src_rate != dst_rate) {
+ SDL_AudioFilter filter = SDL_HandTunedResampleCVT(cvt, dst_channels,
+ src_rate, dst_rate);
+
+ /* No hand-tuned converter? Try the autogenerated ones. */
+ if (filter == NULL) {
+ int i;
+ const int upsample = (src_rate < dst_rate) ? 1 : 0;
+ const int multiple =
+ SDL_FindFrequencyMultiple(src_rate, dst_rate);
+
+ for (i = 0; sdl_audio_rate_filters[i].filter != NULL; i++) {
+ const SDL_AudioRateFilters *filt = &sdl_audio_rate_filters[i];
+ if ((filt->fmt == cvt->dst_format) &&
+ (filt->channels == dst_channels) &&
+ (filt->upsample == upsample) &&
+ (filt->multiple == multiple)) {
+ filter = filt->filter;
+ break;
+ }
+ }
+
+ if (filter == NULL) {
+ SDL_SetError("No conversion available for these rates");
+ return -1;
+ }
+ }
+
+ /* Update (cvt) with filter details... */
+ cvt->filters[cvt->filter_index++] = filter;
+ if (src_rate < dst_rate) {
+ const double mult = ((double) dst_rate) / ((double) src_rate);
+ cvt->len_mult *= (int) SDL_ceil(mult);
+ cvt->len_ratio *= mult;
+ } else {
+ cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
+ }
+
+ return 1; /* added a converter. */
+ }
+
+ return 0; /* no conversion necessary. */
+}
+
+
+/* Creates a set of audio filters to convert from one format to another.
+ Returns -1 if the format conversion is not supported, 0 if there's
+ no conversion needed, or 1 if the audio filter is set up.
+*/
+
+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)
+{
+ /*
+ * !!! FIXME: reorder filters based on which grow/shrink the buffer.
+ * !!! FIXME: ideally, we should do everything that shrinks the buffer
+ * !!! FIXME: first, so we don't have to process as many bytes in a given
+ * !!! FIXME: filter and abuse the CPU cache less. This might not be as
+ * !!! FIXME: good in practice as it sounds in theory, though.
+ */
+
+ /* there are no unsigned types over 16 bits, so catch this up front. */
+ if ((SDL_AUDIO_BITSIZE(src_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(src_fmt))) {
+ SDL_SetError("Invalid source format");
+ return -1;
+ }
+ if ((SDL_AUDIO_BITSIZE(dst_fmt) > 16) && (!SDL_AUDIO_ISSIGNED(dst_fmt))) {
+ SDL_SetError("Invalid destination format");
+ return -1;
+ }
+
+ /* prevent possible divisions by zero, etc. */
+ if ((src_rate == 0) || (dst_rate == 0)) {
+ SDL_SetError("Source or destination rate is zero");
+ return -1;
+ }
+#ifdef DEBUG_CONVERT
+ printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
+ src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
+#endif
+
+ /* Start off with no conversion necessary */
+ SDL_zerop(cvt);
+ cvt->src_format = src_fmt;
+ cvt->dst_format = dst_fmt;
+ cvt->needed = 0;
+ cvt->filter_index = 0;
+ cvt->filters[0] = NULL;
+ cvt->len_mult = 1;
+ cvt->len_ratio = 1.0;
+ cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
+
+ /* Convert data types, if necessary. Updates (cvt). */
+ if (SDL_BuildAudioTypeCVT(cvt, src_fmt, dst_fmt) == -1) {
+ return -1; /* shouldn't happen, but just in case... */
+ }
+
+ /* Channel conversion */
+ if (src_channels != dst_channels) {
+ if ((src_channels == 1) && (dst_channels > 1)) {
+ cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
+ cvt->len_mult *= 2;
+ src_channels = 2;
+ cvt->len_ratio *= 2;
+ }
+ if ((src_channels == 2) && (dst_channels == 6)) {
+ cvt->filters[cvt->filter_index++] = SDL_ConvertSurround;
+ src_channels = 6;
+ cvt->len_mult *= 3;
+ cvt->len_ratio *= 3;
+ }
+ if ((src_channels == 2) && (dst_channels == 4)) {
+ cvt->filters[cvt->filter_index++] = SDL_ConvertSurround_4;
+ src_channels = 4;
+ cvt->len_mult *= 2;
+ cvt->len_ratio *= 2;
+ }
+ while ((src_channels * 2) <= dst_channels) {
+ cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
+ cvt->len_mult *= 2;
+ src_channels *= 2;
+ cvt->len_ratio *= 2;
+ }
+ if ((src_channels == 6) && (dst_channels <= 2)) {
+ cvt->filters[cvt->filter_index++] = SDL_ConvertStrip;
+ src_channels = 2;
+ cvt->len_ratio /= 3;
+ }
+ if ((src_channels == 6) && (dst_channels == 4)) {
+ cvt->filters[cvt->filter_index++] = SDL_ConvertStrip_2;
+ src_channels = 4;
+ cvt->len_ratio /= 2;
+ }
+ /* This assumes that 4 channel audio is in the format:
+ Left {front/back} + Right {front/back}
+ so converting to L/R stereo works properly.
+ */
+ while (((src_channels % 2) == 0) &&
+ ((src_channels / 2) >= dst_channels)) {
+ cvt->filters[cvt->filter_index++] = SDL_ConvertMono;
+ src_channels /= 2;
+ cvt->len_ratio /= 2;
+ }
+ if (src_channels != dst_channels) {
+ /* Uh oh.. */ ;
+ }
+ }
+
+ /* Do rate conversion, if necessary. Updates (cvt). */
+ if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) ==
+ -1) {
+ return -1; /* shouldn't happen, but just in case... */
+ }
+
+ /* Set up the filter information */
+ if (cvt->filter_index != 0) {
+ cvt->needed = 1;
+ cvt->src_format = src_fmt;
+ cvt->dst_format = dst_fmt;
+ cvt->len = 0;
+ cvt->buf = NULL;
+ cvt->filters[cvt->filter_index] = NULL;
+ }
+ return (cvt->needed);
+}
+
+
+/* vi: set ts=4 sw=4 expandtab: */