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