//
// File: QTSndTween.c
//
// Contains: Sound tweening support for QuickTime movies.
//
// Written by: Tim Monroe
// based largely on the tween sample code in the QuickTime 2.5 Developers Guide
// and the sample code QT3DTween.c.
//
// Copyright: © 1998 by Apple Computer, Inc., all rights reserved.
//
// Change History (most recent first):
//
// <3> 03/21/00 rtm made changes for running under CarbonLib
// <2> 05/26/98 rtm set the time scale of the sound track media to that of the movie,
// using revised code from Peter Hoddie
// <1> 04/10/98 rtm first file; revised to personal coding style
//
//
// This sample shows how to modify an existing QuickTime movie so that the volume of its sound track
// is gradually increased (or decreased) as the movie plays. We do this by adding a tween track to
// the movie and linking the tween track to the existing sound track.
//
// NOTES:
//
// *** (1) ***
// For complete information on creating tween media tracks, see the chapter "Tween Media Handler Components"
// in the QuickTime 2.5 or 3.0 Developers Guide.
//
//
#include <FixMath.h>
#include <Sound.h>
#include "QTSndTween.h"
// global variables
// this variable determines what kind of tween data we add to the movie
Boolean gTweenLoToHigh = true; // do we start at no volume and end at full volume?
//////////
//
// QTSndTween_AddTweenTrackToMovie
// Add a tween track to a QuickTIme movie.
//
//////////
OSErr QTSndTween_AddTweenTrackToMovie (Movie theMovie)
{
Track mySndTrack = NULL;
Track myTrack;
Media myMedia;
StandardFileReply myReply;
SampleDescriptionHandle mySampleDesc = NULL;
QTAtomContainer mySample = NULL;
QTAtomContainer myInputMap = NULL;
QTAtom myAtom = 0;
QTAtom myInputAtom = 0;
short myTweenData[2];
long myRefIndex;
TimeRecord myTimeRec;
OSErr myErr = noErr;
if (theMovie == NULL)
goto bail;
//////////
//
// get the (first) sound track from the movie
//
//////////
mySndTrack = GetMovieIndTrackType(theMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
if (mySndTrack == NULL)
goto bail;
//////////
//
// create the tween track and media, and a sample to contain the tween data
//
//////////
// create the tween track and media
myTrack = NewMovieTrack(theMovie, 0, 0, kNoVolume);
myMedia = NewTrackMedia(myTrack, TweenMediaType, kTweenTimeScale, NULL, 0);
// create a new sample; this sample will hold the tween data
myErr = QTNewAtomContainer(&mySample);
if (myErr != noErr)
goto bail;
myTweenData[0] = gTweenLoToHigh ? EndianU16_NtoB(0) : EndianU16_NtoB(512);
myTweenData[1] = gTweenLoToHigh ? EndianU16_NtoB(512) : EndianU16_NtoB(0);
// make a tween entry for that data;
// a tween entry is a parent atom that contains leaf atoms describing the tweening operation
myErr = QTSndTween_AddTweenEntryToSample(mySample, kSoundTweenID, kTweenTypeShort, &myTweenData, sizeof(myTweenData));
if (myErr != noErr)
goto bail;
// create the sample description
mySampleDesc = (SampleDescriptionHandle)NewHandleClear(sizeof(SampleDescription));
if (mySampleDesc == NULL)
goto bail;
(**mySampleDesc).descSize = sizeof(SampleDescription);
// add the tween sample to the media
BeginMediaEdits(myMedia);
// set the time scale of the media to that of the movie
myTimeRec.value.lo = GetTrackDuration(mySndTrack);
myTimeRec.value.hi = 0;
myTimeRec.scale = GetMovieTimeScale(theMovie);
ConvertTimeScale(&myTimeRec, GetMediaTimeScale(myMedia));
myErr = AddMediaSample(myMedia, mySample, 0, GetHandleSize(mySample), myTimeRec.value.lo, (SampleDescriptionHandle)mySampleDesc, 1, 0, NULL);
if (myErr != noErr)
goto bail;
EndMediaEdits(myMedia);
// add the media to the track
InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1);
// dispose of some things we no longer need
QTDisposeAtomContainer(mySample);
DisposeHandle((Handle)mySampleDesc);
//////////
//
// create a link between the sound track and the tween track, and update the sound track's input map
//
//////////
// first, create a new atom container
myErr = QTNewAtomContainer(&myInputMap);
if (myErr != noErr)
goto bail;
// for *each* tween entry in the tween media sample,
// create a link between the sound track and the tween track, and add an entry to the input map
myErr = AddTrackReference(mySndTrack, myTrack, kTrackModifierReference, &myRefIndex);
if (myErr != noErr)
goto bail;
myErr = QTSndTween_AddTweenEntryToInputMap(myInputMap, myRefIndex, kSoundTweenID, kTrackModifierTypeVolume, NULL);
if (myErr != noErr)
goto bail;
// attach the input map to the sound media
myErr = SetMediaInputMap(GetTrackMedia(mySndTrack), myInputMap);
if (myErr != noErr)
goto bail;
// dispose of the input map
QTDisposeAtomContainer(myInputMap);
//////////
//
// finish up
//
//////////
// save the new movie file; if you are running under CarbonLib, change this to use Navigation Services
StandardPutFile("\pSave Movie as:", "\pNewMovie.mov", &myReply);
if (myReply.sfGood) {
FlattenMovieData(theMovie, flattenAddMovieToDataFork, &myReply.sfFile, FOUR_CHAR_CODE('TVOD'), smSystemScript, createMovieFileDeleteCurFile);
myErr = GetMoviesError();
}
bail:
return(myErr);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tween utilities.
//
// Use these functions add tween entries to samples or to add attributes to tween entries.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////
//
// QTSndTween_AddTweenEntryToSample
// Add a tween entry to the specified sample.
//
// A tween entry defines a set of values for a single tweening operation. A tween entry is a parent atom
// whose children define the tween data type, the tween data, and additional attributes of the operation.
//
// The data specified in the theData parameter is assumed to be in big-endian format.
//
//////////
OSErr QTSndTween_AddTweenEntryToSample (QTAtomContainer theSample, QTAtomID theID, QTAtomType theType, void *theData, long theDataSize)
{
OSErr myErr = noErr;
QTAtom myAtom;
// create an entry for this tween in the sample
myErr = QTInsertChild(theSample, kParentAtomIsContainer, kTweenEntry, theID, 0, 0, NULL, &myAtom);
if (myErr != noErr)
goto bail;
// set the type of this tween entry
theType = EndianU32_NtoB(theType);
myErr = QTInsertChild(theSample, myAtom, kTweenType, 1, 0, sizeof(theType), &theType, NULL);
if (myErr != noErr)
goto bail;
// set the data for this tween entry
myErr = QTInsertChild(theSample, myAtom, kTweenData, 1, 0, theDataSize, theData, NULL);
bail:
return(myErr);
}
//////////
//
// QTSndTween_AddTweenEntryToInputMap
// Add a tween entry to the specified input map.
//
//////////
OSErr QTSndTween_AddTweenEntryToInputMap (QTAtomContainer theInputMap, long theRefIndex, long theID, OSType theType, char *theName)
{
QTAtom myInputAtom;
OSErr myErr = noErr;
// add an entry to the input map
myErr = QTInsertChild(theInputMap, kParentAtomIsContainer, kTrackModifierInput, theRefIndex, 0, 0, NULL, &myInputAtom);
if (myErr != noErr)
goto bail;
// add two child atoms to the parent atom;
// these atoms define the type of the modifier input and the ID of the tween entry atom
theType = EndianU32_NtoB(theType);
myErr = QTInsertChild(theInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(OSType), &theType, NULL);
if (myErr != noErr)
goto bail;
theID = EndianU32_NtoB(theID);
myErr = QTInsertChild(theInputMap, myInputAtom, kInputMapSubInputID, 1, 0, sizeof(long), &theID, NULL);
if (myErr != noErr)
goto bail;
// set the name of the input atom
if (theName != NULL) {
long myLength = 1;
Ptr myPtr = theName;
UInt16 *myShort;
// determine the length of the name string
while (*myPtr++)
myLength++;
// convert the name string to the proper endian format
myPtr = theName;
while (*myPtr) {
myShort = (UInt16 *)myPtr;
*myPtr = EndianU16_NtoB(*myShort);
myPtr = myPtr + 2; // point to next word
}
myErr = QTInsertChild(theInputMap, myInputAtom, kTrackModifierInputName, 1, 0, myLength, theName, NULL);
}
bail:
return(myErr);
}
|