From ce5658416d2cbbb13c2218e7b23f9c7609ad03ba Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 12 Aug 2010 02:28:27 +0000 Subject: [PATCH] add support for up to 8 channels in sound effect files The sounds are down-mixed to 2 channels (qf does not (yet) support more than 2 channel output), but this allows pretty much anything to be used for a source of music. Only 5.1 (6 channel), stereo and mono have been tested, but the others should work (any issues would be mis-interpretation/implementation of the channel layout). --- include/snd_render.h | 18 ++-- libs/audio/renderer/flac.c | 2 +- libs/audio/renderer/snd_mix.c | 195 ++++++++++++++++++++++++++++++++-- libs/audio/renderer/vorbis.c | 2 +- libs/audio/renderer/wav.c | 2 +- 5 files changed, 200 insertions(+), 19 deletions(-) diff --git a/include/snd_render.h b/include/snd_render.h index 5c7c1abaf..ebf9b437d 100644 --- a/include/snd_render.h +++ b/include/snd_render.h @@ -50,6 +50,14 @@ typedef struct channel_s channel_t; typedef struct sfxbuffer_s sfxbuffer_t; typedef struct sfxblock_s sfxblock_t; typedef struct sfxstream_s sfxstream_t; +/** paint samples into the mix buffer + \param offset offset into the mix buffer at which to start mixing + the channel + \param ch sound channel + \param buffer sound data + \param count number of frames to paint +*/ +typedef void sfxpaint_t (int, channel_t *, float *, unsigned); /** Represent a sound sample in the mixer. */ @@ -99,15 +107,7 @@ struct sfxbuffer_s { unsigned length; //!< length of buffer in frames unsigned pos; //!< position of tail within full stream unsigned channels; //!< number of channels per frame - /** paint samples into the mix buffer - \param offset offset into the mix buffer at which to start mixing - the channel - \param ch sound channel - \param buffer sound data - \param count number of frames to paint - */ - void (*paint) (int offset, channel_t *ch, float *buffer, - unsigned count); + sfxpaint_t *paint; //!< channel count specific paint function /** Advance the position with the stream, updating the ring buffer as necessary. Null for chached sounds. \param buffer "this" diff --git a/libs/audio/renderer/flac.c b/libs/audio/renderer/flac.c index de06b0d79..cd146b052 100644 --- a/libs/audio/renderer/flac.c +++ b/libs/audio/renderer/flac.c @@ -453,7 +453,7 @@ SND_LoadFLAC (QFile *file, sfx_t *sfx, char *realname) return -1; } info = flac_get_info (ff); - if (info.channels < 1 || info.channels > 2) { + if (info.channels < 1 || info.channels > 8) { Sys_Printf ("unsupported number of channels"); return -1; } diff --git a/libs/audio/renderer/snd_mix.c b/libs/audio/renderer/snd_mix.c index 9befdddbd..da5e829b9 100644 --- a/libs/audio/renderer/snd_mix.c +++ b/libs/audio/renderer/snd_mix.c @@ -47,7 +47,7 @@ static __attribute__ ((used)) const char rcsid[] = #include "compat.h" #include "snd_render.h" -#define VOLSCALE 1024.0 // so mixing is less likely to overflow +#define VOLSCALE 512.0 // so mixing is less likely to overflow // note: must be >= 255 due to the channel // volumes being 0-255. @@ -179,6 +179,45 @@ SND_PaintChannels (unsigned endtime) } } +static inline void +snd_mix_single (portable_samplepair_t *pair, float **samp, + float lvol, float rvol) +{ + float single = *(*samp)++; + + pair->left += single * lvol; + pair->right += single * rvol; +} + +static inline void +snd_mix_pair (portable_samplepair_t *pair, float **samp, + float lvol, float rvol) +{ + float left = *(*samp)++; + float right = *(*samp)++; + + pair->left += left * lvol; + pair->right += right * rvol; +} + +static inline void +snd_mix_tripple (portable_samplepair_t *pair, float **samp, + float lvol, float rvol) +{ + float left = *(*samp)++; + float center = *(*samp)++; + float right = *(*samp)++; + + pair->left += left * lvol; + pair->left += center * lvol; + pair->right += center * rvol; + pair->right += right * rvol; +} + +/* mono + center + Spacializes the sound. +*/ static void snd_paint_mono (int offs, channel_t *ch, float *sfx, unsigned count) { @@ -273,6 +312,10 @@ snd_paint_mono (int offs, channel_t *ch, float *sfx, unsigned count) } } +/* stereo + left, right + Does not spacialize the sound. +*/ static void snd_paint_stereo (int offs, channel_t *ch, float *samp, unsigned count) { @@ -282,8 +325,135 @@ snd_paint_stereo (int offs, channel_t *ch, float *samp, unsigned count) pair = snd_paintbuffer + offs; while (count-- > 0) { - pair->left += *samp++ * leftvol; - pair->right += *samp++ * rightvol; + snd_mix_pair (pair, &samp, leftvol, rightvol); + pair++; + } +} + +/* 1d surround + left, center, right + Does not spacialize the sound. +*/ +static void +snd_paint_3 (int offs, channel_t *ch, float *samp, unsigned count) +{ + portable_samplepair_t *pair; + float leftvol = ch->leftvol / VOLSCALE; + float rightvol = ch->rightvol / VOLSCALE; + + pair = snd_paintbuffer + offs; + while (count-- > 0) { + snd_mix_tripple (pair, &samp, leftvol, rightvol); + pair++; + } +} + +/* quadraphonic surround + front (left, right), + rear (left, right) + Does not spacialize the sound. +*/ +static void +snd_paint_4 (int offs, channel_t *ch, float *samp, unsigned count) +{ + portable_samplepair_t *pair; + float leftvol = ch->leftvol / VOLSCALE; + float rightvol = ch->rightvol / VOLSCALE; + + pair = snd_paintbuffer + offs; + while (count-- > 0) { + snd_mix_pair (pair, &samp, leftvol, rightvol); + snd_mix_pair (pair, &samp, leftvol, rightvol); + pair++; + } +} + +/* five-channel surround + front (left, center, right), + rear (left, right) + Does not spacialize the sound. +*/ +static void +snd_paint_5 (int offs, channel_t *ch, float *samp, unsigned count) +{ + portable_samplepair_t *pair; + float leftvol = ch->leftvol / VOLSCALE; + float rightvol = ch->rightvol / VOLSCALE; + + pair = snd_paintbuffer + offs; + while (count-- > 0) { + snd_mix_tripple (pair, &samp, leftvol, rightvol); + snd_mix_pair (pair, &samp, leftvol, rightvol); + pair++; + } +} + +/* 5.1 surround + front (left, center, right), + rear (left, right), + lfe + Does not spacialize the sound. +*/ +static void +snd_paint_6 (int offs, channel_t *ch, float *samp, unsigned count) +{ + portable_samplepair_t *pair; + float leftvol = ch->leftvol / VOLSCALE; + float rightvol = ch->rightvol / VOLSCALE; + + pair = snd_paintbuffer + offs; + while (count-- > 0) { + snd_mix_tripple (pair, &samp, leftvol, rightvol); + snd_mix_pair (pair, &samp, leftvol, rightvol); + snd_mix_single (pair, &samp, leftvol, rightvol); + pair++; + } +} + +/* 6.1 surround + front (left, center, right), + side (left, right), + rear (center), + lfe + Does not spacialize the sound. +*/ +static void +snd_paint_7 (int offs, channel_t *ch, float *samp, unsigned count) +{ + portable_samplepair_t *pair; + float leftvol = ch->leftvol / VOLSCALE; + float rightvol = ch->rightvol / VOLSCALE; + + pair = snd_paintbuffer + offs; + while (count-- > 0) { + snd_mix_tripple (pair, &samp, leftvol, rightvol); + snd_mix_pair (pair, &samp, leftvol, rightvol); + snd_mix_single (pair, &samp, leftvol, rightvol); + snd_mix_single (pair, &samp, leftvol, rightvol); + pair++; + } +} + +/* 7.1 surround + front (left, center, right), + side (left, right), + rear (left, right), + lfe + Does not spacialize the sound. +*/ +static void +snd_paint_8 (int offs, channel_t *ch, float *samp, unsigned count) +{ + portable_samplepair_t *pair; + float leftvol = ch->leftvol / VOLSCALE; + float rightvol = ch->rightvol / VOLSCALE; + + pair = snd_paintbuffer + offs; + while (count-- > 0) { + snd_mix_tripple (pair, &samp, leftvol, rightvol); + snd_mix_pair (pair, &samp, leftvol, rightvol); + snd_mix_pair (pair, &samp, leftvol, rightvol); + snd_mix_single (pair, &samp, leftvol, rightvol); pair++; } } @@ -291,9 +461,20 @@ snd_paint_stereo (int offs, channel_t *ch, float *samp, unsigned count) void SND_SetPaint (sfxbuffer_t *sc) { + static sfxpaint_t *painters[] = { + 0, + snd_paint_mono, + snd_paint_stereo, + snd_paint_3, + snd_paint_4, + snd_paint_5, + snd_paint_6, + snd_paint_7, + snd_paint_8, + }; + wavinfo_t *info = sc->sfx->wavinfo (sc->sfx); - if (info->channels == 2) - sc->paint = snd_paint_stereo; - else - sc->paint = snd_paint_mono; + if (info->channels < 0 || info->channels > 8) + Sys_Error ("illegal channel count %d", info->channels); + sc->paint = painters[info->channels]; } diff --git a/libs/audio/renderer/vorbis.c b/libs/audio/renderer/vorbis.c index 4dae1c60f..e5459741c 100644 --- a/libs/audio/renderer/vorbis.c +++ b/libs/audio/renderer/vorbis.c @@ -297,7 +297,7 @@ SND_LoadOgg (QFile *file, sfx_t *sfx, char *realname) return -1; } info = vorbis_get_info (&vf); - if (info.channels < 1 || info.channels > 2) { + if (info.channels < 1 || info.channels > 8) { Sys_Printf ("unsupported number of channels"); return -1; } diff --git a/libs/audio/renderer/wav.c b/libs/audio/renderer/wav.c index c14c33dfe..2f0ef77a5 100644 --- a/libs/audio/renderer/wav.c +++ b/libs/audio/renderer/wav.c @@ -241,7 +241,7 @@ wav_get_info (QFile *file) Sys_Printf ("not Microsfot PCM\n"); goto bail; } - if (dfmt->channels < 1 || dfmt->channels > 2) { + if (dfmt->channels < 1 || dfmt->channels > 8) { Sys_Printf ("unsupported channel count\n"); goto bail; }