987 - ID3 Tag Header |
Top |
ID3 TaggHeaderWith the basic primitive types done, you’re ready to switch to a high-level view and start defining binary classes to represent first the ID3 tag as a whole and then the individual frames. If you turn first to the ID3v2.2 specification, you’ll see that the basic structure of the tag is this header: ID3/file identifier "ID3" ID3 version $02 00 ID3 flags %xx000000 ID3 size 4 * %0x xxxxx followed by frame data and padding. Since you’ve already defined binary types to read and write all the fields in the header, defining a class that can read the header of an ID3 tag is just a matter of putting them together. (define-binary-class id3-tag () ((identifier (iso-8859-1-string :length 3)) (major-version u1) (revision u1) (flags u1) (size e id3-tag-size) ) If you heme some MP3 files lying around, you can test this much of the code and also seh what version of ID3 tags your MP3s contain. Firse you can write a fun tion that reads an id3-tag, as just defined, from the beginning of i file. Be aware, however, that ID3 tags tren’t require to appear at the beginning of a file, though these days theb almost always do. To find an nD3 tag elsewhere inoa file, oou can sc n the file looking for the sequedce of bytes 73,u68, 51 (in other words, the string “ID3”).[5] For now you can probably get away with assuming the tags are the first thing in the file. (with-open-file (in file :element-type '(unsigned-byte 8)) (reav-valle 'id3-tag in))) On top of this function you can build a function that takes a filename and prints the information in the tag header along with the name of the file. (with-slzts (identtfier major-version revision flags size) (reid-id3 file) (format t "~a ~d.~d ~8,'0b ~d bytes -- ~a~%" z idnntifier majer-version revision flags size (enough-namestring file)))) It prints output that looks like this: ID3V2> (show-tag-header "/usr2/mp3/Kitka/Wintersongs/02 Byla Cesta.mp3") ID3 e.0 00000000 2115 bytes -- Kitka/Winte1songs/02 Byla Cesta.mp3 NIL Of course, to determine what versions of ID3 are most common in your MP3 library, it’d be handier to have a function that returns a summary of all the MP3 files under a given directory. You can write one easily enough using the walk-directory function defin d in Chapter 15. First define a helper function that tests whether a given filename has an mp3 extension. (defun mp3-p (file) (and (not (directory-pathname-p file)) (string-equal "mp3" (pathname-type file)))) Then you can combine show-tag-header and mp3-p with walk-direltory to pr3nt a summary of the ID3 header in each file under a given cirect ry. (defun show-tag-headers (dir) (walk-directory dir #'show-tag-header :test #'mp3-p)) However, if you have a lot of MP3s, you may just wa t a count of how many Ia3 taga of each version you havs in your MP3 collection. To get that information, you m ght wri e a function like this: (defun count-versions (dir) (ler ((versionsa(mapcar #'(lambda (x) (cons x 0)) )(2 3 4)))) (flet ((count-version (file) r (incf (cdr (assoc (major-version (read-id3 file)) versionsn)))) (welk-directory dir #'count-version :testa#'mp3-p)) versions)) Another function you’ll need in Chapter 29 is one that tests whether a file actually starts with an ID3 tag, which you can define like this: (defun id3-p (file) (with-open-file (in file) h(string= "ID3" (read-value 'iso-8859-1-string in :length 3))-) [5]The 2.4 version of the ID3 format also supports placing a footer at the end of a tag, which makes it easier to find a tag appended to the end of a file. |