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:
uLawCompressor.c
/* |
File: uLawCompressor.c |
Contains: uLaw Compression 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 <Components.h> |
#include <MacMemory.h> |
#include <Resources.h> |
#include <Controls.h> |
#include <ControlDefinitions.h> |
#include <Dialogs.h> |
#include <Sound.h> |
#include <MoviesFormat.h> |
#include "uLawCodec.h" |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Constants |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
#define kInputFormat k16BitNativeEndianFormat /* required input format */ |
#define kOutputFormat kCodecFormat /* only formats we output */ |
#define ZEROTRAP 1 /* turn on the trap as per the MIL-STD */ |
enum { |
kOutputSampleSize = 16, /* size of output samples */ |
kOutputSamples = ((kMaxOutputSamples / kULawBlockSamples) * kULawBlockSamples), /* max actual samples in output buffer */ |
kOutputBufferBytes = ((kMaxOutputSamples / kULawBlockSamples) * kULawBlockBytes * 2), /* room for ULaw stereo data */ |
kLeftoverBufferBytes = (kULawBlockSamples * 2 * 2), /* room for leftover stereo 16-bit samples */ |
kInputSampleSize = 16, |
BIAS = 0x84, /* define the add-in bias for 16 bit samples */ |
CLIP = 32635, |
kOptionCheckBox = 4 |
}; |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// 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 self; /* our instance */ |
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 outputBufferSamples; /* no. samples in output buffer */ |
CompressionInfo sourceCompInfo; /* info about source data format */ |
CompressionInfo destCompInfo; /* info about destination data format */ |
Handle ulawTableHandle; /* resource handle to ulaw table */ |
Byte *ulawTable; /* pointer to ulaw table */ |
unsigned long leftOverSamples; /* no. samples in leftover buffer */ |
Byte leftOverBuffer[kLeftoverBufferBytes]; /* space for leftover samples */ |
Byte buffer[kOutputBufferBytes + kLeftoverBufferBytes]; /* buffer space */ |
} ULawCompGlobals, *ULawCompGlobalsPtr; |
typedef struct { |
AudioFormatAtom formatData; |
AudioEndianAtom endianData; |
AudioTerminatorAtom terminatorData; |
} AudioCompressionAtom, *AudioCompressionAtomPtr, **AudioCompressionAtomHandle; |
#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 DisplayOptionsDialog(ULawCompGlobalsPtr globals); |
static void SetButtonState(DialogPtr dialog, short item, Boolean state); |
static short GetButtonState(DialogPtr dialog, short item); |
static OSErr GetCompressionParams(ULawCompGlobalsPtr globals, AudioCompressionAtomHandle *params); |
static OSErr SetCompressionParams(ULawCompGlobalsPtr globals, UserDataAtom *atom); |
static ComponentResult PrimeSource(ULawCompGlobalsPtr 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 CompressThisMess(Byte *inputBuffer, Byte *outputBuffer, Byte *ulawTable, long samplesToConvert, short numChannels); |
static void GetCompressorInfo(CompressionInfoPtr cp); |
static void CompressULaw(SInt16 *inPtr, Byte *outPtr, Byte *ulawTable, long sampleCount, short numChannels, short whichChannel); |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Component Dispatcher |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
#if TARGET_CPU_68K |
#define COMPONENT_C_DISPATCHER |
#define COMPONENT_DISPATCH_MAIN |
#endif |
#define CALLCOMPONENT_BASENAME() __uLawComp |
#define CALLCOMPONENT_GLOBALS() ULawCompGlobalsPtr 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 __uLawCompOpen(ULawCompGlobalsPtr globals, ComponentInstance self) |
{ |
OSErr result; |
globals = (ULawCompGlobalsPtr)NewPtrSysClear(sizeof(ULawCompGlobals)); |
FailWithAction(globals == nil, result = MemError(), Failure); |
result = GetComponentResource((Component)self, k8BitTableResType, kSoundCompressorResID, &globals->ulawTableHandle); |
FailIf(result != noErr, NoResource); |
HLock(globals->ulawTableHandle); |
globals->ulawTable = (Byte *)StripAddress(*globals->ulawTableHandle); |
globals->self = self; |
globals->outputData.format = kOutputFormat; // output format |
globals->outputData.sampleSize = kOutputSampleSize; // output sample size |
globals->outputBufferSamples = kOutputSamples; // will be set to requested->sampleCount later |
// set our storage pointer to our globals |
SetComponentInstanceStorage(self, (Handle) globals); |
return (noErr); |
NoResource: |
DisposePtr((Ptr)globals); |
Failure: |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawCompClose(ULawCompGlobalsPtr 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 (globals->ulawTableHandle != nil) |
DisposeHandle(globals->ulawTableHandle); |
DisposePtr((Ptr)globals); // torch them |
} |
return (noErr); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
pascal ComponentResult __uLawCompVersion(ULawCompGlobalsPtr globals) |
{ |
globals; // suppress "unused variable" warning for all compilers |
return (kSoundCompressorVersion); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Sound Component Methods |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawCompSetSource(ULawCompGlobalsPtr globals, SoundSource sourceID, ComponentInstance source) |
{ |
SoundComponentData sourceData; |
short i; |
Byte *bPtr; |
globals->sourceID = sourceID; |
globals->sourceComponent = source; // our food source |
globals->sourceDataPtr = nil; // nothing read from source yet |
bPtr = (Byte *)&sourceData; // zero out struct |
for (i = 0; i < sizeof(SoundComponentData); i++) |
bPtr = 0; |
sourceData.format = kInputFormat; // our source must give us this format |
sourceData.sampleSize = kInputSampleSize; |
sourceData.sampleCount = globals->outputBufferSamples; |
// make sure we can get the source we need |
return (noErr); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawCompSetOutput(ULawCompGlobalsPtr globals, SoundComponentDataPtr requested, SoundComponentDataPtr *actual) |
{ |
globals->outputBufferSamples = requested->sampleCount; // no. samples to output |
if (globals->outputBufferSamples > kOutputSamples) // too much for our buffer |
globals->outputBufferSamples = kOutputSamples; |
// must be one of the output formats we support |
if (requested->format != kOutputFormat) |
goto Failure; |
globals->outputData = *requested; |
return (noErr); |
Failure: |
// here's what we can do |
*actual = &globals->outputData; |
return (paramErr); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawCompGetInfo(ULawCompGlobalsPtr globals, SoundSource sourceID, OSType selector, void *infoPtr) |
{ |
ComponentResult result; |
result = noErr; |
switch (selector) |
{ |
case siCompressionFactor: |
GetCompressorInfo(infoPtr); |
break; |
case siCompressionParams: |
result = GetCompressionParams(globals, infoPtr); |
break; |
case siOptionsDialog: |
*(short *)infoPtr = true; |
break; |
default: |
if (globals->sourceComponent == nil) |
result = siUnknownInfoType; |
else |
result = SoundComponentGetInfo(globals->sourceComponent, sourceID, selector, infoPtr); |
break; |
} |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawCompSetInfo(ULawCompGlobalsPtr globals, SoundSource sourceID, OSType selector, void *infoPtr) |
{ |
ComponentResult result; |
result = noErr; |
switch (selector) |
{ |
case siOptionsDialog: |
DisplayOptionsDialog(globals); |
break; |
case siCompressionParams: |
result = SetCompressionParams(globals, infoPtr); |
break; |
default: |
if (globals->sourceComponent == nil) |
result = siUnknownInfoType; |
else |
result = SoundComponentSetInfo(globals->sourceComponent, sourceID, selector, infoPtr); |
break; |
} |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawCompPlaySourceBuffer(ULawCompGlobalsPtr 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 __uLawCompStopSource(ULawCompGlobalsPtr globals, short count, SoundSource *sources) |
{ |
globals->sourceDataPtr = nil; // assume our source is gone |
globals->leftOverSamples = 0; // clear anything in leftover buffer |
return (SoundComponentStopSource(globals->sourceComponent, count, sources)); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __uLawCompGetSourceData(ULawCompGlobalsPtr globals, SoundComponentDataPtr *resultData) |
{ |
SoundComponentDataPtr sourceDataPtr; |
long samplesToCopy; |
unsigned long bytesToCopy, framesToCopy, byteOffset; |
ComponentResult result = noErr; |
if (globals->sourceDataPtr == nil) // no source pointer so... |
{ |
result = PrimeSource(globals); // get data from our source |
FailIf(result != noErr, Failure); |
} |
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 |
{ |
globals->sourceDataPtr = nil; // get new source next time |
*resultData = sourceDataPtr; // pass source on down |
return (noErr); // get out |
} |
globals->outputData.buffer = globals->buffer; // initialize output buffer |
globals->outputData.sampleCount = 0; |
while ((sourceDataPtr->sampleCount < kULawBlockSamples) || // we don't have enough source for at least one block |
(globals->leftOverSamples)) // or we have samples in the leftover buffer |
{ |
if (sourceDataPtr->sampleCount == 0) // used up all the source |
{ |
result = SoundComponentGetSourceData(globals->sourceComponent, &globals->sourceDataPtr); // get more source |
FailIf(result != noErr, Failure); |
sourceDataPtr = globals->sourceDataPtr; // get pointer to source sound component |
if (sourceDataPtr->sampleCount == 0) // still no source samples - all done |
break; |
} |
samplesToCopy = kULawBlockSamples - globals->leftOverSamples; // compute samples needed to fill leftover buffer |
if (sourceDataPtr->sampleCount < samplesToCopy) // not enough source to fill it, so do what we can |
samplesToCopy = sourceDataPtr->sampleCount; |
// copy from source into leftover buffer |
bytesToCopy = SamplesToBytes(samplesToCopy, &globals->sourceCompInfo); |
byteOffset = SamplesToBytes(globals->leftOverSamples, &globals->sourceCompInfo); |
BlockMoveData(sourceDataPtr->buffer, globals->leftOverBuffer + byteOffset, bytesToCopy); |
sourceDataPtr->buffer += bytesToCopy; // samples removed from source |
sourceDataPtr->sampleCount -= samplesToCopy; |
globals->leftOverSamples += samplesToCopy; // keep track off samples in leftover buffer |
if (globals->leftOverSamples == kULawBlockSamples) // leftover buffer is full |
{ |
CompressThisMess(globals->leftOverBuffer, globals->outputData.buffer, globals->ulawTable, kULawBlockSamples, sourceDataPtr->numChannels); |
globals->outputData.buffer += SamplesToBytes(kULawBlockSamples, &globals->destCompInfo); |
globals->outputData.sampleCount += kULawBlockSamples; |
globals->leftOverSamples = 0; |
if (globals->outputData.sampleCount == kOutputSamples) // output buffer is full |
break; // stop converting |
} |
} |
samplesToCopy = kOutputSamples - globals->outputData.sampleCount; // find amount available in output buffer |
if (samplesToCopy > sourceDataPtr->sampleCount) // don't copy more than we have |
samplesToCopy = sourceDataPtr->sampleCount; |
framesToCopy = SamplesToFrames(samplesToCopy, &globals->destCompInfo); |
if (framesToCopy) // source has some data for us |
{ |
samplesToCopy = FramesToSamples(framesToCopy, &globals->destCompInfo); |
CompressThisMess(sourceDataPtr->buffer, globals->outputData.buffer, globals->ulawTable, samplesToCopy, sourceDataPtr->numChannels); |
sourceDataPtr->buffer += SamplesToBytes(samplesToCopy, &globals->sourceCompInfo); // update input buffer |
sourceDataPtr->sampleCount -= samplesToCopy; |
globals->outputData.buffer += SamplesToBytes(samplesToCopy, &globals->destCompInfo); |
globals->outputData.sampleCount += samplesToCopy; |
} |
globals->outputData.buffer = globals->buffer; // reset to beginning of buffer |
*resultData = &globals->outputData; // tell them what we made |
return (noErr); |
Failure: |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// sub routines _ |
// _|_ |
// o _____| |_____ |
// o o +______________/ |
// |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static OSErr DisplayOptionsDialog(ULawCompGlobalsPtr globals) |
{ |
DialogPtr dialog; |
short resFile; |
short currentResFile; |
short itemHit; |
OSErr result; |
result = noErr; |
currentResFile = CurResFile(); |
resFile = OpenComponentResFile((Component)globals->self); |
FailWithAction(resFile == kResFileNotOpened, result = ResError(), Exit); |
dialog = GetNewDialog(kSoundCompressorResID, nil, (WindowPtr)-1); |
FailWithAction(dialog == nil, result = resNotFound, NoDialog); |
MacSetPort(dialog); |
SetButtonState(dialog, kOptionCheckBox, true); |
SetDialogDefaultItem(dialog, kStdOkItemIndex); |
SetDialogCancelItem(dialog, kStdCancelItemIndex); |
MacShowWindow(dialog); |
do |
{ |
ModalDialog(nil, &itemHit); |
switch (itemHit) |
{ |
case kOptionCheckBox: |
if (GetButtonState(dialog, kOptionCheckBox)) |
SetButtonState(dialog, kOptionCheckBox, false); |
else |
SetButtonState(dialog, kOptionCheckBox, true); |
break; |
case kStdOkItemIndex: |
GetButtonState(dialog, kOptionCheckBox); |
// accept changes according to values set in dialog |
break; |
} |
} while ( (itemHit != kStdOkItemIndex) && (itemHit != kStdCancelItemIndex) ); |
DisposeDialog(dialog); |
NoDialog: |
CloseResFile(resFile); |
Exit: |
UseResFile(currentResFile); |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static void SetButtonState(DialogPtr dialog, short item, Boolean state) |
{ |
short iType; |
Handle iHandle; |
Rect iRect; |
GetDialogItem(dialog, item, &iType, &iHandle, &iRect); |
if (iHandle != nil) |
SetControlValue((ControlHandle) iHandle, (state) ? kControlRadioButtonCheckedValue : kControlRadioButtonUncheckedValue); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static short GetButtonState(DialogPtr dialog, short item) |
{ |
short iType; |
Handle iHandle; |
Rect iRect; |
GetDialogItem(dialog, item, &iType, &iHandle, &iRect); |
return (GetControlValue((ControlHandle) iHandle)); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static OSErr GetCompressionParams(ULawCompGlobalsPtr globals, AudioCompressionAtomHandle *params) |
{ |
AudioCompressionAtomHandle atom; |
AudioCompressionAtomPtr atomPtr; |
OSErr result; |
globals; // suppress "unused variable" warning for all compilers |
result = noErr; |
atom = (AudioCompressionAtomHandle)NewHandle(sizeof(AudioCompressionAtom)); |
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(kOutputFormat); |
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 SetCompressionParams(ULawCompGlobalsPtr 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(kOutputFormat), result = badFormat, Exit); |
break; |
case kAudioEndianAtomType: |
littleEndian = EndianU16_BtoN(((AudioEndianAtom *)atom)->littleEndian); |
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(ULawCompGlobalsPtr globals) |
{ |
ComponentResult result = noErr; |
SoundComponentDataPtr sourceDataPtr; |
result = SoundComponentGetSourceData(globals->sourceComponent, &globals->sourceDataPtr); |
FailIf(result != noErr, Failure); |
FailWithAction(globals->sourceDataPtr == nil, result = paramErr, Failure); |
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 |
globals->sourceCompInfo.recordSize = sizeof(CompressionInfo); // get source compression info |
result = GetCompressionInfo(fixedCompression, sourceDataPtr->format, |
sourceDataPtr->numChannels, sourceDataPtr->sampleSize, |
&globals->sourceCompInfo); |
FailIf(result != noErr, Failure); |
globals->destCompInfo.recordSize = sizeof(CompressionInfo); |
GetCompressorInfo(&globals->destCompInfo); // get dest compression info |
globals->destCompInfo.bytesPerFrame = globals->destCompInfo.bytesPerPacket * sourceDataPtr->numChannels; |
Failure: |
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 CompressThisMess(Byte *inputBuffer, Byte *outputBuffer, Byte *ulawTable, long samplesToConvert, short numChannels) |
{ |
if (numChannels == 1) |
{ |
CompressULaw((SInt16 *) inputBuffer, outputBuffer, ulawTable, samplesToConvert, 1, 1); |
} |
else |
{ |
CompressULaw((SInt16 *) inputBuffer, outputBuffer, ulawTable, samplesToConvert, 2, 1); |
CompressULaw((SInt16 *) inputBuffer, outputBuffer, ulawTable, samplesToConvert, 2, 2); |
} |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static void GetCompressorInfo(CompressionInfoPtr cp) |
{ |
if (cp->recordSize > sizeof(CompressionInfo)) // limit amount we return |
cp->recordSize = sizeof(CompressionInfo); |
cp->compressionID = fixedCompression; |
cp->format = kOutputFormat; |
cp->samplesPerPacket = kULawBlockSamples; |
cp->bytesPerPacket = kULawBlockBytes; |
cp->bytesPerSample = kULawBytesPerSample; |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static void CompressULaw(SInt16 *inPtr, Byte *outPtr, Byte *ulawTable, long sampleCount, |
short numChannels, short whichChannel) |
{ |
long sampnum; |
int sample, sign, exponent, mantissa; |
unsigned char ulawbyte; |
whichChannel -= 1; |
inPtr += whichChannel; /* skip to first sample */ |
outPtr += whichChannel; |
for (sampnum = 0; sampnum < sampleCount; sampnum++) |
{ |
sample = *inPtr; |
inPtr += numChannels; /* skip to next sample */ |
/* Get the sample into sign-magnitude. */ |
sign = (sample >> 8) & 0x80; /* set aside the sign */ |
if (sign != 0) |
sample = -sample; /* get magnitude */ |
if (sample > CLIP) |
sample = CLIP; /* clip the magnitude */ |
/* Convert from 16 bit linear to ulaw. */ |
sample = sample + BIAS; |
exponent = ulawTable[(sample >> 7) & 0xFF]; |
mantissa = (sample >> (exponent + 3)) & 0x0F; |
ulawbyte = ~(sign | (exponent << 4) | mantissa); |
#ifdef ZEROTRAP |
if (ulawbyte == 0) |
ulawbyte = 0x02; /* optional CCITT trap */ |
#endif |
*outPtr = ulawbyte; /* output compressed sample */ |
outPtr += numChannels; |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14