home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C++ Games Programming
/
CPPGAMES.ISO
/
mt
/
mted3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-02-04
|
13KB
|
369 lines
/* mted3.c editor third module for multi */
/* `MIDI Sequencing In C', Jim Conger, M&T Books, 1989 */
#include <stdio.h> /* compiler library headers */
#include <conio.h>
#include "screenf.h"
#include "standard.h"
#include "mpu401.h"
#include "mt.h"
#include "video.h"
#include "mtdeclar.h"
/* Convert measures from b_start to b_end to empty measures. Shut down */
/* any notes playing at start of block to avoid hung notes. */
void
empty_block(int track, int b_start, int b_end)
{
int i;
struct event far *begin_block;
struct event far *end_block;
struct event far *ep1;
struct event far *ep2;
begin_block = advance_to_measure(track, b_start);
init_note_array();
fill_note_array(g_trackarray[track].first, begin_block);
end_block = advance_to_measure(track, b_end + 1);
end_block = end_block->next; /* end is event after block's last m.e. */
ep1 = begin_block->next; /* free memory for all events in block */
while (ep1 != end_block){
ep2 = ep1;
ep1 = ep1->next;
#ifdef TURBOC
farfree(ep2);
#else
_ffree(ep2);
#endif
}
/* put in note offs for notes on at start */
begin_block = add_note_offs(begin_block, g_trackarray[track].midichan);
/* put in sacraficial event to prepare for add_measure */
begin_block = begin_block->next = eventalloc();
begin_block->b[0] = begin_block->b[1] = 0;
for (i = 0; i <= b_end - b_start; i++) /* add back in empty meas's */
begin_block = add_measure(begin_block);
begin_block->next = end_block;
clean_track(track);
}
/* Copy contents of marked block repeatedly starting at the measure */
/* selected. Prompts for number of repetitions. */
void
block_repeat(void)
{
int i, status, reps;
struct item dest_item;
if(g_block_on && g_block_end != -1){
writeword("Move the cursor to the starting point of the repetitions.",
1, g_text_char_v - 1, g_norm_attrib);
status = select_measure(&dest_item);
if (!status){
writerr("Block repeat was cancelled.", g_text_char_v,
g_norm_attrib, g_norm_attrib);
return;
}
clearline(g_text_char_v - 1, g_norm_attrib);
status = getint(g_text_char_v - 1,
"Enter the number of times to repeat the marked block ->",
&reps, 0, 32000, g_norm_attrib, g_emph_attrib);
if (!status || !reps){
writerr("Block repeat was cancelled.", g_text_char_v,
g_norm_attrib, g_norm_attrib);
return;
}
repeat_copy(g_block_start, g_block_track, dest_item.measure,
dest_item.track, g_block_end - g_block_start + 1, reps);
change_channel(dest_item.track,
g_trackarray[dest_item.track].midichan);
}
else{
writerr("Mark the start end end of the source block, then repeat.",
g_text_char_v, g_norm_attrib, g_emph_attrib);
}
}
/* Copy source block repeatedly to destination track starting at dest_meas */
/* Do this reps times. */
void
repeat_copy(int source_meas, int source_track, int dest_meas, int dest_track,
int n_meas, int reps)
{
int i, j, sm;
struct event far *source_p;
struct event far *dest_p;
clearline(g_text_char_v - 1, g_norm_attrib);
writeword("Copying. Hit ESC to interupt. Now on repetition:", 1,
g_text_char_v - 1, g_norm_attrib);
/* build empty measures for destination, then move pointer to start */
advance_to_measure(dest_track, 1 + dest_meas + (n_meas * reps));
dest_p = advance_to_measure(dest_track, dest_meas);
for (i = 0; i < reps; i++){
write_int(i + 1, 60, g_text_char_v - 1, g_norm_attrib);
init_note_array(); /* prepart to track notes left on */
sm = source_meas;
for (j = 0; j < n_meas; j++){
source_p = advance_to_measure(source_track, sm++);
dest_p = merge_measure(dest_p, source_p);
if (dest_p == NULL){
writerr("Out of memory.", g_text_char_v - 1, g_norm_attrib,
g_emph_attrib);
return;
}
if (kbhit()){
if (getch() == ESC){
add_note_offs(dest_p, g_trackarray[dest_track].midichan);
writerr("Copy process interrupted.", g_text_char_v,
g_norm_attrib, g_emph_attrib);
return;
}
}
}
add_note_offs(dest_p, g_trackarray[dest_track].midichan);
}
}
void
transpose_block(void) /* move all midi data within block up/down n notes */
{
int *offset, x, status, b1, b2, time;
struct event far *ep;
struct event far *start_p;
struct event far *end_p;
struct event far *before_end;
offset = &x;
status = getint(g_text_char_v - 1,
"Enter the number of MIDI note numbers to add/subtract ->",
offset, -1 * NNOTES, NNOTES, g_norm_attrib, g_emph_attrib);
if (!status || !*offset){
writerr("Block transpose was cancelled.", g_text_char_v,
g_norm_attrib, g_norm_attrib);
return;
}
/* shut all notes off at start of block */
init_note_array();
start_p = advance_to_measure(g_block_track, g_block_start);
fill_note_array(g_trackarray[g_block_track].first, start_p);
start_p = add_note_offs(start_p, g_trackarray[g_block_track].midichan);
/* shut all notes off at end of block */
init_note_array();
end_p = advance_to_measure(g_block_track, g_block_end + 1);
before_end = find_event_before(g_block_track, end_p);
fill_note_array(start_p, end_p);
add_note_offs(before_end, g_trackarray[g_block_track].midichan);
/* adjust timing byte of note_offs to fall at measure end */
time = end_p->b[0];
end_p->b[0] = 0;
before_end->next->b[0] = time;
ep = start_p->next;
while (ep != end_p){ /* transpose within block */
b1 = ep->b[1];
b2 = ep->b[2];
if (b1 >= NOTE_ON && b1 < NOTE_ON + NCHANNEL ||
b1 >= NOTE_OFF && b1 < NOTE_OFF + NCHANNEL){
b2 += *offset;
while (b2 >= NNOTES){ /* if transposition exceeds MIDI */
b2 -= OCTIVE; /* note range, adjust by octives */
}
while (b2 <= -1 * NNOTES){
b2 += OCTIVE;
}
}
ep->b[2] = b2;
ep = ep->next;
}
clean_track(g_block_track);
}
struct event far /* find and return event right before ep */
*find_event_before(int track, struct event far *ep)
{
struct event far *nextp;
struct event far *lastp;
nextp = g_trackarray[track].first;
while (nextp != ep && nextp != NULL){
lastp = nextp;
nextp = nextp->next;
}
if (nextp != NULL)
return (lastp);
else
return (NULL);
}
/* Purge any unnecessary events from track. Takes care of special cases */
/* in merge process. Converts explicit Note Off's to implied ones. */
void
clean_track(int track)
{
int i, time, no_change;
unsigned int b1, b2, b3;
struct event far *ep;
struct event far *np;
struct event far *oldp;
init_note_array();
ep = g_trackarray[track].first;
np = ep->next;
while (1){
no_change = 1;
b1 = np->b[1];
b2 = np->b[2];
b3 = np->b[3];
if (b1 >= NOTE_OFF && b1 < NOTE_OFF + NCHANNEL){
b1 = (b1 & 0x0F) + NOTE_ON;
b3 = 0; /* convert explicity note_offs to note on, vel = 0 */
np->b[1] = b1;
np->b[3] = 0;
}
if (b1 == ALL_END)
break;
else if (b1 >= NOTE_ON && b1 < NOTE_ON + NCHANNEL){
if (b3) /* if a note on */
g_note_array[b2]++;
else{ /* a note off */
if (g_note_array[b2]) /* if already an on */
g_note_array[b2]--;
else{ /* loose note off - */
time = np->b[0]; /* so delete it */
oldp = np;
np = np->next;
ep->next = np;
#ifdef TURBOC
farfree(oldp);
#else
_ffree(oldp);
#endif
no_change = 0;
while (np->b[0] == TIME_OUT) { /* find event after */
ep = ep->next; /* time_outs */
np = np->next;
}
if (np->b[0] + time < MAX_CLOCK) /* adjust clock */
np->b[0] += time; /* count */
else{
ep = ep->next = eventalloc();
ep->next = np;
ep->b[0] = TIME_OUT;
for (i = 1; i < 4; i++){
ep->b[i] = 0;
}
np->b[0] = np->b[0] + time - MAX_CLOCK;
}
}
}
}
if (no_change){
ep = np;
np = ep->next;
}
}
add_note_offs(ep, g_trackarray[track].midichan);
ep = np->next; /* points to event past ALL_END if any */
np->next = NULL;
g_trackarray[track].last = np;
while (ep != NULL){ /* delete any events past first ALL_END */
np = ep->next;
#ifdef TURBOC
farfree(oldp);
#else
_ffree(ep);
#endif
ep = np;
}
}
void
block_paste(void) /* copies marked block to targeted spot */
{
int i, ans, source_track, source_measure, dest_track, dest_measure;
struct item meas_item;
struct event far *source_event;
struct event far *dest_event;
if (!g_block_on || g_block_end == -1){
writerr("First mark the START and END of the block",
g_text_char_v, g_norm_attrib, g_emph_attrib);
return;
}
writeword(
"Move the cursor to the measure to start the pasted block"
, 1, g_text_char_v - 1, g_norm_attrib);
ans = select_measure(&meas_item);
if (!ans)
return;
else{
clearline(g_text_char_v - 1, g_norm_attrib);
writeword("Copying. Hit ESC to terminate.", 1, g_text_char_v - 1,
g_norm_attrib);
init_note_array();
source_track = g_block_track;
dest_track = meas_item.track;
source_measure = g_block_start;
dest_measure = meas_item.measure;
/* build empty measures as needed in dest track */
advance_to_measure(dest_track, dest_measure +
g_block_end - g_block_start + 1);
dest_event = advance_to_measure(dest_track, dest_measure);
/* merge each measure successively from front */
for (i = 0; i <= g_block_end - g_block_start; i++){
source_event = advance_to_measure(source_track,
source_measure++);
if (source_event == dest_event){
writerr("Source and destination measures cannot be the same.",
g_text_char_v, g_norm_attrib, g_norm_attrib);
return;
}
dest_event = merge_measure(dest_event, source_event);
if (dest_event == NULL){
writerr("Out of memory.", g_text_char_v - 1, g_norm_attrib,
g_emph_attrib);
return;
}
if (kbhit()){
if (getch() == ESC){
writerr("Copy process interrupted.", g_text_char_v,
g_norm_attrib, g_emph_attrib);
break;
}
}
}
add_note_offs(dest_event, g_trackarray[dest_track].midichan);
clean_track(dest_track);
change_channel(dest_track, g_trackarray[dest_track].midichan);
goto_measure(g_current_measure);
}
}