All pastes #401844 Raw Edit

Stuff

public text v1 · immutable
·published 2007-03-19 15:26 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_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;
}