home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C++ Games Programming
/
CPPGAMES.ISO
/
mt
/
mted2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-02-04
|
14KB
|
410 lines
/* mted2.c editor second module for mt */
/* `MIDI Sequencing In C', Jim Conger, M&T Books, 1989 */
#include <stdio.h> /* compiler library headers */
#include <conio.h>
#include <string.h>
#include "screenf.h"
#include "standard.h"
#include "mpu401.h"
#include "mt.h"
#include "video.h"
#include "mtdeclar.h"
/* load the MLE screen data array (mt3[]) with current measure data */
void
init_meas_data(void)
{
int i, j, k, status, end_track;
char nbuf[10];
struct event far *measurep;
for (i = 0; i < NMEASURE_DISP; i++){ /* put measure #s at top */
itoa(i + 1 + g_current_measure, nbuf, 10);
strcpy(mt3[i].content, nbuf);
}
for (i = 0; i < NTRACK; i++){ /* add track names */
k = NMEASURE_DISP + (i * (NMEASURE_DISP + 2));
strcpy(mt3[k].content, g_trackarray[i].name);
}
for (i = 0; i < NTRACK; i++){ /* add midi channel numberr */
k = NMEASURE_DISP + 1 + (i * (NMEASURE_DISP + 2));
itoa(g_trackarray[i].midichan + 1, nbuf, 10);
strcpy(mt3[k].content, nbuf);
}
for (i = 0; i < NTRACK; i++){ /* see if midi data in measure */
measurep = g_trackarray[i].current;
if (measurep == g_trackarray[i].last)
end_track = 1;
else
end_track = 0;
for (j = 0; j < NMEASURE_DISP; j++){
k = j + 2 + NMEASURE_DISP + (i * (NMEASURE_DISP + 2));
if (end_track){
strcpy(mt3[k].content, " ");
}
else{ /* put in special chars for MIDI data, empty meas.. */
if ((status = has_midi_data(measurep)) == 2)
strcpy(mt3[k].content, g_note_char);
else if(status == 1)
strcpy(mt3[k].content, g_meas_char);
else{
strcpy(mt3[k].content, " ");
end_track = 1;
}
measurep = increment_measure(measurep);
}
}
}
if (g_block_on){ /* put block markers in */
if (g_block_end >= g_current_measure && g_block_end <=
g_current_measure + NMEASURE_DISP){
k = NMEASURE_DISP + 2 + (g_block_track * (NMEASURE_DISP + 2)) +
g_block_end - g_current_measure;
strcpy(mt3[k].content, g_blocke_char);
}
if (g_block_start >= g_current_measure && g_block_start <=
g_current_measure + NMEASURE_DISP){
k = NMEASURE_DISP + 2 + (g_block_track * (NMEASURE_DISP + 2)) +
g_block_start - g_current_measure;
if (g_block_start == g_block_end)
strcpy(mt3[k].content, g_smallb_char);
else
strcpy(mt3[k].content, g_blocks_char);
}
}
}
/* Checks if MIDI Note On within given measure. Returns 0 if off end of */
/* data, 1 if measure is empty, and 2 if measure has midi data. */
int
has_midi_data(struct event far *measurep)
{
int first;
struct event far *eventp;
eventp = measurep;
first = 1;
while (eventp != NULL){
if (eventp->b[1] < 0xF0 && eventp->b[3] != 0)
return(2);
else if (eventp->b[1] == MES_END)
if (!first)
return(1);
else{
eventp = eventp->next;
first = 0;
}
else if (eventp->b[1] == DATA_END)
return(0);
else{
eventp = eventp->next;
first = 0;
}
}
return(0);
}
/* find next measure end, return pointer to it. Return NULL if off end */
/* of the track's event list. */
struct event far
*increment_measure(struct event far *eventp)
{
if (eventp == NULL || eventp->b[1] == ALL_END)
return(NULL);
else if (eventp->next != NULL){
eventp = eventp->next;
while (eventp != NULL){
if (eventp->b[1] == MES_END)
return(eventp);
else if (eventp->b[1] == ALL_END)
return(NULL);
else
eventp = eventp->next;
}
}
return(NULL);
}
/* Allow cursor movement on top half of MLE screen to select a measure. */
/* Returns 0 for abort, 1 if successful. */
int
select_measure(struct item *item)
{
int pick, track, measure;
/* allow cursor movement - but only at screen top */
pick = movescrn(g_text_mode, mt3, NMEASURE_DISP + 2, NMEASURE_DISP +
(NTRACK * (NMEASURE_DISP + 2)), g_emph_attrib, g_cursor_attrib);
/* check if on left side or top */
if (pick < NMEASURE_DISP || ((pick - NMEASURE_DISP) %
(NMEASURE_DISP + 2) < 2))
return(0); /* note that ESC will return -2, quitting */
else{
track = (pick - NMEASURE_DISP)/(NMEASURE_DISP + 2);
measure = (pick - NMEASURE_DISP - 2) - (track * (NMEASURE_DISP
+ 2)) + g_current_measure;
item->track = track;
item->measure = measure;
return(1);
}
}
/* Move to given measure, add empty measures at end of track as needed */
/* to extend track to measure number specified. Returns pointer to first */
/* event of that measure. */
struct event far
*advance_to_measure(int track, int measure)
{
int m, tot_ticks, first;
struct event far *ep;
struct event far *lp;
m = 0;
first = 1;
ep = g_trackarray[track].first;
lp = g_trackarray[track].last;
while (ep != lp){ /* run through events counting measures */
if (ep->b[1] == MES_END){
if (!first) /* ignore first event - always meas end */
m++;
first = 0;
}
if (m >= measure)
return(ep); /* found measure within existing data */
else
ep = ep->next;
}
while (m++ < measure){ /* if not, add empty measures as needed */
ep = add_measure(ep); /* overwrites existing ALL_END event */
}
ep->next = eventalloc(); /* put end of track marker at tail */
if (ep->next == NULL)
return(NULL);
ep->next->next = NULL;
ep->next->nbytes = 2;
ep->next->b[0] = 0;
ep->next->b[1] = ALL_END;
ep->next->b[2] = ep->next->b[3] = 0;
g_trackarray[track].last = ep->next;
return(ep); /* returns pointer to right before ALL_END */
}
/* Add an empty measure at starting point. Return pointer to end event. */
struct event far
*add_measure(struct event far *ep)
{
int tot_ticks;
if (ep->b[1] == MES_END) /* don't overwrite last measure end */
ep = ep->next = eventalloc();
if (ep == NULL)
return(NULL);
tot_ticks = g_meter * g_tick;
do {
if (tot_ticks < MAX_CLOCK){ /* measure end within 240 ticks */
ep->nbytes = 2;
ep->b[0] = tot_ticks;
ep->b[1] = MES_END;
ep->b[2] = ep->b[3] = 0;
}
else{ /* time out before measure end */
ep->nbytes = 1;
ep->b[0] = TIME_OUT;
ep->b[1] = ep->b[2] = ep->b[3] = 0;
ep = ep->next = eventalloc();
if (ep == NULL)
return(NULL);
}
tot_ticks -= MAX_CLOCK;
} while (tot_ticks >= 0 );
return(ep);
}
/* Add the MIDI data from the measure pointed to by source_p to the data */
/* in the measure pointed to by dest_p. Correct timing bytes as needed. */
struct event far
*merge_measure(struct event far *dest_p, struct event far *source_p)
{
int i, d_time, s_time, new_dest, new_source;
struct event far *dp_next;
struct event far *sp_next;
struct event far *newp;
dp_next = dest_p->next;
sp_next = source_p->next;
new_dest = new_source = 1;
d_time = s_time = 0;
init_note_array();
do {
if (new_dest){
while (dp_next->b[0] == TIME_OUT){ /* add up TIME_OUTs */
newp = dp_next->next;
#ifdef TURBOC
farfree(dp_next);
#else
_ffree(dp_next); /* free their space */
#endif
dp_next = newp;
d_time += MAX_CLOCK;
}
d_time += dp_next->b[0];
new_dest = 0;
}
/* keep track of notes left on or off */
fill_note_array(dp_next, dp_next->next);
if (new_source){
while (sp_next->b[0] == TIME_OUT){
sp_next = sp_next->next; /* don't free from source */
s_time += MAX_CLOCK;
}
s_time += sp_next->b[0];
new_source = 0;
}
if (d_time <= s_time){ /* dest event is next one */
if (d_time >= MAX_CLOCK){
d_time -= MAX_CLOCK; /* add TIME_OUT if needed */
s_time -= MAX_CLOCK;
dest_p->next = newp = eventalloc();
if (newp == NULL)
return(NULL);
newp->next = dp_next;
newp->nbytes = 1;
newp->b[0] = TIME_OUT;
for (i = 1; i < 4; i++){
newp->b[i] = 0;
}
dest_p = newp;
}
else{
s_time -= d_time;
dp_next->b[0] = d_time;
dest_p = dp_next; /* no need to allocate - */
dp_next = dest_p->next; /* dest is already there */
d_time = 0;
new_dest = 1;
}
}
else{ /* source event is next */
if (s_time >= MAX_CLOCK){
d_time -= MAX_CLOCK; /* add TIME_OUT if needed */
s_time -= MAX_CLOCK;
dest_p->next = newp = eventalloc();
if (newp == NULL)
return(NULL);
newp->next = dp_next;
newp->nbytes = 1;
newp->b[0] = TIME_OUT;
for (i = 1; i < 4; i++){
newp->b[i] = 0;
}
dest_p = newp;
}
else{ /* add source event to dest - */
d_time -= s_time; /* need to alocate a new event */
dest_p->next = newp = eventalloc();
if (newp == NULL)
return(NULL);
newp->next = dp_next;
newp->nbytes = sp_next->nbytes;
newp->b[0] = s_time;
for(i = 1; i < 4; i++){
newp->b[i] = sp_next->b[i];
}
dest_p = newp;
source_p = sp_next;
sp_next = sp_next->next;
s_time = 0;
new_source = 1;
}
}
} while (dest_p->b[1] != MES_END && source_p->b[1] != ALL_END);
return(dest_p);
}
/* Set all g_note_array[] values to 0 in preparation for using the array */
/* to keep track of which notes have been left on after an operation. */
void
init_note_array(void)
{
int i;
for (i = 0; i < NNOTES; i++){
g_note_array[i] = 0;
}
}
/* Keep track of notes on/off between start_event and end_event. Notes On */
/* add to the array, Notes Off subtract. */
void
fill_note_array(struct event far *start_event, struct event far *end_event)
{
int b1, b2;
struct event far *ep;
ep = start_event;
while (ep != end_event){
b1 = ep->b[1];
b2 = ep->b[2];
if (b1 >= NOTE_ON && b1 < NOTE_ON + NCHANNEL){ /* if note on/off */
if (ep->b[3]) /* if a note on */
g_note_array[b2]++;
else{ /* if a note off */
if (g_note_array[b2]) /* can't have negative note count */
g_note_array[b2]--;
}
}
else if (b1 >= NOTE_OFF && b1 < NOTE_OFF + NCHANNEL){ /* note off */
if (g_note_array[b2])
g_note_array[b2]--;
}
ep = ep->next;
}
}
/* Add note offs at end of block, based on g_note_array[] values for */
/* number of notes left on for each MIDI note number. Returns pointer */
/* to last added event. */
struct event far
*add_note_offs(struct event far *dest_event, int channel)
{
int i, j;
struct event far *old_nextp;
old_nextp = dest_event->next;
for (i = 0; i < NNOTES; i++){ /* for every note in MIDI scale... */
while (g_note_array[i]--){ /* for each of this note left on ... */
dest_event = dest_event->next = eventalloc();
if (dest_event == NULL){
dest_event->next = old_nextp;
return(NULL);
}
dest_event->nbytes = 4; /* add a note off with same note number */
dest_event->b[0] = 0;
dest_event->b[1] = NOTE_ON + channel;
dest_event->b[2] = i;
dest_event->b[3] = 0;
}
}
dest_event->next = old_nextp;
return(dest_event);
}