Application Files/WiredSpriteUtilities.c

//////////
//
//  File:       WiredSpriteUtilities.c
//
//  Contains:   Utilities for creating wired sprite media.
//
//  Written by: Sean Allen
//  Revised by: Chris Flick and Tim Monroe
//
//  Copyright:  © 1998 by Apple Computer, Inc., all rights reserved.
//
//  Change History (most recent first):
//     <4>      02/21/03    era     kActionTrackSetClip takes a *RgnHandle as its parameter, not a RgnHandle (radar #3115855)
//     <3>      03/29/98    rtm     added Endian macros to flags parameter in AddActionParameterOptions
//     <2>      03/??/98    cf      added Endian macros
//     <1>      12/??/97    sa      first file
//
//  NOTES:
//
//  ***(1)***
//  You need to pay attention to the endian-ness of the data you pass to these routines. Wired sprite
//  media data is stored in QuickTime atoms and atom containers and must therefore be big-endian. We've
//  tried to conform to this rule: if the data to be written to a wired sprite media is 4 bytes or less,
//  then we will perform the endian swap for you. There are several exceptions to this rule; for instance,
//  we swap the data in any matrices you pass to the AddSpriteSetMatrixAction function. But we do not swap
//  the data in any matrices passed to AddActionParameterOptions (since we don't know that they are matrices!).
//  Let the caller beware!
//
//////////
 
#ifndef _WIREDSPRITEUTILITIES_
#include "WiredSpriteUtilities.h"
#endif
 
#ifndef __ENDIANUTILITIES__
#include "EndianUtilities.h"
#endif
 
/*
 
These atoms are at same level as sprite property atoms
 
[(SpriteActionAtoms)] = 
    kQTEventType, theQTEventType, (1 .. numEventTypes)
            [(ActionListAtoms)]
 
This atom is at same level as kSpriteAtomType atoms
 
<kQTEventFrameLoaded>, 1, 1
    [(ActionListAtoms)]
        
[(ActionListAtoms)] = 
    kAction, (anyUniqueIDs), (1..numActions)
        kWhichAction    1, 1
            [long whichActionConstant]
        <kActionParameter>  (anyUniqueIDs), (1..numParameters)
            [parameter data depending on actionConstant and paramIndex]
        <kActionFlags>  parameterID,  (1..numParamsWithFlags)
            [long actionFlags]
        <kActionParameterMinValue>  parameterID,  (1.. numParamsWithMin)
            [data depends on param type]
        <kActionParameterMaxValue>  parameterID,  (1.. numParamsWithMax)
            [data depends on param type]
        [(ActionTargetAtoms)]
 
[(ActionTargetAtoms)] =
    <kActionTarget>
        <kTargetMovie>
            [no data]
        <kTargetTrackName>
            [PString trackName]
        <kTargetTrackType>
            [OSType trackType]
        <kTargetTrackIndex>
            [long trackIndex]
            OR
            [(kExpressionAtoms)]
        <kTargetTrackID>
            [long trackID]
            OR
            [(kExpressionAtoms)]
        <kTargetSpriteName>
            [PString spriteName]
        <kTargetSpriteIndex>
            [short spriteIndex]
            OR
            [(kExpressionAtoms)]
        <kTargetSpriteID>
            [QTAtomID spriteIID]
            OR
            [(kExpressionAtoms)]
 
 
Both [(CaseStatementActionAtoms)] and [(WhileStatementActionAtoms)]
are child atoms of a kActionParameter 1, 1 atom
 
[(CaseStatementActionAtoms)] =
    kConditionalAtomType, (anyUniqueIDs), (1..numCases)
        [(kExpressionAtoms)]
        kActionListAtomType 1, 1
            [(ActionListAtoms)]         // may contain nested conditional actions
    
[(WhileStatementActionAtoms)] =
    kConditionalAtomType, 1, 1
        [(kExpressionAtoms)]
        kActionListAtomType 1, 1
            [(ActionListAtoms)]             // may contain nested conditional actions
 
[(kExpressionAtoms)] =
    kExpressionContainerAtomType, 1, 1
        <kOperatorAtomType, theOperatorType, 1>
            kOperandAtomType, (anyUniqueIDs), (1..numOperands)
                [(OperandAtoms)]
        OR
        <kOperandAtomType, 1, 1>
            [(OperandAtoms)]
 
[(OperandAtoms)] = 
    <kExpressionOperandAtomType> 1, 1
        [(kExpressionAtoms)]                    // allows for recursion
    OR
    <kConstantOperandAtomType> 1, 1
        [ float theConstant ]
    OR
    <kSpriteVariableOperandAtomType> 1, 1
        [(ActionTargetAtoms)]
        kActionParameter, 1, 1
            [QTAtomID spriteVariableID]
    OR
    <kOperandKeyIsDown> 1, 1
        [(ActionTargetAtoms)]
        kActionParameter, 1, 1
            [UInt16 modifierKeys]
        kActionParameter, 2, 2
            [UInt8 asciiCharCode]
    OR      
    <any other operand atom type>
        [(ActionTargetAtoms)]
*/
 
// exception handling macros
 
#define     FailIf(a, e)        {if (a)     { err = e; goto bail; }}
#define     FailOSErr(a)        {if (err = a)   goto bail;}
#define     FailMemErr(a)       {a; if (err = MemError()) goto bail;}
 
// for the kQTEventFrameLoaded event, the actionAtoms atom should be a sibling of a kSpriteAtomType
 
OSErr AddQTEventAtom( QTAtomContainer container, QTAtom actionAtoms, QTAtomID theQTEventType, QTAtom *newQTEventAtom )
{
    OSErr   err = noErr;
    
    if ( (! container) || (theQTEventType == 0) || (newQTEventAtom == nil) )    { err = paramErr; goto bail; }
    
    if ( theQTEventType == kQTEventFrameLoaded ) {
        FailOSErr( QTInsertChild( container, actionAtoms, kQTEventFrameLoaded, 1, 1, 0, nil, newQTEventAtom ) );
    }
    else {
        *newQTEventAtom =  QTFindChildByID( container, actionAtoms, kQTEventType, theQTEventType, nil );
        if ( ! *newQTEventAtom ) {
            FailOSErr( QTInsertChild( container, actionAtoms, kQTEventType, theQTEventType, 1, 0, nil, newQTEventAtom ) );
        }
    }
    
bail:
    return err;
}
 
OSErr AddActionAtom( QTAtomContainer container, QTAtom eventAtom, long whichActionConstant, QTAtom *newActionAtom )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    if ( (! container) || (whichActionConstant == 0) )  { return paramErr; }
    
    FailOSErr( QTInsertChild( container, eventAtom, kAction, 0, 0, 0, nil, &actionAtom ) );
 
    whichActionConstant = EndianU32_NtoB(whichActionConstant);
    FailOSErr( QTInsertChild( container, actionAtom, kWhichAction, 1, 1, sizeof(whichActionConstant), &whichActionConstant, nil ) );
    
bail:
    if ( newActionAtom ) {
        if ( err )  
            *newActionAtom = 0;
        else
            *newActionAtom = actionAtom;
    }
    return err;
}
 
OSErr AddActionParameterAtom( QTAtomContainer container, QTAtom actionAtom, long parameterIndex, long paramDataSize, void *paramData, QTAtom *newParamAtom )
{
    return QTInsertChild( container, actionAtom, kActionParameter, 0, (short)parameterIndex, paramDataSize, paramData, newParamAtom );
}
 
OSErr AddActionParameterOptions( QTAtomContainer container, QTAtom actionAtom, QTAtomID paramID, long flags, long minValueSize,
                            void *minValue, long maxValueSize, void *maxValue )
{
    OSErr   err = noErr;
 
    flags = EndianU32_NtoB(flags);
    FailOSErr( QTInsertChild( container, actionAtom, kActionFlags, paramID, 0, sizeof(flags), &flags, nil ) );
    if ( minValue ) {
        FailOSErr( QTInsertChild( container, actionAtom, kActionParameterMinValue, paramID, 0, minValueSize, minValue, nil ) );
    }
    if ( maxValue ) {
        FailOSErr( QTInsertChild( container, actionAtom, kActionParameterMaxValue, paramID, 0, maxValueSize, maxValue, nil ) );
    }
 
bail:
    return err;
}
 
OSErr AddTrackNameActionTargetAtom( QTAtomContainer container, QTAtom actionAtom, Str255 trackName, QTAtom *newTargetAtom )
{
    OSErr   err = noErr;
    QTAtom  targetAtom;
    
    if ( newTargetAtom )    *newTargetAtom = 0;
    
    if ( ! (targetAtom = QTFindChildByIndex( container, actionAtom, kActionTarget, 1, nil )) )
        FailOSErr( QTInsertChild( container, actionAtom, kActionTarget, 1, 1, 0, nil, &targetAtom ) );
    FailOSErr( QTInsertChild( container, targetAtom, kTargetTrackName, 1, 1, trackName[0] + 1, trackName, nil ) );
 
bail:
    if ( newTargetAtom )    *newTargetAtom = targetAtom;
    return err;
}
 
OSErr AddTrackIDActionTargetAtom( QTAtomContainer container, QTAtom actionAtom, long trackID, QTAtom *newTargetAtom )
{
    OSErr   err = noErr;
    QTAtom  targetAtom;
    
    if ( newTargetAtom )    *newTargetAtom = 0;
    
    if ( ! (targetAtom = QTFindChildByIndex( container, actionAtom, kActionTarget, 1, nil )) )
        FailOSErr( QTInsertChild( container, actionAtom, kActionTarget, 1, 1, 0, nil, &targetAtom ) );
        
    trackID = EndianU32_NtoB(trackID);
    FailOSErr( QTInsertChild( container, targetAtom, kTargetTrackID, 1, 1, sizeof(trackID), &trackID, nil ) );
 
bail:
    if ( newTargetAtom )    *newTargetAtom = targetAtom;
    return err;
}
 
OSErr AddTrackTypeActionTargetAtom( QTAtomContainer container, QTAtom actionAtom, OSType trackType, QTAtom *newTargetAtom )
{
    OSErr   err = noErr;
    QTAtom  targetAtom;
    
    if ( newTargetAtom )    *newTargetAtom = 0;
    
    if ( ! (targetAtom = QTFindChildByIndex( container, actionAtom, kActionTarget, 1, nil )) )
        FailOSErr( QTInsertChild( container, actionAtom, kActionTarget, 1, 1, 0, nil, &targetAtom ) );
        
    trackType = EndianU32_NtoB(trackType);
    FailOSErr( QTInsertChild( container, targetAtom, kTargetTrackType, 1, 1, sizeof(trackType), &trackType, nil ) );
 
bail:
    if ( newTargetAtom )    *newTargetAtom = targetAtom;
    return err;
}
 
OSErr AddTrackIndexActionTargetAtom( QTAtomContainer container, QTAtom actionAtom, long trackIndex, QTAtom *newTargetAtom )
{
    OSErr   err = noErr;
    QTAtom  targetAtom;
    
    if ( newTargetAtom )    *newTargetAtom = 0;
    
    if ( ! (targetAtom = QTFindChildByIndex( container, actionAtom, kActionTarget, 1, nil )) )
        FailOSErr( QTInsertChild( container, actionAtom, kActionTarget, 1, 1, 0, nil, &targetAtom ) );
 
    trackIndex = EndianU32_NtoB(trackIndex);
    FailOSErr( QTInsertChild( container, targetAtom, kTargetTrackIndex, 1, 1, sizeof(trackIndex), &trackIndex, nil ) );
 
bail:
    if ( newTargetAtom )    *newTargetAtom = targetAtom;
    return err;
}
 
OSErr AddSpriteNameActionTargetAtom( QTAtomContainer container, QTAtom actionAtom, Str255 spriteName, QTAtom *newTargetAtom )
{
    OSErr   err = noErr;
    QTAtom  targetAtom;
    
    if ( newTargetAtom )    *newTargetAtom = 0;
    
    if ( ! (targetAtom = QTFindChildByIndex( container, actionAtom, kActionTarget, 1, nil )) )
        FailOSErr( QTInsertChild( container, actionAtom, kActionTarget, 1, 1, 0, nil, &targetAtom ) );
    FailOSErr( QTInsertChild( container, targetAtom, kTargetSpriteName, 1, 1, spriteName[0] + 1, spriteName, nil ) );
 
bail:
    if ( newTargetAtom )    *newTargetAtom = targetAtom;
    return err;
}
 
OSErr AddSpriteIDActionTargetAtom( QTAtomContainer container, QTAtom actionAtom, QTAtomID spriteID, QTAtom *newTargetAtom )
{
    OSErr   err = noErr;
    QTAtom  targetAtom;
    
    if ( newTargetAtom )    *newTargetAtom = 0;
    
    if ( ! (targetAtom = QTFindChildByIndex( container, actionAtom, kActionTarget, 1, nil )) )
        FailOSErr( QTInsertChild( container, actionAtom, kActionTarget, 1, 1, 0, nil, &targetAtom ) );
 
    spriteID = EndianU32_NtoB(spriteID);
    FailOSErr( QTInsertChild( container, targetAtom, kTargetSpriteID, 1, 1, sizeof(spriteID), &spriteID, nil ) );
 
bail:
    if ( newTargetAtom )    *newTargetAtom = targetAtom;
    return err;
}
 
OSErr AddSpriteIndexActionTargetAtom( QTAtomContainer container, QTAtom actionAtom, short spriteIndex, QTAtom *newTargetAtom )
{
    OSErr   err = noErr;
    QTAtom  targetAtom;
    
    if ( newTargetAtom )    *newTargetAtom = 0;
    
    if ( ! (targetAtom = QTFindChildByIndex( container, actionAtom, kActionTarget, 1, nil )) )
        FailOSErr( QTInsertChild( container, actionAtom, kActionTarget, 1, 1, 0, nil, &targetAtom ) );
 
    spriteIndex = EndianU16_NtoB(spriteIndex);
    FailOSErr( QTInsertChild( container, targetAtom, kTargetSpriteIndex, 1, 1, sizeof(spriteIndex), &spriteIndex, nil ) );
 
bail:
    if ( newTargetAtom )    *newTargetAtom = targetAtom;
    return err;
}
 
 
//______ High level WiredSprite Utilities _____
 
 
OSErr AddQTEventAndActionAtoms( QTAtomContainer container, QTAtom atom, long whichEvent, long whichAction, QTAtom *actionAtom )
{
    OSErr   err = noErr;
    QTAtom  eventAtom;
    
    eventAtom = atom;
    
    if ( whichEvent != 0 )
        FailOSErr( AddQTEventAtom( container, atom, whichEvent, &eventAtom ) );
    
    FailOSErr( AddActionAtom( container, eventAtom, whichAction, actionAtom ) );
 
bail:
    return err;
}
 
// trackTypeIndex only used if trackTargetType is kTargetTrackType, can be zero for default index of 1
OSErr AddTrackTargetAtom( QTAtomContainer container, QTAtom actionAtom, long trackTargetType, void *trackTarget, long trackTypeIndex )
{
    OSErr   err = noErr;
    
    // allow zero for default target, the sprite track which received the event
    if ( trackTargetType ) {
        switch ( trackTargetType ) {
            case kTargetTrackName: {
                    StringPtr trackName = trackTarget;
                    FailOSErr( AddTrackNameActionTargetAtom( container, actionAtom, trackName, nil ) );
                }
                break;
                
            case kTargetTrackID: {
                    long trackID = (long)trackTarget;
                    FailOSErr( AddTrackIDActionTargetAtom( container, actionAtom, trackID, nil ) );
                }
                break;
 
            case kTargetTrackType: {
                    OSType trackType = (long)trackTarget;
                    FailOSErr( AddTrackTypeActionTargetAtom( container, actionAtom, trackType, nil ) );
                    if ( trackTypeIndex )
                        FailOSErr( AddTrackIndexActionTargetAtom( container, actionAtom, trackTypeIndex, nil ) );
                }
                break;
                        
            case kTargetTrackIndex: {
                    long trackIndex = (long)trackTarget;
                    FailOSErr( AddTrackIndexActionTargetAtom( container, actionAtom, trackIndex, nil ) );
                }
                break;
                        
            default:
                err = paramErr; 
        }
    }
    
bail:
    return err;
}
 
OSErr AddSpriteTargetAtom( QTAtomContainer container, QTAtom actionAtom, long spriteTargetType, void *spriteTarget )
{
    OSErr   err = noErr;
    
    // allow zero for default target, the sprite which received the event
    if ( spriteTargetType ) {
        switch ( spriteTargetType ) {
            case kTargetSpriteName: {
                    StringPtr spriteName = spriteTarget;
                    FailOSErr( AddSpriteNameActionTargetAtom( container, actionAtom, spriteName, nil ) );
                }
                break;
                
            case kTargetSpriteID: {
                    QTAtomID spriteID = (QTAtomID)spriteTarget;
                    FailOSErr( AddSpriteIDActionTargetAtom( container, actionAtom, spriteID, nil ) );
                }
                break;
 
            case kTargetSpriteIndex: {
                    short spriteIndex = (short)spriteTarget;
                    FailOSErr( AddSpriteIndexActionTargetAtom( container, actionAtom, spriteIndex, nil ) );
                }
                break;
                        
            default:
                err = paramErr; 
        }
    }
bail:
    return err;
}
 
OSErr AddTrackAndSpriteTargetAtoms( QTAtomContainer container, QTAtom actionAtom, long trackTargetType, void *trackTarget, long trackTypeIndex, 
                                    long spriteTargetType, void *spriteTarget )
{
    OSErr   err = noErr;
    
    FailOSErr( AddTrackTargetAtom( container, actionAtom, trackTargetType, trackTarget, trackTypeIndex ) );
    
    FailOSErr( AddSpriteTargetAtom( container, actionAtom, spriteTargetType, spriteTarget ) );
    
bail:
    return err;
}
 
OSErr AddMovieSetVolumeAction( QTAtomContainer container, QTAtom atom, long whichEvent, short volume )
{   
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMovieSetVolume, &actionAtom ) );
 
    volume = EndianS16_NtoB(volume);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(volume), &volume, nil ) );
 
    // the movie is the default target for movie actions
    
bail:
    return err;
}
 
OSErr AddMovieSetRateAction( QTAtomContainer container, QTAtom atom, long whichEvent, Fixed rate )
{   
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMovieSetRate, &actionAtom ) );
 
    rate = EndianS32_NtoB(rate);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(rate), &rate, nil ) );
 
    // the movie is the default target for movie actions
    
bail:
    return err;
}
 
OSErr AddMovieSetLoopingFlagsAction( QTAtomContainer container, QTAtom atom, long whichEvent, long loopingFlags )
{   
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMovieSetLoopingFlags, &actionAtom ) );
 
    loopingFlags = EndianU32_NtoB(loopingFlags);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(loopingFlags), &loopingFlags, nil ) );
 
    // the movie is the default target for movie actions
    
bail:
    return err;
}
 
OSErr AddMovieGoToTimeAction( QTAtomContainer container, QTAtom atom, long whichEvent, TimeValue time )
{   
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMovieGoToTime, &actionAtom ) );
 
    time = EndianS32_NtoB(time);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(time), &time, nil ) );
 
    // the movie is the default target for movie actions
    
bail:
    return err;
}
 
OSErr AddMovieGoToTimeByNameAction( QTAtomContainer container, QTAtom atom, long whichEvent, Str255 timeName )
{   
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMovieGoToTimeByName, &actionAtom ) );
 
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, timeName[0] + 1, timeName, nil ) );
 
    // the movie is the default target for movie actions
    
bail:
    return err;
}
 
OSErr AddMovieGoToBeginningAction( QTAtomContainer container, QTAtom atom, long whichEvent )
{   
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMovieGoToBeginning, &actionAtom ) );
 
    // the movie is the default target for movie actions
    
bail:
    return err;
}
 
OSErr AddMovieGoToEndAction( QTAtomContainer container, QTAtom atom, long whichEvent )
{   
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMovieGoToEnd, &actionAtom ) );
 
    // the movie is the default target for movie actions
    
bail:
    return err;
}
 
OSErr AddMovieStepForwardAction( QTAtomContainer container, QTAtom atom, long whichEvent )
{   
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMovieStepForward, &actionAtom ) );
 
    // the movie is the default target for movie actions
    
bail:
    return err;
}
 
OSErr AddMovieStepBackwardAction( QTAtomContainer container, QTAtom atom, long whichEvent )
{   
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMovieStepBackward, &actionAtom ) );
 
    // the movie is the default target for movie actions
    
bail:
    return err;
}
 
OSErr AddMovieSetSelectionAction( QTAtomContainer container, QTAtom atom, long whichEvent, TimeValue startTime, TimeValue endTime )
{   
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMovieSetSelection, &actionAtom ) );
 
    startTime = EndianS32_NtoB(startTime);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(startTime), &startTime, nil ) );
 
    endTime = EndianS32_NtoB(endTime);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kSecondParam, sizeof(endTime), &endTime, nil ) );
 
    // the movie is the default target for movie actions
    
bail:
    return err;
}
 
OSErr AddMovieSetSelectionByNameAction( QTAtomContainer container, QTAtom atom, long whichEvent, Str255 startTimeName, Str255 endTimeName )
{   
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMovieSetSelectionByName, &actionAtom ) );
 
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, startTimeName[0] + 1, startTimeName, nil ) );
 
    FailOSErr( AddActionParameterAtom( container, actionAtom, kSecondParam, endTimeName[0] + 1, endTimeName, nil ) );
 
    // the movie is the default target for movie actions
    
bail:
    return err;
}
 
OSErr AddMoviePlaySelectionAction( QTAtomContainer container, QTAtom atom, long whichEvent, Boolean selectionOnly )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMoviePlaySelection, &actionAtom ) );
 
    // Booleans don't need endian flipping
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(selectionOnly), &selectionOnly, nil ) );
 
    // the movie is the default target for movie actions
    
bail:
    return err;
}
 
OSErr AddMovieSetLanguage( QTAtomContainer container, QTAtom atom, long whichEvent, long language )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMovieSetLanguage, &actionAtom ) );
 
    language = EndianS32_NtoB(language);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(language), &language, nil ) );
 
    // the movie is the default target for movie actions
    
bail:
    return err;
}
 
OSErr AddTrackSetVolumeAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                               void *trackTarget, long trackTypeIndex, short volume )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionTrackSetVolume, &actionAtom ) );
 
    volume = EndianS16_NtoB(volume);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(volume), &volume, nil ) );
 
    FailOSErr( AddTrackTargetAtom( container, actionAtom, trackTargetType, trackTarget, trackTypeIndex ) );
    
bail:
    return err;
}
 
OSErr AddTrackSetBalanceAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                                void *trackTarget, long trackTypeIndex, short balance )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionTrackSetBalance, &actionAtom ) );
 
    balance = EndianS16_NtoB(balance);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(balance), &balance, nil ) );
 
    FailOSErr( AddTrackTargetAtom( container, actionAtom, trackTargetType, trackTarget, trackTypeIndex ) );
    
bail:
    return err;
}
 
OSErr AddTrackSetEnabledAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                                void *trackTarget, long trackTypeIndex, Boolean enabled )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionTrackSetEnabled, &actionAtom ) );
 
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(enabled), &enabled, nil ) );
 
    FailOSErr( AddTrackTargetAtom( container, actionAtom, trackTargetType, trackTarget, trackTypeIndex ) );
    
bail:
    return err;
}
 
OSErr AddTrackSetMatrixAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                               void *trackTarget, long trackTypeIndex, MatrixRecordPtr matrix, QTAtom *actionAtom )
{
    OSErr           err = noErr;
    QTAtom          theActionAtom = 0;
    MatrixRecord    bigEndianMatrix;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionTrackSetMatrix, &theActionAtom ) );
 
    bigEndianMatrix = *matrix;
    EndianUtils_MatrixRecord_NtoB( &bigEndianMatrix );
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFirstParam, sizeof(MatrixRecord), &bigEndianMatrix, nil ) );
 
    FailOSErr( AddTrackTargetAtom( container, theActionAtom, trackTargetType, trackTarget, trackTypeIndex ) );
    
    if ( actionAtom )
        *actionAtom = theActionAtom;
bail:
    return err;
}
 
OSErr AddTrackSetLayerAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                              void *trackTarget, long trackTypeIndex, short layer )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionTrackSetLayer, &actionAtom ) );
 
    layer = EndianS16_NtoB(layer);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(layer), &layer, nil ) );
 
    FailOSErr( AddTrackTargetAtom( container, actionAtom, trackTargetType, trackTarget, trackTypeIndex ) );
    
bail:
    return err;
}
 
OSErr AddTrackSetClipAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                             void *trackTarget, long trackTypeIndex, RgnHandle clip )
{
    OSErr           err = noErr;
    QTAtom          actionAtom;
#if TARGET_RT_LITTLE_ENDIAN
    RgnHandle       bigEndianClip = nil;
#else
    SignedByte      saveState;
#endif
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionTrackSetClip, &actionAtom ) );
 
    // clip is native-endian but it needs to be big endian to be stored in the data atom container.
    // We need a routine to flip it.
 
#if TARGET_RT_LITTLE_ENDIAN
    // For little endian platforms, we copy the clip into a temporary region handle and then flip that region
    bigEndianClip = (RgnHandle)NewHandle(0);
    if( err = MemError() ) goto bail;
    
    err = HandAndHand( (Handle)clip, (Handle)bigEndianClip );
    if( err ) goto bail;
    
    EndianUtils_RgnHandle_NtoB( bigEndianClip );
 
    HLockHi((Handle) bigEndianClip );   // Lock the handle down so that it doesn't move during addition to container QTAtomContainer. We
                                        // don't unlock since we dispose of it at bottom of this function.
 
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, GetHandleSize((Handle)bigEndianClip), *bigEndianClip, nil ) );
#else
    // For big endian platforms, just add the clip
    
    // Lock the handle down so that it doesn't move during addition to container QTAtomContainer. Save state so that we
    // can restore its "lockedness" when we're done.
    saveState = HGetState((Handle) clip );
    HLockHi((Handle) clip );
    
        FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, GetHandleSize((Handle)clip), *(Handle)clip, nil ) );
    
    HSetState((Handle) clip, saveState );   // Restore handle's "lockedness"
#endif
 
    FailOSErr( AddTrackTargetAtom( container, actionAtom, trackTargetType, trackTarget, trackTypeIndex ) );
    
bail:
 
#if TARGET_RT_LITTLE_ENDIAN
    if( bigEndianClip ) DisposeRgn( bigEndianClip );
#endif
    
    return err;
}
 
OSErr AddSpriteSetMatrixAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType,
                                void *trackTarget, long trackTypeIndex, long spriteTargetType, void *spriteTarget, 
                                MatrixRecordPtr matrix, QTAtom *actionAtom )
{
    OSErr           err = noErr;
    QTAtom          theActionAtom;
    MatrixRecord    bigEndianMatrix;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionSpriteSetMatrix, &theActionAtom ) );
 
    bigEndianMatrix = *matrix;
    EndianUtils_MatrixRecord_NtoB( &bigEndianMatrix );
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFirstParam, sizeof(MatrixRecord), &bigEndianMatrix, nil ) );
 
    FailOSErr( AddTrackAndSpriteTargetAtoms( container, theActionAtom, trackTargetType, trackTarget, trackTypeIndex, 
                                             spriteTargetType, spriteTarget ) );
    if ( actionAtom )
        *actionAtom = theActionAtom;
                                             
bail:
    return err;
}
 
OSErr AddSpriteSetImageIndexAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType,
                                    void *trackTarget, long trackTypeIndex, long spriteTargetType, void *spriteTarget, 
                                    short setImageIndex, QTAtom *actionAtom )
{
    OSErr   err = noErr;
    QTAtom  theActionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionSpriteSetImageIndex, &theActionAtom ) );
 
    setImageIndex = EndianS16_NtoB(setImageIndex);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFirstParam, sizeof(setImageIndex), &setImageIndex, nil ) );
 
    FailOSErr( AddTrackAndSpriteTargetAtoms( container, theActionAtom, trackTargetType, trackTarget, trackTypeIndex, 
                                             spriteTargetType, spriteTarget ) );
    if ( actionAtom )
        *actionAtom = theActionAtom;
                                             
bail:
    return err;
}
 
OSErr AddSpriteSetVisibleAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                                 void *trackTarget, long trackTypeIndex, long spriteTargetType, void *spriteTarget, 
                                 short visible, QTAtom *actionAtom )
{
    OSErr   err = noErr;
    QTAtom  theActionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionSpriteSetVisible, &theActionAtom ) );
 
    visible = EndianS16_NtoB(visible);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFirstParam, sizeof(visible), &visible, nil ) );
 
    FailOSErr( AddTrackAndSpriteTargetAtoms( container, theActionAtom, trackTargetType, trackTarget, trackTypeIndex, 
                                             spriteTargetType, spriteTarget ) );
    if ( actionAtom )
        *actionAtom = theActionAtom;
                                             
bail:
    return err;
}
 
OSErr AddSpriteSetLayerAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                               void *trackTarget, long trackTypeIndex, long spriteTargetType, void *spriteTarget, 
                               short layer )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionSpriteSetLayer, &actionAtom ) );
 
    layer = EndianS16_NtoB(layer);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(layer), &layer, nil ) );
 
    FailOSErr( AddTrackAndSpriteTargetAtoms( container, actionAtom, trackTargetType, trackTarget, trackTypeIndex, 
                                             spriteTargetType, spriteTarget ) );
 
bail:
    return err;
}
 
OSErr AddSpriteSetGraphicsModeAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                                      void *trackTarget, long trackTypeIndex, long spriteTargetType, void *spriteTarget, 
                                      ModifierTrackGraphicsModeRecord *graphicsMode, QTAtom *actionAtom )
{
    OSErr                               err = noErr;
    QTAtom                              theActionAtom;
    ModifierTrackGraphicsModeRecord     bigEndianGraphicsMode;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionSpriteSetGraphicsMode, &theActionAtom ) );
 
    bigEndianGraphicsMode               = *graphicsMode;
    bigEndianGraphicsMode.graphicsMode  = EndianU32_NtoB(bigEndianGraphicsMode.graphicsMode);
    bigEndianGraphicsMode.opColor.red   = EndianU16_NtoB(bigEndianGraphicsMode.opColor.red);
    bigEndianGraphicsMode.opColor.green = EndianU16_NtoB(bigEndianGraphicsMode.opColor.green);
    bigEndianGraphicsMode.opColor.blue  = EndianU16_NtoB(bigEndianGraphicsMode.opColor.blue);
    
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFirstParam, sizeof(ModifierTrackGraphicsModeRecord), 
                                       &bigEndianGraphicsMode, nil ) );
 
    FailOSErr( AddTrackAndSpriteTargetAtoms( container, theActionAtom, trackTargetType, trackTarget, trackTypeIndex, 
                                             spriteTargetType, spriteTarget ) );
 
    if ( actionAtom )
        *actionAtom = theActionAtom;
bail:
    return err;
}
 
OSErr AddSpriteTranslateAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                                      void *trackTarget, long trackTypeIndex, long spriteTargetType, void *spriteTarget, 
                                      Fixed x, Fixed y, Boolean isRelative, QTAtom *actionAtom )
{
    OSErr   err = noErr;
    QTAtom  theActionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionSpriteTranslate, &theActionAtom ) );
 
    x = EndianS32_NtoB(x);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFirstParam, sizeof(x), &x, nil ) );
 
    y = EndianS32_NtoB(y);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kSecondParam, sizeof(y), &y, nil ) );
 
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kThirdParam, sizeof(isRelative), &isRelative, nil ) );
 
    FailOSErr( AddTrackAndSpriteTargetAtoms( container, theActionAtom, trackTargetType, trackTarget, trackTypeIndex, 
                                             spriteTargetType, spriteTarget ) );
 
    if ( actionAtom )
        *actionAtom = theActionAtom;
bail:
    return err;
}
 
// ¥¥¥¥ÊaboutX and aboutY are no longer parameters!!! Uses registration point now. Also, isRelative is gone.
OSErr AddSpriteScaleAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                            void *trackTarget, long trackTypeIndex, long spriteTargetType, void *spriteTarget, 
                            Fixed xScale, Fixed yScale, Fixed aboutX, Fixed aboutY, Boolean isRelative, QTAtom *actionAtom )
{
    OSErr   err = noErr;
    QTAtom  theActionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionSpriteScale, &theActionAtom ) );
 
    xScale = EndianS32_NtoB(xScale);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFirstParam, sizeof(xScale), &xScale, nil ) );
 
    yScale = EndianS32_NtoB(yScale);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kSecondParam, sizeof(yScale), &yScale, nil ) );
 
    aboutX = EndianS32_NtoB(aboutX);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kThirdParam, sizeof(aboutX), &aboutX, nil ) );
 
    aboutY = EndianS32_NtoB(aboutY);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFourthParam, sizeof(aboutY), &aboutY, nil ) );
 
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFifthParam, sizeof(isRelative), &isRelative, nil ) );
 
    FailOSErr( AddTrackAndSpriteTargetAtoms( container, theActionAtom, trackTargetType, trackTarget, trackTypeIndex, 
                                             spriteTargetType, spriteTarget ) );
 
    if ( actionAtom )
        *actionAtom = theActionAtom;
bail:
    return err;
}
 
 
// ¥¥¥¥ÊaboutX and aboutY are no longer parameters!!! Uses registration point now. Also, isRelative is gone.
 
OSErr AddSpriteRotateAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                            void *trackTarget, long trackTypeIndex, long spriteTargetType, void *spriteTarget, 
                            Fixed degrees, Fixed aboutX, Fixed aboutY, Boolean isRelative, QTAtom *actionAtom )
{
    OSErr   err = noErr;
    QTAtom  theActionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionSpriteRotate, &theActionAtom ) );
 
    degrees = EndianS32_NtoB(degrees);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFirstParam, sizeof(degrees), &degrees, nil ) );
 
    aboutX = EndianS32_NtoB(aboutX);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kSecondParam, sizeof(aboutX), &aboutX, nil ) );
 
    aboutY = EndianS32_NtoB(aboutY);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kThirdParam, sizeof(aboutY), &aboutY, nil ) );
 
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFourthParam, sizeof(isRelative), &isRelative, nil ) );
 
    FailOSErr( AddTrackAndSpriteTargetAtoms( container, theActionAtom, trackTargetType, trackTarget, trackTypeIndex, 
                                             spriteTargetType, spriteTarget ) );
 
    if ( actionAtom )
        *actionAtom = theActionAtom;
bail:
    return err;
}
 
// ¥¥¥¥ isRelative is gone?
 
OSErr AddSpriteStretchAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                            void *trackTarget, long trackTypeIndex, long spriteTargetType, void *spriteTarget, 
                            Fixed p1x, Fixed p1y, Fixed p2x, Fixed p2y, Fixed p3x, Fixed p3y, Fixed p4x, Fixed p4y, 
                            Boolean isRelative, QTAtom *actionAtom )
{
    OSErr   err = noErr;
    QTAtom  theActionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionSpriteStretch, &theActionAtom ) );
 
    p1x = EndianS32_NtoB(p1x);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFirstParam, sizeof(p1x), &p1x, nil ) );
 
    p1y = EndianS32_NtoB(p1y);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kSecondParam, sizeof(p1y), &p1y, nil ) );
 
    p2x = EndianS32_NtoB(p2x);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kThirdParam, sizeof(p2x), &p2x, nil ) );
 
    p2y = EndianS32_NtoB(p2y);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFourthParam, sizeof(p2y), &p2y, nil ) );
 
    p3x = EndianS32_NtoB(p3x);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kFifthParam, sizeof(p3x), &p3x, nil ) );
 
    p3y = EndianS32_NtoB(p3y);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kSixthParam, sizeof(p3y), &p3y, nil ) );
 
    p4x = EndianS32_NtoB(p4x);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kSeventhParam, sizeof(p4x), &p4x, nil ) );
 
    p4y = EndianS32_NtoB(p4y);
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kEighthParam, sizeof(p4y), &p4y, nil ) );
 
    FailOSErr( AddActionParameterAtom( container, theActionAtom, kNinthParam, sizeof(isRelative), &isRelative, nil ) );
 
    FailOSErr( AddTrackAndSpriteTargetAtoms( container, theActionAtom, trackTargetType, trackTarget, trackTypeIndex, 
                                             spriteTargetType, spriteTarget ) );
 
    if ( actionAtom )
        *actionAtom = theActionAtom;
bail:
    return err;
}
 
OSErr AddMusicPlayNoteAction( QTAtomContainer container, QTAtom atom, long whichEvent, long trackTargetType, 
                              void *trackTarget, long trackTypeIndex, long sampleDescIndex, long partIndex,
                              long pitch, long velocity, long duration )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionMusicPlayNote, &actionAtom ) );
 
    sampleDescIndex = EndianS32_NtoB(sampleDescIndex);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(sampleDescIndex), &sampleDescIndex, nil ) );
    
    partIndex = EndianS32_NtoB(partIndex);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kSecondParam, sizeof(partIndex), &partIndex, nil ) );
    
    pitch = EndianS32_NtoB(pitch);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kThirdParam, sizeof(pitch), &pitch, nil ) );
    
    velocity = EndianS32_NtoB(velocity);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFourthParam, sizeof(velocity), &velocity, nil ) );
    
    duration = EndianS32_NtoB(duration);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFifthParam, sizeof(duration), &duration, nil ) );
 
    FailOSErr( AddTrackTargetAtom( container, actionAtom, trackTargetType, trackTarget, trackTypeIndex ) );
 
bail:
    return err;
}
 
OSErr AddSpriteTrackSetVariableAction( QTAtomContainer container, QTAtom atom, long whichEvent, QTAtomID variableID, float value, 
                                       long trackTargetType, void *trackTarget, long trackTypeIndex )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionSpriteTrackSetVariable, &actionAtom ) );
 
    variableID = EndianU32_NtoB(variableID);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(variableID), &variableID, nil ) );
 
//  value = EndianU32_NtoB(value);              // just flipping the 4 bytes
    EndianUtils_Float_NtoB(&value);
    
    FailOSErr( AddActionParameterAtom( container, actionAtom, kSecondParam, sizeof(value), &value, nil ) );
 
    FailOSErr( AddTrackTargetAtom( container, actionAtom, trackTargetType, trackTarget, trackTypeIndex ) );
 
bail:
    return err;
}                                      
                        
OSErr AddGoToURLAction( QTAtomContainer container, QTAtom atom, long whichEvent, Handle urlLink )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionGoToURL, &actionAtom ) );
 
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, GetHandleSize(urlLink), *urlLink, nil ) );
 
    // no target for system actions
 
bail:
    return err;
}
 
OSErr AddSendQTEventAction( QTAtomContainer container, QTAtom atom, long whichEvent, QTEventRecordPtr theEvent,
                            long trackTargetType, void *trackTarget, long trackTypeIndex, long spriteTargetType, void *spriteTarget )
{
    OSErr   err = noErr;
    QTAtom  actionAtom, paramAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionSendQTEventToSprite, &actionAtom ) );
 
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, 0, nil, &paramAtom ) );
 
    // note that these target atoms are the first parameter to the kActionSendQTEvent action 
    FailOSErr( AddTrackAndSpriteTargetAtoms( container, paramAtom, trackTargetType, trackTarget, trackTypeIndex, 
                                             spriteTargetType, spriteTarget ) );
 
    FailOSErr( AddActionParameterAtom( container, actionAtom, kSecondParam, sizeof(*theEvent), theEvent, &paramAtom ) );
 
bail:
    return err;
}                                      
                        
OSErr AddDebugStrAction( QTAtomContainer container, QTAtom atom, long whichEvent, Str255 theString )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionDebugStr, &actionAtom ) );
 
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, theString[0] + 1, theString, nil ) );
 
    // no target for system actions
 
bail:
    return err;
}
 
OSErr AddPushCurrentTimeAction( QTAtomContainer container, QTAtom atom, long whichEvent )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionPushCurrentTime, &actionAtom ) );
 
    // no target for system actions
 
bail:
    return err;
}
            
OSErr AddPushCurrentTimeWithLabelAction( QTAtomContainer container, QTAtom atom, long whichEvent, Str255 theLabel )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionPushCurrentTimeWithLabel, &actionAtom ) );
 
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, theLabel[0] + 1, theLabel, nil ) );
 
    // no target for system actions
 
bail:
    return err;
}
        
        
OSErr AddPopAndGotoTopTimeAction( QTAtomContainer container, QTAtom atom, long whichEvent )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionPopAndGotoTopTime, &actionAtom ) );
 
    // no target for system actions
 
bail:
    return err;
}
 
OSErr AddPopAndGotoLabeledTimeAction( QTAtomContainer container, QTAtom atom, long whichEvent, Str255 theLabel )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionPopAndGotoLabeledTime, &actionAtom ) );
 
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, theLabel[0] + 1, theLabel, nil ) );
 
    // no target for system actions
 
bail:
    return err;
}
 
OSErr AddApplicationNumberAndStringAction( QTAtomContainer container, QTAtom atom, long whichEvent, long theNumber, Str255 theString )
{
    OSErr   err = noErr;
    QTAtom  actionAtom;
    
    FailOSErr( AddQTEventAndActionAtoms( container, atom, whichEvent, kActionApplicationNumberAndString, &actionAtom ) );
 
    theNumber = EndianS32_NtoB(theNumber);
    FailOSErr( AddActionParameterAtom( container, actionAtom, kFirstParam, sizeof(theNumber), &theNumber, nil ) );
 
    FailOSErr( AddActionParameterAtom( container, actionAtom, kSecondParam, theString[0] + 1, theString, nil ) );
 
    // no target for system actions
 
bail:
    return err;
}
                        
                               
// ________ Interpreted Actions __________
 
OSErr AddOperandAtom( QTAtomContainer container, QTAtom operatorAtom, QTAtomType operandType, short operandIndex,
                      QTAtomContainer operandAtoms, float constantValue )
{
    OSErr   err = noErr;
    QTAtom  operandAtom, operandTypeAtom;
    
    FailOSErr( QTInsertChild( container, operatorAtom, kOperandAtomType, 0, operandIndex, 0, nil, &operandAtom ) );
    
    FailOSErr( QTInsertChild( container, operandAtom, operandType, 1, 1, 0, nil, &operandTypeAtom ) );
 
    if ( operandType == kOperandConstant ) {
    
        EndianUtils_Float_NtoB(&constantValue);
    //  constantValue = EndianU32_NtoB(constantValue);
        FailOSErr( QTSetAtomData( container, operandTypeAtom, sizeof( constantValue ), &constantValue ) );
    }
    else {
        FailOSErr( QTInsertChildren( container, operandTypeAtom, operandAtoms ) );
    }
    
bail:
    return err;
}
 
OSErr AddVariableOperandAtom( QTAtomContainer container, QTAtom operatorAtom, short operandIndex,
                              long trackTargetType, void *trackTarget, long trackTypeIndex, QTAtomID variableID )
{
    OSErr   err = noErr;
    QTAtom  operandAtom, operandTypeAtom;
    
    FailOSErr( QTInsertChild( container, operatorAtom, kOperandAtomType, 0, operandIndex, 0, nil, &operandAtom ) );
    
    FailOSErr( QTInsertChild( container, operandAtom, kOperandSpriteTrackVariable, 1, 1, 0, nil, &operandTypeAtom ) );
 
    variableID = EndianU32_NtoB(variableID);
    FailOSErr( QTInsertChild( container, operandTypeAtom, kActionParameter, 1, 1, sizeof(variableID), &variableID, nil ) );
 
    FailOSErr( AddTrackTargetAtom( container, operandTypeAtom, trackTargetType, trackTarget, trackTypeIndex ) );
        
bail:
    return err;
}
 
OSErr AddOperatorAtom( QTAtomContainer container, QTAtom expressionAtom, QTAtomID theOperatorType, QTAtom *operatorAtom )
{
    return QTInsertChild( container, expressionAtom, kOperatorAtomType, theOperatorType, 1, 0, nil, operatorAtom );
}
 
OSErr AddExpressionContainerAtomType( QTAtomContainer container, QTAtom atom, QTAtom *expressionAtom )
{
    return QTInsertChild( container, atom, kExpressionContainerAtomType, 1, 1, 0, nil, expressionAtom );
}
 
OSErr AddConditionalAtom( QTAtomContainer container, QTAtom atom, short conditionIndex, QTAtom *conditionalAtom )
{
    return QTInsertChild( container, atom, kConditionalAtomType, 0, conditionIndex, 0, nil, conditionalAtom );
}
 
OSErr AddActionListAtom( QTAtomContainer container, QTAtom atom, QTAtom *actionListAtom )
{
    return QTInsertChild( container, atom, kActionListAtomType, 1, 1, 0, nil, actionListAtom );
}