rendered paste body#include "phd_FormatConverter.h"#include "phd_Dither.h"#include <QVarLengthArray>//--- endian convenience ------------------------------------------------------typedef enum { LittleEndian = QSysInfo::LittleEndian, BigEndian = QSysInfo::BigEndian, ByteOrder = QSysInfo::ByteOrder} Endian;//--- toInt32 -----------------------------------------------------------------template <typename T>inline qint32 toInt32(T sample);template <>inline qint32 toInt32<float>(float sample) { // sample * (2^31-1) + 0.5 double tmp = sample * 2147483647.0 + 0.5; return (qint32)qBound(-2147483648.0, tmp, 2147483647.0);}template <>inline qint32 toInt32<qint24>(qint24 sample) {#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN qint32 tmp = sample.bytes[0] | (sample.bytes[1] << 8) | (sample.bytes[2] << 16);#else qint32 tmp = sample.bytes[2] | (sample.bytes[1] << 8) | (sample.bytes[0] << 16);#endif return tmp << 8;}template <>inline qint32 toInt32<quint24>(quint24 sample) {#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN qint32 tmp = sample.bytes[0] | (sample.bytes[1] << 8) | (sample.bytes[2] << 16);#else qint32 tmp = sample.bytes[2] | (sample.bytes[1] << 8) | (sample.bytes[0] << 16);#endif return (tmp << 8) ^ (1 << 31);}template <>inline qint32 toInt32<qint16>(qint16 sample) { return (qint32)sample << 16;}template <>inline qint32 toInt32<quint16>(quint16 sample) { return ((qint32)sample << 16) ^ (1 << 31);}template <>inline qint32 toInt32<qint8>(qint8 sample) { return (qint32)sample << 24;}template <>inline qint32 toInt32<quint8>(quint8 sample) { return ((qint32)sample << 24) ^ (1 << 31);}//--- fromInt32 ---------------------------------------------------------------template <typename T>inline T fromInt32(qint32 sample);template <>inline float fromInt32<float>(qint32 sample) { // sample * (1 / (2^31-1)) return (float)sample * 4.6566128752457969e-10;}template <>inline qint24 fromInt32<qint24>(qint32 sample) { qint32 tmp1 = sample >> 8; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN qint24 tmp2 = { tmp1 & 0xff, (tmp1 >> 8) & 0xff, (tmp1 >> 16) & 0xff };#else qint24 tmp2 = { (tmp1 >> 16) & 0xff, (tmp1 >> 8) & 0xff, tmp1 & 0xff };#endif return tmp2;}template <>inline quint24 fromInt32<quint24>(qint32 sample) { qint32 tmp1 = (sample ^ (1 << 31)) >> 8; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN quint24 tmp2 = { tmp1 & 0xff, (tmp1 >> 8) & 0xff, (tmp1 >> 16) & 0xff };#else quint24 tmp2 = { (tmp1 >> 16) & 0xff, (tmp1 >> 8) & 0xff, tmp1 & 0xff };#endif return tmp2;}template <>inline qint16 fromInt32<qint16>(qint32 sample) { return sample >> 16;}template <>inline quint16 fromInt32<quint16>(qint32 sample) { return (sample ^ (1 << 31)) >> 16;}template <>inline qint8 fromInt32<qint8>(qint32 sample) { return sample >> 24;}template <>inline quint8 fromInt32<quint8>(qint32 sample) { return (sample ^ (1 << 31)) >> 24;}//--- Depth -------------------------------------------------------------------template <typename T>struct Depth { static int const bits = 0;};#define SPECIALIZE_DEPTH(_type, _depth) \ template <> \ struct Depth<_type> { \ static int const bits = _depth; \ };SPECIALIZE_DEPTH(float, 24)SPECIALIZE_DEPTH(qint24, 24)SPECIALIZE_DEPTH(quint24, 24)SPECIALIZE_DEPTH(qint16, 16)SPECIALIZE_DEPTH(quint16, 16)SPECIALIZE_DEPTH(qint8, 8)SPECIALIZE_DEPTH(quint8, 8)#undef SPECIALIZE_DEPTHtemplate <typename T1, typename T2>struct Difference { static int const bits = Depth<T1>::bits - Depth<T2>::bits;};//--- convert -----------------------------------------------------------------template <typename T1, Endian E1, typename T2, Endian E2, Dither::Mode mode>struct PartialConvert { static inline void convert(T1* input, T2* output, int size);};#define SPECIALIZE_PARTIALCONVERT(_input_endian, _output_endian) \ template <typename T1, typename T2> \ struct PartialConvert<T1, _input_endian, T2, _output_endian, \ Dither::None> { \ static inline void convert(T1* input, T2* output, int size) { \ for (int i = 0; i < size; ++i) \ *output++ = qTo##_output_endian( \ fromInt32<T2>( \ toInt32<T1>( \ qFrom##_input_endian(*input++)))); \ } \ };SPECIALIZE_PARTIALCONVERT(LittleEndian, LittleEndian)SPECIALIZE_PARTIALCONVERT(BigEndian, BigEndian)SPECIALIZE_PARTIALCONVERT(LittleEndian, BigEndian)SPECIALIZE_PARTIALCONVERT(BigEndian, LittleEndian)#undef SPECIALIZE_PARTIALCONVERT//--- dithered convert --------------------------------------------------------#define SPECIALIZE_DITHERED_PARTIALCONVERT(_input_endian, _output_endian) \ template <typename T1, typename T2, Dither::Mode mode> \ struct PartialConvert<T1, _input_endian, T2, _output_endian, mode> { \ static inline void convert(T1* input, T2* output, int size) { \ for (int i = 0; i < size; ++i) \ *output++ = qTo##_output_endian( \ fromInt32<T2>( \ dither<Depth<T2>::bits, mode>( \ toInt32<T1>( \ qFrom##_input_endian(*input++))))); \ } \ };SPECIALIZE_DITHERED_PARTIALCONVERT(LittleEndian, LittleEndian)SPECIALIZE_DITHERED_PARTIALCONVERT(BigEndian, BigEndian)SPECIALIZE_DITHERED_PARTIALCONVERT(LittleEndian, BigEndian)SPECIALIZE_DITHERED_PARTIALCONVERT(BigEndian, LittleEndian)#undef SPECIALIZE_DITHERED_PARTIALCONVERT//--- wrapper -----------------------------------------------------------------template <typename T1, Endian E1, typename T2, Endian E2, Dither::Mode mode>inline void wrapper(void* input, void* output, int size) { PartialConvert<T1, E1, T2, E2, mode>::convert((T1*)input, (T2*)output, size);}typedef void (*Wrapper)(void* input, void* output, int size);#define DITHER(_input_type, _output_type, _dither_mode) \ Difference<_input_type, _output_type>::bits >= 16 ? _dither_mode \ : Dither::None#define WRAPPER(_input_type, _input_endian, _output_type, _output_endian) { \ /* None */ \ wrapper<_input_type, _input_endian, _output_type, _output_endian, \ Dither::None>, \ /* Rectangular */ \ wrapper<_input_type, _input_endian, _output_type, _output_endian, \ DITHER(_input_type, _output_type, Dither::Rectangular)>, \ /* Triangular */ \ wrapper<_input_type, _input_endian, _output_type, _output_endian, \ DITHER(_input_type, _output_type, Dither::Triangular)>, \ /* HighPassTriangular */ \ wrapper<_input_type, _input_endian, _output_type, _output_endian, \ DITHER(_input_type, _output_type, Dither::HighPassTriangular)> \}#define WRAPPERS(_input_type, _input_endian) { \ /* F32 */ \ WRAPPER(_input_type, _input_endian, float, ByteOrder), \ /* S24LE */ \ WRAPPER(_input_type, _input_endian, qint24, LittleEndian), \ /* S24BE */ \ WRAPPER(_input_type, _input_endian, qint24, BigEndian), \ /* S16LE */ \ WRAPPER(_input_type, _input_endian, qint16, LittleEndian), \ /* S16BE */ \ WRAPPER(_input_type, _input_endian, qint16, BigEndian), \ /* U16LE */ \ WRAPPER(_input_type, _input_endian, quint16, LittleEndian), \ /* U16BE */ \ WRAPPER(_input_type, _input_endian, quint16, BigEndian), \ /* S8 */ \ WRAPPER(_input_type, _input_endian, qint8, ByteOrder), \ /* U8 */ \ WRAPPER(_input_type, _input_endian, quint8, ByteOrder) \}// wrappers[input-format][output-format][dither-mode]static Wrapper wrappers[9][9][4] = { // F32 WRAPPERS(float, ByteOrder), // S24LE WRAPPERS(qint24, LittleEndian), // S24BE WRAPPERS(qint24, BigEndian), // S16LE WRAPPERS(qint16, LittleEndian), // S16BE WRAPPERS(qint16, BigEndian), // U16LE WRAPPERS(quint16, LittleEndian), // U16BE WRAPPERS(quint16, BigEndian), // S8 WRAPPERS(qint8, ByteOrder), // U8 WRAPPERS(quint8, ByteOrder)};#undef DITHER#undef WRAPPER#undef WRAPPERS//--- partial reader ----------------------------------------------------------template <typename T1, typename T2, bool interleaved, bool inplace>struct PartialReader { static inline int reader(Wrapper wrapper, ISource* source, void* buffer, int size, int channels);};template <typename T1, typename T2>struct PartialReader<T1, T2, true, true> { static inline int reader(Wrapper wrapper, ISource* source, void* buffer, int size, int channels) { int offset = size - (size * sizeof(T1)) / sizeof(T2); T2* output = (T2*)buffer; T1* input = (T1*)(output + offset * channels); int result = source->read(input, size); if (result <= 0) return result; wrapper(input, output, size * channels); return result; }};template <typename T1, typename T2>struct PartialReader<T1, T2, true, false> { static inline int reader(Wrapper wrapper, ISource* source, void* buffer, int size, int channels) { QVarLengthArray<T1, 2048> input; T2* output = (T2*)buffer; input.resize(size * channels); int result = source->read(input.data(), size); if (result > 0) wrapper(input.data(), output, size * channels); return result; }};template <typename T1, typename T2>struct PartialReader<T1, T2, false, true> { static inline int reader(Wrapper wrapper, ISource* source, void* buffer, int size, int channels) { T1** input = new T1*[channels]; T2** output = (T2**)buffer; int offset = size - (size * sizeof(T1)) / sizeof(T2); for (int i = 0; i < channels; ++i) input[i] = (T1*)(output[i] + offset); int result = source->read(input, size); if (result > 0) { for (int i = 0; i < channels; ++i) wrapper(input[i], output[i], size); } delete[] input; return result; }};template <typename T1, typename T2>struct PartialReader<T1, T2, false, false> { static inline int reader(Wrapper wrapper, ISource* source, void* buffer, int size, int channels) { typedef QVarLengthArray<T1, 1024> TypedArray; TypedArray* base = new TypedArray[channels]; T1** input = new T1*[channels]; T2** output = (T2**)buffer; for (int i = 0; i < channels; ++i) { base[i].resize(size); input[i] = base[i].data(); } int result = source->read(input, size); if (result > 0) { for (int i = 0; i < channels; ++i) wrapper(input[i], output[i], size); } delete[] input; delete[] base; return result; }};//--- reader ------------------------------------------------------------------typedef int (*Reader)(Wrapper wrapper, ISource* source, void* buffer, int size, int channels);#define READER(_input_type, _output_type) { \ /* interleaved */ \ PartialReader<_input_type, _output_type, true, \ sizeof(_input_type) <= sizeof(_output_type)>::reader, \ /* non-interleaved */ \ PartialReader<_input_type, _output_type, false, \ sizeof(_input_type) <= sizeof(_output_type)>::reader \}#define READERS(_input_type) { \ /* F32 */ \ READER(_input_type, float), \ /* S24LE */ \ READER(_input_type, qint24), \ /* S24BE */ \ READER(_input_type, qint24), \ /* S16LE */ \ READER(_input_type, qint16), \ /* S16BE */ \ READER(_input_type, qint16), \ /* U16LE */ \ READER(_input_type, quint16), \ /* U16BE */ \ READER(_input_type, quint16), \ /* S8 */ \ READER(_input_type, qint8), \ /* U8 */ \ READER(_input_type, quint8), \}// readers[input-format][output-format][interleaved ? 0 : 1]static Reader readers[9][9][2] = { // F32 READERS(float), // S24LE READERS(qint24), // S24BE READERS(qint24), // S16LE READERS(qint16), // S16BE READERS(qint16), // U16LE READERS(quint16), // U16BE READERS(quint16), // S8 READERS(qint8), // U8 READERS(quint8)};#undef READER#undef READERS//--- FormatConverter::Private ------------------------------------------------class FormatConverter::Private {public: Private(Sample::Format inputFormat) : mSource(NULL), mSeekable(NULL), mInputFormat(inputFormat), mOutputFormat(Sample::Invalid), mReader(NULL), mWrapper(NULL) { mInputPort.mime = "audio/pcm"; mInputPort.params["format"] = mInputFormat; mOutputPort.mime = "audio/pcm"; dither_initialize(); } Port mInputPort; Port mOutputPort; ISource* mSource; ISeekable* mSeekable; Sample::Format mInputFormat; Sample::Format mOutputFormat; int mChannels; bool mInterleaved; Reader mReader; Wrapper mWrapper;};//--- FormatConverter ---------------------------------------------------------FormatConverter::FormatConverter(Sample::Format inputFormat, QObject* parent /*= NULL*/) : SeekableTransport(parent) { mp = new Private(inputFormat);}FormatConverter::~FormatConverter() { delete mp;}// reimplemented from Elementbool FormatConverter::initialize() { return true;}// reimplemented from ElementQString FormatConverter::name() const { if (mp->mSource) return QString("FormatConverter [%1->%2,%3,%4]") .arg(Sample::name(mp->mInputFormat)) .arg(Sample::name(mp->mOutputFormat)) .arg(mp->mChannels) .arg(mp->mInterleaved ? "i" : "d"); return QString("FormatConverter [%1]").arg(Sample::name(mp->mInputFormat));}// reimplemented from ISeekablebool FormatConverter::seek(qint64 position) { if (mp->mSeekable) return mp->mSeekable->seek(position); return false;}// reimplemented from ISeekableqint64 FormatConverter::position() const { if (mp->mSeekable) return mp->mSeekable->position(); return 0;}// reimplemented from ISeekableqint64 FormatConverter::size() const { if (mp->mSeekable) return mp->mSeekable->size(); return 0;}// reimplemented from ISinkPort FormatConverter::input() const { return mp->mInputPort;}// reimplemented from ISinkbool FormatConverter::reconnect() { if (mp->mSource) { mp->mSource = NULL; mp->mSeekable = NULL; } if (!dequeue()) return false; mp->mSource = current(mp->mSeekable); mp->mChannels = mp->mSource->output().params["channels"].toInt(); mp->mInterleaved = mp->mSource->output().params["interleaved"].toBool(); mp->mOutputPort.fillUpParamsFrom(mp->mSource->output()); mp->mReader = readers[mp->mInputFormat][mp->mOutputFormat] [mp->mInterleaved ? 0 : 1]; // mp->mWrapper = wrappers[mp->mInputFormat][mp->mOutputFormat][Dither::None];// mp->mWrapper = wrappers[mp->mInputFormat][mp->mOutputFormat][Dither::Rectangular];// mp->mWrapper = wrappers[mp->mInputFormat][mp->mOutputFormat][Dither::Triangular]; mp->mWrapper = wrappers[mp->mInputFormat][mp->mOutputFormat][Dither::HighPassTriangular]; return true;}// reimplemented from ISourcevoid FormatConverter::setOutputHint(const Port& hint) { mp->mOutputFormat = (Sample::Format)hint.params["format"].toInt(); mp->mOutputPort.params["format"] = mp->mOutputFormat;}// reimplemented from ISourcePort FormatConverter::output() const { return mp->mOutputPort;}// reimplemented from ISourcevoid FormatConverter::resolved(const QByteArray& mime) {}// reimplemented from ISourceint FormatConverter::read(void* buffer, int size) { if (!mp->mSource) return -1; return mp->mReader(mp->mWrapper, mp->mSource, buffer, size, mp->mChannels);}// reimplemented from ISourceint FormatConverter::peek(void* buffer, int size) { return -1;}// reimplemented from ITransportint FormatConverter::advantage(const Port& input, bool isSeekable, const Port& output) const { if (input.params["format"] != output.params["format"]) return 1; return 0;}