home *** CD-ROM | disk | FTP | other *** search
/ Computer Music Interactif…cial Edition 1999 Winter / cd 3.iso / mac / Mac / Shares / Midishare™1.68 / Development Tools / Sources Examples / Other MidiShare Examples / midiplay / midiplay.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-16  |  6.0 KB  |  295 lines  |  [TEXT/MPS ]

  1. /*====================== A MIDI SHARE TOOL  (© GRAME 92) =====================
  2.  
  3. NAME
  4.       MidiPlay -- a small MidiShare MPW tool
  5.  
  6. SYNOPSIS
  7.       MidiPlay <MidiFile file name>
  8.       user control :    Q <enter> quit
  9.                           P <enter> start playing
  10.                         S <enter> stop playing
  11.  
  12. DESCRIPTION
  13.     "MidiPlay" open a MidiShare session, read a MidiFile, convert its tempo map
  14.     to ms, wait for user commands to play the sequence, and then close the session.
  15.  
  16. ===============================================================================*/
  17.  
  18.  
  19. #include <String.h>
  20. #include <StdLib.h>
  21. #include <Stdio.h>
  22. #include <MidiShare.h>
  23. #include <CursorCtl.h>
  24. #include <MidiFile.h>
  25.  
  26.  
  27.  
  28. //------------------------ merge utilities ----------------------------
  29.  
  30. static MidiEvPtr AddSeq( register MidiEvPtr e1, register MidiEvPtr e2)
  31. {
  32.     register MidiEvPtr next;
  33.     
  34.     while( next= Link(e1))                /* tant qu'une séquence n'est finie */
  35.     {
  36.         if( Date(next) <= Date(e2))        /* date inférieure dans la même seq */
  37.             e1= next;                    /* rien à faire : on continue        */
  38.         else                            /* sinon                            */
  39.         {
  40.             Link( e1)= e2;                /* on linke avec l'autre séquence    */
  41.             e1= e2;                        /* et on les inverse                */
  42.             e2= next;
  43.         }
  44.     }
  45.     if( Link(e1)= e2)            /* linke avec la fin de l'autre séquence     */
  46.         while( Link(e2))
  47.             e2= Link(e2);
  48.     return e2;                    /* et renvoie le dernier evt de la séquence */
  49. }
  50.  
  51. void MixSeq( MidiSeqPtr src, MidiSeqPtr dest)
  52. {
  53.     register MidiEvPtr firstSrc, firstDest;
  54.     
  55.     if( dest && src)                            /* dest et src existent        */
  56.     {
  57.         if( firstSrc= src->first)                /* src non vide                */
  58.         {
  59.             if( !(firstDest= dest->first))        /* si destination est vide    */
  60.             {
  61.                 dest->first= firstSrc;            /* recopie du premier et    */
  62.                 dest->last= src->last;            /* dernier evt de src        */
  63.             }
  64.             else if( Date(firstSrc) < Date(firstDest))
  65.                                                 /* 1ier evt source précède    */
  66.             {                                    /* le 1ier evt destination    */
  67.                 dest->first= firstSrc;            /* range dans destination    */
  68.                 dest->last= AddSeq( firstSrc, firstDest);    /* et chainage    */
  69.             }
  70.             else dest->last= AddSeq( firstDest, firstSrc);    /* et chainage    */
  71.         }
  72.         MidiFreeCell((MidiEvPtr) src);
  73.     }
  74. }
  75.  
  76.  
  77.  
  78. //------------------------ tempo map utilities ----------------------------
  79.  
  80. void TrsfTempoSeq(MidiSeqPtr s, double ticks) 
  81. {
  82.     double    tt;    // durée d'un ticks (micro sec)
  83.     double    t1;    // temps du dernier changement de tempo (micro sec)
  84.     double    t2;    // temps actuel (micro sec)
  85.     long    d1;    // date du dernier changement de tempo (ticks)
  86.     
  87.     
  88.     MidiEvPtr    e;
  89.     
  90.     t1 = 0.0;
  91.     tt = 500000.0 / ticks;    
  92.     d1 = 0;
  93.     e = First(s);
  94.     
  95.     while (e) {
  96.         t2 = t1 + tt * (Date(e) - d1);
  97.         if (EvType(e) == typeTempo) {
  98.             tt = MidiGetField(e, 0) / ticks;
  99.             d1 = Date(e);
  100.             t1 = t2;
  101.         }
  102.         Date(e) = (long) (t2 / 1000.0);
  103.         e = Link(e);
  104.     }
  105. }
  106.  
  107. void TrsfSmpteSeq(MidiSeqPtr s, long fps, long tpf)
  108. {
  109.     MidiEvPtr    e;
  110.     long        tps;
  111.     
  112.     tps = fps * tpf;
  113.     e = First(s);
  114.     
  115.     while (e) {
  116.         Date(e) = Date(e) * 1000 / tps;
  117.         e = Link(e);
  118.     }
  119. }
  120.  
  121. long LenSeq(MidiSeqPtr s) 
  122. {
  123.     long         c; 
  124.     MidiEvPtr     e; 
  125.     
  126.     for (c=0, e=First(s); e; c++, e=Link(e));
  127.     return c;
  128. }
  129.  
  130. //----------------------------- TSequencer ---------------------------------
  131.  
  132.  
  133. // definition of a TSequencer
  134.  
  135. #define idle 0
  136. #define playing 1
  137. #define recording 2
  138.  
  139. typedef struct TSequencer {
  140.     short        ref;
  141.     short         state;
  142.     MidiSeqPtr    seq;
  143.     MidiEvPtr    task;
  144. } TSequencer;
  145.  
  146. void OpenSeq(TSequencer * s, char * n);
  147. void CloseSeq(TSequencer * s);
  148. void StopSeq(TSequencer * s);
  149. void PlaySeq(TSequencer * s);
  150. void RecSeq(TSequencer * s);
  151.  
  152. pascal void    NullRcv (short refNum);
  153. pascal void    RecRcv (short refNum);
  154. pascal void    PlayTask (long date, short refNum, TSequencer * s, MidiEvPtr e, long);
  155.  
  156.  
  157. // implementation of a TSequencer
  158.  
  159. void OpenSeq(TSequencer * s, char * n)
  160. {
  161.     midiFILE *     f;
  162.     int            i;
  163.     
  164.  // initialisation
  165.     
  166.     s->ref = MidiOpen("\pMidiPlay");
  167.     s->state = idle;
  168.     s->seq = MidiNewSeq();
  169.     s->task = 0;
  170.     
  171.  // read the midi file
  172.     
  173.     f = MidiFileOpen(n, MidiFileRead);
  174.     if (!f) {
  175.         printf ("Error opening MidiFile %s (%d)\n", n, MidiFile_errno);
  176.         CloseSeq(s);
  177.         exit(MidiFile_errno);
  178.     }
  179.     
  180.     for (i = f->ntrks; i; i--)
  181.         MixSeq( MidiFileReadTrack(f), s->seq);
  182.         
  183.     if (smpte(f)) 
  184.         TrsfSmpteSeq(s->seq, frame_par_sec(f), ticks_par_frame(f));
  185.     else
  186.         TrsfTempoSeq(s->seq, ticks_par_quarterNote(f));
  187.     
  188.     printf("File : %s, Format : %d, Tracks : %d, Length : %d, Duration : %d\n",
  189.             n, f->format, f->ntrks, LenSeq(s->seq), Date(Last(s->seq)) );
  190.         
  191.     (void) MidiFileClose(f);
  192.     
  193.  // installation
  194.     
  195.     MidiSetInfo(s->ref, s);
  196.     MidiSetRcvAlarm(s->ref, NullRcv);
  197.     
  198.     MidiConnect(s->ref, 0, 1);
  199.     MidiConnect(0, s->ref, 1);
  200. }
  201.  
  202. void CloseSeq(TSequencer * s)
  203. {
  204.     StopSeq(s);
  205.     MidiFreeSeq(s->seq);
  206.     MidiClose(s->ref);
  207. }
  208.  
  209. void StopSeq(TSequencer * s)
  210. {
  211.     printf("Stop\n");
  212.     switch (s->state) {
  213.         case playing :
  214.             MidiForgetTask(&s->task);
  215.             s->state = idle;
  216.             break;
  217.         case recording :
  218.             MidiSetRcvAlarm(s->ref, NullRcv);
  219.             s->state = idle;
  220.             break;
  221.     }
  222. }
  223.  
  224. void PlaySeq(TSequencer * s)
  225. {
  226.     MidiEvPtr e;
  227.     
  228.     StopSeq(s);
  229.     printf("Play\n");
  230.     if (e = First(s->seq)) {
  231.         s->state = playing;
  232.         PlayTask(MidiGetTime(), s->ref, s, e, 0);
  233.     }
  234. }
  235.  
  236. void RecSeq(TSequencer * s)
  237. {
  238.     StopSeq(s);
  239.     printf("Record\n");
  240.     s->state = recording;
  241.     MidiSetRcvAlarm(s->ref, RecRcv);
  242. }
  243.     
  244. pascal void NullRcv (short ref)
  245. {
  246.     MidiEvPtr e;
  247.     while (e = MidiGetEv(ref)) MidiFreeEv(e);
  248. }
  249.  
  250. pascal void RecRcv (short ref)
  251. {
  252.     TSequencer * s;
  253.     MidiEvPtr e;
  254.     
  255.     s = (TSequencer *) MidiGetInfo(ref);
  256.     while (e = MidiGetEv(ref)) MidiAddSeq(s->seq, e);
  257. }
  258.  
  259. pascal void    PlayTask (long date, short r, TSequencer * s, MidiEvPtr e, long d)
  260. {
  261.     d = Date(e);
  262.     while (e && (Date(e) == d)) {
  263.         MidiSendAt(r, MidiCopyEv(e), date+10);
  264.         e = Link(e);
  265.     }
  266.     if (e) {
  267.         s->task = MidiTask((TaskPtr)PlayTask, date+Date(e)-d, r, (long)s, (long)e, 0);
  268.     } else {
  269.         s->task = 0;
  270.         s->state = idle;
  271.     }
  272. }
  273.     
  274.  
  275.  
  276.  
  277. //-------------------------------- main ------------------------------------
  278.  
  279. main( int, char *argv[])
  280. {
  281.     char        c;
  282.     TSequencer    mySequencer;
  283.     
  284.     OpenSeq(&mySequencer, argv[1]);
  285.     
  286.     while ((c = getchar()) && c != 'q' && c != 'Q')  switch (c) {
  287.  
  288.         case 'P': case 'p': PlaySeq(&mySequencer); break;
  289.         case 'S': case 's': StopSeq(&mySequencer); break;
  290.     }
  291.     
  292.     CloseSeq(&mySequencer);
  293. }
  294.  
  295.