MidiShare Code Examples


We give here some very simple examples of MidiShare programs. They have no "user-interface", just a command line like in a traditional UNIX environment, in order to keep the listing short. They where writed for the Macintosh but you can easily adapt them to other computers. The specific points with the Macintosh is that the string arguments to MidiShare functions are in Pascal format (starting with \p like in "\pExample1") and the user defined functions (like tasks and alarms) that are passed to MidiShare functions are prefixed with the pascal keyword. If you run these examples on another computer, you need to remove both the \p and the pascal keyword.

  1. the shortest MidiShare program
  2. still short but safer
  3. waiting 3 seconds
  4. multitasking
  5. real-time event processing
  6. a small sequencer


The shortest MidiShare program

Program example are always too long to type. Here is the shortest MidiShare program one can write. It starts a MidiShare session using the MidiOpen function and then closes the session using the MidiClose function. ThatŐs all.

#include <MidiShare.h>
 
main()
{
	short	myRefNum;
	
	myRefNum = MidiOpen("\pExample1");
	MidiClose(myRefNum);
}


Still short but safer

The previous example was not very safe. Usually you need first to test if MidiShare is available, then check its version and finally test if you succeed in opening a MidiShare session.

#include <stdio.h>
#include <stdlib.h>
#include <MidiShare.h>
 
main()
{
	short	myRefNum;
	
	if (! MidiShare() ) {
		printf("error : MidiShare not available\n");
		exit(0);
	}
 
	if ( MidiGetVersion() < 168 ) {
		printf("error : MidiShare version 1.68 or greater required\n");
		exit(0);
	}
 
	myRefNum = MidiOpen("\pExample2");
 
	if (myRefNum < 0) {
		printf("Unable to open a MidiShare session (code %d)\n", 						myRefNum);
		exit(0);
	}
 
	MidiClose(myRefNum);
}


Waiting 3 seconds

In this example we spend 3 seconds printing dots. The checking of the previous example have been removed for sake of simplicity.

#include <stdio.h>
#include <stdlib.h>
#include <MidiShare.h>
 
 
main()
{
	short   myRefNum;
	long    stopdate;
	
	myRefNum = MidiOpen("\pExample3");
	stopdate = MidiGetTime() + 3000;
 
	printf("waiting");
	while (MidiGetTime() < stopdate) {
		printf(".");
	}
	printf("\n");
 
	MidiClose(myRefNum);
}


Multitasking

The previous example used a very trivial method of time handling. In this example we use a method in which several tasks are scheduled in the future. The PrintTask function is used as a repeatitive task to print characters. The StopTask is used to inform the program stop.

#include <stdio.h>
#include <stdlib.h>
#include <MidiShare.h>
 
long	gStopflag;
 
pascal void PrintTask (long dt, short ref, long c, long delay, long a3);
pascal void StopTask (long dt, short ref, long a1, long a2, long a3);
 
main()
{
	
	short	myRefNum;
	short      i;
	long       dt;
 
	myRefNum = MidiOpen("\pExample4");
	dt = MidiGetTime();
	
	/* schedule the stop task */
	gStopflag= 0;
	MidiTask(StopTask, dt+6150, myRefNum, 0, 0, 0);
	
	/* schedule the print task with different
	delays and characters to print */
	MidiDTask(PrintTask, dt+100, myRefNum, ' ', 100, 0);
	MidiDTask(PrintTask, dt+201, myRefNum, 'H', 200, 0);
	MidiDTask(PrintTask, dt+302, myRefNum, 'E', 300, 0);
	MidiDTask(PrintTask, dt+403, myRefNum, 'L', 400, 0);
	MidiDTask(PrintTask, dt+604, myRefNum, 'L', 600, 0);
	MidiDTask(PrintTask, dt+1005, myRefNum, 'O', 1000, 0);
 
	printf("Running :\n");
	
	while (gStopflag == 0) {
		for (i = MidiCountDTasks(myRefNum); i; i--) {
			MidiExec1DTask(myRefNum);
		}
	}
	
	printf("\nStopped\n");
 
	MidiClose(myRefNum);
}
 
 
pascal void PrintTask (long dt, short ref, long c, long delay, long a3)
{
	fputc(c, stdout); 
	fflush(stdout);
	MidiDTask(PrintTask, dt+delay, ref, c, delay, 0);
}
 
pascal void StopTask (long dt, short ref, long a1, long a2, long a3)
{
	gStopflag= 1;
}

In the above example you may have notice that two different functions, MidiTask and MidiDTask, are used to schedule function calls.

Function calls scheduled with MidiTask are automatically executed in real time at interrupt level by MidiShare. These functions must be very fast ( < 1ms) and must not call any slow or non-reentrant Operating System functions.

Function calls scheduled with MidiDTask behaves differently. They are not executed automatically but stored in a special list of pending tasks. The application can periodicaly (for example in its main event loop) execute pending tasks by calling MidiExec1DTask as in this example. In this case slow or non-rentrant functions can be safely called within the scheduled function.

In both cases the scheduled functions can use global variables, as the A5 register of the application is automatically restored by MidiShare before calling the scheduled function.


Real-time event processing

In this example we see how to install a receive alarm to process incoming events in real time. The processing is very simple, received events are delayed accordingly to their Midi channel (delay = channel number * 100ms).

#include <stdio.h>
#include <stdlib.h>
#include <MidiShare.h>
 
 
pascal void DelayRcvAlarm (short ref);
 
void main()
{
	
	short	myRefNum;
	short	i;
	long	dt;
 
	/* Open the MidiShare session */
	myRefNum = MidiOpen("\pExample5");
	
	/* Install the receive alarm */
	MidiSetRcvAlarm( myRefNum, DelayRcvAlarm );
	
	/* Connect the application to MidiShare physical I/Os
	the 3 arguments of MidiConnect are the reference number of the source,
	the reference number of the destination and the state
      of the connection (1=connected, 0=not connected) */
	MidiConnect (myRefNum, 0, 1);
	MidiConnect (0, myRefNum, 1);
 
	printf("Now Midi events are delayed\n");
	printf(" <type the ENTER key to stop the program>\n");
	
	getc(stdin);
	
	printf("\nStopped\n");
 
	/* close the MidiShare session */
	MidiClose(myRefNum);
}
 
 
pascal void DelayRcvAlarm (short ref)
{
	MidiEvPtr	e;
	
	while ( e = MidiGetEv(ref) ) {
		Date(e) += Chan(e)*100;
		MidiSend(ref, e);
	}
}

 

The receive alarm is called at interrupt level every time new events are received by the application. The argument passed to the receive alarm is the reference number of the application.


A small sequencer

This example implements a small sequencer able to record and play back midi events.

#include <stdio.h>
#include <stdlib.h>
#include <MidiShare.h>
 
long		gStopFlag;
MidiSeqPtr	gSequence;
 
pascal void record (short aRefNum);
pascal void play (long time, short refnum, long nextEv, long unused1, 							long unused2);
 
void main ()
{
	short	myRefNum;
 
	/* OPEN A MIDISHARE SESSION */
	myRefNum = MidiOpen("\pExample6");
 
 
	printf("type <ENTER> to start recording\n");
	getc(stdin);
 
	/* START RECORDING */
	gSequence = MidiNewSeq();		/* sequence for recording */
	MidiSetRcvAlarm(myRefNum, record);   /* set rcv alarm for rec */
	MidiConnect(0, myRefNum, true);	/* connect input */
	
	printf("\n\n Now recording.... \n");
	printf("(type <ENTER> to stop recording and play back)\n");
	getc(stdin);
	
	/* PLAY BACK */
	MidiConnect(0, myRefNum, false);	/* disconnect input */
	MidiConnect(myRefNum, 0, true);	 /* connect output */
	MidiSetRcvAlarm(myRefNum, 0);	   /* remove the rcv alarm */
	play(MidiGetTime(), myRefNum, (long) FirstEv(gSequence), 0, 0);
 
	printf("\n\nNow playing back....\n");
	printf("(type <ENTER> to stop and exit program)\n");
	getc(stdin);
	
	/* STOP PLAY BACK AND EXIT */
	gStopFlag = 1;				 /* set to stop playing */
	MidiFreeSeq(gSequence);		    /* free the sequence */
	MidiClose(myRefNum);			 /* close the session */
}
 
/* THE RECEIVE ALARM TO RECORD EVENTS */
pascal void record (short ref)
{
	MidiEvPtr e;
	
	while (e = MidiGetEv(ref)) {		/* get received events */
		MidiAddSeq(gSequence,e);	    /* store into the seq */
	}
}
 
/* THE TASK TO PLAYBACK EVENTS */
pascal void play ( long time, short refnum, long nextEv, long unused1, long unused2)
{
	long		date;
	MidiEvPtr 	e;
	
	/* If we have not been stopped	*/
	/* and still have events to play	*/
	if (!gStopFlag && nextEv) {			
		e = (MidiEvPtr) nextEv;	
		date = Date(e);
 
		/* for all the events at the same date */		
		while (e && Date(e) == date) 	{		
			MidiSendIm(refnum, MidiCopyEv(e));    /* Send a copy */
			e = e->link;				  /* Go to next one */
		}
		
		/* If we still have events to play in future? */
		if (e) {	
			/* schedule the play task again */				
			MidiTask(play, Date(e)-date+time, refnum, (long)e, 0, 0);
		}
	}
}