#ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #ifndef NO_STRING_H #include #else #include #endif #if defined(__FreeBSD__) || defined(__WIN32__) || defined(__bsdi__) #include #else #include #endif #include "timidity.h" /* I guess "rb" should be right for any libc */ #define OPEN_MODE "rb" void patinfo(const char *patfile); void string_dump(const char *s, int len); void safe_puts(const char *s, int len); uint16 conv_short(uint8 *s); uint32 conv_long(uint8 *s); void skip(FILE *fp, size_t len); void dump_modes(uint8 modes); int find_note(uint32 freq); char *note_string(int note); int32 convert_envelope_rate(uint8 rate); double convert_envelope_volume(uint8 offset); double convert_envelope_time(uint8 rate, uint8 o1, uint8 o2); uint32 freq_table[128]= { 8176, 8662, 9177, 9723, 10301, 10913, 11562, 12250, 12978, 13750, 14568, 15434, 16352, 17324, 18354, 19445, 20602, 21827, 23125, 24500, 25957, 27500, 29135, 30868, 32703, 34648, 36708, 38891, 41203, 43654, 46249, 48999, 51913, 55000, 58270, 61735, 65406, 69296, 73416, 77782, 82407, 87307, 92499, 97999, 103826, 110000, 116541, 123471, 130813, 138591, 146832, 155563, 164814, 174614, 184997, 195998, 207652, 220000, 233082, 246942, 261626, 277183, 293665, 311127, 329628, 349228, 369994, 391995, 415305, 440000, 466164, 493883, 523251, 554365, 587330, 622254, 659255, 698456, 739989, 783991, 830609, 880000, 932328, 987767, 1046502, 1108731, 1174659, 1244508, 1318510, 1396913, 1479978, 1567982, 1661219, 1760000, 1864655, 1975533, 2093005, 2217461, 2349318, 2489016, 2637020, 2793826, 2959955, 3135963, 3322438, 3520000, 3729310, 3951066, 4186009, 4434922, 4698636, 4978032, 5274041, 5587652, 5919911, 6271927, 6644875, 7040000, 7458620, 7902133, 8372018, 8869844, 9397273, 9956063, 10548082, 11175303, 11839822, 12543854 }; /* v=2.^((x/127-1) * 6) */ FLOAT_T vol_table[128] = { 0.015625, 0.016145143728351113, 0.016682602624583379, 0.017237953096759438, 0.017811790741104401, 0.01840473098076444, 0.019017409725829021, 0.019650484055324921, 0.020304632921913132, 0.020980557880044631, 0.021678983838355849, 0.02240065983711079, 0.023146359851523596, 0.023916883621822989, 0.024713057510949051, 0.025535735390801884, 0.026385799557992876, 0.027264161680080529, 0.028171763773305786, 0.029109579212875332, 0.030078613776876421, 0.031079906724942836, 0.032114531912828696, 0.033183598944085631, 0.034288254360078256, 0.035429682869614412, 0.036609108619508737, 0.037827796507442342, 0.039087053538526394, 0.040388230227024875, 0.041732722044739302, 0.043121970917609151, 0.044557466772132896, 0.046040749133268132, 0.047573408775524545, 0.049157089429020417, 0.050793489542332405, 0.05248436410402918, 0.054231526524842463, 0.056036850582493913, 0.057902272431264008, 0.059829792678457581, 0.061821478529993396, 0.063879466007418645, 0.066005962238725971, 0.068203247825430205, 0.070473679288442961, 0.072819691595368496, 0.075243800771931268, 0.077748606600335793, 0.080336795407452768, 0.083011142945821612, 0.085774517370559328, 0.088629882315368294, 0.091580300070941839, 0.094628934869176312, 0.097779056276712184, 0.10103404270144323, 0.1043973850157546, 0.1078726903003755, 0.11146368571286204, 0.11517422248485852, 0.11900828005242428, 0.12296997032385605, 0.12706354208958254, 0.13129338557886089, 0.13566403716816194, 0.14018018424629392, 0.14484667024148207, 0.14966849981579558, 0.15465084423249356, 0.15979904690204472, 0.16511862911277009, 0.17061529595225433, 0.17629494242587571, 0.18216365977901747, 0.18822774202974024, 0.19449369271892172, 0.20096823188510385, 0.20765830327152621, 0.21457108177307616, 0.22171398113114205, 0.2290946618846218, 0.23672103958561411, 0.2446012932886038, 0.25274387432224471, 0.26115751535314891, 0.26985123975140174, 0.27883437126784744, 0.28811654403352405, 0.29770771289197112, 0.30761816407549192, 0.31785852623682015, 0.32843978184802081, 0.33937327897885317, 0.3506707434672246, 0.36234429149478936, 0.37440644258117928, 0.38687013301080181, 0.39974872970660535, 0.41305604456569134, 0.42680634927214656, 0.44101439060298442, 0.45569540624360722, 0.47086514112975281, 0.48653986433345225, 0.50273638651110641, 0.51947207793239625, 0.53676488710936021, 0.55463336004561792, 0.57309666012638816, 0.59217458867062556, 0.61188760616732485, 0.63225685421876243, 0.65330417821421161, 0.67505215075844849, 0.69752409588017272, 0.72074411404630734, 0.74473710800900605, 0.76952880951308478, 0.79514580689252357, 0.82161557358563286, 0.84896649759946774, 0.87722791195508854, 0.90643012614631979, 0.93660445864574493, 0.96778327049280244, 1 }; int main(int argc, char **argv) { int i; if(argc == 1) patinfo(NULL); else for(i = 1; i < argc; i++) patinfo(argv[i]); return 0; } void patinfo(const char *patfile) { FILE *fp; uint8 tmp[1024]; int samples, i, j; if(patfile == NULL) { printf("(stdin):" NLS); fp = stdin; } else { printf("%s:" NLS, patfile); if((fp = fopen(patfile, OPEN_MODE)) == NULL) { perror(patfile); return; } } if ((239 != fread(tmp, 1, 239, fp)) || (memcmp(tmp, "GF1PATCH110\0ID#000002", 22) && memcmp(tmp, "GF1PATCH100\0ID#000002", 22))) /* don't know what the differences are */ { fprintf(stderr, " Not an instrument" NLS); if(fp != stdin) fclose(fp); return; } if(tmp[82] != 1 && tmp[82] != 0) /* instruments. To some patch makers, 0 means 1 */ { fprintf(stderr, " Can't handle patches with %d instruments" NLS, tmp[82]); if(fp != stdin) fclose(fp); return; } if(tmp[151] != 1 && tmp[151] != 0) /* layers. What's a layer? */ { fprintf(stderr, " Can't handle instruments with %d layers" NLS, tmp[151]); if(fp != stdin) fclose(fp); return; } printf("16 Discription: "); string_dump((char *)tmp + 22, 60); printf("52 Instruments: %d" NLS, tmp[82]); printf("53 Voices: %d" NLS, tmp[83]); printf("54 Channels: %d" NLS, tmp[84]); printf("55 Waveforms: %d" NLS, conv_short(tmp + 85)); printf("57 MasterVolume: %d" NLS, conv_short(tmp + 87)); printf("59 DataSize: %ld" NLS, (long)conv_long(tmp + 89)); /* 93 -> 129 */ printf("5d "); for(i = 93; i < 129; i++) printf(" 0x%02x", tmp[i]); fputs(NLS, stdout); printf("81 InstrumentNumber: %d" NLS, conv_short(tmp + 129)); printf("83 InstrumentName: "); safe_puts((char *)tmp + 131, 16); printf("93 InstrumentSize: %ld" NLS, (long)conv_long(tmp + 147)); printf("97 Layers: %d" NLS, tmp[151]); /* 152 -> 192 */ printf("98 "); for(i = 152; i < 192; i++) printf(" 0x%02x", tmp[i]); fputs(NLS, stdout); printf("c0 LayerDuplicate: %d" NLS, tmp[192]); printf("c1 Layer: %d" NLS, tmp[193]); printf("c2 LayerSize: %ld" NLS, (long)conv_long(tmp + 194)); samples = tmp[198]; printf("c6 Samples: %d" NLS, samples); printf("99 "); for(i = 199; i < 239; i++) printf(" 0x%02x", tmp[i]); fputs(NLS, stdout); for(i = 0; i < samples; i++) { uint8 fractions; int32 tmplong; uint16 tmpshort; uint8 tmpchar; int32 data_length; int32 tmpaddr; int note; #define READ_CHAR(thing) \ if (1 != fread(&tmpchar, 1, 1, fp)) goto fail; \ thing = tmpchar; #define READ_SHORT(thing) \ if (1 != fread(&tmpshort, 2, 1, fp)) goto fail; \ thing = LE_SHORT(tmpshort); #define READ_LONG(thing) \ if (1 != fread(&tmplong, 4, 1, fp)) goto fail; \ thing = LE_LONG(tmplong); printf(" Sample No: %d" NLS, i); printf("\t%lx\t", (long)ftell(fp)); if(fread(tmp, 1, 7, fp) != 7) goto fail; printf("WaveName: "); safe_puts((char *)tmp, 7); printf("\t%lx\t", (long)ftell(fp)); if(1 != fread(&fractions, 1, 1, fp)) { fail: fprintf(stderr, "\tError reading sample %d" NLS, i); if(fp != stdin) fclose(fp); return; } printf("Fractions: %d %d" NLS, fractions & 0x0f, (fractions>>4) & 0x0f); printf("\t%lx\t", (long)ftell(fp)); READ_LONG(data_length); printf("DataLength: %ld" NLS, (long)data_length); printf("\t%lx\t", (long)ftell(fp)); READ_LONG(tmplong); printf("LoopStart: %ld" NLS, (long)tmplong); printf("\t%lx\t", (long)ftell(fp)); READ_LONG(tmplong); printf("LoopEnd: %ld" NLS, (long)tmplong); printf("\t%lx\t", (long)ftell(fp)); READ_SHORT(tmpshort); printf("SampleRate: %d" NLS, tmpshort); printf("\t%lx\t", (long)ftell(fp)); READ_LONG(tmplong); printf("LowFrequency: %ld note ", (long)tmplong); note = find_note(tmplong); if(tmplong != freq_table[note]) putchar('~'); printf("%d (%s)" NLS, note, note_string(note)); printf("\t%lx\t", (long)ftell(fp)); READ_LONG(tmplong); printf("HighFrequency: %ld note ", (long)tmplong); note = find_note(tmplong); if(tmplong != freq_table[note]) putchar('~'); printf("%d (%s)" NLS, note, note_string(note)); printf("\t%lx\t", (long)ftell(fp)); READ_LONG(tmplong); printf("RootFrequency: %ld note ", (long)tmplong); note = find_note(tmplong); if(tmplong != freq_table[note]) putchar('~'); printf("%d (%s)" NLS, note, note_string(note)); printf("\t%lx\t", (long)ftell(fp)); READ_SHORT(tmpshort); printf("Tune: %d" NLS, (int)tmpshort); /* Always 1, not used anymore */ printf("\t%lx\t", (long)ftell(fp)); READ_CHAR(tmp[0]); printf("Panning: %d", tmp[0]); /* 0..15 */ if(tmp[0] == 0) printf(" (Left)"); else if(tmp[0] == 7) printf(" (Center)"); else if(tmp[0] == 15) printf(" (Right)"); fputs(NLS, stdout); tmpaddr = ftell(fp); if (18 != fread(tmp, 1, 18, fp)) goto fail; for(j = 0; j < 6; j++) { double envt; if(j == 0) envt = convert_envelope_time(tmp[0], 0, tmp[6]); else envt = convert_envelope_time(tmp[j], tmp[j + 5], tmp[j + 6]); printf("\t%lx\tEnvelopeRate(%s): 0x%02x %ld (%.3e sec)" NLS, (long)(tmpaddr + j), j < 3 ? "on" : "off", tmp[j], (long)convert_envelope_rate(tmp[j]), envt); } for(; j < 12; j++) printf("\t%lx\tEnvelopeOffset(%s): %d %.1f%%" NLS, (long)(tmpaddr + j), j < 9 ? "on" : "off", tmp[j], convert_envelope_volume(tmp[j]) * 100); printf("\t%lx\tTremoloSweep: %d" NLS, (long)tmpaddr + 12, tmp[12]); printf("\t%lx\tTremoloRate: %d" NLS, (long)tmpaddr + 13, tmp[13]); printf("\t%lx\tTremoloDepth: %d" NLS, (long)tmpaddr + 14, tmp[14]); printf("\t%lx\tVibratoSweep: %d" NLS, (long)tmpaddr + 15, tmp[15]); printf("\t%lx\tVibratoRate: %d" NLS, (long)tmpaddr + 16, tmp[16]); printf("\t%lx\tVibratoDepth: %d" NLS, (long)tmpaddr + 17, tmp[17]); printf("\t%lx\t", (long)ftell(fp)); READ_CHAR(tmpchar); printf("Mode: 0x%02x (", tmpchar); dump_modes(tmpchar); printf(")" NLS); printf("\t%lx\t", (long)ftell(fp)); READ_SHORT(tmpshort); printf("ScaleFrequency: %d" NLS, (int)tmpshort); printf("\t%lx\t", (long)ftell(fp)); READ_SHORT(tmpshort); printf("ScaleFactor: %d" NLS, (int)tmpshort); printf("\t%lx\t", (long)ftell(fp)); for(j = 0; j < 36; j++) { int c; if((c = getc(fp)) == EOF) { puts("EOF"); exit(1); } printf("0x%02x ", c); } fputs(NLS, stdout); /* data */ printf("\t%lx\tData..." NLS, (long)ftell(fp)); skip(fp, data_length); } if(fp != stdin) fclose(fp); } void string_dump(const char *s, int len) { int i; for(i = 0; i < len; i++) if(s[i] < 32) putchar('.'); else putchar(s[i]); fputs(NLS, stdout); } void safe_puts(const char *s, int len) { int i; for(i = 0; i < len && s[i]; i++) if(s[i] < 32) putchar('.'); else putchar(s[i]); fputs(NLS, stdout); } uint16 conv_short(uint8 *s) { uint16 x; memcpy(&x, s, 2); return LE_SHORT(x); } uint32 conv_long(uint8 *s) { uint32 x; memcpy(&x, s, 4); return LE_LONG(x); } void skip(FILE *fp, size_t len) { size_t c; char tmp[1024]; while(len > 0) { c = len; if(c > 1024) c = 1024; len -= c; if(c != fread(tmp, 1, c, fp)) return; } } void dump_modes(uint8 modes) { int i, flag; char *mode_names[8] = { "16BIT", /* 1 */ "UNSIGNED", /* 2 */ "LOOPING", /* 4 */ "PINGPONG", /* 8 */ "REVERSE", /* 16 */ "SUSTAIN", /* 32 */ "ENVELOPE", /* 64 */ "CLAMPED" /* 128 */ }; flag = 0; for(i = 0; i < 8; i++) { if(modes & (1<>6) & 0x3); r*=3; r = (int32)(rate & 0x3f) << r; return r; } double convert_envelope_volume(uint8 offset) { /* This is not too good... Can anyone tell me what these values mean? Are they GUS-style "exponential" volumes? And what does that mean? */ return vol_table[offset >> 1]; } double convert_envelope_time(uint8 rate, uint8 o1, uint8 o2) { int32 d, r; if(o1 > o2) d = o1 - o2; else d = o2 - o1; d <<= 22; r = convert_envelope_rate(rate) << 9; return (double)d / r / 44100.0; }