home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d7xx / d787 / scale.lha / Scale / Source.lha / scale2.c < prev    next >
C/C++ Source or Header  |  1992-12-12  |  14KB  |  498 lines

  1. /* Program Scale2.c -- calls to "atool31" and "PlayNote" in atool31.c */
  2.  
  3. /*   ==>  RECOMMENDED <== */
  4. /*    Set tab interval to 3 for listing of this code */
  5.  
  6. /* Programmer:  Dick Taylor               November 1992 */
  7. /*              99 Valley View Rd, Glastonbury CT 06033 USA */
  8.  
  9. /* Please refer to file scale.doc for usage and background. */
  10.  
  11. #include <exec/types.h>
  12. #include <intuition/intuition.h>
  13. #include <exec/ports.h>
  14. #include <devices/timer.h>
  15.  
  16. #define SECONDS tr_time.tv_secs
  17. #define MICROSECONDS tr_time.tv_micro
  18.  
  19. extern int  PlayNote(), atool31(), StartChans();
  20. extern char Key, Key2, Note[4], TimeV[4], ttext[];
  21. extern int  Octave[4], Tempo;
  22. extern struct            /* Ascend/Descend structure */
  23. {
  24.     char ad[15];    /* For each of 4 channels, we have */
  25.     int  ct[15];    /* 15 pairs of A/D/R and count, 14 are usable */
  26. }    zChan[4];
  27. extern BOOL fin, cycle;
  28. extern struct Gadget stop_gadget;
  29. extern struct PropInfo tempo_info;
  30. extern struct Gadget tempo_gadget;
  31. extern struct IntuiText tp_text;
  32. extern struct IntuiText stext_request;
  33. extern struct IntuiText sok_request;
  34. extern struct Window *w;
  35.  
  36. int Increm[4],        /* Increment, either 0 or -12; per channel */
  37.     ADRsig[4],        /* Ascend(1)/Descend(-1)/Rest(0) signal; per chan */
  38.     iADR[4],            /* Position in ADR array; per chan */
  39.     zCt[4],            /* ADR Count for current ADR step; per chan */
  40.     ProtoScale[4][8],    /* Prototype Scale notes, per channel */
  41.     RelTime[4],        /* Relative Time, either 1, 2, or 4; per chan */
  42.     Vol[4],            /* Volume; per chan.  50 = play   0 = rest */
  43.     Duration[4],    /* Note Duration; per chan.  500 = .5 sec */
  44.     iScale = 1,        /* In playing scales after the first octave -- */
  45.                         /* 1 = play 7 notes   0 = play 8 notes, all chan's */
  46.     jScale;            /* Same usage as iScale */
  47.  
  48. char aCh;        /* Temp -- char: A, D, R, + */
  49.  
  50. BOOL Desc[4],    /* Descending flag T or F; per chan */
  51.     SaveDesc[4],    /* Save Descending flag T or F; per chan */
  52.     Play[4],        /* Play flag T or F; per chan */
  53.     PFlag[4],    /* Play Flag: T for A or D, F for R; per chan */
  54.     Repeat=FALSE,    /* Repeat Flag: T if any chan is repeating (+) */
  55.     ChRep[4],        /* Chan Repeat Flag: T if chan repeating (+); per chan */
  56.     rtn;            /* Flag -- Default F; T if user signals to stop Play */
  57.  
  58. /* This program uses the TimerDevice to time each 1/1 octave, so that */
  59. /* all notes will be synchronized at the start of each 1/1 octave. */
  60.  
  61. int secs,        /* Total Wait time for 1/1 octave, in microseconds */
  62. /* Specify time in seconds (xx.yyy) to Timer Device in 2 parts -- */
  63.     I_secs,        /* Whole-number seconds -- xx (integer)*/
  64.     M_secs,        /* Fractional seconds -- yyy in microseconds */
  65.     TimingFF = 10000;        /* Timing Fudge Factor -- empirically */
  66.                     /* determined value (= .01 sec), subtracted from secs, */
  67.                     /* to smooth transition from one octave to the next. */
  68.  
  69. struct
  70. {
  71.     int Pitch[32];        /* Structure/array for saving one set of notes */
  72.     int Volume[32];    /* before sending them to PlayNote. */
  73. } Chan[4];                /* One set = either 1, 2, or 4 octaves of notes, */        
  74.                             /* depending on Relative Time value -- RelTime[] */
  75. int kPV[4];                /* Position counters -- Pitch/Vol, per Chan */
  76.  
  77.  
  78.  
  79.  
  80. PlayScale()
  81. {
  82.  int c,        /* Channel -- 0, 1, 2, 3 */
  83.     i,j,m,n;        /* Local variables */
  84.  BOOL First = TRUE;
  85.  
  86. struct Message *Tmsg;            /* TimerDevice message */
  87. ULONG wakebits,IDCMPsig,TIMERsig;
  88. BOOL ErrOpenTimer = TRUE,err;
  89. int val;
  90.  
  91. struct timerequest *tr;    /* Request Block Pointer */
  92. struct MsgPort  *tp;    /* Port Pointer */
  93. struct MsgPort  *CreatePort();
  94.  
  95.  tp = (struct MsgPort *) CreatePort(0,0);    /* Create Port for TimerDevice */
  96.  if (tp == 0)
  97.  {
  98.     stext_request.IText = 
  99.             "Module scale2: Can't create port for TimerDevice; exit.";
  100.     AutoRequest(w,&stext_request,NULL,&sok_request,NULL,NULL,640,72);
  101.     goto StopPlay;
  102.  }
  103.  
  104.  tr = NULL;        /* Create TimerDevice request block */
  105.  tr = (struct timerequest *) CreateExtIO(tp,sizeof(struct timerequest));
  106.  if (tr == 0)
  107.  {
  108.     stext_request.IText = 
  109.             "Module scale2: Can't create request block for TimerDevice; exit.";
  110.     AutoRequest(w,&stext_request,NULL,&sok_request,NULL,NULL,640,72);
  111.     goto StopPlay;
  112.  }
  113.  
  114.  ErrOpenTimer = OpenDevice(TIMERNAME,UNIT_VBLANK,tr,0);    /* Open Timer Device */
  115.  if (ErrOpenTimer)
  116.  {
  117.     stext_request.IText = 
  118.             "Module scale2: Can't open TimerDevice; exit.";
  119.     AutoRequest(w,&stext_request,NULL,&sok_request,NULL,NULL,640,72);
  120.     goto StopPlay;
  121.  }
  122.  
  123.  atool31(0);        /* Initialize the AudioTools system */
  124.  StartChans();        /* Start channels -- will play when receive notes */
  125.  
  126.  IDCMPsig = 1<<w->UserPort->mp_SigBit;    /* IDCMP signal bit */
  127.  TIMERsig = 1<<tp->mp_SigBit;                /* TimerDevice signal bit */
  128.  rtn = FALSE;
  129.  
  130.  err = Prelims();    /* Convert some input items to AudioTools numeric form: */
  131.                     /* Key Note; per chan -- First Note, prototype scale notes  */ 
  132.  if (err) goto StopPlay;
  133.  
  134.                 /* This major loop plays the scales.  */
  135. do                /* do-while loop -- repeats when cycle = TRUE */
  136. {
  137.     Setup();    /* For each chan, initialize variables & flags */
  138.  
  139.             /* This loop plays one time through all scale spec's */
  140.             /* It continues to loop as long as any non-+ chan's are active */
  141.     while (zCt[0]+zCt[1]+zCt[2]+zCt[3] > 0)
  142.     {
  143.         GetNotes();    /* Calc 1 set of notes for all chan's; save in array. */
  144.                         /* 1 set of notes = Either 1, 2, or 4 octaves per chan, */
  145.                         /* depending on value of RelTime[] 1, 2, or 4 */
  146.  
  147.         if (First)
  148.             First = FALSE;
  149.         else
  150.         {
  151. WaitAgain:                    /* Wait for IDCMP signal or Timer signal */
  152.             wakebits = Wait(IDCMPsig | TIMERsig);
  153.  
  154.             if (wakebits & IDCMPsig)
  155.             {
  156.                 DoIDCMP();            /* Process IDCMP message(s) */
  157.             }
  158.  
  159.             if (wakebits & TIMERsig)
  160.                 while (Tmsg = (struct Message *) GetMsg(tp))
  161.                     /* Receive Timer message, do nothing */ ;
  162.             else goto WaitAgain;
  163.  
  164.             if (rtn == TRUE)
  165.                 goto StopPlay;
  166.         }
  167.  
  168.                                                 /* Start the Timer Device */
  169.         tr->tr_node.io_Command = TR_ADDREQUEST;
  170.         tr->SECONDS = I_secs;
  171.         tr->MICROSECONDS = M_secs;
  172.         SendIO(tr);            /* Send Timer command to system */
  173.  
  174.         PlayIt();        /* Send notes from array to PlayNote in AudioTools */
  175.  
  176.         jScale = iScale;
  177.     }            /* Close while loop (zCt[0]+zCt[1]+...) */
  178.  }            /* Close do-while loop */
  179.  while (cycle);
  180.  
  181.  Delay(secs/20000 + 1);        /* Wait for last octave to finish */
  182.                                 /* Delay for length of last Timer interval */
  183.  
  184.  while (Tmsg = (struct Message *) GetMsg(tp))
  185.     /* Receive last Timer message, do nothing */ ;
  186.  
  187. StopPlay:
  188.  
  189.  atool31(1);        /* Close down the sound system */
  190.  if (!ErrOpenTimer) CloseDevice(tr);    /* Close TimerDevice */ 
  191.  if (tr) DeleteExtIO(tr,sizeof(struct timerequest));    /* Delete IO Block */
  192.  if (tp)  DeletePort(tp);    /* Delete Port */
  193. }        /* Close function PlayScale() */
  194.  
  195.  
  196. Prelims()        /* Convert some input items to AudioTools numeric form: */
  197.                     /* Key Note; per chan -- First Note, prototype scale notes  */ 
  198. {
  199.  int 
  200.     i,j,m,n,        /* Local variables */
  201.     FNInt,        /* First Note Interval, from key note */
  202.     KeyNote,        /* Key Note -- starting note (0-6) for current key  */
  203.     KeyNoteInt;        /* Key Note Interval -- interval to find starting note */
  204.  static  ScaleInt[8] = {0,2,2,1,2,2,2,1};    /* Intervals major scale */
  205.  char tempKey;
  206.  
  207.             /* Find the Key note */
  208. KeyNote = (Key - 'A' + 5) % 7;    /* Conv Key CDEFGAB to digit 0-6 */
  209.                 /* (0 = C, 1 = D, ... , 6 = B) */
  210. KeyNoteInt = 0;
  211. for (j = 0; j <= KeyNote; ++j)
  212.    KeyNoteInt += ScaleInt[j];        /* Convert Key code to Key note interval */
  213.  
  214. if (Key2 == '#') KeyNoteInt += 1;
  215. else if (Key2 == 'b') KeyNoteInt -= 1;
  216.  
  217.  iScale = 1;
  218.  for (i = 0; i < 4; ++i)
  219.  {
  220.     ChRep[i] = FALSE;
  221.     RelTime[i] = TimeV[i] - '0';        /* Conv char 1/2/4 to integer */
  222.     if (zChan[i].ad[0] != ' ' && (RelTime[i] == 2 || RelTime[i] == 4)) iScale = 0;
  223.     Duration[i] = Tempo / RelTime[i];    /* Get note duration */
  224.  
  225.     FNInt = 0;    /* Find interval from Key note to first note */
  226.     tempKey = Key; n = 0;
  227.     if (Note[i] != ' ')
  228.     while (tempKey != Note[i])    /* Step up key to reach Note[] */
  229.     {
  230.         n += 1;
  231.         FNInt += ScaleInt[n];        /* FNInt = note interval from Key note */
  232.         tempKey += 1;            /* Increm temp key */
  233.         if (tempKey > 'G') tempKey = 'A';
  234.         if (n > 7) 
  235.         {
  236.             stext_request.IText = 
  237.                 "Module scale2: program error finding 1st note. Exit";
  238.             AutoRequest(w,&stext_request,NULL,&sok_request,NULL,NULL,640,72);
  239.             return(TRUE);    /* Exit signal */
  240.         }
  241.     }
  242.     
  243.     ProtoScale[i][0] = 12*(Octave[i]-1) + KeyNoteInt + FNInt;    /*Get 1st note of scale */
  244.  
  245.     m = 1 + n;
  246.  
  247.     for (j = 1; j < 8; ++j)
  248.     {    ProtoScale[i][j] = ProtoScale[i][j-1] + ScaleInt[m];    /* Rest of scale notes */
  249.         m += 1;
  250.         if (m > 7) m = 1;
  251.     }
  252.  }
  253. return(FALSE);    /* OK return */
  254. }        /* Close function Prelims() */
  255.  
  256.  
  257.  
  258. Setup()        /* For each chan, initialize variables & flags */
  259. {                /* needed to play the scales */
  260.  int i;
  261.  char a;
  262.  
  263. jScale = 0;
  264. for (i = 0; i < 4; ++i)
  265. {
  266.     iADR[i] = 0;        /* position in A/D series */
  267.     zCt[i] = 0;
  268.     aCh = zChan[i].ad[0];
  269.     if (aCh == ' ') Play[i] = FALSE;    /* Chan doesn't play */
  270.   else
  271.   {
  272.     Play[i] = TRUE; 
  273.     PFlag[i] = TRUE;
  274.     if (aCh == 'D')                /* Descend */
  275.     {    Desc[i] = TRUE;
  276.         Increm[i] = -12;
  277.         ADRsig[i] = -1;
  278.     }
  279.     else if (aCh == 'A')            /* Ascend */
  280.             {    Desc[i] = FALSE; 
  281.                 Increm[i] = 0; 
  282.                 ADRsig[i] = 1;
  283.             }
  284.             else                        /* Rest */
  285.             {    ADRsig[i] = 0;
  286.                 PFlag[i] = FALSE;
  287.             }
  288.  
  289.     zCt[i] = zChan[i].ct[0];    /* Count for first A/D */
  290.     SaveDesc[i] = Desc[i];
  291.   }
  292.  }
  293. }        /* Close function Setup() */
  294.  
  295.  
  296.  
  297. GetNotes()        /* Calc 1 set of notes for all chan's; save in array. */
  298.                     /* 1 set of notes = Either 1, 2, or 4 octaves per chan, */
  299.                     /* depending on value of RelTime[] 1, 2, or 4 */
  300. {
  301.  int c,i,j,m,n,p;        /* local variables */
  302.  
  303.     secs = (Tempo * (8-jScale)) * 1000;    /* Total Wait time in microsecs */
  304.     secs -= TimingFF;        /* Empirical fudge factor */
  305.                                     /* Divide Wait time into 2 parts -- */
  306.     I_secs = secs / 1000000;    /* Whole number (integer) seconds */
  307.     M_secs = secs % 1000000;    /* Fractional part in microsecs */
  308.  
  309.     for (i = 0; i < 4; ++i)
  310.     {
  311.         kPV[i] = 0;                /* Reset channel note position counters */
  312.         if (ADRsig[i] == 0) Vol[i] = 0;    /* Set volume for each channel */
  313.         else Vol[i] = 50;                /* 0 = rest, 50 = play */
  314.     }
  315.  
  316.     for (j = jScale; j < 8; ++j)    /* Play 8 or 7 scale notes */
  317.                                     /* jScale value: 0 = 8 note scale, 1 = 7 notes */
  318.     {
  319.         for (c = 0; c < 4; ++c)        /* Four channels */
  320.         {
  321.             if (Play[c])
  322.             {
  323.                 n = j * RelTime[c];
  324.                 for (i = 0; i < RelTime[c]; ++i)
  325.                 {
  326.                     m = (n + i) % 8;
  327.                     if (Desc[c]) m = 7 - m;
  328.                     p = ProtoScale[c][m] + Increm[c];
  329.                     Chan[c].Pitch[kPV[c]] = p;    /* Save pitch in struct/array */
  330.                     Chan[c].Volume[kPV[c]] = Vol[c];    /* Save volume */
  331.                     kPV[c] += 1;
  332.                 }
  333.             }
  334.             if (Play[c])
  335.             {
  336.                 if (RelTime[c] == 2 && j == 3) CheckAD(c);
  337.                 if (RelTime[c] == 4 && j != 7 && j%2 == 1) CheckAD(c);
  338.             }
  339.         }        /* Close channel loop c */
  340.     }            /* Close scale loop j */
  341.  
  342.     for (i = 0; i < 4; ++i)
  343.         kPV[i] = 0;                /* Reset channel note position counters */
  344. }        /* Close function GetNotes() */
  345.  
  346.  
  347.  
  348. DoIDCMP()    /* Process IDCMP message(s) */
  349. {
  350.     struct IntuiMessage *Imsg;        /* IDCMP message */
  351.     ULONG class;
  352.     struct Gadget *address;
  353.     int i, val;
  354.  
  355.     while (Imsg = (struct IntuiMessage *) GetMsg(w->UserPort))
  356.     {
  357.         class = Imsg->Class;
  358.         address = Imsg->IAddress;
  359.         ReplyMsg(Imsg);
  360.         switch (class)
  361.         {
  362.             case CLOSEWINDOW:
  363.                 fin = TRUE;
  364.                 rtn = TRUE;
  365.                 break;
  366.             case GADGETUP:
  367.                 if (address == &stop_gadget)
  368.                 {
  369.                     rtn =TRUE;
  370.                 }
  371.                 else if (address == &tempo_gadget)
  372.                 {
  373.                     tp_text.FrontPen = 0;
  374.                     PrintIText (w->RPort,&tp_text,0,0);    /* Erase old Tempo val */
  375.                     Tempo = 500 - (float)tempo_info.HorizPot/MAXPOT * 400;
  376.                     val = (Tempo + 5)/ 10;
  377.                     for (i = 2; i > 0; --i)
  378.                     {
  379.                         ttext[i] = val%10 + '0';
  380.                         val = val/10;
  381.                     }
  382.                     tp_text.FrontPen = 1;
  383.                     PrintIText (w->RPort,&tp_text,0,0);    /* Write new Tempo val */
  384.                     for (i = 0; i < 4; ++i)
  385.                         Duration[i] = Tempo/RelTime[i];    /* New Durations */
  386.                     secs = (Tempo * (8-jScale)) * 1000;
  387.                     secs -= TimingFF;        /* Empirical fudge factor */
  388.                     I_secs = secs / 1000000;    /* New Timer values */
  389.                     M_secs = secs % 1000000;
  390.                 }
  391.                 break;
  392.             default:
  393.                 break;
  394.         }    /* Close switch */
  395.     }        /* Close while */
  396. }        /* Close function DoIDCMP() */
  397.  
  398.  
  399.  
  400.  
  401. PlayIt()        /* Send notes from array to PlayNote in AudioTools */
  402. {
  403.     int c,i,j,m;
  404.  
  405.     /* Send array notes to PlayNote */
  406.     for (j = jScale; j < 8; ++j)
  407.     {
  408.         for (c = 0; c < 4; ++c)
  409.         {
  410.             if (Play[c])
  411.             {
  412.                 for (i = 0; i < RelTime[c]; ++i)
  413.                 {
  414.                     PlayNote(c,Chan[c].Pitch[kPV[c]],
  415.                                   Chan[c].Volume[kPV[c]],Duration[c]);
  416.                     kPV[c] += 1;
  417.                 }
  418.             }
  419.         }
  420.     }
  421.  
  422.     for (i = 0; i < 4; ++i)
  423.         if (Play[i]) CheckAD(i);
  424.  
  425.             /* If using Repeat (+), check when to stop playing */
  426.     if (Repeat)
  427.     {    m = 0;
  428.         for (i=0; i<4; ++i)            /* Are any non-repeats */
  429.             if (!ChRep[i]) m += zCt[i]; /* still playing? */
  430.         if (m == 0)
  431.             for (i=0; i<4; ++i)
  432.                 zCt[i] = 0;        /* Set all zCt's = 0 stops play */
  433.     }
  434. }        /* Close function PlayIt() */
  435.  
  436.  
  437.  
  438. CheckAD(i)        /* Process the ADR+ entry to prep for next octave */
  439.   int i;            /* i is the channel */
  440. {
  441.     if (zCt[i] > 1)
  442.     {
  443.         zCt[i] -= 1;        /* Decrement ADR+ step count */
  444.         Increm[i] += ADRsig[i] * 12;    /* Bump increment either up or down */
  445.             /* by 12, for next octave --either higher or lower. */
  446.             /* No change for R = rest */
  447.     }
  448.     else
  449.     {
  450.         iADR[i] += 1;        /* Advance ADR+ entry counter */
  451.         aCh = zChan[i].ad[iADR[i]];    /* Retrieve next ADR+ code */
  452.         if (aCh == ' ')
  453.         {
  454.             Play[i] = FALSE;
  455.             zCt[i] = 0;     /* All done this chan */
  456.         }
  457.         else
  458.         {                                /* Take next AD entry */
  459.             if (aCh == '+')                        /* '+' = repeat ADR's */
  460.             {    Repeat = TRUE;        /* Restart at beginning of ADR+ series*/
  461.                 ChRep[i] = TRUE;
  462.                 iADR[i] = 0;
  463.                 PFlag[i] = FALSE;
  464.                 aCh = zChan[i].ad[0];
  465.             }
  466.             if (aCh == 'R')
  467.             {
  468.                 ADRsig[i] = 0;        /* 'R' = rest */
  469.                 Vol[i] = 0;            /* Set Volume to 0 */
  470.             }
  471.             else 
  472.             {    if (aCh == 'D')    /* Check asc/desc */
  473.                 {    
  474.                     Desc[i] = TRUE;    /* Descending */ 
  475.                     ADRsig[i] = -1; 
  476.                 }
  477.                 else
  478.                 {    
  479.                     Desc[i] = FALSE;    /* Ascending */
  480.                     ADRsig[i] = 1;
  481.                 }
  482.                 Play[i] = TRUE;
  483.                 Vol[i] = 50;        /* Set Volume to 50 */
  484.                 if (! PFlag[i])
  485.                 {
  486.                     PFlag[i] = TRUE;
  487.                     if (aCh == 'A') Increm[i] = 0;
  488.                     else Increm[i] = -12;
  489.                 }
  490.                 else if (Desc[i] == SaveDesc[i])
  491.                         Increm[i] += ADRsig[i]*12;
  492.                 SaveDesc[i] = Desc[i];
  493.             }
  494.             zCt[i] = zChan[i].ct[iADR[i]];    /* Get count this AD */
  495.         }
  496.     }
  497. }        /* Close function CheckAD() */
  498.