home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C++ Games Programming
/
CPPGAMES.ISO
/
mt
/
mtsc2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-01-13
|
10KB
|
332 lines
/* mtsc2.c */
/* `MIDI Sequencing In C', Jim Conger, M&T Books, 1989 */
/* #define TURBOC 1 Define if using TURBOC, leave out for Microsoft */
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#ifdef TURBOC
#include <alloc.h>
#else
#include <malloc.h>
#endif
#include "standard.h"
#include "screenf.h"
#include "mpu401.h"
#include "mt.h"
#include "video.h"
#include "mtsc.h"
#include "mtdeclar.h"
/* Draw the note edit area box on the graphics screen. */
void
init_screen_box(int beat, int measure)
{
int x1, x2, y1, y2;
x1 = LEFT_BORDER;
y1 = g_top_note_line - HALF_NOTE_DOTS;
x2 = g_dots_h - 1;
y2 = g_bot_note_line + HALF_NOTE_DOTS;
draw_rectangle(FALSE, x1, y1, x2, y2, g_line_color);
draw_rectangle(TRUE, x1 + 1, y1 + 1, x2 - 1, y2 - 1, g_back_color);
top_scale(beat, x1, y1, x2, y2, measure);
dotted_lines(x1, y1, x2, y2, 8, 20, g_line_color);
g_sc_refresh = 1;
}
/* put top scale on screen, initialize globals for side boundaries */
void
top_scale(int beat, int leftside, int topline, int rightside, int botline,
int measure)
{
int i, tick, xpos;
char nbuf[10];
g_first_measure = measure;
tick = 0;
xpos = leftside;
clearline(2, g_norm_attrib);
writeword("Beat:", 1, 2, g_norm_attrib);
/* put in tick marks at the top of the NLE edit box */
for (i = leftside; i < rightside; i += MIN_SPACE){
if (tick % TICK_PER_BEAT == 0){
drawline(xpos, topline, xpos, botline, g_line_color);
write_int(beat + 1, 1 + (xpos/g_let_dots_h), 2, g_emph_attrib);
if (beat < g_meter - 1)
beat++;
else{
beat = 0;
tick = 0;
measure++;
}
}
else if (tick % (TICK_PER_BEAT/2) == 0)
drawline(xpos, topline - 6, xpos, topline, g_line_color);
else if (tick % (TICK_PER_BEAT/4) == 0)
drawline(xpos, topline - 4, xpos, topline, g_line_color);
else if (tick % (TICK_PER_BEAT/8) == 0)
drawline(xpos, topline - 2, xpos, topline, g_line_color);
else
drawline(xpos, topline - 1, xpos, topline, g_line_color);
tick += g_scale;
xpos += MIN_SPACE;
}
}
/* Write top note name on screen and initialize global for bottom note */
void
name_top_note(int oct_shown)
{
int ypos;
char buf[10];
g_bot_note = g_top_note - (oct_shown * 12) + 1;
writeword(" ", 72, g_graph_char_v - 2, g_norm_attrib);
writeword(g_notes[g_top_note].name, 72, g_graph_char_v - 2,
g_norm_attrib);
}
void
name_measure(int measure) /* put measure number at top left corner */
{
char buf[20], nbuf[10];
strcpy(buf, "Meas: ");
itoa(measure + 1, nbuf, 10);
strcat(buf, nbuf);
strcat(buf, " ");
writeword(buf, 1, 1, g_norm_attrib);
}
/* puts dotted lines in rectangular region */
void
dotted_lines(int topx, int topy, int botx, int boty, int vspace, int hspace,
int color)
{
int x, y;
for (y = topy + (vspace/2) ; y < boty; y += vspace){
for (x = topx; x < botx; x += hspace){
dotplot(x, y, color);
}
}
}
/* Convert track data from event list to temporary form used for editing. */
/* The note_time structure makes it easier to locate and draw single notes. */
struct note_time far
*build_note_list(int track)
{
int measure, tick, i, b0, b1, b2, b3;
struct event far *ep;
struct note_time far *notep;
struct note_time far *first_notep;
struct on_event on_array[NNOTES];
for (i = 0; i < NNOTES; i++){ /* keeps track of pending note_ons */
on_array[i].event = NULL;
}
ep = g_trackarray[track].first;
if (ep->b[1] == MES_END) /* skip start of track marker */
ep = ep->next;
notep = first_notep =
#ifdef TURBOC
(struct note_time far *)farmalloc(sizeof(struct note_time));
#else
(struct note_time far *)_fmalloc(sizeof(struct note_time));
#endif
notep->on_event = NULL;
notep->off_event = NULL;
notep->on_measure = notep->off_measure = 0;
notep->on_tick = notep->off_tick = 0;
notep->note_number = 0;
notep->next = NULL;
measure = tick = 0;
while (ep != NULL){
b0 = ep->b[0];
b1 = ep->b[1];
b2 = ep->b[2];
b3 = ep->b[3];
if (b1 == MES_END){
measure++;
tick = 0;
}
else if (b1 == ALL_END)
break;
else if (b1 >= NOTE_ON && b1 < NOTE_ON + NCHANNEL ||
b1 >= NOTE_OFF && b1 < NOTE_OFF + NCHANNEL){
tick += b0;
/* if already have note on, and this is note off */
if (on_array[b2].event != NULL &&
(b3 == 0 || (b1 >= NOTE_OFF && b1 < NOTE_OFF + NCHANNEL))){
notep->on_event = on_array[b2].event;
notep->on_measure = on_array[b2].measure;
notep->on_tick = on_array[b2].tick;
notep->note_number = b2;
notep->off_event = ep;
notep->off_measure = measure;
notep->off_tick = tick;
notep = notep->next = (struct note_time far *)
#ifdef TURBOC
farmalloc(sizeof(struct note_time));
#else
_fmalloc(sizeof(struct note_time));
#endif
if (notep == NULL){
free_note_list(first_notep);
return(NULL);
}
notep->next = NULL;
on_array[b2].event = NULL;
}
else if (b3 != 0){ /* if not a loose note off */
on_array[b2].event = ep;
on_array[b2].measure = measure;
on_array[b2].tick = tick;
on_array[b2].vel = b3;
}
}
else if (b0 == TIME_OUT){
tick += MAX_CLOCK;
}
else{
tick += b0; /* all data except note on/off ignored */
} /* but timing value added to running count. */
if (kbhit()){ /* quit if ESC key hit */
if (getch() == ESC){
free_note_list(first_notep);
return(NULL);
}
}
ep = ep->next;
}
return(first_notep);
}
/* Free memory used for temporary note list. Used on exit from NLE. */
void
free_note_list(struct note_time far *np)
{
struct note_time far *nextp;
while (np != NULL){
nextp = np->next;
#if TURBOC
farfree(np);
#else
_ffree(np);
#endif
np = nextp;
}
}
/* Display all notes within screen boundaries as horiz. lines */
void
disp_notes(struct note_time far *first_notep, int first_measure, int beat)
{
int start_x, end_x;
struct note_time far *np;
g_first_tick = beat * TICK_PER_BEAT;
np = first_notep;
do { /* check if within 10 measures to avoid overflow */
if (abs(np->on_measure - first_measure) < 10 &&
abs(np->off_measure - first_measure) < 10){
draw_note(np, g_emph_color);
}
np = np->next;
} while (np != NULL);
}
/* put line on screen for note duration */
void
draw_note(struct note_time far *np, int color)
{
int ypos, start_x, end_x;
start_x = LEFT_BORDER + ((((np->on_measure - g_first_measure) *
TICK_PER_BEAT * g_meter) + np->on_tick - g_first_tick) *
MIN_SPACE)/g_scale;
end_x = LEFT_BORDER + ((((np->off_measure - g_first_measure) *
TICK_PER_BEAT * g_meter) + np->off_tick - g_first_tick) *
MIN_SPACE)/g_scale;
if ((start_x >= LEFT_BORDER + MIN_SPACE) &&
(start_x < g_dots_h) ||
(end_x >= LEFT_BORDER + MIN_SPACE) &&
(end_x < g_dots_h)){
if (np->note_number > g_top_note || np->note_number < g_bot_note)
return;
if (start_x < LEFT_BORDER + MIN_SPACE)
start_x = LEFT_BORDER + MIN_SPACE;
if (end_x > g_dots_h - 1)
end_x = g_dots_h - 1;
ypos = find_note_line(np->note_number);
drawline(start_x, ypos, end_x, ypos, color);
}
}
void
mark_middle_c(int first) /* put little m on middle C key on keyboard image */
{
static int ypos = 0; /* static to save last value of ypos */
if (ypos && !first) /* erase old m, unless first time or off scale */
xsprite(little_m, 40, ypos - 3, g_line_color);
ypos = find_note_line(60); /* Middle C is note 60 */
if (ypos)
xsprite(little_m, 40, ypos - 3, g_line_color);
}
/* Returns the screen line number for note. Returns 0 if note is outside */
/* of range displayed on screen. */
int
find_note_line(int note_no)
{
int ypos, note;
if (note_no > g_top_note || note_no < g_bot_note)
return(0);
ypos = g_top_note_line;
note = g_top_note;
while (note > note_no)
ypos += g_notes[note--].down_dots;
return(ypos);
}