home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_progs / sound / algorhyt.lha / source / AlgoRhythms.c next >
C/C++ Source or Header  |  1992-02-21  |  44KB  |  1,169 lines

  1. /*AlgoRhythms.c*/
  2. /*Thomas E. Janzen 4 September 1989; 2-11-90 */
  3. /*18 September 1989 26 nov 89 11 December 1989 16 December 1989*/
  4. /*Music played with this program 
  5. /* Copyright © 1990,1991,1992 Thomas E. Janzen */
  6. /*out the serial port to a single MIDI channel with MAXVOICE voices */
  7. /*The music is randomized by changes slowly by sinusoidal functions */
  8. /* Copyright (c) © 1990, 1991, 1992 by Thomas E. Janzen
  9.    All Rights Reserved
  10.  
  11.    THIS SOFTWARE IS FURNISHED FREE OF CHARGE FOR STUDY AND USE AND MAY
  12.    BE COPIED ONLY FOR PERSONAL USE OR COMPLETELY AS OFFERED WITH NO
  13.    CHANGES FOR FREE DISTRIBUTION.  NO TITLE TO AND OWNERSHIP OF THE
  14.    SOFTWARE IS HEREBY TRANSFERRED.  THOMAS E. JANZEN ASSUMES NO 
  15.    RESPONSBILITY FOR THE USE OR RELIABILITY OF THIS SOFTWARE.
  16.    
  17.    Thomas E. Janzen
  18.    58A School St. Apt. 2-L
  19.    Hudson, MA 01749
  20.    (508)562-1295
  21. */
  22. /*
  23. **  FACILITY:
  24. **
  25. **    AlgoRhythms music improviser on Commodore (TM) Amiga (TM)
  26. **    compiled with SAS/C V5.10b
  27. **
  28. **  ABSTRACT:
  29. **
  30. **    AlgoRhythms.c improvises music.
  31. **
  32. **  AUTHORS: Thomas E. Janzen
  33. **
  34. **  CREATION DATE:    26-MAR-1990
  35. **
  36. **  MODIFICATION HISTORY:
  37. **    DATE    NAME    DESCRIPTION
  38. 1.01  12 Aug 90 T Janzen Shortened Duration string to fit in new gadgets
  39. 1.02   8 Jan 91 Misc. improvements of code; added Events.StopTime
  40. 1.03  11 feb 91 misc. and fixed bug of cut off notes on short scales 
  41. 1.04  23 Feb 91 put back autorequesters using new compile command no crash
  42. 1.05  24 Jul 91 created a custom screen; added quartal and quintal scales;
  43. 1.06  24 SEP 91 use algorhythms.col to define colors, update.
  44. 1.07   3 NOV 91 Use struct timeval for all times until it must be double
  45. 1.08  10 NOV 91 TEJ integers in CHARACTER struct.290 notes/sec @ 16V,64 @ 1
  46. 2.0   26 DEC 91 TEJ Record MIDI and save MIDI standard file
  47.                 Use req.library by Colin Fox and Bruce Dawson
  48.                 Use 20 voices.
  49.       12 JAN 92 Integers for MaxNoteLen and MinNoteLen
  50. **--
  51. */
  52.  
  53. #include    <limits.h>
  54. #include    <math.h>
  55. #include    <stdlib.h>
  56. #include    <stdio.h>
  57. #include    <string.h>
  58. #include    <intuition/intuition.h>
  59. #include    <exec/memory.h>
  60. #include    <exec/interrupts.h>
  61. #include    <exec/devices.h>
  62. #include    <devices/serial.h>
  63. #include <devices/timer.h>
  64. #include    <proto/all.h>
  65. #include    <Workbench/startup.h>
  66. #include    "MusicTimer.h"
  67. #include    "Window.h"
  68. #include    "MusicSerial.h"
  69. #include    "Gadgets.h"
  70. #include    "Files.h"
  71. #include    "DrawForm.h"
  72. #include    "Scales.h"
  73. #include    "Menus.h"
  74. #include "Record.h"
  75. #include <libraries/reqbase.h>
  76. #include <proto/req.h>
  77.  
  78. #define TWOPI    (2 * PI)
  79. #define PROJECT (0)
  80. #define FORM (1)
  81. #define SCALE (2)
  82. #define CHANNEL (3)
  83.  
  84. /* 
  85. ** This type of structure holds the instantaneous values for the range and
  86. ** median pitch, dynamic, duration, and thickness. 
  87. */
  88.  
  89. typedef struct {
  90.     struct timeval StartTime,
  91.                    Duration,
  92.                   StopTime;
  93.     int      Pitch,
  94.              Dynamic,
  95.              Channel,
  96.              CurPitch,
  97.              LowPitch, /* CHANGE THIS IN ALGORHYTHMS.C AND MUSICSERIAL.C*/
  98.              HighPitch,
  99.              Walking,
  100.             Playing;
  101. } NOTEEVENT;
  102.  
  103. typedef struct {
  104.     double   CenterCycle,
  105.              CenterPhase,
  106.              SpreadCycle,
  107.              SpreadPhase;
  108. } PARAMETER;
  109.  
  110. typedef struct {
  111.     int   PitchSpread,    /* range of pitches */
  112.           PitchCenter,    /* ~ median pitch */
  113.           DynamicSpread,    /* range of dynamic levels */
  114.           DynamicCenter,    /* ~ median of dynamic levels */
  115.           DurSpread,       /* range of durations */
  116.           DurCenter,       /* ~ median of durations */
  117.           Thickness;        /* number of voices playing at once */
  118. } CHARACTER;
  119.  
  120. /* 
  121. ** The NOTEEVENT type struct holds information for a given note or MIDI
  122. ** pitch event. 
  123. */
  124.  
  125. /* 
  126. ** If the serial channel fails, fubar is set and the program exits. 
  127. */
  128. #ifdef MEASURE
  129. extern unsigned int NotesTotalMeasure;
  130. #endif
  131. extern int  fubar = FALSE,
  132.             scale[120] = {48,50,53,55,58,60,62,65,67,70,72,74,77};
  133.     /* holds the scale of notes allowed */
  134. static int  playing = FALSE,    /* playing music */
  135.             started = FALSE;    /* Has started playing music */
  136. int done = FALSE,    /* Is done playing because it timed out */
  137.     quit = FALSE;    /* Was told to quit out of the program */
  138. static int  DelayTicks = 2,    /* number of fiftieths of a second to wait */
  139.             EventIndex = 0;    /* Index into Events */
  140. int    range = 10;     /* Pitch Range, really length of scale array */
  141. static int    halfrange = 5;    /* half of range */
  142. static unsigned int  MaxNoteLenms = 2000, /* Max duration of note in ms */
  143.                      MinNoteLenms = 0,    /* Min duration of  note in ms */
  144.                      DifNoteLenms = 2000; /* MaxNoteLenms - MinNoteLenms */
  145. static PARAMETER  Pitch_Form     = {180.0,-PID2,200.0,-PID2},
  146.     /* The periods and phases of mean and range for Pitch */
  147.                   Thickness_Form    = {0.0,    0.0,190.0,-PID2},
  148.     /* The periods and phases of mean and range for Texture */
  149.                   Dynamics_Form    = {170.0,-PID2,165  ,-PID2},
  150.     /* The periods and phases of mean and range for Dynamics */
  151.                   Duration_Form    = {200.0, PID2,180.0, PID2};
  152.     /* The periods and phases of mean and range for Duration */
  153. static int numvoices = MAXVOICE;    /* Total possible numbers of voices */
  154. static struct timeval Sys_Time,
  155.                       Range_Time = {0, 0};
  156. static struct ReqFileRequester file_req;
  157. struct Process    *process;
  158. APTR    old_error_window;
  159. extern struct ReqBase *ReqBase;
  160.  
  161. static double Cvt_Time_Secs (struct timeval *Time);
  162.  
  163. static CHARACTER *ranges (  PARAMETER *Pitch, 
  164.                      PARAMETER *Dyn, 
  165.                      PARAMETER *Dur,  
  166.                       PARAMETER *Thickness, 
  167.                      const struct timeval *Music_Time, CHARACTER *NextNow);
  168. static PARAMETER Randomize_Parameter (void);
  169. static void MakeEvent (NOTEEVENT *, CHARACTER *, 
  170.                        struct timeval *Music_Time); 
  171.                       /* Calculates the next note to send out */
  172. static int ParseMessage (int class, int code, struct timeval *StrTime,
  173.                           PARAMETER *PitchForm, 
  174.                          PARAMETER *RhythmForm,
  175.                           PARAMETER *DynamicsForm, 
  176.                          PARAMETER *TextureForm,
  177.                           struct timeval *Duration, int *tempo, 
  178.                          NOTEEVENT *Events);
  179. #ifdef CLI
  180. int main (int argc, char *argv[]) /* CLI version */
  181. #else
  182. void main (void) /* I/O is all Intuition windows/menus/dialogue boxes */
  183. #endif
  184. {
  185. #ifdef CLI
  186.    char FileString[128];
  187. #else
  188.    static int  code, 
  189.                class,       /* mouse codes esp. for menus */
  190.                signals,
  191.                signal;
  192.    auto struct IntuiMessage *message;
  193. #endif
  194.  
  195.    auto struct timeval   Tenth_Second = {0, 1000000};
  196.    static CHARACTER CurrentStyle;
  197.     register int tick = 0;    /* Index for counting 1/25's of a second*/
  198.     int   tempo,        /* ticks per second */
  199.          i;                /* index */
  200.     auto struct timeval  Music_Time,
  201.                         Start_Time, /*the current time in seconds*/
  202.                          PieceDuration = {600, 0}; /*piece length*/
  203.     static CHARACTER Now;        /* Current instantaneous 
  204.                                 mean and range for the 4 parameters*/
  205.         /* Time in seconds * 2 * pi */
  206.     static NOTEEVENT Events[MAXVOICE];
  207.         /* array of the currently playing notes */
  208.  
  209. #ifndef CLI
  210.     MakeWindow ();        /* Open the window for AlgoRhythms */
  211. #endif
  212.     Open_MIDI_Port ();       /* Open the serial port for MIDI use */
  213.     if (fubar == TRUE) 
  214.    {    
  215.       /* Get out if serial port failed to open */
  216.         goto cleanup2;    /* skip out on failure */
  217.     }
  218. #ifndef CLI
  219.     Init_Menu ();               /* Set up the menu */
  220.     tempo = 50 / DelayTicks;    /* Tempo is pulses per second */
  221.     range = InstallScale (11, scale);    /* Install a musical scale */
  222.     halfrange = range / 2;              /* recalculate halfrange */
  223.    process = (struct Process *)FindTask (NULL);
  224.    old_error_window = process->pr_WindowPtr;
  225.    process->pr_WindowPtr = (APTR)w;
  226. #endif
  227.     for (i = 0; i < MAXVOICE; i++)    /* Initialize the note Events */
  228.     {
  229.         Events[i].Pitch      = halfrange;
  230.         Events[i].Dynamic    = 0.0;
  231.         Events[i].StartTime.tv_micro = Events[i].StartTime.tv_secs = 0;
  232.         Events[i].StopTime.tv_micro  = Events[i].StopTime.tv_secs = 0;
  233.         Events[i].Duration.tv_micro  = Events[i].Duration.tv_secs = 0;
  234.         Events[i].Channel    =   0;
  235.         Events[i].CurPitch   = 60;
  236.         Events[i].LowPitch   = 24;
  237.         Events[i].HighPitch  = 108;
  238.         Events[i].Walking    = FALSE;
  239.       Events[i].Playing    = FALSE;
  240.     }
  241.     /*
  242.    ** set the form of the piece
  243.    */
  244. #ifdef CLI
  245.    if (argc != 2) 
  246.    {
  247.        puts ("usage: AlgoRhythmsCLI {Form_file}\n");
  248.       goto cleanup2;
  249.        exit (1);
  250.    }
  251.    strcpy (FileString, argv[1]);
  252.     i = Read_File (FileString, &PieceDuration,
  253.        &range, scale, &numvoices, &tempo, &Pitch_Form,
  254.         &Thickness_Form, &Dynamics_Form, &Duration_Form, Events,
  255.         &MinNoteLenms, &MaxNoteLenms);
  256.         if (i == 0) 
  257.       {
  258.             if (tempo == 0) 
  259.           {
  260.              DelayTicks = 0;
  261.           }
  262.              else 
  263.           {
  264.                   DelayTicks = 50 / (tempo);
  265.              }
  266.             halfrange = range / 2;
  267.       }
  268. #endif
  269.     StartTimer ();                /* Start timer device */
  270.     GetSysTime (&Sys_Time);            /* Get the time */
  271.     srand (Sys_Time.tv_micro);      /* use microseconds time to seed random */
  272.  
  273.     /* 
  274.    ** Save Time the program started 
  275.    */
  276.    Start_Time = Music_Time;
  277.     Music_Time.tv_micro = Music_Time.tv_secs = 0; /* Set time to zero to start */
  278.    /*Save Time the program started*/
  279.  
  280. #ifndef CLI
  281.     /* Initialize the Form parameters as random */
  282.     Pitch_Form     = Randomize_Parameter ();
  283.     Duration_Form  = Randomize_Parameter ();
  284.     Dynamics_Form  = Randomize_Parameter ();
  285.     Thickness_Form = Randomize_Parameter ();
  286.  
  287.     DrawForm (&PieceDuration, &Pitch_Form, &Duration_Form,
  288.               &Dynamics_Form, &Thickness_Form); /* Draw the Form graph */
  289. #endif
  290.     Now = *ranges (&Pitch_Form, &Dynamics_Form,
  291.                     &Duration_Form, 
  292.                   &Thickness_Form, &Music_Time, &CurrentStyle);
  293.     /* Initialize the ranges (pitch, dynamic, duration) */
  294.  
  295. #ifdef CLI
  296.     started = TRUE;
  297.     done = FALSE;
  298.     SendFunction (STARTFUNCT);
  299. #endif
  300.     /* 
  301.    ** Master Control Loop 
  302.     ** Program stays in here until it quits 
  303.    */
  304.     while ( !(quit)) 
  305.    {    
  306.       /* until you quit */
  307.         GetSysTime (&Sys_Time);
  308.       Music_Time = Sys_Time;
  309.       SubTime (&Music_Time, &Start_Time); /* Music_Time = Now - Start */
  310.  
  311.       /* as long as you are playing */
  312.         while (playing = (!(done) && started) && !(quit)) 
  313.       {
  314.             GetSysTime (&Sys_Time);    /* get the time and convert
  315.                                  to double normalize to
  316.                                  the starting time of the
  317.                                  piece of music*/
  318.          Music_Time = Sys_Time;
  319.          SubTime (&Music_Time, &Start_Time);
  320.             /* 
  321.          ** Get the instantaneous mean & range of
  322.             ** pitch, dynamics, duration, and texture
  323.          */
  324.          if (CmpTime (&Music_Time, &Range_Time) == -1)
  325.          {
  326.                Now = *ranges (&Pitch_Form, &Dynamics_Form, &Duration_Form, 
  327.                         &Thickness_Form, &Music_Time, &CurrentStyle);
  328.             Range_Time = Music_Time;
  329.             AddTime (&Range_Time, &Tenth_Second);
  330.          }
  331.             /* loop through the voices in order*/
  332.             for (EventIndex = 0; EventIndex < numvoices; EventIndex++)
  333.             {    
  334.             /* 
  335.             ** if the previous note in this voice
  336.                 ** is over, then make a new note
  337.             ** Is first parm > than second parm ? 
  338.             */
  339.             if (CmpTime (&Music_Time, &Events[EventIndex].StopTime) == -1)
  340.             {
  341.                     MakeEvent (&Events[EventIndex], &Now, &Music_Time);
  342.                 }
  343.             }
  344.             /* Indicate the time on the form graph */
  345. #ifndef CLI
  346.             DrawTime (&Music_Time, &PieceDuration);
  347.             /* If there is an action, then find out what */
  348.           while (message = (struct IntuiMessage *) GetMsg (w->UserPort))
  349.          {
  350.             class = message->Class;
  351.             code = message->Code;
  352.             ReplyMsg ((struct Message *)message);
  353.             if ((class == MENUPICK) && (code == MENUNULL))
  354.             {
  355.                continue;
  356.             }
  357.                 ParseMessage (class, code, &Start_Time,
  358.                              &Pitch_Form, &Duration_Form, &Dynamics_Form,
  359.                              &Thickness_Form, &PieceDuration, &tempo, Events);
  360.             }
  361. #endif
  362.             /* 
  363.          ** If DelayTicks is not zero then pause to
  364.             ** simulate a regular beat 
  365.          */
  366.             if (DelayTicks) 
  367.          {
  368.                 for (tick = 0; tick < DelayTicks; tick = tick + 2)
  369.                 {
  370.                     /* Send the MIDI timing clock */
  371.                     SendFunction (CLOCKFUNCT);
  372.                     Delay (2); /* wait 2/50's of a sec*/
  373.                 }
  374.             }
  375.             if (done = (CmpTime (&Music_Time, &PieceDuration) == -1))
  376.          {
  377. #ifdef CLI
  378.             quit = done;
  379. #endif
  380.                 /* if the piece is done, stop playing */
  381.                 StopAllNotes (Events);
  382.                 /* re-initialize started */
  383.                 started = FALSE;
  384.             }
  385.         }
  386.         /*
  387.       ** if the piece is playing, then wait, free up AmigaDOS,
  388.         ** until a mouse event hits this window
  389.       */
  390. #ifndef CLI
  391.       signals = 1L << w->UserPort->mp_SigBit;
  392.         signal = Wait (signals);
  393.       if (!(signal & signals))
  394.       {
  395.          continue;
  396.       }
  397.         /* When the event hits, find out what */
  398.        while (message = (struct IntuiMessage *) GetMsg (w->UserPort))
  399.       {
  400.          class = message->Class;
  401.          code = message->Code;
  402.          ReplyMsg ((struct Message *)message);
  403.          if ((class == MENUPICK) && (code == MENUNULL))
  404.          {
  405.             continue;
  406.          }
  407.            ParseMessage (class, code, &Start_Time,
  408.                          &Pitch_Form, &Duration_Form, &Dynamics_Form,
  409.                          &Thickness_Form, &PieceDuration, &tempo, Events);
  410.       }
  411.  
  412. #endif
  413.         continue; /* continue in Master Control Loop until quit */
  414.     }    
  415. cleanup1:            /* normal dump out of the program */
  416. #ifndef CLI
  417.    process->pr_WindowPtr = old_error_window;
  418.     CloseMenu ();        /* shut down menu */
  419. #endif
  420.     StopAllNotes (Events);    /* turn off all the notes */
  421.     Delay (10);        /* wait 1/5 seconds */
  422.     RemoveTimer ();        /* release the timer device */
  423. cleanup2:         /* exit here if the serial port wouldn't open*/
  424. #ifndef CLI
  425.     ShutWindow ();    /* remove the window */
  426. #endif
  427.     StopMIDI ();    /* close the serial device */
  428.    Erase_Recording ();
  429.     exit (0);    /* exit program */
  430. } /* end main*/
  431.  
  432. static CHARACTER *ranges (PARAMETER *Pitch, 
  433.                     PARAMETER *Dyn,
  434.                     PARAMETER *Dur,  
  435.                     PARAMETER *Thickness, 
  436.                     const struct timeval *CurrentTime,
  437.                     CHARACTER *NextNow)
  438.     /* ranges calculates the instantaneous mean and range of
  439.     ** Pitch, Dynamics, Duration, and Thickness.
  440.     ** Inputs:
  441.     ** Pitch : Form parameter
  442.     ** Dyn   : Form parameter
  443.     ** Dur   : Form parameter
  444.     ** Thickness : Form parameter
  445.     ** phase : time * 2 * pi
  446.     ** *NextNow : pointer in which result will be stored
  447.    */
  448. {
  449.     double   realrange,       /* floating-point version of range */
  450.              realhalfrange,    /* floating-point version of halfrange */
  451.             phase;
  452.             
  453.     realrange = (double) range;    /* calculate range */
  454.     realhalfrange = (double) halfrange;/* calculate half of range */
  455.     
  456.    phase = TWOPI * ((double)(CurrentTime->tv_secs) +
  457.              ((double)(CurrentTime->tv_micro) * 0.000001));
  458.    
  459.     NextNow->PitchSpread = (int)((sin ((phase / Pitch->SpreadCycle)
  460.       + Pitch->SpreadPhase) + 1.0) * realhalfrange);
  461.         /*Pitch range is a sin function of time*/
  462.     NextNow->PitchCenter = (int)((sin ((phase / (Pitch->CenterCycle))
  463.       + (Pitch->CenterPhase)) + 1.0) * realhalfrange); 
  464.         /* Median Pitch is a sin funct of time */
  465.     /* 
  466.    ** The following rigamaroll prevents pitch range from
  467.     ** overlapping into non-usable notes (less than 0 and higher
  468.     ** than the top scale note).  It forces the range to be
  469.     ** from top or bottom of the scale through the mean and
  470.     ** an equal distance to the other side
  471.    */
  472.     if ((NextNow->PitchCenter - (NextNow->PitchSpread / 2)) < 0)
  473.    {
  474.         NextNow->PitchCenter = 1 + ((NextNow->PitchCenter
  475.          + (NextNow->PitchSpread / 2)) / 2);
  476.     }
  477.     else
  478.    {
  479.         if ((NextNow->PitchCenter + (NextNow->PitchSpread / 2)) 
  480.          > (double)range) 
  481.       {
  482.             NextNow->PitchCenter = realhalfrange - 1
  483.          + ((NextNow->PitchCenter - (NextNow->PitchSpread / 2)) / 2);
  484.         }
  485.     }
  486.     NextNow->DynamicSpread  = (int)((sin ((phase / (Dyn->SpreadCycle))
  487.                            + Dyn->SpreadPhase) + 1.01) * 63.0);
  488.         /*Range of dynamics is a sin function of time*/
  489.     NextNow->DynamicCenter  = (int)(
  490.       (sin (phase / Dyn->CenterCycle + Dyn->CenterPhase) + 1.01) * 50.0
  491.       + 25.0);
  492.         /*Median dynamic is a sin function of time*/
  493.     NextNow->DurSpread   = (int)(((
  494.                         sin (phase / Dur->SpreadCycle + Dur->SpreadPhase) 
  495.                         + 1.01) / 2.0)
  496.                         * (double)DifNoteLenms);
  497.         /* Range of durations is a sin function of time*/
  498.     NextNow->DurCenter   = (int)
  499.       (
  500.          (
  501.             sin (phase / Dur->CenterCycle + Dur->CenterPhase) + 1.01
  502.          ) / 2.0 * (double)DifNoteLenms
  503.       ) + MinNoteLenms; 
  504.    /*Median duration is a sin function of time*/
  505.     NextNow->Thickness   = (int)(((sin ((phase / (Thickness->SpreadCycle))
  506.                         + Thickness->SpreadPhase) + 1.01) * 
  507.                         (double)numvoices / 2.0) - 1.0);
  508.         /*the number of voices playing is a sin function of time*/
  509.     return NextNow;
  510. }
  511.  
  512. static PARAMETER Randomize_Parameter(void)
  513. {
  514.     /* Returns a randomized parameter of any type */
  515.     PARAMETER Temp;
  516.     register double reallong_max;
  517.     
  518.     reallong_max = (double)LONG_MAX;
  519.     Temp.CenterCycle = ((double)rand () / reallong_max) * 120.0 + 90.0;
  520.         /*1.5 to 3.5 minutes */
  521.     Temp.CenterPhase = ((double)rand () / reallong_max) * TWOPI;
  522.     Temp.SpreadCycle = ((double)rand () / reallong_max) * 120.0 + 90.0;
  523.         /*1.5 to 3.5 minutes */
  524.     Temp.SpreadPhase = ((double)rand () / reallong_max) * TWOPI;
  525.     return Temp;
  526. }
  527.  
  528. static void MakeEvent (NOTEEVENT *NewEvent, CHARACTER *Style, 
  529.                        struct timeval *Music_Time)
  530. /* MakeEvent finds the next note, its duration, and its dynamic, and then*/
  531. /* plays it */
  532. {
  533.     int   LowNote,          /* Boolean flag that the note is as the */
  534.                            /* bottom of the scale */
  535.           HighNote,       /* Boolean flag = note is at top of scale */
  536.           OKRandNote,    /* Boolean flag, not low and not high */
  537.          walk,             /* a direction for the note to walk */
  538.          NewPitchIndex; /* index to the new pitch */
  539.     register double   reallong_max,    /* maximum integer in real form*/
  540.                       reallong_maxdiv2; /* max int/2 */
  541.     int    NewDynamic; /* a temporary holder of a new dynamic value*/
  542.     unsigned int NewDuration;/* a temporary holder of a new duration value*/
  543.    auto struct timeval NewDuration_time;
  544.    
  545.     OKRandNote        = TRUE;                        /* initialize OKRandNote */
  546.     reallong_max      = (double)LONG_MAX;          /* Init */
  547.     reallong_maxdiv2  = reallong_max / 2.0;       /* Init */
  548.    if (NewEvent->Playing)
  549.    {
  550.       NewEvent->Dynamic = 0;
  551.       NewEvent->StopTime = *Music_Time;
  552.       PlayNoteOn (NewEvent);                     /* Turn off the old note */
  553.       NewEvent->Playing = FALSE;
  554.       if (Recording)
  555.       {
  556.          Record_Note_Event (NewEvent);
  557.       }
  558.    }
  559.     if (EventIndex > (int)Style->Thickness)
  560.    {
  561.       return;
  562.    }
  563.    if (Style->DynamicSpread)
  564.    {
  565.       NewDynamic  = (rand () % Style->DynamicSpread) 
  566.                   - (Style->DynamicSpread / 2)
  567.                   + Style->DynamicCenter;
  568.    }
  569.    else
  570.    {
  571.       NewDynamic = Style->DynamicCenter;
  572.    }
  573.    if (NewDynamic > 127)
  574.    {  /*compress dynamic to be valid*/
  575.         NewDynamic = 127;
  576.     }
  577.     if (NewDynamic < 0 )
  578.    {  /*compress dynamic to be valid*/
  579.         NewDynamic = 0;
  580.     }
  581.     NewEvent->Dynamic = NewDynamic; /* make dynamic a byte*/
  582.  
  583.    if (Style->DurSpread)
  584.    {
  585.       NewDuration  = (rand () % Style->DurSpread 
  586.                   - Style->DurSpread / 2
  587.                   + Style->DurCenter);
  588.    }
  589.    else
  590.    {
  591.       NewDuration = Style->DurCenter;
  592.    }
  593.    NewDuration = (NewDuration < MinNoteLenms) ? MinNoteLenms : NewDuration;
  594.    NewDuration = (NewDuration > MaxNoteLenms) ? MaxNoteLenms : NewDuration;
  595.    NewDuration_time.tv_secs = NewDuration / 1000;
  596.    NewDuration_time.tv_micro = (NewDuration * 1000) % 1000000;
  597.    /* 
  598.    ** Put duration in
  599.    ** durations list 
  600.    */
  601.     NewEvent->Duration = NewDuration_time;
  602.     NewEvent->StartTime = *Music_Time;
  603.    NewEvent->StopTime = NewDuration_time;
  604.    AddTime (&NewEvent->StopTime, Music_Time);
  605.  
  606.     if (NewEvent->Walking)
  607.    {  
  608.       /* If the voice is walking */
  609.         HighNote = NewEvent->CurPitch >= NewEvent->HighPitch;
  610.         LowNote  = NewEvent->CurPitch <= NewEvent->LowPitch;
  611.         walk = (rand () % 3) - 1;
  612.         if (LowNote)
  613.       {
  614.             walk = 1;
  615.        }
  616.         if (HighNote)
  617.       {
  618.             walk = -1;
  619.         }
  620.         NewPitchIndex = NewEvent->Pitch + walk;
  621.     }
  622.     else
  623.    {
  624.       if (Style->PitchSpread)
  625.       {
  626.          NewPitchIndex  = rand () % Style->PitchSpread 
  627.                   - Style->PitchSpread / 2
  628.                   + Style->PitchCenter;
  629.       }
  630.       else
  631.       {
  632.          NewPitchIndex = Style->PitchCenter;
  633.       }
  634.         HighNote = (scale[NewPitchIndex] >= NewEvent->HighPitch);
  635.             LowNote  = (scale[NewPitchIndex] <= NewEvent->LowPitch);
  636.             OKRandNote = !HighNote && !LowNote;
  637.         }
  638.         if (NewPitchIndex >= range)
  639.       {
  640.             NewPitchIndex = range - 1; /*fold under if too hi*/
  641.         }
  642.         if (NewPitchIndex < 0)
  643.       {    
  644.             NewPitchIndex = 0;    /*fold up if too low */
  645.       }
  646.         NewEvent->Pitch = (int) NewPitchIndex; /*pitch in note list*/
  647.         NewEvent->CurPitch = scale[(int)NewPitchIndex];
  648.         /*Play the note*/
  649.         if (playing && OKRandNote)
  650.       {
  651.          PlayNoteOn (NewEvent);
  652.          NewEvent->Playing = TRUE;
  653.          if (Recording)
  654.          {
  655.             Record_Note_Event (NewEvent);
  656.          }
  657.       }
  658.    return;
  659. }
  660.  
  661. #ifndef CLI
  662. static int ParseMessage (int class, int code, struct timeval *StrTime,
  663.                           PARAMETER *PitchForm, PARAMETER *RhythmForm,
  664.                           PARAMETER *DynamicsForm, PARAMETER *TextureForm,
  665.                           struct timeval *Duration, int *tempo, 
  666.                          NOTEEVENT Events[MAXVOICE]) 
  667. /* 
  668. ** Parse Message interprets the codes from the menu handler in Menu.c
  669. ** Inputs:
  670. ** class : class of mouse event
  671. ** code  : code of mouse event
  672. ** PitchForm, RhythmForm, DynamicsForm, TextureForm : Form Parameters
  673. ** Duration : length of piece in seconds
  674. ** tempo    : pulses per second
  675. ** Events   : Array of current note events 
  676. */
  677. {
  678.     int   i,
  679.           tempint,
  680.           Status, /* file status */
  681.           item = 0, /* menu item */
  682.           subitem = 0, /* menu subitem */
  683.           Response;
  684. #ifdef MEASURE
  685.    static unsigned char MeasureString[32];
  686.    static struct IntuiText MeasureTxt = {2, 1, JAM2, 15, 10, &font_choice,
  687.          MeasureString, NULL};
  688. #endif
  689.    static NOTEEVENT Reset_Event = {{0,0},{0,0},{0,0},0,0,-1,0,0,0,0,0};
  690.     static struct timeval StopTime;  /* The Time that the music
  691.                                         ** stopped */
  692.     static char AnswerBuf[96], /* string buffer for user to type in */
  693.                MIDI_path[96] = "\0",
  694.                MIDI_dir[96]  = "\0",
  695.                MIDI_file[64] = "\0",
  696.                 form_path[64] = "\0",
  697.                form_dir[96]  = "\0",
  698.                form_file[64] = "\0",
  699.                Title_String[128]  = "\0";
  700.     char *AnsBuf; /* user answer buffer */
  701.     /* Strings for gadgets */
  702.     static char FileNameString[]     = "File Name",
  703.                 DurationString[]     = "Duration(seconds)",
  704.                 PaceString[]         = "Rhythmic Pace",
  705.                 DynamicString[]      = "Dynamics",
  706.                 TextureString[]      = "Texture",
  707.                 PitchString[]        = "Pitch",
  708.                DynamicMean[]        = "Dynamic Mean",
  709.                 DynamicSpread[]      = "Dynamic Spread",
  710.                 TextureSpread[]      = "Texture Spread",
  711.                 PitchMean[]          = "Pitch Mean",
  712.                 PitchSpread[]        = "Pitch Spread",
  713.                 RhythmMean[]         = "Rhythm Mean",
  714.                 RhythmSpread[]       = "Rhythm Spread",
  715.                 VoiceString[]        = "Number of Voices",
  716.                 BlankString[4]       = " ",
  717.                 SpreadPeriodString[] = "Spread Period",
  718.                 MeanPeriodString[]   = "Mean Period",
  719.                 PulseString[]        = "Pulses per Second",
  720.                 TransposeString[]    = "Transpose",
  721.                 load_file_banner[]     = "Load File",
  722.                 save_form_banner[]     = "Save File",
  723.                MIDI_form_banner[]     = "MIDI file",
  724.                 NoteLenmsString[]      = "Note Length",
  725.                 MinimumString[]      = "Minimum",
  726.                 MaximumString[]      = "Maximum",
  727.                 About1String[32]     = "Welcome to AlgoRhythms 2.0",
  728.                 About2String[40] = "Copyright 1992 Thomas E. Janzen",
  729.                 ThanksString[] = "Thanks";
  730.  
  731.     static struct IntuiText About1Txt = 
  732.            {2, 1, JAM2, 5, 4, &font_choice, About1String, NULL},
  733.        About2Txt = 
  734.            {2, 1, JAM2, 5, 15, NULL, About2String, &About1Txt},
  735.       ThanksTxt = {2, 1, JAM1, 5, 4, NULL, ThanksString, NULL};
  736.    
  737.    file_req.dirnamescolor = 2;
  738.    file_req.devicenamescolor = 2;
  739.    
  740.    switch (class) 
  741.    {
  742.        case NEWSIZE: /* Window has been re-sized, so re-draw the graph */
  743.           DrawForm (Duration, PitchForm, RhythmForm, DynamicsForm,
  744.                      TextureForm);
  745.            break;
  746.        case MENUPICK: /* a menu selection was made */
  747.           if (code != MENUNULL)
  748.          {
  749.              item = ITEMNUM(code);
  750.              subitem = SUBNUM(code);
  751.              switch (MENUNUM(code)) 
  752.             {
  753.                 case PROJECT: /* Project menu strip was selected */
  754.                 if (item != NOITEM) 
  755.                switch (item) 
  756.                {
  757.                    case 0: /* quit program */
  758.                       quit = TRUE;
  759.                       break;
  760.                    case 1: /* About copyright notice */
  761.                       Response =  AutoRequest (w, &About2Txt, &ThanksTxt, 
  762.                                        &ThanksTxt, 0L, 0L, 300L, 60L);
  763.                       break;
  764.                   case 2: /* Save MIDI file */
  765.                      if (ReqBase != NULL)
  766.                      {
  767.                         file_req.PathName = MIDI_path;
  768.                         file_req.Dir = MIDI_dir;
  769.                         file_req.File = MIDI_file;
  770.                         if (!FileRequester (&file_req))
  771.                         {
  772.                            break;
  773.                         }
  774.                      }
  775.                      else
  776.                      {
  777.                          Status = GetStringInput (MIDI_path, 
  778.                                                  MIDI_form_banner, 
  779.                               FileNameString);
  780.                           if (Status  == 1) break;
  781.                      }
  782.                      Write_MIDI (MIDI_path);
  783.                      break;
  784.                   case 3: /* Erase */
  785.                      Erase_Recording ();
  786.                      break;
  787.                   case 4: /* Record */
  788.                      Record_Init ();
  789.                      Recording = !Recording;
  790.                      break;
  791.                    case 5: /* Save a form file */
  792.                      if (ReqBase == NULL)
  793.                      {
  794.                          Status = GetStringInput (form_path, 
  795.                                                  save_form_banner, 
  796.                         FileNameString);
  797.                           if (Status)
  798.                         {
  799.                               DisplayBeep (NULL);
  800.                            break;
  801.                         }
  802.                      }
  803.                      else
  804.                      {
  805.                         file_req.PathName = form_path;
  806.                         file_req.Dir = form_dir;
  807.                         file_req.File = form_file;
  808.                         if (!FileRequester (&file_req))
  809.                         {
  810.                            break;
  811.                         }
  812.                      }
  813.                        Status = Save_File (form_path, Duration, 
  814.                                         &range, scale, &numvoices, 
  815.                                          tempo, PitchForm, TextureForm, 
  816.                                          DynamicsForm, RhythmForm, 
  817.                                          Events, MinNoteLenms, 
  818.                                          MaxNoteLenms);
  819.                        if (Status)
  820.                      {
  821.                            DisplayBeep (NULL);
  822.                         break;
  823.                      }
  824.                      strcpy (Title_String, form_path);
  825.                      SetWindowTitles (w, Title_String, (void *) -1L);
  826.                       break;
  827.                    case 6: /* load a form file */
  828.                      if (ReqBase == NULL)
  829.                      {
  830.                         Status = GetStringInput (form_path, 
  831.                                               load_file_banner,
  832.                                                   FileNameString);
  833.                           if (Status)
  834.                         {
  835.                               DisplayBeep(NULL);
  836.                            break;
  837.                         }
  838.                      }
  839.                      else
  840.                      {
  841.                         file_req.PathName = form_path;
  842.                         file_req.Dir = form_dir;
  843.                         file_req.File = form_file;
  844.                         if (!FileRequester (&file_req))
  845.                         {
  846.                            break;
  847.                         }
  848.                      }
  849.                        Status = Read_File (form_path, Duration,
  850.                           &range, scale, &numvoices, tempo, PitchForm,
  851.                           TextureForm, DynamicsForm, RhythmForm, Events,
  852.                           &MinNoteLenms, &MaxNoteLenms);
  853.                        if (!Status) 
  854.                      {
  855.                            if (*tempo == 0) DelayTicks = 0;
  856.                            else 
  857.                         {
  858.                                DelayTicks = 50 / (*tempo);
  859.                            }
  860.                            halfrange = range / 2;
  861.                            DrawForm(Duration, PitchForm, RhythmForm,
  862.                                      DynamicsForm, TextureForm);
  863.                         strcpy (Title_String, form_path);
  864.                         SetWindowTitles (w, Title_String, (void *) -1L);
  865.                         Range_Time.tv_secs 
  866.                         = Range_Time.tv_micro 
  867.                         = 0;
  868.                        }
  869.                      else
  870.                      {
  871.                         DisplayBeep(NULL);
  872.                      }
  873.                       break;
  874.                    case 7: /* Continue after stopping */
  875.                       started = TRUE;
  876.                      PlayNoteOn (&Reset_Event);
  877.                       GetSysTime (&Sys_Time);
  878.                      StrTime->tv_secs = StrTime->tv_secs 
  879.                         + (int)(Sys_Time.tv_secs - StopTime.tv_secs);
  880.                       break;
  881.                    case 8: /* stop the music but don't exit */
  882.                       started = FALSE;
  883.                       for (i = 0; i < MAXVOICE; i++)
  884.                       {
  885.                           Events[i].StartTime.tv_secs 
  886.                            = Events[i].StartTime.tv_micro
  887.                            = 0;
  888.                           Events[i].Duration.tv_secs 
  889.                            = Events[i].Duration.tv_micro
  890.                            = 0;
  891.                         Events[i].StopTime.tv_secs
  892.                            = Events[i].StopTime.tv_micro
  893.                            = 0;
  894.                       }
  895.                        StopAllNotes (Events);
  896.                       GetSysTime (&StopTime);
  897. #ifdef MEASURE
  898.                      sprintf (MeasureString, "%d", NotesTotalMeasure);
  899.                      PrintIText (rp, &MeasureTxt, 1, 1);
  900.                      NotesTotalMeasure = 0;
  901. #endif
  902.                       break;
  903.                    case 9: /* Start to Play music */
  904.                       started = TRUE;
  905.                       done = FALSE;
  906.                       GetSysTime (StrTime);
  907.                      PlayNoteOn (&Reset_Event);
  908.                      for (i = 0; i < MAXVOICE; i++)
  909.                       {
  910.                           Events[i].StartTime.tv_secs 
  911.                            = Events[i].StartTime.tv_micro
  912.                            = 0;
  913.                           Events[i].Duration.tv_secs 
  914.                            = Events[i].Duration.tv_micro
  915.                            = 0;
  916.                         Events[i].StopTime.tv_secs
  917.                            = Events[i].StopTime.tv_micro
  918.                            = 0;
  919.                       }
  920.                       SendFunction (STARTFUNCT);
  921.                      Range_Time.tv_secs 
  922.                         = Range_Time.tv_micro 
  923.                         = 0;
  924.                       break;
  925.                   default:
  926.                      break;
  927.                 } /*switch itemnum*/
  928.                 break;
  929.                 case FORM: /* Form menu strip was selected */
  930.                    if (item != NOITEM) 
  931.                   switch (item) 
  932.                   {
  933.                        case 0: /* note length */
  934.                           if (subitem != NOSUB) 
  935.                            switch (subitem) 
  936.                            {
  937.                                 case 0: /* minimum note length */
  938.                                    sprintf (AnswerBuf, "%5.2f", 
  939.                                        (double)MinNoteLenms / 1000.0);
  940.                                   AnsBuf = GetGadgetInput (AnswerBuf,
  941.                                     NoteLenmsString, MinimumString);
  942.                                    MinNoteLenms 
  943.                                     = (int)(atof (AnsBuf) * 1000.0);
  944.                                    DifNoteLenms 
  945.                                     = MaxNoteLenms - MinNoteLenms;
  946.                                    break;
  947.                                 case 1: /* maximum note length */
  948.                                    sprintf (AnswerBuf, "%5.2f", 
  949.                                     (double)MaxNoteLenms / 1000.0);
  950.                                   AnsBuf = GetGadgetInput (AnswerBuf,
  951.                                             NoteLenmsString, MaximumString);
  952.                                    MaxNoteLenms 
  953.                                     = (int)(atof (AnsBuf) * 1000.0);
  954.                                    DifNoteLenms 
  955.                                     = MaxNoteLenms - MinNoteLenms;
  956.                                    break;
  957.                               default:
  958.                                  break;
  959.                              }
  960.                              break;
  961.                       case 1: /* Texture form set up */
  962.                           if (subitem != NOSUB) 
  963.                            switch(subitem)
  964.                            {
  965.                                 case 0: /* Randomize texture */
  966.                                    *TextureForm = 
  967.                                        Randomize_Parameter ();
  968.                                    break;
  969.                                 case 1: /* Spread Period */
  970.                                    sprintf (AnswerBuf, "%2.0f", 
  971.                                     TextureForm->SpreadCycle);
  972.                                   AnsBuf = GetGadgetInput (AnswerBuf,
  973.                                        TextureString, SpreadPeriodString);
  974.                                    TextureForm->SpreadCycle = atof (AnsBuf);
  975.                                    break;
  976.                                 case 2: /* Spread Phase */
  977.                                    TextureForm->SpreadPhase = 
  978.                                    GetPhaseInput( TextureForm->SpreadPhase, 
  979.                                                 TextureSpread);
  980.                                    break;
  981.                               default:
  982.                                  break;
  983.                              }
  984.                                 break;
  985.                       case 2: /* Dynamic */
  986.                           if (subitem != NOSUB) 
  987.                            switch (subitem) 
  988.                            {
  989.                                 case 0: /* Randomize */
  990.                                    *DynamicsForm = 
  991.                                     Randomize_Parameter ();
  992.                                    break;
  993.                                 case 1: /* Spread Phase*/
  994.                                    DynamicsForm->SpreadPhase = 
  995.                                    GetPhaseInput (
  996.                                        DynamicsForm->SpreadPhase, 
  997.                                        DynamicSpread);
  998.                                    break;
  999.                                 case 2: /* Spread Period */
  1000.                                    sprintf (AnswerBuf,"%2.0f", 
  1001.                                     DynamicsForm->SpreadCycle);
  1002.                                   AnsBuf = GetGadgetInput (AnswerBuf,
  1003.                                                  DynamicString, 
  1004.                                               SpreadPeriodString);
  1005.                                    DynamicsForm->SpreadCycle = atof (AnsBuf);
  1006.                                    break;
  1007.                                 case 3: /* mean Phase */
  1008.                                    DynamicsForm->CenterPhase = 
  1009.                                       GetPhaseInput (
  1010.                                        DynamicsForm->CenterPhase, 
  1011.                                        DynamicMean);
  1012.                                    break; 
  1013.                                 case 4: /* Mean Period */
  1014.                                    sprintf (AnswerBuf, "%2.0f", 
  1015.                                  DynamicsForm->CenterCycle);
  1016.                                    AnsBuf = GetGadgetInput (AnswerBuf,
  1017.                                                   DynamicString, 
  1018.                                                MeanPeriodString);
  1019.                                    DynamicsForm->CenterCycle = atof (AnsBuf);
  1020.                                    break;
  1021.                               default:
  1022.                                  break;
  1023.                              }
  1024.                              break;
  1025.                       case 3: /* Rhythm */
  1026.                          if (subitem != NOSUB) 
  1027.                            switch (subitem) 
  1028.                            {
  1029.                                 case 0: /* Randomize */
  1030.                                    *RhythmForm = 
  1031.                                           Randomize_Parameter ();
  1032.                                       break;
  1033.                                    case 1: /* Spread Phase */
  1034.                                       RhythmForm->SpreadPhase = 
  1035.                                       GetPhaseInput (RhythmForm->SpreadPhase,
  1036.                                                    RhythmSpread);
  1037.                                       break;
  1038.                                    case 2: /* Spread Period */
  1039.                                       sprintf (AnswerBuf, "%2.0f", 
  1040.                                        RhythmForm->SpreadCycle);
  1041.                                      AnsBuf = GetGadgetInput (AnswerBuf, 
  1042.                                        PaceString, SpreadPeriodString);
  1043.                                       RhythmForm->SpreadCycle = atof(AnsBuf);
  1044.                                     break;
  1045.                                    case 3: /* mean Phase */
  1046.                                       RhythmForm->CenterPhase = 
  1047.                                        GetPhaseInput (
  1048.                                        RhythmForm->CenterPhase, 
  1049.                                        RhythmMean);
  1050.                                       break;
  1051.                                    case 4: /* Mean Period */
  1052.                                       sprintf (AnswerBuf, "%2.0f", 
  1053.                                     RhythmForm->CenterCycle);
  1054.                                      AnsBuf = GetGadgetInput (AnswerBuf,
  1055.                                                    PaceString, 
  1056.                                                MeanPeriodString);
  1057.                                       RhythmForm->CenterCycle = 
  1058.                                        atof (AnsBuf); 
  1059.                                       break;
  1060.                                  default:
  1061.                                     break;
  1062.                                }
  1063.                                    break;
  1064.                       case 4: /* Pitch */
  1065.                           if (subitem != NOSUB) 
  1066.                            switch (subitem) 
  1067.                            {
  1068.                                 case 0: /* Randomize */
  1069.                                    *PitchForm = 
  1070.                                  Randomize_Parameter ();
  1071.                                    break;
  1072.                                 case 1: /* Spread Phase */
  1073.                                    PitchForm->SpreadPhase = 
  1074.                                     GetPhaseInput (PitchForm->SpreadPhase,
  1075.                                      PitchSpread);
  1076.                                    break;
  1077.                                 case 2: /* Spread Period */
  1078.                                    sprintf (AnswerBuf, "%2.0f",
  1079.                                  PitchForm->SpreadCycle);
  1080.                                   AnsBuf = GetGadgetInput (AnswerBuf,
  1081.                                        PitchString, SpreadPeriodString);
  1082.                                    PitchForm->SpreadCycle = atof (AnsBuf);
  1083.                                    break;
  1084.                                 case 3: /* mean Phase */
  1085.                                    PitchForm->CenterPhase = GetPhaseInput (
  1086.                                     PitchForm->CenterPhase, PitchMean);
  1087.                                    break;
  1088.                                 case 4: /* Mean Period */
  1089.                                    sprintf (AnswerBuf, "%2.0f",
  1090.                                     PitchForm->CenterCycle);
  1091.                                    AnsBuf = GetGadgetInput(AnswerBuf, 
  1092.                                     PitchString, MeanPeriodString);
  1093.                                    PitchForm->CenterCycle = atof (AnsBuf); 
  1094.                                    break;
  1095.                               default:
  1096.                                  break;
  1097.                              }
  1098.                                       break;
  1099.                       case 5: /* Duration */
  1100.                           sprintf (AnswerBuf, "%2.0f", 
  1101.                            Cvt_Time_Secs (Duration));
  1102.                          AnsBuf = GetGadgetInput (AnswerBuf, BlankString, 
  1103.                                     DurationString);
  1104.                           Duration->tv_secs = (int) atof (AnsBuf);
  1105.                           break;
  1106.                       case 6: /* pulse */
  1107.                           sprintf (AnswerBuf, "%d", *tempo);
  1108.                           AnsBuf = GetGadgetInput (AnswerBuf,
  1109.                                              BlankString, PulseString);
  1110.                           *tempo = abs (atoi (AnsBuf));
  1111.                           if (*tempo == 0) DelayTicks = 0;
  1112.                           else 
  1113.                            DelayTicks = 50 / (*tempo);
  1114.                           break;
  1115.                       case 7: /* ReDraw */
  1116.                          DrawForm (Duration, PitchForm, RhythmForm,
  1117.                                      DynamicsForm, TextureForm);
  1118.                          break;
  1119.                       case 8: /* numvoices */
  1120.                           sprintf (AnswerBuf, "%d", numvoices);
  1121.                           AnsBuf = GetGadgetInput (AnswerBuf,
  1122.                                              BlankString, VoiceString);
  1123.                           tempint = atoi (AnsBuf);
  1124.                           if ((tempint <= MAXVOICE) 
  1125.                            && (tempint > 0))
  1126.                         numvoices = tempint;
  1127.                           else
  1128.                         DisplayBeep (NULL);
  1129.                           break;
  1130.                      default:
  1131.                         break;
  1132.                 } /* switch itemnum */
  1133.                                break;
  1134.                 case SCALE:
  1135.                    if (item != NOITEM) 
  1136.                      switch(item)
  1137.                      {
  1138.                          case 0: /* transpose the scale */
  1139.                             sprintf (AnswerBuf, "0");
  1140.                             AnsBuf = GetGadgetInput (AnswerBuf, BlankString,
  1141.                                                     TransposeString);
  1142.                             TransposeScale (atoi (AnsBuf), scale, range);
  1143.                             break;
  1144.                         default:
  1145.                             range = InstallScale (item, scale);
  1146.                             halfrange = range / 2;
  1147.                       } /* switch itemnum */
  1148.                       break;
  1149.                 case CHANNEL:
  1150.                    GetChannelStuff (&Events[item], item);
  1151.                    break;
  1152.              } /* switch menunum */
  1153.           } /* while not menunull */
  1154.           break;
  1155.           case CLOSEWINDOW:
  1156.               quit = TRUE;
  1157.              break;
  1158.          default:
  1159.             break;
  1160.     } /* switch class */
  1161.    return (0);
  1162. } /* end function */
  1163. #endif
  1164.  
  1165. static double Cvt_Time_Secs (struct timeval *Time)
  1166. {
  1167.    return (double)Time->tv_secs + ((double)Time->tv_micro / 1000000.0);
  1168. }
  1169.