All pastes #401845 Raw Edit

Stuff

public cpp v1 · immutable
·published 2007-03-19 15:27 UTC
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;}