home *** CD-ROM | disk | FTP | other *** search
/ QuickTime 2.0 Developer Kit / QuickTime 2.0 Developer Kit.iso / mac / MAC / Programming Stuff / Sample Code / Media Handlers / TimeCode / TimeCode Samples / ExportCMX3600ƒ / ExportCMX3600.c next >
Encoding:
C/C++ Source or Header  |  1994-12-07  |  20.2 KB  |  720 lines  |  [TEXT/MPS ]

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