home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C++ Games Programming
/
CPPGAMES.ISO
/
mt
/
mtrc3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-02-04
|
11KB
|
332 lines
/* mtrc3.c - record and play functions for recorder */
/* `MIDI Sequencing In C', Jim Conger, M&T Books, 1989 */
/* #define TURBOC 1 Define if using TURBOC, leave out for Microsoft */
#include <stdio.h> /* compiler library headers */
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#ifdef TURBOC
#include <alloc.h>
#else
#include <malloc.h>
#endif
#include "screenf.h"
#include "standard.h"
#include "mpu401.h"
#include "mt.h"
#include "video.h"
#include "mtdeclar.h"
/* Sends single event's data. MIDI vol corrected if g_track_vel_used */
/* is set true, meaning that at least one track has vol set to < 100 */
void
play_event(int track, struct event far *ep) /* ep points to event data */
{
int bytes, secbyte;
bytes = ep->nbytes; /* use int to avoid repeatedly doing -> calcs. */
secbyte = ep->b[1]; /* ditto */
putdata401(ep->b[0]); /* send first byte to MPU */
if (bytes > 1){
putdata401(secbyte); /* send second byte */
if (bytes > 2){
putdata401(ep->b[2]); /* send third byte */
/* if b2 = note on, adjust volume */
if (bytes > 3){
if (secbyte >= NOTE_ON && secbyte < NOTE_ON+NTRACK
&& g_track_vel_used) /* send fourth byte - adj. vel */
putdata401(ep->b[3] * g_track_vel[track] / 100);
else
putdata401(ep->b[3]); /* send fourth byte, no vel adj */
}
}
}
}
/* issue MPU commands to shut down record process. Shuts each track down */
/* individually to avoid hung notes */
void
stop_401(int tracks_on)
{
int i, cmd;
if (tracks_on){
for (i = 0; i < NTRACK; i++){
cmd = get401(); /* get track request from MPU */
if (cmd == ALL_END || cmd == -1)
break; /* MPU sends ALL_END when done */
else if (cmd >= REQ_T1 && cmd <= REQ_T8){
putdata401(0); /* shut each play track */
putdata401(DATA_END); /* down individually */
}
}
}
repeat_cmd401(MET_OFF); /* final MPU shutdown command sequence */
repeat_cmd401(STOP_PLAY); /* after all tracks are s/d */
repeat_cmd401(CLEAR_PMAP);
}
/* Reset and initialize MPU-401. Returns track bit map (trackbits) */
/* as an int. Called before start of record and play process. */
/* Also sets temp array ep[] so that each element points to first event */
/* int the track to be played. */
int
init_401(struct event far *ep[])
{
int i, status, trackbits;
g_track_vel_used = trackbits = 0;
/* build track bit map */
for (i = NTRACK - 1; i >= 0; i--){
trackbits <<= 1;
if (g_trackarray[i].active && g_trackarray[i].numevents > 1)
trackbits++;
ep[i] = g_trackarray[i].current;
if (ep[i]->b[1] == MES_END) /* skip first measure end mark */
ep[i] = ep[i]->next;
g_track_vel[i] = g_trackarray[i].midivol; /* build velocity data */
if (g_track_vel[i] != 100)
g_track_vel_used = 1; /* if any track vel != 0, vel correct */
}
status = repeat_cmd401(RESET); /* send all initializing commands */
if (status == -1){
writerr("Unable to reset MPU-401 - play process aborted.",
g_text_char_v - 1, g_norm_attrib, g_emph_attrib);
return(0);
}
if (g_pitchbend) /* send setup command sequence to MPU */
repeat_cmd401(BEND_ON);
if (g_exclusive)
repeat_cmd401(EXCL_THRU);
repeat_cmd401(SET_TEMPO);
putdata401(g_metrate);
repeat_cmd401(METRO_MEAS);
putdata401(g_meter);
repeat_cmd401(TB_120); /* MT uses only 120 ticks/beat timebase */
repeat_cmd401(MIDI_METRO); /* metro always beets every quarter note */
putdata401(24);
if (g_meton)
repeat_cmd401(MET_ON_WOUT);
repeat_cmd401(ACT_TRACK);
putdata401(trackbits);
repeat_cmd401(CLEAR_PCOUNT);
repeat_cmd401(START_PLAY);
return(trackbits); /* return bit map of tracks set to play */
}
/* Update measure number - only if highest active track. Used in play */
/* process to avoid measure number advancing on very measure end sent */
/* when multiple tracks are playing. */
void
maybe_measure_number(int track, int trackbits)
{
int hi_act_track, i;
for (i = 0; i < NTRACK; i++){ /* find the track # of highest track */
if (trackbits & (1 << i)) /* set to play. Only this one trips */
hi_act_track = i; /* update of measure # on screen. */
}
if ((track == hi_act_track) && !g_trace_on)
write_int(++g_current_measure + 1, 53, 18, g_norm_attrib);
}
/* prompt for track number, then erase all track data. Called from both */
/* the Record and MLE screens. Uses erase_one() to do erasing. */
void
erase_track(void)
{
int track, ans;
char nbuf[10], buf[SCRNWIDE];
ans = getint(g_text_char_v - 1,
"Which track number do you wish to erase? ->",
&track, 1, NTRACK, g_norm_attrib, g_norm_attrib);
if (ans){
strcpy(buf, "Erase track number ");
itoa(track, nbuf, 10);
strcat(buf, nbuf);
strcat(buf, " ? (Y/N)->");
clearline(g_text_char_v - 1, g_norm_attrib);
writeword(buf, 1, g_text_char_v - 1, g_norm_attrib);
ans = getche();
if (toupper(ans) == 'Y')
erase_one(--track);
}
}
/* workhorse track eraser. Updates g_trackarray[], and calls clear_events */
/* to free all memory associated with track's event list */
void
erase_one(int track)
{
clear_events(g_trackarray[track].first->next);
g_trackarray[track].current = g_trackarray[track].first;
g_trackarray[track].last = g_trackarray[track].first;
g_trackarray[track].first->next = NULL;
g_trackarray[track].current->nbytes = 2;
g_trackarray[track].current->b[0] = 0;
g_trackarray[track].current->b[1] = MES_END;
g_trackarray[track].current->b[2] = 0;
g_trackarray[track].current->b[3] = 0;
if (track == g_block_track)
g_block_on = 0;
}
/* erase all data on all tracks. This is only called from the MT primary */
/* menu as the CLEAR command. */
void
erase_all(void)
{
int i;
for (i = 0; i < NTRACK; i++)
erase_one(i);
g_current_measure = 0;
}
/* updates the screen data for top of record screen. These items are */
/* all elements of the mt2[] menu defined in MTSCREEN.H. After the update */
/* the normal menu functions are used to control the screen display. */
void
init_track_str(void)
{
int i;
char buf[10];
for (i = 0; i < NTRACK; i++){
strcpy(mt2[i].content, g_trackarray[i].name);
itoa(g_trackarray[i].midichan + 1, buf, 10); /* channel number */
strcpy(mt2[i + NTRACK].content, buf);
itoa(g_trackarray[i].midivol, buf, 10); /* MIDI volume */
strcpy(mt2[i + (5 * NTRACK)].content, buf);
ltoa(g_trackarray[i].numevents, buf, 10); /* event count */
strcpy(mt2[i + (6 * NTRACK)].content, buf);
if (i != g_record_track){
strcpy(mt2[i + (2 * NTRACK)].content, " ");
strcpy(mt2[i + (4 * NTRACK)].content, "OFF");
}
else{
strcpy(mt2[i + (2 * NTRACK)].content, "*ACTIVE*");
strcpy(mt2[i + (4 * NTRACK)].content, "ON ");
g_trackarray[i].active = 0; /* can't play & record at once */
}
if (g_trackarray[i].active){ /* update play status */
strcpy(mt2[i + (3 * NTRACK)].content, "ON ");
}
else{
strcpy(mt2[i + (3 * NTRACK)].content, "OFF");
}
}
}
/* update event count for each track, ret total number. This is needed */
/* to keep the calculation of the amount of memory used up-to-date */
long
count_events(void)
{
int i;
long track_total, total;
struct event far *tp;
total = 0;
for (i = 0; i < NTRACK; i++){
tp = g_trackarray[i].first;
track_total = 0;
do { /* compute events stored in track */
tp = tp->next;
track_total++;
} while (tp != NULL);
g_trackarray[i].numevents = track_total;
total += track_total;
}
return(total);
}
/* updates all values at bottom of the recorder screen */
void
init_rec_val(void)
{
write_int(g_metrate, SCRNWIDE - 6, 16, g_norm_attrib);
write_int(g_meter, SCRNWIDE - 6, 15, g_norm_attrib);
write_int(g_current_measure + 1, 53, 18, g_norm_attrib);
write_int(g_pct_free_memory, 53, 19, g_norm_attrib);
write_on_off(g_meton, SCRNWIDE - 6, 14);
write_on_off(g_pitchbend, SCRNWIDE - 6, 17);
write_on_off(g_exclusive, SCRNWIDE - 6, 18);
write_on_off(g_trace_on, SCRNWIDE - 6, 19);
}
void
calc_pct_free(void) /* calculate % free memory */
{
int free;
float f;
count_events();
f = g_free_memory - used_memory();
g_pct_free_memory = 100 * f/g_free_memory;
}
void
write_on_off(int param, int column, int row) /* put an ON or OFF on screen */
{
if (param)
writeword("ON ", column, row, g_emph_attrib);
else
writeword("OFF", column, row, g_norm_attrib);
}
/* Sends all notes off message on all channels. This is a menu item on */
/* on the RECORD screen. */
void
all_notes_off(void)
{
int i;
repeat_cmd401(UART);
for(i = 0; i < NCHANNEL; i++){
putdata401(MODE_MESSAGE + i);
putdata401(ALL_NOTES_OFF);
putdata401(0);
}
sendcmd401(RESET);
}
/* Writes a message at the top of the screen prior to the data trace output */
void
trace_header(void)
{
clearscreen(g_norm_attrib);
writeword("Data Trace Option - all data in hex.", 1, 1, g_emph_attrib);
writeword("rc=recieved, tc=trans command, td=trans data\n\n", 1, 2,
g_emph_attrib);
}