#include #include #include typedef struct Tag { u8int quality; char encvers[9+1]; u8int rev; u8int vbr; int lowpass; u32int peak; u16int trackgain; u16int albumgain; u8int encflags; u8int ath; u8int bitrate; u16int delay; u16int padding; u8int shape; u8int stereo; u8int unwise; u8int srcfreq; u8int gain; u8int surround; u16int preset; u32int length; u16int crc; u16int tagcrc; } Tag; void gtag(Tag *t, uchar *p) { t->quality = *p++; memcpy(t->encvers, p, 9); t->encvers[9] = '\0'; p += 9; t->rev = *p >> 4; t->vbr = *p++ & 0x0F; t->lowpass = *p++ * 100; // FIXME -- endianness and float t->peak = *p++ << 24; t->peak |= *p++ << 16; t->peak |= *p++ << 8; t->peak |= *p++; t->trackgain = *p++ << 8; t->trackgain |= *p++; t->albumgain = *p++ << 8; t->albumgain |= *p++; t->encflags = *p >> 4; t->ath = *p++ & 0x0F; t->bitrate = *p++; t->delay = *p++ << 4; t->delay |= *p >> 4; t->padding = (*p++ & 0x0F) << 8; t->padding |= *p++; t->shape = *p >> 6; t->stereo = (*p >> 3) & 0x07; t->unwise = (*p >> 2) & 0x01; t->srcfreq = *p++ & 0x3; t->gain = *p++; t->surround = (*p >> 3) & 0x07; t->preset = (*p++ & 0x07) << 8; t->preset |= *p++; t->length = *p++ << 24; t->length |= *p++ << 16; t->length |= *p++ << 8; t->length |= *p++; t->crc = *p++ << 8; t->crc |= *p++; t->tagcrc = *p++ << 8; t->tagcrc |= *p; } u32int gss32(uchar *p) { u32int x; x = *p++ << 21; x |= *p++ << 14; x |= *p++ << 7; x |= *p; return x; } int quality2V(int quality) { return (100 - quality) / 10; } int quality2q(int quality) { return (100 - quality) % 10; } void usage(void) { fprint(2, "usage: %s [file]\n", argv0); exits("usage"); } void main(int argc, char **argv) { int fd; Biobuf bin; uchar buf[36]; int id3len; Tag tag; ARGBEGIN { default: usage(); } ARGEND switch(argc) { case 0: fd = 0; break; case 1: if((fd = open(argv[0], OREAD)) < 0) sysfatal("open %s: %r", argv[0]); break; default: usage(); SET(fd); } Binit(&bin, fd, OREAD); if(Bread(&bin, buf, 10) < 10) sysfatal("read header: %r"); if(strncmp((char *)buf, "ID3", 3) == 0) { // fprint(2, "saw id3 tag\n"); id3len = 10 + gss32(buf+6); if(Bseek(&bin, id3len, 0) < 0) sysfatal("seek frame: %r"); if(Bread(&bin, buf, 2) < 2) sysfatal("read frame: %r"); } else { id3len = 0; } if(buf[0] != 0xFF || (buf[1] & 0xE0) != 0xE0) sysfatal("no sync word"); // FIXME -- check for a xing tag if(Bseek(&bin, id3len + 0x9B, 0) < 0) sysfatal("seek tag: %r"); if(Bread(&bin, buf, sizeof buf) < 0) sysfatal("read tag: %r"); gtag(&tag, buf); print("encoder %s\n", tag.encvers); print("revision %d\n", tag.rev); print("quality %d\n", tag.quality); print("V %d\n", quality2V(tag.quality)); print("q %d\n", quality2q(tag.quality)); print("vbr %d\n", tag.vbr); print("lowpass %d Hz\n", tag.lowpass); print("peak %#.8x\n", tag.peak); print("trackgain %#.4x\n", tag.trackgain); print("albumgain %#.4x\n", tag.albumgain); print("flags %#x\n", tag.encflags); print("ath %d\n", tag.ath); print("bitrate %d kb/s\n", tag.bitrate); print("delay %d\n", tag.delay); print("padding %d\n", tag.padding); print("shape %d\n", tag.shape); print("stereo %d\n", tag.stereo); print("unwise %d\n", tag.unwise); print("srcfreq %d\n", tag.srcfreq); print("gain %d\n", tag.gain); print("surround %d\n", tag.surround); print("preset %d\n", tag.preset); print("length %d\n", tag.length); print("cec %#.4x\n", tag.crc); print("tagcrc %#.4x\n", tag.tagcrc); exits(nil); } /* http://gabriel.mp3-tech.org/mp3infotag.html */