Mercurial > sdl-ios-xcode
view src/audio/SDL_audiocvt.c @ 5080:6d94060d16a9
Fixed bug #1011
Daniel Ellis 2010-06-25 15:20:31 PDT
SDL based applications sometimes display the wrong application name in the
Sound Preferences dialog when using pulseaudio.
I can see from the code that the SDL pulse module is initiating a new pulse
audio context and passing an application name using the function
get_progname().
The get_progname() function returns the name of the current process. However,
the process name is often not a suitable name to use. For example, the OpenShot
video editor is a python application, and so "python" is displayed in the Sound
Preferences window (see Bug #596504), when it should be displaying "OpenShot".
PulseAudio allows applications to specify the application name, either at the
time the context is created (as SDL does currently), or by special environment
variables (see http://www.pulseaudio.org/wiki/ApplicationProperties). If no
name is specified, then pulseaudio will determine the name based on the
process.
If you specify the application name when initiating the pulseaudio context,
then that will override any application name specified using an environment
variable.
As libsdl is a library, I believe the solution is for libsdl to not specify any
application name when initiating a pulseaudio context, which will enable
applications to specify the application name using environment variables. In
the case that the applications do not specify anything, pulseaudio will fall
back to using the process name anyway.
The attached patch removes the get_progname() function and passes NULL as the
application name when creating the pulseaudio context, which fixes the issue.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sun, 23 Jan 2011 21:55:04 -0800 |
parents | f7b03b6838cb |
children | b530ef003506 |
line wrap: on
line source
/* 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: */