1/*
2 * Copyright 2008 Stephan A��mus <superstippi@gmx.de>
3 * All rights reserved. Distributed under the terms of the MIT licensce.
4 */
5
6
7#include "AudioChannelConverter.h"
8
9#include <new>
10#include <stdio.h>
11#include <string.h>
12
13using std::nothrow;
14
15
16//#define TRACE_AUDIO_CONVERTER
17#ifdef TRACE_AUDIO_CONVERTER
18#	define TRACE(x...)	printf(x)
19#else
20#	define TRACE(x...)
21#endif
22
23
24template<typename Type, typename BigType>
25static void
26convert(Type* inBuffer, Type* outBuffer, int32 inChannels, int32 outChannels,
27	int32 frames)
28{
29	// TODO: more conversions!
30	switch (inChannels) {
31		case 0:
32			break;
33		case 1:
34			switch (outChannels) {
35				case 2:
36					for (int32 i = 0; i < frames; i++) {
37						*outBuffer++ = *inBuffer;
38						*outBuffer++ = *inBuffer++;
39					}
40					break;
41			}
42			break;
43		case 2:
44			switch (outChannels) {
45				case 1:
46					for (int32 i = 0; i < frames; i++) {
47						*outBuffer++
48							= (Type)((BigType)inBuffer[0] + inBuffer[1]) / 2;
49						inBuffer += 2;
50					}
51					break;
52			}
53			break;
54		default:
55			switch (outChannels) {
56				case 2:
57					for (int32 i = 0; i < frames; i++) {
58						outBuffer[0] = inBuffer[0];
59						outBuffer[1] = inBuffer[1];
60						inBuffer += outChannels;
61						outBuffer += 2;
62					}
63					break;
64			}
65			break;
66	}
67}
68
69
70// #pragma mark -
71
72
73AudioChannelConverter::AudioChannelConverter(AudioReader* source,
74		const media_format& format)
75	: AudioReader(format),
76	  fSource(source)
77{
78	// TODO: check the format and make sure everything matches
79	// except for channel count
80}
81
82
83AudioChannelConverter::~AudioChannelConverter()
84{
85}
86
87
88bigtime_t
89AudioChannelConverter::InitialLatency() const
90{
91	return fSource->InitialLatency();
92}
93
94
95status_t
96AudioChannelConverter::Read(void* outBuffer, int64 pos, int64 frames)
97{
98	TRACE("AudioChannelConverter::Read(%p, %lld, %lld)\n", outBuffer, pos, frames);
99	status_t error = InitCheck();
100	if (error != B_OK)
101		return error;
102	pos += fOutOffset;
103
104	int32 inChannels = fSource->Format().u.raw_audio.channel_count;
105	int32 outChannels = fFormat.u.raw_audio.channel_count;
106	TRACE("   convert %ld -> %ld channels\n", inChannels, outChannels);
107
108	int32 inSampleSize = fSource->Format().u.raw_audio.format
109		& media_raw_audio_format::B_AUDIO_SIZE_MASK;
110	int32 inFrameSize = inSampleSize * inChannels;
111	uint8* inBuffer = new (nothrow) uint8[inFrameSize * frames];
112
113	TRACE("   fSource->Read()\n");
114	status_t ret = fSource->Read(inBuffer, pos, frames);
115	if (ret != B_OK) {
116		delete[] inBuffer;
117		return ret;
118	}
119
120	// We know that both formats are the same except for channel count
121	switch (fFormat.u.raw_audio.format) {
122		case media_raw_audio_format::B_AUDIO_FLOAT:
123			convert<float, float>((float*)inBuffer, (float*)outBuffer,
124				inChannels, outChannels, frames);
125			break;
126		case media_raw_audio_format::B_AUDIO_INT:
127			convert<int32, int64>((int32*)inBuffer, (int32*)outBuffer,
128				inChannels, outChannels, frames);
129			break;
130		case media_raw_audio_format::B_AUDIO_SHORT:
131			convert<int16, int32>((int16*)inBuffer, (int16*)outBuffer,
132				inChannels, outChannels, frames);
133			break;
134		case media_raw_audio_format::B_AUDIO_UCHAR:
135			convert<uint8, uint16>((uint8*)inBuffer, (uint8*)outBuffer,
136				inChannels, outChannels, frames);
137			break;
138		case media_raw_audio_format::B_AUDIO_CHAR:
139			convert<int8, int16>((int8*)inBuffer, (int8*)outBuffer,
140				inChannels, outChannels, frames);
141			break;
142	}
143
144	delete[] inBuffer;
145
146	TRACE("AudioChannelConverter::Read() done: %s\n", strerror(ret));
147	return ret;
148}
149
150
151status_t
152AudioChannelConverter::InitCheck() const
153{
154	status_t error = AudioReader::InitCheck();
155	if (error == B_OK && !fSource)
156		error = B_NO_INIT;
157	return error;
158}
159
160
161AudioReader*
162AudioChannelConverter::Source() const
163{
164	return fSource;
165}
166
167