Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
uLawDecompressor.c
/* |
File: uLawDecompressor.c |
Contains µLaw 2:1 Decompression Sound Component |
Written by: Jim Reekes |
Copyright: © 1991-1998 by Apple Computer, Inc., all rights reserved. |
*/ |
#if defined(_MSC_VER) && !defined(__MWERKS__) |
#pragma warning(disable:4229) // ignore anachronism used: modifiers on data are ignored |
#endif |
#include <MacTypes.h> |
#include <Errors.h> |
#include <Endian.h> |
#include <MacMemory.h> |
#include <Resources.h> |
#include <Components.h> |
#include <Sound.h> |
#include <MoviesFormat.h> |
#if !TARGET_OS_MAC |
#include "QTML.h" |
#endif |
#include "uLawCodec.h" |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Constants |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
#define kInputFormat kCodecFormat /* required input format */ |
#define kOutputFormat k16BitNativeEndianFormat /* decompressors must output native samples */ |
enum { |
kOutputSampleSize = 16, /* size of output samples */ |
kOutputBufferBytes = (kMaxOutputSamples * (kOutputSampleSize/8) * 2) /* room for 16-bit stereo data */ |
}; |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// types |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
#if PRAGMA_STRUCT_ALIGN |
#pragma options align=mac68k |
#elif PRAGMA_STRUCT_PACKPUSH |
#pragma pack(push, 2) |
#elif PRAGMA_STRUCT_PACK |
#pragma pack(2) |
#endif |
// Keep your data long word aligned for best performance |
typedef struct { |
ComponentInstance sourceComponent; /* who to call for more source data */ |
SoundComponentDataPtr sourceDataPtr; /* pointer to source data descriptor */ |
SoundComponentData outputData; /* local data descriptor record */ |
SoundSource sourceID; |
long maxFrames; /* max frames we can output, considering stereo */ |
long outputBufferSamples; /* no. samples in output buffer */ |
CompressionInfo compInfo; /* info about compressor */ |
Handle ulawTableHandle; /* resource handle to ulaw table */ |
short *ulawTable; /* pointer to ulaw table */ |
Byte buffer[kOutputBufferBytes]; /* buffer space */ |
#if !TARGET_OS_MAC |
QTMLMutex interruptMutex; /* prevent (if necessary) the app and interrupt killing eachother */ |
#endif |
} ULawDecompGlobals, *ULawDecompGlobalsPtr; |
typedef struct { |
AudioFormatAtom formatData; |
AudioEndianAtom endianData; |
AudioTerminatorAtom terminatorData; |
} AudioDecompressionAtom, *AudioDecompressionAtomPtr, **AudioDecompressionAtomHandle; |
#if PRAGMA_STRUCT_ALIGN |
#pragma options align=reset |
#elif PRAGMA_STRUCT_PACKPUSH |
#pragma pack(pop) |
#elif PRAGMA_STRUCT_PACK |
#pragma pack() |
#endif |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// prototypes |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static OSErr GetDecompressionParams(ULawDecompGlobalsPtr globals, AudioDecompressionAtomHandle *params); |
static OSErr SetDecompressionParams(ULawDecompGlobalsPtr globals, UserDataAtom *atom); |
static ComponentResult PrimeSource(ULawDecompGlobalsPtr globals); |
static unsigned long SamplesToBytes(unsigned long sampleCount, CompressionInfoPtr compInfo); |
static unsigned long BytesToSamples(unsigned long byteCount, CompressionInfoPtr compInfo); |
static unsigned long SamplesToFrames(unsigned long sampleCount, CompressionInfoPtr compInfo); |
static unsigned long FramesToSamples(unsigned long framesCount, CompressionInfoPtr compInfo); |
static void InitializeCompressionInfo(ULawDecompGlobalsPtr globals); |
static OSErr DecompressorGetInfo(ULawDecompGlobalsPtr globals, OSType selector, void *infoPtr); |
static OSErr DecompressorSetInfo(ULawDecompGlobalsPtr globals, OSType selector, void *infoPtr); |
static OSErr SetCompressorInfo(ULawDecompGlobalsPtr globals, CompressionInfoPtr cp); |
static void ExpandULaw(Byte *inbuf, short *outbuf, short *ulawTable, long framesToConvert, short numChannels, short whichChannel, short sampleSize); |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Component Dispatcher |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
#if TARGET_CPU_68K |
#define COMPONENT_C_DISPATCHER |
#define COMPONENT_DISPATCH_MAIN |
#endif |
#define CALLCOMPONENT_BASENAME() __uLawDecomp |
#define CALLCOMPONENT_GLOBALS() ULawDecompGlobalsPtr storage |
#define SOUNDCOMPONENT_BASENAME() CALLCOMPONENT_BASENAME() |
#define SOUNDCOMPONENT_GLOBALS() CALLCOMPONENT_GLOBALS() |
#define COMPONENT_UPP_SELECT_ROOT() SoundComponent |
#define COMPONENT_DISPATCH_FILE "uLawCodecDispatch.h" |
#define GET_DELEGATE_COMPONENT() (storage->sourceComponent) |
#include "Components.k.h" |
#include "Sound.k.h" |
#include "ComponentDispatchHelper.c" |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Component Routines |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawDecompOpen(ULawDecompGlobalsPtr globals, ComponentInstance self) |
{ |
OSErr result; |
globals = (ULawDecompGlobalsPtr)NewPtrSysClear(sizeof(ULawDecompGlobals)); |
FailWithAction(globals == nil, result = MemError(), Failure); |
result = GetComponentResource((Component)self, k16BitTableResType, kSoundDecompressorResID, &globals->ulawTableHandle); |
FailIf(result != noErr, NoResource); |
HLock(globals->ulawTableHandle); |
globals->ulawTable = (short *)StripAddress(*globals->ulawTableHandle); |
#if TARGET_RT_LITTLE_ENDIAN |
// The ulawTable values are stored in the resource fork as 16-bit big-endian data |
// (Rez assumes any integers in a .r file are big-endian, for compatibility). |
// Make them little-endian, so we can do math with them on this little-endian machine. |
// There are ways to get the Resource Manager to do this for you by registering |
// a callback for the resource type, but that's beyond the scope of this example. |
{ |
long numElements = GetHandleSize(globals->ulawTableHandle) / 2; |
long i; |
for (i = 0; i < numElements; i++) { |
globals->ulawTable[i] = EndianU16_BtoN(globals->ulawTable[i]); |
} |
} |
#endif |
globals->outputData.format = kOutputFormat; // output format |
globals->outputData.sampleSize = kOutputSampleSize; // output sample size |
globals->outputBufferSamples = kMaxOutputSamples; // will be set to requested->sampleCount later |
InitializeCompressionInfo(globals); |
// set our storage pointer to our globals |
SetComponentInstanceStorage(self, (Handle) globals); |
#if !TARGET_OS_MAC |
globals->interruptMutex = QTMLCreateMutex(); |
FailWithAction(globals->interruptMutex == nil, result = memFullErr, NoMutex); |
#endif |
return (noErr); |
NoMutex: |
DisposeHandle(globals->ulawTableHandle); |
NoResource: |
DisposePtr((Ptr)globals); |
Failure: |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawDecompClose(ULawDecompGlobalsPtr globals, ComponentInstance self) |
{ |
ComponentResult result; |
self; // suppress "unused variable" warning for all compilers |
if (globals != nil) // we have some globals |
{ |
if (globals->sourceComponent) |
{ |
result = CloseComponent(globals->sourceComponent); // torch source component |
FailMessage(result != noErr); |
} |
globals->outputData.sampleCount = 0; // nothing in our buffer now |
#if !TARGET_OS_MAC |
if (globals->interruptMutex != nil) |
{ |
QTMLDestroyMutex(globals->interruptMutex); |
globals->interruptMutex = nil; |
} |
#endif |
if (globals->ulawTableHandle != nil) |
DisposeHandle(globals->ulawTableHandle); |
DisposePtr((Ptr)globals); // torch them |
} |
return (noErr); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
pascal ComponentResult __uLawDecompVersion(ULawDecompGlobalsPtr globals) |
{ |
globals; // suppress "unused variable" warning for all compilers |
return (kSoundDecompressorVersion); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Sound Component Methods |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawDecompSetSource(ULawDecompGlobalsPtr globals, SoundSource sourceID, ComponentInstance source) |
{ |
SoundComponentDataPtr sourceData; |
globals->sourceID = sourceID; |
globals->sourceComponent = source; // our food source |
globals->sourceDataPtr = nil; // nothing read from source yet |
// make sure we can get the source we need |
return (SoundComponentSetOutput(source, &globals->outputData, &sourceData)); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawDecompSetOutput(ULawDecompGlobalsPtr globals, SoundComponentDataPtr requested, SoundComponentDataPtr *actual) |
{ |
globals->outputBufferSamples = requested->sampleCount; // no. samples to output |
if (globals->outputBufferSamples > kMaxOutputSamples) // too much for our buffer |
globals->outputBufferSamples = kMaxOutputSamples; |
// must be one of the output formats we support |
FailIf((requested->sampleSize == 8) && (requested->format != k8BitOffsetBinaryFormat), Failure); |
// decompressors output to native endian by definition |
FailIf((requested->sampleSize == 16) && (requested->format != k16BitNativeEndianFormat), Failure); |
globals->outputData = *requested; |
return (noErr); |
Failure: |
// here's what we can do |
*actual = &globals->outputData; |
return (paramErr); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawDecompGetInfo(ULawDecompGlobalsPtr globals, SoundSource sourceID, OSType selector, void *infoPtr) |
{ |
ComponentResult result; |
result = noErr; |
switch (selector) |
{ |
case siCompressionFactor: |
*(CompressionInfoPtr)infoPtr = globals->compInfo; |
break; |
case siDecompressionParams: |
result = GetDecompressionParams(globals, (AudioDecompressionAtomHandle *)infoPtr); |
break; |
default: |
if (globals->sourceComponent == nil) |
result = siUnknownInfoType; |
else |
result = SoundComponentGetInfo(globals->sourceComponent, sourceID, selector, infoPtr); |
break; |
} |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawDecompSetInfo(ULawDecompGlobalsPtr globals, SoundSource sourceID, OSType selector, void *infoPtr) |
{ |
ComponentResult result; |
result = noErr; |
switch (selector) |
{ |
case siDecompressionParams: |
result = SetDecompressionParams(globals, (UserDataAtom *)infoPtr); |
break; |
default: |
if (globals->sourceComponent == nil) |
result = siUnknownInfoType; |
else |
result = SoundComponentSetInfo(globals->sourceComponent, sourceID, selector, infoPtr); |
} |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawDecompPlaySourceBuffer(ULawDecompGlobalsPtr globals, SoundSource sourceID, SoundParamBlockPtr pb, long actions) |
{ |
globals->sourceDataPtr = nil; // no source yet |
globals->outputData.sampleCount = 0; // our buffer is empty |
return (SoundComponentPlaySourceBuffer(globals->sourceComponent, sourceID, pb, actions)); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawDecompStopSource(ULawDecompGlobalsPtr globals, short count, SoundSource *sources) |
{ |
globals->sourceDataPtr = nil; // assume our source is gone |
return (SoundComponentStopSource(globals->sourceComponent, count, sources)); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawDecompGetSourceData(ULawDecompGlobalsPtr globals, SoundComponentDataPtr *resultData) |
{ |
SoundComponentDataPtr sourceDataPtr; |
long samplesConverted; |
long framesToConvert; |
ComponentResult result = noErr; |
Byte *inputBuffer; |
if (globals->sourceDataPtr == nil) // no source pointer so... |
{ |
result = PrimeSource(globals); // get data from our source |
FailIf(result != noErr, Exit); |
} |
sourceDataPtr = globals->sourceDataPtr; // get pointer to source sound component |
if (sourceDataPtr->sampleCount == 0) // source is out of bytes |
{ // get some more source |
result = SoundComponentGetSourceData(globals->sourceComponent, &globals->sourceDataPtr); |
FailIf(result != noErr, Exit); |
sourceDataPtr = globals->sourceDataPtr; // get pointer to source sound component |
} |
if ((sourceDataPtr->format == globals->outputData.format) || // input and output are same |
(sourceDataPtr->buffer == nil) || // or no source buffer |
(sourceDataPtr->sampleCount == 0)) // or no source buffer |
{ |
globals->sourceDataPtr = nil; // get new source next time |
*resultData = sourceDataPtr; // pass source on down |
} |
else |
{ |
framesToConvert = SamplesToFrames(sourceDataPtr->sampleCount, &globals->compInfo); |
if (framesToConvert) // source has some data for us |
{ |
if (framesToConvert > globals->maxFrames) |
framesToConvert = globals->maxFrames; // limited to size of output |
samplesConverted = FramesToSamples(framesToConvert, &globals->compInfo); |
inputBuffer = sourceDataPtr->buffer; // point at input buffer |
sourceDataPtr->buffer += SamplesToBytes(samplesConverted, &globals->compInfo); // update input buffer |
sourceDataPtr->sampleCount -= samplesConverted; |
if (sourceDataPtr->numChannels == 1) |
{ |
ExpandULaw(inputBuffer, (short *) globals->buffer, globals->ulawTable, |
framesToConvert, 1, 1, globals->outputData.sampleSize); |
} |
else |
{ |
// do the left samples |
ExpandULaw(inputBuffer, (short *) globals->buffer, globals->ulawTable, |
framesToConvert, 2, 1, globals->outputData.sampleSize); |
// do the right samples |
ExpandULaw(inputBuffer, (short *) globals->buffer, globals->ulawTable, |
framesToConvert, 2, 2, globals->outputData.sampleSize); |
} |
} |
else |
samplesConverted = 0; |
globals->outputData.buffer = globals->buffer; // data in this buffer |
globals->outputData.sampleCount = samplesConverted; // return num. samples converted |
*resultData = &globals->outputData; // tell them what we made |
} |
Exit: |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// sub routines _ |
// _|_ |
// o _____| |_____ |
// o o +______________/ |
// |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static OSErr GetDecompressionParams(ULawDecompGlobalsPtr globals, AudioDecompressionAtomHandle *params) |
{ |
AudioDecompressionAtomHandle atom; |
AudioDecompressionAtomPtr atomPtr; |
OSErr result; |
globals; // suppress "unused variable" warning for all compilers |
result = noErr; |
atom = (AudioDecompressionAtomHandle)NewHandle(sizeof(AudioDecompressionAtom)); |
FailWithAction(atom == nil, result = MemError(), Exit); |
atomPtr = *atom; |
atomPtr->formatData.size = EndianU32_NtoB(sizeof(AudioFormatAtom)); |
atomPtr->formatData.atomType = EndianU32_NtoB(kAudioFormatAtomType); |
atomPtr->formatData.format = EndianU32_NtoB(kInputFormat); |
atomPtr->endianData.size = EndianU32_NtoB(sizeof(AudioEndianAtom)); |
atomPtr->endianData.atomType = EndianU32_NtoB(kAudioEndianAtomType); |
atomPtr->endianData.littleEndian = EndianU16_NtoB(false); // µlaw is not little endian |
atomPtr->terminatorData.size = EndianU32_NtoB(sizeof(AudioTerminatorAtom)); |
atomPtr->terminatorData.atomType = EndianU32_NtoB(kAudioTerminatorAtomType); |
*params = atom; |
Exit: |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static OSErr SetDecompressionParams(ULawDecompGlobalsPtr globals, UserDataAtom *atom) |
{ |
OSErr result; |
short littleEndian; |
Boolean moreAtoms; |
globals; // suppress "unused variable" warning for all compilers |
result = noErr; |
moreAtoms = true; |
littleEndian = false; |
do |
{ |
long atomSize = EndianS32_BtoN(atom->size); |
FailWithAction(atomSize < 8, result = invalidAtomErr, Exit); |
switch (EndianU32_BtoN(atom->atomType)) |
{ |
case kAudioFormatAtomType: |
FailWithAction(((AudioFormatAtom *)atom)->format != EndianU32_NtoB(kInputFormat), result = badFormat, Exit); |
break; |
case kAudioEndianAtomType: |
#if !TARGET_OS_MAC |
// Don't do this during an interrupt |
QTMLGrabMutex(globals->interruptMutex); |
#endif |
littleEndian = EndianU16_BtoN(((AudioEndianAtom *)atom)->littleEndian); |
#if !TARGET_OS_MAC |
QTMLReturnMutex(globals->interruptMutex); |
#endif |
break; |
case kAudioTerminatorAtomType: |
moreAtoms = false; |
break; |
default: // unknown atom type |
break; |
} |
atom = (UserDataAtom *)((long)atom + atomSize); |
} while (moreAtoms); |
if (littleEndian) |
result = paramErr; // we do not do little endian |
Exit: |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static ComponentResult PrimeSource(ULawDecompGlobalsPtr globals) |
{ |
ComponentResult result = noErr; |
SoundComponentDataPtr sourceDataPtr; |
result = SoundComponentGetSourceData(globals->sourceComponent, &globals->sourceDataPtr); |
FailIf(result != noErr, Exit); |
FailWithAction(globals->sourceDataPtr == nil, result = paramErr, Exit); |
sourceDataPtr = globals->sourceDataPtr; |
globals->outputData.flags = sourceDataPtr->flags; // copy flags unchanged |
globals->outputData.sampleRate = sourceDataPtr->sampleRate; // copy sample rate unchanged |
globals->outputData.numChannels = sourceDataPtr->numChannels; // copy numchannels unchanged |
// update bytesPerFrame according to number of channels |
globals->compInfo.bytesPerFrame = globals->compInfo.bytesPerPacket * sourceDataPtr->numChannels; |
globals->maxFrames = SamplesToFrames(globals->outputBufferSamples, &globals->compInfo); |
Exit: |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static unsigned long SamplesToBytes(unsigned long sampleCount, CompressionInfoPtr compInfo) |
{ |
return ((sampleCount / compInfo->samplesPerPacket) * compInfo->bytesPerFrame); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static unsigned long BytesToSamples(unsigned long byteCount, CompressionInfoPtr compInfo) |
{ |
return ((byteCount / compInfo->bytesPerFrame) * compInfo->samplesPerPacket); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static unsigned long SamplesToFrames(unsigned long sampleCount, CompressionInfoPtr compInfo) |
{ |
return (sampleCount / compInfo->samplesPerPacket); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static unsigned long FramesToSamples(unsigned long frameCount, CompressionInfoPtr compInfo) |
{ |
return (frameCount * compInfo->samplesPerPacket); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static void InitializeCompressionInfo(ULawDecompGlobalsPtr globals) |
{ |
globals->compInfo.recordSize = sizeof(CompressionInfo); |
globals->compInfo.format = kInputFormat; |
globals->compInfo.compressionID = fixedCompression; |
globals->compInfo.samplesPerPacket = kULawBlockSamples; |
globals->compInfo.bytesPerPacket = kULawBlockBytes; |
globals->compInfo.bytesPerSample = kULawBytesPerSample; |
globals->compInfo.bytesPerFrame = kULawBlockBytes; |
globals->compInfo.futureUse1 = 0; |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// µLaw 2:1 Decompression |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
#if TARGET_RT_BIG_ENDIAN |
#define GetEndianHighByte(p) (*(Byte *)(&p)) |
#else |
#define GetEndianHighByte(p) (*((Byte *)(&p)+1)) |
#endif |
void ExpandULaw(Byte *inbuf, short *outbuf, short *ulawTable, |
long framesToConvert, short numChannels, short whichChannel, short sampleSize) |
{ |
short i; |
whichChannel -= 1; |
inbuf += whichChannel; |
if (sampleSize == 8) |
{ |
Byte *outbuf8 = (Byte *) outbuf; |
Byte b, toggle = 0x80; |
if (numChannels == 1) |
{ |
for (i = framesToConvert - 1; i >= 0; --i) |
{ |
b = GetEndianHighByte(ulawTable[*inbuf++]); |
b ^= toggle; |
*outbuf8++ = b; |
} |
} |
else |
{ |
outbuf8 += whichChannel; |
for (i = framesToConvert - 1; i >= 0; --i) |
{ |
b = GetEndianHighByte(ulawTable[*inbuf]); |
b ^= toggle; |
*outbuf8 = b; |
inbuf += 2; |
outbuf8 += 2; |
} |
} |
} |
else |
{ |
if (numChannels == 1) |
{ |
for (i = framesToConvert - 1; i >= 0; --i) |
{ |
*outbuf++ = ulawTable[*inbuf++]; |
} |
} |
else |
{ |
outbuf += whichChannel; |
for (i = framesToConvert - 1; i >= 0; --i) |
{ |
*outbuf = ulawTable[*inbuf]; |
inbuf += 2; |
outbuf += 2; |
} |
} |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14