aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/converter.c
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2017-04-11 07:25:55 -0700
committerChris Robinson <[email protected]>2017-04-11 07:25:55 -0700
commitbcdd1cee10f6f2ebe51191b104b0e45c261801e6 (patch)
tree3b8bfaea2e31bab0c164430f022bce2c5b3c17aa /Alc/converter.c
parentcaae349fdc16a761cda511f74c4cc5c611f5591a (diff)
Add a mono<->stereo converter
This converter always outputs floats, and uses energy-preserving scaling.
Diffstat (limited to 'Alc/converter.c')
-rw-r--r--Alc/converter.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/Alc/converter.c b/Alc/converter.c
index 1ea2e70f..ebbc0966 100644
--- a/Alc/converter.c
+++ b/Alc/converter.c
@@ -330,3 +330,125 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
return pos;
}
+
+
+ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans)
+{
+ ChannelConverter *converter;
+
+ if(srcChans != dstChans && !((srcChans == DevFmtMono && dstChans == DevFmtStereo) ||
+ (srcChans == DevFmtStereo && dstChans == DevFmtMono)))
+ return NULL;
+
+ converter = al_calloc(DEF_ALIGN, sizeof(*converter));
+ converter->mSrcType = srcType;
+ converter->mSrcChans = srcChans;
+ converter->mDstChans = dstChans;
+
+ return converter;
+}
+
+void DestroyChannelConverter(ChannelConverter **converter)
+{
+ if(converter)
+ {
+ al_free(*converter);
+ *converter = NULL;
+ }
+}
+
+
+#define DECL_TEMPLATE(T) \
+static void MonoConvert##T(ALfloat *restrict dst, const T *src, ALsizei frames)\
+{ \
+ const T *data = (T*)src; \
+ ALsizei i; \
+ \
+ for(i = 0;i < frames;i++) \
+ dst[i*2 + 1] = dst[i*2 + 0] = Sample_##T(data[i]) * 0.707106781187f; \
+} \
+ \
+static void StereoConvert##T(ALfloat *restrict dst, const T *src, ALsizei frames)\
+{ \
+ const T *data = (T*)src; \
+ ALsizei i; \
+ \
+ for(i = 0;i < frames;i++) \
+ dst[i] = (Sample_##T(data[i*2 + 0])+Sample_##T(data[i*2 + 1])) * \
+ 0.707106781187f; \
+}
+
+DECL_TEMPLATE(ALbyte)
+DECL_TEMPLATE(ALubyte)
+DECL_TEMPLATE(ALshort)
+DECL_TEMPLATE(ALushort)
+DECL_TEMPLATE(ALint)
+DECL_TEMPLATE(ALuint)
+DECL_TEMPLATE(ALfloat)
+
+#undef DECL_TEMPLATE
+
+void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames)
+{
+ if(converter->mSrcChans == converter->mDstChans)
+ {
+ LoadSamples(dst, src, 1, converter->mSrcType,
+ frames*ChannelsFromDevFmt(converter->mSrcChans));
+ return;
+ }
+
+ if(converter->mSrcChans == DevFmtStereo && converter->mDstChans == DevFmtMono)
+ {
+ switch(converter->mSrcType)
+ {
+ case DevFmtByte:
+ MonoConvertALbyte(dst, src, frames);
+ break;
+ case DevFmtUByte:
+ MonoConvertALubyte(dst, src, frames);
+ break;
+ case DevFmtShort:
+ MonoConvertALshort(dst, src, frames);
+ break;
+ case DevFmtUShort:
+ MonoConvertALushort(dst, src, frames);
+ break;
+ case DevFmtInt:
+ MonoConvertALint(dst, src, frames);
+ break;
+ case DevFmtUInt:
+ MonoConvertALuint(dst, src, frames);
+ break;
+ case DevFmtFloat:
+ MonoConvertALfloat(dst, src, frames);
+ break;
+ }
+ }
+ else /*if(converter->mSrcChans == DevFmtMono && converter->mDstChans == DevFmtStereo)*/
+ {
+ switch(converter->mSrcType)
+ {
+ case DevFmtByte:
+ StereoConvertALbyte(dst, src, frames);
+ break;
+ case DevFmtUByte:
+ StereoConvertALubyte(dst, src, frames);
+ break;
+ case DevFmtShort:
+ StereoConvertALshort(dst, src, frames);
+ break;
+ case DevFmtUShort:
+ StereoConvertALushort(dst, src, frames);
+ break;
+ case DevFmtInt:
+ StereoConvertALint(dst, src, frames);
+ break;
+ case DevFmtUInt:
+ StereoConvertALuint(dst, src, frames);
+ break;
+ case DevFmtFloat:
+ StereoConvertALfloat(dst, src, frames);
+ break;
+ }
+ }
+}