From 8aba82f5afc3bae1c5d3b336c57165b430afa5cf Mon Sep 17 00:00:00 2001 From: Adrian Ulrich Date: Sun, 24 Mar 2013 10:57:14 +0100 Subject: [PATCH] support for mp3 in bastp --- src/ch/blinkenlights/bastp/ID3v2File.java | 126 +++++++++++++++++++++ src/ch/blinkenlights/bastp/LameHeader.java | 64 +++++++++++ 2 files changed, 190 insertions(+) create mode 100644 src/ch/blinkenlights/bastp/ID3v2File.java create mode 100644 src/ch/blinkenlights/bastp/LameHeader.java diff --git a/src/ch/blinkenlights/bastp/ID3v2File.java b/src/ch/blinkenlights/bastp/ID3v2File.java new file mode 100644 index 00000000..5a30cdeb --- /dev/null +++ b/src/ch/blinkenlights/bastp/ID3v2File.java @@ -0,0 +1,126 @@ +/***************************************************************** + * This file is part of 'bastp!' - the BuggyAndSloppyTagParser! * + * * + * (C) 2012 Adrian Ulrich * + * * + * Released as 'Public Domain' software * + * * + * This is junk but the ID3v2 spec is even worse! * + * * + *****************************************************************/ + +package ch.blinkenlights.bastp; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.HashMap; +import java.util.Enumeration; + + + +public class ID3v2File extends Common { + private static int ID3_ENC_LATIN = 0x00; + private static int ID3_ENC_UTF16LE = 0x01; + private static int ID3_ENC_UTF16BE = 0x02; + private static int ID3_ENC_UTF8 = 0x03; + + public ID3v2File() { + } + + public HashMap getTags(RandomAccessFile s) throws IOException { + HashMap tags = new HashMap(); + + final int v2hdr_len = 10; + byte[] v2hdr = new byte[v2hdr_len]; + + // read the whole 10 byte header into memory + s.seek(0); + s.read(v2hdr); + + int id3v = ((b2be32(v2hdr,0))) & 0xFF; // swapped ID3\04 -> ver. ist the first byte + int v3len = ((b2be32(v2hdr,6))); // total size EXCLUDING the this 10 byte header + v3len = ((v3len & 0x7f000000) >> 3) | // for some funky reason, this is encoded as 7*4 bits + ((v3len & 0x007f0000) >> 2) | + ((v3len & 0x00007f00) >> 1) | + ((v3len & 0x0000007f) >> 0) ; + + // debug(">> tag version ID3v2."+id3v); + // debug(">> LEN= "+v3len+" // "+v3len); + + // we should already be at the first frame + // so we can start the parsing right now + tags = parse_v3_frames(s, v3len); + tags.put("_hdrlen", v3len+v2hdr_len); + return tags; + } + + /* Parses all ID3v2 frames at the current position up until payload_len + ** bytes were read + */ + public HashMap parse_v3_frames(RandomAccessFile s, long payload_len) throws IOException { + HashMap tags = new HashMap(); + byte[] frame = new byte[10]; // a frame header is always 10 bytes + long bread = 0; // total amount of read bytes + + while(bread < payload_len) { + bread += s.read(frame); + String framename = new String(frame, 0, 4); + int slen = b2be32(frame, 4); + + /* Abort on silly sizes */ + if(slen < 1 || slen > 524288) + break; + + byte[] xpl = new byte[slen]; + bread += s.read(xpl); + + if(framename.substring(0,1).equals("T")) { + String otag = framenameToOggTag(framename); + if(otag.length() > 0 && !tags.containsKey(otag)) { + addTagEntry(tags, otag, getDecodedString(xpl)); + } + } + else if(framename.equals("RVA2")) { + // + } + + } + return tags; + } + + /* Converts ID3v2 sillyframes to OggNames */ + private String framenameToOggTag(String k) { + HashMap lu = new HashMap(); + lu.put("TIT2", "TITLE"); + lu.put("TALB", "ALBUM"); + lu.put("TPE1", "ARTIST"); + + if(lu.containsKey(k)) { + return (String)lu.get(k); + } + return ""; + } + + /* Converts a raw byte-stream text into a java String */ + private String getDecodedString(byte[] raw) { + int encid = raw[0] & 0xFF; + int len = raw.length; + String v = ""; + try { + if(encid == ID3_ENC_LATIN) { + v = new String(raw, 1, len-1, "ISO-8859-1"); + } + else if (encid == ID3_ENC_UTF8) { + v = new String(raw, 1, len-1, "UTF-8"); + } + else if (encid == ID3_ENC_UTF16LE) { + v = new String(raw, 3, len-3, "UTF-16LE"); + } + else if (encid == ID3_ENC_UTF16BE) { + v = new String(raw, 3, len-3, "UTF-16BE"); + } + } catch(Exception e) {} + return v; + } + +} diff --git a/src/ch/blinkenlights/bastp/LameHeader.java b/src/ch/blinkenlights/bastp/LameHeader.java new file mode 100644 index 00000000..3f122d01 --- /dev/null +++ b/src/ch/blinkenlights/bastp/LameHeader.java @@ -0,0 +1,64 @@ +/***************************************************************** + * This file is part of 'bastp!' - the BuggyAndSloppyTagParser! * + * * + * (C) 2012 Adrian Ulrich * + * * + * Released as 'Public Domain' software * + * * + * This is junk but the ID3v2 spec is even worse! * + * * + *****************************************************************/ + +package ch.blinkenlights.bastp; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.HashMap; +import java.util.Enumeration; + + +public class LameHeader extends Common { + + public LameHeader() { + } + + public HashMap getTags(RandomAccessFile s) throws IOException { + return parseLameHeader(s, 0); + } + + public HashMap parseLameHeader(RandomAccessFile s, long offset) throws IOException { + HashMap tags = new HashMap(); + byte[] chunk = new byte[4]; + + s.seek(offset + 0x24); + s.read(chunk); + + String lameMark = new String(chunk, 0, chunk.length, "ISO-8859-1"); + + if(lameMark.equals("Info") || lameMark.equals("Xing")) { + s.seek(offset+0xAB); + s.read(chunk); + + int raw = b2be32(chunk, 0); + int gtrk_raw = raw >> 16; /* first 16 bits are the raw track gain value */ + int galb_raw = raw & 0xFFFF; /* the rest is for the album gain value */ + + float gtrk_val = (float)(gtrk_raw & 0x01FF)/10; + float galb_val = (float)(galb_raw & 0x01FF)/10; + + gtrk_val = ((gtrk_raw&0x0200)!=0 ? -1*gtrk_val : gtrk_val); + galb_val = ((galb_raw&0x0200)!=0 ? -1*galb_val : galb_val); + + if( (gtrk_raw&0xE000) == 0x2000 ) { + addTagEntry(tags, "REPLAYGAIN_TRACK_GAIN", gtrk_val+" dB"); + } + if( (gtrk_raw&0xE000) == 0x4000 ) { + addTagEntry(tags, "REPLAYGAIN_ALBUM_GAIN", galb_val+" dB"); + } + + } + + return tags; + } + +}