mirror of https://github.com/encounter/SDL.git
audio: Improvements in channel conversion code.
This commit is contained in:
parent
35166609d5
commit
38854e0333
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
/* Effectively mix right and left channels into a single channel */
|
/* Effectively mix right and left channels into a single channel */
|
||||||
static void SDLCALL
|
static void SDLCALL
|
||||||
SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
SDL_ConvertStereoToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||||
{
|
{
|
||||||
float *dst = (float *) cvt->buf;
|
float *dst = (float *) cvt->buf;
|
||||||
const float *src = dst;
|
const float *src = dst;
|
||||||
|
@ -51,20 +51,22 @@ SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Discard top 4 channels */
|
/* Convert from 5.1 to stereo. Average left and right, discard subwoofer. */
|
||||||
static void SDLCALL
|
static void SDLCALL
|
||||||
SDL_ConvertStrip(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||||
{
|
{
|
||||||
float *dst = (float *) cvt->buf;
|
float *dst = (float *) cvt->buf;
|
||||||
const float *src = dst;
|
const float *src = dst;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("6 channels", "stereo");
|
LOG_DEBUG_CONVERT("5.1", "stereo");
|
||||||
SDL_assert(format == AUDIO_F32SYS);
|
SDL_assert(format == AUDIO_F32SYS);
|
||||||
|
|
||||||
|
/* this assumes FL+FR+FC+subwoof+BL+BR layout. */
|
||||||
for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 2) {
|
for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 2) {
|
||||||
dst[0] = src[0];
|
const double front_center = (double) src[2];
|
||||||
dst[1] = src[1];
|
dst[0] = (float) ((src[0] + front_center + src[4]) / 3.0); /* left */
|
||||||
|
dst[1] = (float) ((src[1] + front_center + src[5]) / 3.0); /* right */
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt /= 3;
|
cvt->len_cvt /= 3;
|
||||||
|
@ -74,22 +76,25 @@ SDL_ConvertStrip(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Discard top 2 channels of 6 */
|
/* Convert from 5.1 to quad */
|
||||||
static void SDLCALL
|
static void SDLCALL
|
||||||
SDL_ConvertStrip_2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
SDL_Convert51ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||||
{
|
{
|
||||||
float *dst = (float *) cvt->buf;
|
float *dst = (float *) cvt->buf;
|
||||||
const float *src = dst;
|
const float *src = dst;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("6 channels", "quad");
|
LOG_DEBUG_CONVERT("5.1", "quad");
|
||||||
SDL_assert(format == AUDIO_F32SYS);
|
SDL_assert(format == AUDIO_F32SYS);
|
||||||
|
|
||||||
|
/* assumes quad is FL+FR+BL+BR layout and 5.1 is FL+FR+FC+subwoof+BL+BR */
|
||||||
for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 4) {
|
for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 4) {
|
||||||
dst[0] = src[0];
|
/* FIXME: this is a good candidate for SIMD. */
|
||||||
dst[1] = src[1];
|
const double front_center = (double) src[2];
|
||||||
dst[2] = src[2];
|
dst[0] = (float) ((src[0] + front_center) * 0.5); /* FL */
|
||||||
dst[3] = src[3];
|
dst[1] = (float) ((src[1] + front_center) * 0.5); /* FR */
|
||||||
|
dst[2] = (float) ((src[4] + front_center) * 0.5); /* BL */
|
||||||
|
dst[3] = (float) ((src[5] + front_center) * 0.5); /* BR */
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt /= 6;
|
cvt->len_cvt /= 6;
|
||||||
|
@ -99,9 +104,10 @@ SDL_ConvertStrip_2(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Duplicate a mono channel to both stereo channels */
|
/* Duplicate a mono channel to both stereo channels */
|
||||||
static void SDLCALL
|
static void SDLCALL
|
||||||
SDL_ConvertStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
SDL_ConvertMonoToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||||
{
|
{
|
||||||
const float *src = (const float *) (cvt->buf + cvt->len_cvt);
|
const float *src = (const float *) (cvt->buf + cvt->len_cvt);
|
||||||
float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
|
float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
|
||||||
|
@ -125,7 +131,7 @@ SDL_ConvertStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||||
|
|
||||||
/* Duplicate a stereo channel to a pseudo-5.1 stream */
|
/* Duplicate a stereo channel to a pseudo-5.1 stream */
|
||||||
static void SDLCALL
|
static void SDLCALL
|
||||||
SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
SDL_ConvertStereoTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
float lf, rf, ce;
|
float lf, rf, ce;
|
||||||
|
@ -140,12 +146,13 @@ SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||||
src -= 2;
|
src -= 2;
|
||||||
lf = src[0];
|
lf = src[0];
|
||||||
rf = src[1];
|
rf = src[1];
|
||||||
ce = (lf * 0.5f) + (rf * 0.5f);
|
ce = (lf + rf) * 0.5f;
|
||||||
dst[0] = src[0];
|
dst[0] = lf + (lf - ce); /* FL */
|
||||||
dst[1] = src[1];
|
dst[1] = rf + (rf - ce); /* FR */
|
||||||
dst[2] = lf - ce;
|
dst[2] = ce; /* FC */
|
||||||
dst[3] = rf - ce;
|
dst[3] = ce; /* !!! FIXME: wrong! This is the subwoofer. */
|
||||||
dst[4] = dst[5] = ce;
|
dst[4] = lf; /* BL */
|
||||||
|
dst[5] = rf; /* BR */
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt *= 3;
|
cvt->len_cvt *= 3;
|
||||||
|
@ -157,11 +164,11 @@ SDL_ConvertSurround(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||||
|
|
||||||
/* Duplicate a stereo channel to a pseudo-4.0 stream */
|
/* Duplicate a stereo channel to a pseudo-4.0 stream */
|
||||||
static void SDLCALL
|
static void SDLCALL
|
||||||
SDL_ConvertSurround_4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
SDL_ConvertStereoToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||||
{
|
{
|
||||||
const float *src = (const float *) (cvt->buf + cvt->len_cvt);
|
const float *src = (const float *) (cvt->buf + cvt->len_cvt);
|
||||||
float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
|
float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
|
||||||
float lf, rf, ce;
|
float lf, rf;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("stereo", "quad");
|
LOG_DEBUG_CONVERT("stereo", "quad");
|
||||||
|
@ -172,11 +179,10 @@ SDL_ConvertSurround_4(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||||
src -= 2;
|
src -= 2;
|
||||||
lf = src[0];
|
lf = src[0];
|
||||||
rf = src[1];
|
rf = src[1];
|
||||||
ce = (lf / 2) + (rf / 2);
|
dst[0] = lf; /* FL */
|
||||||
dst[0] = src[0];
|
dst[1] = rf; /* FR */
|
||||||
dst[1] = src[1];
|
dst[2] = lf; /* BL */
|
||||||
dst[2] = lf - ce;
|
dst[3] = rf; /* BR */
|
||||||
dst[3] = rf - ce;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt *= 2;
|
cvt->len_cvt *= 2;
|
||||||
|
@ -536,36 +542,36 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
|
||||||
/* Channel conversion */
|
/* Channel conversion */
|
||||||
if (src_channels != dst_channels) {
|
if (src_channels != dst_channels) {
|
||||||
if ((src_channels == 1) && (dst_channels > 1)) {
|
if ((src_channels == 1) && (dst_channels > 1)) {
|
||||||
cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
|
cvt->filters[cvt->filter_index++] = SDL_ConvertMonoToStereo;
|
||||||
cvt->len_mult *= 2;
|
cvt->len_mult *= 2;
|
||||||
src_channels = 2;
|
src_channels = 2;
|
||||||
cvt->len_ratio *= 2;
|
cvt->len_ratio *= 2;
|
||||||
}
|
}
|
||||||
if ((src_channels == 2) && (dst_channels == 6)) {
|
if ((src_channels == 2) && (dst_channels == 6)) {
|
||||||
cvt->filters[cvt->filter_index++] = SDL_ConvertSurround;
|
cvt->filters[cvt->filter_index++] = SDL_ConvertStereoTo51;
|
||||||
src_channels = 6;
|
src_channels = 6;
|
||||||
cvt->len_mult *= 3;
|
cvt->len_mult *= 3;
|
||||||
cvt->len_ratio *= 3;
|
cvt->len_ratio *= 3;
|
||||||
}
|
}
|
||||||
if ((src_channels == 2) && (dst_channels == 4)) {
|
if ((src_channels == 2) && (dst_channels == 4)) {
|
||||||
cvt->filters[cvt->filter_index++] = SDL_ConvertSurround_4;
|
cvt->filters[cvt->filter_index++] = SDL_ConvertStereoToQuad;
|
||||||
src_channels = 4;
|
src_channels = 4;
|
||||||
cvt->len_mult *= 2;
|
cvt->len_mult *= 2;
|
||||||
cvt->len_ratio *= 2;
|
cvt->len_ratio *= 2;
|
||||||
}
|
}
|
||||||
while ((src_channels * 2) <= dst_channels) {
|
while ((src_channels * 2) <= dst_channels) {
|
||||||
cvt->filters[cvt->filter_index++] = SDL_ConvertStereo;
|
cvt->filters[cvt->filter_index++] = SDL_ConvertMonoToStereo;
|
||||||
cvt->len_mult *= 2;
|
cvt->len_mult *= 2;
|
||||||
src_channels *= 2;
|
src_channels *= 2;
|
||||||
cvt->len_ratio *= 2;
|
cvt->len_ratio *= 2;
|
||||||
}
|
}
|
||||||
if ((src_channels == 6) && (dst_channels <= 2)) {
|
if ((src_channels == 6) && (dst_channels <= 2)) {
|
||||||
cvt->filters[cvt->filter_index++] = SDL_ConvertStrip;
|
cvt->filters[cvt->filter_index++] = SDL_Convert51ToStereo;
|
||||||
src_channels = 2;
|
src_channels = 2;
|
||||||
cvt->len_ratio /= 3;
|
cvt->len_ratio /= 3;
|
||||||
}
|
}
|
||||||
if ((src_channels == 6) && (dst_channels == 4)) {
|
if ((src_channels == 6) && (dst_channels == 4)) {
|
||||||
cvt->filters[cvt->filter_index++] = SDL_ConvertStrip_2;
|
cvt->filters[cvt->filter_index++] = SDL_Convert51ToQuad;
|
||||||
src_channels = 4;
|
src_channels = 4;
|
||||||
cvt->len_ratio /= 2;
|
cvt->len_ratio /= 2;
|
||||||
}
|
}
|
||||||
|
@ -575,7 +581,7 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
|
||||||
*/
|
*/
|
||||||
while (((src_channels % 2) == 0) &&
|
while (((src_channels % 2) == 0) &&
|
||||||
((src_channels / 2) >= dst_channels)) {
|
((src_channels / 2) >= dst_channels)) {
|
||||||
cvt->filters[cvt->filter_index++] = SDL_ConvertMono;
|
cvt->filters[cvt->filter_index++] = SDL_ConvertStereoToMono;
|
||||||
src_channels /= 2;
|
src_channels /= 2;
|
||||||
cvt->len_ratio /= 2;
|
cvt->len_ratio /= 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ main(int argc, char **argv)
|
||||||
Uint32 len = 0;
|
Uint32 len = 0;
|
||||||
Uint8 *data = NULL;
|
Uint8 *data = NULL;
|
||||||
int cvtfreq = 0;
|
int cvtfreq = 0;
|
||||||
|
int cvtchans = 0;
|
||||||
int bitsize = 0;
|
int bitsize = 0;
|
||||||
int blockalign = 0;
|
int blockalign = 0;
|
||||||
int avgbytes = 0;
|
int avgbytes = 0;
|
||||||
|
@ -28,12 +29,13 @@ main(int argc, char **argv)
|
||||||
/* Enable standard application logging */
|
/* Enable standard application logging */
|
||||||
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
|
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
|
||||||
|
|
||||||
if (argc != 4) {
|
if (argc != 5) {
|
||||||
SDL_Log("USAGE: %s in.wav out.wav newfreq\n", argv[0]);
|
SDL_Log("USAGE: %s in.wav out.wav newfreq newchans\n", argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cvtfreq = SDL_atoi(argv[3]);
|
cvtfreq = SDL_atoi(argv[3]);
|
||||||
|
cvtchans = SDL_atoi(argv[4]);
|
||||||
|
|
||||||
if (SDL_Init(SDL_INIT_AUDIO) == -1) {
|
if (SDL_Init(SDL_INIT_AUDIO) == -1) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init() failed: %s\n", SDL_GetError());
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init() failed: %s\n", SDL_GetError());
|
||||||
|
@ -47,7 +49,7 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SDL_BuildAudioCVT(&cvt, spec.format, spec.channels, spec.freq,
|
if (SDL_BuildAudioCVT(&cvt, spec.format, spec.channels, spec.freq,
|
||||||
spec.format, spec.channels, cvtfreq) == -1) {
|
spec.format, cvtchans, cvtfreq) == -1) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "failed to build CVT: %s\n", SDL_GetError());
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "failed to build CVT: %s\n", SDL_GetError());
|
||||||
SDL_FreeWAV(data);
|
SDL_FreeWAV(data);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
@ -83,7 +85,7 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
bitsize = SDL_AUDIO_BITSIZE(spec.format);
|
bitsize = SDL_AUDIO_BITSIZE(spec.format);
|
||||||
blockalign = (bitsize / 8) * spec.channels;
|
blockalign = (bitsize / 8) * cvtchans;
|
||||||
avgbytes = cvtfreq * blockalign;
|
avgbytes = cvtfreq * blockalign;
|
||||||
|
|
||||||
SDL_WriteLE32(io, 0x46464952); /* RIFF */
|
SDL_WriteLE32(io, 0x46464952); /* RIFF */
|
||||||
|
@ -92,7 +94,7 @@ main(int argc, char **argv)
|
||||||
SDL_WriteLE32(io, 0x20746D66); /* fmt */
|
SDL_WriteLE32(io, 0x20746D66); /* fmt */
|
||||||
SDL_WriteLE32(io, 16); /* chunk size */
|
SDL_WriteLE32(io, 16); /* chunk size */
|
||||||
SDL_WriteLE16(io, 1); /* uncompressed */
|
SDL_WriteLE16(io, 1); /* uncompressed */
|
||||||
SDL_WriteLE16(io, spec.channels); /* channels */
|
SDL_WriteLE16(io, cvtchans); /* channels */
|
||||||
SDL_WriteLE32(io, cvtfreq); /* sample rate */
|
SDL_WriteLE32(io, cvtfreq); /* sample rate */
|
||||||
SDL_WriteLE32(io, avgbytes); /* average bytes per second */
|
SDL_WriteLE32(io, avgbytes); /* average bytes per second */
|
||||||
SDL_WriteLE16(io, blockalign); /* block align */
|
SDL_WriteLE16(io, blockalign); /* block align */
|
||||||
|
|
Loading…
Reference in New Issue