/* * Copyright 2000-2006 Ingo Weinhold * Copyright 2008 Stephan Aßmus * All rights reserved. Distributed under the terms of the MIT licensce. */ #include "AudioFormatConverter.h" #include #include //#define TRACE_AUDIO_CONVERTER #ifdef TRACE_AUDIO_CONVERTER # include # define TRACE(x...) printf(x) #else # define TRACE(x...) #endif struct ReadFloat { inline int operator()(const void* buffer) const { // 0 == mid, -1.0 == bottom, 1.0 == top float b = *(float*)buffer; if (b < -1.0f) b = -1.0f; else if (b > 1.0f) b = 1.0f; return (int)((double)b * (double)0x7fffffff); } }; struct ReadInt { inline int operator()(const void* buffer) const { // 0 == mid, 0x80000001 == bottom, 0x7fffffff == top int b = *(int*)buffer; if (b == INT_MIN) b++; return b; } }; struct ReadShort { inline int operator()(const void* buffer) const { // 0 == mid, -32767 == bottom, +32767 short b = *(short*)buffer; if (b == -32768) b++; return int(int64(b) * 0x7fffffff / 32767); } }; struct ReadUChar { inline int operator()(const void* buffer) const { // 128 == mid, 1 == bottom, 255 == top uchar b = *(uchar*)buffer; if (b == 0) b++; return int((int64(b) - 0x80) * 0x7fffffff / 127); } }; struct ReadChar { inline int operator()(const void* buffer) const { // 0 == mid, -127 == bottom, +127 == top char b = *(char*)buffer; if (b == 0) b++; return int(int64(b) * 0x7fffffff / 127); } }; struct WriteFloat { inline void operator()(void* buffer, int value) const { *(float*)buffer = (double)value / (double)0x7fffffff; } }; struct WriteInt { inline void operator()(void* buffer, int value) const { *(int*)buffer = value; } }; struct WriteShort { inline void operator()(void* buffer, int value) const { *(short*)buffer = (short)(value / (int)0x10000); } }; struct WriteUChar { inline void operator()(void* buffer, int value) const { *(uchar*)buffer = (uchar)(value / (int)0x1000000 + 128); } }; struct WriteChar { inline void operator()(void* buffer, int value) const { *(char*)buffer = (char)(value / (int)0x1000000); } }; template static void convert(const ReadT& read, const WriteT& write, const char* inBuffer, char* outBuffer, int32 frames, int32 inSampleSize, int32 outSampleSize, int32 channelCount) { for (int32 i = 0; i < frames; i++) { for (int32 c = 0; c < channelCount; c++) { write(outBuffer, read(inBuffer)); inBuffer += inSampleSize; outBuffer += outSampleSize; } } } static void swap_sample_byte_order(void* buffer, uint32 format, size_t length) { type_code type = B_ANY_TYPE; switch (format) { case media_raw_audio_format::B_AUDIO_FLOAT: type = B_FLOAT_TYPE; break; case media_raw_audio_format::B_AUDIO_INT: type = B_INT32_TYPE; break; case media_raw_audio_format::B_AUDIO_SHORT: type = B_INT16_TYPE; break; case media_raw_audio_format::B_AUDIO_UCHAR: break; case media_raw_audio_format::B_AUDIO_CHAR: break; } if (type != B_ANY_TYPE) swap_data(type, buffer, length, B_SWAP_ALWAYS); } // #pragma mark - AudioFormatConverter::AudioFormatConverter(AudioReader* source, uint32 format, uint32 byteOrder) : AudioReader(), fSource(NULL) { uint32 hostByteOrder = (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN; if (source && source->Format().type == B_MEDIA_RAW_AUDIO && source->Format().u.raw_audio.byte_order == hostByteOrder) { fFormat = source->Format(); fFormat.u.raw_audio.format = format; fFormat.u.raw_audio.byte_order = byteOrder; int32 inSampleSize = source->Format().u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK; int32 outSampleSize = fFormat.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK; if (inSampleSize != outSampleSize) { fFormat.u.raw_audio.buffer_size = source->Format().u.raw_audio.buffer_size * outSampleSize / inSampleSize; } } else source = NULL; fSource = source; } AudioFormatConverter::~AudioFormatConverter() { } bigtime_t AudioFormatConverter::InitialLatency() const { return fSource->InitialLatency(); } status_t AudioFormatConverter::Read(void* buffer, int64 pos, int64 frames) { TRACE("AudioFormatConverter::Read(%p, %lld, %lld)\n", buffer, pos, frames); status_t error = InitCheck(); if (error != B_OK) { TRACE("AudioFormatConverter::Read() done 1\n"); return error; } pos += fOutOffset; if (fFormat.u.raw_audio.format == fSource->Format().u.raw_audio.format && fFormat.u.raw_audio.byte_order == fSource->Format().u.raw_audio.byte_order) { TRACE("AudioFormatConverter::Read() done 2\n"); return fSource->Read(buffer, pos, frames); } int32 inSampleSize = fSource->Format().u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK; int32 outSampleSize = fFormat.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK; int32 channelCount = fFormat.u.raw_audio.channel_count; int32 inFrameSize = inSampleSize * channelCount; int32 outFrameSize = outSampleSize * channelCount; char* reformatBuffer = NULL; char* inBuffer = (char*)buffer; #ifdef TRACE_AUDIO_CONVERTER char formatString[256]; string_for_format(fSource->Format(), formatString, 256); TRACE(" source format: %s\n", formatString); TRACE(" in format : format: %lx, sample size: %ld, channels: %ld, " "byte order: %lu\n", fSource->Format().u.raw_audio.format, inSampleSize, channelCount, fSource->Format().u.raw_audio.byte_order); TRACE(" out format: format: %lx, sample size: %ld, channels: %ld, " "byte order: %lu\n", fFormat.u.raw_audio.format, outSampleSize, channelCount, fFormat.u.raw_audio.byte_order); #endif // TRACE_AUDIO_CONVERTER if (inSampleSize != outSampleSize) { reformatBuffer = new char[frames * inFrameSize]; inBuffer = reformatBuffer; } error = fSource->Read(inBuffer, pos, frames); // convert samples to host endianess uint32 hostByteOrder = (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN; if (fSource->Format().u.raw_audio.byte_order != hostByteOrder) { swap_sample_byte_order(inBuffer, fSource->Format().u.raw_audio.format, frames * inFrameSize); } // convert the sample type switch (fSource->Format().u.raw_audio.format) { // float case media_raw_audio_format::B_AUDIO_FLOAT: switch (fFormat.u.raw_audio.format) { case media_raw_audio_format::B_AUDIO_FLOAT: break; case media_raw_audio_format::B_AUDIO_INT: convert(ReadFloat(), WriteInt(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_SHORT: convert(ReadFloat(), WriteShort(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_UCHAR: convert(ReadFloat(), WriteUChar(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_CHAR: convert(ReadFloat(), WriteChar(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; } break; // int case media_raw_audio_format::B_AUDIO_INT: switch (fFormat.u.raw_audio.format) { case media_raw_audio_format::B_AUDIO_FLOAT: convert(ReadInt(), WriteFloat(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_INT: break; case media_raw_audio_format::B_AUDIO_SHORT: convert(ReadInt(), WriteShort(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_UCHAR: convert(ReadInt(), WriteUChar(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_CHAR: convert(ReadInt(), WriteChar(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; } break; // short case media_raw_audio_format::B_AUDIO_SHORT: switch (fFormat.u.raw_audio.format) { case media_raw_audio_format::B_AUDIO_FLOAT: convert(ReadShort(), WriteFloat(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_INT: convert(ReadShort(), WriteInt(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_SHORT: break; case media_raw_audio_format::B_AUDIO_UCHAR: convert(ReadShort(), WriteUChar(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_CHAR: convert(ReadShort(), WriteChar(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; } break; // uchar case media_raw_audio_format::B_AUDIO_UCHAR: switch (fFormat.u.raw_audio.format) { case media_raw_audio_format::B_AUDIO_FLOAT: convert(ReadUChar(), WriteFloat(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_INT: convert(ReadUChar(), WriteInt(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_SHORT: convert(ReadUChar(), WriteShort(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_UCHAR: break; case media_raw_audio_format::B_AUDIO_CHAR: convert(ReadUChar(), WriteChar(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; } break; // char case media_raw_audio_format::B_AUDIO_CHAR: switch (fFormat.u.raw_audio.format) { case media_raw_audio_format::B_AUDIO_FLOAT: convert(ReadChar(), WriteFloat(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_INT: convert(ReadChar(), WriteInt(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_SHORT: convert(ReadChar(), WriteShort(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_UCHAR: convert(ReadChar(), WriteUChar(), inBuffer, (char*)buffer, frames, inSampleSize, outSampleSize, channelCount); break; case media_raw_audio_format::B_AUDIO_CHAR: break; } break; } // convert samples to output endianess if (fFormat.u.raw_audio.byte_order != hostByteOrder) { swap_sample_byte_order(buffer, fFormat.u.raw_audio.format, frames * outFrameSize); } delete[] reformatBuffer; TRACE("AudioFormatConverter::Read() done\n"); return B_OK; } status_t AudioFormatConverter::InitCheck() const { status_t error = AudioReader::InitCheck(); if (error == B_OK && !fSource) error = B_NO_INIT; if (error == B_OK) error = fSource->InitCheck(); return error; } AudioReader* AudioFormatConverter::Source() const { return fSource; }