|
@@ -30,6 +30,262 @@ is from the ID3 'spec'"
|
|
|
(2 (flex:octets-to-string octets :external-format :ucs-2be :start start :end end))
|
|
(2 (flex:octets-to-string octets :external-format :ucs-2be :start start :end end))
|
|
|
(3 (flex:octets-to-string octets :external-format :utf-8 :start start :end end))))
|
|
(3 (flex:octets-to-string octets :external-format :utf-8 :start start :end end))))
|
|
|
|
|
|
|
|
|
|
+;;;; V22 frame types:
|
|
|
|
|
+(defparameter *v22-frame-names* '(("BUF" "Recommended buffer size")
|
|
|
|
|
+ ("CNT" "Play counter")
|
|
|
|
|
+ ("COM" "Comments")
|
|
|
|
|
+ ("CRA" "Audio encryption")
|
|
|
|
|
+ ("CRM" "Encrypted meta frame")
|
|
|
|
|
+ ("EQU" "Equalization")
|
|
|
|
|
+ ("ETC" "Event timing codes")
|
|
|
|
|
+ ("GEO" "General encapsulated object")
|
|
|
|
|
+ ("IPL" "Involved people list")
|
|
|
|
|
+ ("LNK" "Linked information")
|
|
|
|
|
+ ("MCI" "Music CD Identifier")
|
|
|
|
|
+ ("MLL" "MPEG location lookup table")
|
|
|
|
|
+ ("PIC" "Attached picture")
|
|
|
|
|
+ ("POP" "Popularimeter")
|
|
|
|
|
+ ("REV" "Reverb")
|
|
|
|
|
+ ("RVA" "Relative volume adjustment")
|
|
|
|
|
+ ("SLT" "Synchronized lyric/text")
|
|
|
|
|
+ ("STC" "Synced tempo codes")
|
|
|
|
|
+ ("TAL" "Album/Movie/Show title")
|
|
|
|
|
+ ("TBP" "BPM (Beats Per Minute)")
|
|
|
|
|
+ ("TCM" "Composer")
|
|
|
|
|
+ ("TCO" "Content type")
|
|
|
|
|
+ ("TCR" "Copyright message")
|
|
|
|
|
+ ("TDA" "Date")
|
|
|
|
|
+ ("TDY" "Playlist delay")
|
|
|
|
|
+ ("TEN" "Encoded by")
|
|
|
|
|
+ ("TFT" "File type")
|
|
|
|
|
+ ("TIM" "Time")
|
|
|
|
|
+ ("TKE" "Initial key")
|
|
|
|
|
+ ("TLA" "Language(s)")
|
|
|
|
|
+ ("TLE" "Length")
|
|
|
|
|
+ ("TMT" "Media type")
|
|
|
|
|
+ ("TOA" "Original artist(s)/performer(s)")
|
|
|
|
|
+ ("TOF" "Original filename")
|
|
|
|
|
+ ("TOL" "Original Lyricist(s)/text writer(s)")
|
|
|
|
|
+ ("TOR" "Original release year")
|
|
|
|
|
+ ("TOT" "Original album/Movie/Show title")
|
|
|
|
|
+ ("TP1" "Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group")
|
|
|
|
|
+ ("TP2" "Band/Orchestra/Accompaniment")
|
|
|
|
|
+ ("TP3" "Conductor/Performer refinement")
|
|
|
|
|
+ ("TP4" "Interpreted, remixed, or otherwise modified by")
|
|
|
|
|
+ ("TPA" "Part of a set")
|
|
|
|
|
+ ("TPB" "Publisher")
|
|
|
|
|
+ ("TRC" "ISRC (International Standard Recording Code)")
|
|
|
|
|
+ ("TRD" "Recording dates")
|
|
|
|
|
+ ("TRK" "Track number/Position in set")
|
|
|
|
|
+ ("TSI" "Size")
|
|
|
|
|
+ ("TSS" "Software/hardware and settings used for encoding")
|
|
|
|
|
+ ("TT1" "Content group description")
|
|
|
|
|
+ ("TT2" "Title/Songname/Content description")
|
|
|
|
|
+ ("TT3" "Subtitle/Description refinement")
|
|
|
|
|
+ ("TXT" "Lyricist/text writer")
|
|
|
|
|
+ ("TXX" "User defined text information frame")
|
|
|
|
|
+ ("TYE" "Year")
|
|
|
|
|
+ ("UFI" "Unique file identifier")
|
|
|
|
|
+ ("ULT" "Unsychronized lyric/text transcription")
|
|
|
|
|
+ ("WAF" "Official audio file webpage")
|
|
|
|
|
+ ("WAR" "Official artist/performer webpage")
|
|
|
|
|
+ ("WAS" "Official audio source webpage")
|
|
|
|
|
+ ("WCM" "Commercial information")
|
|
|
|
|
+ ("WCP" "Copyright/Legal information")
|
|
|
|
|
+ ("WPB" "Publishers official webpage")
|
|
|
|
|
+ ("WXX" "User defined URL link frame")))
|
|
|
|
|
+;;;; V23 frame names
|
|
|
|
|
+(defparameter *v23-frame-names* '(("AENC" "Audio encryption")
|
|
|
|
|
+ ("APIC" "Attached picture")
|
|
|
|
|
+ ("COMM" "Comments")
|
|
|
|
|
+ ("COMR" "Commercial frame")
|
|
|
|
|
+ ("ENCR" "Encryption method registration")
|
|
|
|
|
+ ("EQUA" "Equalization")
|
|
|
|
|
+ ("ETCO" "Event timing codes")
|
|
|
|
|
+ ("GEOB" "General encapsulated object")
|
|
|
|
|
+ ("GRID" "Group identification registration")
|
|
|
|
|
+ ("IPLS" "Involved people list")
|
|
|
|
|
+ ("LINK" "Linked information")
|
|
|
|
|
+ ("MCDI" "Music CD identifier")
|
|
|
|
|
+ ("MLLT" "MPEG location lookup table")
|
|
|
|
|
+ ("OWNE" "Ownership frame")
|
|
|
|
|
+ ("PCNT" "Play counter")
|
|
|
|
|
+ ("POPM" "Popularimeter")
|
|
|
|
|
+ ("POSS" "Position synchronisation frame")
|
|
|
|
|
+ ("PRIV" "Private frame")
|
|
|
|
|
+ ("RBUF" "Recommended buffer size")
|
|
|
|
|
+ ("RVAD" "Relative volume adjustment")
|
|
|
|
|
+ ("RVRB" "Reverb")
|
|
|
|
|
+ ("SYLT" "Synchronized lyric/text")
|
|
|
|
|
+ ("SYTC" "Synchronized tempo codes")
|
|
|
|
|
+ ("TALB" "Album/Movie/Show title")
|
|
|
|
|
+ ("TBPM" "BPM (beats per minute)")
|
|
|
|
|
+ ("TCOM" "Composer")
|
|
|
|
|
+ ("TCON" "Content type")
|
|
|
|
|
+ ("TCOP" "Copyright message")
|
|
|
|
|
+ ("TDAT" "Date")
|
|
|
|
|
+ ("TDLY" "Playlist delay")
|
|
|
|
|
+ ("TENC" "Encoded by")
|
|
|
|
|
+ ("TEXT" "Lyricist/Text writer")
|
|
|
|
|
+ ("TFLT" "File type")
|
|
|
|
|
+ ("TIME" "Time")
|
|
|
|
|
+ ("TIT1" "Content group description")
|
|
|
|
|
+ ("TIT2" "Title/songname/content description")
|
|
|
|
|
+ ("TIT3" "Subtitle/Description refinement")
|
|
|
|
|
+ ("TKEY" "Initial key")
|
|
|
|
|
+ ("TLAN" "Language(s)")
|
|
|
|
|
+ ("TLEN" "Length")
|
|
|
|
|
+ ("TMED" "Media type")
|
|
|
|
|
+ ("TOAL" "Original album/movie/show title")
|
|
|
|
|
+ ("TOFN" "Original filename")
|
|
|
|
|
+ ("TOLY" "Original lyricist(s)/text writer(s)")
|
|
|
|
|
+ ("TOPE" "Original artist(s)/performer(s)")
|
|
|
|
|
+ ("TORY" "Original release year")
|
|
|
|
|
+ ("TOWN" "File owner/licensee")
|
|
|
|
|
+ ("TPE1" "Lead performer(s)/Soloist(s)")
|
|
|
|
|
+ ("TPE2" "Band/orchestra/accompaniment")
|
|
|
|
|
+ ("TPE3" "Conductor/performer refinement")
|
|
|
|
|
+ ("TPE4" "Interpreted, remixed, or otherwise modified by")
|
|
|
|
|
+ ("TPOS" "Part of a set")
|
|
|
|
|
+ ("TPUB" "Publisher")
|
|
|
|
|
+ ("TRCK" "Track number/Position in set")
|
|
|
|
|
+ ("TRDA" "Recording dates")
|
|
|
|
|
+ ("TRSN" "Internet radio station name")
|
|
|
|
|
+ ("TRSO" "Internet radio station owner")
|
|
|
|
|
+ ("TSIZ" "Size")
|
|
|
|
|
+ ("TSRC" "ISRC (international standard recording code)")
|
|
|
|
|
+ ("TSSE" "Software/Hardware and settings used for encoding")
|
|
|
|
|
+ ("TXXX" "User defined text information frame")
|
|
|
|
|
+ ("TYER" "Year")
|
|
|
|
|
+ ("UFID" "Unique file identifier")
|
|
|
|
|
+ ("USER" "Terms of use")
|
|
|
|
|
+ ("USLT" "Unsychronized lyric/text transcription")
|
|
|
|
|
+ ("WCOM" "Commercial information")
|
|
|
|
|
+ ("WCOP" "Copyright/Legal information")
|
|
|
|
|
+ ("WOAF" "Official audio file webpage")
|
|
|
|
|
+ ("WOAR" "Official artist/performer webpage")
|
|
|
|
|
+ ("WOAS" "Official audio source webpage")
|
|
|
|
|
+ ("WORS" "Official internet radio station homepage")
|
|
|
|
|
+ ("WPAY" "Payment")
|
|
|
|
|
+ ("WPUB" "Publishers official webpage")
|
|
|
|
|
+ ("WXXX" "User defined URL link frame")))
|
|
|
|
|
+(defparameter *v24-frame-names* '(("AENC" "Audio encryption")
|
|
|
|
|
+ ("APIC" "Attached picture")
|
|
|
|
|
+ ("ASPI" "Audio seek point index")
|
|
|
|
|
+ ("COMM" "Comments")
|
|
|
|
|
+ ("COMR" "Commercial frame")
|
|
|
|
|
+ ("ENCR" "Encryption method registration")
|
|
|
|
|
+ ("EQU2" "Equalisation (2)")
|
|
|
|
|
+ ("ETCO" "Event timing codes")
|
|
|
|
|
+ ("GEOB" "General encapsulated object")
|
|
|
|
|
+ ("GRID" "Group identification registration")
|
|
|
|
|
+ ("LINK" "Linked information")
|
|
|
|
|
+ ("MCDI" "Music CD identifier")
|
|
|
|
|
+ ("MLLT" "MPEG location lookup table")
|
|
|
|
|
+ ("OWNE" "Ownership frame")
|
|
|
|
|
+ ("PCNT" "Play counter")
|
|
|
|
|
+ ("POPM" "Popularimeter")
|
|
|
|
|
+ ("POSS" "Position synchronisation frame")
|
|
|
|
|
+ ("PRIV" "Private frame")
|
|
|
|
|
+ ("RBUF" "Recommended buffer size")
|
|
|
|
|
+ ("RVA2" "Relative volume adjustment (2)")
|
|
|
|
|
+ ("RVRB" "Reverb")
|
|
|
|
|
+ ("SEEK" "Seek frame")
|
|
|
|
|
+ ("SIGN" "Signature frame")
|
|
|
|
|
+ ("SYLT" "Synchronised lyric/text")
|
|
|
|
|
+ ("SYTC" "Synchronised tempo codes")
|
|
|
|
|
+ ("TALB" "Album/Movie/Show title")
|
|
|
|
|
+ ("TBPM" "BPM (beats per minute)")
|
|
|
|
|
+ ("TCOM" "Composer")
|
|
|
|
|
+ ("TCON" "Content type")
|
|
|
|
|
+ ("TCOP" "Copyright message")
|
|
|
|
|
+ ("TDEN" "Encoding time")
|
|
|
|
|
+ ("TDLY" "Playlist delay")
|
|
|
|
|
+ ("TDOR" "Original release time")
|
|
|
|
|
+ ("TDRC" "Recording time")
|
|
|
|
|
+ ("TDRL" "Release time")
|
|
|
|
|
+ ("TDTG" "Tagging time")
|
|
|
|
|
+ ("TENC" "Encoded by")
|
|
|
|
|
+ ("TEXT" "Lyricist/Text writer")
|
|
|
|
|
+ ("TFLT" "File type")
|
|
|
|
|
+ ("TIPL" "Involved people list")
|
|
|
|
|
+ ("TIT1" "Content group description")
|
|
|
|
|
+ ("TIT2" "Title/songname/content description")
|
|
|
|
|
+ ("TIT3" "Subtitle/Description refinement")
|
|
|
|
|
+ ("TKEY" "Initial key")
|
|
|
|
|
+ ("TLAN" "Language(s)")
|
|
|
|
|
+ ("TLEN" "Length")
|
|
|
|
|
+ ("TMCL" "Musician credits list")
|
|
|
|
|
+ ("TMED" "Media type")
|
|
|
|
|
+ ("TMOO" "Mood")
|
|
|
|
|
+ ("TOAL" "Original album/movie/show title")
|
|
|
|
|
+ ("TOFN" "Original filename")
|
|
|
|
|
+ ("TOLY" "Original lyricist(s)/text writer(s)")
|
|
|
|
|
+ ("TOPE" "Original artist(s)/performer(s)")
|
|
|
|
|
+ ("TOWN" "File owner/licensee")
|
|
|
|
|
+ ("TPE1" "Lead performer(s)/Soloist(s)")
|
|
|
|
|
+ ("TPE2" "Band/orchestra/accompaniment")
|
|
|
|
|
+ ("TPE3" "Conductor/performer refinement")
|
|
|
|
|
+ ("TPE4" "Interpreted, remixed, or otherwise modified by")
|
|
|
|
|
+ ("TPOS" "Part of a set")
|
|
|
|
|
+ ("TPRO" "Produced notice")
|
|
|
|
|
+ ("TPUB" "Publisher")
|
|
|
|
|
+ ("TRCK" "Track number/Position in set")
|
|
|
|
|
+ ("TRSN" "Internet radio station name")
|
|
|
|
|
+ ("TRSO" "Internet radio station owner")
|
|
|
|
|
+ ("TSOA" "Album sort order")
|
|
|
|
|
+ ("TSOP" "Performer sort order")
|
|
|
|
|
+ ("TSOT" "Title sort order")
|
|
|
|
|
+ ("TSRC" "ISRC (international standard recording code)")
|
|
|
|
|
+ ("TSSE" "Software/Hardware and settings used for encoding")
|
|
|
|
|
+ ("TSST" "Set subtitle")
|
|
|
|
|
+ ("TXXX" "User defined text information frame")
|
|
|
|
|
+ ("UFID" "Unique file identifier")
|
|
|
|
|
+ ("USER" "Terms of use")
|
|
|
|
|
+ ("USLT" "Unsynchronised lyric/text transcription")
|
|
|
|
|
+ ("WCOM" "Commercial information")
|
|
|
|
|
+ ("WCOP" "Copyright/Legal information")
|
|
|
|
|
+ ("WOAF" "Official audio file webpage")
|
|
|
|
|
+ ("WOAR" "Official artist/performer webpage")
|
|
|
|
|
+ ("WOAS" "Official audio source webpage")
|
|
|
|
|
+ ("WORS" "Official Internet radio station homepage")
|
|
|
|
|
+ ("WPAY" "Payment")
|
|
|
|
|
+ ("WPUB" "Publishers official webpage")
|
|
|
|
|
+ ("WXXX" "User defined URL link frame")))
|
|
|
|
|
+
|
|
|
|
|
+(defstruct frame-db-entry
|
|
|
|
|
+ text
|
|
|
|
|
+ (is-v22 nil)
|
|
|
|
|
+ (is-v23 nil)
|
|
|
|
|
+ (is-v24 nil))
|
|
|
|
|
+
|
|
|
|
|
+(defparameter *frame-db* nil)
|
|
|
|
|
+
|
|
|
|
|
+(defmacro make-frame-db ()
|
|
|
|
|
+ `(progn
|
|
|
|
|
+ (setf *frame-db* (make-hash-table :test #'equalp))
|
|
|
|
|
+ (dolist (s *v22-frame-names*)
|
|
|
|
|
+ (setf (gethash (first s) *frame-db*)
|
|
|
|
|
+ (make-frame-db-entry :text (second s) :is-v22 t)))
|
|
|
|
|
+ (dolist (s *v23-frame-names*)
|
|
|
|
|
+ (setf (gethash (first s) *frame-db*)
|
|
|
|
|
+ (make-frame-db-entry :text (second s) :is-v23 t)))
|
|
|
|
|
+ (dolist (s *v24-frame-names*)
|
|
|
|
|
+ (multiple-value-bind (val found) (gethash (first s) *frame-db*)
|
|
|
|
|
+ (setf (gethash (first s) *frame-db*)
|
|
|
|
|
+ (if found
|
|
|
|
|
+ (progn
|
|
|
|
|
+ (setf (frame-db-entry-is-v24 val) t)
|
|
|
|
|
+ val)
|
|
|
|
|
+ (make-frame-db-entry :text (second s) :is-v24 t)))))))
|
|
|
|
|
+(make-frame-db)
|
|
|
|
|
+
|
|
|
|
|
+(defun get-frame-db-entry (id)
|
|
|
|
|
+ "Given a frame id/name, return the associated FRAME-DB-ENTRY"
|
|
|
|
|
+ (declare #.utils:*standard-optimize-settings*)
|
|
|
|
|
+
|
|
|
|
|
+ (gethash id *frame-db*))
|
|
|
|
|
+
|
|
|
;;;; ID3 header/extended header/v2.1 header
|
|
;;;; ID3 header/extended header/v2.1 header
|
|
|
(defclass id3-header ()
|
|
(defclass id3-header ()
|
|
|
((version :accessor version :initarg :version :initform 0 :documentation "ID3 version: 2, 3, or 4")
|
|
((version :accessor version :initarg :version :initform 0 :documentation "ID3 version: 2, 3, or 4")
|
|
@@ -309,7 +565,7 @@ are different..."
|
|
|
(ecase version
|
|
(ecase version
|
|
|
(2 (format stream "None"))
|
|
(2 (format stream "None"))
|
|
|
(3 (format stream
|
|
(3 (format stream
|
|
|
- "flags: 0x~4,'0x: ~:[0/~;tag-alter-preservation/~]~:[0/~;file-alter-preservation/~]~:[0/~;read-only/~]~:[0/~;compress/~]~:[0/~;encypt/~]~:[0~;group~]"
|
|
|
|
|
|
|
+ "0x~4,'0x: ~:[0/~;tag-alter-preservation/~]~:[0/~;file-alter-preservation/~]~:[0/~;read-only/~]~:[0/~;compress/~]~:[0/~;encypt/~]~:[0~;group~]"
|
|
|
flags
|
|
flags
|
|
|
(frame-23-altertag-p flags)
|
|
(frame-23-altertag-p flags)
|
|
|
(frame-23-alterfile-p flags)
|
|
(frame-23-alterfile-p flags)
|
|
@@ -332,8 +588,12 @@ are different..."
|
|
|
(defun vpprint-frame-header (id3-frame)
|
|
(defun vpprint-frame-header (id3-frame)
|
|
|
(with-output-to-string (stream)
|
|
(with-output-to-string (stream)
|
|
|
(with-slots (pos version id len flags) id3-frame
|
|
(with-slots (pos version id len flags) id3-frame
|
|
|
- (format stream "offset: ~:d, version = ~d, id: ~a, len: ~:d, ~a"
|
|
|
|
|
- pos version id len
|
|
|
|
|
|
|
+ (format stream "offset: ~:d, version = ~d, id: ~a, description: ~a, len: ~:d, flags: ~a"
|
|
|
|
|
+ pos version id
|
|
|
|
|
+ (aif (get-frame-db-entry id)
|
|
|
|
|
+ (frame-db-entry-text it)
|
|
|
|
|
+ "Non-standard")
|
|
|
|
|
+ len
|
|
|
(if flags
|
|
(if flags
|
|
|
(print-frame-flags version flags nil)
|
|
(print-frame-flags version flags nil)
|
|
|
"flags: none")))))
|
|
"flags: none")))))
|