#ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #ifndef NO_STRING_H #include #else #include #endif #ifndef __WIN32__ #include #endif #include "timidity.h" #include "common.h" #include "instrum.h" #include "playmidi.h" #include "controls.h" #include "output.h" #include "arc.h" #include "wrd.h" #define DEFINE_GLOBALS #ifdef JAPANESE #include "mid-j.defs" #else #include "mid.defs" #endif /* JAPANESE */ /* to avoid some unnecessary parameter passing */ static int32 at; static int current_read_track; static int current_read_format; static int32 divisions, tempo; /*ARGSUSED*/ static int null_cmsg(int type, int verbosity_level, char *fmt, ...){return 0;} static void null_proc(){} static ControlMode null_control_mode = { "", 0, 1,0,0, NULL, null_proc, NULL, NULL, null_cmsg, null_proc }; static PlayMode null_play_mode = { 8000, PE_MONO, 0, -1, {0,0,0,0,0}, "", 0, "", NULL, NULL, null_proc, NULL, NULL, null_proc, NULL, NULL }; /*ARGSUSED*/ static int null_wrdt_open(char *wrdt_opts) { return 0; } /*ARGSUSED*/ static void null_wrdt_apply(int cmd, int argc, int args[]) { } static void null_wrdt_update_events(void) { } static void null_wrdt_end(void) { } static void null_wrdt_close(void) { } static WRDTracer null_wrdt_mode = { "No WRD trace", '-', 0, null_wrdt_open, null_wrdt_apply, null_wrdt_update_events, NULL, null_wrdt_end, null_wrdt_close }; PlayMode *play_mode = &null_play_mode; ControlMode *ctl = &null_control_mode; WRDTracer *wrdt = &null_wrdt_mode; static struct { char *name; char *info; } control_names[] = { {"Bank select MSB", "0-127, MSB"}, /* 0 */ {"Modulation wheel MSB", "0-127, MSB"}, /* 1 */ {"Breath control MSB", "0-127, MSB"}, /* 2 */ {NULL, "0-127, MSB"}, /* 3 */ {"Foot controller MSB", "0-127, MSB"}, /* 4 */ {"Portamento time MSB", "0-127, MSB"}, /* 5 */ {"Data entry MSB", "0-127, MSB"}, /* 6 */ {"Main volume MSB", "0-127, MSB"}, /* 7 */ {"Balance MSB", "0-127, MSB"}, /* 8 */ {NULL, "0-127, MSB"}, /* 9 */ {"Pan position MSB", "0-127, MSB"}, /* 10 */ {"Expression MSB", "0-127, MSB"}, /* 11 */ {"Effect control 1 MSB", "0-127, MSB"}, /* 12 */ {"Effect control 2/control change MSB","0-127"},/* 13 */ {NULL, "0-127, MSB"}, /* 14 */ {NULL, "0-127, MSB"}, /* 15 */ {"General purpose control 1 MSB","0-127, MSB"}, /* 16 */ {"General purpose control 2 MSB","0-127, MSB"}, /* 17 */ {"General purpose control 3 MSB","0-127, MSB"}, /* 18 */ {"General purpose control 4 MSB","0-127, MSB"}, /* 19 */ {NULL, "0-127, MSB"},/* 20 */ {NULL, "0-127, MSB"},/* 21 */ {NULL, "0-127, MSB"},/* 22 */ {NULL, "0-127, MSB"},/* 23 */ {NULL, "0-127, MSB"},/* 24 */ {NULL, "0-127, MSB"},/* 25 */ {NULL, "0-127, MSB"},/* 26 */ {NULL, "0-127, MSB"},/* 27 */ {NULL, "0-127, MSB"},/* 28 */ {NULL, "0-127, MSB"},/* 29 */ {NULL, "0-127, MSB"},/* 30 */ {NULL, "0-127, MSB"},/* 31 */ {"Bank select LSB", "0-127, LSB"}, /* 32 */ {"Modulation wheel LSB", "0-127, LSB"}, /* 33 */ {"Breath control LSB", "0-127, LSB"}, /* 34 */ {NULL, "0-127, LSB"}, /* 35 */ {"Foot controller LSB", "0-127, LSB"}, /* 36 */ {"Portamento time LSB", "0-127, LSB"}, /* 37 */ {"Data entry LSB", "0-127, LSB"}, /* 38 */ {"Main volume LSB", "0-127, LSB"}, /* 39 */ {"Balance LSB", "0-127, LSB"}, /* 40 */ {"Pan position LSB", "0-127, LSB"}, /* 41 */ {"Expression LSB", "0-127, LSB"}, /* 42 */ {"Effect control 1 LSB", "0-127, LSB"}, /* 43 */ {"Effect control 2 LSB", "0-127, LSB"}, /* 44 */ {NULL, "0-127, LSB"},/* 45 */ {NULL, "0-127, LSB"},/* 46 */ {NULL, "0-127, LSB"},/* 47 */ {NULL, "0-127, LSB"},/* 48 */ {NULL, "0-127, LSB"},/* 49 */ {NULL, "0-127, LSB"},/* 50 */ {NULL, "0-127, LSB"},/* 51 */ {NULL, "0-127, LSB"},/* 52 */ {NULL, "0-127, LSB"},/* 53 */ {NULL, "0-127, LSB"},/* 54 */ {NULL, "0-127, LSB"},/* 55 */ {NULL, "0-127, LSB"},/* 56 */ {NULL, "0-127, LSB"},/* 57 */ {NULL, "0-127, LSB"},/* 58 */ {NULL, "0-127, LSB"},/* 59 */ {NULL, "0-127, LSB"},/* 60 */ {NULL, "0-127, LSB"},/* 61 */ {NULL, "0-127, LSB"},/* 62 */ {NULL, "0-127, LSB"},/* 63 */ {"Damper pedal on/off (Sustain)", "0=off, 127=on"},/* 64 */ {"Portamento on/off", "0=off, 127=on"},/* 65 */ {"Sustenuto on/off", "0=off, 127=on"},/* 66 */ {"Soft pedal on/off", "0=off, 127=on"},/* 67 */ {"Legato pedal on/off", "0=off, 127=on"},/* 68 */ {"Hold 2 pedal on/off", "0=off, 127=on"},/* 69 */ {"Sound variation", "0-127"}, /* 70 */ {"Harmonic content/Sound timbre","0-127"}, /* 71 */ {"Release time", "0-127"}, /* 72 */ {"Attack time", "0-127"}, /* 73 */ {"Brightness", "0-127"}, /* 74 */ {NULL,"0-127"}, /* 75 */ {NULL,"0-127"}, /* 76 */ {NULL,"0-127"}, /* 77 */ {NULL,"0-127"}, /* 78 */ {NULL,"0-127"}, /* 79 */ {"General purpose control 5 (Mute)", NULL},/* 80 */ {"General purpose control 6", NULL},/* 81 */ {"General purpose control 7", NULL},/* 82 */ {"General purpose control 8(Portamento control (64 = C4))", NULL},/* 83 */ {NULL, NULL}, /* 84 */ {NULL, NULL}, /* 85 */ {NULL, NULL}, /* 86 */ {NULL, NULL}, /* 87 */ {NULL, NULL}, /* 88 */ {NULL, NULL}, /* 89 */ {NULL, NULL}, /* 90 */ {"Reverb", "0-127"}, /* 91 */ {"Tremulo depth", "0-127"}, /* 92 */ {"Chorus depth", "0-127"}, /* 93 */ {"Celeste (detune) depth", "0-127"}, /* 94 */ {"Phaser level", "0-127"}, /* 95 */ {"Data entry +1", "0"}, /* 96 */ {"Data entry -1", "0"}, /* 97 */ {"NRPN LSB", NULL}, /* 98 */ {"NRPN MSB", NULL}, /* 99 */ {"RPN LSB", NULL}, /* 100 */ {"RPN MSB", NULL}, /* 101 */ {NULL, NULL}, /* 102 */ {NULL, NULL}, /* 103 */ {NULL, NULL}, /* 104 */ {NULL, NULL}, /* 105 */ {NULL, NULL}, /* 106 */ {NULL, NULL}, /* 107 */ {NULL, NULL}, /* 108 */ {NULL, NULL}, /* 109 */ {NULL, NULL}, /* 110 */ {NULL, NULL}, /* 111 */ {NULL, NULL}, /* 112 */ {NULL, NULL}, /* 113 */ {NULL, NULL}, /* 114 */ {NULL, NULL}, /* 115 */ {NULL, NULL}, /* 116 */ {NULL, NULL}, /* 117 */ {NULL, NULL}, /* 118 */ {NULL, NULL}, /* 119 */ {"All sound off", "0"}, /* 120 */ {"All controllers off", "0"}, /* 121 */ {"Local control on/off", "0=off 127=on"}, /* 122 */ {"All notes off", "0"}, /* 123 */ {"Omni mode off (includes all notes off)", "0"}, /* 124 */ {"Omni mode on (includes all notes off)", "0"}, /* 125 */ {"Poly mode on/off(includes all notes off)", ""}, /* 126 */ {"Poly mode on(incl mono=off&all notes off)","0"}, /* 127 */ }; #define POS tf_tell(tf) #define HEX(x) ("0123456789abcdef"[x]) static void print_02x(int32 x) { int c1, c2; c1 = HEX((x >> 4) & 0x0f); c2 = HEX(x & 0x0f); putchar('0'); putchar('x'); putchar(c1); putchar(c2); } static void print_d(int32 val) { char buff[16]; char *p; if(val == 0x80000000) /* Note that -0x80000000 equal 0x80000000 */ { fputs("-2147483648", stdout); return; } if(val < 0) { putchar('-'); val = -val; } p = buff + 15; *p = '\0'; do { *--p = (char)(val % 10 + '0'); val /= 10; } while(val > 0); fputs(p, stdout); } static void print_x(int32 val) { char buff[16]; char *p; if(val == 0x80000000) { fputs("-80000000", stdout); return; } if(val < 0) { putchar('-'); val = -val; } p = buff + 15; *p = '\0'; do { *--p = HEX(val & 0xf); val >>= 4; } while(val > 0); fputs(p, stdout); } /* Read variable-length number (7 bits per byte, MSB first) */ static int32 getvl(struct timidity_file *tf) { int32 l = 0; int c; if((c = tf_getc(tf)) == EOF) return EOF; putchar('['); print_02x(c); l += (c & 0x7f); if(!(c & 0x80)) { putchar(']'); putchar('='); print_d(l); putchar(' '); return l; } l <<= 7; for(;;) { if((c = tf_getc(tf)) == EOF) { fputs(",EOF]=??" NLS, stdout); return -1; } putchar(','); print_02x(c); l += (c & 0x7f); if(!(c & 0x80)) { putchar(']'); putchar('='); print_d(l); putchar(' '); return l; } l <<= 7; } } /* Print a string from the file, followed by a newline. Any non-ASCII or unprintable characters will be converted to periods. */ static void dumpstring(struct timidity_file *tf, int32 len) { char *si, *so; int s_maxlen = SAFE_CONVERT_LENGTH(len); if(len <= 0) { fputs(NLS, stdout); return; } si = (char *)new_segment(&tmpbuffer, len + 1); so = (char *)new_segment(&tmpbuffer, s_maxlen); if(len != tf_read(si, 1, len, tf)) { reuse_mblock(&tmpbuffer); return; } si[len]='\0'; code_convert(si, so, s_maxlen, NULL, NULL); fputs(so, stdout); fputs(NLS, stdout); reuse_mblock(&tmpbuffer); return; } #define PRINT_D1(s1, d1, s2) \ fputs(s1, stdout); \ print_d(d1); \ fputs(s2, stdout); #define PRINT_D2(s1, d1, s2, d2, s3) \ fputs(s1, stdout); \ print_d(d1); \ fputs(s2, stdout); \ print_d(d2); \ fputs(s3, stdout); #define PRINT_D3(s1, d1, s2, d2, s3, d3, s4) \ fputs(s1, stdout); \ print_d(d1); \ fputs(s2, stdout); \ print_d(d2); \ fputs(s3, stdout); \ print_d(d3); \ fputs(s4, stdout); #define ENDPAREN ")" NLS #define MAX_SYSEX_DUMPLEN 128 static void dump_sysex(struct timidity_file *tf, int32 len) { unsigned char data[MAX_SYSEX_DUMPLEN]; int32 i, skips, mid; char *mid_name; fputs(NLS "\t SysEx", stdout); skips = 0; if(len == 0) goto end_of_sysex; if(len > sizeof(data)) { skips = (int32)(len - sizeof(data)); len = sizeof(data); } if((i = tf_read(data, 1, len, tf)) != len) { len = i; goto end_of_sysex; } /* Manufacture ID */ mid = data[0]; mid_name = mid2name(mid); if(mid_name == NULL) goto end_of_sysex; putchar(' '); fputs(mid_name, stdout); if(len >= 10 && data[0] == 0x41 && /* Roland ID */ data[1] == 0x10 && /* Device ID */ data[2] == 0x42 && /* GS Model ID */ data[3] == 0x12) /* Data Set Command */ { /* Roland GS-Based Synthesizers. */ int32 addr; /* SysEx address */ addr = (((int32)data[4])<<16 | ((int32)data[5])<<8 | (int32)data[6]); if((addr & 0xFFF0FF) == 0x401015) fputs(" Rhythm parts", stdout); else if((addr & 0xFFF0FF) == 0x401016) fputs(" Key shift", stdout); else if(addr == 0x400004) fputs(" Master volume", stdout); else if((addr & 0xFFF0FF) == 0x401019) fputs(" Volume on/off", stdout); else if((addr & 0xFFF0FF) == 0x401002) fputs(" Receive channel on/off", stdout); else if((addr & 0xFFF0FF) == 0x40101C) fputs(" Random pan", stdout); else if(0x402000 <= addr && addr <= 0x402F5A) fputs(" Controller routing", stdout); else if((addr & 0xFFF0FF) == 0x401040) fputs(" Alternate scale tunings", stdout); else if((addr & 0xFFF0FF) == 0x404022) fputs(" SC-88Pro insertion effect on/off", stdout); else if((addr & 0xFFFFF0) == 0x400130) { fputs(" Changing effects", stdout); switch(addr & 0xF) { case 0x0: /* reverb type */ switch(data[7]) { case 0: fputs(" reverb room1", stdout); break; case 1: fputs(" reverb room2", stdout); break; case 2: fputs(" reverb room3", stdout); break; case 3: fputs(" reverb hall1", stdout); break; case 4: fputs(" reverb hall2", stdout); break; case 5: fputs(" reverb palate", stdout); break; case 6: fputs(" reverb delay", stdout); break; case 7: fputs(" reverb panning delay", stdout); break; default: fputs(" reverb type ", stdout); print_02x(data[7]); break; } break; case 0x3: fputs(" reverb level", stdout); break; case 0x8: switch(data[7]) { case 0: fputs(" chorus 1", stdout); break; case 1: fputs(" chorus 2", stdout); break; case 2: fputs(" chorus 3", stdout); break; case 3: fputs(" chorus 4", stdout); break; case 4: fputs(" feedback chorus", stdout); break; case 5: fputs(" flanger chorus", stdout); break; case 6: fputs(" short delay chorus", stdout); break; case 7: fputs(" short delay (FB) chorus", stdout); break; default: fputs(" chorus type ", stdout); print_02x(data[7]); break; } break; case 0x9: fputs(" PRE-LPF", stdout); break; case 0xa: fputs(" level", stdout); break; case 0xb: fputs(" feed back", stdout); break; case 0xc: fputs(" delay", stdout); break; case 0xd: fputs(" rate", stdout); break; case 0xe: fputs(" depth", stdout); break; case 0xf: fputs(" send level", stdout); break; default: putchar(' '); print_02x(addr & 0xF); break; } } else if(addr == 400150) /* SC-88 Delay type */ { switch(data[7]) { case 0: fputs(" Delay type 1", stdout); break; case 1: fputs(" Delay type 2", stdout); break; case 2: fputs(" Delay type 3", stdout); break; case 3: fputs(" Delay type 4", stdout); break; case 4: fputs(" Delay type pan delay 1", stdout); break; case 5: fputs(" Delay type pan delay 2", stdout); break; case 6: fputs(" Delay type pan delay 3", stdout); break; case 7: fputs(" Delay type pan delay 4", stdout); break; case 8: fputs(" Delay type delay to reverb", stdout); break; case 9: fputs(" Delay type pan repeat", stdout); break; default: fputs(" Delay type ", stdout); print_02x(data[7]); break; } } else if((addr & 0xFFF0FF) == 0x401003) fputs(" Rx pitch-bend", stdout); else if(addr == 0x400110) fputs(" Voice reserve", stdout); else if(addr == 0x400158) fputs(" Master delay level", stdout); else if(addr == 0x40007F) fputs(" Reset", stdout); else if(addr == 0x00007F) fputs(" SC-88 Single-Module", stdout); } else if(len > 9 && data[0] == 0x41 && /* Roland ID */ data[1] == 0x10 && /* Device ID */ data[2] == 0x45 && data[3] == 0x12 && data[4] == 0x10 && data[5] == 0x00 && data[6] == 0x00) { fputs(" Insert Text", stdout); } else if(len == 8 && data[0] == 0x43 && data[1] == 0x10 && data[2] == 0x4C && data[3] == 0x00 && data[4] == 0x00 && data[5] == 0x7E) { fputs(" System ON", stdout); } else if(len > 4 && mid >= 0x7e) { int subid, subid2; subid = data[2]; subid2 = data[3]; switch(subid) { case 0x01: fputs(" Sample dump header", stdout); break; case 0x02: fputs(" Data packet", stdout); break; case 0x03: fputs(" Dump request", stdout); break; case 0x04: fputs(" Device control", stdout); switch(subid2) { case 0x01: fputs(" Master volume", stdout); break; default: print_02x(subid2); break; } break; case 0x09: fputs(" System enable/disable", stdout); break; case 0x0F: fputs(" Handshaking message ACK", stdout); break; case 0x0E: fputs(" Handshaking message NAK", stdout); break; case 0x0D: fputs(" Handshaking message Cancel", stdout); break; case 0x0C: fputs(" Handshaking message Wait", stdout); break; } } end_of_sysex: putchar(':'); for(i = 0; i < len; i++) { putchar(' '); print_02x(data[i]); } if(skips) { fputs("...", stdout); skip(tf, skips); } } static void dump_key_sig(struct timidity_file *tf) { int key; #ifdef JAPANESE char buff[32]; static char *notename[24] = { "ハ", "嬰ハ", "ニ", "嬰ニ", "ホ", "ヘ", "嬰ヘ", "ト", "嬰ト", "イ", "嬰イ", "ロ", "ハ", "変ニ", "ニ", "変ホ", "ホ", "ヘ", "変ト", "ト", "変イ", "イ", "変ロ", "ロ" }; static char *keyname[2] = {"長調", "短調"}; static unsigned char *charset = (unsigned char *)"あ"; char *icode; #else static char *notename[24] = { "C", "#C", "D", "#D", "E", "F", "#F", "G", "#G", "A", "#A", "B", "C", "-D", "D", "-E", "E", "F", "-G", "G", "-A", "A", "-B", "B" }; static char *keyname[2] = {"major", "minor"}; #endif /* JAPANESE */ int sf, mi; fputs("Key signature: ", stdout); sf = tf_getc(tf); mi = tf_getc(tf); print_02x(sf); putchar(' '); print_02x(mi); fputs(": ", stdout); if(sf >= 128) sf -= 256; if(sf < -7 || sf > 7 || mi > 1) { fputs("?" NLS, stdout); return; } key = 60 + 7 * sf; if(mi) key -= 3; key %= 12; if(sf < 0) key += 12; #ifdef JAPANESE strcpy(buff, notename[key]); strcat(buff, keyname[mi]); switch(charset[0]) { case 0xa4: icode = "EUC"; break; case 0x82: icode = "SJIS"; break; case 0x1b: icode = "JIS"; break; default: icode = NULL; break; } code_convert(buff, NULL, sizeof(buff), icode, NULL); fputs(buff, stdout); #else fputs(notename[key], stdout); putchar(' '); fputs(keyname[mi], stdout); #endif /* JAPANESE */ fputs(NLS, stdout); } static void dump_time_sig(struct timidity_file *tf) { int nn, dd, cc, bb; fputs("Time signature: ", stdout); nn = tf_getc(tf); dd = tf_getc(tf); cc = tf_getc(tf); bb = tf_getc(tf); print_02x(nn); putchar(' '); print_02x(dd); putchar(' '); print_02x(cc); putchar(' '); print_02x(bb); fputs(": ", stdout); print_d(nn); putchar('/'); print_d(1<7) ? 0 : type], stdout); dumpstring(tf, len); } else switch(type) { case 0x00: fputs(NLS "\t Sequence Number: ", stdout); print_02x(tf_getc(tf)); putchar(' '); print_02x(tf_getc(tf)); fputs(NLS, stdout); break; case 0x2F: /* End of Track */ fputs(NLS "\t End of Track" NLS, stdout); return 0; case 0x51: /* Tempo */ a = tf_getc(tf); b = tf_getc(tf); c = tf_getc(tf); print_02x(a); putchar(' '); print_02x(b); putchar(' '); print_02x(c); fputs(NLS "\t Tempo=", stdout); tempo = c + (int32)b * 256 + (int32)a * 65536; print_d(tempo); printf(" (%d BPM, %.3f msec/delta)", (int)(60.0 * 1000000.0 / tempo + 0.5), (double)tempo / divisions / 1000.0); fputs(NLS, stdout); return 1; case 0x54: /* SMPTE Offset (hr mn se fr ff) */ fputs(NLS "\t SMPTE offset: ", stdout); for(i = 0; i < 4; i++) { print_02x(tf_getc(tf)); putchar(' '); } print_02x(tf_getc(tf)); fputs(NLS, stdout); break; case 0x58: /* Time Signature (nn dd cc bb) */ fputs(NLS "\t ", stdout); dump_time_sig(tf); break; case 0x59: /* Key Signature (sf mi) */ fputs(NLS "\t ", stdout); dump_key_sig(tf); break; case 0x7f: /* Sequencer-Specific Meta-Event */ fputs(NLS "\t Sequencer specific meta event:", stdout); for(i = 0; i < len; i++) { putchar(' '); print_02x(tf_getc(tf)); } fputs(NLS, stdout); break; case 0x20: /* MIDI channel prefix (SMF v1.0) */ fputs(NLS "\t Channel prefix: ", stdout); print_d(tf_getc(tf)); fputs(NLS, stdout); break; case 0x21: /* MIDI port number */ fputs(NLS "\t MIDI port number: ", stdout); print_d(tf_getc(tf)); fputs(NLS, stdout); break; default: fputs(NLS "\t Meta event: type: ", stdout); print_02x(type); fputs(" val:", stdout); for(i = 0; i < len; i++) { putchar(' '); print_02x(tf_getc(tf)); } fputs(NLS, stdout); break; } } else { a = me; if(a & 0x80) /* status byte */ { lastchan = a & 0x0F; laststatus = (a>>4) & 0x07; a = tf_getc(tf); print_02x(a); putchar(' '); a &= 0x7F; } switch(laststatus) { case 0: /* Note off */ b = tf_getc(tf); print_02x(b); b &= 0x7F; PRINT_D2(NLS "\t Note off (ch=", lastchan, ", note=", a, ENDPAREN); return 1; case 1: /* Note on */ b = tf_getc(tf); print_02x(b); b &= 0x7F; PRINT_D3(NLS "\t Note on (ch=", lastchan, ", note=", a, ", velocity=", b, ENDPAREN); return 1; case 2: /* Key Pressure */ b = tf_getc(tf); print_02x(b); b &= 0x7F; PRINT_D3(NLS "\t Key pressure (ch=", lastchan, ", note=", a, ", velocity=", b, ENDPAREN); return 1; case 3: /* Control change */ b = tf_getc(tf); print_02x(b); b &= 0x7F; fputs(NLS "\t Control: ", stdout); switch(a) { case 98: nrpn=1; rpn_lsb[lastchan]=b; break; case 99: nrpn=1; rpn_msb[lastchan]=b; break; case 100: nrpn=0; rpn_lsb[lastchan]=b; break; case 101: nrpn=0; rpn_msb[lastchan]=b; break; case 6: if(nrpn) { switch(rpn_msb[lastchan]) { case 0x01: switch(rpn_lsb[lastchan]) { case 0x08: fputs("NRPN: Vibrato rate ch=", stdout); print_d(lastchan); fputs(" rate=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x09: fputs("NRPN: Vibrato depth ch=", stdout); print_d(lastchan); fputs(" depth=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x0a: fputs("NRPN: Vibrato delay ch=", stdout); print_d(lastchan); fputs(" delay=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x20: fputs("NRPN: Filter cutoff frequency ch=", stdout); print_d(lastchan); fputs(" val=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x21: fputs("NRPN: Filter Resonance ch=", stdout); print_d(lastchan); fputs(" val=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x63: fputs("NRPN: Attack Time ch=", stdout); print_d(lastchan); fputs(" time=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x64: fputs("NRPN: EG Decay Time ch=", stdout); print_d(lastchan); fputs(" time=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x66: fputs("NRPN: EG Release Time ch=", stdout); print_d(lastchan); fputs(" time=", stdout); print_02x(b); fputs(NLS, stdout); return 1; default: fputs("NRPN: ", stdout); print_d(0x01); putchar(','); print_d(rpn_lsb[lastchan]); putchar(' '); fputs(" ch=", stdout); print_d(lastchan); fputs(" data=", stdout); print_02x(b); fputs(NLS, stdout); return 1; } /*NOTREACHED*/ case 0x14: fputs("NRPN: Drum Filter Cutoff (Yamaha) ch=", stdout); print_d(lastchan); fputs(" note=", stdout); print_d(rpn_lsb[lastchan]); fputs(" val=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x15: fputs("NRPN: Drum Filter Resonance (Yamaha) ch=", stdout); print_d(lastchan); fputs(" note=", stdout); print_d(rpn_lsb[lastchan]); fputs(" val=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x16: fputs("NRPN: Drum EG Attack Time (Yamaha) ch=", stdout); print_d(lastchan); fputs(" note=", stdout); print_d(rpn_lsb[lastchan]); fputs(" time=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x17: fputs("NRPN: Drum EG Decay Time (Yamaha) ch=", stdout); print_d(lastchan); fputs(" note=", stdout); print_d(rpn_lsb[lastchan]); fputs(" time=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x18: fputs("NRPN: Coarse Pitch of Drum (Roland)/" "Fine Pitch of Drum (Yamaha) ch=", stdout); print_d(lastchan); fputs(" note=", stdout); print_d(rpn_lsb[lastchan]); fputs(" pitch=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x19: fputs("NRPN: Coarse Pitch of Drum (Yamaha) ch=", stdout); print_d(lastchan); fputs(" note=", stdout); print_d(rpn_lsb[lastchan]); fputs(" pitch=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x1a: fputs("NRPN: Level of Drum ch=", stdout); print_d(lastchan); fputs(" note=", stdout); print_d(rpn_lsb[lastchan]); fputs(" level=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x1c: fputs("NRPN: Panpot of Drum ch=", stdout); print_d(lastchan); fputs(" note=", stdout); print_d(rpn_lsb[lastchan]); fputs(" pan=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x1d: fputs("NRPN: Reverb Send Level of Drum ch=", stdout); print_d(lastchan); fputs(" note=", stdout); print_d(rpn_lsb[lastchan]); fputs(" level=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x1e: fputs("NRPN: Chorus Send Level of Drum ch=", stdout); print_d(lastchan); fputs(" note=", stdout); print_d(rpn_lsb[lastchan]); fputs(" level=", stdout); print_02x(b); fputs(NLS, stdout); return 1; case 0x1f: fputs("NRPN: Variation Send Level of Drum ch=", stdout); print_d(lastchan); fputs(" note=", stdout); print_d(rpn_lsb[lastchan]); fputs(" level=", stdout); print_02x(b); fputs(NLS, stdout); return 1; default: fputs("NRPN: ", stdout); print_d(rpn_lsb[lastchan]); putchar(','); print_d(rpn_lsb[lastchan]); putchar(' '); fputs(" ch=", stdout); print_d(lastchan); fputs(" data=", stdout); print_02x(b); fputs(NLS, stdout); return 1; } /*NOTREACHED*/ } else { switch((rpn_msb[lastchan]<<8) | rpn_lsb[lastchan]) { case 0x0000: /* Pitch bend sensitivity */ PRINT_D2("RPN: Pitch bend sensitivity ch=", lastchan, ", pitchsens=", b, NLS); return 1; case 0x0001: PRINT_D2("RPN: Fine tuning ch=", lastchan, ", tune=", b, NLS); return 1; case 0x0002: PRINT_D2("RPN: Coarse tuning ch=", lastchan, ", tune=", b, NLS); return 1; case 0x7F7F: /* RPN reset */ /* reset pitch bend sensitivity to 2 */ PRINT_D1("RPN: RPN reset (ch=", lastchan, ", pitchsens=2)" NLS); return 1; default: fputs("RPN: ", stdout); print_d(rpn_lsb[lastchan]); putchar(','); print_d(rpn_lsb[lastchan]); putchar(' '); fputs(" ch=", stdout); print_d(lastchan); fputs(" data=", stdout); print_02x(b); fputs(NLS, stdout); return 1; } } /*NOTREACHED*/ default: break; } if(control_names[a].name != NULL) fputs(control_names[a].name, stdout); else print_02x(a); PRINT_D2(" (ch=", lastchan, ", val=", b, ENDPAREN); break; case 4: /* Program change */ a &= 0x7f; PRINT_D2(NLS "\t Program change (ch=", lastchan, ", prog=", a, ENDPAREN); return 1; case 5: a &= 0x7f; PRINT_D2(NLS "\t Channel pressure (ch=", lastchan, ", pressure=", a, ENDPAREN); return 1; case 6: /* Pitch wheel */ b = tf_getc(tf); print_02x(b); putchar(' '); b &= 0x7F; i = (int32)a + (int32)b * 128; if(i == 0x2000 || i < 0 || i > 0x3FFF) i = 0; else i -= 0x2000; PRINT_D2(NLS "\t Pitch wheel (ch=", lastchan, ", pitchbend=", i, ENDPAREN); return 1; default: fputs(NLS "\t *** Can't happen: status ", stdout); print_02x(laststatus); fputs(", channel ", stdout); print_02x(lastchan); fputs(NLS, stdout); break; } } } /*NOTREACHED*/ return 0; } /* Read a midi track */ static int scan_track(struct timidity_file *tf, int append) { int32 len; char tmp[4]; if(!append) at=0; /* Check the formalities */ if ((tf_read(tmp,1,4,tf) != 4) || (tf_read(&len,4,1,tf) != 1)) { fprintf(stderr, "%s: Can't read track header." NLS, current_filename); return -1; } len=BE_LONG(len); if (memcmp(tmp, "MTrk", 4)) { fprintf(stderr, "%s: Corrupt MIDI file." NLS, current_filename); return -1; } printf("%lx\tTrackLen: %ld" NLS, (long)POS - 4, (long)len); for (;;) { int status; status = print_midi_event(tf); if(status < 0) /* Some kind of error */ return status; if(status == 0) /* End-of-track */ return 0; } } void scan_midi_file(char *fname) { int32 len; int16 format, tracks, divisions_tmp; char tmp[4]; struct timidity_file *tf; if((tf = open_file(fname, 1, OF_SILENT)) == NULL) { perror(fname); return; } if(tf->url->url_tell == NULL) tf->url = url_buff_open(tf->url, 1); printf("%s:" NLS, fname); at = 0; errno = 0; if ((tf_read(tmp,1,4,tf) != 4) || (tf_read(&len,4,1,tf) != 1)) { if(errno) { fprintf(stderr, "%s: %s" NLS, current_filename, sys_errlist[errno]); } else fprintf(stderr, "%s: Not a MIDI file!" NLS, current_filename); close_file(tf); return; } len=BE_LONG(len); /* Mac Binary analisys from Aoki Daisuke */ if(memcmp(tmp, "MThd", 4) || len < 6) { char tmp2[128]; if ((tmp[0]!='\0') || (tf_read(tmp2, 1, (128-4-4), tf)!=(128-4-4)) || (tf_read(tmp,1,4,tf) != 4) || (tf_read(&len,4,1,tf) != 1)) { fprintf(stderr, "%s: Not a MIDI file!" NLS, current_filename); close_file(tf); return; } else { len=BE_LONG(len); if (memcmp(tmp, "MThd", 4) || len < 6) { fprintf(stderr, "%s: Not a MIDI file!" NLS, current_filename); close_file(tf); return; } } } printf("%x\t", 4); printf("HeaderLen: %d" NLS, (int)len); printf("%lx\t", (long)POS); tf_read(&format, 2, 1, tf); format=BE_SHORT(format); printf("Format: %d" NLS, format); printf("%lx\t", (long)POS); tf_read(&tracks, 2, 1, tf); tracks=BE_SHORT(tracks); printf("Tracks: %d" NLS, tracks); printf("%lx\t", (long)POS); tf_read(&divisions_tmp, 2, 1, tf); divisions_tmp=BE_SHORT(divisions_tmp); if(divisions_tmp<0) { /* SMPTE time -- totally untested. Got a MIDI file that uses this? */ divisions= (int32)(-(divisions_tmp/256)) * (int32)(divisions_tmp & 0xFF); } else divisions=(int32)(divisions_tmp); printf("Divisions: 0x%04x (%ld)" NLS, ((unsigned)divisions_tmp) & 0xffff, (long)divisions); if(len > 6) { int i, c; printf("OtherHeaderBytes:"); for(i = len - 6; i < 0; i++) { c = tf_getc(tf); putchar(' '); print_02x(c); } fputs(NLS, stdout); } if(format < 0 || format > 2) { fprintf(stderr, "%s: Unknown MIDI file format %d" NLS, current_filename, format); close_file(tf); return; } #if 0 ctl->cmsg(CMSG_INFO, VERB_VERBOSE, "Format: %d Tracks: %d Divisions: %d", format, tracks, divisions); #endif current_read_format = format; tempo = 500000; switch(format) { case 0: current_read_track = 0; scan_track(tf, 0); break; case 1: for (current_read_track=0; current_read_track