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.
ComponentDispatch.c
/* |
File: ComponentDispatch.c |
Contains: Common routines for dispatching for any sound component |
Written by: Mark Cookson |
Copyright: Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
8/13/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
#include "ComponentDispatch.h" |
#include <Gestalt.h> |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Sound Component Entry Point |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
#if GENERATINGPOWERPC |
ProcInfoType __procinfo=uppSoundComponentEntryPointProcInfo; |
#endif |
pascal ComponentResult main(ComponentParameters *params, SoundComponentGlobalsPtr globals) |
{ |
ComponentResult result; |
short selector = params->what; |
if (selector < 0) |
switch (selector - kComponentRegisterSelect) // standard component selectors |
{ |
case kComponentRegisterSelect - kComponentRegisterSelect: |
result = CallComponentFunctionWithStorageUniv((Handle) globals, params, __SoundComponentRegister); |
break; |
case kComponentVersionSelect - kComponentRegisterSelect: |
return (kSoundComponentVersion); |
break; |
case kComponentCanDoSelect - kComponentRegisterSelect: |
result = __SoundComponentCanDo(0, *((short *) ¶ms->params[0])); |
break; |
case kComponentCloseSelect - kComponentRegisterSelect: |
result = CallComponentFunctionWithStorageUniv((Handle) globals, params, __SoundComponentClose); |
break; |
case kComponentOpenSelect - kComponentRegisterSelect: |
result = CallComponentFunctionWithStorageUniv((Handle) globals, params, __SoundComponentOpen); |
break; |
default: |
result = badComponentSelector; |
break; |
} |
else if (selector < kDelegatedSoundComponentSelectors) // selectors that cannot be delegated |
switch (selector) |
{ |
case kSoundComponentSetSourceSelect: |
result = CallComponentFunctionWithStorageUniv((Handle) globals, params, __SoundComponentSetSource); |
break; |
case kSoundComponentGetSourceDataSelect: |
result = CallComponentFunctionWithStorageUniv((Handle) globals, params, __SoundComponentGetSourceData); |
break; |
case kSoundComponentSetOutputSelect: |
result = CallComponentFunctionWithStorageUniv((Handle) globals, params, __SoundComponentSetOutput); |
break; |
default: |
result = badComponentSelector; |
break; |
} |
else // selectors that can be delegated |
switch (selector) |
{ |
case kSoundComponentGetInfoSelect: |
result = CallComponentFunctionWithStorageUniv((Handle) globals, params, __SoundComponentGetInfo); |
break; |
case kSoundComponentStopSourceSelect: |
result = CallComponentFunctionWithStorageUniv((Handle) globals, params, __SoundComponentStopSource); |
break; |
case kSoundComponentPlaySourceBufferSelect: |
result = CallComponentFunctionWithStorageUniv((Handle) globals, params, __SoundComponentPlaySourceBuffer); |
break; |
default: |
result = DelegateComponentCall(params, globals->sourceComponent); |
break; |
} |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
static pascal ComponentResult __SoundComponentCanDo(void *unused1, short selector) |
{ |
#pragma unused (unused1) |
ComponentResult result; |
switch (selector) |
{ |
case kComponentRegisterSelect: |
case kComponentVersionSelect: |
case kComponentCanDoSelect: |
case kComponentCloseSelect: |
case kComponentOpenSelect: |
case kSoundComponentSetSourceSelect: |
case kSoundComponentGetSourceSelect: |
case kSoundComponentGetSourceDataSelect: |
case kSoundComponentSetOutputSelect: |
// selectors that can be delegated |
case kSoundComponentGetInfoSelect: |
case kSoundComponentStopSourceSelect: |
case kSoundComponentPlaySourceBufferSelect: |
result = true; |
break; |
default: |
result = false; |
break; |
} |
return (result); |
} |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Component Manager Methods |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
/* ============================================================================== |
Component Open |
This routine is called when the Component Manager creates an instance of this |
component. The routine should allocate global variables in the appropriate heap |
and call SetComponentInstanceStorage() so the Component Manager can remember |
the globals and pass them to all the method calls. |
Determining the heap to use can be tricky. The Component Manager will normally |
load the component code into the system heap, which is good, since many applications |
will be sharing this component to play sound. In this case, the components's global |
variable storage should also be created in the system heap. |
However, if system heap memory is tight, the Component Manager will load |
the component into the application heap of the first application that plays sound. |
When this happens, the component should create global storage in the application heap |
instead. The Sound Manager will make sure that other applications will not try |
to play sound while the component is in this application heap. |
To determine the proper heap to use, call GetComponentInstanceA5(). If the value |
returned is 0, then the component was loaded into the system heap, and all storage |
should be allocated there. If the value returned is non-zero, the component is in |
the application heap specifed by returned A5 value, and all storage should be |
allocated in this application heap. |
NOTE: If the component is loaded into the application heap, the value returned by |
GetComponentRefCon() will be 0. |
NOTE: Do not attempt to initialize in this call, since the Component Manager will |
call Open() BEFORE calling Register(). |
NOTE: This routine is never called at interrupt time. |
============================================================================== */ |
pascal ComponentResult __SoundComponentOpen(void *unused1, ComponentInstance self) |
{ |
#pragma unused (unused1) |
Handle h; |
SoundComponentGlobalsPtr globals; |
h = NewHandleClear(sizeof(SoundComponentGlobals)); // get space for globals |
if (h == nil) |
return(MemError()); |
HLock(h); |
globals = (SoundComponentGlobalsPtr) *h; |
SetComponentInstanceStorage (self, (Handle) globals); // save pointer to our globals |
globals->globalsHandle = h; // remember the handle |
globals->thisComponent.format = kOutputSampleFormat; // output sample format |
globals->thisComponent.sampleSize = kOutputSampleSize; // output sample size |
globals->outputSamples = kMaxOutputSamples; // size of our output buffer |
return (noErr); |
} |
/* ============================================================================== |
Component Close |
This routine is called when the Component Manager is closing the instance of |
this component. It should delete all global storage and close any other components |
that were opened. |
NOTE: Be sure to check that the globals pointer passed in to this routine is |
not set to NIL. If the Open() routine fails for any reason, the Component |
Manager will call this routine passing in a NIL for the globals. |
NOTE: This routine is never called at interrupt time. |
============================================================================== */ |
pascal ComponentResult __SoundComponentClose(SoundComponentGlobalsPtr globals, ComponentInstance self) |
{ |
#pragma unused (self) |
if (globals) // we have some globals |
{ |
if (globals->sourceComponent) // we have a source component |
CloseComponent(globals->sourceComponent); // close it |
globals->thisComponent.sampleCount = 0; // nothing in our buffer now |
DisposeHandle(globals->globalsHandle); // dispose our storage |
} |
return (noErr); |
} |
/* ============================================================================== |
Component Register |
This routine is called once, usually at boot time, when the Component Manager |
is first registering this sound component. This routine should check to see if the proper |
Sound Manager is installed and return 0 if it is. If the right Sound Manager is not |
installed, the routine should return 1 and this component will not be registered. |
NOTE: The cmpWantsRegisterMessage bit must be set in the component flags of the |
sound component in order for this routine to be called. |
NOTE: This routine is never called at interrupt time. |
============================================================================== */ |
pascal ComponentResult __SoundComponentRegister(SoundComponentGlobalsPtr globals) |
{ |
#pragma unused (globals) |
long result; |
NumVersion version; |
if ((Gestalt(gestaltSoundAttr, &result) == noErr) && // snd gestalt is available |
(result & (1L << gestaltSoundIOMgrPresent))) // snd dispatcher is available |
{ |
version = SndSoundManagerVersion(); // get the Sound Manager version |
if (version.majorRev >= kRequiredSndMgrMajorRev) // it's what we need |
{ |
return (0); // install this compression component |
} |
} |
return (1); // do not install component |
} |
/* ============================================================================== |
GetInfo |
This routine returns information about this output component to the Sound Manager. |
A 4-byte OSType selector is used to determine the type and size of the information |
to return. If the component does not support a selector, it should delegate this |
call on up the chain. |
NOTE: This can be called at interrupt time. However, selectors that return |
a handle will not be called at interrupt time. |
============================================================================== */ |
pascal ComponentResult __SoundComponentGetInfo(SoundComponentGlobalsPtr globals, SoundSource sourceID, |
OSType selector, void *infoPtr) |
{ |
ComponentResult result = noErr; |
switch (selector) |
{ |
case siCompressionFactor: |
GetCompressorInfo(infoPtr); // fill out the CompressionInfo structure passed in |
break; |
default: |
result = SoundComponentGetInfo(globals->sourceComponent, sourceID, selector, infoPtr); |
break; |
} |
return (result); |
} |
/* ============================================================================== |
StopSource |
This routine is used to stop sounds that are currently playing. It should |
clear out any internal buffers, reset any compression state information |
and then delegate the call up the chain. |
NOTE: This can be called at interrupt time. |
============================================================================== */ |
pascal ComponentResult __SoundComponentStopSource(SoundComponentGlobalsPtr globals, short count, SoundSource *sources) |
{ |
globals->sourceDataPtr = nil; // clear out internal buffers |
globals->thisComponent.sampleCount = 0; // our buffer is empty |
#ifdef COMPRESSION |
InitializeCompressor(globals); // initialize our compressor state |
#else |
InitializeDecompressor(globals); // initialize our compressor state |
#endif |
return (SoundComponentStopSource(globals->sourceComponent, count, sources)); // delegate this call |
} |
/* ============================================================================== |
PlaySourceBuffer |
This routine is used to start a new sound playing. It should clear out any internal buffers |
but should NOT reset any compression state information, since this could be a |
continuation of a sound that has been broken into pieces. Then the call should be |
delegated up the chain. |
NOTE: This can be called at interrupt time. |
============================================================================== */ |
pascal ComponentResult __SoundComponentPlaySourceBuffer(SoundComponentGlobalsPtr globals, SoundSource sourceID, SoundParamBlockPtr pb, long actions) |
{ |
globals->sourceDataPtr = nil; // clear out internal buffers |
globals->thisComponent.sampleCount = 0; // our buffer is empty |
return (SoundComponentPlaySourceBuffer(globals->sourceComponent, sourceID, pb, actions)); // delegate this call |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-03-14