1d5ac70f0Sopenharmony_ci/*
2d5ac70f0Sopenharmony_ci * midifile 1.11
3d5ac70f0Sopenharmony_ci *
4d5ac70f0Sopenharmony_ci * Read and write a MIDI file.  Externally-assigned function pointers are
5d5ac70f0Sopenharmony_ci * called upon recognizing things in the file.
6d5ac70f0Sopenharmony_ci *
7d5ac70f0Sopenharmony_ci * Original release ?
8d5ac70f0Sopenharmony_ci * June 1989 - Added writing capability, M. Czeiszperger.
9d5ac70f0Sopenharmony_ci *
10d5ac70f0Sopenharmony_ci *          The file format implemented here is called
11d5ac70f0Sopenharmony_ci *          Standard MIDI Files, and is part of the Musical
12d5ac70f0Sopenharmony_ci *          instrument Digital Interface specification.
13d5ac70f0Sopenharmony_ci *          The spec is available from:
14d5ac70f0Sopenharmony_ci *
15d5ac70f0Sopenharmony_ci *               International MIDI Association
16d5ac70f0Sopenharmony_ci *               5316 West 57th Street
17d5ac70f0Sopenharmony_ci *               Los Angeles, CA 90056
18d5ac70f0Sopenharmony_ci *
19d5ac70f0Sopenharmony_ci *          An in-depth description of the spec can also be found
20d5ac70f0Sopenharmony_ci *          in the article "Introducing Standard MIDI Files", published
21d5ac70f0Sopenharmony_ci *          in Electronic Musician magazine, April, 1989.
22d5ac70f0Sopenharmony_ci *
23d5ac70f0Sopenharmony_ci * February 1993 - Minor adjustments, Greg Lee:
24d5ac70f0Sopenharmony_ci *	(1) can now set the global variable Mf_interactive to 1 to prevent the
25d5ac70f0Sopenharmony_ci *	    reading functions from looking for file and track headers
26d5ac70f0Sopenharmony_ci *	(2) can now write system exclusive data with
27d5ac70f0Sopenharmony_ci *		mf_write_midi_event(delta_time, system_exclusive, 0, data, size)
28d5ac70f0Sopenharmony_ci *	(3) changed definition of 'sequencer_specific' in midifile.h to 0x7f
29d5ac70f0Sopenharmony_ci *	(4) changed mf_write_tempo to take additional delta_time as first argument
30d5ac70f0Sopenharmony_ci *	    (since delta need not be zero)
31d5ac70f0Sopenharmony_ci *	(5) added function mf_write_seqnum(unsigned long delta_time, unsigned seqnum)
32d5ac70f0Sopenharmony_ci *	(6) changed mf_write_midi_event to use running status
33d5ac70f0Sopenharmony_ci *	(7) removed the code to write an end of track meta event automatically
34d5ac70f0Sopenharmony_ci *		-- this must now be done by the user of the library (I changed
35d5ac70f0Sopenharmony_ci *		it because I need to be able to control the time delta of this
36d5ac70f0Sopenharmony_ci *		 meta event)
37d5ac70f0Sopenharmony_ci *	(8) added global variables Mf_division, Mf_currtempo, Mf_realtime, which
38d5ac70f0Sopenharmony_ci *		are updated by the reading functions.  Mf_realtime is useful,
39d5ac70f0Sopenharmony_ci *		because Mf_currtime does not really measure time at all, since
40d5ac70f0Sopenharmony_ci *		its units change value at every tempo change.  Mf_realtime is
41d5ac70f0Sopenharmony_ci *		the midi-time elapsed in units of 1/16 of a centisecond (but it
42d5ac70f0Sopenharmony_ci *		does not handle SMPTE times)
43d5ac70f0Sopenharmony_ci *	(9) maintains a history of tempo settings to update Mf_currtempo,
44d5ac70f0Sopenharmony_ci *		to handle tempo tracks.
45d5ac70f0Sopenharmony_ci *	(10) if there is an Mf_error function, the error routine no longer
46d5ac70f0Sopenharmony_ci *		exits, leaving it to the application to do this.
47d5ac70f0Sopenharmony_ci *	(11) chanmessage skips over invalid c1 command bytes > 127 and
48d5ac70f0Sopenharmony_ci *		adjusts invalid c2 argument byte > 127 to 127.
49d5ac70f0Sopenharmony_ci *	(12) readmt returns EOF when it encounters a 0 or 0x1a byte instead of an expected
50d5ac70f0Sopenharmony_ci *		header string (some midi files have padding at end).
51d5ac70f0Sopenharmony_ci */
52d5ac70f0Sopenharmony_ci#define NO_LC_DEFINES
53d5ac70f0Sopenharmony_ci#include "midifile.h"
54d5ac70f0Sopenharmony_ci#ifdef NO_LC_DEFINES
55d5ac70f0Sopenharmony_ci#define system_exclusive      	0xf0
56d5ac70f0Sopenharmony_ci#define	meta_event		0xFF
57d5ac70f0Sopenharmony_ci#define	set_tempo		0x51
58d5ac70f0Sopenharmony_ci#define lowerbyte(x) ((unsigned char)(x & 0xff))
59d5ac70f0Sopenharmony_ci#define upperbyte(x) ((unsigned char)((x & 0xff00)>>8))
60d5ac70f0Sopenharmony_ci#endif
61d5ac70f0Sopenharmony_ci
62d5ac70f0Sopenharmony_ci#define NULLFUNC 0
63d5ac70f0Sopenharmony_ci#if 0
64d5ac70f0Sopenharmony_ci#define NULL 0
65d5ac70f0Sopenharmony_ci#endif
66d5ac70f0Sopenharmony_ci
67d5ac70f0Sopenharmony_ci#define THINK
68d5ac70f0Sopenharmony_ci
69d5ac70f0Sopenharmony_ci#ifdef THINK
70d5ac70f0Sopenharmony_ci#include <stdlib.h>
71d5ac70f0Sopenharmony_ci#endif
72d5ac70f0Sopenharmony_ci
73d5ac70f0Sopenharmony_ci#include <stdio.h>
74d5ac70f0Sopenharmony_ci#include <limits.h>
75d5ac70f0Sopenharmony_ci
76d5ac70f0Sopenharmony_ci#include <string.h>
77d5ac70f0Sopenharmony_ci/*void exit(), free();*/
78d5ac70f0Sopenharmony_ci
79d5ac70f0Sopenharmony_ci/* public stuff */
80d5ac70f0Sopenharmony_ci
81d5ac70f0Sopenharmony_ci/* Functions to be called while processing the MIDI file. */
82d5ac70f0Sopenharmony_ciint (*Mf_getc) () = NULLFUNC;
83d5ac70f0Sopenharmony_civoid (*Mf_error) () = NULLFUNC;
84d5ac70f0Sopenharmony_civoid (*Mf_header) () = NULLFUNC;
85d5ac70f0Sopenharmony_civoid (*Mf_trackstart) () = NULLFUNC;
86d5ac70f0Sopenharmony_civoid (*Mf_trackend) () = NULLFUNC;
87d5ac70f0Sopenharmony_civoid (*Mf_noteon) () = NULLFUNC;
88d5ac70f0Sopenharmony_civoid (*Mf_noteoff) () = NULLFUNC;
89d5ac70f0Sopenharmony_civoid (*Mf_pressure) () = NULLFUNC;
90d5ac70f0Sopenharmony_civoid (*Mf_parameter) () = NULLFUNC;
91d5ac70f0Sopenharmony_civoid (*Mf_pitchbend) () = NULLFUNC;
92d5ac70f0Sopenharmony_civoid (*Mf_program) () = NULLFUNC;
93d5ac70f0Sopenharmony_civoid (*Mf_chanpressure) () = NULLFUNC;
94d5ac70f0Sopenharmony_civoid (*Mf_sysex) () = NULLFUNC;
95d5ac70f0Sopenharmony_civoid (*Mf_arbitrary) () = NULLFUNC;
96d5ac70f0Sopenharmony_civoid (*Mf_metamisc) () = NULLFUNC;
97d5ac70f0Sopenharmony_civoid (*Mf_seqnum) () = NULLFUNC;
98d5ac70f0Sopenharmony_civoid (*Mf_eot) () = NULLFUNC;
99d5ac70f0Sopenharmony_civoid (*Mf_smpte) () = NULLFUNC;
100d5ac70f0Sopenharmony_civoid (*Mf_tempo) () = NULLFUNC;
101d5ac70f0Sopenharmony_civoid (*Mf_timesig) () = NULLFUNC;
102d5ac70f0Sopenharmony_civoid (*Mf_keysig) () = NULLFUNC;
103d5ac70f0Sopenharmony_civoid (*Mf_seqspecific) () = NULLFUNC;
104d5ac70f0Sopenharmony_civoid (*Mf_text) () = NULLFUNC;
105d5ac70f0Sopenharmony_ci
106d5ac70f0Sopenharmony_ci/* Functions to implement in order to write a MIDI file */
107d5ac70f0Sopenharmony_ciint (*Mf_putc) () = NULLFUNC;
108d5ac70f0Sopenharmony_ciint (*Mf_writetrack) () = NULLFUNC;
109d5ac70f0Sopenharmony_ciint (*Mf_writetempotrack) () = NULLFUNC;
110d5ac70f0Sopenharmony_ci
111d5ac70f0Sopenharmony_ciint Mf_nomerge = 0;		/* 1 => continue'ed system exclusives are */
112d5ac70f0Sopenharmony_ci /* not collapsed. */
113d5ac70f0Sopenharmony_ciint Mf_interactive = 0;		/* 1 => file and track headers are not required */
114d5ac70f0Sopenharmony_ciunsigned long Mf_currtime = 0L;	/* current time in delta-time units */
115d5ac70f0Sopenharmony_ciunsigned long Mf_realtime = 0L;	/* current time in 1/16 centisecond-time units */
116d5ac70f0Sopenharmony_cistatic double Mf_f_realtime = 0;/* as above, floating */
117d5ac70f0Sopenharmony_cistatic double old_f_realtime = 0;
118d5ac70f0Sopenharmony_ciint Mf_division = 96;
119d5ac70f0Sopenharmony_ciunsigned long Mf_currtempo = 500000;
120d5ac70f0Sopenharmony_cistatic unsigned long old_currtempo = 500000;
121d5ac70f0Sopenharmony_cistatic unsigned long old_realtime = 0;
122d5ac70f0Sopenharmony_cistatic unsigned long old_currtime = 0;
123d5ac70f0Sopenharmony_cistatic unsigned long revised_time = 0;
124d5ac70f0Sopenharmony_cistatic unsigned long tempo_change_time = 0;
125d5ac70f0Sopenharmony_ci
126d5ac70f0Sopenharmony_ci#define MAX_HISTORY 512
127d5ac70f0Sopenharmony_cistatic unsigned long tempo_history[MAX_HISTORY];
128d5ac70f0Sopenharmony_cistatic unsigned long tempo_history_time[MAX_HISTORY];
129d5ac70f0Sopenharmony_cistatic int tempo_history_count = 0;
130d5ac70f0Sopenharmony_ci
131d5ac70f0Sopenharmony_ci/* private stuff */
132d5ac70f0Sopenharmony_cistatic long Mf_toberead = 0L;
133d5ac70f0Sopenharmony_cistatic long Mf_numbyteswritten = 0L;
134d5ac70f0Sopenharmony_ci
135d5ac70f0Sopenharmony_cistatic long readvarinum ();
136d5ac70f0Sopenharmony_cistatic long read32bit ();
137d5ac70f0Sopenharmony_cistatic long to32bit ();
138d5ac70f0Sopenharmony_cistatic int read16bit ();
139d5ac70f0Sopenharmony_cistatic int to16bit ();
140d5ac70f0Sopenharmony_cistatic char *msg ();
141d5ac70f0Sopenharmony_cistatic void readheader ();
142d5ac70f0Sopenharmony_cistatic int readtrack ();
143d5ac70f0Sopenharmony_cistatic void badbyte ();
144d5ac70f0Sopenharmony_cistatic void metaevent ();
145d5ac70f0Sopenharmony_cistatic void sysex ();
146d5ac70f0Sopenharmony_cistatic void chanmessage ();
147d5ac70f0Sopenharmony_cistatic void msginit ();
148d5ac70f0Sopenharmony_cistatic int msgleng ();
149d5ac70f0Sopenharmony_cistatic void msgadd ();
150d5ac70f0Sopenharmony_cistatic void biggermsg ();
151d5ac70f0Sopenharmony_cistatic int eputc ();
152d5ac70f0Sopenharmony_ci
153d5ac70f0Sopenharmony_cidouble mf_ticks2sec (unsigned long ticks, int division, unsigned long tempo);
154d5ac70f0Sopenharmony_ciint mf_write_meta_event ();
155d5ac70f0Sopenharmony_civoid mf_write_tempo ();
156d5ac70f0Sopenharmony_civoid mf_write_seqnum ();
157d5ac70f0Sopenharmony_civoid WriteVarLen ();
158d5ac70f0Sopenharmony_ci
159d5ac70f0Sopenharmony_ci#ifdef READ_MODS
160d5ac70f0Sopenharmony_ci#include "mp_mod.c"
161d5ac70f0Sopenharmony_cistatic int mod_file_flag = 0;
162d5ac70f0Sopenharmony_ci#endif /* READ_MODS */
163d5ac70f0Sopenharmony_cistatic int force_exit;
164d5ac70f0Sopenharmony_ci
165d5ac70f0Sopenharmony_civoid
166d5ac70f0Sopenharmony_cimfread ()
167d5ac70f0Sopenharmony_ci{
168d5ac70f0Sopenharmony_ci  force_exit = 0;
169d5ac70f0Sopenharmony_ci  if (Mf_getc == NULLFUNC)
170d5ac70f0Sopenharmony_ci    mferror ("mfread() called without setting Mf_getc");
171d5ac70f0Sopenharmony_ci
172d5ac70f0Sopenharmony_ci  readheader ();
173d5ac70f0Sopenharmony_ci#ifdef READ_MODS
174d5ac70f0Sopenharmony_ci  if (mod_file_flag)
175d5ac70f0Sopenharmony_ci    do_module();
176d5ac70f0Sopenharmony_ci  else
177d5ac70f0Sopenharmony_ci#endif
178d5ac70f0Sopenharmony_ci    while (readtrack () && !force_exit)
179d5ac70f0Sopenharmony_ci      ;
180d5ac70f0Sopenharmony_ci}
181d5ac70f0Sopenharmony_ci
182d5ac70f0Sopenharmony_ci/* for backward compatibility with the original lib */
183d5ac70f0Sopenharmony_civoid
184d5ac70f0Sopenharmony_cimidifile ()
185d5ac70f0Sopenharmony_ci{
186d5ac70f0Sopenharmony_ci  mfread ();
187d5ac70f0Sopenharmony_ci}
188d5ac70f0Sopenharmony_ci
189d5ac70f0Sopenharmony_cistatic
190d5ac70f0Sopenharmony_ciint
191d5ac70f0Sopenharmony_cireadmt (s)			/* read through the "MThd" or "MTrk" header string */
192d5ac70f0Sopenharmony_ci     char *s;
193d5ac70f0Sopenharmony_ci{
194d5ac70f0Sopenharmony_ci  int n = 0;
195d5ac70f0Sopenharmony_ci  char *p = s;
196d5ac70f0Sopenharmony_ci  int c;
197d5ac70f0Sopenharmony_ci
198d5ac70f0Sopenharmony_ci  while (n++ < 4 && (c = (*Mf_getc) ()) != EOF)
199d5ac70f0Sopenharmony_ci    {
200d5ac70f0Sopenharmony_ci      if (c != *p++)
201d5ac70f0Sopenharmony_ci	{
202d5ac70f0Sopenharmony_ci	  char buff[32];
203d5ac70f0Sopenharmony_ci	  if (!c) return(EOF);
204d5ac70f0Sopenharmony_ci	  if (c == 0x1a) return(EOF);
205d5ac70f0Sopenharmony_ci	  (void) strcpy (buff, "expecting ");
206d5ac70f0Sopenharmony_ci	  (void) strcat (buff, s);
207d5ac70f0Sopenharmony_ci	  mferror (buff);
208d5ac70f0Sopenharmony_ci	  break;
209d5ac70f0Sopenharmony_ci	}
210d5ac70f0Sopenharmony_ci    }
211d5ac70f0Sopenharmony_ci  return (c);
212d5ac70f0Sopenharmony_ci}
213d5ac70f0Sopenharmony_ci
214d5ac70f0Sopenharmony_cistatic
215d5ac70f0Sopenharmony_ciint
216d5ac70f0Sopenharmony_ciegetc ()			/* read a single character and abort on EOF */
217d5ac70f0Sopenharmony_ci{
218d5ac70f0Sopenharmony_ci  int c = (*Mf_getc) ();
219d5ac70f0Sopenharmony_ci
220d5ac70f0Sopenharmony_ci  if (c == EOF) {
221d5ac70f0Sopenharmony_ci    mferror ("premature EOF");
222d5ac70f0Sopenharmony_ci    force_exit = 1;
223d5ac70f0Sopenharmony_ci  }
224d5ac70f0Sopenharmony_ci  Mf_toberead--;
225d5ac70f0Sopenharmony_ci  return (c);
226d5ac70f0Sopenharmony_ci}
227d5ac70f0Sopenharmony_ci
228d5ac70f0Sopenharmony_cistatic
229d5ac70f0Sopenharmony_civoid
230d5ac70f0Sopenharmony_cireadheader ()			/* read a header chunk */
231d5ac70f0Sopenharmony_ci{
232d5ac70f0Sopenharmony_ci  int format, ntrks, division;
233d5ac70f0Sopenharmony_ci
234d5ac70f0Sopenharmony_ci
235d5ac70f0Sopenharmony_ci  Mf_division = 96;
236d5ac70f0Sopenharmony_ci  Mf_currtempo = 500000;
237d5ac70f0Sopenharmony_ci  old_currtempo = 500000;
238d5ac70f0Sopenharmony_ci  tempo_history_count = 0;
239d5ac70f0Sopenharmony_ci  tempo_history[tempo_history_count] = Mf_currtempo;
240d5ac70f0Sopenharmony_ci  tempo_history_time[tempo_history_count] = 0;
241d5ac70f0Sopenharmony_ci
242d5ac70f0Sopenharmony_ci  if (Mf_interactive)
243d5ac70f0Sopenharmony_ci    {
244d5ac70f0Sopenharmony_ci      Mf_toberead = 0;
245d5ac70f0Sopenharmony_ci      format = 0;
246d5ac70f0Sopenharmony_ci      ntrks = 1;
247d5ac70f0Sopenharmony_ci      division = 96;
248d5ac70f0Sopenharmony_ci    }
249d5ac70f0Sopenharmony_ci  else
250d5ac70f0Sopenharmony_ci#ifdef READ_MODS
251d5ac70f0Sopenharmony_ci    if (!strncmp(Mf_file_contents, "MThd", 4))
252d5ac70f0Sopenharmony_ci#endif
253d5ac70f0Sopenharmony_ci    {
254d5ac70f0Sopenharmony_ci      if (readmt ("MThd") == EOF)
255d5ac70f0Sopenharmony_ci	return;
256d5ac70f0Sopenharmony_ci
257d5ac70f0Sopenharmony_ci      Mf_toberead = read32bit ();
258d5ac70f0Sopenharmony_ci      format = read16bit ();
259d5ac70f0Sopenharmony_ci      ntrks = read16bit ();
260d5ac70f0Sopenharmony_ci      Mf_division = division = read16bit ();
261d5ac70f0Sopenharmony_ci    }
262d5ac70f0Sopenharmony_ci#ifdef READ_MODS
263d5ac70f0Sopenharmony_ci  else
264d5ac70f0Sopenharmony_ci    {
265d5ac70f0Sopenharmony_ci      format = 0;
266d5ac70f0Sopenharmony_ci      ntrks = 1;
267d5ac70f0Sopenharmony_ci      division = Mf_division;
268d5ac70f0Sopenharmony_ci      Mf_toberead = 0;
269d5ac70f0Sopenharmony_ci      mod_file_flag = 1;
270d5ac70f0Sopenharmony_ci    }
271d5ac70f0Sopenharmony_ci#endif
272d5ac70f0Sopenharmony_ci
273d5ac70f0Sopenharmony_ci  if (Mf_header)
274d5ac70f0Sopenharmony_ci    (*Mf_header) (format, ntrks, division);
275d5ac70f0Sopenharmony_ci
276d5ac70f0Sopenharmony_ci  /* flush any extra stuff, in case the length of header is not 6 */
277d5ac70f0Sopenharmony_ci  while (Mf_toberead > 0 && !force_exit)
278d5ac70f0Sopenharmony_ci    (void) egetc ();
279d5ac70f0Sopenharmony_ci}
280d5ac70f0Sopenharmony_ci
281d5ac70f0Sopenharmony_ci
282d5ac70f0Sopenharmony_ci/*#define DEBUG_TIMES*/
283d5ac70f0Sopenharmony_cistatic
284d5ac70f0Sopenharmony_ciunsigned long
285d5ac70f0Sopenharmony_cifind_tempo()
286d5ac70f0Sopenharmony_ci{
287d5ac70f0Sopenharmony_ci  int i;
288d5ac70f0Sopenharmony_ci  unsigned long old_tempo = Mf_currtempo;
289d5ac70f0Sopenharmony_ci  unsigned long new_tempo = Mf_currtempo;
290d5ac70f0Sopenharmony_ci
291d5ac70f0Sopenharmony_ci  for (i = 0; i <= tempo_history_count; i++) {
292d5ac70f0Sopenharmony_ci    if (tempo_history_time[i] <= Mf_currtime) old_tempo = tempo_history[i];
293d5ac70f0Sopenharmony_ci    new_tempo = tempo_history[i];
294d5ac70f0Sopenharmony_ci    if (tempo_history_time[i] > revised_time) break;
295d5ac70f0Sopenharmony_ci  }
296d5ac70f0Sopenharmony_ci  if (i > tempo_history_count || tempo_history_time[i] > Mf_currtime) {
297d5ac70f0Sopenharmony_ci#ifdef DEBUG_TIMES
298d5ac70f0Sopenharmony_ciprintf("[past %lu, old_tempo %lu]\n", tempo_history_time[i], old_tempo);
299d5ac70f0Sopenharmony_ci#endif
300d5ac70f0Sopenharmony_ci    revised_time = Mf_currtime;
301d5ac70f0Sopenharmony_ci    return(old_tempo);
302d5ac70f0Sopenharmony_ci  }
303d5ac70f0Sopenharmony_ci  tempo_change_time = revised_time = tempo_history_time[i];
304d5ac70f0Sopenharmony_ci#ifdef DEBUG_TIMES
305d5ac70f0Sopenharmony_ciprintf("[revised_time %lu, new_tempo %lu]\n", revised_time, new_tempo);
306d5ac70f0Sopenharmony_ci#endif
307d5ac70f0Sopenharmony_ci  return(new_tempo);
308d5ac70f0Sopenharmony_ci}
309d5ac70f0Sopenharmony_ci
310d5ac70f0Sopenharmony_cistatic
311d5ac70f0Sopenharmony_ciint
312d5ac70f0Sopenharmony_cireadtrack ()			/* read a track chunk */
313d5ac70f0Sopenharmony_ci{
314d5ac70f0Sopenharmony_ci  /* This array is indexed by the high half of a status byte.  It's */
315d5ac70f0Sopenharmony_ci  /* value is either the number of bytes needed (1 or 2) for a channel */
316d5ac70f0Sopenharmony_ci  /* message, or 0 (meaning it's not  a channel message). */
317d5ac70f0Sopenharmony_ci  static int chantype[] =
318d5ac70f0Sopenharmony_ci  {
319d5ac70f0Sopenharmony_ci    0, 0, 0, 0, 0, 0, 0, 0,	/* 0x00 through 0x70 */
320d5ac70f0Sopenharmony_ci    2, 2, 2, 2, 1, 1, 2, 0	/* 0x80 through 0xf0 */
321d5ac70f0Sopenharmony_ci  };
322d5ac70f0Sopenharmony_ci  long lookfor;
323d5ac70f0Sopenharmony_ci  int c, c1, type;
324d5ac70f0Sopenharmony_ci  int sysexcontinue = 0;	/* 1 if last message was an unfinished sysex */
325d5ac70f0Sopenharmony_ci  int running = 0;		/* 1 when running status used */
326d5ac70f0Sopenharmony_ci  int status = 0;		/* status value (e.g. 0x90==note-on) */
327d5ac70f0Sopenharmony_ci  int needed;
328d5ac70f0Sopenharmony_ci
329d5ac70f0Sopenharmony_ci  if (Mf_interactive)
330d5ac70f0Sopenharmony_ci    {
331d5ac70f0Sopenharmony_ci      Mf_toberead = INT_MAX;
332d5ac70f0Sopenharmony_ci    }
333d5ac70f0Sopenharmony_ci  else
334d5ac70f0Sopenharmony_ci    {
335d5ac70f0Sopenharmony_ci      if (readmt ("MTrk") == EOF)
336d5ac70f0Sopenharmony_ci	return (0);
337d5ac70f0Sopenharmony_ci
338d5ac70f0Sopenharmony_ci      Mf_toberead = read32bit ();
339d5ac70f0Sopenharmony_ci    }
340d5ac70f0Sopenharmony_ci  Mf_currtime = Mf_realtime = 0;
341d5ac70f0Sopenharmony_ci  Mf_f_realtime = old_f_realtime = 0;
342d5ac70f0Sopenharmony_ci  old_currtime = old_realtime = 0;
343d5ac70f0Sopenharmony_ci  Mf_currtempo = find_tempo();
344d5ac70f0Sopenharmony_ci
345d5ac70f0Sopenharmony_ci  if (Mf_trackstart)
346d5ac70f0Sopenharmony_ci    (*Mf_trackstart) ();
347d5ac70f0Sopenharmony_ci
348d5ac70f0Sopenharmony_ci  while (!force_exit && (Mf_interactive || Mf_toberead > 0))
349d5ac70f0Sopenharmony_ci    {
350d5ac70f0Sopenharmony_ci
351d5ac70f0Sopenharmony_ci      if (Mf_interactive)
352d5ac70f0Sopenharmony_ci	Mf_currtime += 1;
353d5ac70f0Sopenharmony_ci      else
354d5ac70f0Sopenharmony_ci	{
355d5ac70f0Sopenharmony_ci	  double delta_secs;
356d5ac70f0Sopenharmony_ci	  unsigned long delta_ticks = readvarinum ();
357d5ac70f0Sopenharmony_ci	  revised_time = Mf_currtime;
358d5ac70f0Sopenharmony_ci	  Mf_currtime += delta_ticks;	/* delta time */
359d5ac70f0Sopenharmony_ci
360d5ac70f0Sopenharmony_ci/*
361d5ac70f0Sopenharmony_ci * Step through each tempo change from old_currtime up to now,
362d5ac70f0Sopenharmony_ci * revising Mf_realtime after each change.
363d5ac70f0Sopenharmony_ci */
364d5ac70f0Sopenharmony_ci
365d5ac70f0Sopenharmony_ci	  while (revised_time < Mf_currtime) {
366d5ac70f0Sopenharmony_ci	    unsigned long save_time = revised_time;
367d5ac70f0Sopenharmony_ci	    unsigned long save_tempo = Mf_currtempo;
368d5ac70f0Sopenharmony_ci	    Mf_currtempo = find_tempo();
369d5ac70f0Sopenharmony_ci
370d5ac70f0Sopenharmony_ci	    if (Mf_currtempo != old_currtempo) {
371d5ac70f0Sopenharmony_ci	      old_currtempo = Mf_currtempo;
372d5ac70f0Sopenharmony_ci	      old_realtime = Mf_realtime;
373d5ac70f0Sopenharmony_ci	      if (revised_time != tempo_change_time) {
374d5ac70f0Sopenharmony_ci	        old_f_realtime = Mf_f_realtime;
375d5ac70f0Sopenharmony_ci	        old_currtime = save_time;
376d5ac70f0Sopenharmony_ci	      }
377d5ac70f0Sopenharmony_ci	    delta_secs = mf_ticks2sec (revised_time-old_currtime, Mf_division, save_tempo);
378d5ac70f0Sopenharmony_ci#ifdef DEBUG_TIMES
379d5ac70f0Sopenharmony_ciprintf("d(rev %lu - old %lu, div %d, tempo %lu) = %.3f\n",
380d5ac70f0Sopenharmony_cirevised_time, old_currtime, Mf_division, save_tempo, delta_secs * 1600.0);
381d5ac70f0Sopenharmony_ci#endif
382d5ac70f0Sopenharmony_ci	    Mf_f_realtime = old_f_realtime + delta_secs * 1600.0;
383d5ac70f0Sopenharmony_ci	    Mf_realtime = (unsigned long)(0.5 + Mf_f_realtime);
384d5ac70f0Sopenharmony_ci#ifdef DEBUG_TIMES
385d5ac70f0Sopenharmony_ciprintf("\tt=%lu ticks ( = %lu csec/16 < old %.2f + %.2f)\n", Mf_currtime, Mf_realtime,
386d5ac70f0Sopenharmony_ciold_f_realtime, delta_secs * 1600.0);
387d5ac70f0Sopenharmony_ci#endif
388d5ac70f0Sopenharmony_ci	      if (revised_time == tempo_change_time) {
389d5ac70f0Sopenharmony_ci		old_currtime = revised_time;
390d5ac70f0Sopenharmony_ci	      old_f_realtime = Mf_f_realtime;
391d5ac70f0Sopenharmony_ci	      }
392d5ac70f0Sopenharmony_ci	    }
393d5ac70f0Sopenharmony_ci	    else {
394d5ac70f0Sopenharmony_ci	    delta_secs = mf_ticks2sec (revised_time-old_currtime, Mf_division, Mf_currtempo);
395d5ac70f0Sopenharmony_ci#ifdef DEBUG_TIMES
396d5ac70f0Sopenharmony_ciprintf("d(rev %lu - old %lu, div %d, tempo %lu) = %.3f\n",
397d5ac70f0Sopenharmony_cirevised_time, old_currtime, Mf_division, Mf_currtempo, delta_secs * 1600.0);
398d5ac70f0Sopenharmony_ci#endif
399d5ac70f0Sopenharmony_ci	    Mf_f_realtime = old_f_realtime + delta_secs * 1600.0;
400d5ac70f0Sopenharmony_ci	    Mf_realtime = (unsigned long)(0.5 + Mf_f_realtime);
401d5ac70f0Sopenharmony_ci#ifdef DEBUG_TIMES
402d5ac70f0Sopenharmony_ciprintf("\tt=%lu ticks ( = %lu csec/16 < old %.2f + %.2f)\n", Mf_currtime, Mf_realtime,
403d5ac70f0Sopenharmony_ciold_f_realtime, delta_secs * 1600.0);
404d5ac70f0Sopenharmony_ci#endif
405d5ac70f0Sopenharmony_ci	    }
406d5ac70f0Sopenharmony_ci
407d5ac70f0Sopenharmony_ci
408d5ac70f0Sopenharmony_ci	  }
409d5ac70f0Sopenharmony_ci	}
410d5ac70f0Sopenharmony_ci
411d5ac70f0Sopenharmony_ci      c = egetc ();
412d5ac70f0Sopenharmony_ci
413d5ac70f0Sopenharmony_ci      if (sysexcontinue && c != 0xf7)
414d5ac70f0Sopenharmony_ci	mferror ("didn't find expected continuation of a sysex");
415d5ac70f0Sopenharmony_ci
416d5ac70f0Sopenharmony_ci      if ((c & 0x80) == 0)
417d5ac70f0Sopenharmony_ci	{			/* running status? */
418d5ac70f0Sopenharmony_ci	  if (status == 0)
419d5ac70f0Sopenharmony_ci	    mferror ("unexpected running status");
420d5ac70f0Sopenharmony_ci	  running = 1;
421d5ac70f0Sopenharmony_ci	}
422d5ac70f0Sopenharmony_ci      else
423d5ac70f0Sopenharmony_ci	{
424d5ac70f0Sopenharmony_ci	  status = c;
425d5ac70f0Sopenharmony_ci	  running = 0;
426d5ac70f0Sopenharmony_ci	}
427d5ac70f0Sopenharmony_ci
428d5ac70f0Sopenharmony_ci      needed = chantype[(status >> 4) & 0xf];
429d5ac70f0Sopenharmony_ci
430d5ac70f0Sopenharmony_ci      if (needed)
431d5ac70f0Sopenharmony_ci	{			/* ie. is it a channel message? */
432d5ac70f0Sopenharmony_ci
433d5ac70f0Sopenharmony_ci	  if (running)
434d5ac70f0Sopenharmony_ci	    c1 = c;
435d5ac70f0Sopenharmony_ci	  else
436d5ac70f0Sopenharmony_ci	    c1 = egetc ();
437d5ac70f0Sopenharmony_ci	  chanmessage (status, c1, (needed > 1) ? egetc () : 0);
438d5ac70f0Sopenharmony_ci	  continue;;
439d5ac70f0Sopenharmony_ci	}
440d5ac70f0Sopenharmony_ci
441d5ac70f0Sopenharmony_ci      switch (c)
442d5ac70f0Sopenharmony_ci	{
443d5ac70f0Sopenharmony_ci
444d5ac70f0Sopenharmony_ci	case 0xff:		/* meta event */
445d5ac70f0Sopenharmony_ci
446d5ac70f0Sopenharmony_ci	  type = egetc ();
447d5ac70f0Sopenharmony_ci	  lookfor = Mf_toberead - readvarinum ();
448d5ac70f0Sopenharmony_ci	  msginit ();
449d5ac70f0Sopenharmony_ci
450d5ac70f0Sopenharmony_ci	  while (Mf_toberead > lookfor)
451d5ac70f0Sopenharmony_ci	    msgadd (egetc ());
452d5ac70f0Sopenharmony_ci
453d5ac70f0Sopenharmony_ci	  metaevent (type);
454d5ac70f0Sopenharmony_ci	  break;
455d5ac70f0Sopenharmony_ci
456d5ac70f0Sopenharmony_ci	case 0xf0:		/* start of system exclusive */
457d5ac70f0Sopenharmony_ci
458d5ac70f0Sopenharmony_ci	  lookfor = Mf_toberead - readvarinum ();
459d5ac70f0Sopenharmony_ci	  msginit ();
460d5ac70f0Sopenharmony_ci	  msgadd (0xf0);
461d5ac70f0Sopenharmony_ci
462d5ac70f0Sopenharmony_ci	  while (Mf_toberead > lookfor)
463d5ac70f0Sopenharmony_ci	    msgadd (c = egetc ());
464d5ac70f0Sopenharmony_ci
465d5ac70f0Sopenharmony_ci	  if (c == 0xf7 || Mf_nomerge == 0)
466d5ac70f0Sopenharmony_ci	    sysex ();
467d5ac70f0Sopenharmony_ci	  else
468d5ac70f0Sopenharmony_ci	    sysexcontinue = 1;	/* merge into next msg */
469d5ac70f0Sopenharmony_ci	  break;
470d5ac70f0Sopenharmony_ci
471d5ac70f0Sopenharmony_ci	case 0xf7:		/* sysex continuation or arbitrary stuff */
472d5ac70f0Sopenharmony_ci
473d5ac70f0Sopenharmony_ci	  lookfor = Mf_toberead - readvarinum ();
474d5ac70f0Sopenharmony_ci
475d5ac70f0Sopenharmony_ci	  if (!sysexcontinue)
476d5ac70f0Sopenharmony_ci	    msginit ();
477d5ac70f0Sopenharmony_ci
478d5ac70f0Sopenharmony_ci	  while (Mf_toberead > lookfor)
479d5ac70f0Sopenharmony_ci	    msgadd (c = egetc ());
480d5ac70f0Sopenharmony_ci
481d5ac70f0Sopenharmony_ci	  if (!sysexcontinue)
482d5ac70f0Sopenharmony_ci	    {
483d5ac70f0Sopenharmony_ci	      if (Mf_arbitrary)
484d5ac70f0Sopenharmony_ci		(*Mf_arbitrary) (msgleng (), msg ());
485d5ac70f0Sopenharmony_ci	    }
486d5ac70f0Sopenharmony_ci	  else if (c == 0xf7)
487d5ac70f0Sopenharmony_ci	    {
488d5ac70f0Sopenharmony_ci	      sysex ();
489d5ac70f0Sopenharmony_ci	      sysexcontinue = 0;
490d5ac70f0Sopenharmony_ci	    }
491d5ac70f0Sopenharmony_ci	  break;
492d5ac70f0Sopenharmony_ci	default:
493d5ac70f0Sopenharmony_ci	  badbyte (c);
494d5ac70f0Sopenharmony_ci	  break;
495d5ac70f0Sopenharmony_ci	}
496d5ac70f0Sopenharmony_ci    }
497d5ac70f0Sopenharmony_ci  if (Mf_trackend)
498d5ac70f0Sopenharmony_ci    (*Mf_trackend) ();
499d5ac70f0Sopenharmony_ci  return (1);
500d5ac70f0Sopenharmony_ci}
501d5ac70f0Sopenharmony_ci
502d5ac70f0Sopenharmony_cistatic
503d5ac70f0Sopenharmony_civoid
504d5ac70f0Sopenharmony_cibadbyte (c)
505d5ac70f0Sopenharmony_ci     int c;
506d5ac70f0Sopenharmony_ci{
507d5ac70f0Sopenharmony_ci  char buff[32];
508d5ac70f0Sopenharmony_ci
509d5ac70f0Sopenharmony_ci  (void) sprintf (buff, "unexpected byte: 0x%02x", c);
510d5ac70f0Sopenharmony_ci  mferror (buff);
511d5ac70f0Sopenharmony_ci}
512d5ac70f0Sopenharmony_ci
513d5ac70f0Sopenharmony_cistatic
514d5ac70f0Sopenharmony_civoid
515d5ac70f0Sopenharmony_cimetaevent (int type)
516d5ac70f0Sopenharmony_ci{
517d5ac70f0Sopenharmony_ci  int leng = msgleng ();
518d5ac70f0Sopenharmony_ci  char *m = msg ();
519d5ac70f0Sopenharmony_ci
520d5ac70f0Sopenharmony_ci  switch (type)
521d5ac70f0Sopenharmony_ci    {
522d5ac70f0Sopenharmony_ci    case 0x00:
523d5ac70f0Sopenharmony_ci      if (Mf_seqnum)
524d5ac70f0Sopenharmony_ci	(*Mf_seqnum) (to16bit (m[0], m[1]));
525d5ac70f0Sopenharmony_ci      break;
526d5ac70f0Sopenharmony_ci    case 0x01:			/* Text event */
527d5ac70f0Sopenharmony_ci    case 0x02:			/* Copyright notice */
528d5ac70f0Sopenharmony_ci    case 0x03:			/* Sequence/Track name */
529d5ac70f0Sopenharmony_ci    case 0x04:			/* Instrument name */
530d5ac70f0Sopenharmony_ci    case 0x05:			/* Lyric */
531d5ac70f0Sopenharmony_ci    case 0x06:			/* Marker */
532d5ac70f0Sopenharmony_ci    case 0x07:			/* Cue point */
533d5ac70f0Sopenharmony_ci    case 0x08:
534d5ac70f0Sopenharmony_ci    case 0x09:
535d5ac70f0Sopenharmony_ci    case 0x0a:
536d5ac70f0Sopenharmony_ci    case 0x0b:
537d5ac70f0Sopenharmony_ci    case 0x0c:
538d5ac70f0Sopenharmony_ci    case 0x0d:
539d5ac70f0Sopenharmony_ci    case 0x0e:
540d5ac70f0Sopenharmony_ci    case 0x0f:
541d5ac70f0Sopenharmony_ci      /* These are all text events */
542d5ac70f0Sopenharmony_ci      if (Mf_text)
543d5ac70f0Sopenharmony_ci	(*Mf_text) (type, leng, m);
544d5ac70f0Sopenharmony_ci      break;
545d5ac70f0Sopenharmony_ci    case 0x2f:			/* End of Track */
546d5ac70f0Sopenharmony_ci      if (Mf_eot)
547d5ac70f0Sopenharmony_ci	(*Mf_eot) ();
548d5ac70f0Sopenharmony_ci      break;
549d5ac70f0Sopenharmony_ci    case 0x51:			/* Set tempo */
550d5ac70f0Sopenharmony_ci      if (Mf_tempo)
551d5ac70f0Sopenharmony_ci	(*Mf_tempo) (Mf_currtempo = to32bit (0, m[0], m[1], m[2]));
552d5ac70f0Sopenharmony_ci      if (tempo_history[tempo_history_count] == Mf_currtempo) break;
553d5ac70f0Sopenharmony_ci      if (tempo_history_time[tempo_history_count] > Mf_currtime) break;
554d5ac70f0Sopenharmony_ci      if (tempo_history_count < MAX_HISTORY - 1) tempo_history_count++;
555d5ac70f0Sopenharmony_ci      tempo_history[tempo_history_count] = Mf_currtempo;
556d5ac70f0Sopenharmony_ci      tempo_history_time[tempo_history_count] = Mf_currtime;
557d5ac70f0Sopenharmony_ci      break;
558d5ac70f0Sopenharmony_ci    case 0x54:
559d5ac70f0Sopenharmony_ci      if (Mf_smpte)
560d5ac70f0Sopenharmony_ci	(*Mf_smpte) (m[0], m[1], m[2], m[3], m[4]);
561d5ac70f0Sopenharmony_ci      break;
562d5ac70f0Sopenharmony_ci    case 0x58:
563d5ac70f0Sopenharmony_ci      if (Mf_timesig)
564d5ac70f0Sopenharmony_ci	(*Mf_timesig) (m[0], m[1], m[2], m[3]);
565d5ac70f0Sopenharmony_ci      break;
566d5ac70f0Sopenharmony_ci    case 0x59:
567d5ac70f0Sopenharmony_ci      if (Mf_keysig)
568d5ac70f0Sopenharmony_ci	(*Mf_keysig) (m[0], m[1]);
569d5ac70f0Sopenharmony_ci      break;
570d5ac70f0Sopenharmony_ci    case 0x7f:
571d5ac70f0Sopenharmony_ci      if (Mf_seqspecific)
572d5ac70f0Sopenharmony_ci	(*Mf_seqspecific) (leng, m);
573d5ac70f0Sopenharmony_ci      break;
574d5ac70f0Sopenharmony_ci    default:
575d5ac70f0Sopenharmony_ci      if (Mf_metamisc)
576d5ac70f0Sopenharmony_ci	(*Mf_metamisc) (type, leng, m);
577d5ac70f0Sopenharmony_ci    }
578d5ac70f0Sopenharmony_ci}
579d5ac70f0Sopenharmony_ci
580d5ac70f0Sopenharmony_cistatic
581d5ac70f0Sopenharmony_civoid
582d5ac70f0Sopenharmony_cisysex ()
583d5ac70f0Sopenharmony_ci{
584d5ac70f0Sopenharmony_ci  if (Mf_sysex)
585d5ac70f0Sopenharmony_ci    (*Mf_sysex) (msgleng (), msg ());
586d5ac70f0Sopenharmony_ci}
587d5ac70f0Sopenharmony_ci
588d5ac70f0Sopenharmony_cistatic
589d5ac70f0Sopenharmony_civoid
590d5ac70f0Sopenharmony_cichanmessage (status, c1, c2)
591d5ac70f0Sopenharmony_ci     int status;
592d5ac70f0Sopenharmony_ci     int c1, c2;
593d5ac70f0Sopenharmony_ci{
594d5ac70f0Sopenharmony_ci  int chan = status & 0xf;
595d5ac70f0Sopenharmony_ci
596d5ac70f0Sopenharmony_ci  /* I found a midi file with Mod Wheel values 128. --gl */
597d5ac70f0Sopenharmony_ci
598d5ac70f0Sopenharmony_ci  if (c1 > 127) /*mferror("chanmessage: bad c1") ??*/ return;
599d5ac70f0Sopenharmony_ci  if (c2 > 127) c2 = 127;
600d5ac70f0Sopenharmony_ci
601d5ac70f0Sopenharmony_ci  switch (status & 0xf0)
602d5ac70f0Sopenharmony_ci    {
603d5ac70f0Sopenharmony_ci    case 0x80:
604d5ac70f0Sopenharmony_ci      if (Mf_noteoff)
605d5ac70f0Sopenharmony_ci	(*Mf_noteoff) (chan, c1, c2);
606d5ac70f0Sopenharmony_ci      break;
607d5ac70f0Sopenharmony_ci    case 0x90:
608d5ac70f0Sopenharmony_ci      if (Mf_noteon)
609d5ac70f0Sopenharmony_ci	(*Mf_noteon) (chan, c1, c2);
610d5ac70f0Sopenharmony_ci      break;
611d5ac70f0Sopenharmony_ci    case 0xa0:
612d5ac70f0Sopenharmony_ci      if (Mf_pressure)
613d5ac70f0Sopenharmony_ci	(*Mf_pressure) (chan, c1, c2);
614d5ac70f0Sopenharmony_ci      break;
615d5ac70f0Sopenharmony_ci    case 0xb0:
616d5ac70f0Sopenharmony_ci      if (Mf_parameter)
617d5ac70f0Sopenharmony_ci	(*Mf_parameter) (chan, c1, c2);
618d5ac70f0Sopenharmony_ci      break;
619d5ac70f0Sopenharmony_ci    case 0xe0:
620d5ac70f0Sopenharmony_ci      if (Mf_pitchbend)
621d5ac70f0Sopenharmony_ci	(*Mf_pitchbend) (chan, c1, c2);
622d5ac70f0Sopenharmony_ci      break;
623d5ac70f0Sopenharmony_ci    case 0xc0:
624d5ac70f0Sopenharmony_ci      if (Mf_program)
625d5ac70f0Sopenharmony_ci	(*Mf_program) (chan, c1);
626d5ac70f0Sopenharmony_ci      break;
627d5ac70f0Sopenharmony_ci    case 0xd0:
628d5ac70f0Sopenharmony_ci      if (Mf_chanpressure)
629d5ac70f0Sopenharmony_ci	(*Mf_chanpressure) (chan, c1);
630d5ac70f0Sopenharmony_ci      break;
631d5ac70f0Sopenharmony_ci    }
632d5ac70f0Sopenharmony_ci}
633d5ac70f0Sopenharmony_ci
634d5ac70f0Sopenharmony_ci/* readvarinum - read a varying-length number, and return the */
635d5ac70f0Sopenharmony_ci/* number of characters it took. */
636d5ac70f0Sopenharmony_ci
637d5ac70f0Sopenharmony_cistatic long
638d5ac70f0Sopenharmony_cireadvarinum ()
639d5ac70f0Sopenharmony_ci{
640d5ac70f0Sopenharmony_ci  long value;
641d5ac70f0Sopenharmony_ci  int c;
642d5ac70f0Sopenharmony_ci
643d5ac70f0Sopenharmony_ci  c = egetc ();
644d5ac70f0Sopenharmony_ci  value = c;
645d5ac70f0Sopenharmony_ci  if (c & 0x80)
646d5ac70f0Sopenharmony_ci    {
647d5ac70f0Sopenharmony_ci      value &= 0x7f;
648d5ac70f0Sopenharmony_ci      do
649d5ac70f0Sopenharmony_ci	{
650d5ac70f0Sopenharmony_ci	  c = egetc ();
651d5ac70f0Sopenharmony_ci	  value = (value << 7) + (c & 0x7f);
652d5ac70f0Sopenharmony_ci	}
653d5ac70f0Sopenharmony_ci      while (c & 0x80);
654d5ac70f0Sopenharmony_ci    }
655d5ac70f0Sopenharmony_ci  return (value);
656d5ac70f0Sopenharmony_ci}
657d5ac70f0Sopenharmony_ci
658d5ac70f0Sopenharmony_cistatic long
659d5ac70f0Sopenharmony_cito32bit (int c1, int c2, int c3, int c4)
660d5ac70f0Sopenharmony_ci{
661d5ac70f0Sopenharmony_ci  long value = 0L;
662d5ac70f0Sopenharmony_ci
663d5ac70f0Sopenharmony_ci  value = (c1 & 0xff);
664d5ac70f0Sopenharmony_ci  value = (value << 8) + (c2 & 0xff);
665d5ac70f0Sopenharmony_ci  value = (value << 8) + (c3 & 0xff);
666d5ac70f0Sopenharmony_ci  value = (value << 8) + (c4 & 0xff);
667d5ac70f0Sopenharmony_ci  return (value);
668d5ac70f0Sopenharmony_ci}
669d5ac70f0Sopenharmony_ci
670d5ac70f0Sopenharmony_cistatic int
671d5ac70f0Sopenharmony_cito16bit (c1, c2)
672d5ac70f0Sopenharmony_ci     int c1, c2;
673d5ac70f0Sopenharmony_ci{
674d5ac70f0Sopenharmony_ci  return ((c1 & 0xff) << 8) + (c2 & 0xff);
675d5ac70f0Sopenharmony_ci}
676d5ac70f0Sopenharmony_ci
677d5ac70f0Sopenharmony_cistatic long
678d5ac70f0Sopenharmony_ciread32bit ()
679d5ac70f0Sopenharmony_ci{
680d5ac70f0Sopenharmony_ci  int c1, c2, c3, c4;
681d5ac70f0Sopenharmony_ci
682d5ac70f0Sopenharmony_ci  c1 = egetc ();
683d5ac70f0Sopenharmony_ci  c2 = egetc ();
684d5ac70f0Sopenharmony_ci  c3 = egetc ();
685d5ac70f0Sopenharmony_ci  c4 = egetc ();
686d5ac70f0Sopenharmony_ci  return to32bit (c1, c2, c3, c4);
687d5ac70f0Sopenharmony_ci}
688d5ac70f0Sopenharmony_ci
689d5ac70f0Sopenharmony_cistatic int
690d5ac70f0Sopenharmony_ciread16bit ()
691d5ac70f0Sopenharmony_ci{
692d5ac70f0Sopenharmony_ci  int c1, c2;
693d5ac70f0Sopenharmony_ci  c1 = egetc ();
694d5ac70f0Sopenharmony_ci  c2 = egetc ();
695d5ac70f0Sopenharmony_ci  return to16bit (c1, c2);
696d5ac70f0Sopenharmony_ci}
697d5ac70f0Sopenharmony_ci
698d5ac70f0Sopenharmony_ci/* static */
699d5ac70f0Sopenharmony_civoid
700d5ac70f0Sopenharmony_cimferror (s)
701d5ac70f0Sopenharmony_ci     char *s;
702d5ac70f0Sopenharmony_ci{
703d5ac70f0Sopenharmony_ci  if (Mf_error)
704d5ac70f0Sopenharmony_ci    (*Mf_error) (s);
705d5ac70f0Sopenharmony_ci  else exit (1);
706d5ac70f0Sopenharmony_ci}
707d5ac70f0Sopenharmony_ci
708d5ac70f0Sopenharmony_ci/* The code below allows collection of a system exclusive message of */
709d5ac70f0Sopenharmony_ci/* arbitrary length.  The Msgbuff is expanded as necessary.  The only */
710d5ac70f0Sopenharmony_ci/* visible data/routines are msginit(), msgadd(), msg(), msgleng(). */
711d5ac70f0Sopenharmony_ci
712d5ac70f0Sopenharmony_ci#define MSGINCREMENT 128
713d5ac70f0Sopenharmony_cistatic char *Msgbuff = NULL;	/* message buffer */
714d5ac70f0Sopenharmony_cistatic int Msgsize = 0;		/* Size of currently allocated Msg */
715d5ac70f0Sopenharmony_cistatic int Msgindex = 0;	/* index of next available location in Msg */
716d5ac70f0Sopenharmony_ci
717d5ac70f0Sopenharmony_cistatic
718d5ac70f0Sopenharmony_civoid
719d5ac70f0Sopenharmony_cimsginit ()
720d5ac70f0Sopenharmony_ci{
721d5ac70f0Sopenharmony_ci  Msgindex = 0;
722d5ac70f0Sopenharmony_ci}
723d5ac70f0Sopenharmony_ci
724d5ac70f0Sopenharmony_cistatic char *
725d5ac70f0Sopenharmony_cimsg ()
726d5ac70f0Sopenharmony_ci{
727d5ac70f0Sopenharmony_ci  return (Msgbuff);
728d5ac70f0Sopenharmony_ci}
729d5ac70f0Sopenharmony_ci
730d5ac70f0Sopenharmony_cistatic
731d5ac70f0Sopenharmony_ciint
732d5ac70f0Sopenharmony_cimsgleng ()
733d5ac70f0Sopenharmony_ci{
734d5ac70f0Sopenharmony_ci  return (Msgindex);
735d5ac70f0Sopenharmony_ci}
736d5ac70f0Sopenharmony_ci
737d5ac70f0Sopenharmony_cistatic
738d5ac70f0Sopenharmony_civoid
739d5ac70f0Sopenharmony_cimsgadd (c)
740d5ac70f0Sopenharmony_ci     int c;
741d5ac70f0Sopenharmony_ci{
742d5ac70f0Sopenharmony_ci  /* If necessary, allocate larger message buffer. */
743d5ac70f0Sopenharmony_ci  if (Msgindex >= Msgsize)
744d5ac70f0Sopenharmony_ci    biggermsg ();
745d5ac70f0Sopenharmony_ci  Msgbuff[Msgindex++] = c;
746d5ac70f0Sopenharmony_ci}
747d5ac70f0Sopenharmony_ci
748d5ac70f0Sopenharmony_cistatic
749d5ac70f0Sopenharmony_civoid
750d5ac70f0Sopenharmony_cibiggermsg ()
751d5ac70f0Sopenharmony_ci{
752d5ac70f0Sopenharmony_ci/* 	char *malloc(); */
753d5ac70f0Sopenharmony_ci  char *newmess;
754d5ac70f0Sopenharmony_ci  char *oldmess = Msgbuff;
755d5ac70f0Sopenharmony_ci  int oldleng = Msgsize;
756d5ac70f0Sopenharmony_ci
757d5ac70f0Sopenharmony_ci  Msgsize += MSGINCREMENT;
758d5ac70f0Sopenharmony_ci  newmess = (char *) malloc ((unsigned) (sizeof (char) * Msgsize));
759d5ac70f0Sopenharmony_ci
760d5ac70f0Sopenharmony_ci  if (newmess == NULL)
761d5ac70f0Sopenharmony_ci    mferror ("malloc error!");
762d5ac70f0Sopenharmony_ci
763d5ac70f0Sopenharmony_ci  /* copy old message into larger new one */
764d5ac70f0Sopenharmony_ci  if (oldmess != NULL)
765d5ac70f0Sopenharmony_ci    {
766d5ac70f0Sopenharmony_ci      register char *p = newmess;
767d5ac70f0Sopenharmony_ci      register char *q = oldmess;
768d5ac70f0Sopenharmony_ci      register char *endq = &oldmess[oldleng];
769d5ac70f0Sopenharmony_ci
770d5ac70f0Sopenharmony_ci      for (; q != endq; p++, q++)
771d5ac70f0Sopenharmony_ci	*p = *q;
772d5ac70f0Sopenharmony_ci      free (oldmess);
773d5ac70f0Sopenharmony_ci    }
774d5ac70f0Sopenharmony_ci  Msgbuff = newmess;
775d5ac70f0Sopenharmony_ci}
776d5ac70f0Sopenharmony_ci
777d5ac70f0Sopenharmony_cistatic int laststatus = 0;
778d5ac70f0Sopenharmony_ci
779d5ac70f0Sopenharmony_ci/*
780d5ac70f0Sopenharmony_ci * mfwrite() - The only function you'll need to call to write out
781d5ac70f0Sopenharmony_ci *             a midi file.
782d5ac70f0Sopenharmony_ci *
783d5ac70f0Sopenharmony_ci * format      0 - Single multi-channel track
784d5ac70f0Sopenharmony_ci *             1 - Multiple simultaneous tracks
785d5ac70f0Sopenharmony_ci *             2 - One or more sequentially independent
786d5ac70f0Sopenharmony_ci *                 single track patterns
787d5ac70f0Sopenharmony_ci * ntracks     The number of tracks in the file.
788d5ac70f0Sopenharmony_ci * division    This is kind of tricky, it can represent two
789d5ac70f0Sopenharmony_ci *             things, depending on whether it is positive or negative
790d5ac70f0Sopenharmony_ci *             (bit 15 set or not).  If  bit  15  of division  is zero,
791d5ac70f0Sopenharmony_ci *             bits 14 through 0 represent the number of delta-time
792d5ac70f0Sopenharmony_ci *             "ticks" which make up a quarter note.  If bit  15 of
793d5ac70f0Sopenharmony_ci *             division  is  a one, delta-times in a file correspond to
794d5ac70f0Sopenharmony_ci *             subdivisions of a second similar to  SMPTE  and  MIDI
795d5ac70f0Sopenharmony_ci *             time code.  In  this format bits 14 through 8 contain
796d5ac70f0Sopenharmony_ci *             one of four values - 24, -25, -29, or -30,
797d5ac70f0Sopenharmony_ci *             corresponding  to  the  four standard  SMPTE and MIDI
798d5ac70f0Sopenharmony_ci *             time code frame per second formats, where  -29
799d5ac70f0Sopenharmony_ci *             represents  30  drop  frame.   The  second  byte
800d5ac70f0Sopenharmony_ci *             consisting  of  bits 7 through 0 corresponds the the
801d5ac70f0Sopenharmony_ci *             resolution within a frame.  Refer the Standard MIDI
802d5ac70f0Sopenharmony_ci *             Files 1.0 spec for more details.
803d5ac70f0Sopenharmony_ci * fp          This should be the open file pointer to the file you
804d5ac70f0Sopenharmony_ci *             want to write.  It will have be a global in order
805d5ac70f0Sopenharmony_ci *             to work with Mf_putc.
806d5ac70f0Sopenharmony_ci */
807d5ac70f0Sopenharmony_civoid
808d5ac70f0Sopenharmony_cimfwrite (format, ntracks, division, fp)
809d5ac70f0Sopenharmony_ci     int format, ntracks, division;
810d5ac70f0Sopenharmony_ci     FILE *fp;
811d5ac70f0Sopenharmony_ci{
812d5ac70f0Sopenharmony_ci  int i;
813d5ac70f0Sopenharmony_ci  void mf_write_track_chunk (), mf_write_header_chunk ();
814d5ac70f0Sopenharmony_ci
815d5ac70f0Sopenharmony_ci  if (Mf_putc == NULLFUNC)
816d5ac70f0Sopenharmony_ci    mferror ("mfmf_write() called without setting Mf_putc");
817d5ac70f0Sopenharmony_ci
818d5ac70f0Sopenharmony_ci  if (Mf_writetrack == NULLFUNC)
819d5ac70f0Sopenharmony_ci    mferror ("mfmf_write() called without setting Mf_mf_writetrack");
820d5ac70f0Sopenharmony_ci
821d5ac70f0Sopenharmony_ci  laststatus = 0;
822d5ac70f0Sopenharmony_ci
823d5ac70f0Sopenharmony_ci  /* every MIDI file starts with a header */
824d5ac70f0Sopenharmony_ci  mf_write_header_chunk (format, ntracks, division);
825d5ac70f0Sopenharmony_ci
826d5ac70f0Sopenharmony_ci  laststatus = 0;
827d5ac70f0Sopenharmony_ci
828d5ac70f0Sopenharmony_ci  /* In format 1 files, the first track is a tempo map */
829d5ac70f0Sopenharmony_ci  if (format == 1 && (Mf_writetempotrack))
830d5ac70f0Sopenharmony_ci    {
831d5ac70f0Sopenharmony_ci      (*Mf_writetempotrack) ();
832d5ac70f0Sopenharmony_ci    }
833d5ac70f0Sopenharmony_ci
834d5ac70f0Sopenharmony_ci  /* The rest of the file is a series of tracks */
835d5ac70f0Sopenharmony_ci  for (i = 0; i < ntracks; i++)
836d5ac70f0Sopenharmony_ci    mf_write_track_chunk (i, fp);
837d5ac70f0Sopenharmony_ci}
838d5ac70f0Sopenharmony_ci
839d5ac70f0Sopenharmony_civoid
840d5ac70f0Sopenharmony_cimf_write_track_chunk (which_track, fp)
841d5ac70f0Sopenharmony_ci     int which_track;
842d5ac70f0Sopenharmony_ci     FILE *fp;
843d5ac70f0Sopenharmony_ci{
844d5ac70f0Sopenharmony_ci  unsigned long trkhdr, trklength;
845d5ac70f0Sopenharmony_ci  long offset, place_marker;
846d5ac70f0Sopenharmony_ci  void write16bit (), write32bit ();
847d5ac70f0Sopenharmony_ci
848d5ac70f0Sopenharmony_ci
849d5ac70f0Sopenharmony_ci  laststatus = 0;
850d5ac70f0Sopenharmony_ci
851d5ac70f0Sopenharmony_ci  trkhdr = MTrk;
852d5ac70f0Sopenharmony_ci  trklength = 0;
853d5ac70f0Sopenharmony_ci
854d5ac70f0Sopenharmony_ci  /* Remember where the length was written, because we don't
855d5ac70f0Sopenharmony_ci	   know how long it will be until we've finished writing */
856d5ac70f0Sopenharmony_ci  offset = ftell (fp);
857d5ac70f0Sopenharmony_ci
858d5ac70f0Sopenharmony_ci#ifdef DEBUG
859d5ac70f0Sopenharmony_ci  printf ("offset = %d\n", (int) offset);
860d5ac70f0Sopenharmony_ci#endif
861d5ac70f0Sopenharmony_ci
862d5ac70f0Sopenharmony_ci  /* Write the track chunk header */
863d5ac70f0Sopenharmony_ci  write32bit (trkhdr);
864d5ac70f0Sopenharmony_ci  write32bit (trklength);
865d5ac70f0Sopenharmony_ci
866d5ac70f0Sopenharmony_ci  Mf_numbyteswritten = 0L;	/* the header's length doesn't count */
867d5ac70f0Sopenharmony_ci
868d5ac70f0Sopenharmony_ci  if (Mf_writetrack)
869d5ac70f0Sopenharmony_ci    {
870d5ac70f0Sopenharmony_ci      (*Mf_writetrack) (which_track);
871d5ac70f0Sopenharmony_ci    }
872d5ac70f0Sopenharmony_ci
873d5ac70f0Sopenharmony_ci  /* mf_write End of track meta event */
874d5ac70f0Sopenharmony_ci/* but this does not necessarily have a delta of 0, so
875d5ac70f0Sopenharmony_ci * I don't want to do it -- leave it up to the user of the
876d5ac70f0Sopenharmony_ci * library functions to do
877d5ac70f0Sopenharmony_ci *	--gl
878d5ac70f0Sopenharmony_ci	eputc(0);
879d5ac70f0Sopenharmony_ci	eputc(laststatus = meta_event);
880d5ac70f0Sopenharmony_ci	eputc(end_of_track);
881d5ac70f0Sopenharmony_ci
882d5ac70f0Sopenharmony_ci 	eputc(0);
883d5ac70f0Sopenharmony_ci */
884d5ac70f0Sopenharmony_ci
885d5ac70f0Sopenharmony_ci  /* It's impossible to know how long the track chunk will be beforehand,
886d5ac70f0Sopenharmony_ci           so the position of the track length data is kept so that it can
887d5ac70f0Sopenharmony_ci           be written after the chunk has been generated */
888d5ac70f0Sopenharmony_ci  place_marker = ftell (fp);
889d5ac70f0Sopenharmony_ci
890d5ac70f0Sopenharmony_ci  /* This method turned out not to be portable because the
891d5ac70f0Sopenharmony_ci           parameter returned from ftell is not guaranteed to be
892d5ac70f0Sopenharmony_ci           in bytes on every machine */
893d5ac70f0Sopenharmony_ci  /* track.length = place_marker - offset - (long) sizeof(track); */
894d5ac70f0Sopenharmony_ci
895d5ac70f0Sopenharmony_ci#ifdef DEBUG
896d5ac70f0Sopenharmony_ci  printf ("length = %d\n", (int) trklength);
897d5ac70f0Sopenharmony_ci#endif
898d5ac70f0Sopenharmony_ci
899d5ac70f0Sopenharmony_ci  if (fseek (fp, offset, 0) < 0)
900d5ac70f0Sopenharmony_ci    mferror ("error seeking during final stage of write");
901d5ac70f0Sopenharmony_ci
902d5ac70f0Sopenharmony_ci  trklength = Mf_numbyteswritten;
903d5ac70f0Sopenharmony_ci
904d5ac70f0Sopenharmony_ci  /* Re-mf_write the track chunk header with right length */
905d5ac70f0Sopenharmony_ci  write32bit (trkhdr);
906d5ac70f0Sopenharmony_ci  write32bit (trklength);
907d5ac70f0Sopenharmony_ci
908d5ac70f0Sopenharmony_ci  fseek (fp, place_marker, 0);
909d5ac70f0Sopenharmony_ci}				/* End gen_track_chunk() */
910d5ac70f0Sopenharmony_ci
911d5ac70f0Sopenharmony_ci
912d5ac70f0Sopenharmony_civoid
913d5ac70f0Sopenharmony_cimf_write_header_chunk (format, ntracks, division)
914d5ac70f0Sopenharmony_ci     int format, ntracks, division;
915d5ac70f0Sopenharmony_ci{
916d5ac70f0Sopenharmony_ci  unsigned long ident, length;
917d5ac70f0Sopenharmony_ci  void write16bit (), write32bit ();
918d5ac70f0Sopenharmony_ci
919d5ac70f0Sopenharmony_ci  ident = MThd;			/* Head chunk identifier                    */
920d5ac70f0Sopenharmony_ci  length = 6;			/* Chunk length                             */
921d5ac70f0Sopenharmony_ci
922d5ac70f0Sopenharmony_ci  /* individual bytes of the header must be written separately
923d5ac70f0Sopenharmony_ci       to preserve byte order across cpu types :-( */
924d5ac70f0Sopenharmony_ci  write32bit (ident);
925d5ac70f0Sopenharmony_ci  write32bit (length);
926d5ac70f0Sopenharmony_ci  write16bit (format);
927d5ac70f0Sopenharmony_ci  write16bit (ntracks);
928d5ac70f0Sopenharmony_ci  write16bit (division);
929d5ac70f0Sopenharmony_ci}				/* end gen_header_chunk() */
930d5ac70f0Sopenharmony_ci
931d5ac70f0Sopenharmony_ci
932d5ac70f0Sopenharmony_ci/*
933d5ac70f0Sopenharmony_ci * mf_write_midi_event()
934d5ac70f0Sopenharmony_ci *
935d5ac70f0Sopenharmony_ci * Library routine to mf_write a single MIDI track event in the standard MIDI
936d5ac70f0Sopenharmony_ci * file format. The format is:
937d5ac70f0Sopenharmony_ci *
938d5ac70f0Sopenharmony_ci *                    <delta-time><event>
939d5ac70f0Sopenharmony_ci *
940d5ac70f0Sopenharmony_ci * In this case, event can be any multi-byte midi message, such as
941d5ac70f0Sopenharmony_ci * "note on", "note off", etc.
942d5ac70f0Sopenharmony_ci *
943d5ac70f0Sopenharmony_ci * delta_time - the time in ticks since the last event.
944d5ac70f0Sopenharmony_ci * type - the type of meta event.
945d5ac70f0Sopenharmony_ci * chan - The midi channel.
946d5ac70f0Sopenharmony_ci * data - A pointer to a block of chars containing the META EVENT,
947d5ac70f0Sopenharmony_ci *        data.
948d5ac70f0Sopenharmony_ci * size - The length of the meta-event data.
949d5ac70f0Sopenharmony_ci */
950d5ac70f0Sopenharmony_ciint
951d5ac70f0Sopenharmony_cimf_write_midi_event (delta_time, type, chan, data, size)
952d5ac70f0Sopenharmony_ci     unsigned long delta_time;
953d5ac70f0Sopenharmony_ci     int chan, type;
954d5ac70f0Sopenharmony_ci     unsigned long size;
955d5ac70f0Sopenharmony_ci     char *data;
956d5ac70f0Sopenharmony_ci{
957d5ac70f0Sopenharmony_ci  int i;
958d5ac70f0Sopenharmony_ci  unsigned char c;
959d5ac70f0Sopenharmony_ci
960d5ac70f0Sopenharmony_ci  WriteVarLen (delta_time);
961d5ac70f0Sopenharmony_ci
962d5ac70f0Sopenharmony_ci  /* all MIDI events start with the type in the first four bits,
963d5ac70f0Sopenharmony_ci       and the channel in the lower four bits */
964d5ac70f0Sopenharmony_ci  if (type == system_exclusive || type == 0xf7)
965d5ac70f0Sopenharmony_ci    {
966d5ac70f0Sopenharmony_ci      c = type;
967d5ac70f0Sopenharmony_ci      laststatus = 0;
968d5ac70f0Sopenharmony_ci    }
969d5ac70f0Sopenharmony_ci  else
970d5ac70f0Sopenharmony_ci    c = type | chan;
971d5ac70f0Sopenharmony_ci
972d5ac70f0Sopenharmony_ci  if (chan > 15)
973d5ac70f0Sopenharmony_ci    perror ("error: MIDI channel greater than 16\n");
974d5ac70f0Sopenharmony_ci
975d5ac70f0Sopenharmony_ci  if (laststatus != c)
976d5ac70f0Sopenharmony_ci    eputc (laststatus = c);
977d5ac70f0Sopenharmony_ci
978d5ac70f0Sopenharmony_ci  if (type == system_exclusive || type == 0xf7)
979d5ac70f0Sopenharmony_ci    WriteVarLen (size);
980d5ac70f0Sopenharmony_ci
981d5ac70f0Sopenharmony_ci  /* write out the data bytes */
982d5ac70f0Sopenharmony_ci  for (i = 0; i < (int)size; i++)
983d5ac70f0Sopenharmony_ci    eputc (data[i]);
984d5ac70f0Sopenharmony_ci
985d5ac70f0Sopenharmony_ci  return (size);
986d5ac70f0Sopenharmony_ci}				/* end mf_write MIDI event */
987d5ac70f0Sopenharmony_ci
988d5ac70f0Sopenharmony_ci/*
989d5ac70f0Sopenharmony_ci * mf_write_meta_event()
990d5ac70f0Sopenharmony_ci *
991d5ac70f0Sopenharmony_ci * Library routine to mf_write a single meta event in the standard MIDI
992d5ac70f0Sopenharmony_ci * file format. The format of a meta event is:
993d5ac70f0Sopenharmony_ci *
994d5ac70f0Sopenharmony_ci *          <delta-time><FF><type><length><bytes>
995d5ac70f0Sopenharmony_ci *
996d5ac70f0Sopenharmony_ci * delta_time - the time in ticks since the last event.
997d5ac70f0Sopenharmony_ci * type - the type of meta event.
998d5ac70f0Sopenharmony_ci * data - A pointer to a block of chars containing the META EVENT,
999d5ac70f0Sopenharmony_ci *        data.
1000d5ac70f0Sopenharmony_ci * size - The length of the meta-event data.
1001d5ac70f0Sopenharmony_ci */
1002d5ac70f0Sopenharmony_ciint
1003d5ac70f0Sopenharmony_cimf_write_meta_event (delta_time, type, data, size)
1004d5ac70f0Sopenharmony_ci     unsigned long delta_time;
1005d5ac70f0Sopenharmony_ci     unsigned char *data, type;
1006d5ac70f0Sopenharmony_ci     unsigned long size;
1007d5ac70f0Sopenharmony_ci{
1008d5ac70f0Sopenharmony_ci  int i;
1009d5ac70f0Sopenharmony_ci
1010d5ac70f0Sopenharmony_ci  WriteVarLen (delta_time);
1011d5ac70f0Sopenharmony_ci
1012d5ac70f0Sopenharmony_ci  /* This marks the fact we're writing a meta-event */
1013d5ac70f0Sopenharmony_ci  eputc (laststatus = meta_event);
1014d5ac70f0Sopenharmony_ci
1015d5ac70f0Sopenharmony_ci  /* The type of meta event */
1016d5ac70f0Sopenharmony_ci  eputc (type);
1017d5ac70f0Sopenharmony_ci
1018d5ac70f0Sopenharmony_ci  /* The length of the data bytes to follow */
1019d5ac70f0Sopenharmony_ci  WriteVarLen (size);
1020d5ac70f0Sopenharmony_ci
1021d5ac70f0Sopenharmony_ci  for (i = 0; i < (int)size; i++)
1022d5ac70f0Sopenharmony_ci    {
1023d5ac70f0Sopenharmony_ci      if (eputc (data[i]) != data[i])
1024d5ac70f0Sopenharmony_ci	return (-1);
1025d5ac70f0Sopenharmony_ci    }
1026d5ac70f0Sopenharmony_ci  return (size);
1027d5ac70f0Sopenharmony_ci}				/* end mf_write_meta_event */
1028d5ac70f0Sopenharmony_ci
1029d5ac70f0Sopenharmony_civoid
1030d5ac70f0Sopenharmony_cimf_write_tempo (delta_time, tempo)
1031d5ac70f0Sopenharmony_ci     unsigned long delta_time;
1032d5ac70f0Sopenharmony_ci     unsigned long tempo;
1033d5ac70f0Sopenharmony_ci{
1034d5ac70f0Sopenharmony_ci  /* Write tempo */
1035d5ac70f0Sopenharmony_ci  /* all tempos are written as 120 beats/minute, */
1036d5ac70f0Sopenharmony_ci  /* expressed in microseconds/quarter note     */
1037d5ac70f0Sopenharmony_ci
1038d5ac70f0Sopenharmony_ci  WriteVarLen (delta_time);
1039d5ac70f0Sopenharmony_ci  eputc (laststatus = meta_event);
1040d5ac70f0Sopenharmony_ci  eputc (set_tempo);
1041d5ac70f0Sopenharmony_ci
1042d5ac70f0Sopenharmony_ci  eputc (3);
1043d5ac70f0Sopenharmony_ci  eputc ((unsigned) (0xff & (tempo >> 16)));
1044d5ac70f0Sopenharmony_ci  eputc ((unsigned) (0xff & (tempo >> 8)));
1045d5ac70f0Sopenharmony_ci  eputc ((unsigned) (0xff & tempo));
1046d5ac70f0Sopenharmony_ci}
1047d5ac70f0Sopenharmony_ci
1048d5ac70f0Sopenharmony_civoid
1049d5ac70f0Sopenharmony_cimf_write_seqnum (delta_time, seqnum)
1050d5ac70f0Sopenharmony_ci     unsigned long delta_time;
1051d5ac70f0Sopenharmony_ci     unsigned seqnum;
1052d5ac70f0Sopenharmony_ci{
1053d5ac70f0Sopenharmony_ci
1054d5ac70f0Sopenharmony_ci  WriteVarLen (delta_time);
1055d5ac70f0Sopenharmony_ci  eputc (laststatus = meta_event);
1056d5ac70f0Sopenharmony_ci  eputc (0);
1057d5ac70f0Sopenharmony_ci
1058d5ac70f0Sopenharmony_ci  eputc ((unsigned) (0xff & (seqnum >> 8)));
1059d5ac70f0Sopenharmony_ci  eputc ((unsigned) (0xff & seqnum));
1060d5ac70f0Sopenharmony_ci}
1061d5ac70f0Sopenharmony_ci
1062d5ac70f0Sopenharmony_ciunsigned long
1063d5ac70f0Sopenharmony_cimf_sec2ticks (secs, division, tempo)
1064d5ac70f0Sopenharmony_ci     int division;
1065d5ac70f0Sopenharmony_ci     unsigned long tempo;
1066d5ac70f0Sopenharmony_ci     double secs;
1067d5ac70f0Sopenharmony_ci{
1068d5ac70f0Sopenharmony_ci  return (unsigned long) (((secs * 1000.0) / 4.0 * division) / tempo);
1069d5ac70f0Sopenharmony_ci}
1070d5ac70f0Sopenharmony_ci
1071d5ac70f0Sopenharmony_ci/*
1072d5ac70f0Sopenharmony_ci * Write multi-length bytes to MIDI format files
1073d5ac70f0Sopenharmony_ci */
1074d5ac70f0Sopenharmony_civoid
1075d5ac70f0Sopenharmony_ciWriteVarLen (value)
1076d5ac70f0Sopenharmony_ci     unsigned long value;
1077d5ac70f0Sopenharmony_ci{
1078d5ac70f0Sopenharmony_ci  unsigned long buffer;
1079d5ac70f0Sopenharmony_ci
1080d5ac70f0Sopenharmony_ci  buffer = value & 0x7f;
1081d5ac70f0Sopenharmony_ci  while ((value >>= 7) > 0)
1082d5ac70f0Sopenharmony_ci    {
1083d5ac70f0Sopenharmony_ci      buffer <<= 8;
1084d5ac70f0Sopenharmony_ci      buffer |= 0x80;
1085d5ac70f0Sopenharmony_ci      buffer += (value & 0x7f);
1086d5ac70f0Sopenharmony_ci    }
1087d5ac70f0Sopenharmony_ci  while (1)
1088d5ac70f0Sopenharmony_ci    {
1089d5ac70f0Sopenharmony_ci      eputc ((unsigned) (buffer & 0xff));
1090d5ac70f0Sopenharmony_ci
1091d5ac70f0Sopenharmony_ci      if (buffer & 0x80)
1092d5ac70f0Sopenharmony_ci	buffer >>= 8;
1093d5ac70f0Sopenharmony_ci      else
1094d5ac70f0Sopenharmony_ci	return;
1095d5ac70f0Sopenharmony_ci    }
1096d5ac70f0Sopenharmony_ci}				/* end of WriteVarLen */
1097d5ac70f0Sopenharmony_ci
1098d5ac70f0Sopenharmony_ci/*
1099d5ac70f0Sopenharmony_ci * This routine converts delta times in ticks into seconds. The
1100d5ac70f0Sopenharmony_ci * else statement is needed because the formula is different for tracks
1101d5ac70f0Sopenharmony_ci * based on notes and tracks based on SMPTE times.
1102d5ac70f0Sopenharmony_ci *
1103d5ac70f0Sopenharmony_ci */
1104d5ac70f0Sopenharmony_cidouble
1105d5ac70f0Sopenharmony_cimf_ticks2sec (ticks, division, tempo)
1106d5ac70f0Sopenharmony_ci     int division;
1107d5ac70f0Sopenharmony_ci     unsigned long tempo;
1108d5ac70f0Sopenharmony_ci     unsigned long ticks;
1109d5ac70f0Sopenharmony_ci{
1110d5ac70f0Sopenharmony_ci  double smpte_format, smpte_resolution;
1111d5ac70f0Sopenharmony_ci
1112d5ac70f0Sopenharmony_ci  if (division > 0)
1113d5ac70f0Sopenharmony_ci    return ((double) (((double) (ticks) * (double) (tempo)) / ((double) (division) * 1000000.0)));
1114d5ac70f0Sopenharmony_ci  else
1115d5ac70f0Sopenharmony_ci    {
1116d5ac70f0Sopenharmony_ci      smpte_format = upperbyte (division);
1117d5ac70f0Sopenharmony_ci      smpte_resolution = lowerbyte (division);
1118d5ac70f0Sopenharmony_ci      return (double) ((double) ticks / (smpte_format * smpte_resolution * 1000000.0));
1119d5ac70f0Sopenharmony_ci    }
1120d5ac70f0Sopenharmony_ci}				/* end of ticks2sec() */
1121d5ac70f0Sopenharmony_ci
1122d5ac70f0Sopenharmony_ci
1123d5ac70f0Sopenharmony_ci/*
1124d5ac70f0Sopenharmony_ci * write32bit()
1125d5ac70f0Sopenharmony_ci * write16bit()
1126d5ac70f0Sopenharmony_ci *
1127d5ac70f0Sopenharmony_ci * These routines are used to make sure that the byte order of
1128d5ac70f0Sopenharmony_ci * the various data types remains constant between machines. This
1129d5ac70f0Sopenharmony_ci * helps make sure that the code will be portable from one system
1130d5ac70f0Sopenharmony_ci * to the next.  It is slightly dangerous that it assumes that longs
1131d5ac70f0Sopenharmony_ci * have at least 32 bits and ints have at least 16 bits, but this
1132d5ac70f0Sopenharmony_ci * has been true at least on PCs, UNIX machines, and Macintosh's.
1133d5ac70f0Sopenharmony_ci *
1134d5ac70f0Sopenharmony_ci */
1135d5ac70f0Sopenharmony_civoid
1136d5ac70f0Sopenharmony_ciwrite32bit (data)
1137d5ac70f0Sopenharmony_ci     unsigned long data;
1138d5ac70f0Sopenharmony_ci{
1139d5ac70f0Sopenharmony_ci  eputc ((unsigned) ((data >> 24) & 0xff));
1140d5ac70f0Sopenharmony_ci  eputc ((unsigned) ((data >> 16) & 0xff));
1141d5ac70f0Sopenharmony_ci  eputc ((unsigned) ((data >> 8) & 0xff));
1142d5ac70f0Sopenharmony_ci  eputc ((unsigned) (data & 0xff));
1143d5ac70f0Sopenharmony_ci}
1144d5ac70f0Sopenharmony_ci
1145d5ac70f0Sopenharmony_civoid
1146d5ac70f0Sopenharmony_ciwrite16bit (data)
1147d5ac70f0Sopenharmony_ci     int data;
1148d5ac70f0Sopenharmony_ci{
1149d5ac70f0Sopenharmony_ci  eputc ((unsigned) ((data & 0xff00) >> 8));
1150d5ac70f0Sopenharmony_ci  eputc ((unsigned) (data & 0xff));
1151d5ac70f0Sopenharmony_ci}
1152d5ac70f0Sopenharmony_ci
1153d5ac70f0Sopenharmony_ci/* write a single character and abort on error */
1154d5ac70f0Sopenharmony_cistatic int
1155d5ac70f0Sopenharmony_cieputc (c)
1156d5ac70f0Sopenharmony_ci     unsigned char c;
1157d5ac70f0Sopenharmony_ci{
1158d5ac70f0Sopenharmony_ci  int return_val;
1159d5ac70f0Sopenharmony_ci
1160d5ac70f0Sopenharmony_ci  if ((Mf_putc) == NULLFUNC)
1161d5ac70f0Sopenharmony_ci    {
1162d5ac70f0Sopenharmony_ci      mferror ("Mf_putc undefined");
1163d5ac70f0Sopenharmony_ci      return (-1);
1164d5ac70f0Sopenharmony_ci    }
1165d5ac70f0Sopenharmony_ci
1166d5ac70f0Sopenharmony_ci  return_val = (*Mf_putc) (c);
1167d5ac70f0Sopenharmony_ci
1168d5ac70f0Sopenharmony_ci  if (return_val == EOF)
1169d5ac70f0Sopenharmony_ci    mferror ("error writing");
1170d5ac70f0Sopenharmony_ci
1171d5ac70f0Sopenharmony_ci  Mf_numbyteswritten++;
1172d5ac70f0Sopenharmony_ci  return (return_val);
1173d5ac70f0Sopenharmony_ci}
1174