1/*
2 * Copyright 2000-2006 Ingo Weinhold <ingo_weinhold@gmx.de>
3 * Copyright 2008 Stephan A��mus <superstippi@gmx.de>
4 * All rights reserved. Distributed under the terms of the MIT licensce.
5 */
6
7
8#include "AudioFormatConverter.h"
9
10#include <ByteOrder.h>
11#include <MediaDefs.h>
12
13
14//#define TRACE_AUDIO_CONVERTER
15#ifdef TRACE_AUDIO_CONVERTER
16#	include <stdio.h>
17#	define TRACE(x...)	printf(x)
18#else
19#	define TRACE(x...)
20#endif
21
22
23struct ReadFloat {
24	inline int operator()(const void* buffer) const {
25		// 0 == mid, -1.0 == bottom, 1.0 == top
26		float b = *(float*)buffer;
27		if (b < -1.0f)
28			b = -1.0f;
29		else if (b > 1.0f)
30			b = 1.0f;
31		return (int)((double)b * (double)0x7fffffff);
32	}
33};
34
35struct ReadInt {
36	inline int operator()(const void* buffer) const {
37		// 0 == mid, 0x80000001 == bottom, 0x7fffffff == top
38		int b = *(int*)buffer;
39		if (b == INT_MIN)
40			b++;
41		return b;
42	}
43};
44
45struct ReadShort {
46	inline int operator()(const void* buffer) const {
47		// 0 == mid, -32767 == bottom, +32767
48		short b = *(short*)buffer;
49		if (b == -32768)
50			b++;
51		return int(int64(b) * 0x7fffffff / 32767);
52	}
53};
54
55struct ReadUChar {
56	inline int operator()(const void* buffer) const {
57		// 128 == mid, 1 == bottom, 255 == top
58		uchar b = *(uchar*)buffer;
59		if (b == 0)
60			b++;
61		return int((int64(b) - 0x80) * 0x7fffffff / 127);
62	}
63};
64
65struct ReadChar {
66	inline int operator()(const void* buffer) const {
67		// 0 == mid, -127 == bottom, +127 == top
68		char b = *(char*)buffer;
69		if (b == 0)
70			b++;
71		return int(int64(b) * 0x7fffffff / 127);
72	}
73};
74
75struct WriteFloat {
76	inline void operator()(void* buffer, int value) const {
77		*(float*)buffer = (double)value / (double)0x7fffffff;
78	}
79
80};
81
82struct WriteInt {
83	inline void operator()(void* buffer, int value) const {
84		*(int*)buffer = value;
85	}
86};
87
88struct WriteShort {
89	inline void operator()(void* buffer, int value) const {
90		*(short*)buffer = (short)(value / (int)0x10000);
91	}
92};
93
94struct WriteUChar {
95	inline void operator()(void* buffer, int value) const {
96		*(uchar*)buffer = (uchar)(value / (int)0x1000000 + 128);
97	}
98};
99
100struct WriteChar {
101	inline void operator()(void* buffer, int value) const {
102		*(char*)buffer = (char)(value / (int)0x1000000);
103	}
104};
105
106
107template<typename ReadT, typename WriteT>
108static void
109convert(const ReadT& read, const WriteT& write,
110		const char* inBuffer, char* outBuffer, int32 frames,
111		int32 inSampleSize, int32 outSampleSize, int32 channelCount)
112{
113	for (int32 i = 0; i < frames; i++) {
114		for (int32 c = 0; c < channelCount; c++) {
115			write(outBuffer, read(inBuffer));
116			inBuffer += inSampleSize;
117			outBuffer += outSampleSize;
118		}
119	}
120}
121
122
123static void
124swap_sample_byte_order(void* buffer, uint32 format, size_t length)
125{
126	type_code type = B_ANY_TYPE;
127	switch (format) {
128		case media_raw_audio_format::B_AUDIO_FLOAT:
129			type = B_FLOAT_TYPE;
130			break;
131		case media_raw_audio_format::B_AUDIO_INT:
132			type = B_INT32_TYPE;
133			break;
134		case media_raw_audio_format::B_AUDIO_SHORT:
135			type = B_INT16_TYPE;
136			break;
137		case media_raw_audio_format::B_AUDIO_UCHAR:
138			break;
139		case media_raw_audio_format::B_AUDIO_CHAR:
140			break;
141	}
142	if (type != B_ANY_TYPE)
143		swap_data(type, buffer, length, B_SWAP_ALWAYS);
144}
145
146
147// #pragma mark -
148
149
150AudioFormatConverter::AudioFormatConverter(AudioReader* source, uint32 format,
151		uint32 byteOrder)
152	:
153	AudioReader(),
154	fSource(NULL)
155{
156	uint32 hostByteOrder
157		= (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
158	if (source && source->Format().type == B_MEDIA_RAW_AUDIO
159		&& source->Format().u.raw_audio.byte_order == hostByteOrder) {
160		fFormat = source->Format();
161		fFormat.u.raw_audio.format = format;
162		fFormat.u.raw_audio.byte_order = byteOrder;
163		int32 inSampleSize = source->Format().u.raw_audio.format
164			& media_raw_audio_format::B_AUDIO_SIZE_MASK;
165		int32 outSampleSize = fFormat.u.raw_audio.format
166			& media_raw_audio_format::B_AUDIO_SIZE_MASK;
167		if (inSampleSize != outSampleSize) {
168			fFormat.u.raw_audio.buffer_size
169				= source->Format().u.raw_audio.buffer_size * outSampleSize
170				  / inSampleSize;
171		}
172	} else
173		source = NULL;
174	fSource = source;
175}
176
177
178AudioFormatConverter::~AudioFormatConverter()
179{
180}
181
182
183bigtime_t
184AudioFormatConverter::InitialLatency() const
185{
186	return fSource->InitialLatency();
187}
188
189status_t
190AudioFormatConverter::Read(void* buffer, int64 pos, int64 frames)
191{
192	TRACE("AudioFormatConverter::Read(%p, %lld, %lld)\n", buffer, pos, frames);
193	status_t error = InitCheck();
194	if (error != B_OK) {
195		TRACE("AudioFormatConverter::Read() done 1\n");
196		return error;
197	}
198	pos += fOutOffset;
199
200	if (fFormat.u.raw_audio.format == fSource->Format().u.raw_audio.format
201		&& fFormat.u.raw_audio.byte_order
202		   == fSource->Format().u.raw_audio.byte_order) {
203		TRACE("AudioFormatConverter::Read() done 2\n");
204		return fSource->Read(buffer, pos, frames);
205	}
206
207	int32 inSampleSize = fSource->Format().u.raw_audio.format
208		& media_raw_audio_format::B_AUDIO_SIZE_MASK;
209	int32 outSampleSize = fFormat.u.raw_audio.format
210		& media_raw_audio_format::B_AUDIO_SIZE_MASK;
211	int32 channelCount = fFormat.u.raw_audio.channel_count;
212	int32 inFrameSize = inSampleSize * channelCount;
213	int32 outFrameSize = outSampleSize * channelCount;
214	char* reformatBuffer = NULL;
215	char* inBuffer = (char*)buffer;
216
217	#ifdef TRACE_AUDIO_CONVERTER
218		char formatString[256];
219		string_for_format(fSource->Format(), formatString, 256);
220		TRACE("  source format: %s\n", formatString);
221		TRACE("  in format : format: %lx, sample size: %ld, channels: %ld, "
222			"byte order: %lu\n", fSource->Format().u.raw_audio.format,
223			inSampleSize, channelCount,
224			fSource->Format().u.raw_audio.byte_order);
225		TRACE("  out format: format: %lx, sample size: %ld, channels: %ld, "
226			"byte order: %lu\n", fFormat.u.raw_audio.format, outSampleSize,
227			channelCount, fFormat.u.raw_audio.byte_order);
228	#endif // TRACE_AUDIO_CONVERTER
229
230	if (inSampleSize != outSampleSize) {
231		reformatBuffer = new char[frames * inFrameSize];
232		inBuffer = reformatBuffer;
233	}
234	error = fSource->Read(inBuffer, pos, frames);
235	// convert samples to host endianess
236	uint32 hostByteOrder
237		= (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
238	if (fSource->Format().u.raw_audio.byte_order != hostByteOrder) {
239		swap_sample_byte_order(inBuffer, fSource->Format().u.raw_audio.format,
240							   frames * inFrameSize);
241	}
242	// convert the sample type
243	switch (fSource->Format().u.raw_audio.format) {
244		// float
245		case media_raw_audio_format::B_AUDIO_FLOAT:
246			switch (fFormat.u.raw_audio.format) {
247				case media_raw_audio_format::B_AUDIO_FLOAT:
248					break;
249				case media_raw_audio_format::B_AUDIO_INT:
250					convert(ReadFloat(), WriteInt(), inBuffer, (char*)buffer,
251							frames, inSampleSize, outSampleSize, channelCount);
252					break;
253				case media_raw_audio_format::B_AUDIO_SHORT:
254					convert(ReadFloat(), WriteShort(), inBuffer, (char*)buffer,
255							frames, inSampleSize, outSampleSize, channelCount);
256					break;
257				case media_raw_audio_format::B_AUDIO_UCHAR:
258					convert(ReadFloat(), WriteUChar(), inBuffer, (char*)buffer,
259							frames, inSampleSize, outSampleSize, channelCount);
260					break;
261				case media_raw_audio_format::B_AUDIO_CHAR:
262					convert(ReadFloat(), WriteChar(), inBuffer, (char*)buffer,
263							frames, inSampleSize, outSampleSize, channelCount);
264					break;
265			}
266			break;
267		// int
268		case media_raw_audio_format::B_AUDIO_INT:
269			switch (fFormat.u.raw_audio.format) {
270				case media_raw_audio_format::B_AUDIO_FLOAT:
271					convert(ReadInt(), WriteFloat(), inBuffer, (char*)buffer,
272							frames, inSampleSize, outSampleSize, channelCount);
273					break;
274				case media_raw_audio_format::B_AUDIO_INT:
275					break;
276				case media_raw_audio_format::B_AUDIO_SHORT:
277					convert(ReadInt(), WriteShort(), inBuffer, (char*)buffer,
278							frames, inSampleSize, outSampleSize, channelCount);
279					break;
280				case media_raw_audio_format::B_AUDIO_UCHAR:
281					convert(ReadInt(), WriteUChar(), inBuffer, (char*)buffer,
282							frames, inSampleSize, outSampleSize, channelCount);
283					break;
284				case media_raw_audio_format::B_AUDIO_CHAR:
285					convert(ReadInt(), WriteChar(), inBuffer, (char*)buffer,
286							frames, inSampleSize, outSampleSize, channelCount);
287					break;
288			}
289			break;
290		// short
291		case media_raw_audio_format::B_AUDIO_SHORT:
292			switch (fFormat.u.raw_audio.format) {
293				case media_raw_audio_format::B_AUDIO_FLOAT:
294					convert(ReadShort(), WriteFloat(), inBuffer, (char*)buffer,
295							frames, inSampleSize, outSampleSize, channelCount);
296					break;
297				case media_raw_audio_format::B_AUDIO_INT:
298					convert(ReadShort(), WriteInt(), inBuffer, (char*)buffer,
299							frames, inSampleSize, outSampleSize, channelCount);
300					break;
301				case media_raw_audio_format::B_AUDIO_SHORT:
302					break;
303				case media_raw_audio_format::B_AUDIO_UCHAR:
304					convert(ReadShort(), WriteUChar(), inBuffer, (char*)buffer,
305							frames, inSampleSize, outSampleSize, channelCount);
306					break;
307				case media_raw_audio_format::B_AUDIO_CHAR:
308					convert(ReadShort(), WriteChar(), inBuffer, (char*)buffer,
309							frames, inSampleSize, outSampleSize, channelCount);
310					break;
311			}
312			break;
313		// uchar
314		case media_raw_audio_format::B_AUDIO_UCHAR:
315			switch (fFormat.u.raw_audio.format) {
316				case media_raw_audio_format::B_AUDIO_FLOAT:
317					convert(ReadUChar(), WriteFloat(), inBuffer, (char*)buffer,
318							frames, inSampleSize, outSampleSize, channelCount);
319					break;
320				case media_raw_audio_format::B_AUDIO_INT:
321					convert(ReadUChar(), WriteInt(), inBuffer, (char*)buffer,
322							frames, inSampleSize, outSampleSize, channelCount);
323					break;
324				case media_raw_audio_format::B_AUDIO_SHORT:
325					convert(ReadUChar(), WriteShort(), inBuffer, (char*)buffer,
326							frames, inSampleSize, outSampleSize, channelCount);
327					break;
328				case media_raw_audio_format::B_AUDIO_UCHAR:
329					break;
330				case media_raw_audio_format::B_AUDIO_CHAR:
331					convert(ReadUChar(), WriteChar(), inBuffer, (char*)buffer,
332							frames, inSampleSize, outSampleSize, channelCount);
333					break;
334			}
335			break;
336		// char
337		case media_raw_audio_format::B_AUDIO_CHAR:
338			switch (fFormat.u.raw_audio.format) {
339				case media_raw_audio_format::B_AUDIO_FLOAT:
340					convert(ReadChar(), WriteFloat(), inBuffer, (char*)buffer,
341							frames, inSampleSize, outSampleSize, channelCount);
342					break;
343				case media_raw_audio_format::B_AUDIO_INT:
344					convert(ReadChar(), WriteInt(), inBuffer, (char*)buffer,
345							frames, inSampleSize, outSampleSize, channelCount);
346					break;
347				case media_raw_audio_format::B_AUDIO_SHORT:
348					convert(ReadChar(), WriteShort(), inBuffer, (char*)buffer,
349							frames, inSampleSize, outSampleSize, channelCount);
350					break;
351				case media_raw_audio_format::B_AUDIO_UCHAR:
352					convert(ReadChar(), WriteUChar(), inBuffer, (char*)buffer,
353							frames, inSampleSize, outSampleSize, channelCount);
354					break;
355				case media_raw_audio_format::B_AUDIO_CHAR:
356					break;
357			}
358			break;
359	}
360	// convert samples to output endianess
361	if (fFormat.u.raw_audio.byte_order != hostByteOrder) {
362		swap_sample_byte_order(buffer, fFormat.u.raw_audio.format,
363							   frames * outFrameSize);
364	}
365
366	delete[] reformatBuffer;
367	TRACE("AudioFormatConverter::Read() done\n");
368	return B_OK;
369}
370
371
372status_t
373AudioFormatConverter::InitCheck() const
374{
375	status_t error = AudioReader::InitCheck();
376	if (error == B_OK && !fSource)
377		error = B_NO_INIT;
378	if (error == B_OK)
379		error = fSource->InitCheck();
380	return error;
381}
382
383
384AudioReader*
385AudioFormatConverter::Source() const
386{
387	return fSource;
388}
389
390