anchor.diff:     (extra-flags (optional :type 'u2 :if (extended-p flags)))
      (padding-size (optional :type 'u4 :if (extended-p flags)))
      (crc (optional :type 'u4 :if (crc-p flags extra-flags)))
  -   (frames id3-frames :size size :frame-type 'id3-v2.3-tag)))
  +   (frames (id3-frames :size tag-size :frame-type 'id3-v2.3-frame))))
   
   (defun extended-p (flag)
     (logbitp 6 flag))
   
   (defun crc-p (flags extra)
     (and (extended-p flags) (logbitp 15 extra)))
  +
  +(defgeneric frame-header-size (frame))
  +
  +(defun frame-types (file)
  +  (delete-duplicates (mapcar #'id (frames (read-id3 file))) :test #'string=))
  +
  +(defun non-terminated-type (encoding)
  +  (ecase encoding
  +    (0 'iso-8859-1-string)
  +    (1 'ucs-2-string)))
  +
  +(defun terminated-type (encoding)
  +  (ecase encoding
  +    (0 'iso-8859-1-terminated-string)
  +    (1 'ucs-2-terminated-string)))
  +
  +(defun string-args (encoding length terminator)
  +  (cond
  +    (length
  +     (values (non-terminated-type encoding) :length length))
  +    (terminator
  +     (values (terminated-type encoding) :terminator terminator))))
  +
  +(define-binary-type id3-encoded-string (encoding length terminator)
  +  (:reader (in)
  +           (multiple-value-bind (type keyword arg)
  +               (string-args encoding length terminator)
  +             (read-value type in keyword arg)))
  +  (:writer (out val)
  +           (multiple-value-bind (type keyword arg)
  +               (string-args encoding length terminator)
  +             (write-value type out val keyword arg))))
  +
  +(define-binary-class text-info-frame ()
  +  ((encoding u1)
  +   (information (id3-encoded-string :encoding encoding :length (bytes-left 1)))))
  +
  +(defun bytes-left (bytes-read)
  +  (- (size (current-binary-object)) bytes-read))
  +
  +(define-binary-class text-info-frame-v2.2 (id3-v2.2-frame text-info-frame) ())
  +(define-binary-class text-info-frame-v2.3 (id3-v2.3-frame text-info-frame) ())
  +
  +(define-binary-class comment-frame ()
  +  ((encoding u1)
  +   (language (iso-8859-1-string :length 3))
  +   (description (id3-encoded-string :encoding encoding :terminator +null+))
  +   (text (id3-encoded-string
  +          :encoding encoding
  +          :length (bytes-left
  +                   (+ 1 3 (encoded-string-length description encoding t)))))))
  +
  +(defun encoded-string-length (string encoding terminated)
  +  (let ((characters (+ (length string)
  +                       (if terminated 1 0)
  +                       (ecase encoding (0 0) (1 1)))))
  +    (* characters (ecase encoding (0 1) (1 2)))))
  +
  +(define-binary-class comment-frame-v2.2 (id3-v2.2-frame comment-frame) ())
  +(define-binary-class comment-frame-v2.3 (id3-v2.3-frame comment-frame) ())
  +
  +(defun find-frame (id3 ids)
  +  (find-if #'(lambda (x) (find (id x) ids :test #'string=)) (frames id3)))
  +
  +(defun get-text-info (id3 &rest ids)
  +  (let ((frame (find-frame id3 ids)))
  +    (when frame (information frame))))
  +
  +(defun song   (id3) (get-text-info id3 "TIT2"))
  +(defun album  (id3) (get-text-info id3 "TAL" "TALB"))
  +(defun artist (id3) (get-text-info id3 "TP1" "TPE1"))
  +(defun track  (id3) (get-text-info id3 "TRK" "TRCK"))
  +(defun year   (id3) (get-text-info id3 "TYE" "TYER" "TDRC"))
  +(defun genre  (id3) (get-text-info id3 "TCO" "TCON"))
  +
  +(defun all-info (id3)
  +  (let ((f-list '(song album artist track year genre)))
  +    (mapcar #'(lambda (f)
  +                        (format t "~a~15t~a~%" (symbol-name f)
  +                                (funcall (symbol-function f) id3)))
  +            f-list)))
  +
  +(defun translated-genre (id3)
  +  (let ((genre (genre id3)))
  +    (if (and genre (char= #\( (char genre 0)))
  +        (translate-v1-genre genre))))
  +
  +(defun translate-v1-genre (genre)
  +  (aref *id3-v1-genres* (parse-integer genre :start 1 :junk-allowed t)))
  +
  +(defparameter *id3-v1-genres*
  +  #(
  +    ;; These are the official ID3v1 genres.
  +    "Blues" "Classic Rock" "Country" "Dance" "Disco" "Funk" "Grunge"
  +    "Hip-Hop" "Jazz" "Metal" "New Age" "Oldies" "Other" "Pop" "R&B" "Rap"
  +    "Reggae" "Rock" "Techno" "Industrial" "Alternative" "Ska"
  +    "Death Metal" "Pranks" "Soundtrack" "Euro-Techno" "Ambient"
  +    "Trip-Hop" "Vocal" "Jazz+Funk" "Fusion" "Trance" "Classical"
  +    "Instrumental" "Acid" "House" "Game" "Sound Clip" "Gospel" "Noise"
  +    "AlternRock" "Bass" "Soul" "Punk" "Space" "Meditative"
  +    "Instrumental Pop" "Instrumental Rock" "Ethnic" "Gothic" "Darkwave"
  +    "Techno-Industrial" "Electronic" "Pop-Folk" "Eurodance" "Dream"
  +    "Southern Rock" "Comedy" "Cult" "Gangsta" "Top 40" "Christian Rap"
  +    "Pop/Funk" "Jungle" "Native American" "Cabaret" "New Wave"
  +    "Psychadelic" "Rave" "Showtunes" "Trailer" "Lo-Fi" "Tribal"
  +    "Acid Punk" "Acid Jazz" "Polka" "Retro" "Musical" "Rock & Roll"
  +    "Hard Rock"
  +
  +    ;; These were made up by the authors of Winamp but backported into
  +    ;; the ID3 spec.
  +    "Folk" "Folk-Rock" "National Folk" "Swing" "Fast Fusion"
  +    "Bebob" "Latin" "Revival" "Celtic" "Bluegrass" "Avantgarde"
  +    "Gothic Rock" "Progressive Rock" "Psychedelic Rock" "Symphonic Rock"
  +    "Slow Rock" "Big Band" "Chorus" "Easy Listening" "Acoustic" "Humour"
  +    "Speech" "Chanson" "Opera" "Chamber Music" "Sonata" "Symphony"
  +    "Booty Bass" "Primus" "Porn Groove" "Satire" "Slow Jam" "Club"
  +    "Tango" "Samba" "Folklore" "Ballad" "Power Ballad" "Rhythmic Soul"
  +    "Freestyle" "Duet" "Punk Rock" "Drum Solo" "A capella" "Euro-House"
  +    "Dance Hall"
  +
  +    ;; These were also invented by the Winamp folks but ignored by the
  +    ;; ID3 authors.
  +    "Goa" "Drum & Bass" "Club-House" "Hardcore" "Terror" "Indie"
  +    "BritPop" "Negerpunk" "Polsk Punk" "Beat" "Christian Gangsta Rap"
  +    "Heavy Metal" "Black Metal" "Crossover" "Contemporary Christian"
  +    "Christian Rock" "Merengue" "Salsa" "Thrash Metal" "Anime" "Jpop"
  +    "Synthpop"))
  
positive.code:              (write-value 'general-string out val
                            :length (length val)
                            :type (ucs-2-char-type #xfffe)))))
  
  (define-binary-type iso-8859-1-string (length)
    (:reader (in)
  
negative.code:                (signal 'in-padding))
               (let ((rest (read-value 'iso-8859-1-string in
                                       :length (1- length))))
                 (concatenate 'string (string (code-char first-byte)) rest))))
    (:writer (out val)
             (write-value 'iso-8859-1-string out val)))
  
  (defun read-frame (frame-type in)
    (handler-case (read-value frame-type in)
      (in-padding () nil)))
  
  (define-binary-class id3-v2.2-tag (id3-tag)
    ((frames (id3-frames :size tag-size :frame-type 'id3-v2.2-frame))))
  
  (define-binary-type optional (type if)
    (:reader (in)
  