home *** CD-ROM | disk | FTP | other *** search
/ QuickTime 2.0 Beta / Quicktime 2.0 Beta.iso / Programming Stuff / Sample Code / TimeCode Samples / ExportCMX3600ƒ / ExportCMX3600.c next >
Encoding:
C/C++ Source or Header  |  1994-04-27  |  19.9 KB  |  702 lines  |  [TEXT/KAHL]

  1. /*
  2.     File:        ExportCMX3600.c
  3.  
  4.     Written by:    Jim Batson
  5.  
  6.     Copyright:    © 1994 by Apple Computer, Inc., all rights reserved.
  7.  
  8. */
  9.  
  10. #include <Resources.h>
  11. #include <Files.h>
  12. #include <Movies.h>
  13. #include <Events.h>
  14. #include <Components.h>
  15. #include <QuickTimeComponents.h>
  16. #include <Errors.h>
  17. #include <Memory.h>
  18.  
  19. typedef struct {
  20.     ComponentInstance        self;
  21.     
  22.     TimeCodeDef             dstTcdef;    
  23.     TimeCodeRecord             dstTcrec;    
  24.     Str255                     EDLtitle;
  25. } ExportCMX3600GlobalsRecord, *ExportCMX3600Globals;
  26.  
  27. pascal ComponentResult ExportCMX3600Open( ExportCMX3600Globals store, ComponentInstance self );
  28. pascal ComponentResult ExportCMX3600Close( ExportCMX3600Globals store, ComponentInstance self );
  29. pascal ComponentResult ExportCMX3600CanDo( ExportCMX3600Globals store, short ftnNumber );
  30. pascal ComponentResult ExportCMX3600Version( ExportCMX3600Globals store );
  31.  
  32. pascal ComponentResult ExportCMX3600ToFile(ExportCMX3600Globals store, 
  33.         const FSSpec *theFile, Movie m, Track onlyThisTrack, TimeValue startTime, TimeValue duration);
  34. extern pascal ComponentResult ExportCMX3600DoUserDialog(ExportCMX3600Globals store, 
  35.         Movie theMovie, Track onlyThisTrack, TimeValue startTime, TimeValue duration, Boolean *canceled);
  36.  
  37. // entry point for all Component Manager requests
  38. #ifdef THINK_C
  39.     #ifndef DEBUG_LINKED
  40.         pascal ComponentResult main( ComponentParameters *params, Handle store );
  41.         pascal ComponentResult main(ComponentParameters *params, Handle storage)
  42.     #else
  43.         pascal ComponentResult ExportCMX3600Dispatcher( ComponentParameters *params, Handle store );
  44.         pascal ComponentResult ExportCMX3600Dispatcher(ComponentParameters *params, Handle storage)
  45.     #endif
  46. #else
  47.     pascal ComponentResult ExportCMX3600Dispatcher( ComponentParameters *params, Handle store );
  48.     pascal ComponentResult ExportCMX3600Dispatcher(ComponentParameters *params, Handle storage)
  49. #endif
  50. {
  51.     OSErr err = badComponentSelector;
  52.     ComponentFunctionUPP componentProc = 0;
  53.  
  54.     switch (params->what) {
  55.         case kComponentOpenSelect: componentProc = (ComponentFunctionUPP)ExportCMX3600Open; break;
  56.         case kComponentCloseSelect: componentProc = (ComponentFunctionUPP)ExportCMX3600Close; break;
  57.         case kComponentCanDoSelect: componentProc = (ComponentFunctionUPP)ExportCMX3600CanDo; break;
  58.         case kComponentVersionSelect: componentProc = (ComponentFunctionUPP)ExportCMX3600Version; break;
  59.         case kMovieExportToFileSelect: componentProc = (ComponentFunctionUPP)ExportCMX3600ToFile; break;
  60.         case kMovieExportDoUserDialogSelect: componentProc = (ComponentFunctionUPP)ExportCMX3600DoUserDialog; break;
  61.     }
  62.  
  63.     if (componentProc)
  64.         err = CallComponentFunctionWithStorage(storage, params, componentProc);
  65.  
  66.     return err;
  67. }
  68.  
  69. pascal ComponentResult ExportCMX3600CanDo( ExportCMX3600Globals store, short ftnNumber )
  70. {
  71.     switch (ftnNumber) {
  72.         case kComponentOpenSelect:
  73.         case kComponentCloseSelect:
  74.         case kComponentCanDoSelect:
  75.         case kComponentVersionSelect:
  76.         case kMovieExportToFileSelect:
  77.         case kMovieExportDoUserDialogSelect:
  78.             return true;
  79.             break;
  80.         default:
  81.             return false;
  82.             break;
  83.     }
  84. }
  85.  
  86. pascal ComponentResult ExportCMX3600Version( ExportCMX3600Globals store )
  87. {
  88.     return 0x00010001;
  89. }
  90.  
  91. pascal ComponentResult ExportCMX3600Open(ExportCMX3600Globals store, ComponentInstance self)
  92. {
  93.     OSErr err;
  94.     Str63 defTitle = {"\pUntitled"};
  95.     
  96. #ifdef DEBUG_LINKED
  97.     SetComponentInstanceA5(self, GetComponentRefcon((Component)self));
  98. #endif
  99.     store = (ExportCMX3600Globals)NewPtrClear(sizeof(ExportCMX3600GlobalsRecord));
  100.     if (err = MemError()) goto bail;
  101.     store->self = self;
  102.  
  103.     BlockMove( &defTitle[0], &store->EDLtitle[0], defTitle[0]+1 );    
  104.  
  105.     store->dstTcdef.flags = tc24HourMax | tcDropFrame;
  106.     store->dstTcdef.fTimeScale = 2997;
  107.     store->dstTcdef.frameDuration = 100;
  108.     store->dstTcdef.numFrames = 30;
  109.  
  110.     store->dstTcrec.t.hours = 0;
  111.     store->dstTcrec.t.minutes = 1;
  112.     store->dstTcrec.t.seconds = 0;
  113.     store->dstTcrec.t.frames = 0;
  114.     
  115.  
  116.     SetComponentInstanceStorage(self, (Handle)store);
  117. bail:
  118.     return err;
  119. }
  120.  
  121. pascal ComponentResult ExportCMX3600Close(ExportCMX3600Globals store, ComponentInstance self)
  122. {
  123.     if (store) DisposPtr((Ptr)store);
  124.  
  125.     return noErr;
  126. }
  127.  
  128. // •••••••••••••••••••••••••••••••••••••
  129. // The Conversion Code starts here
  130.  
  131. void outputChars( short refNum, StringPtr s );
  132. void outputChars( short refNum, StringPtr s )
  133. {
  134.     long count;
  135.     long i;
  136.     char *sp;
  137.     char c;
  138.     
  139.     sp = (char*)s;
  140.     count = *sp++;
  141.     for (i = 0; i < count; i++, sp++) {
  142.         c = *sp;
  143.         if ((c >= 'a') && (c <= 'z'))
  144.             *sp = c + ('A' - 'a');
  145.         else if (c == ';')
  146.             *sp = ':';
  147.         }
  148.     FSWrite( refNum, &count, &s[1] );
  149. }
  150.  
  151.  
  152. void outputCharsLF( short refNum, StringPtr s );
  153. void outputCharsLF( short refNum, StringPtr s )
  154. {
  155.     long count;
  156.     char lf[2];
  157.     
  158.     outputChars(refNum,s);
  159.     
  160.     lf[0] = 0xd;
  161.     lf[1] = 0xa;
  162.     count = 2;
  163.     FSWrite( refNum, &count, &lf[0] );
  164. }
  165.  
  166. void outputEditNum( short refNum, long editNum );
  167. void outputEditNum( short refNum, long editNum )
  168. {
  169.     char s[6];
  170.     
  171.     s[0] = 5;
  172.     s[4] = ' ';
  173.     s[5] = ' ';
  174.     s[3] = '0' + editNum % 10;
  175.     editNum /= 10;
  176.     s[2] = '0' + editNum % 10;
  177.     editNum /= 10;
  178.     s[1] = '0' + editNum % 10;
  179.     
  180.     outputChars( refNum, (StringPtr)s );
  181. }
  182.  
  183. void outputRate( short refNum, double rate );
  184. void outputRate( short refNum, double rate )
  185. {
  186.     char s[5];
  187.     long intNum;
  188.     long fracNum;
  189.     
  190.     s[0] = 4;
  191.     intNum = rate;
  192.     fracNum = (rate*10.0 - intNum*10);
  193.     s[2] = '0' + intNum % 10;
  194.     intNum /= 10;
  195.     s[1] = '0' + intNum % 10;
  196.     s[3] = '.';
  197.     s[4] = '0' + fracNum;
  198.     
  199.     outputChars( refNum, (StringPtr)s );
  200. }
  201.  
  202. pascal ComponentResult ExportCMX3600ToFile(ExportCMX3600Globals store, const FSSpec *theFile, 
  203.                 Movie theMovie, Track theTrack, TimeValue startTime, TimeValue duration)
  204. {
  205.     OSErr err = noErr;
  206.     short refNum = 0;
  207.     long editCnt = 1;
  208.     Str63 tapename;
  209.     Media theMedia;
  210.     TimeScale movieTimeScale;
  211.     TimeScale mediaTimeScale;
  212.     TimeValue editDur;
  213.     TimeValue mediaTime;
  214.     MediaHandler mh;
  215.     Handle srcNameH = nil;
  216.     TimeCodeDef tcdef;
  217.     TimeCodeRecord tcrec;
  218.     UserData srcRef = nil;
  219.     Str63 inTime, outTime;
  220.     long dstFrameCnt = 0;
  221.     Str63 lastDstTime, newDstTime;
  222.     long srcFrameIn, srcFrameOut;
  223.     TimeCodeRecord dstTcrec;
  224.     Boolean lastGuyWasDropFrame;
  225.     Boolean thisGuyIsDropFrame;
  226.     Boolean dstIsDropFrame;
  227.     
  228.  
  229.     if (!theTrack) {
  230.         // We currently only handle a single TimeCode track
  231.         theTrack = GetMovieIndTrackType( theMovie, 1, TimeCodeMediaType, movieTrackMediaType);
  232.         if (!theTrack) return trackIDNotFound;
  233.     }
  234.  
  235.     // open up the data fork of the CMX3600 output file (the caller is responsible
  236.     //    for creating the file)
  237.     err = FSpOpenDF(theFile, fsRdWrPerm, &refNum);
  238.     if (err = ResError()) goto bail;
  239.  
  240.     srcNameH = NewHandle(4);
  241.     
  242.     theMedia = GetTrackMedia(theTrack);
  243.     theMovie = GetTrackMovie(theTrack);
  244.     mh = GetMediaHandler( theMedia );
  245.     movieTimeScale = GetMovieTimeScale(theMovie);
  246.     mediaTimeScale = GetMediaTimeScale(theMedia);
  247.             
  248.     dstTcrec = store->dstTcrec;
  249.     
  250.     err = TCTimeCodeToFrameNumber(mh, &store->dstTcdef, &dstTcrec, &dstFrameCnt); if (err) goto bail;
  251.     
  252.     err = TCFrameNumberToTimeCode(mh, dstFrameCnt, &store->dstTcdef, &dstTcrec); if (err) goto bail;
  253.     err = TCTimeCodeToString(mh, &store->dstTcdef, &dstTcrec, lastDstTime); if (err) goto bail;
  254.     
  255.     // Output destination info
  256.     outputCharsLF(refNum,"\p");
  257.     outputChars(refNum,"\pTITLE: ");
  258.     outputCharsLF(refNum,store->EDLtitle);
  259.     outputCharsLF(refNum,"\p");
  260.     dstIsDropFrame = lastGuyWasDropFrame = ((store->dstTcdef.flags & tcDropFrame) == tcDropFrame);
  261.     if (dstIsDropFrame) 
  262.         outputCharsLF(refNum,"\pFCM: DROP FRAME");
  263.     else
  264.         outputCharsLF(refNum,"\pFCM: NON-DROP FRAME");
  265.     outputCharsLF(refNum,"\p");
  266.     
  267.     // iterate through the movie time segment we were given
  268.     GetTrackNextInterestingTime( theTrack, nextTimeTrackEdit | nextTimeEdgeOK | nextTimeIgnoreActiveSegment, 
  269.                         startTime, kFix1, &startTime, &editDur );
  270.     while (startTime < duration) {
  271.         TimeValue mediaStart;
  272.         Fixed trackRate;
  273.         
  274.         trackRate = GetTrackEditRate(theTrack, startTime);
  275.         mediaStart = TrackTimeToMediaTime( startTime, theTrack );
  276.         
  277.         if (mediaStart < 0) {  // Empty edit segment
  278.             TimeRecord tr;
  279.             long numframes;
  280.             Str63 inEmpty, outEmpty;
  281.             TimeCodeRecord emptyTcrec;
  282.             
  283.             // convert edit duration to destination time code scale
  284.             tr.base = nil;
  285.             tr.scale = movieTimeScale;
  286.             tr.value.loLong = editDur;
  287.             tr.value.hiLong = 0;
  288.             ConvertTimeScale(&tr, store->dstTcdef.fTimeScale);
  289.             // convert to number of frames
  290.             numframes = tr.value.loLong / store->dstTcdef.frameDuration;
  291.             
  292.             if (numframes) {    // ignore if we fall out due to round off
  293.                 // Calculate new dst out time
  294.                 dstFrameCnt += numframes;
  295.                 err = TCFrameNumberToTimeCode(mh, dstFrameCnt, &store->dstTcdef, &dstTcrec); if (err) goto bail;
  296.                 err = TCTimeCodeToString(mh, &store->dstTcdef, &dstTcrec, newDstTime); if (err) goto bail;
  297.                 
  298.                 // Make blank in & out times
  299.                 err = TCFrameNumberToTimeCode(mh, 0, &store->dstTcdef, &emptyTcrec); if (err) goto bail;
  300.                 err = TCTimeCodeToString(mh, &store->dstTcdef, &emptyTcrec, inEmpty); if (err) goto bail;
  301.                 err = TCFrameNumberToTimeCode(mh, numframes, &store->dstTcdef, &emptyTcrec); if (err) goto bail;
  302.                 err = TCTimeCodeToString(mh, &store->dstTcdef, &emptyTcrec, outEmpty); if (err) goto bail;
  303.                 
  304.                 
  305.                 // handle drop-frames changing
  306.                 if (dstIsDropFrame != lastGuyWasDropFrame) {
  307.                     if (dstIsDropFrame) 
  308.                         outputCharsLF(refNum,"\pFCM: DROP FRAME");
  309.                     else
  310.                         outputCharsLF(refNum,"\pFCM: NON-DROP FRAME");
  311.                     lastGuyWasDropFrame = dstIsDropFrame;
  312.                     }
  313.                 
  314.                 // put out the edit
  315.                 outputEditNum(refNum, editCnt++);
  316.                 outputChars(refNum,"\pBL        V    C         ");
  317.                 outputChars(refNum,inEmpty);
  318.                 outputChars(refNum,"\p  ");
  319.                 outputChars(refNum,outEmpty);
  320.                 outputChars(refNum,"\p  ");
  321.                 outputChars(refNum,lastDstTime);
  322.                 outputChars(refNum,"\p  ");
  323.                 outputCharsLF(refNum,newDstTime);
  324.                 outputCharsLF(refNum,"\p");
  325.                 
  326.                 // transfer dst out time to dst in time
  327.                 BlockMove(&newDstTime[0], &lastDstTime[0], newDstTime[0]+1 );
  328.                 }
  329.             startTime++;    // bump start time so GetTrackNextInteresting moves along
  330.         }
  331.         else {
  332.             TimeRecord tr;
  333.             TimeValue mediaNext;
  334.             TimeValue mediaStop;
  335.             TimeValue mediaDur;
  336.             long origSrcFrameIn;
  337.             long srcNumFrames;
  338.             short i;
  339.             
  340.             // convert edit duration to media time scale
  341.             tr.value.hiLong = 0;
  342.             tr.value.loLong = editDur;
  343.             tr.base = 0;
  344.             tr.scale = movieTimeScale;
  345.             ConvertTimeScale(&tr,mediaTimeScale);
  346.             mediaStop = mediaStart + tr.value.loLong;
  347.             
  348.             while (mediaStart < mediaStop) {
  349.                 // get next sample in media for edit
  350.                 GetMediaNextInterestingTime( theMedia, nextTimeMediaSample, mediaStart, kFix1, &mediaNext, &mediaDur );
  351.                 
  352.                 // fix up if we run off end
  353.                 if ((mediaNext >= mediaStop) || (mediaNext < 0)) {
  354.                     mediaNext = mediaStop;
  355.                     }
  356.                 
  357.                 // make src in time code
  358.                 err = TCGetTimeCodeAtTime( mh, mediaStart, &srcFrameIn, &tcdef, &tcrec, &srcRef ); if (err) goto bail;
  359.                 err = TCTimeCodeToString( mh, &tcdef, &tcrec, inTime ); if (err) goto bail;
  360.                 
  361.                 // make src out time code
  362.                 err = TCGetTimeCodeAtTime( mh, mediaNext-1, &srcFrameOut, &tcdef, &tcrec, nil ); if (err) goto bail;
  363.                 err = TCTimeCodeToString( mh, &tcdef, &tcrec, outTime ); if (err) goto bail;
  364.                 
  365.                 // remember some info for rate != 1x
  366.                 origSrcFrameIn = srcFrameIn;
  367.                 srcNumFrames = srcFrameOut - srcFrameIn;
  368.                 
  369.                 // calculate dst out time code
  370.                 dstFrameCnt += srcNumFrames;
  371.                 err = TCFrameNumberToTimeCode(mh, dstFrameCnt, &store->dstTcdef, &dstTcrec); if (err) goto bail;
  372.                 err = TCTimeCodeToString(mh, &store->dstTcdef, &dstTcrec, newDstTime); if (err) goto bail;
  373.                 
  374.                 // Get source name, if no source name, make it all blanks
  375.                 i = 0;
  376.                 if (srcRef) {        // get source name
  377.                     err = GetUserDataText( srcRef, srcNameH, 'name', 1, langEnglish );
  378.                     if (!err) {
  379.                         long slen;
  380.                         slen = GetHandleSize(srcNameH);
  381.                         for (i = 0; (i < 8) && (i < slen); i++) {
  382.                             tapename[i+1] = (*srcNameH)[i];
  383.                             // break on illegal chars for tape name
  384.                             //     (if I only knew what they really where…)
  385.                             if (tapename[i+1] == ' ') break;
  386.                             if (tapename[i+1] == ',') break;
  387.                             if (tapename[i+1] == ':') break;
  388.                             }
  389.                         DisposeUserData( srcRef );
  390.                     }
  391.                 }
  392.                 if (i == 0) {        // let's give the tape a name
  393.                     // the best thing would be to keep track of the sample descriptions so we could
  394.                     // name them a,b,c,…
  395.                     tapename[++i] = 'A';
  396.                     }
  397.                 for (; i < 8; i++) {
  398.                     tapename[i+1] = ' ';
  399.                     }
  400.                 tapename[0] = 8;
  401.                 
  402.                 // handle drop-frame changing
  403.                 thisGuyIsDropFrame = ((tcdef.flags & tcDropFrame) == tcDropFrame);
  404.                 if (thisGuyIsDropFrame != lastGuyWasDropFrame) {
  405.                     if (thisGuyIsDropFrame) 
  406.                         outputCharsLF(refNum,"\pFCM: DROP FRAME");
  407.                     else
  408.                         outputCharsLF(refNum,"\pFCM: NON-DROP FRAME");
  409.                     lastGuyWasDropFrame = thisGuyIsDropFrame;
  410.                     }
  411.                 
  412.                 // output the edit
  413.                 outputEditNum(refNum, editCnt++);
  414.                 outputChars(refNum,tapename);
  415.                 outputChars(refNum,"\p  AA/V C         ");
  416.                 outputChars(refNum,inTime);
  417.                 outputChars(refNum,"\p  ");
  418.                 outputChars(refNum,outTime);
  419.                 outputChars(refNum,"\p  ");
  420.                 outputChars(refNum,lastDstTime);
  421.                 outputChars(refNum,"\p  ");
  422.                 outputCharsLF(refNum,newDstTime);
  423.                 
  424.                 // transfer dst out time to dst in time
  425.                 BlockMove(&newDstTime[0], &lastDstTime[0], sizeof(newDstTime) );
  426.                 
  427.                 // handle non 1x playback
  428.                 if (trackRate != kFix1) {
  429.                     double editRate = (double)trackRate / kFix1;
  430.                     long realFrameCnt;
  431.                     Str63 newTime;
  432.                     
  433.                     // number of frames in source going to dest
  434.                     realFrameCnt = FixMul(trackRate,srcNumFrames);
  435.                     
  436.                     // calculate src out time code
  437.                     err = TCFrameNumberToTimeCode(mh, origSrcFrameIn+realFrameCnt, &tcdef, &tcrec); if (err) goto bail;
  438.                     err = TCTimeCodeToString( mh, &tcdef, &tcrec, newTime ); if (err) goto bail;
  439.                     
  440.                     // output the rate playback
  441.                     outputChars(refNum, "\pM2   ");
  442.                     outputChars(refNum,tapename);
  443.                     editRate *= tcdef.numFrames;
  444.                     outputChars(refNum,"\p       ");
  445.                     outputRate(refNum, editRate);
  446.                     outputChars(refNum,"\p                    ");
  447.                     outputCharsLF(refNum,newTime);
  448.                     }
  449.  
  450.                 outputCharsLF(refNum,"\p");
  451.                 
  452.                 mediaStart = mediaNext;
  453.                 }
  454.         }
  455.         GetTrackNextInterestingTime( theTrack, nextTimeTrackEdit | nextTimeIgnoreActiveSegment, 
  456.             startTime, kFix1, &startTime, &editDur );
  457.     }
  458.  
  459. bail:
  460.     if (refNum) FSClose(refNum);
  461.     return err;
  462. }
  463.  
  464.  
  465. // •••••••••••••••••••••••••••••••••••••
  466. // The Options Dialog code starts here
  467.  
  468. #define diDialog 1128
  469.  
  470. #define diEDLName 4
  471. #define diTimeScale 6
  472. #define diFrameDur 8
  473. #define diNumFrames 10
  474.  
  475. #define diDropFrame 11
  476. #define diHours (diDropFrame + 2)
  477. #define diMinutes (diHours + 1)
  478. #define diSeconds (diMinutes + 1)
  479. #define diFrames (diSeconds + 1)
  480.  
  481. void setDialogTextNumber(DialogPtr d, short itemNumber, long number);
  482. void setDialogTextString(DialogPtr d, short itemNumber, StringPtr str);
  483. Boolean validateDialogLong(DialogPtr d, short itemNumber, long *result);
  484. ControlHandle getDItemHandle(DialogPtr d, short itemNumber);
  485.  
  486. extern pascal ComponentResult ExportCMX3600DoUserDialog(ExportCMX3600Globals store, Movie theMovie, Track onlyThisTrack, 
  487.             TimeValue startTime, TimeValue duration, Boolean *canceled)
  488. {
  489.     OSErr retstat = noErr;
  490.     DialogPtr optionsDialog = nil;
  491.     short itemHit = cancel;
  492.     ControlHandle curCtl;
  493.     Boolean newVal;
  494.     short i;
  495.     Rect negRect;
  496.     GrafPtr curPort;
  497.     
  498.     long     tcTimeScale;
  499.     long     tcFrameDur;
  500.     long     tcNumFrames;
  501.     long    tcHours;
  502.     long     tcMinutes;
  503.     long     tcSeconds;
  504.     long     tcFrames;
  505.     Str255     tcSrcName;
  506.     Boolean tcDropFrameVal;
  507.     
  508.     short    curResFile;
  509.     short    myResFile;
  510.     
  511.     tcTimeScale = store->dstTcdef.fTimeScale;
  512.     tcFrameDur = store->dstTcdef.frameDuration;
  513.     tcNumFrames = store->dstTcdef.numFrames;
  514.     tcDropFrameVal = ((store->dstTcdef.flags & tcDropFrame) != 0);
  515.     tcHours = store->dstTcrec.t.hours;
  516.     tcMinutes = store->dstTcrec.t.minutes;
  517.     tcSeconds = store->dstTcrec.t.seconds;
  518.     tcFrames = store->dstTcrec.t.frames;
  519.     tcSrcName[0] = 0;
  520.     
  521.     GetPort(&curPort);
  522.     
  523. #ifndef DEBUG_LINKED
  524.     curResFile = CurResFile();
  525.     myResFile = OpenComponentResFile( (Component)store->self );
  526.     UseResFile( myResFile );
  527. #endif
  528.  
  529.     optionsDialog = GetNewDialog( diDialog, nil, (WindowPtr)-1L );
  530.     if (!optionsDialog) goto bail;
  531.     
  532.     SetDialogDefaultItem(optionsDialog, 1);
  533.     SetDialogCancelItem(optionsDialog, 2);
  534.  
  535.     curCtl = getDItemHandle( optionsDialog, diDropFrame );
  536.     SetCtlValue(curCtl,tcDropFrameVal);
  537.  
  538.     setDialogTextNumber(optionsDialog, diTimeScale, tcTimeScale );
  539.     setDialogTextNumber(optionsDialog, diFrameDur, tcFrameDur );
  540.     setDialogTextNumber(optionsDialog, diNumFrames, tcNumFrames );
  541.     setDialogTextNumber(optionsDialog, diHours, tcHours );
  542.     setDialogTextNumber(optionsDialog, diMinutes, tcMinutes );
  543.     setDialogTextNumber(optionsDialog, diSeconds, tcSeconds );
  544.     setDialogTextNumber(optionsDialog, diFrames, tcFrames );
  545.  
  546.     setDialogTextString(optionsDialog, diEDLName, tcSrcName);
  547.  
  548. noGood:
  549.     do {
  550.     
  551.         ModalDialog( nil, &itemHit );
  552.         switch (itemHit) {
  553.             case diDropFrame:
  554.                 curCtl = getDItemHandle( optionsDialog, diDropFrame );
  555.                 SetCtlValue(curCtl,!GetCtlValue(curCtl));
  556.                 break;
  557.             }
  558.     } while ((itemHit != ok) && (itemHit != cancel));
  559.     
  560.     if (itemHit == ok) {
  561.         curCtl = getDItemHandle(optionsDialog, diEDLName);
  562.         GetIText((Handle)curCtl, tcSrcName);
  563.     
  564.         curCtl = getDItemHandle( optionsDialog, diDropFrame );
  565.         tcDropFrameVal = GetCtlValue(curCtl);
  566.  
  567.         if (!validateDialogLong(optionsDialog, diTimeScale, &tcTimeScale))
  568.             goto noGood;
  569.         if (!validateDialogLong(optionsDialog, diFrameDur, &tcFrameDur))
  570.             goto noGood;
  571.         if (!validateDialogLong(optionsDialog, diNumFrames, &tcNumFrames))
  572.             goto noGood;
  573.         if (!validateDialogLong(optionsDialog, diHours, &tcHours))
  574.             goto noGood;
  575.         if (!validateDialogLong(optionsDialog, diMinutes, &tcMinutes))
  576.             goto noGood;
  577.         if (!validateDialogLong(optionsDialog, diSeconds, &tcSeconds))
  578.             goto noGood;
  579.         if (!validateDialogLong(optionsDialog, diFrames, &tcFrames))
  580.             goto noGood;
  581.         }
  582.     
  583.     store->dstTcdef.fTimeScale = tcTimeScale;
  584.     store->dstTcdef.frameDuration = tcFrameDur;
  585.     store->dstTcdef.numFrames = tcNumFrames;
  586.     if (tcDropFrameVal) 
  587.         store->dstTcdef.flags |= tcDropFrame;
  588.     else
  589.         store->dstTcdef.flags &= ~(long)tcDropFrame;
  590.         
  591.     store->dstTcrec.t.hours = tcHours;
  592.     store->dstTcrec.t.minutes = tcMinutes;
  593.     store->dstTcrec.t.seconds = tcSeconds;
  594.     store->dstTcrec.t.frames = tcFrames;
  595.     BlockMove( &tcSrcName[0], &store->EDLtitle[0], tcSrcName[0]+1 );
  596.  
  597.     DisposeDialog(optionsDialog);
  598. bail:
  599.     SetPort(curPort);
  600. #ifndef DEBUG_LINKED
  601.     UseResFile(curResFile);
  602.     CloseComponentResFile( myResFile );
  603. #endif
  604.     *canceled = (itemHit != ok);
  605.     return retstat;
  606. }
  607.  
  608. void setDialogTextNumber(DialogPtr d, short itemNumber, long number)
  609. {
  610.     Str255 theText;
  611.  
  612.     NumToString(number, theText);
  613.     SetIText((Handle)getDItemHandle(d, itemNumber), theText);
  614.     SelIText(d, itemNumber, 0, 32767);
  615. }
  616.  
  617.  
  618. void setDialogTextString(DialogPtr d, short itemNumber, StringPtr str)
  619. {
  620.     SetIText((Handle)getDItemHandle(d, itemNumber), str);
  621.     SelIText(d, itemNumber, 0, 32767);
  622. }
  623.  
  624. Boolean validateDialogLong(DialogPtr d, short itemNumber, long *result)
  625. {
  626.     Str255 theText;
  627.     OSErr err;
  628.     ControlHandle ch;
  629.     Boolean digitFound;
  630.     short i;
  631.  
  632.     ch = getDItemHandle(d, itemNumber);
  633.  
  634.     GetIText((Handle)ch, theText);
  635.  
  636.     digitFound = false;
  637.     for (i = 1; i < theText[0]; i++) {
  638.         if (theText[i] >= '0' && theText[i] <= '9') 
  639.             digitFound = true;
  640.         else if (digitFound) {
  641.             theText[0] = i-1;
  642.             break;
  643.         }
  644.         else if (theText[i] != ' ') {
  645.             SelIText(d, itemNumber, 0, 32767);
  646.             SysBeep(1);
  647.             return false;
  648.         }
  649.     }
  650.  
  651.     StringToNum( theText, result );
  652.  
  653.     return true;
  654. }
  655.  
  656. ControlHandle getDItemHandle(DialogPtr d, short itemNumber)
  657. {
  658.     short kind;
  659.     ControlHandle ch;
  660.     Rect r;
  661.  
  662.     GetDItem(d, itemNumber, &kind, (Handle *)&ch, &r);
  663.  
  664.     return(ch);
  665. }
  666.  
  667. // •••••••••••••••••••••••••••••••••••••
  668. // Debugging Code starts here
  669. //
  670. // Call the following to the exporter into your code
  671.  
  672.  
  673. #ifdef DEBUG_LINKED
  674. void RegisterExportCMX3600(void);
  675. void RegisterExportCMX3600(void)
  676. {
  677.     ComponentDescription foo;
  678.     EventRecord theEvent;
  679.     Component fooc;
  680.     Handle nameH;
  681.     StringPtr name = {"\pCMX3600 Test"};
  682.  
  683.       foo.componentType = 'spit';
  684.       foo.componentSubType = 'TEXT';
  685.       foo.componentManufacturer = 'tmcd';
  686.       foo.componentFlags = canMovieExportFiles | hasMovieExportUserInterface;
  687.       foo.componentFlagsMask = 0;
  688.  
  689.     nameH = NewHandle(name[0] + 1);
  690.     BlockMove( &name[0], *nameH, name[0]+1 );
  691.  
  692.     fooc = RegisterComponent(&foo, (void *)ExportCMX3600Dispatcher, 0 /* keep it local */, nameH, 0, 0);
  693.  
  694.  
  695.     DisposeHandle( nameH );
  696. }
  697.  
  698. #endif
  699.  
  700.  
  701.  
  702.