/* Audio File Library Copyright (C) 2010, Michael Pruett 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SIMPLE_MODULE_H #define SIMPLE_MODULE_H #include "config.h" #include "Compiler.h" #include "Module.h" #include "byteorder.h" #include #include #include #include class SimpleModule : public Module { public: virtual void runPull() OVERRIDE; virtual void runPush() OVERRIDE; virtual void run(Chunk &inChunk, Chunk &outChunk) = 0; }; struct SwapModule : public SimpleModule { public: virtual const char *name() const OVERRIDE { return "swap"; } virtual void describe() OVERRIDE { m_outChunk->f.byteOrder = m_inChunk->f.byteOrder == AF_BYTEORDER_BIGENDIAN ? AF_BYTEORDER_LITTLEENDIAN : AF_BYTEORDER_BIGENDIAN; } virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE { switch (m_inChunk->f.bytesPerSample(false)) { case 2: run<2, int16_t>(inChunk, outChunk); break; case 3: run<3, char>(inChunk, outChunk); break; case 4: run<4, int32_t>(inChunk, outChunk); break; case 8: run<8, int64_t>(inChunk, outChunk); break; default: assert(false); break; } } private: template void run(Chunk &inChunk, Chunk &outChunk) { int sampleCount = inChunk.f.channelCount * inChunk.frameCount; runSwap(reinterpret_cast(inChunk.buffer), reinterpret_cast(outChunk.buffer), sampleCount); } template void runSwap(const T *input, T *output, int sampleCount) { for (int i=0; i inline void SwapModule::runSwap<3, char>(const char *input, char *output, int count) { for (int i=0; i void transform(const void *srcData, void *dstData, size_t count) { typedef typename UnaryFunction::argument_type InputType; typedef typename UnaryFunction::result_type OutputType; const InputType *src = reinterpret_cast(srcData); OutputType *dst = reinterpret_cast(dstData); std::transform(src, src + count, dst, UnaryFunction()); } template struct IntTypes; template <> struct IntTypes { typedef int8_t SignedType; typedef uint8_t UnsignedType; }; template <> struct IntTypes { typedef int16_t SignedType; typedef uint16_t UnsignedType; }; template <> struct IntTypes { typedef int32_t SignedType; typedef uint32_t UnsignedType; }; template <> struct IntTypes { typedef int32_t SignedType; typedef uint32_t UnsignedType; }; template struct signConverter { typedef typename IntTypes::SignedType SignedType; typedef typename IntTypes::UnsignedType UnsignedType; static const int kScaleBits = (Format + 1) * CHAR_BIT - 1; static const int kMinSignedValue = 0-(1U< { UnsignedType operator()(SignedType x) { return x - kMinSignedValue; } }; struct unsignedToSigned : public std::unary_function { SignedType operator()(UnsignedType x) { return x + kMinSignedValue; } }; }; class ConvertSign : public SimpleModule { public: ConvertSign(FormatCode format, bool fromSigned) : m_format(format), m_fromSigned(fromSigned) { } virtual const char *name() const OVERRIDE { return "sign"; } virtual void describe() OVERRIDE { const int scaleBits = m_inChunk->f.bytesPerSample(false) * CHAR_BIT; m_outChunk->f.sampleFormat = m_fromSigned ? AF_SAMPFMT_UNSIGNED : AF_SAMPFMT_TWOSCOMP; double shift = -(1 << (scaleBits - 1)); if (m_fromSigned) shift = -shift; m_outChunk->f.pcm.intercept += shift; m_outChunk->f.pcm.minClip += shift; m_outChunk->f.pcm.maxClip += shift; } virtual void run(Chunk &input, Chunk &output) OVERRIDE { size_t count = input.frameCount * m_inChunk->f.channelCount; if (m_fromSigned) convertSignedToUnsigned(input.buffer, output.buffer, count); else convertUnsignedToSigned(input.buffer, output.buffer, count); } private: FormatCode m_format; bool m_fromSigned; template static void convertSignedToUnsigned(const void *src, void *dst, size_t count) { transform::signedToUnsigned>(src, dst, count); } void convertSignedToUnsigned(const void *src, void *dst, size_t count) { switch (m_format) { case kInt8: convertSignedToUnsigned(src, dst, count); break; case kInt16: convertSignedToUnsigned(src, dst, count); break; case kInt24: convertSignedToUnsigned(src, dst, count); break; case kInt32: convertSignedToUnsigned(src, dst, count); break; default: assert(false); } } template static void convertUnsignedToSigned(const void *src, void *dst, size_t count) { transform::unsignedToSigned>(src, dst, count); } void convertUnsignedToSigned(const void *src, void *dst, size_t count) { switch (m_format) { case kInt8: convertUnsignedToSigned(src, dst, count); break; case kInt16: convertUnsignedToSigned(src, dst, count); break; case kInt24: convertUnsignedToSigned(src, dst, count); break; case kInt32: convertUnsignedToSigned(src, dst, count); break; default: assert(false); } } }; struct Expand3To4Module : public SimpleModule { public: Expand3To4Module(bool isSigned) : m_isSigned(isSigned) { } virtual const char *name() const OVERRIDE { return "expand3to4"; } virtual void describe() OVERRIDE { m_outChunk->f.packed = false; } virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE { int count = inChunk.f.channelCount * inChunk.frameCount; if (m_isSigned) run(reinterpret_cast(inChunk.buffer), reinterpret_cast(outChunk.buffer), count); else run(reinterpret_cast(inChunk.buffer), reinterpret_cast(outChunk.buffer), count); } private: bool m_isSigned; template void run(const uint8_t *input, T *output, int sampleCount) { for (int i=0; i> 8; } } }; struct Compress4To3Module : public SimpleModule { public: Compress4To3Module(bool isSigned) : m_isSigned(isSigned) { } virtual const char *name() const OVERRIDE { return "compress4to3"; } virtual void describe() OVERRIDE { m_outChunk->f.packed = true; } virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE { int count = inChunk.f.channelCount * inChunk.frameCount; if (m_isSigned) run(inChunk.buffer, outChunk.buffer, count); else run(inChunk.buffer, outChunk.buffer, count); } private: bool m_isSigned; template void run(const void *input, void *output, int count) { const T *in = reinterpret_cast(input); uint8_t *out = reinterpret_cast(output); for (int i=0; i void extract3(T in, uint8_t &c0, uint8_t &c1, uint8_t &c2) { #ifdef WORDS_BIGENDIAN c0 = (in >> 16) & 0xff; c1 = (in >> 8) & 0xff; c2 = in & 0xff; #else c2 = (in >> 16) & 0xff; c1 = (in >> 8) & 0xff; c0 = in & 0xff; #endif } }; template struct intToFloat : public std::unary_function { Result operator()(Arg x) const { return x; } }; struct ConvertIntToFloat : public SimpleModule { ConvertIntToFloat(FormatCode inFormat, FormatCode outFormat) : m_inFormat(inFormat), m_outFormat(outFormat) { } virtual const char *name() const OVERRIDE { return "intToFloat"; } virtual void describe() OVERRIDE { m_outChunk->f.sampleFormat = m_outFormat == kDouble ? AF_SAMPFMT_DOUBLE : AF_SAMPFMT_FLOAT; m_outChunk->f.sampleWidth = m_outFormat == kDouble ? 64 : 32; } virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE { const void *src = inChunk.buffer; void *dst = outChunk.buffer; int count = inChunk.frameCount * inChunk.f.channelCount; if (m_outFormat == kFloat) { switch (m_inFormat) { case kInt8: run(src, dst, count); break; case kInt16: run(src, dst, count); break; case kInt24: case kInt32: run(src, dst, count); break; default: assert(false); } } else if (m_outFormat == kDouble) { switch (m_inFormat) { case kInt8: run(src, dst, count); break; case kInt16: run(src, dst, count); break; case kInt24: case kInt32: run(src, dst, count); break; default: assert(false); } } } private: FormatCode m_inFormat, m_outFormat; template static void run(const void *src, void *dst, int count) { transform >(src, dst, count); } }; template struct lshift : public std::unary_function { Result operator()(const Arg &x) const { return x << shift; } }; template struct rshift : public std::unary_function { Result operator()(const Arg &x) const { return x >> shift; } }; struct ConvertInt : public SimpleModule { ConvertInt(FormatCode inFormat, FormatCode outFormat) : m_inFormat(inFormat), m_outFormat(outFormat) { assert(isInteger(m_inFormat)); assert(isInteger(m_outFormat)); } virtual const char *name() const OVERRIDE { return "convertInt"; } virtual void describe() OVERRIDE { getDefaultPCMMapping(m_outChunk->f.sampleWidth, m_outChunk->f.pcm.slope, m_outChunk->f.pcm.intercept, m_outChunk->f.pcm.minClip, m_outChunk->f.pcm.maxClip); } virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE { const void *src = inChunk.buffer; void *dst = outChunk.buffer; size_t count = inChunk.frameCount * inChunk.f.channelCount; #define MASK(N, M) (((N)<<3) | (M)) #define HANDLE(N, M) \ case MASK(N, M): convertInt(src, dst, count); break; switch (MASK(m_inFormat, m_outFormat)) { HANDLE(kInt8, kInt16) HANDLE(kInt8, kInt24) HANDLE(kInt8, kInt32) HANDLE(kInt16, kInt8) HANDLE(kInt16, kInt24) HANDLE(kInt16, kInt32) HANDLE(kInt24, kInt8) HANDLE(kInt24, kInt16) HANDLE(kInt24, kInt32) HANDLE(kInt32, kInt8) HANDLE(kInt32, kInt16) HANDLE(kInt32, kInt24) } #undef MASK #undef HANDLE } private: FormatCode m_inFormat, m_outFormat; void getDefaultPCMMapping(int &bits, double &slope, double &intercept, double &minClip, double &maxClip) { bits = (m_outFormat + 1) * CHAR_BIT; slope = (1LL << (bits - 1)); intercept = 0; minClip = -(1 << (bits - 1)); maxClip = (1LL << (bits - 1)) - 1; } static bool isInteger(FormatCode code) { return code >= kInt8 && code <= kInt32; } template Output)> struct shift; template struct shift : public rshift::SignedType, typename IntTypes::SignedType, (Input - Output) * CHAR_BIT> { }; template struct shift : public lshift::SignedType, typename IntTypes::SignedType, (Output - Input) * CHAR_BIT> { }; template static void convertInt(const void *src, void *dst, int count) { transform >(src, dst, count); } }; template struct floatToFloat : public std::unary_function { Result operator()(Arg x) const { return x; } }; struct ConvertFloat : public SimpleModule { ConvertFloat(FormatCode inFormat, FormatCode outFormat) : m_inFormat(inFormat), m_outFormat(outFormat) { assert((m_inFormat == kFloat && m_outFormat == kDouble) || (m_inFormat == kDouble && m_outFormat == kFloat)); } virtual const char *name() const OVERRIDE { return "convertFloat"; } virtual void describe() OVERRIDE { switch (m_outFormat) { case kFloat: m_outChunk->f.sampleFormat = AF_SAMPFMT_FLOAT; m_outChunk->f.sampleWidth = 32; break; case kDouble: m_outChunk->f.sampleFormat = AF_SAMPFMT_DOUBLE; m_outChunk->f.sampleWidth = 64; break; default: assert(false); } } virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE { const void *src = inChunk.buffer; void *dst = outChunk.buffer; size_t count = inChunk.frameCount * inChunk.f.channelCount; switch (m_outFormat) { case kFloat: transform >(src, dst, count); break; case kDouble: transform >(src, dst, count); break; default: assert(false); } } private: FormatCode m_inFormat, m_outFormat; }; struct Clip : public SimpleModule { Clip(FormatCode format, const PCMInfo &outputMapping) : m_format(format), m_outputMapping(outputMapping) { } virtual const char *name() const OVERRIDE { return "clip"; } virtual void describe() OVERRIDE { m_outChunk->f.pcm = m_outputMapping; } virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE { const void *src = inChunk.buffer; void *dst = outChunk.buffer; int count = inChunk.frameCount * inChunk.f.channelCount; switch (m_format) { case kInt8: run(src, dst, count); break; case kInt16: run(src, dst, count); break; case kInt24: case kInt32: run(src, dst, count); break; case kFloat: run(src, dst, count); break; case kDouble: run(src, dst, count); break; default: assert(false); } } private: FormatCode m_format; PCMInfo m_outputMapping; template void run(const void *srcData, void *dstData, int count) { const T minValue = m_outputMapping.minClip; const T maxValue = m_outputMapping.maxClip; const T *src = reinterpret_cast(srcData); T *dst = reinterpret_cast(dstData); for (int i=0; if.sampleFormat = AF_SAMPFMT_TWOSCOMP; m_outChunk->f.sampleWidth = (m_outputFormat + 1) * CHAR_BIT; m_outChunk->f.pcm = m_outputMapping; } virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE { const void *src = inChunk.buffer; void *dst = outChunk.buffer; int count = inChunk.frameCount * inChunk.f.channelCount; if (m_inputFormat == kFloat) { switch (m_outputFormat) { case kInt8: run(src, dst, count); break; case kInt16: run(src, dst, count); break; case kInt24: case kInt32: run(src, dst, count); break; default: assert(false); } } else if (m_inputFormat == kDouble) { switch (m_outputFormat) { case kInt8: run(src, dst, count); break; case kInt16: run(src, dst, count); break; case kInt24: case kInt32: run(src, dst, count); break; default: assert(false); } } } private: FormatCode m_inputFormat, m_outputFormat; PCMInfo m_inputMapping, m_outputMapping; template void run(const void *srcData, void *dstData, int count) { const Input *src = reinterpret_cast(srcData); Output *dst = reinterpret_cast(dstData); double m = m_outputMapping.slope / m_inputMapping.slope; double b = m_outputMapping.intercept - m * m_inputMapping.intercept; double minValue = m_outputMapping.minClip; double maxValue = m_outputMapping.maxClip; for (int i=0; i(t); } } }; struct ApplyChannelMatrix : public SimpleModule { public: ApplyChannelMatrix(FormatCode format, bool isReading, int inChannels, int outChannels, double minClip, double maxClip, const double *matrix); virtual ~ApplyChannelMatrix(); virtual const char *name() const OVERRIDE; virtual void describe() OVERRIDE; virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE; private: FormatCode m_format; int m_inChannels, m_outChannels; double m_minClip, m_maxClip; double *m_matrix; void initDefaultMatrix(); template void run(const void *input, void *output, int frameCount); }; struct Transform : public SimpleModule { public: Transform(FormatCode format, const PCMInfo &inputMapping, const PCMInfo &outputMapping) : m_format(format), m_inputMapping(inputMapping), m_outputMapping(outputMapping) { assert(m_format == kFloat || m_format == kDouble); } virtual const char *name() const OVERRIDE { return "transform"; } virtual void describe() OVERRIDE { m_outChunk->f.pcm = m_outputMapping; } virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE { int count = inChunk.frameCount * inChunk.f.channelCount; if (m_format == kFloat) run(inChunk.buffer, outChunk.buffer, count); else if (m_format == kDouble) run(inChunk.buffer, outChunk.buffer, count); else assert(false); } private: FormatCode m_format; PCMInfo m_inputMapping, m_outputMapping; template void run(const void *srcData, void *dstData, int count) { const T *src = reinterpret_cast(srcData); T *dst = reinterpret_cast(dstData); double m = m_outputMapping.slope / m_inputMapping.slope; double b = m_outputMapping.intercept - m * m_inputMapping.intercept; for (int i=0; i