home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 242.lha / MidiFileRecorder / midiclock.c < prev    next >
C/C++ Source or Header  |  1989-04-04  |  7KB  |  252 lines

  1. /* MIDICLOCK, Pete Yadlowsky, 3/89
  2.  
  3.     This program is based loosely on a simple CIA timer application
  4.     originally written by Paul Higginbotham (sp?) and placed in the
  5.     public domain. Thanks, Paul.
  6.  
  7.     The function of this program is to provide a time counter that
  8.     any task may access, usually for the purpose of calculating
  9.     time elapsed between events. This program was written to
  10.     facilitate the recording of MIDI events and to allow several
  11.     MIDI processes to share a common timebase, but is general enough
  12.     to be useful in a wide range of applications.
  13.  
  14.     The program sets up a CIA timer interrupt in order to produce
  15.     a number of 'ticks' per second (specified on command line or
  16.     in message), and to simply count these ticks. The current
  17.     tick count, along with the current rate (actually, microseconds
  18.     per tick), is stored in a simple structure whose address is
  19.     placed in the tc_UserData field of the timer process's task
  20.     structure. A task that wishes to get access to this data need
  21.     only find the timer task (called 'MidiClock') and set a pointer
  22.     to the aforementioned structure (found in midiclock.h).
  23.  
  24.     When midiclock is first invoked, an optional ticks/sec value
  25.     (default is 120) is read from the command line and the timer
  26.     process is started. Further invocations can be made to message
  27.     the running timer to either change its rate or terminate:
  28.  
  29.         midiclock 240    changes the rate to 240 ticks/sec
  30.         midiclock -q    terminates the timer
  31.  
  32.     Next on the list of projects is to have the timer task send
  33.     wake-up messages (one-shot or continuous) to interested
  34.     tasks, typically for MIDI playback or sync. This is becoming
  35.     a sort of specialized timer.device, without a lot of the
  36.     overhead.
  37.  
  38.     If you pass this source code on, please try to keep
  39.     'midiclock.h' with it.
  40. */
  41.  
  42. #include <exec/types.h>
  43. #include <exec/nodes.h>
  44. #include <exec/lists.h>
  45. #include <exec/memory.h>
  46. #include <exec/ports.h>
  47. #include <exec/tasks.h>
  48. #include <exec/interrupts.h>
  49. #include <hardware/cia.h>
  50. #include <hardware/custom.h>
  51. #include <hardware/intbits.h>
  52. #include <resources/cia.h>
  53. #include <stdio.h>
  54. #include <libraries/dos.h>
  55. #include <libraries/dosextens.h>
  56. #include "midiclock.h"
  57.  
  58. extern struct CIA ciab;
  59. struct mc_Msg *GetMsg();
  60.  
  61. static struct Interrupt
  62.    CIATimerInterrupt,
  63.    *OldCIAInterrupt = (struct Interrupt *)-1;
  64.  
  65. struct MidiClockData time;
  66.  
  67. static struct Library *CIAResource = NULL;
  68.  
  69. /* using CIAB timer B */
  70.  
  71. #define ciatlo ciab.ciatblo
  72. #define ciathi ciab.ciatbhi
  73. #define ciacr ciab.ciacrb
  74. #define CIAINTBIT CIAICRB_TB
  75. #define CLEAR 0
  76. #define DEFAULT_TICKS 120
  77. #define NOMSG -1
  78. #define KILL 0
  79. #define RATE 1
  80. #define MC_PRIORITY 30
  81.  
  82. void CIAInterrupt()
  83. {
  84.     time.counter++;
  85. }
  86.  
  87. /* start the timer, clear pending interrupts, and enable timer B Interrupts */
  88. StartCIATimer()
  89. {
  90.     ciacr &= ~(CIACRBF_RUNMODE);    /* set it to reload on overflow */
  91.     ciacr |= (CIACRBF_LOAD | CIACRBF_START);
  92.     SetICR(CIAResource,CLEAR|CIAICRF_TB);
  93.     AbleICR(CIAResource, CIAICRF_SETCLR | CIAICRF_TB);
  94.     return 0;
  95. }
  96.  
  97. void StopCIATimer()
  98. {
  99.     AbleICR(CIAResource, CLEAR | CIAICRF_TB);
  100.     ciacr &= ~CIACRBF_START;
  101. }
  102.  
  103. void SetCIATimer (ticks) /* ticks/second converted to usecs */
  104. int ticks;
  105. {
  106.     long micros;
  107.  
  108.     micros = (10000000 / ticks + 5) / 10;    
  109.     time.intrvl = micros;
  110.     micros = (micros * 10000 / 1397 + 5) / 10; /* 1.397 usecs/tick */
  111.     ciatlo = micros & 0xff;
  112.     ciathi = micros >> 8;
  113. }
  114.  
  115. void EndCIATimer()
  116. {
  117.     if (OldCIAInterrupt == NULL)
  118.     {
  119.         StopCIATimer ();
  120.         RemICRVector (CIAResource, CIAINTBIT, &CIATimerInterrupt);
  121.     }
  122. }
  123.  
  124. int BeginCIATimer (ticks)
  125. int ticks;
  126. {
  127.     /* Open the CIA resource */
  128.     if ((CIAResource = (struct Library *)OpenResource(CIABNAME)) == NULL)
  129.     {
  130.         return(1);
  131.     }
  132.  
  133.     CIATimerInterrupt.is_Node.ln_Type = NT_INTERRUPT;
  134.     CIATimerInterrupt.is_Node.ln_Pri = 127;
  135.     CIATimerInterrupt.is_Node.ln_Name =  "CIA_MIDI_TIMER";
  136.     CIATimerInterrupt.is_Code = CIAInterrupt;
  137.     CIATimerInterrupt.is_Data = (APTR) &time;
  138.  
  139.     /* install interrupt */
  140.     if ((OldCIAInterrupt = AddICRVector(CIAResource,CIAINTBIT,&CIATimerInterrupt)) != NULL)
  141.     {
  142.         EndCIATimer ();
  143.         return (2);
  144.     }
  145.  
  146.     SetCIATimer (ticks);
  147.     StartCIATimer ();
  148.     return (0);
  149. }
  150.  
  151. main (argc, argv)
  152. int argc;
  153. char *argv[];
  154. {
  155.     int i, error, quit, ticks, oldpri;
  156.     char *pt, *oldname;
  157.     struct Process *FindTask(), *timerproc;
  158.     struct MsgPort *rpyport, *myport, *timerport, *CreatePort();
  159.     struct mc_Msg *msg, ctlmsg;
  160.  
  161.     /* If timer process is not found, make this the timer process */
  162.  
  163.     if ((timerproc = FindTask (MIDICLOCKNAME)) == NULL) {
  164.         if (argc > 1) ticks = atoi (argv[1]); /* command line arg */
  165.         else ticks = DEFAULT_TICKS;
  166.         if (error = BeginCIATimer (ticks)) { /* set up interrupt */
  167.             printf ("MIDICLOCK: error starting CIA timer.\n");
  168.             exit (error);
  169.             }
  170.         /* Set name and priority, hang clock's data structure on task
  171.            structure for access by other processes. */
  172.         timerproc = FindTask (0);
  173.         oldname = timerproc->pr_Task.tc_Node.ln_Name;
  174.         timerproc->pr_Task.tc_Node.ln_Name = MIDICLOCKNAME;
  175.         timerproc->pr_Task.tc_UserData = (APTR) &time;
  176.         oldpri = SetTaskPri (timerproc, MC_PRIORITY);
  177.         myport = &(timerproc->pr_MsgPort);
  178.         printf ("\nMIDICLOCK: started, rate is %d ticks/sec.\n", ticks);
  179.  
  180.         for (quit = 0; !quit; ) {
  181.             WaitPort (myport); /* wait for control messages */
  182.             while (msg = GetMsg (myport)) {
  183.                 switch (msg->command) {
  184.                     case KILL:
  185.                         quit = 1;
  186.                         printf ("MIDICLOCK: terminated.\n");
  187.                         break;
  188.                     case RATE:
  189.                         StopCIATimer ();
  190.                         SetCIATimer (msg->data);
  191.                         StartCIATimer ();
  192.                         printf ("MIDICLOCK: rate is %d ticks/sec.\n", msg->data);
  193.                         break;
  194.                     default:
  195.                     }
  196.                 ReplyMsg (msg);
  197.                 }
  198.             }
  199.         EndCIATimer (); /* stop timer and clear interrupt */
  200.         /* In the event that this process is attached to a CLI,
  201.            restore its name and priority */
  202.         timerproc->pr_Task.tc_Node.ln_Name = oldname;
  203.         SetTaskPri (timerproc, oldpri);
  204.         exit (0);
  205.         }
  206.  
  207.     /* Timer process is already running, so this must be a control
  208.        job.
  209.     */
  210.  
  211.     if ((rpyport = CreatePort (0, 0)) == NULL) {
  212.         printf ("MIDICLOCK: Can't create reply port.\n");
  213.         goto cleanup;
  214.         }
  215.     ctlmsg.msg.mn_Node.ln_Type = NT_MESSAGE;
  216.     ctlmsg.msg.mn_ReplyPort    = rpyport;
  217.  
  218.     timerport = &(timerproc->pr_MsgPort);
  219.     /* process command line args, send control messages to timer */
  220.     for (i = 1; i < argc; i++) {
  221.         pt = argv[i];
  222.         if (*pt == '-') {
  223.             switch (*++pt) {
  224.                 case 'q': /* terminate */
  225.                     ctlmsg.command = KILL;
  226.                     break;
  227.                 case 't': /* change rate */
  228.                     if (++i < argc) {
  229.                         ctlmsg.command = RATE;
  230.                         ctlmsg.data = atoi (argv[i]);
  231.                         }
  232.                     else ctlmsg.command = NOMSG;
  233.                     break;
  234.                 default:
  235.                 }
  236.             }
  237.         else { /* non-switch argument is assumed to be time value */
  238.             ctlmsg.command = RATE;
  239.             ctlmsg.data = atoi (argv[i]);
  240.             }
  241.         if (ctlmsg.command != NOMSG) { /* send message, await reply */
  242.             PutMsg (timerport, &ctlmsg);
  243.             WaitPort (rpyport);
  244.             GetMsg (rpyport);
  245.             }
  246.         }
  247.  
  248. cleanup:
  249.     if (rpyport) DeletePort (rpyport);
  250.     return 0;
  251. }
  252.