Книга: Practical Common Lisp
What Frames Do You Actually Need?
What Frames Do You Actually Need?
With the ability to read both version 2.2 and version 2.3 tags using generic frames, you're ready to start implementing classes to represent the specific frames you care about. However, before you dive in, you should take a breather and figure out what frames you actually care about since, as I mentioned earlier, the ID3 spec specifies many frames that are almost never used. Of course, what frames you care about depends on what kinds of applications you're interested in writing. If you're mostly interested in extracting information from existing ID3 tags, then you need implement only the classes representing the frames containing the information you care about. On the other hand, if you want to write an ID3 tag editor, you may need to support all the frames.
Rather than guessing which frames will be most useful, you can use the code you've already written to poke around a bit at the REPL and see what frames are actually used in your own MP3s. To start, you need an instance of id3-tag
, which you can get with the read-id3
function.
ID3V2> (read-id3 "/usr2/mp3/Kitka/Wintersongs/02 Byla Cesta.mp3")
#<ID3V2.2-TAG @ #x727b2912>
Since you'll want to play with this object a bit, you should save it in a variable.
ID3V2> (defparameter *id3* (read-id3 "/usr2/mp3/Kitka/Wintersongs/02 Byla Cesta.mp3"))
*ID3*
Now you can see, for example, how many frames it has.
ID3V2> (length (frames *id3*))
11
Not too many—let's take a look at what they are.
ID3V2> (frames *id3*)
(#<GENERIC-FRAME-V2.2 @ #x72dabdda> #<GENERIC-FRAME-V2.2 @ #x72dabec2>
#<GENERIC-FRAME-V2.2 @ #x72dabfa2> #<GENERIC-FRAME-V2.2 @ #x72dac08a>
#<GENERIC-FRAME-V2.2 @ #x72dac16a> #<GENERIC-FRAME-V2.2 @ #x72dac24a>
#<GENERIC-FRAME-V2.2 @ #x72dac32a> #<GENERIC-FRAME-V2.2 @ #x72dac40a>
#<GENERIC-FRAME-V2.2 @ #x72dac4f2> #<GENERIC-FRAME-V2.2 @ #x72dac632>
#<GENERIC-FRAME-V2.2 @ #x72dac7b2>)
Okay, that's not too informative. What you really want to know are what kinds of frames are in there. In other words, you want to know the id
s of those frames, which you can get with a simple MAPCAR
like this:
ID3V2> (mapcar #'id (frames *id3*))
("TT2" "TP1" "TAL" "TRK" "TPA" "TYE" "TCO" "TEN" "COM" "COM" "COM")
If you look up these identifiers in the ID3v2.2 spec, you'll discover that all the frames with identifiers starting with T are text information frames and have a similar structure. And COM is the identifier for comment frames, which have a structure similar to that of text information frames. The particular text information frames identified here turn out to be the frames for representing the song title, artist, album, track, part of set, year, genre, and encoding program.
Of course, this is just one MP3 file. Maybe other frames are used in other files. It's easy enough to discover. First define a function that combines the previous MAPCAR
expression with a call to read-id3
and wraps the whole thing in a DELETE-DUPLICATES
to keep things tidy. You'll have to use a :test
argument of #'string=
to DELETE-DUPLICATES
to specify that you want two elements considered the same if they're the same string.
(defun frame-types (file)
(delete-duplicates (mapcar #'id (frames (read-id3 file))) :test #'string=))
This should give the same answer except with only one of each identifier when passed the same filename.
ID3V2> (frame-types "/usr2/mp3/Kitka/Wintersongs/02 Byla Cesta.mp3")
("TT2" "TP1" "TAL" "TRK" "TPA" "TYE" "TCO" "TEN" "COM")
Then you can use Chapter 15's walk-directory
function along with mp3-p
to find every MP3 file under a directory and combine the results of calling frame-types
on each file. Recall that NUNION
is the recycling version of the UNION
function; since frame-types
makes a new list for each file, this is safe.
(defun frame-types-in-dir (dir)
(let ((ids ()))
(flet ((collect (file)
(setf ids (nunion ids (frame-types file) :test #'string=))))
(walk-directory dir #'collect :test #'mp3-p))
ids))
Now pass it the name of a directory, and it'll tell you the set of identifiers used in all the MP3 files under that directory. It may take a few seconds depending how many MP3 files you have, but you'll probably get something similar to this:
ID3V2> (frame-types-in-dir "/usr2/mp3/")
("TCON" "COMM" "TRCK" "TIT2" "TPE1" "TALB" "TCP" "TT2" "TP1" "TCM"
"TAL" "TRK" "TPA" "TYE" "TCO" "TEN" "COM")
The four-letter identifiers are the version 2.3 equivalents of the version 2.2 identifiers I discussed previously. Since the information stored in those frames is exactly the information you'll need in Chapter 27, it makes sense to implement classes only for the frames actually used, namely, text information and comment frames, which you'll do in the next two sections. If you decide later that you want to support other frame types, it's mostly a matter of translating the ID3 specifications into the appropriate binary class definitions.
- Structure of an ID3v2 Tag
- Defining a Package
- Integer Types
- String Types
- ID3 Tag Header
- ID3 Frames
- Detecting Tag Padding
- Supporting Multiple Versions of ID3
- Versioned Frame Base Classes
- Versioned Concrete Frame Classes
- What Frames Do You Actually Need?
- Text Information Frames
- Comment Frames
- Extracting Information from an ID3 Tag