Versioned Frame Base Classes
Where before you defined a single base class for all frames, you’ll now have two classes, id3v2.2-frame
and id3v2.3-frame
. The id3v2.2-frame
class will be essentially the same as the original id3-frame
class.
(define-tagged-binary-class id3v2.2-frame ()
((id (frame-id :length 3))
(size u3))
(:dispatch (find-frame-class id)))
The id3v2.3-frame
, on the other hand, requires more changes. The frame identifier and size fields were extended in version 2.3 from three to four bytes each, and two bytes worth of flags were added. Additionally, the frame, like the version 2.3 tag, can contain optional fields, controlled by the values of three of the frame’s flags.8 With those changes in mind, you can define the version 2.3 frame base class, along with some helper functions, like this:
(define-tagged-binary-class id3v2.3-frame ()
((id (frame-id :length 4))
(size u4)
(flags u2)
(decompressed-size (optional :type 'u4 :if (frame-compressed-p flags)))
(encryption-scheme (optional :type 'u1 :if (frame-encrypted-p flags)))
(grouping-identity (optional :type 'u1 :if (frame-grouped-p flags))))
(:dispatch (find-frame-class id)))
(defun frame-compressed-p (flags) (logbitp 7 flags))
(defun frame-encrypted-p (flags) (logbitp 6 flags))
(defun frame-grouped-p (flags) (logbitp 5 flags))
With these two classes defined, you can now implement the methods on the generic function frame-header-size
.
(defmethod frame-header-size ((frame id3v2.2-frame)) 6)
(defmethod frame-header-size ((frame id3v2.3-frame)) 10)
The optional fields in a version 2.3 frame aren’t counted as part of the header for this computation since they’re already included in the value of the frame’s size
.