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