home *** CD-ROM | disk | FTP | other *** search
- /* MOXC -- a C version of Collinge's MOXIE language */
-
- /*****************************************************************************
- * Change Log
- * Date | Change
- *-----------+-----------------------------------------------------------------
- * 31-Dec-85 | Modified for use with midi
- * 5-Feb-86 | Added m_rest and m_restuntil allowing rests at top level
- * 28-May-86 | Added command line parsing
- * 4-Jun-86 | changed keyevent to separate calls for each event type
- * 10-Jul-86 | put loop in mainscore with prompt to play and replay
- *****************************************************************************/
-
- /* IMPORTS:
- asciievent(k) user-defined action for terminal input
- bendchange(ch, val) user-defined pitch bend handler
- ctrlchange(ch, c, val) user-defined control change handler
- keydown(ch, p, v) user-defined MIDI note on handler
- keyup(ch, p) user-defined MIDI note off handler
- mainscore() user-defined first action(s)
- musicfns lots of time and io functions
- peddown(ch) user-defined pedal down handler
- pedup(ch) user-defined pedal up handler
- touchchange(ch, val) user-defined aftertouch handler
- */
- asciievent();
- bendchange();
- ctrlchange();
- keydown();
- keyup();
- mainscore();
- peddown();
- pedup();
- prgmchange();
- touchchange();
-
- /* EXPORTS:
- cause(delay, routine, p1, p2, ..., p8)
- moxcdone -- set to true to quit
- eventtime -- ideallized current time
- */
-
- #include "cext.h"
- #include "stdio.h"
- #include "malloc.h"
- #include "mpu.h"
- #include "cmdline.h"
- #include "midicode.h"
- #include "moxc.h"
-
- #define SAFEMOXC true
-
- /* lists of switches and options */
- #define nswitches 8
- private char *switches[nswitches] =
- { "-debug", "-d", "-miditrace", "-m", "-trace", "-t", "-help", "-block" };
- #define noptions 1
- private char *options[1] = { "-tune" };
-
- #define n_d_sw 2
- private char *d_switches[n_d_sw] = { "-d", "-debug" };
-
-
- /* number of events to prepare to run on each main loop */
- #define NPREPARE 5
-
- #define NPRIORITY 10
-
- typedef struct event {
- struct event *next; /* link to next event record */
- long time; /* time of this event */
- int priority; /* priority of this event (0 is highest) */
- int (*routine)(); /* who to call */
- int p1, p2, p3, p4, p5, p6, p7, p8; /* what to pass */
- } *event_type;
-
- /*
- * pending is used to sort events by priority and hold them until
- * there is time to insert them in the sorted evqueue. Note that
- * in this implementation, only one priority is used.
- * nodes are allocated/returned from/to evfree
- */
- event_type pending[NPRIORITY];
- int npending; /* tells how many events are in pending array */
- event_type evqueue; /* waiting to run event queue */
- event_type evfree = NULL; /* free list */
- int moxcdone; /* flag to halt execution */
- long eventtime; /* time of current event -- used to avoid timing errors due */
- /* to finite execution speed */
- int debug = false;
-
- /*****************************************************************************
- * Routines local to this module
- *****************************************************************************/
- private void cmdline_help();
- private event_type evallocate();
- private event_type evcdr();
- private event_type evcons();
- private void evdeallocate();
- private boolean evgtr();
- private event_type evinsert();
- private void evrun();
- private void evshow();
- private void moxcinit();
- private void moxcpoll();
- private void schedule();
-
- /****************************************************************************
- * cause
- * Inputs:
- * int delay: time before this event should occur
- * int (*routine)(): routine that implements the event
- * int p1 through p8: parameters to pass to routine
- * Effect:
- * builds an event and puts it in pending queue for later scheduling
- ****************************************************************************/
-
- void cause(delay, routine, p1, p2, p3, p4, p5, p6, p7, p8)
- int delay, (*routine)(), p1, p2, p3, p4, p5, p6, p7, p8;
- {
- event_type ev;
- int priority;
- /* priorities are not currently implemented:
- if (priority >= NPRIORITY) priority = NPRIORITY-1;
- if (priority <= 0) priority = 0;
- */
- priority = 0;
- #ifdef SAFEMOXC
- if (routine == 0) {
- printf("Error: cause called with NULL routine\n");
- musicterm();
- exit(1);
- }
- #endif
- ev = evallocate();
- ev->time = eventtime + delay;
- ev->priority = priority;
- ev->routine = routine;
- ev->p1 = p1;
- ev->p2 = p2;
- ev->p3 = p3;
- ev->p4 = p4;
- ev->p5 = p5;
- ev->p6 = p6;
- ev->p7 = p7;
- ev->p8 = p8;
-
- npending++;
- pending[priority] = evcons(ev, pending[priority]);
- if (debug) {
- printf("(cause) event is pending:");
- evshow(ev);
- }
- }
-
- /****************************************************************************
- * cmdline_help
- * Effect:
- * Prints out command line help
- ****************************************************************************/
-
- private void cmdline_help()
- {
- fprintf(stderr,"program_name [options]\n");
- fprintf(stderr," Options are below. Those with * are for wizards:\n");
- fprintf(stderr," -block disable MIDI thru\n");
- fprintf(stderr," -debug (-d) enable verbose debug mode\n");
- fprintf(stderr," -help this message\n");
- fprintf(stderr," -miditrace (-m) turn on MIDI command trace\n");
- fprintf(stderr," -tune file use tuning from file\n");
- fprintf(stderr," -trace (-t) trace music\n");
- }
-
- /****************************************************************************
- * evallocate
- * Outputs:
- * returns event_type allocated from freelist or with malloc
- ****************************************************************************/
-
- private event_type evallocate()
- {
- if (evfree) return evcdr(&evfree);
- /* else */ return ((event_type) malloc(sizeof(struct event)));
- }
-
- /****************************************************************************
- * evcdr
- * Inputs:
- * event_type *evlist: address of a list pointer
- * Outputs:
- * returns the head of the list
- * Effect:
- * removes the head of the list from *evlist
- ****************************************************************************/
-
- private event_type evcdr(evlist)
- event_type *evlist;
- {
- event_type ptr;
- ptr = *evlist;
- *evlist = (*evlist)->next;
- ptr->next = NULL;
- return ptr;
- }
-
- /****************************************************************************
- * evcons
- * Inputs:
- * event_type ev: event to put at the head of the list
- * event_type evlist: the list
- * Outputs:
- * returns list with ev at the head
- * Effect: modifies ev's next pointer
- ****************************************************************************/
-
- private event_type evcons(ev, evlist)
- event_type evlist, ev;
- {
- ev->next = evlist;
- return ev;
- }
-
- /****************************************************************************
- * evdeallocate
- * Inputs:
- * event_type ev: a node to deallocate
- * Effect:
- * returns ev to free list
- ****************************************************************************/
-
- private void evdeallocate(ev)
- event_type ev;
- {
- evfree = evcons(ev, evfree);
- }
-
- /****************************************************************************
- * evgtr
- * Inputs:
- * event_type ev1, ev2: two events to be compared
- * Outputs:
- ** returns true if ev1 is earlier or has lower priority number than ev2
- ****************************************************************************/
-
- private boolean evgtr(ev1, ev2)
- event_type ev1, ev2;
- {
- return (ev1->time < ev2->time) ||
- ((ev1->time == ev2->time) && (ev1->priority < ev2->priority));
- }
-
- /****************************************************************************
- * evinsert
- * Inputs:
- * event_type evlist: the list (a priority queue)
- * event_type ev: the event to insert in evlist
- * Outputs:
- * returns list resulting from inserting ev into evlist
- * Implementation:
- * if ev goes at the head, ev is cons onto evlist and returned
- * otherwise evlist is modified by inserting ev at the right spot
- ****************************************************************************/
-
- private event_type evinsert(evlist, ev)
- event_type evlist, ev;
- {
- event_type ptr;
- if (!evlist) { /* no list, return event */
- ev->next = NULL;
- return ev;
- }
- if (evgtr(ev, evlist)) { /* make event first on list */
- return evcons(ev, evlist);
- }
- ptr = evlist;
- while ((ptr->next) && evgtr(ptr->next, ev)) {
- ptr = ptr->next;
- }
- ev->next = ptr->next;
- ptr->next = ev;
- return evlist;
- }
-
- /****************************************************************************
- * evrun
- * Inputs:
- * event_type ev: the event to execute
- * Effect:
- * executes the previously scheduled event ev and deallocates it
- ****************************************************************************/
-
- private void evrun()
- {
- event_type ev;
- if (debug) {
- printf("(evrun) running an event: \n");
- }
- ev = evcdr(&evqueue);
- eventtime = ev->time;
- if (debug) evshow(ev);
- (*(ev->routine))
- (ev->p1, ev->p2, ev->p3, ev->p4, ev->p5, ev->p6, ev->p7, ev->p8);
- evdeallocate(ev);
- }
-
- /****************************************************************************
- * evshow
- * Inputs:
- * eventtype ev: the event to show
- * Effect:
- * prints a description of ev
- * Assumes:
- * ev is not null
- ****************************************************************************/
- private void evshow(ev)
- event_type ev;
- {
- printf("address: %d\n", ev);
- printf("time: %ld\n", ev->time);
- printf("priority: %d\n", ev->priority);
- printf("routine: %d\n", ev->routine);
- printf("parameters: %d, %d, %d, %d, %d, %d, %d, %d\n",
- ev->p1, ev->p2, ev->p3, ev->p4, ev->p5, ev->p6, ev->p7, ev->p8);
- }
-
- /****************************************************************************
- * m_rest
- * Inputs:
- * int time: Amount of time to rest
- * Effect:
- * Waits until the amount of time specified has lapsed
- * Assumes:
- * Must not be called from a "caused" routine. Must only be called
- * from "mainscore" or a routine called directly or indirectly from
- * "mainscore" without using "cause".
- ****************************************************************************/
-
- void m_rest(time)
- int time;
- {
- m_restuntil(time + gettime());
- }
-
- /****************************************************************************
- * m_restuntil
- * Inputs:
- * int time: Event time to rest until
- * Effect:
- * Waits until the specified time has been reached (absolute time).
- * Other "caused" events will take place during the rest provided
- * this routine is called from "mainscore" (see m_rest description).
- ****************************************************************************/
- void m_restuntil(time)
- int time;
- {
- while(time > gettime()) {
- moxcpoll();
- }
- }
-
- /****************************************************************************
- * main
- * Inputs:
- * int argc: number of command line arguments
- * char * argv: command line argument array
- * Effect:
- * initializes and runs moxc program
- ****************************************************************************/
-
- void main(argc,argv)
- int argc;
- char * argv[];
- {
- while (askbool("Type RETURN to play, or N RETURN to quit", true)) {
- moxcinit(argc, argv); /* initialize structures */
- mainscore(); /* call user's start program */
- while (!moxcdone) { /* test for finish */
- if (!evqueue) moxcdone |= (npending == 0);
- moxcpoll(); /* do work */
- }
- musicterm();
- printf("End of Moxc execution.\n");
- }
- }
-
- /****************************************************************************
- * moxcinit
- * Inputs:
- * int argc: number of command line arguments
- * char * argv: command line argument array
- * Effect: initializes moxc system
- ****************************************************************************/
-
- private void moxcinit(argc, argv)
- int argc;
- char * argv[];
- {
- int i; /* loop variable */
-
- cl_init(switches, nswitches, options, noptions, argv, argc);
-
- if (cl_switch("-help")) {
- cmdline_help();
- exit(0);
- }
-
- debug = (cl_nswitch(d_switches, n_d_sw) != NULL);
-
- for (i=0; i < NPRIORITY; i++) pending[i] = NULL;
- evqueue = NULL;
- eventtime = 0;
-
- musicinit();
-
- moxcdone = 0;
- }
-
- /****************************************************************************
- * moxcpoll
- * Effect: dispatch on user inputs, cause events
- ****************************************************************************/
-
- private void moxcpoll()
- {
- long now; /* current time */
- int k; /* terminal input (this is int so users do not
- * have to declare type of parameter */
- byte midi_data[4]; /* midi input */
-
- /* get the time */
- now = gettime();
- /* see if any user-caused events have happened */
- eventtime = now;
- /* poll for and decode midi keyboard input */
- if (getbuf(false, midi_data)) {
- byte code = midi_data[0] & MIDI_CODE_MASK;
- if (code == MIDI_ON_NOTE) {
- if (midi_data[2] == 0) { /* velocity 0 -> note off */
- keyup((midi_data[0] & MIDI_CHN_MASK) + 1,
- midi_data[1] - 12);
- } else {
- keydown((midi_data[0] & MIDI_CHN_MASK) + 1,
- midi_data[1] - 12, midi_data[2]);
- }
- } else if (code == MIDI_OFF_NOTE) {
- keyup((midi_data[0] & MIDI_CHN_MASK) + 1,
- midi_data[1] - 12);
- } else if (code == MIDI_TOUCH) {
- touchchange((midi_data[0] & MIDI_CHN_MASK) + 1,
- midi_data[1]);
- } else if (code == MIDI_BEND) {
- bendchange((midi_data[0] & MIDI_CHN_MASK) + 1,
- midi_data[1] + (midi_data[2] << 7));
- } else if (code == MIDI_CTRL && midi_data[1] == SUSTAIN) {
- if (midi_data[2] == 0)
- pedup((midi_data[0] & MIDI_CHN_MASK) + 1);
- else peddown((midi_data[0] & MIDI_CHN_MASK) + 1);
- } else if (code == MIDI_CTRL) {
- ctrlchange((midi_data[0] & MIDI_CHN_MASK) + 1,
- midi_data[1], midi_data[2]);
- } else if (code == MIDI_CH_PROGRAM) {
- prgmchange((midi_data[0] & MIDI_CHN_MASK) + 1,
- midi_data[1]);
- }
- }
- /* poll ASCII keyboard */
- if (kbhit()) {
- k = getch();
- asciievent(k);
- if (debug && evqueue)
- printf("nextevent is scheduled for %ld\n", evqueue->time);
- }
- /* if it is now time, run the next event */
- else if ((evqueue != NULL) && (now >= evqueue->time)) evrun();
- /* if events are waiting to be scheduled ... */
- if (npending > 0) schedule();
- }
-
- /****************************************************************************
- * quit
- * Effect: tells moxc to shut down
- ****************************************************************************/
-
- void quit()
- {
- moxcdone = true;
- }
-
- /****************************************************************************
- * schedule
- * Effect: takes events off pending queues and prepares them to run
- ****************************************************************************/
-
- private void schedule()
- {
- int i, n;
- event_type ev;
-
- /* insert up to NPREPARE events from pending queues */
- i = 0; /* i is number of events inserted */
- n = 0; /* n is the priority */
- while (i < NPREPARE && n < NPRIORITY) {
- if (pending[n]) {
- npending--;
- ev = evcdr(&pending[n]);
- evqueue = evinsert(evqueue, ev);
- i++;
- if (debug) {
- printf("(main) event inserted: \n");
- evshow(ev);
- }
- } else {
- n++;
- }
- }
- }