home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 11 / develop 11 code / MultiBuffer / MultiBuffer Source / MainApp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-15  |  17.2 KB  |  655 lines  |  [TEXT/MPS ]

  1.  
  2. #pragma load "MacHeaders"
  3.  
  4.  
  5. #ifndef __MAININCLUDES__
  6. #include "MainApp.h"
  7. #endif
  8.  
  9.  
  10. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  11. // The "g" prefix is used to emphasize that a variable is global.
  12.  
  13. //    gInBackground is maintained by our OSEvent handling routines. Any part of
  14. //    the program can check it to find out if it is currently in the background.
  15. Boolean            gInBackground;        // maintained by Initialize and DoEvent
  16.  
  17. //    gAmplitude and gPitch are computed from the current state of the sliders in
  18. //    the main app window.
  19. unsigned char    gAmplitude;
  20. unsigned short    gPitch;
  21. Boolean            gUpdateWave;
  22.  
  23. //    gPrivatePtr gives us a ptr to MultiBuffer's private memory, so we can dispose of it
  24. //    when the play is finished.
  25. Ptr                gPrivatePtr;
  26.  
  27.  
  28.  
  29.  
  30. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  31. // prototypes
  32.  
  33. void        main(void);
  34. void        EventLoop(void);
  35. void        DoEvent(EventRecord *event);
  36. void        DoUpdate(WindowPtr window);
  37. void        DoActivate(WindowPtr window, Boolean becomingActive);
  38. void        DoContentClick(WindowPtr window, EventRecord *event);
  39. void        AdjustMenus(void);
  40. void        DoMenuCommand(long menuResult);
  41. void        DoCloseWindow(WindowPtr window);
  42. void        Terminate(void);
  43. void        Initialize(void);
  44. Boolean        IsDAWindow(WindowPtr window);
  45. long        GetSleep(void);
  46. void        DoIdle(void);
  47. Boolean        FailLowMemory(long memRequested);
  48. void        AlertUser(short errNum, short errStrIndex, Boolean fatal);
  49. void        NewMainWindow(void);
  50. void        DrawMainWindow(WindowPtr window);
  51. void        MainWindowClick(WindowPtr window, EventRecord *event);
  52. pascal void        ScrollAdjust(ControlHandle control, short part);
  53. ControlHandle    FindMyControl(WindowPtr window, short cntlRefCon);
  54.  
  55.  
  56. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  57. //This routine is part of the MPW runtime library. This external reference
  58. // to it is done so that we can unload its segment, %A5Init.
  59.  
  60. extern void _DataInit();
  61.  
  62.  
  63. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  64. void main(void)
  65. {
  66.     UnloadSeg((Ptr) _DataInit);        // _DataInit must not be in the Main code segment
  67.  
  68.     MaxApplZone();                    // expand the heap so code segments load at the top
  69.     Initialize();                    // initialize the program
  70.     EventLoop();                    // call the main event loop
  71. }
  72.  
  73.  
  74. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  75. // Get events forever, and handle them by calling DoEvent. Get the events by
  76. // calling WaitNextEvent.  This is alway available in System 6 or later.
  77. // WaitNextEvent will return false instead of giving up a nullEvent.
  78.  
  79. void EventLoop(void)
  80. {
  81.     EventRecord    event;
  82.  
  83.     while (true) {
  84.         if ( WaitNextEvent(everyEvent, &event, GetSleep(), nil) )
  85.             DoEvent(&event);
  86.         else
  87.             DoIdle();
  88.     }
  89. }
  90.  
  91. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  92. void DoEvent(EventRecord *event)
  93. {
  94.     short        part, err;
  95.     WindowPtr    window;
  96.     char        key;
  97.  
  98.     switch (event->what) {
  99.         case mouseDown:
  100.             part = FindWindow(event->where, &window);
  101.             switch (part) {
  102.                 case inMenuBar:
  103.                     AdjustMenus();                    // bring ’em up-to-date
  104.                     DoMenuCommand(MenuSelect(event->where));
  105.                     break;
  106.                 case inSysWindow:
  107.                     SystemClick(event, window);
  108.                     break;
  109.                 case inContent:
  110.                     if (window != FrontWindow())
  111.                         SelectWindow(window);
  112.                     else
  113.                         DoContentClick(window, event);
  114.                     break;
  115.                 case inDrag:
  116.                     DragWindow(window, event->where, &qd.screenBits.bounds);
  117.                     break;
  118.                 case inGoAway:
  119.                     if (TrackGoAway(window, event->where))
  120.                         HideWindow(window);
  121.                     break;
  122.                 case inGrow:
  123.                     break;
  124.                 case inZoomIn:
  125.                 case inZoomOut:
  126.                     if (TrackBox(window, event->where, part))
  127.                         break;
  128.                 }
  129.             break;
  130.         case keyDown:
  131.         case autoKey:
  132.             key = event->message & charCodeMask;
  133.             if (event->modifiers & cmdKey) {    // Command key down
  134.                 if (event->what == keyDown) {
  135.                     AdjustMenus();                // enable/disable/check menu items properly
  136.                     DoMenuCommand(MenuKey(key));
  137.                 }
  138.             }
  139.             break;
  140.         case activateEvt:
  141.             DoActivate((WindowPtr) event->message, (event->modifiers & activeFlag) != 0);
  142.             break;
  143.         case updateEvt:
  144.             DoUpdate((WindowPtr) event->message);
  145.             break;
  146.         case diskEvt:
  147.             if (HiWrd(event->message) != noErr)
  148.                 err = DIBadMount(kDIPosition, event->message);
  149.             break;
  150.         case osEvt:
  151.             switch (event->message >> 24) {
  152.                 case suspendResumeMessage:        // suspend/resume is also an activate/deactivate
  153.                     gInBackground = (event->message & resumeFlag) == 0;
  154.                     DoActivate(FrontWindow(), !gInBackground);
  155.                     break;
  156.             }
  157.             break;
  158.     }
  159. }
  160.  
  161. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  162. void DoUpdate(WindowPtr window)
  163. {
  164.     SetPort(window);
  165.     BeginUpdate(window);                        // this sets up the visRgn
  166.     if (!EmptyRgn(window->visRgn)) {            // draw if updating needs to be done
  167.  
  168.         PenNormal();                            // get ready for standard drawing
  169.         switch (GetWRefCon(window)) {
  170.  
  171.             case rMainWindow:
  172.                 DrawMainWindow(window);
  173.                 break;
  174.  
  175.         }
  176.     }
  177.     EndUpdate(window);
  178. }
  179.  
  180. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  181. void DoActivate(WindowPtr window, Boolean becomingActive)
  182. {
  183.  
  184. #pragma unused (window)
  185.  
  186.     if (becomingActive) {
  187.     }
  188.     else {
  189.     }
  190. }
  191.  
  192. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  193. void DoContentClick(WindowPtr window, EventRecord *event)
  194. {
  195.  
  196.     switch (GetWRefCon(window)) {
  197.  
  198.         case rMainWindow:
  199.             MainWindowClick(window, event);
  200.             break;
  201.     }
  202. }
  203.  
  204. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  205. // Enable and disable menus based on the current state. The user can only
  206. // select enabled menu items. We set up all the menu items before calling
  207. // MenuSelect or MenuKey, since these are the only times that a menu item can
  208. // be selected. Note that MenuSelect is also the only time the user will see
  209. // menu items. This approach to deciding what enable/ disable state a menu item
  210. // has the advantage of concentrating all the decision-making in one routine,
  211. // as opposed to being spread throughout the application. Other application
  212. // designs may take a different approach that is just as valid.
  213.  
  214. void AdjustMenus(void)
  215. {
  216.     WindowPtr    window;
  217.     MenuHandle    menu;
  218.  
  219.     window = FrontWindow();
  220.  
  221.     menu = GetMHandle(mEdit);
  222.     if ( IsDAWindow(window) ) {                // a desk accessory might need the edit menu
  223.         EnableItem(menu, iUndo);
  224.         EnableItem(menu, iCut);
  225.         EnableItem(menu, iCopy);
  226.         EnableItem(menu, iClear);
  227.         EnableItem(menu, iPaste);
  228.     }
  229.     else {
  230.         DisableItem(menu, iUndo);
  231.         DisableItem(menu, iCut);
  232.         DisableItem(menu, iCopy);
  233.         DisableItem(menu, iClear);
  234.         DisableItem(menu, iPaste);
  235.     }
  236.  
  237. }
  238.  
  239. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  240. // This is called when an item is chosen from the menu bar (after calling
  241. // MenuSelect or MenuKey). It performs the right operation for each command. It
  242. // is good to have both the result of MenuSelect and MenuKey go to one routine
  243. // like this to keep everything organized.
  244.  
  245. void DoMenuCommand(long menuResult)
  246. {
  247.     Str255        daName;
  248.     short        daRefNum;
  249.     short        menuID;
  250.     short        menuItem;
  251.     short        itemHit;
  252.     OSErr        err;
  253.  
  254.     menuID = HiWrd(menuResult);
  255.     menuItem = LoWrd(menuResult);
  256.     switch (menuID) {
  257.         case mApple:
  258.             switch (menuItem) {
  259.                 case iAbout:        // bring up alert for About
  260.                     itemHit = Alert(rAboutAlert, nil);
  261.                     break;
  262.                 default:            // all non-About items in this menu are DAs et al
  263.                     GetItem(GetMHandle(mApple), menuItem, daName);
  264.                     daRefNum = OpenDeskAcc(daName);
  265.                     break;
  266.             }
  267.             break;
  268.         case mFile:
  269.             switch (menuItem) {
  270.                 case iPlay:
  271.                     KillDoubleBuffer ();                                // stop current play and
  272.                     FreeDBPrivateMem (gPrivatePtr);                        // release it's memory
  273.  
  274.                     err = PlayFile(true, &gPrivatePtr);
  275.                     if (err != noErr)
  276.                         AlertUser(err, eUnexpected, !kFatalError);
  277.                     break;
  278.                 case iPlayBackwards:
  279.                     KillDoubleBuffer ();                                // stop current play and
  280.                     FreeDBPrivateMem (gPrivatePtr);                        // release it's memory
  281.  
  282.                     err = PlayFile(false, &gPrivatePtr);
  283.                     if (err != noErr)
  284.                         AlertUser(err, eUnexpected, !kFatalError);
  285.                     break;
  286.                 case iRecord:
  287.                     err = RecordAIFFFile(kAppCreator);
  288.                     if (err != noErr)
  289.                         AlertUser(err, eUnexpected, !kFatalError);
  290.                     break;
  291.                 case iSynthisize:
  292.                     gUpdateWave = true;
  293.                     break;
  294.                 case iKill:
  295.                     KillDoubleBuffer ();                                // stop current play and
  296.                     FreeDBPrivateMem (gPrivatePtr);                        // release it's memory
  297.                     break;
  298.                 case iQuit:
  299.                     Terminate();
  300.                     break;
  301.             }
  302.             break;
  303.     }
  304.     HiliteMenu(0); // unhighlight what MenuSelect (or MenuKey) hilited
  305. }
  306.  
  307. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  308. // Close a window and dispose of any associating data. This handles desk accessory
  309. // and application windows.
  310.  
  311. void DoCloseWindow(WindowPtr window)
  312. {
  313.     if (IsDAWindow(window))
  314.         CloseDeskAcc(((WindowPeek) window)->windowKind);
  315.     else {
  316.         switch (GetWRefCon(window)) {
  317.  
  318.             case rMainWindow:
  319.                 DisposeWindow(window);
  320.                 break;
  321.         }
  322.     }
  323. }
  324.  
  325. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  326. void Terminate()
  327. {
  328.     WindowPtr    aWindow;
  329.  
  330.     do {
  331.         aWindow = FrontWindow();                // get the current front window
  332.         if (aWindow != nil)
  333.             DoCloseWindow(aWindow);                // close this window
  334.     } while (aWindow != nil);
  335.  
  336.     CloseDoubleBuffer();
  337.     ExitToShell();                                // exit if no cancellation
  338. }
  339.  
  340. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  341. void Initialize()
  342. {
  343.     Handle            menuBar;
  344.     EventRecord     event;
  345.     short            count;
  346.     OSErr            err;
  347.     long            response;
  348.  
  349.     gInBackground = false;
  350.     
  351.     gPrivatePtr = nil;
  352.  
  353.     InitGraf(&qd.thePort);
  354.     InitFonts();
  355.     InitWindows();
  356.     InitMenus();
  357.     TEInit();
  358.     InitDialogs(nil);
  359.     InitCursor();
  360.  
  361.     // bring the app to the foreground
  362.     for (count = 1; count <= 3; count++)
  363.         EventAvail(everyEvent, &event);
  364.  
  365.     // I want to know if WaitNextEvent is available, which is always true for
  366.     // System 6.02 or later.  I should be checking for this trap to be implimented,
  367.     // but I also don't trust any Sound Manager that was shipped privous to 6.02.
  368.     // Since I checked for this version of the system I know that WaitNextEvent is
  369.     // there, but otherwise I would be checking for the features that I want
  370.     // and not for the system version.
  371.  
  372.     err = Gestalt(gestaltSystemVersion, &response);
  373.     if (err != noErr)
  374.         AlertUser(err, eSystemTooOld, kFatalError);
  375.     else
  376.         if (response < kOldestSystemAllowed)
  377.             AlertUser(err, eSystemTooOld, kFatalError);
  378.  
  379.  
  380.     menuBar = GetNewMBar(rMenuBar);
  381.     if (menuBar == nil)
  382.         AlertUser(MemError(), eNoMenuBar, kFatalError);
  383.     SetMenuBar(menuBar);
  384.     DisposHandle(menuBar);
  385.     AddResMenu(GetMHandle(mApple), 'DRVR');
  386.     DrawMenuBar();
  387.  
  388.     NewMainWindow();
  389.  
  390.     err = InitDoubleBuffer();
  391.     if (err != noErr)
  392.         AlertUser(err, eUnexpected, kFatalError);
  393.  
  394.     // test for minimal memory requirements after allocating application's stuff
  395.     if (FailLowMemory(kMinHeap))
  396.         AlertUser(0, eNoMemory, kFatalError);
  397.         
  398.  
  399.     //    Make sure we have rational values for the amplitude and pitch globals.
  400.     gPitch = kPitchDefault;
  401.     gAmplitude = kAmpDefault;
  402.     
  403.     //    Don't need a wave table until asked for it...
  404.     gUpdateWave = false;
  405. }
  406.  
  407. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  408. // Check to see if a window belongs to a desk accessory.
  409.  
  410. Boolean    IsDAWindow(WindowPtr window)
  411. {
  412.     if (window)                                // DA windows have negative windowKinds
  413.         return (((WindowPeek) window)->windowKind < 0);
  414.     else
  415.         return false;
  416. }
  417.  
  418. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  419. //    Calculate a sleep value for WaitNextEvent. This takes into account the things
  420. //    that DoIdle does with idle time.
  421.  
  422. long GetSleep(void)
  423. {
  424.     if (gInBackground)
  425.         return (kBackSleep);
  426.     else
  427.         return (kForeSleep);
  428. }
  429.  
  430. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  431. void DoIdle(void)
  432. {
  433.     WindowPtr        window;
  434.     WaveCyclePtr    wave;
  435.     long            finalTick;
  436.  
  437.     window = FrontWindow();
  438.     
  439.     if (gUpdateWave == true) {
  440.         // Should probably set a watch cursor here...
  441.  
  442.         wave = NewWaveForm (gAmplitude,gPitch);
  443.         
  444.         KillDoubleBuffer ();                                // stop current play and
  445.  
  446.         FreeDBPrivateMem (gPrivatePtr);                        // release it's memory
  447.         
  448.         Delay (20, &finalTick);                                // Let current play complete
  449.  
  450.         PlayWave (88000, wave, &gPrivatePtr);                //    About four seconds...
  451.         
  452.         gUpdateWave = false;
  453.     }    
  454. }
  455.  
  456. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  457. Boolean FailLowMemory(long memRequested)
  458. {
  459.     long        total;
  460.     long        contig;
  461.  
  462.     PurgeSpace(&total, &contig);
  463.     return ( total < (memRequested + kMinSpace) );
  464. }
  465.  
  466. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  467. void AlertUser(short errNum, short errStrIndex, Boolean fatal)
  468. {
  469.     short        itemHit;
  470.     Str255        msg1;
  471.     Str255        msg2;
  472.  
  473.     if (errNum != userCanceledErr) {                        // ignore cancels
  474.         SetCursor(&qd.arrow);
  475.         if (errNum)
  476.             NumToString(errNum, msg1);
  477.         else
  478.             *msg1 = 0;                                        // set length to zero
  479.         GetIndString(msg2, rErrStrings, errStrIndex);
  480.         ParamText(msg1, msg2, "\p", "\p");
  481.         itemHit = Alert(rUserAlert, nil);
  482.         if (fatal)
  483.             ExitToShell();
  484.     }
  485. }
  486.  
  487. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  488. void NewMainWindow(void)
  489. {
  490.     ControlHandle    control;
  491.     WindowPtr        window;
  492.     StringHandle    strHandle;
  493.  
  494.     window = (WindowPtr) NewPtr(sizeof(MainWindow));
  495.     if (window == nil)
  496.         AlertUser(MemError(), eNoWindow, kFatalError);
  497.     window = GetNewWindow(rMainWindow, window, (WindowPtr)-1);
  498.     if (window == nil)
  499.         AlertUser(MemError(), eNoWindow, kFatalError);
  500.     SetPort(window);
  501.     TextFont(systemFont);
  502.     SetWRefCon(window, rMainWindow);
  503.  
  504.     control = GetNewControl(rAmpButton, window);
  505.     if (control == nil)
  506.         AlertUser(MemError(), eNoWindow, kFatalError);
  507.     SetCRefCon(control, rAmpButton);
  508.  
  509.     control = GetNewControl(rPitchButton, window);
  510.     if (control == nil)
  511.         AlertUser(MemError(), eNoWindow, kFatalError);
  512.     SetCRefCon(control, rPitchButton);
  513.  
  514.     strHandle = GetString(rAmpString);
  515.     if (strHandle == nil)
  516.         AlertUser(ResError(), eResourceErr, kFatalError);
  517.     ((MainWindowPtr)window)->ampString = strHandle;
  518.  
  519.     strHandle = GetString(rPitchString);
  520.     if (strHandle == nil)
  521.         AlertUser(ResError(), eResourceErr, kFatalError);
  522.     ((MainWindowPtr)window)->pitchString = strHandle;
  523.  
  524.     ShowWindow(window);
  525. }
  526.  
  527. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  528. void DrawMainWindow(WindowPtr window)
  529. {
  530.     ControlHandle    control;
  531.     Rect            drawArea;
  532.  
  533.     UpdateControls(window, window->visRgn);
  534.     control = FindMyControl(window, rAmpButton);
  535.     if (control != nil) {
  536.         drawArea = (**control).contrlRect;
  537.         OffsetRect(&drawArea, 0, kControlTextOffset);
  538.         TextBox(*((MainWindowPtr)window)->ampString + 1,
  539.                     Length(*((MainWindowPtr)window)->ampString), &drawArea, teJustCenter);
  540.     }
  541.     control = FindMyControl(window, rPitchButton);
  542.     if (control != nil) {
  543.         drawArea = (**control).contrlRect;
  544.         OffsetRect(&drawArea, 0, kControlTextOffset);
  545.         TextBox(*((MainWindowPtr)window)->pitchString + 1,
  546.                     Length(*((MainWindowPtr)window)->pitchString), &drawArea, teJustCenter);
  547.     }
  548. }
  549.  
  550. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  551. void MainWindowClick(WindowPtr window, EventRecord *event)
  552. {
  553.     Point            mouse;
  554.     ControlHandle    control;
  555.     short            part;
  556.     short            oldValue;
  557.  
  558.     SetPort(window);
  559.     mouse = event->where;                            // get the click position
  560.     GlobalToLocal(&mouse);
  561.  
  562.     part = FindControl(mouse, window, &control);
  563.     if (part != 0) {                                // check for a hit
  564.  
  565.         switch (GetCRefCon(control)) {
  566.  
  567.             case rAmpButton:
  568.                 if (part == inThumb)
  569.                     TrackControl(control, mouse, nil);
  570.                 else
  571.                     TrackControl(control, mouse, (ProcPtr)ScrollAdjust);
  572.                 oldValue = gAmplitude;                // save amplitude value
  573.                 gAmplitude  = GetCtlValue(control);
  574.                 
  575.                 //    Since recalculating the wave form may take a while, make sure
  576.                 //    the value has actually changed...
  577.                 if (oldValue != gAmplitude)
  578.                     gUpdateWave = true;
  579.                     
  580.                 break;
  581.  
  582.             case rPitchButton:
  583.                 if (part == inThumb)
  584.                     TrackControl(control, mouse, nil);
  585.                 else
  586.                     TrackControl(control, mouse, (ProcPtr)ScrollAdjust);
  587.                 oldValue  = gPitch;                    // save pitch value
  588.                 gPitch = GetCtlValue(control);
  589.                 
  590.                 //    Since recalculating the wave form may take a while, make sure
  591.                 //    the value has actually changed...
  592.                 if (oldValue != gAmplitude)
  593.                     gUpdateWave = true;
  594.  
  595.                 break;
  596.         }
  597.     }
  598. }
  599.  
  600. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  601. pascal void ScrollAdjust(ControlHandle control, short part)
  602. {
  603.     short        curValue;
  604.     short        minValue;
  605.     short        maxValue;
  606.  
  607.     curValue = GetCtlValue(control);
  608.     minValue = GetCtlMin(control);
  609.     maxValue = GetCtlMax(control);
  610.  
  611.     switch (part) {
  612.  
  613.         case inUpButton:
  614.             if (curValue > minValue)
  615.                 SetCtlValue(control, curValue - 1);
  616.             break;
  617.         case inDownButton:
  618.             if (curValue < maxValue)
  619.                 SetCtlValue(control, curValue + 1);
  620.             break;
  621.         case inPageUp:
  622.             curValue -= 5;
  623.             if (curValue < minValue)
  624.                 curValue = minValue;
  625.             if (curValue >= minValue)
  626.                 SetCtlValue(control, curValue);
  627.             break;
  628.         case inPageDown:
  629.             curValue += 5;
  630.             if (curValue > maxValue)
  631.                 curValue = maxValue;
  632.             if (curValue <= maxValue)
  633.                 SetCtlValue(control, curValue);
  634.             break;
  635.     }
  636.  
  637. }
  638.  
  639. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  640. ControlHandle FindMyControl(WindowPtr window, short cntlRefCon)
  641. {
  642.     ControlHandle        cntlHandle;
  643.  
  644.     cntlHandle = ((WindowPeek)(window))->controlList;
  645.     while (cntlHandle != nil) {
  646.         if (GetCRefCon(cntlHandle) != cntlRefCon)
  647.             cntlHandle = (**cntlHandle).nextControl;
  648.         else
  649.             break;
  650.     }
  651.     return (cntlHandle);
  652. }
  653.  
  654.  
  655.