native_midi_gpl/playevents.c
changeset 160 c62666b42573
equal deleted inserted replaced
159:01490534f9fe 160:c62666b42573
       
     1 /************************************************************************
       
     2    playevents.c  -- actually sends sorted list of events to device
       
     3 
       
     4    Copyright (C) 1994-1996 Nathan I. Laredo
       
     5 
       
     6    This program is modifiable/redistributable under the terms
       
     7    of the GNU General Public Licence.
       
     8 
       
     9    You should have received a copy of the GNU General Public License
       
    10    along with this program; if not, write to the Free Software
       
    11    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
       
    12    Send your comments and all your spare pocket change to
       
    13    laredo@gnu.ai.mit.edu (Nathan Laredo) or to PSC 1, BOX 709, 2401
       
    14    Kelly Drive, Lackland AFB, TX 78236-5128, USA.
       
    15  *************************************************************************/
       
    16 /*    edited by Peter Kutak           */
       
    17 /*    email : kutak@stonline.sk       */
       
    18 
       
    19 #if defined(linux) || defined(__FreeBSD__)
       
    20 
       
    21 #include "playmidi.h"
       
    22 #include <sys/time.h>
       
    23 
       
    24 extern int seq_set_patch(int, int);
       
    25 extern void seq_key_pressure(int, int, int, int);
       
    26 extern void seq_start_note(int, int, int, int);
       
    27 extern void seq_stop_note(int, int, int, int);
       
    28 extern void seq_control(int, int, int, int);
       
    29 extern void seq_chn_pressure(int, int, int);
       
    30 extern void seq_bender(int, int, int, int);
       
    31 extern void seq_reset();
       
    32 
       
    33 SEQ_USE_EXTBUF();
       
    34 extern int division, ntrks, format;
       
    35 extern int gus_dev, ext_dev, sb_dev, awe_dev, perc, seqfd, p_remap;
       
    36 extern int play_gus, play_fm, play_ext, play_awe, reverb, chorus, chanmask;
       
    37 extern int usevol[16];
       
    38 extern struct miditrack seq[MAXTRKS];
       
    39 extern float skew;
       
    40 extern unsigned long int default_tempo;
       
    41 extern char ImPlaying,StopPlease;
       
    42 extern void load_sysex(int, unsigned char *, int);
       
    43 
       
    44 unsigned long int ticks, tempo;
       
    45 struct timeval start_time;
       
    46 
       
    47 unsigned long int rvl(s)
       
    48 struct miditrack *s;
       
    49 {
       
    50     register unsigned long int value = 0;
       
    51     register unsigned char c;
       
    52 
       
    53     if (s->index < s->length && ((value = s->data[(s->index)++]) & 0x80)) {
       
    54 	value &= 0x7f;
       
    55 	do {
       
    56 	    if (s->index >= s->length)
       
    57 		c = 0;
       
    58 	    else
       
    59 		value = (value << 7) +
       
    60 		    ((c = s->data[(s->index)++]) & 0x7f);
       
    61 	} while (c & 0x80);
       
    62     }
       
    63     return (value);
       
    64 }
       
    65 
       
    66 /* indexed by high nibble of command */
       
    67 int cmdlen[16] =
       
    68 {0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0};
       
    69 
       
    70 #define CMD		seq[track].running_st
       
    71 #define TIME		seq[track].ticks
       
    72 #define CHN		(CMD & 0xf)
       
    73 #define NOTE		data[0]
       
    74 #define VEL		data[1]
       
    75 
       
    76 int playevents()
       
    77 {
       
    78     unsigned long int tempo = default_tempo, lasttime = 0;
       
    79     unsigned int lowtime, track, best, length, loaded;
       
    80     unsigned char *data;
       
    81     double current = 0.0, dtime = 0.0;
       
    82     int use_dev, play_status, playing = 1;
       
    83 
       
    84     seq_reset();
       
    85     gettimeofday(&start_time, NULL);	/* for synchronization */
       
    86     for (track = 0; track < ntrks; track++) {
       
    87 	seq[track].index = seq[track].running_st = 0;
       
    88 	seq[track].ticks = rvl(&seq[track]);
       
    89     }
       
    90     for (best = 0; best < 16; best++) {
       
    91 	if (ISAWE(best))
       
    92 	    use_dev = awe_dev;
       
    93 	else if (ISGUS(best))
       
    94 	    use_dev = gus_dev;
       
    95 	else if (ISFM(best))
       
    96 	    use_dev = sb_dev;
       
    97 	else
       
    98 	    use_dev = ext_dev;
       
    99 	seq_control(use_dev, best, CTL_BANK_SELECT, 0);
       
   100 	seq_control(use_dev, best, CTL_EXT_EFF_DEPTH, reverb);
       
   101 	seq_control(use_dev, best, CTL_CHORUS_DEPTH, chorus);
       
   102 	seq_control(use_dev, best, CTL_MAIN_VOLUME, 127);
       
   103 	seq_chn_pressure(use_dev, best, 127);
       
   104 	seq_control(use_dev, best, 0x4a, 127);
       
   105     }
       
   106     SEQ_START_TIMER();
       
   107     SEQ_DUMPBUF();
       
   108     while (playing) {
       
   109 	lowtime = ~0;
       
   110 	for (best = track = 0; track < ntrks; track++)
       
   111 	    if (seq[track].ticks < lowtime) {
       
   112 		best = track;
       
   113 		lowtime = TIME;
       
   114 	    }
       
   115 	if (lowtime == ~0)
       
   116 	    break;		/* no more data to read */
       
   117 	track = best;
       
   118 	if (ISMIDI(CHN))
       
   119 	    use_dev = ext_dev;
       
   120 	else if (ISAWE(CHN))
       
   121 	    use_dev = awe_dev;
       
   122 	else if (ISGUS(CHN))
       
   123 	    use_dev = gus_dev;
       
   124 	else
       
   125 	    use_dev = sb_dev;
       
   126 
       
   127 	/* this section parses data in midi file buffer */
       
   128 	if ((seq[track].data[seq[track].index] & 0x80) &&
       
   129 	    (seq[track].index < seq[track].length))
       
   130 	    CMD = seq[track].data[seq[track].index++];
       
   131 	if (CMD == 0xff && seq[track].index < seq[track].length)
       
   132 	    CMD = seq[track].data[seq[track].index++];
       
   133 	if (CMD > 0xf7)	/* midi real-time message (ignored) */
       
   134 	    length = 0;
       
   135 	else if (!(length = cmdlen[(CMD & 0xf0) >> 4]))
       
   136 	    length = rvl(&seq[track]);
       
   137 
       
   138 	if (seq[track].index + length < seq[track].length) {
       
   139 	    /* use the parsed midi data */
       
   140 	    data = &(seq[track].data[seq[track].index]);
       
   141 	    if (CMD == set_tempo)
       
   142 		tempo = ((*(data) << 16) | (data[1] << 8) | data[2]);
       
   143 	    if (TIME > lasttime) {
       
   144 		if (division > 0) {
       
   145 		    dtime = ((double) ((TIME - lasttime) * (tempo / 10000)) /
       
   146 			     (double) (division)) * skew;
       
   147 		    current += dtime;
       
   148 		    lasttime = TIME;
       
   149 		} else if (division < 0)
       
   150 		    current = ((double) TIME /
       
   151 			       ((double) ((division & 0xff00 >> 8) *
       
   152 				   (division & 0xff)) * 10000.0)) * skew;
       
   153 		/* stop if there's more than 40 seconds of nothing */
       
   154 		if (dtime > 4096.0)
       
   155 		    playing = 0;
       
   156 		else if ((int) current > ticks) {
       
   157 		    SEQ_WAIT_TIME((ticks = (int) current));
       
   158 		    SEQ_DUMPBUF();
       
   159 		}
       
   160 	    }
       
   161 	    if (CMD > 0x7f && CMD < 0xf0 && ISPERC(CHN) && p_remap) {
       
   162 		CMD &= 0xf0;
       
   163 		CMD |= (p_remap - 1);
       
   164 	    }
       
   165 	    loaded = 0;		/* for patch setting failures */
       
   166 	    if (playing && CMD > 0x7f && ISPLAYING(CHN))
       
   167 		switch (CMD & 0xf0) {
       
   168 		case MIDI_KEY_PRESSURE:
       
   169 		    if (ISPERC(CHN) && VEL && (!ISMIDI(CHN)&&!ISAWE(CHN)))
       
   170 			loaded = seq_set_patch(CHN, NOTE + 128);
       
   171 		    if (loaded != -1)
       
   172 			seq_key_pressure(use_dev, CHN, NOTE, VEL);
       
   173 		    break;
       
   174 		case MIDI_NOTEON:
       
   175 		    if (ISPERC(CHN) && VEL && (!ISMIDI(CHN)&&!ISAWE(CHN)))
       
   176 			loaded = seq_set_patch(CHN, NOTE + 128);
       
   177 		    if (VEL && usevol[CHN])
       
   178 			VEL = usevol[CHN];
       
   179 		    if (loaded != -1)
       
   180 			seq_start_note(use_dev, CHN, NOTE, VEL);
       
   181 		    break;
       
   182 		case MIDI_NOTEOFF:
       
   183 		    seq_stop_note(use_dev, CHN, NOTE, VEL);
       
   184 		    break;
       
   185 		case MIDI_CTL_CHANGE:
       
   186 		    seq_control(use_dev, CHN, NOTE, VEL);
       
   187 		    break;
       
   188 		case MIDI_CHN_PRESSURE:
       
   189 		    seq_chn_pressure(use_dev, CHN, NOTE);
       
   190 		    break;
       
   191 		case MIDI_PITCH_BEND:
       
   192 		    seq_bender(use_dev, CHN, NOTE, VEL);
       
   193 		    break;
       
   194 		case MIDI_PGM_CHANGE:
       
   195 		    if (ISMIDI(CHN) || ISAWE(CHN) || !ISPERC(CHN))
       
   196 			NOTE = seq_set_patch(CHN, NOTE);
       
   197 		    break;
       
   198 		case MIDI_SYSTEM_PREFIX:
       
   199 		    if (length > 1)
       
   200 			load_sysex(length, data, CMD);
       
   201 		    break;
       
   202 		default:
       
   203 		    break;
       
   204 		}
       
   205 	}
       
   206 	/* this last little part queues up the next event time */
       
   207 	seq[track].index += length;
       
   208 	if (seq[track].index >= seq[track].length)
       
   209 	    seq[track].ticks = ~0;	/* mark track complete */
       
   210 	else
       
   211 	    seq[track].ticks += rvl(&seq[track]);
       
   212     }
       
   213     SEQ_DUMPBUF();
       
   214     ImPlaying = 0;
       
   215     return 1;
       
   216 }
       
   217 #endif /* linux || FreeBSD */