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