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_DEPTH
template <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 Element
bool FormatConverter::initialize() {
return true;
}
// reimplemented from Element
QString 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 ISeekable
bool FormatConverter::seek(qint64 position) {
if (mp->mSeekable)
return mp->mSeekable->seek(position);
return false;
}
// reimplemented from ISeekable
qint64 FormatConverter::position() const {
if (mp->mSeekable)
return mp->mSeekable->position();
return 0;
}
// reimplemented from ISeekable
qint64 FormatConverter::size() const {
if (mp->mSeekable)
return mp->mSeekable->size();
return 0;
}
// reimplemented from ISink
Port FormatConverter::input() const {
return mp->mInputPort;
}
// reimplemented from ISink
bool 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 ISource
void FormatConverter::setOutputHint(const Port& hint) {
mp->mOutputFormat = (Sample::Format)hint.params["format"].toInt();
mp->mOutputPort.params["format"] = mp->mOutputFormat;
}
// reimplemented from ISource
Port FormatConverter::output() const {
return mp->mOutputPort;
}
// reimplemented from ISource
void FormatConverter::resolved(const QByteArray& mime) {
}
// reimplemented from ISource
int FormatConverter::read(void* buffer, int size) {
if (!mp->mSource)
return -1;
return mp->mReader(mp->mWrapper, mp->mSource, buffer, size, mp->mChannels);
}
// reimplemented from ISource
int FormatConverter::peek(void* buffer, int size) {
return -1;
}
// reimplemented from ITransport
int FormatConverter::advantage(const Port& input, bool isSeekable,
const Port& output) const {
if (input.params["format"] != output.params["format"])
return 1;
return 0;
}