Use templates for audiolib mixing functions

Patch from NY00123.

git-svn-id: https://svn.eduke32.com/eduke32@8183 1a8010ca-5511-0410-912e-c29ae57300e0

# Conflicts:
#	source/audiolib/src/mix.cpp
#	source/audiolib/src/mixst.cpp
This commit is contained in:
terminx 2019-10-19 23:44:53 +00:00 committed by Christoph Oelckers
parent 75205ca69c
commit 9756db95ca
4 changed files with 116 additions and 191 deletions

View file

@ -72,10 +72,53 @@ static inline enable_if_t<is_signed<T>::value, T> SCALE_SAMPLE(T src, float volu
{
return (T)Blrintf((float)src * volume);
}
template <typename T>
static inline enable_if_t<is_unsigned<T>::value, T> SCALE_SAMPLE(T src, float volume)
static inline T CONVERT_SAMPLE_FROM_SIGNED(int32_t src);
template<>
inline int16_t CONVERT_SAMPLE_FROM_SIGNED<int16_t>(int32_t src)
{
return FLIP_SIGN(SCALE_SAMPLE(FLIP_SIGN(src), volume));
return src;
}
template <typename T>
static inline int32_t CONVERT_SAMPLE_TO_SIGNED(T src);
template<>
inline int32_t CONVERT_SAMPLE_TO_SIGNED<int16_t>(int16_t src)
{
return src;
}
template <typename S, typename D>
static inline int32_t CONVERT_LE_SAMPLE_TO_SIGNED(S src);
template<>
inline int32_t CONVERT_LE_SAMPLE_TO_SIGNED<uint8_t, int16_t>(uint8_t src)
{
return FLIP_SIGN(src) << 8;
}
template<>
inline int32_t CONVERT_LE_SAMPLE_TO_SIGNED<int16_t, int16_t>(int16_t src)
{
return B_LITTLE16(src);
}
template <typename T>
static int32_t CLAMP_SAMPLE(int32_t src);
template<>
inline int32_t CLAMP_SAMPLE<int16_t>(int32_t src)
{
return clamp(src, INT16_MIN, INT16_MAX);
}
template <typename T>
static T MIX_SAMPLES(int32_t signed_sample, T untouched_sample)
{
return CONVERT_SAMPLE_FROM_SIGNED<T>(CLAMP_SAMPLE<T>(signed_sample + CONVERT_SAMPLE_TO_SIGNED<T>(untouched_sample)));
}
struct split16_t
@ -214,17 +257,13 @@ void MV_ReleaseXAVoice(VoiceNode *voice);
void MV_ReleaseXMPVoice(VoiceNode *voice);
// implemented in mix.c
uint32_t MV_Mix16BitMono(struct VoiceNode *voice, uint32_t length);
uint32_t MV_Mix16BitStereo(struct VoiceNode *voice, uint32_t length);
uint32_t MV_Mix16BitMono16(struct VoiceNode *voice, uint32_t length);
uint32_t MV_Mix16BitStereo16(struct VoiceNode *voice, uint32_t length);
void MV_16BitReverb(char const *src, char *dest, const float volume, int32_t count);
template <typename S, typename D> uint32_t MV_MixMono(struct VoiceNode * const voice, uint32_t length);
template <typename S, typename D> uint32_t MV_MixStereo(struct VoiceNode * const voice, uint32_t length);
template <typename T> void MV_Reverb(char const *src, char *dest, const float volume, int32_t count);
// implemented in mixst.c
uint32_t MV_Mix16BitMono8Stereo(struct VoiceNode *voice, uint32_t length);
uint32_t MV_Mix16BitStereo8Stereo(struct VoiceNode *voice, uint32_t length);
uint32_t MV_Mix16BitMono16Stereo(struct VoiceNode *voice, uint32_t length);
uint32_t MV_Mix16BitStereo16Stereo(struct VoiceNode *voice, uint32_t length);
template <typename S, typename D> uint32_t MV_MixMonoStereo(struct VoiceNode * const voice, uint32_t length);
template <typename S, typename D> uint32_t MV_MixStereoStereo(struct VoiceNode * const voice, uint32_t length);
extern char *MV_MixDestination; // pointer to the next output sample
extern int32_t MV_SampleSize;

View file

@ -20,6 +20,12 @@
#include "_multivc.h"
template uint32_t MV_MixMono<uint8_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template uint32_t MV_MixStereo<uint8_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template uint32_t MV_MixMono<int16_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template uint32_t MV_MixStereo<int16_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template void MV_Reverb<int16_t>(char const *src, char *dest, const float volume, int32_t count);
/*
length = count of samples to mix
position = offset of starting sample in source
@ -27,11 +33,12 @@
volume = direct volume adjustment, 1.0 = no change
*/
// 8-bit mono source, 16-bit mono output
uint32_t MV_Mix16BitMono(struct VoiceNode * const voice, uint32_t length)
// mono source, mono output
template <typename S, typename D>
uint32_t MV_MixMono(struct VoiceNode * const voice, uint32_t length)
{
auto const source = (uint8_t const *)voice->sound;
auto dest = (int16_t *)MV_MixDestination;
auto const source = (S const *)voice->sound;
auto dest = (D *)MV_MixDestination;
uint32_t position = voice->position;
uint32_t const rate = voice->RateScale;
@ -39,12 +46,12 @@ uint32_t MV_Mix16BitMono(struct VoiceNode * const voice, uint32_t length)
do
{
int32_t const isample0 = FLIP_SIGN(source[position >> 16]) << 8;
auto const isample0 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[position >> 16]);
position += rate;
*dest = (int16_t)clamp(SCALE_SAMPLE(isample0, volume*voice->LeftVolume) + *dest, INT16_MIN, INT16_MAX);
dest += MV_SampleSize >> 1;
*dest = MIX_SAMPLES<D>(SCALE_SAMPLE(isample0, volume*voice->LeftVolume), *dest);
dest++;
voice->LeftVolume = SMOOTH_VOLUME(voice->LeftVolume, voice->LeftVolumeDest);
}
@ -55,11 +62,12 @@ uint32_t MV_Mix16BitMono(struct VoiceNode * const voice, uint32_t length)
return position;
}
// 8-bit mono source, 16-bit stereo output
uint32_t MV_Mix16BitStereo(struct VoiceNode * const voice, uint32_t length)
// mono source, stereo output
template <typename S, typename D>
uint32_t MV_MixStereo(struct VoiceNode * const voice, uint32_t length)
{
auto const source = (uint8_t const *)voice->sound;
auto dest = (int16_t *)MV_MixDestination;
auto const source = (S const *)voice->sound;
auto dest = (D *)MV_MixDestination;
uint32_t position = voice->position;
uint32_t const rate = voice->RateScale;
@ -67,14 +75,14 @@ uint32_t MV_Mix16BitStereo(struct VoiceNode * const voice, uint32_t length)
do
{
int32_t const isample0 = FLIP_SIGN(source[position >> 16]) << 8;
auto const isample0 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[position >> 16]);
position += rate;
*dest = (int16_t)clamp(SCALE_SAMPLE(isample0, volume*voice->LeftVolume) + *dest, INT16_MIN, INT16_MAX);
*(dest + (MV_RightChannelOffset >> 1))
= (int16_t)clamp(SCALE_SAMPLE(isample0, volume*voice->RightVolume) + *(dest + (MV_RightChannelOffset >> 1)), INT16_MIN, INT16_MAX);
dest += MV_SampleSize >> 1;
*dest = MIX_SAMPLES<D>(SCALE_SAMPLE(isample0, volume*voice->LeftVolume), *dest);
*(dest + (MV_RightChannelOffset / sizeof(*dest)))
= MIX_SAMPLES<D>(SCALE_SAMPLE(isample0, volume*voice->RightVolume), *(dest + (MV_RightChannelOffset / sizeof(*dest))));
dest += 2;
voice->LeftVolume = SMOOTH_VOLUME(voice->LeftVolume, voice->LeftVolumeDest);
voice->RightVolume = SMOOTH_VOLUME(voice->RightVolume, voice->RightVolumeDest);
@ -86,79 +94,16 @@ uint32_t MV_Mix16BitStereo(struct VoiceNode * const voice, uint32_t length)
return position;
}
// 16-bit mono source, 16-bit mono output
uint32_t MV_Mix16BitMono16(struct VoiceNode * const voice, uint32_t length)
template <typename T>
void MV_Reverb(char const *src, char *dest, const float volume, int32_t count)
{
auto const source = (int16_t const *)voice->sound;
auto dest = (int16_t *)MV_MixDestination;
uint32_t position = voice->position;
uint32_t const rate = voice->RateScale;
float const volume = voice->volume*MV_GlobalVolume;
auto input = (T const *)src;
auto output = (T *)dest;
do
{
int32_t const isample0 = (int16_t)B_LITTLE16(source[position >> 16]);
position += rate;
int32_t const sample0 = SCALE_SAMPLE(isample0, volume*voice->LeftVolume);
*dest = (int16_t)clamp(sample0 + *dest, INT16_MIN, INT16_MAX);
dest += MV_SampleSize >> 1;
voice->LeftVolume = SMOOTH_VOLUME(voice->LeftVolume, voice->LeftVolumeDest);
}
while (--length);
MV_MixDestination = (char *)dest;
return position;
}
// 16-bit mono source, 16-bit stereo output
uint32_t MV_Mix16BitStereo16(struct VoiceNode * const voice, uint32_t length)
{
auto const source = (int16_t const *)voice->sound;
auto dest = (int16_t *)MV_MixDestination;
uint32_t position = voice->position;
uint32_t const rate = voice->RateScale;
float const volume = voice->volume*MV_GlobalVolume;
do
{
int32_t const isample0 = (int16_t)B_LITTLE16(source[position >> 16]);
position += rate;
int32_t const sample0 = SCALE_SAMPLE(isample0, volume*voice->LeftVolume);
int32_t const sample1 = SCALE_SAMPLE(isample0, volume*voice->RightVolume);
*dest = (int16_t)clamp(sample0 + *dest, INT16_MIN, INT16_MAX);
*(dest + (MV_RightChannelOffset >> 1))
= (int16_t)clamp(sample1 + *(dest + (MV_RightChannelOffset >> 1)), INT16_MIN, INT16_MAX);
dest += MV_SampleSize >> 1;
voice->LeftVolume = SMOOTH_VOLUME(voice->LeftVolume, voice->LeftVolumeDest);
voice->RightVolume = SMOOTH_VOLUME(voice->RightVolume, voice->RightVolumeDest);
}
while (--length);
MV_MixDestination = (char *)dest;
return position;
}
void MV_16BitReverb(char const *src, char *dest, const float volume, int32_t count)
{
auto input = (uint16_t const *)src;
auto output = (int16_t *)dest;
do
{
int16_t const isample0 = (int16_t)*input++;
*output++ = SCALE_SAMPLE(isample0, volume);
auto const isample0 = CONVERT_SAMPLE_TO_SIGNED<T>(*input++);
*output++ = CONVERT_SAMPLE_FROM_SIGNED<T>(SCALE_SAMPLE(isample0, volume));
}
while (--count > 0);
}

View file

@ -20,6 +20,11 @@
#include "_multivc.h"
template uint32_t MV_MixMonoStereo<uint8_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template uint32_t MV_MixStereoStereo<uint8_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template uint32_t MV_MixMonoStereo<int16_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template uint32_t MV_MixStereoStereo<int16_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
/*
length = count of samples to mix
position = offset of starting sample in source
@ -27,11 +32,12 @@
volume = direct volume adjustment, 1.0 = no change
*/
// 8-bit stereo source, 16-bit mono output
uint32_t MV_Mix16BitMono8Stereo(struct VoiceNode * const voice, uint32_t length)
// stereo source, mono output
template <typename S, typename D>
uint32_t MV_MixMonoStereo(struct VoiceNode * const voice, uint32_t length)
{
auto const source = (uint8_t const *)voice->sound;
auto dest = (int16_t *)MV_MixDestination;
auto const source = (S const *)voice->sound;
auto dest = (D *)MV_MixDestination;
uint32_t position = voice->position;
uint32_t const rate = voice->RateScale;
@ -39,13 +45,13 @@ uint32_t MV_Mix16BitMono8Stereo(struct VoiceNode * const voice, uint32_t length)
do
{
int32_t const isample0 = FLIP_SIGN(source[(position >> 16) << 1]) << 8;
int32_t const isample1 = FLIP_SIGN(source[((position >> 16) << 1) + 1]) << 8;
auto const isample0 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[(position >> 16) << 1]);
auto const isample1 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[((position >> 16) << 1) + 1]);
position += rate;
*dest = (int16_t)clamp((SCALE_SAMPLE((isample0 + isample1) >> 1, volume*voice->LeftVolume)) + *dest, INT16_MIN, INT16_MAX);
dest += MV_SampleSize >> 1;
*dest = MIX_SAMPLES<D>((SCALE_SAMPLE((isample0 + isample1) >> 1, volume*voice->LeftVolume)), *dest);
dest++;
voice->LeftVolume = SMOOTH_VOLUME(voice->LeftVolume, voice->LeftVolumeDest);
}
@ -56,11 +62,12 @@ uint32_t MV_Mix16BitMono8Stereo(struct VoiceNode * const voice, uint32_t length)
return position;
}
// 8-bit stereo source, 16-bit stereo output
uint32_t MV_Mix16BitStereo8Stereo(struct VoiceNode * const voice, uint32_t length)
// stereo source, stereo output
template <typename S, typename D>
uint32_t MV_MixStereoStereo(struct VoiceNode * const voice, uint32_t length)
{
auto const source = (uint8_t const *)voice->sound;
auto dest = (int16_t *)MV_MixDestination;
auto const source = (S const *)voice->sound;
auto dest = (D *)MV_MixDestination;
uint32_t position = voice->position;
uint32_t const rate = voice->RateScale;
@ -68,81 +75,15 @@ uint32_t MV_Mix16BitStereo8Stereo(struct VoiceNode * const voice, uint32_t lengt
do
{
int32_t const isample0 = FLIP_SIGN(source[(position >> 16) << 1]) << 8;
int32_t const isample1 = FLIP_SIGN(source[((position >> 16) << 1) + 1]) << 8;
auto const isample0 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[(position >> 16) << 1]);
auto const isample1 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[((position >> 16) << 1) + 1]);
position += rate;
*dest = (int16_t)clamp(SCALE_SAMPLE(isample0, volume*voice->LeftVolume) + *dest, INT16_MIN, INT16_MAX);
*(dest + (MV_RightChannelOffset >> 1))
= (int16_t)clamp(SCALE_SAMPLE(isample1, volume*voice->RightVolume) + *(dest + (MV_RightChannelOffset >> 1)), INT16_MIN, INT16_MAX);
dest += MV_SampleSize >> 1;
voice->LeftVolume = SMOOTH_VOLUME(voice->LeftVolume, voice->LeftVolumeDest);
voice->RightVolume = SMOOTH_VOLUME(voice->RightVolume, voice->RightVolumeDest);
}
while (--length);
MV_MixDestination = (char *)dest;
return position;
}
// 16-bit stereo source, 16-bit mono output
uint32_t MV_Mix16BitMono16Stereo(struct VoiceNode * const voice, uint32_t length)
{
auto const source = (int16_t const *)voice->sound;
auto dest = (int16_t *)MV_MixDestination;
uint32_t position = voice->position;
uint32_t const rate = voice->RateScale;
float const volume = voice->volume*MV_GlobalVolume;
do
{
int32_t const isample0 = (int16_t)B_LITTLE16(source[(position >> 16) << 1]);
int32_t const isample1 = (int16_t)B_LITTLE16(source[((position >> 16) << 1) + 1]);
position += rate;
int32_t const sample0 = SCALE_SAMPLE((isample0 + isample1) >> 1, volume*voice->LeftVolume);
*dest = (int16_t)clamp(sample0 + *dest, INT16_MIN, INT16_MAX);
dest += MV_SampleSize >> 1;
voice->LeftVolume = SMOOTH_VOLUME(voice->LeftVolume, voice->LeftVolumeDest);
}
while (--length);
MV_MixDestination = (char *)dest;
return position;
}
// 16-bit stereo source, 16-bit stereo output
uint32_t MV_Mix16BitStereo16Stereo(struct VoiceNode * const voice, uint32_t length)
{
auto const source = (int16_t const *)voice->sound;
auto dest = (int16_t *)MV_MixDestination;
uint32_t position = voice->position;
uint32_t const rate = voice->RateScale;
float const volume = voice->volume*MV_GlobalVolume;
do
{
int32_t const isample0 = (int16_t)B_LITTLE16(source[(position >> 16) << 1]);
int32_t const isample1 = (int16_t)B_LITTLE16(source[((position >> 16) << 1) + 1]);
position += rate;
int32_t const sample0 = SCALE_SAMPLE(isample0, volume*voice->LeftVolume);
int32_t const sample1 = SCALE_SAMPLE(isample1, volume*voice->RightVolume);
*dest = (int16_t)clamp(sample0 + *dest, INT16_MIN, INT16_MAX);
*(dest + (MV_RightChannelOffset >> 1))
= (int16_t)clamp(sample1 + *(dest + (MV_RightChannelOffset >> 1)), INT16_MIN, INT16_MAX);
dest += MV_SampleSize >> 1;
*dest = MIX_SAMPLES<D>(SCALE_SAMPLE(isample0, volume*voice->LeftVolume), *dest);
*(dest + (MV_RightChannelOffset / sizeof(*dest)))
= MIX_SAMPLES<D>(SCALE_SAMPLE(isample1, volume*voice->RightVolume), *(dest + (MV_RightChannelOffset / sizeof(*dest))));
dest += 2;
voice->LeftVolume = SMOOTH_VOLUME(voice->LeftVolume, voice->LeftVolumeDest);
voice->RightVolume = SMOOTH_VOLUME(voice->RightVolume, voice->RightVolumeDest);

View file

@ -240,7 +240,7 @@ static void MV_ServiceVoc(void)
{
int const count = (source + length > end) ? (end - source) : length;
MV_16BitReverb(source, dest, MV_ReverbVolume, count >> 1);
MV_Reverb<int16_t>(source, dest, MV_ReverbVolume, count >> 1);
// if we go through the loop again, it means that we've wrapped around the buffer
source = MV_MixBuffer[ 0 ];
@ -505,15 +505,15 @@ int32_t MV_SetFrequency(int32_t handle, int32_t frequency)
Mono Ster | Mono Mono Ster Ster | Mixer
Out Out | In In In In |
----------------------+---------------------------+-------------
X | X | Mix16BitMono16
X | X | Mix16BitMono
X | X | Mix16BitStereo16
X | X | Mix16BitStereo
X | X | MixMono<int16_t, int16_t>
X | X | MixMono<uint8_t, int16_t>
X | X | MixStereo<int16_t, int16_t>
X | X | MixStereo<uint8_t, int16_t>
----------------------+---------------------------+-------------
X | X | Mix16BitStereo16Stereo
X | X | Mix16BitStereo8Stereo
X | X | Mix16BitMono16Stereo
X | X | Mix16BitMono8Stereo
X | X | MixStereoStereo<int16_t, int16_t>
X | X | MixStereoStereo<uint8_t, int16_t>
X | X | MixMonoStereo<int16_t, int16_t>
X | X | MixMonoStereo<uint8_t, int16_t>
---------------------------------------------------------------------*/
void MV_SetVoiceMixMode(VoiceNode *voice)
@ -531,8 +531,8 @@ void MV_SetVoiceMixMode(VoiceNode *voice)
// stereo look-up table
static constexpr decltype(voice->mix) mixslut[]
= { MV_Mix16BitStereo, MV_Mix16BitMono, MV_Mix16BitStereo16, MV_Mix16BitMono16,
MV_Mix16BitStereo8Stereo, MV_Mix16BitMono8Stereo, MV_Mix16BitStereo16Stereo, MV_Mix16BitMono16Stereo };
= { MV_MixStereo<uint8_t, int16_t>, MV_MixMono<uint8_t, int16_t>, MV_MixStereo<int16_t, int16_t>, MV_MixMono<int16_t, int16_t>,
MV_MixStereoStereo<uint8_t, int16_t>, MV_MixMonoStereo<uint8_t, int16_t>, MV_MixStereoStereo<int16_t, int16_t>, MV_MixMonoStereo<int16_t, int16_t> };
voice->mix = mixslut[type];
}