#include #include #include #include "global.h" #include #include #include #include "mymsp.h" extern dispatcher(); /* labels in in-line assembly must be declared. */ extern set_timer(); extern unset_timer(); extern int jukebox; /* flag for jukebox mode */ extern char *song_ram[24]; extern char *song_list[24]; extern int song_pointer; extern int number_of_songs; /* GLOBAL VARIABLES */ extern int contrl[12]; extern int intin[128]; extern int ptsin[128]; extern int intout[128]; extern int ptsout[128]; /* storage wasted for idiotic bindings */ extern int work_in[11]; /* Input to GSX parameter array */ extern int work_out[57]; /* Output from GSX parameter array */ extern int pid; /* process ID number */ extern int gl_hchar; extern int gl_wchar; extern int gl_wbox; extern int gl_hbox; /* system sizes */ extern int hidden; extern int slidepos[10]; /* timer globals */ long ticks = MAXTICKS; /* local tick counter. */ long oldvector; /* storage for old terminate vector. */ EVENT_BUFFER time_out[16]; ASSIGNMENT track_info[16]; int current_preset[16]; int track_enables[4]; char *song_buffer,*song_data; long song_size; extern int active_song; int time_sig,key_sig; int tempo; int event; /* event counter */ char temp[120],path[80],name[20]; /* file stuff */ char song_name[34]; int dur[0x15] = { 0,4,0,6,8,9,12,16,18,24,32,36,48,64,72,96,128,144,192,0,288 }; int key_sig_tab[128]; int octave[6] = {0,-24,-12,0,12,24}; int s_octave[6][7]; long r_stack[40]; /* repeat stacks */ int count_stack[40]; int loop_pointer; char *song_p; /* global song pointer */ int yuck_flag; int active_timer = FALSE; int play_flag; int end_flag; int done_flag; int done_handshake = FALSE; char midi_str[80]; /* midi note buffer */ int midi_str_len; /* ** process communications */ int mess_buff[5]; start_song(s_d) char *s_d; { int i; int *wptr; yuck_flag = FALSE; play_flag = FALSE; done_flag = FALSE; end_flag = FALSE; wptr = (int *)s_d; for(i=0;i<4;++i,++wptr) track_enables[i] = *wptr; /* get track enable info */ song_p = (char *)(s_d + 8); } parse() { /* this routine decodes the data in the song portion */ register i,t,j; register char *song; int shortest; int t1,t2; static char midi[80]; /* buffer for midi data to play */ char *repeat_start; int repeat; shortest = 288; t = 0; song = song_p; while(1) { i = ((int)(*song)) & 0x0ff; switch(i) /* switch song data */ { case REPEAT_STOP: ++song; --repeat; if(repeat > 0) song = repeat_start; case EVENT_END: ++event; if(play_flag) { ticks = (long)shortest; if(t > 0) midi_ws(t - 1,midi); timing(shortest); play_flag = FALSE; song_p = song; return; } ++song; break; case KEY_SIGNATURE: ++song; /* this should now point to 0x01 */ ++song; /* now points to signature */ key_sig = (int)(*song); gen_key_tab(key_sig); ++song; /* point to next item */ break; case TEMPO: ++song; /* point to tempo byte */ tempo = (int)(*song) & 0xff; ++song; /* point to next item */ if((tempo = 12288 / (( 48 * tempo) / 60)) > 255) tempo = 0; *((char *)0xfffa1f) = tempo; break; case BAR: ++song; /* point to end of event byte */ break; case TIME_SIGNATURE: ++song; /* point to time signature of data */ time_sig = (int)(*song); ++song; /* point to next item */ break; case LOUDNESS: ++song; /* points to 0x01 */ ++song; /* points to loudness */ for(j=0;j<16;++j) track_info[j].velocity = *song; ++song; /* point to next item */ break; case REPEAT_START: ++song; /* increment up to count byte */ repeat = (int)*song++; repeat_start = song; /* this is where we repeat to */ break; case END: end_flag = TRUE; return(0); break; default: /* if we got down here, what was found must be a note so, we first get the track/type,duration,accidentals and then the note number If, the note starts a tie, treat it like any other note, if a note is at the end of a tie, then find the note in the time out buffer. If the note is the beginning and end of a tie, still find it in the timeout buffer */ if(i & 0x20) /* end tie */ { ++song; t1 = (int)*song++; /* duration */ t2 = (int)*song++; /* note */ if(!(i & 0x10)) /* if not a rest */ { switch(t1 & 0xc0) { case INKEY: t2 = t2 + key_sig_tab[t2]; break; case NATURAL: break; case SHARP: t2 += 1; break; case FLAT: t2 -= 1; break; } } if((j = search(t2,track_info[i & 0x0f].channel)) ==-1) /* find the note in the timeout buffer */ j = get_free(); } else { ++song; t1 = *song++; t2 = *song++; if(!(i & 0x10)) { switch(t1 & 0xc0) { case INKEY: t2 = t2 + key_sig_tab[t2]; break; case NATURAL: break; case SHARP: t2 += 1; break; case FLAT: t2 -= 1; break; } } j = get_free(); } if(j >= 0) /* find free spot in note buffer */ { time_out[j].track = i & 0x0f; time_out[j].channel = track_info[(time_out[j].track)].channel; time_out[j].velocity = track_info[(time_out[j].track)].velocity; time_out[j].tie_beg = i & 0x40; time_out[j].tie_end = i & 0x20; time_out[j].in_use_flag = TRUE; time_out[j].rest = i & 0x10; /* tag as rest if need be */ time_out[j].duration = dur[t1 & 0x1f]; time_out[j].note = t2; if(time_out[j].duration < shortest) shortest = time_out[j].duration; if(t1 & 0x20) /* accent */ { time_out[j].velocity += 40; if(time_out[j].velocity > 127) time_out[j].velocity = 127; } if(!time_out[j].rest && !time_out[j].tie_end) { if(current_preset[time_out[j].channel] != track_info[time_out[j].track].patch) { midi[t++] = 0xc0 | time_out[j].channel; /* patch change */ midi[t++] = track_info[time_out[j].track].patch - 1; current_preset[time_out[j].channel] = track_info[time_out[j].track].patch; } midi[t++] = (char)(time_out[j].channel | 0x90); midi[t++] = (char)(time_out[j].note) + track_info[(time_out[j].track)].octave; midi[t++] = (char)(time_out[j].velocity); } play_flag = TRUE; /* when we hit the END OF FRAME, play */ } else { yuck_flag = TRUE; song += 3; } break; } /* end of switch i */ } /* end while */ } int search(note,chan) int note,chan; { register int i; for(i=0;i<16;++i) { if(time_out[i].note == note) if(!time_out[i].rest && (chan == time_out[i].channel)) return(i); } return(-1); } int get_free() { register int i; for(i=0;i<16;++i) { if(time_out[i].in_use_flag == 0) return(i); } return(-1); } wait_all_off() { register int i; register int shortest; shortest = 300; for(i=0;i<16;++i) { if(time_out[i].in_use_flag) { if(time_out[i].duration > 0 && (time_out[i].duration < shortest)) shortest = time_out[i].duration; } } if(shortest < 300) { timing(shortest); ticks = (long)shortest; } else { done_flag = TRUE; if(jukebox) { song_pointer++; if(song_pointer == number_of_songs) song_pointer = 0; song_buffer = song_ram[song_pointer]; init_buffer(); get_song_parameters(); song_data = (char *)&song_buffer[0x200]; ticks = 100l; event = 0; start_song(song_data); done_handshake = TRUE; } else *((char *)0xfffa19) |= 0xf0; /* stop timer A */ } } timing(n_duration) int n_duration; { register int midi_len; /* lenth of midi buffer string */ register int i; midi_len = 0; for(i=0;i<16;++i) { if(time_out[i].in_use_flag) { if(((time_out[i].duration -= n_duration) <= 0)) { if(((!time_out[i].tie_beg) && (!time_out[i].rest)) || ((!time_out[i].rest) && (time_out[i].duration < -48))) { midi_str[midi_len++] = (char)(time_out[i].channel | 0x90); midi_str[midi_len++] = (char)(time_out[i].note) + track_info[(time_out[i].track)].octave; midi_str[midi_len++] = 0; time_out[i].in_use_flag = FALSE; } if(time_out[i].rest) time_out[i].in_use_flag = FALSE; } } } midi_len--; midi_str_len = midi_len; } midi_off() { if(midi_str_len > 0) midi_ws(midi_str_len,midi_str); midi_str_len = 0; } /* timer routines: This routine is called by the interrupt handler to increment the local tick counter. */ ticker() { ticks--; asm { andi.w #0xf8ff,SR /* enable the interrupts */ bclr.b #5,0xfffa0f /* Tell MFP the interrupt has been serviced */ } if(ticks == 0l) { if(!end_flag) parse(); if(end_flag && !midi_str_len) /* if end flag was hit during parse, do this */ wait_all_off(); } if(ticks == 3l) { midi_off(); } if(ticks < -10) ticks = 4; } /* This function is callled by the main() function to set up the application terminate function and the 68901 function timer. */ set_timer() { /* Tell the timer chip to call the dispatcher routine for the interrupt. */ Xbtimer(MyApp, Control, Data, dispatcher); active_timer = TRUE; } /* Turn off the timer and reset the terminate vector. */ unset_timer() { /* Turn off the application timer. */ Xbtimer(MyApp, Off, Off, NULL); active_timer = FALSE; } do_perform(vw) int vw; { /* well, this is it, this routine plays music studio songs */ if(!active_song) { form_alert(1,"[1][No song is loaded][HEcK]"); return; } init_buffer(); get_song_parameters(); song_data = (char *)&song_buffer[0x200]; ticks = 100l; set_timer(); event = 0; start_song(song_data); } do_stop(vw) int vw; { unset_timer(); } load_next_song() { if(!done_flag) return; if(!jukebox) return; load_file(song_list[song_pointer]); do_perform(); song_pointer +=1; if(song_pointer > number_of_songs) song_pointer = 0; }