xref: /haiku/src/apps/mediaplayer/media_node_framework/audio/AudioChannelConverter.cpp (revision 425ac1b60a56f4df7a0e88bd784545c0ec4fa01f)
10fc56ed5SStephan Aßmus /*
28dd3060dSAxel Dörfler  * Copyright 2008 Stephan Aßmus <superstippi@gmx.de>
30fc56ed5SStephan Aßmus  * All rights reserved. Distributed under the terms of the MIT licensce.
40fc56ed5SStephan Aßmus  */
58dd3060dSAxel Dörfler 
68dd3060dSAxel Dörfler 
70fc56ed5SStephan Aßmus #include "AudioChannelConverter.h"
80fc56ed5SStephan Aßmus 
90fc56ed5SStephan Aßmus #include <new>
100fc56ed5SStephan Aßmus #include <stdio.h>
110fc56ed5SStephan Aßmus #include <string.h>
120fc56ed5SStephan Aßmus 
130fc56ed5SStephan Aßmus using std::nothrow;
140fc56ed5SStephan Aßmus 
158dd3060dSAxel Dörfler 
160fc56ed5SStephan Aßmus //#define TRACE_AUDIO_CONVERTER
170fc56ed5SStephan Aßmus #ifdef TRACE_AUDIO_CONVERTER
180fc56ed5SStephan Aßmus #	define TRACE(x...)	printf(x)
190fc56ed5SStephan Aßmus #else
200fc56ed5SStephan Aßmus #	define TRACE(x...)
210fc56ed5SStephan Aßmus #endif
220fc56ed5SStephan Aßmus 
230fc56ed5SStephan Aßmus 
240fc56ed5SStephan Aßmus template<typename Type, typename BigType>
250fc56ed5SStephan Aßmus static void
convert(Type * inBuffer,Type * outBuffer,int32 inChannels,int32 outChannels,int32 frames)260fc56ed5SStephan Aßmus convert(Type* inBuffer, Type* outBuffer, int32 inChannels, int32 outChannels,
270fc56ed5SStephan Aßmus 	int32 frames)
280fc56ed5SStephan Aßmus {
290fc56ed5SStephan Aßmus 	// TODO: more conversions!
300fc56ed5SStephan Aßmus 	switch (inChannels) {
31fa1a1c29SStephan Aßmus 		case 0:
32fa1a1c29SStephan Aßmus 			break;
330fc56ed5SStephan Aßmus 		case 1:
340fc56ed5SStephan Aßmus 			switch (outChannels) {
350fc56ed5SStephan Aßmus 				case 2:
360fc56ed5SStephan Aßmus 					for (int32 i = 0; i < frames; i++) {
370fc56ed5SStephan Aßmus 						*outBuffer++ = *inBuffer;
380fc56ed5SStephan Aßmus 						*outBuffer++ = *inBuffer++;
390fc56ed5SStephan Aßmus 					}
400fc56ed5SStephan Aßmus 					break;
410fc56ed5SStephan Aßmus 			}
420fc56ed5SStephan Aßmus 			break;
430fc56ed5SStephan Aßmus 		case 2:
440fc56ed5SStephan Aßmus 			switch (outChannels) {
450fc56ed5SStephan Aßmus 				case 1:
460fc56ed5SStephan Aßmus 					for (int32 i = 0; i < frames; i++) {
470fc56ed5SStephan Aßmus 						*outBuffer++
480fc56ed5SStephan Aßmus 							= (Type)((BigType)inBuffer[0] + inBuffer[1]) / 2;
490fc56ed5SStephan Aßmus 						inBuffer += 2;
500fc56ed5SStephan Aßmus 					}
510fc56ed5SStephan Aßmus 					break;
520fc56ed5SStephan Aßmus 			}
530fc56ed5SStephan Aßmus 			break;
54fa1a1c29SStephan Aßmus 		default:
55169bcbe7SStephan Aßmus 			switch (outChannels) {
56169bcbe7SStephan Aßmus 				case 2:
57169bcbe7SStephan Aßmus 					for (int32 i = 0; i < frames; i++) {
58169bcbe7SStephan Aßmus 						outBuffer[0] = inBuffer[0];
59169bcbe7SStephan Aßmus 						outBuffer[1] = inBuffer[1];
60fa1a1c29SStephan Aßmus 						inBuffer += outChannels;
61169bcbe7SStephan Aßmus 						outBuffer += 2;
62169bcbe7SStephan Aßmus 					}
63169bcbe7SStephan Aßmus 					break;
64169bcbe7SStephan Aßmus 			}
65169bcbe7SStephan Aßmus 			break;
660fc56ed5SStephan Aßmus 	}
670fc56ed5SStephan Aßmus }
680fc56ed5SStephan Aßmus 
690fc56ed5SStephan Aßmus 
708dd3060dSAxel Dörfler // #pragma mark -
718dd3060dSAxel Dörfler 
728dd3060dSAxel Dörfler 
AudioChannelConverter(AudioReader * source,const media_format & format)738dd3060dSAxel Dörfler AudioChannelConverter::AudioChannelConverter(AudioReader* source,
748dd3060dSAxel Dörfler 		const media_format& format)
758dd3060dSAxel Dörfler 	: AudioReader(format),
768dd3060dSAxel Dörfler 	  fSource(source)
778dd3060dSAxel Dörfler {
788dd3060dSAxel Dörfler 	// TODO: check the format and make sure everything matches
798dd3060dSAxel Dörfler 	// except for channel count
808dd3060dSAxel Dörfler }
818dd3060dSAxel Dörfler 
828dd3060dSAxel Dörfler 
~AudioChannelConverter()838dd3060dSAxel Dörfler AudioChannelConverter::~AudioChannelConverter()
848dd3060dSAxel Dörfler {
858dd3060dSAxel Dörfler }
868dd3060dSAxel Dörfler 
878dd3060dSAxel Dörfler 
888dd3060dSAxel Dörfler bigtime_t
InitialLatency() const898dd3060dSAxel Dörfler AudioChannelConverter::InitialLatency() const
908dd3060dSAxel Dörfler {
91c445fa21SStefano Ceccherini 	return fSource->InitialLatency();
928dd3060dSAxel Dörfler }
938dd3060dSAxel Dörfler 
948dd3060dSAxel Dörfler 
950fc56ed5SStephan Aßmus status_t
Read(void * outBuffer,int64 pos,int64 frames)960fc56ed5SStephan Aßmus AudioChannelConverter::Read(void* outBuffer, int64 pos, int64 frames)
970fc56ed5SStephan Aßmus {
98*425ac1b6SAlexander von Gluck IV 	TRACE("AudioChannelConverter::Read(%p, %lld, %lld)\n", outBuffer, pos, frames);
990fc56ed5SStephan Aßmus 	status_t error = InitCheck();
1000fc56ed5SStephan Aßmus 	if (error != B_OK)
1010fc56ed5SStephan Aßmus 		return error;
1020fc56ed5SStephan Aßmus 	pos += fOutOffset;
1030fc56ed5SStephan Aßmus 
1040fc56ed5SStephan Aßmus 	int32 inChannels = fSource->Format().u.raw_audio.channel_count;
1050fc56ed5SStephan Aßmus 	int32 outChannels = fFormat.u.raw_audio.channel_count;
1060fc56ed5SStephan Aßmus 	TRACE("   convert %ld -> %ld channels\n", inChannels, outChannels);
1070fc56ed5SStephan Aßmus 
1080fc56ed5SStephan Aßmus 	int32 inSampleSize = fSource->Format().u.raw_audio.format
1090fc56ed5SStephan Aßmus 		& media_raw_audio_format::B_AUDIO_SIZE_MASK;
1100fc56ed5SStephan Aßmus 	int32 inFrameSize = inSampleSize * inChannels;
1110fc56ed5SStephan Aßmus 	uint8* inBuffer = new (nothrow) uint8[inFrameSize * frames];
1120fc56ed5SStephan Aßmus 
1130fc56ed5SStephan Aßmus 	TRACE("   fSource->Read()\n");
1140fc56ed5SStephan Aßmus 	status_t ret = fSource->Read(inBuffer, pos, frames);
1150fc56ed5SStephan Aßmus 	if (ret != B_OK) {
1160fc56ed5SStephan Aßmus 		delete[] inBuffer;
1170fc56ed5SStephan Aßmus 		return ret;
1180fc56ed5SStephan Aßmus 	}
1190fc56ed5SStephan Aßmus 
1200fc56ed5SStephan Aßmus 	// We know that both formats are the same except for channel count
1210fc56ed5SStephan Aßmus 	switch (fFormat.u.raw_audio.format) {
1220fc56ed5SStephan Aßmus 		case media_raw_audio_format::B_AUDIO_FLOAT:
1230fc56ed5SStephan Aßmus 			convert<float, float>((float*)inBuffer, (float*)outBuffer,
1240fc56ed5SStephan Aßmus 				inChannels, outChannels, frames);
1250fc56ed5SStephan Aßmus 			break;
1260fc56ed5SStephan Aßmus 		case media_raw_audio_format::B_AUDIO_INT:
1270fc56ed5SStephan Aßmus 			convert<int32, int64>((int32*)inBuffer, (int32*)outBuffer,
1280fc56ed5SStephan Aßmus 				inChannels, outChannels, frames);
1290fc56ed5SStephan Aßmus 			break;
1300fc56ed5SStephan Aßmus 		case media_raw_audio_format::B_AUDIO_SHORT:
1310fc56ed5SStephan Aßmus 			convert<int16, int32>((int16*)inBuffer, (int16*)outBuffer,
1320fc56ed5SStephan Aßmus 				inChannels, outChannels, frames);
1330fc56ed5SStephan Aßmus 			break;
1340fc56ed5SStephan Aßmus 		case media_raw_audio_format::B_AUDIO_UCHAR:
1350fc56ed5SStephan Aßmus 			convert<uint8, uint16>((uint8*)inBuffer, (uint8*)outBuffer,
1360fc56ed5SStephan Aßmus 				inChannels, outChannels, frames);
1370fc56ed5SStephan Aßmus 			break;
1380fc56ed5SStephan Aßmus 		case media_raw_audio_format::B_AUDIO_CHAR:
1390fc56ed5SStephan Aßmus 			convert<int8, int16>((int8*)inBuffer, (int8*)outBuffer,
1400fc56ed5SStephan Aßmus 				inChannels, outChannels, frames);
1410fc56ed5SStephan Aßmus 			break;
1420fc56ed5SStephan Aßmus 	}
1430fc56ed5SStephan Aßmus 
1440fc56ed5SStephan Aßmus 	delete[] inBuffer;
1450fc56ed5SStephan Aßmus 
1460fc56ed5SStephan Aßmus 	TRACE("AudioChannelConverter::Read() done: %s\n", strerror(ret));
1470fc56ed5SStephan Aßmus 	return ret;
1480fc56ed5SStephan Aßmus }
1490fc56ed5SStephan Aßmus 
1500fc56ed5SStephan Aßmus 
1510fc56ed5SStephan Aßmus status_t
InitCheck() const1520fc56ed5SStephan Aßmus AudioChannelConverter::InitCheck() const
1530fc56ed5SStephan Aßmus {
1540fc56ed5SStephan Aßmus 	status_t error = AudioReader::InitCheck();
1550fc56ed5SStephan Aßmus 	if (error == B_OK && !fSource)
1560fc56ed5SStephan Aßmus 		error = B_NO_INIT;
1570fc56ed5SStephan Aßmus 	return error;
1580fc56ed5SStephan Aßmus }
1590fc56ed5SStephan Aßmus 
1600fc56ed5SStephan Aßmus 
1610fc56ed5SStephan Aßmus AudioReader*
Source() const1620fc56ed5SStephan Aßmus AudioChannelConverter::Source() const
1630fc56ed5SStephan Aßmus {
1640fc56ed5SStephan Aßmus 	return fSource;
1650fc56ed5SStephan Aßmus }
1660fc56ed5SStephan Aßmus 
167