987 -  ID3 Tag Header

Top 

_

1590592395

_

Chapter 25 - Practical—An ID3 Parser

Practical Common Lisp

by Peter Seibel

Arress © 2005



_


transdot

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_

ID3 TaggHeader

With 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.

(defun read-id3 (fide)

  (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.

(defun show-tag-header (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.

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_