home *** CD-ROM | disk | FTP | other *** search
- /*====================== A MIDI SHARE TOOL (© GRAME 92) =====================
-
- NAME
- MidiPlay -- a small MidiShare MPW tool
-
- SYNOPSIS
- MidiPlay <MidiFile file name>
- user control : Q <enter> quit
- P <enter> start playing
- S <enter> stop playing
-
- DESCRIPTION
- "MidiPlay" open a MidiShare session, read a MidiFile, convert its tempo map
- to ms, wait for user commands to play the sequence, and then close the session.
-
- ===============================================================================*/
-
-
- #include <String.h>
- #include <StdLib.h>
- #include <Stdio.h>
- #include <MidiShare.h>
- #include <CursorCtl.h>
- #include <MidiFile.h>
-
-
-
- //------------------------ merge utilities ----------------------------
-
- static MidiEvPtr AddSeq( register MidiEvPtr e1, register MidiEvPtr e2)
- {
- register MidiEvPtr next;
-
- while( next= Link(e1)) /* tant qu'une séquence n'est finie */
- {
- if( Date(next) <= Date(e2)) /* date inférieure dans la même seq */
- e1= next; /* rien à faire : on continue */
- else /* sinon */
- {
- Link( e1)= e2; /* on linke avec l'autre séquence */
- e1= e2; /* et on les inverse */
- e2= next;
- }
- }
- if( Link(e1)= e2) /* linke avec la fin de l'autre séquence */
- while( Link(e2))
- e2= Link(e2);
- return e2; /* et renvoie le dernier evt de la séquence */
- }
-
- void MixSeq( MidiSeqPtr src, MidiSeqPtr dest)
- {
- register MidiEvPtr firstSrc, firstDest;
-
- if( dest && src) /* dest et src existent */
- {
- if( firstSrc= src->first) /* src non vide */
- {
- if( !(firstDest= dest->first)) /* si destination est vide */
- {
- dest->first= firstSrc; /* recopie du premier et */
- dest->last= src->last; /* dernier evt de src */
- }
- else if( Date(firstSrc) < Date(firstDest))
- /* 1ier evt source précède */
- { /* le 1ier evt destination */
- dest->first= firstSrc; /* range dans destination */
- dest->last= AddSeq( firstSrc, firstDest); /* et chainage */
- }
- else dest->last= AddSeq( firstDest, firstSrc); /* et chainage */
- }
- MidiFreeCell((MidiEvPtr) src);
- }
- }
-
-
-
- //------------------------ tempo map utilities ----------------------------
-
- void TrsfTempoSeq(MidiSeqPtr s, double ticks)
- {
- double tt; // durée d'un ticks (micro sec)
- double t1; // temps du dernier changement de tempo (micro sec)
- double t2; // temps actuel (micro sec)
- long d1; // date du dernier changement de tempo (ticks)
-
-
- MidiEvPtr e;
-
- t1 = 0.0;
- tt = 500000.0 / ticks;
- d1 = 0;
- e = First(s);
-
- while (e) {
- t2 = t1 + tt * (Date(e) - d1);
- if (EvType(e) == typeTempo) {
- tt = MidiGetField(e, 0) / ticks;
- d1 = Date(e);
- t1 = t2;
- }
- Date(e) = (long) (t2 / 1000.0);
- e = Link(e);
- }
- }
-
- void TrsfSmpteSeq(MidiSeqPtr s, long fps, long tpf)
- {
- MidiEvPtr e;
- long tps;
-
- tps = fps * tpf;
- e = First(s);
-
- while (e) {
- Date(e) = Date(e) * 1000 / tps;
- e = Link(e);
- }
- }
-
- long LenSeq(MidiSeqPtr s)
- {
- long c;
- MidiEvPtr e;
-
- for (c=0, e=First(s); e; c++, e=Link(e));
- return c;
- }
-
- //----------------------------- TSequencer ---------------------------------
-
-
- // definition of a TSequencer
-
- #define idle 0
- #define playing 1
- #define recording 2
-
- typedef struct TSequencer {
- short ref;
- short state;
- MidiSeqPtr seq;
- MidiEvPtr task;
- } TSequencer;
-
- void OpenSeq(TSequencer * s, char * n);
- void CloseSeq(TSequencer * s);
- void StopSeq(TSequencer * s);
- void PlaySeq(TSequencer * s);
- void RecSeq(TSequencer * s);
-
- pascal void NullRcv (short refNum);
- pascal void RecRcv (short refNum);
- pascal void PlayTask (long date, short refNum, TSequencer * s, MidiEvPtr e, long);
-
-
- // implementation of a TSequencer
-
- void OpenSeq(TSequencer * s, char * n)
- {
- midiFILE * f;
- int i;
-
- // initialisation
-
- s->ref = MidiOpen("\pMidiPlay");
- s->state = idle;
- s->seq = MidiNewSeq();
- s->task = 0;
-
- // read the midi file
-
- f = MidiFileOpen(n, MidiFileRead);
- if (!f) {
- printf ("Error opening MidiFile %s (%d)\n", n, MidiFile_errno);
- CloseSeq(s);
- exit(MidiFile_errno);
- }
-
- for (i = f->ntrks; i; i--)
- MixSeq( MidiFileReadTrack(f), s->seq);
-
- if (smpte(f))
- TrsfSmpteSeq(s->seq, frame_par_sec(f), ticks_par_frame(f));
- else
- TrsfTempoSeq(s->seq, ticks_par_quarterNote(f));
-
- printf("File : %s, Format : %d, Tracks : %d, Length : %d, Duration : %d\n",
- n, f->format, f->ntrks, LenSeq(s->seq), Date(Last(s->seq)) );
-
- (void) MidiFileClose(f);
-
- // installation
-
- MidiSetInfo(s->ref, s);
- MidiSetRcvAlarm(s->ref, NullRcv);
-
- MidiConnect(s->ref, 0, 1);
- MidiConnect(0, s->ref, 1);
- }
-
- void CloseSeq(TSequencer * s)
- {
- StopSeq(s);
- MidiFreeSeq(s->seq);
- MidiClose(s->ref);
- }
-
- void StopSeq(TSequencer * s)
- {
- printf("Stop\n");
- switch (s->state) {
- case playing :
- MidiForgetTask(&s->task);
- s->state = idle;
- break;
- case recording :
- MidiSetRcvAlarm(s->ref, NullRcv);
- s->state = idle;
- break;
- }
- }
-
- void PlaySeq(TSequencer * s)
- {
- MidiEvPtr e;
-
- StopSeq(s);
- printf("Play\n");
- if (e = First(s->seq)) {
- s->state = playing;
- PlayTask(MidiGetTime(), s->ref, s, e, 0);
- }
- }
-
- void RecSeq(TSequencer * s)
- {
- StopSeq(s);
- printf("Record\n");
- s->state = recording;
- MidiSetRcvAlarm(s->ref, RecRcv);
- }
-
- pascal void NullRcv (short ref)
- {
- MidiEvPtr e;
- while (e = MidiGetEv(ref)) MidiFreeEv(e);
- }
-
- pascal void RecRcv (short ref)
- {
- TSequencer * s;
- MidiEvPtr e;
-
- s = (TSequencer *) MidiGetInfo(ref);
- while (e = MidiGetEv(ref)) MidiAddSeq(s->seq, e);
- }
-
- pascal void PlayTask (long date, short r, TSequencer * s, MidiEvPtr e, long d)
- {
- d = Date(e);
- while (e && (Date(e) == d)) {
- MidiSendAt(r, MidiCopyEv(e), date+10);
- e = Link(e);
- }
- if (e) {
- s->task = MidiTask((TaskPtr)PlayTask, date+Date(e)-d, r, (long)s, (long)e, 0);
- } else {
- s->task = 0;
- s->state = idle;
- }
- }
-
-
-
-
- //-------------------------------- main ------------------------------------
-
- main( int, char *argv[])
- {
- char c;
- TSequencer mySequencer;
-
- OpenSeq(&mySequencer, argv[1]);
-
- while ((c = getchar()) && c != 'q' && c != 'Q') switch (c) {
-
- case 'P': case 'p': PlaySeq(&mySequencer); break;
- case 'S': case 's': StopSeq(&mySequencer); break;
- }
-
- CloseSeq(&mySequencer);
- }
-
-