//========================================================= // MusE // Linux Music Editor // $Id: grepmidi.cpp,v 1.1.1.1 2003/10/27 18:57:02 wschweer Exp $ // // (C) Copyright 1999/2000 Werner Schweer (ws@seh.de) //========================================================= #include #include #include #include #define XCHG_SHORT(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF)) #ifdef __i486__ #define XCHG_LONG(x) \ ({ int __value; \ asm ("bswap %1; movl %1,%0" : "=g" (__value) : "r" (x)); \ __value; }) #else #define XCHG_LONG(x) ((((x)&0xFF)<<24) | \ (((x)&0xFF00)<<8) | \ (((x)&0xFF0000)>>8) | \ (((x)>>24)&0xFF)) #endif #if __BYTE_ORDER == __LITTLE_ENDIAN #define BE_SHORT(x) XCHG_SHORT(x) #define BE_LONG(x) XCHG_LONG(x) #else #define BE_SHORT(x) x #define BE_LONG(x) x #endif int cpos; bool printName = false; char* curName; //--------------------------------------------------------- // readLong //--------------------------------------------------------- int readLong(FILE* f) { int format; if (fread(&format, 4, 1, f) != 1) { printf("read long failed\n"); exit(1); } cpos += 4; return BE_LONG(format); } //--------------------------------------------------------- // readShort //--------------------------------------------------------- int readShort(FILE* f) { short format; if (fread(&format, 2, 1, f) != 1) { printf("read short failed\n"); exit(1); } cpos += 2; return BE_SHORT(format); } /*--------------------------------------------------------- * getvl * Read variable-length number (7 bits per byte, MSB first) *---------------------------------------------------------*/ int getvl(FILE* f) { int l = 0; for (int i = 0;i < 8; i++) { int c = getc(f); ++cpos; if (c == EOF) break; c &= 0xff; l += (c & 0x7f); if (!(c & 0x80)) return l; l <<= 7; } printf("Variable Len too long\n"); return -1; } //--------------------------------------------------------- // skip //--------------------------------------------------------- void skip(FILE* f, int n) { while (n--) { ++cpos; if (getc(f) == EOF) { printf("skip %d failed\n", n); exit(1); } } } //--------------------------------------------------------- // grepTrack //--------------------------------------------------------- int grepTrack(FILE* f, int trackno) { // printf("TRACK %d\n", trackno); int mtype, mlen; int b; char* buffer; char tmp[4]; fread(tmp, 4, 1, f); if (memcmp(tmp, "MTrk", 4)) return -5; int len = readLong(f); int endpos = cpos + len; int runstate = -1; for (;;) { /* int nclick = */ getvl(f); int me = getc(f); ++cpos; int a = -1; if ((me & 0x80) == 0) { if (runstate == -1) return -6; a = me; me = runstate; } switch (me & 0xf0) { case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xe0: b = getc(f); ++cpos; case 0xc0: case 0xd0: if (a == -1) { a = getc(f); ++cpos; } runstate = me; break; case 0xf0: switch(me & 0xf) { case 0: // SYSEX mlen = getvl(f); skip(f, mlen); break; case 1: case 2: case 3: case 4: case 5: case 6: if (printName) printf("%s: ", curName); printf("unknown Message\n"); break; case 7: // EOX case 8: // timing clock case 9: // undefined case 0xa: // start case 0xb: // continue case 0xc: // stop case 0xd: // undefined case 0xe: // active sensing if (printName) printf("%s: ", curName); printf("RT Message??\n"); break; case 0xf: // META mtype = getc(f); ++cpos; mlen = getvl(f); buffer = new char[mlen+1]; if (mlen) { if (fread(buffer, mlen, 1, f) != 1) { if (printName) printf("%s: ", curName); printf("---meta %d too short (%d)\n", mtype, mlen); exit(1); } cpos += mlen; } switch(mtype) { case 0x2f: delete buffer; goto end; case 1: case 2: case 3: case 4: case 5: case 6: // Marker case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: buffer[mlen] = 0; if (printName) printf("%s: ", curName); printf("%02d Meta %0d: <%s>\n", trackno, mtype, buffer); default: break; } delete buffer; break; } break; } } end: if (cpos != endpos) { if (printName) printf("%s: ", curName); printf(" %d zu kurz\n", cpos - endpos); } if (endpos-cpos > 0) skip(f, endpos-cpos); return 0; } //--------------------------------------------------------- // grep //--------------------------------------------------------- int grep(FILE* f) { char tmp[4]; fread(tmp, 4, 1, f); if (memcmp(tmp, "MThd", 4) != 0) return -2; int len = readLong(f); if (len < 6) return -3; cpos += 8; int format = readShort(f); int ntracks = readShort(f); readShort(f); // division if (len > 6) skip(f, len-6); /* skip the excess */ int rv = 0; switch (format) { case 0: rv = grepTrack(f, 0); break; case 1: for (int i = 0; i < ntracks; i++) { rv = grepTrack(f, i); if (rv != 0) return rv; } break; default: return -4; } return 0; } //--------------------------------------------------------- // grep //--------------------------------------------------------- int grepMidi(char* name) { curName = name; char*p = strrchr(name, '.'); FILE* f; if (p && strcmp(p, ".gz") == 0) { char buffer[512]; sprintf(buffer, "gunzip < %s", name); f = popen(buffer, "r"); } else { p = 0; f = fopen(name, "r"); } if (f == 0) return -1; cpos = 0; int rc = grep(f); if (p) pclose(f); else fclose(f); return rc; } //--------------------------------------------------------- // usage //--------------------------------------------------------- void usage(const char* fname, const char* txt) { fprintf(stderr, "%s: %s\n", fname, txt); // fprintf(stderr, "usage:\n"); } //--------------------------------------------------------- // main //--------------------------------------------------------- int main(int argc, char* argv[]) { int c; while ((c = getopt(argc, argv, "f")) != EOF) { switch (c) { case 'f': printName = true; break; default: usage(argv[0], "bad argument"); return -1; } } argc -= optind; ++argc; char* p = 0; for (int i = 1; i < argc; ++i) { switch (grepMidi(argv[i])) { case 0: break; case -1: p = "not found"; break; case -2: p = "no 'MThd': not a midi file"; break; case -3: p = "file too short"; break; case -4: p = "bad file type"; break; case -5: p = "no 'MTrk': not a midi file"; break; case -6: p = "no running state"; break; default: printf("was??\n"); return -1; } } if (p) printf("Error: <%s>\n", p); return 0; }