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 *) &params->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
}