/* trans2.c -- replacement for phase2.c for use in record program */ /***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 31-Dec-85 | Created changelog * 31-Dec-85 | Add c:\ to include directives * 31-Dec-85 | Changed to use new CBREAK as well as kbhit * 1-Jan-86 | Added stop_reason * 1-Jan-86 | Require musicfns.h before adagio.h * | stop_time is now long * | Turn off all notes in moreclean * | changed control logic in play * 1-Jan-86 | Added miditrace * 1-Jan-86 | Added command scanner at play request level * 18-Jan-86 | Gave priority to note offs. * | Created stop_check routine. * 21-Jan-86 | Added mpu_error_check to main loop * 3-Feb-86 | Changed help message slightly * 7-Feb-86 | Adapted from phase2 of adagio system to do overdubs * 21-May-86 | Pulled over lots of code from latest phase2 * 7-Aug-86 | Initialize bend, touch, porta, mod, and foot controls *****************************************************************************/ /* This module plays notes compiled and sorted in phase1 and * records from the keyboard */ #include "cext.h" #include "stdio.h" #include "adagio.h" #include "mpu.h" #include "record.h" #include "userio.h" #include "trans2.h" #define stop_code ' ' char stop_explanation[] = "Space bar"; extern int musictrace; extern int miditrace; extern int CBREAK; extern char outfile[]; /* output file from command line */ #define STOP_CC 1 #define STOP_CBRK 2 #define STOP_KEY 3 #define STOP_SPACE 4 private long offset = 100; /* time offset from clock to performance */ private int program[num_voices]; /* current program */ /**************************************************************************** * routines declared in this module ****************************************************************************/ private void init_stuff(); private void moreclean(); private void play(); private void play_help(); private void print_status(); private boolean stop_check(); /**************************************************************************** * init_stuff * Effect: * one-time initializations to prepare for playing and recording ****************************************************************************/ private void init_stuff() { off_init(); } /**************************************************************************** * moreclean * Inputs: * event_type score: the score that was in progress * int stop_reason: the reason the score was stopped * Effect: * prints a message to announce stopped state * tells what was playing at the stop time * Implementation: * What was playing is determined by reading the time and searching * for notes that are on at that time. If nothing is found on a * given channel, it would be nice to print the last note played * on the channel provided it was played within say 1 sec of the * stop time. This is unimplemented, but would help locate short * notes. ****************************************************************************/ private void moreclean(score, stop_reason) event_type score; int stop_reason; { long stop_time; event_type n; while (note_offs(0x7fffffff)) ; /* turn off all notes */ printf ("\n * * STOPPED * *\n"); switch(stop_reason) { /* reason for stopping */ case STOP_CC: printf("Control-C seen\n"); break; case STOP_CBRK: printf("Control-break seen\n"); break; case STOP_KEY: printf("%s hit\n",stop_explanation); break; case STOP_SPACE:printf("Out of space for recording\n"); break; } /* reason for stopping */ stop_time = gettime() - offset; if (stop_time > 0) printf ("Stopped at time = %ld (hundreths of a second). \n\n", stop_time); for (n = score; n != NULL; n = n->next) { if (is_note(n) && (n->ntime <= stop_time) && (n->ntime + n->u.note.ndur) >= stop_time) { printf("Voice: %d was playing line: %d\n", n->nvoice + 1, n->nline); } } } /**************************************************************************** * phase2 * Inputs: * event_type root: Root of play list * Effect: * Plays the music ****************************************************************************/ void phase2(root) event_type root; { char resp; short done = false; int truth = true; init_stuff(); while (!done) { /* ask user */ truth = true; printf ("\nType to record, q to quit, ? for help:"); while(true) { /* read input */ resp = getchar(); switch(tolower(resp)) { /* decode */ case ' ': continue; /* ignore spaces */ case '?': play_help(); readln(stdin); break; case '-': truth = !truth; continue; /* read next char */ case 't': musictrace = truth; readln(stdin); break; case 'm': miditrace = truth; readln(stdin); break; case 'q': done = true; readln(stdin); break; case 's': print_status(); readln(stdin); break; case '\n': CBREAK = 0; play(root); break; } /* decode */ break; } /* read input */ } /* ask user */ } /**************************************************************************** * play * Inputs: * event_type score: Score to play * Effect: * Plays the score ****************************************************************************/ private void play(score) event_type score; { event_type event = score; /* save first pointer for moreclean */ short done = false; int stop_reason; long time = 0; int i; musicinit(); /* initialize midi recording */ if (!rec_init(outfile, askbool("Pitch bend, etc. on", false))) { printf("No space for recording, use a smaller adagio file\n"); musicterm(); exit(1); } printf("Type %s to stop.\n",stop_explanation); /* Initialize all midi channels with reasonable start values: */ for (i = 1; i <= num_voices; i++) { midi_program(i, 1); program[i - 1] = 1; midi_bend(i, 0); midi_touch(i, 0); midi_ctrl(i, PORTARATE, 99); midi_ctrl(i, PORTASWITCH, 0); midi_ctrl(i, MODWHEEL, 0); midi_ctrl(i, FOOT, 99); } timereset(); l_restuntil(offset); while (!done) { /* play it, Sam */ time = gettime() - offset; /* delay everything by offset */ if (rec_poll(time)) { /* record anything that's there */ done = true; stop_reason = STOP_SPACE; } if (CBREAK || kbhit()) { done |= stop_check(&stop_reason); } note_offs(time); if (done) { /* clean up */ moreclean(score, stop_reason); rec_final(true); /* write out recorded data */ } else if (event != NULL) { /* something to play */ if (time >= event->ntime) { if (is_note(event)) { /* play a note */ /* check for correct program (preset) */ if (event->u.note.nprogram != program[event->nvoice]) { midi_program(event->nvoice+1, event->u.note.nprogram); program[event->nvoice] = event->u.note.nprogram; } /* if it is a note (not a rest) play it */ if (event->u.note.npitch != NO_PITCH) { midi_note(event->nvoice+1, event->u.note.npitch, event->u.note.nloud); off_schedule(event->ntime + event->u.note.ndur, event->nvoice, event->u.note.npitch); } } else { /* send control info */ switch (vc_ctrl(event->nvoice)) { case 1: midi_ctrl(vc_voice(event->nvoice) + 1, PORTARATE, event->u.ctrl.value); break; case 2: midi_ctrl(vc_voice(event->nvoice) + 1, PORTASWITCH, event->u.ctrl.value); break; case 3: midi_ctrl(vc_voice(event->nvoice) + 1, MODWHEEL, event->u.ctrl.value); break; case 4: midi_touch(vc_voice(event->nvoice) + 1, event->u.ctrl.value); break; case 5: midi_ctrl(vc_voice(event->nvoice) + 1, FOOT, event->u.ctrl.value); break; case 6: midi_bend(vc_voice(event->nvoice) + 1, event->u.ctrl.value << 6); break; default: break; } } event = event->next; } } else mpu_error_check(); } /* play it, Sam */ /* Debugging: * i = gettic(); * printf("Max Latency is %d\n", i); */ musicterm(); } /**************************************************************************** * play_help * Effect: * Lists help for play option ****************************************************************************/ private void play_help() { fprintf(stderr," Play music\n"); fprintf(stderr," q Quit Adagio (Exit)\n\n"); fprintf(stderr," m Turn on MIDI byte trace\n"); fprintf(stderr,"-m Turn off MIDI byte trace\n"); fprintf(stderr," s Report state\n"); fprintf(stderr," t Turn on music operation trace\n"); fprintf(stderr,"-t Turn off music operation trace\n"); fprintf(stderr," ? This message\n"); } /**************************************************************************** * print_status * Effect: * Informative output about state ****************************************************************************/ private void print_status() { fprintf(stderr,"MIDI trace (m option) %s\n",(miditrace ? "on" : "off")); fprintf(stderr,"Music trace (t option) %s\n",(musictrace ? "on" : "off")); } /**************************************************************************** * stop_check * Outputs: * *reason is set to reason for stop * true is returned iff play should stop * Effect: * Checks for break character or stop code from kbd ****************************************************************************/ private boolean stop_check(reason) int *reason; { boolean done = false; switch(CBREAK) { /* stop reason */ case 0: /* no stop code, try keyboard */ done = (getch() == stop_code); if (done) *reason = STOP_KEY; break; case 1: /* ctrl-break */ done = true; if (kbhit()) getch(); *reason = STOP_CBRK; break; case 2: /* ctrl-C */ done = true; *reason = STOP_CC; if (kbhit()) getch(); break; } /* stop reason */ return done; }