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.
Relevant replacement documents include:
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 <MacErrors.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