Просмотр исходного кода

tree works...finally; checkpointing

Mark VandenBrink 12 лет назад
Родитель
Сommit
d23b423f41
7 измененных файлов с 200 добавлено и 239 удалено
  1. 3 3
      audio-streams.lisp
  2. 1 1
      id3-frame.lisp
  3. 3 0
      logging.lisp
  4. 177 232
      mp4-atom.lisp
  5. 2 2
      packages.lisp
  6. 13 0
      taglib-tests.lisp
  7. 1 1
      tree.lisp

+ 3 - 3
audio-streams.lisp

@@ -334,7 +334,7 @@ a displaced array from STREAMs underlying vector.  If it is == 7, then we have t
 (defvar *get-audio-info* t "controls whether the parsing functions also parse audio info like bit-rate, etc")
 (defvar *get-audio-info* t "controls whether the parsing functions also parse audio info like bit-rate, etc")
 
 
 (defmethod parse-audio-file ((stream mp4-file-stream) &key (get-audio-info *get-audio-info*) &allow-other-keys)
 (defmethod parse-audio-file ((stream mp4-file-stream) &key (get-audio-info *get-audio-info*) &allow-other-keys)
-  "Parse an MP4A file by reading it's ATOMS and decoding them."
+  "Parse an MP4A file by reading its ATOMS and decoding them."
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
   (handler-case
   (handler-case
       (progn
       (progn
@@ -345,7 +345,7 @@ a displaced array from STREAMs underlying vector.  If it is == 7, then we have t
       (utils:warn-user "make-mp4-stream got condition: ~a" c))))
       (utils:warn-user "make-mp4-stream got condition: ~a" c))))
 
 
 (defmethod parse-audio-file ((stream flac-file-stream) &key (get-audio-info *get-audio-info*) &allow-other-keys)
 (defmethod parse-audio-file ((stream flac-file-stream) &key (get-audio-info *get-audio-info*) &allow-other-keys)
-  "Parse a flac file by reading it's headers and decoding them."
+  "Parse a flac file by reading its headers and decoding them."
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
   (declare (ignore get-audio-info)) ; audio info comes for "free" by parsing headers
   (declare (ignore get-audio-info)) ; audio info comes for "free" by parsing headers
   (handler-case
   (handler-case
@@ -354,7 +354,7 @@ a displaced array from STREAMs underlying vector.  If it is == 7, then we have t
       (utils:warn-user "make-flac-stream got condition: ~a" c))))
       (utils:warn-user "make-flac-stream got condition: ~a" c))))
 
 
 (defmethod parse-audio-file ((stream mp3-file-stream) &key (get-audio-info *get-audio-info*) &allow-other-keys)
 (defmethod parse-audio-file ((stream mp3-file-stream) &key (get-audio-info *get-audio-info*) &allow-other-keys)
-  "Parse an MP3 file by reading it's FRAMES and decoding them."
+  "Parse an MP3 file by reading its FRAMES and decoding them."
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
   (handler-case
   (handler-case
       (progn
       (progn

+ 1 - 1
id3-frame.lisp

@@ -980,7 +980,7 @@ NB: 2.3 and 2.4 extended flags are different..."
       (make-instance frame-class :pos pos :version version :id frame-name :len frame-len :flags frame-flags :instream instream))))
       (make-instance frame-class :pos pos :version version :id frame-name :len frame-len :flags frame-flags :instream instream))))
 
 
 (defmethod find-id3-frames ((mp3-file mp3-file-stream))
 (defmethod find-id3-frames ((mp3-file mp3-file-stream))
-  "With an open mp3-file, make sure it is in fact an MP3 file, then read it's header and frames"
+  "With an open mp3-file, make sure it is in fact an MP3 file, then read its header and frames"
 
 
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
   (labels ((read-loop (version stream)
   (labels ((read-loop (version stream)

+ 3 - 0
logging.lisp

@@ -13,6 +13,9 @@
           ,@body)
           ,@body)
      (log5:stop-sender 'trace-log)))
      (log5:stop-sender 'trace-log)))
 
 
+(defun stop-logging ()
+  (log5:stop-sender 'trace-log))
+
 (defparameter *logging-categories* '(mp4-atom::cat-log-mp4-atom
 (defparameter *logging-categories* '(mp4-atom::cat-log-mp4-atom
                                      audio-streams::cat-log-stream
                                      audio-streams::cat-log-stream
                                      mpeg::cat-log-mpeg-frame
                                      mpeg::cat-log-mpeg-frame

+ 177 - 232
mp4-atom.lisp

@@ -16,7 +16,7 @@
 
 
 (defun as-int (str)
 (defun as-int (str)
   "Given a 4-byte string, return an integer type equivalent.
   "Given a 4-byte string, return an integer type equivalent.
-(eg (as-int \"hdlr\" == +audioprop-hdlr+))"
+(ie (as-int \"hdlr\" == +audioprop-hdlr+))"
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
   (declare (type (simple-array character 1) str))
   (declare (type (simple-array character 1) str))
 
 
@@ -30,6 +30,8 @@
     int))
     int))
 
 
 (defun as-string (atom-type)
 (defun as-string (atom-type)
+  "The inverse of as-int: given an integer, return the
+string representation"
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
   (declare (fixnum atom-type))
   (declare (fixnum atom-type))
   (with-output-to-string (s nil)
   (with-output-to-string (s nil)
@@ -40,7 +42,10 @@
 (utils:memoize 'as-string)
 (utils:memoize 'as-string)
 
 
 (defun mk-atom-class-name (name)
 (defun mk-atom-class-name (name)
+  "Create an atom class name by concatenating ATOM- with NAME"
+(declare #.utils:*standard-optimize-settings*)
   (string-upcase (concatenate 'string "atom-" (as-string name))))
   (string-upcase (concatenate 'string "atom-" (as-string name))))
+
 (utils:memoize 'mk-atom-class-name)
 (utils:memoize 'mk-atom-class-name)
 
 
 (eval-when (:compile-toplevel :load-toplevel :execute)
 (eval-when (:compile-toplevel :load-toplevel :execute)
@@ -60,6 +65,7 @@
              (ldb (byte 8 0) retval)  ,(as-octet l4))
              (ldb (byte 8 0) retval)  ,(as-octet l4))
        retval)))
        retval)))
 
 
+(defconstant +root+                  (mk-mp4-atom-type #\R #\O #\O #\T)  "fake root for tree")
 (defconstant +itunes-album+          (mk-mp4-atom-type #xa9 #\a #\l #\b) "text: album name")
 (defconstant +itunes-album+          (mk-mp4-atom-type #xa9 #\a #\l #\b) "text: album name")
 (defconstant +itunes-album-artist+   (mk-mp4-atom-type #\a  #\A #\R #\T) "text: album artist")
 (defconstant +itunes-album-artist+   (mk-mp4-atom-type #\a  #\A #\R #\T) "text: album artist")
 (defconstant +itunes-artist+         (mk-mp4-atom-type #xa9 #\A #\R #\T) "text: artist name")
 (defconstant +itunes-artist+         (mk-mp4-atom-type #xa9 #\A #\R #\T) "text: artist name")
@@ -101,53 +107,71 @@
 (defconstant +mp4-atom-trak+         (mk-mp4-atom-type #\t #\r #\a #\k))
 (defconstant +mp4-atom-trak+         (mk-mp4-atom-type #\t #\r #\a #\k))
 (defconstant +mp4-atom-udta+         (mk-mp4-atom-type #\u #\d #\t #\a))
 (defconstant +mp4-atom-udta+         (mk-mp4-atom-type #\u #\d #\t #\a))
 
 
+(defvar *in-progress* nil "the node currently being worked upon")
+(defvar *tree*        nil "the root of the atom tree")
 
 
 (defclass mp4-atom ()
 (defclass mp4-atom ()
-  ((atom-file-position :accessor atom-file-position :initarg :atom-file-position)
-   (atom-size          :accessor atom-size          :initarg :atom-size)
-   (atom-type          :accessor atom-type          :initarg :atom-type)
-   (atom-children      :accessor atom-children      :initform nil))
-  (:documentation "The minimal mp4-atom.  Note: not all atoms have children, but we put them here anyway to make things 'simple'"))
-
-(defmethod addc ((me mp4-atom) value)
-  "Want to add children atoms to end of ATOM-CHILDREN to preserve in-file order."
-  (declare #.utils:*standard-optimize-settings*)
-  (with-slots (atom-children) me
-    (if (null atom-children)
-        (setf atom-children (list value))
-        (nconc atom-children (list value)))))
+  ((atom-file-pos :accessor atom-file-pos :initarg :atom-file-pos :initform nil)
+   (atom-size     :accessor atom-size     :initarg :atom-size     :initform nil)
+   (atom-type     :accessor atom-type     :initarg :atom-type     :initform nil))
+  (:documentation "The minimal mp4-atom."))
 
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Concreate atoms ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defmethod initialize-instance :around ((me mp4-atom) &key &allow-other-keys)
+  (declare #.utils:*standard-optimize-settings*)
+  (log5:with-context "AROUND:mp4-container-atom-initilalizer"
+    (let* ((old *in-progress*)
+           (*in-progress* (tree:make-node me)))
+      ;(log-mp4-atom "AROUND: entering with old: ~a me: ~a" old me)
+      (if old
+          (progn
+            ;(log-mp4-atom "Adding child ~a to ~a" *in-progress* old)
+            (tree:add-child old *in-progress*))
+          (setf *tree* *in-progress*))
+      (call-next-method))))
+
+(defmacro with-mp4-atom-slots ((instance) &body body)
+  `(with-slots (atom-file-pos atom-size atom-type) ,instance
+     ,@body))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Concrete atoms ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (defclass atom-skip (mp4-atom) ())
 (defclass atom-skip (mp4-atom) ())
-(defmethod initialize-instance :after ((me atom-skip) &key (mp4-file nil) &allow-other-keys)
+
+(defmethod initialize-instance :after ((me atom-skip) &key mp4-file &allow-other-keys)
   "The 'skip' atom.  Used when we want to capture the header of atom, but don't want/need
   "The 'skip' atom.  Used when we want to capture the header of atom, but don't want/need
 to read the payload of an atom."
 to read the payload of an atom."
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
-  (with-slots (atom-size atom-type) me
-    (stream-seek mp4-file (- atom-size 8) :current)))
+  (log5:with-context "atom-skip-initilalizer"
+    (with-mp4-atom-slots (me)
+      (log-mp4-atom "skipping atom of type: ~a" (as-string atom-type))
+      (stream-seek mp4-file (- atom-size 8) :current))))
+
+(defclass mp4-container-atom (mp4-atom) ())
 
 
-(defun read-container-atoms (mp4-file parent-atom)
-  "Loop through a container atom and add it's children to it"
+(defmethod initialize-instance :after ((me mp4-container-atom) &key mp4-file &allow-other-keys)
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
-  (with-slots (atom-children atom-file-position atom-of-interest atom-size atom-type atom-decoded) parent-atom
-    (loop for end = (+ atom-file-position atom-size)
-          for current = (stream-here mp4-file) then (stream-here mp4-file)
-          while (< current end) do
-            (addc parent-atom (make-mp4-atom mp4-file atom-type)))))
+  (log5:with-context "mp4-container-atom-initilalizer"
+    (log-mp4-atom "entering with file at pos ~:d, me: ~a"
+                  (stream-here mp4-file) me)
+    (with-mp4-atom-slots (me)
+      (loop for end = (+ atom-file-pos atom-size)
+            for current = (stream-here mp4-file) then (stream-here mp4-file)
+            while (< current end) do
+              ;;(break "Now at ~a/~a" current end)
+              (make-mp4-atom mp4-file me)))))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ILST ATOMS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ILST ATOMS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defclass atom-ilst (mp4-atom) ())
+(defclass atom-ilst (mp4-container-atom) ())
 
 
-(defmethod initialize-instance :after ((me atom-ilst) &key (mp4-file nil) &allow-other-keys)
+(defmethod initialize-instance :around ((me atom-ilst) &key mp4-file  &allow-other-keys)
   "Construct an ilst atom.  ILST atoms are containers that hold data elements related to tagging.
   "Construct an ilst atom.  ILST atoms are containers that hold data elements related to tagging.
 Loop through this container and construct constituent atoms"
 Loop through this container and construct constituent atoms"
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
+  ;;(break "ilst")
   (log5:with-context "atom-ilst-initializer"
   (log5:with-context "atom-ilst-initializer"
-    (with-slots (atom-size atom-type atom-children) me
+    (with-mp4-atom-slots (me)
       (log-mp4-atom "atom-ilst-init: found ilst atom <~a> @ ~:d, looping for ~:d bytes"
       (log-mp4-atom "atom-ilst-init: found ilst atom <~a> @ ~:d, looping for ~:d bytes"
-                    (as-string atom-type) (stream-here mp4-file) (- atom-size 8))
-      (read-container-atoms mp4-file me))))
-
+                    (as-string atom-type) (stream-here mp4-file) (- atom-size 8)))
+    (call-next-method)))
 
 
 (defclass atom-©alb (atom-ilst) ())
 (defclass atom-©alb (atom-ilst) ())
 (defclass atom-aART (atom-ilst) ())
 (defclass atom-aART (atom-ilst) ())
@@ -173,100 +197,54 @@ Loop through this container and construct constituent atoms"
 (defclass atom-©day (atom-ilst) ())
 (defclass atom-©day (atom-ilst) ())
 
 
 (defclass atom-data (mp4-atom)
 (defclass atom-data (mp4-atom)
-   ((atom-version      :accessor atom-version     :initarg :atom-version)
-    (atom-flags        :accessor atom-flags       :initarg :atom-flags)
-    (atom-value        :accessor atom-value       :initarg :atom-value)
-    (atom-parent-type  :accessor atom-parent-type :initarg :atom-parent-type :initform nil))
-   (:documentation "Represents the 'data' portion of ilst data atom"))
+  ((atom-version :accessor atom-version :initarg :atom-version :initform nil)
+   (atom-flags   :accessor atom-flags   :initarg :atom-flags   :initform nil)
+   (atom-value   :accessor atom-value   :initarg :atom-value   :initform nil))
+  (:documentation "Represents the 'data' portion of ilst data atom"))
 
 
- (defmethod initialize-instance :after ((me atom-data) &key mp4-file &allow-other-keys)
+(defmethod initialize-instance :after ((me atom-data) &key mp4-file parent &allow-other-keys)
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
-   (log5:with-context "atom-data-init"
-     (with-slots (atom-size atom-type atom-version atom-flags atom-value atom-parent-type) me
-       (setf atom-version (stream-read-u8 mp4-file)
-             atom-flags (stream-read-u24 mp4-file))
-       (assert (= 0 (stream-read-u32 mp4-file)) () "a data atom lacks the required null field") ; XXX is this true?
-       (log-mp4-atom "atom-data-init: size = ~:d, name = ~a, version = ~d, flags = ~x" atom-size (as-string atom-type) atom-version atom-flags)
-       (setf atom-value (decode-ilst-data-atom atom-type me atom-parent-type mp4-file))
-       (log-mp4-atom "atom-data-init: made an ilst atom-data: ~a" (vpprint me nil)))))
-
-;;; the ILST atom decoders.  First, a lot of the decoders do the same thing, so we define a macros
-;;; and use those for the relevants atoms.
-(defgeneric decode-ilst-data-atom (type atom atom-parent-type mp4-file))
-
-;;; Quicktime spec says strings are stored as UTF-8...
-(defmacro simple-text-decode (type)
-  `(defmethod decode-ilst-data-atom ((type (eql +itunes-ilst-data+)) atom (atom-parent-type (eql ,type)) mp4-file)
-     (stream-read-utf-8-string-with-len mp4-file (- (atom-size atom) 16))))
-
-(simple-text-decode +itunes-album+)
-(simple-text-decode +itunes-album-artist+)
-(simple-text-decode +itunes-artist+)
-(simple-text-decode +itunes-comment+)
-(simple-text-decode +itunes-composer+)
-(simple-text-decode +itunes-copyright+)
-(simple-text-decode +itunes-year+)
-(simple-text-decode +itunes-encoder+)
-(simple-text-decode +itunes-groups+)
-(simple-text-decode +itunes-genre-x+)
-(simple-text-decode +itunes-lyrics+)
-(simple-text-decode +itunes-purchased-date+)
-(simple-text-decode +itunes-title+)
-(simple-text-decode +itunes-tool+)
-(simple-text-decode +itunes-writer+)
-
-;;; for reasons I'm not clear on, there may or may not be extra bytes after the data in these atoms
-;;; hence, the seek at the end to get us by any unread bytes.
-(defmacro simple-a-b-decode (type)
-  `(defmethod decode-ilst-data-atom ((type (eql +itunes-ilst-data+)) atom (atom-parent-type (eql ,type)) mp4-file)
-     (let ((tmp (stream-read-u16 mp4-file)))
-       (declare (ignore tmp)))
-       ;(format t "ilist decode, parent = ~a: ~x~%" (as-string atom-parent-type) tmp))
-     (let ((a) (b))
-       (setf a (stream-read-u16 mp4-file)
-             b (stream-read-u16 mp4-file))
-       (stream-seek mp4-file (- (atom-size atom) 16 6) :current) ; seek to end of atom: 16 == header; 4 is a, b, skip read above
-       (list a b))))
-
-(simple-a-b-decode +itunes-track+)
-(simple-a-b-decode +itunes-track-n+)
-(simple-a-b-decode +itunes-disk+)
-
-(defmacro simple-u16-decode (type)
-  `(defmethod decode-ilst-data-atom ((type (eql +itunes-ilst-data+)) atom (atom-parent-type (eql ,type)) mp4-file)
-     (declare (ignore atom))
-     (stream-read-u16 mp4-file)))
-
-(simple-u16-decode +itunes-tempo+)
-(simple-u16-decode +itunes-genre+)
-
-(defmethod decode-ilst-data-atom ((type (eql +itunes-ilst-data+)) atom (atom-parent-type (eql +itunes-compilation+)) mp4-file)
-  (declare (ignore atom))
-  (stream-read-u8 mp4-file))
-
-(defmethod decode-ilst-data-atom ((type (eql +itunes-ilst-data+)) atom (atom-parent-type (eql +itunes-cover-art+)) mp4-file)
-  (stream-read-sequence mp4-file (- (atom-size atom) 16)))
+  (log5:with-context "atom-data-initializer"
+    (with-slots (atom-size atom-type atom-version atom-flags atom-value) me
+      (setf atom-version (stream-read-u8 mp4-file)
+            atom-flags   (stream-read-u24 mp4-file))
+      (assert (= 0 (stream-read-u32 mp4-file)) ()
+              "a data atom lacks the required null field")
+      (log-mp4-atom "atom-data-init: size = ~:d, name = ~a, version = ~d, flags = ~x"
+                    atom-size (as-string atom-type) atom-version atom-flags)
+      (setf atom-value
+            (cond ((member (atom-type parent)
+                           (list +itunes-album+ +itunes-album-artist+ +itunes-artist+
+                                 +itunes-comment+ +itunes-composer+ +itunes-copyright+
+                                 +itunes-year+ +itunes-encoder+ +itunes-groups+
+                                 +itunes-genre-x+ +itunes-lyrics+ +itunes-purchased-date+
+                                 +itunes-title+ +itunes-tool+ +itunes-writer+))
+                   (stream-read-utf-8-string-with-len mp4-file (- (atom-size me) 16)))
+                  ((member (atom-type parent)
+                           (list +itunes-track+
+                                 +itunes-track-n+
+                                 +itunes-disk+))
+                   (stream-read-u16 mp4-file) ; throw away
+                   (let* ((a (stream-read-u16 mp4-file))
+                          (b (stream-read-u16 mp4-file)))
+                     (stream-seek mp4-file (- (atom-size me) 16 6) :current)
+                     (list a b)))
+                  ((member (atom-type parent)
+                           (list +itunes-tempo+ +itunes-genre+))
+                   (stream-read-u16 mp4-file))
+              ((= (atom-type parent) +itunes-compilation+)
+               (stream-read-u8 mp4-file))
+              ((= (atom-type parent) +itunes-cover-art+)
+               (stream-read-sequence mp4-file (- (atom-size me) 16)))))
+      (log-mp4-atom "atom-data-init: made an ilst atom-data: ~a" (vpprint me nil)))))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; AUDIO PROPERTY ATOMS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; AUDIO PROPERTY ATOMS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; the pure container classes we need recurse into
-(defclass atom-trak (mp4-atom) ())
-(defmethod initialize-instance :after ((me atom-trak) &key (mp4-file nil) &allow-other-keys)
-  (read-container-atoms mp4-file me))
-(defclass atom-minf (mp4-atom) ())
-(defmethod initialize-instance :after ((me atom-minf) &key (mp4-file nil) &allow-other-keys)
-  (read-container-atoms mp4-file me))
-(defclass atom-moov (mp4-atom) ())
-(defmethod initialize-instance :after ((me atom-moov) &key (mp4-file nil) &allow-other-keys)
-  (read-container-atoms mp4-file me))
-(defclass atom-udta (mp4-atom) ())
-(defmethod initialize-instance :after ((me atom-udta) &key (mp4-file nil) &allow-other-keys)
-  (read-container-atoms mp4-file me))
-(defclass atom-mdia (mp4-atom) ())
-(defmethod initialize-instance :after ((me atom-mdia) &key (mp4-file nil) &allow-other-keys)
-  (read-container-atoms mp4-file me))
-(defclass atom-stbl (mp4-atom) ())
-(defmethod initialize-instance :after ((me atom-stbl) &key (mp4-file nil) &allow-other-keys)
-  (read-container-atoms mp4-file me))
+(defclass atom-trak (mp4-container-atom) ())
+(defclass atom-minf (mp4-container-atom) ())
+(defclass atom-moov (mp4-container-atom) ())
+(defclass atom-udta (mp4-container-atom) ())
+(defclass atom-mdia (mp4-container-atom) ())
+(defclass atom-stbl (mp4-container-atom) ())
 
 
 (defclass atom-hdlr (mp4-atom)
 (defclass atom-hdlr (mp4-atom)
   ((version :accessor version) ; 1 byte
   ((version :accessor version) ; 1 byte
@@ -278,7 +256,8 @@ Loop through this container and construct constituent atoms"
    (rmask   :accessor rmask)   ; 4 bytes
    (rmask   :accessor rmask)   ; 4 bytes
    (mhdlr   :accessor mhdlr))) ; null-terminated string (but we're reading it as octets)
    (mhdlr   :accessor mhdlr))) ; null-terminated string (but we're reading it as octets)
 
 
-(defmethod initialize-instance :after ((me atom-hdlr) &key (mp4-file nil) &allow-other-keys)
+(defmethod initialize-instance :after ((me atom-hdlr) &key mp4-file &allow-other-keys)
+  (declare #.utils:*standard-optimize-settings*)
   (with-slots (version flags qtype mtype resv rflag rmask mhdlr atom-size) me
   (with-slots (version flags qtype mtype resv rflag rmask mhdlr atom-size) me
     (setf version  (stream-read-u8 mp4-file)
     (setf version  (stream-read-u8 mp4-file)
           flags    (stream-read-u24 mp4-file)
           flags    (stream-read-u24 mp4-file)
@@ -287,7 +266,9 @@ Loop through this container and construct constituent atoms"
           resv     (stream-read-u32 mp4-file)
           resv     (stream-read-u32 mp4-file)
           rflag    (stream-read-u32 mp4-file)
           rflag    (stream-read-u32 mp4-file)
           rmask    (stream-read-u32 mp4-file)
           rmask    (stream-read-u32 mp4-file)
-          mhdlr    (stream-read-sequence mp4-file (- atom-size 32))))) ; 32 is 8-bytes of header plus fields above
+          mhdlr    (stream-read-sequence mp4-file (- atom-size 32))) ; 32 is 8-bytes of header plus fields above
+    ;;(break "hdlr")
+    ))
 
 
 (defclass atom-mdhd (mp4-atom)
 (defclass atom-mdhd (mp4-atom)
   ((version  :accessor version)
   ((version  :accessor version)
@@ -299,7 +280,7 @@ Loop through this container and construct constituent atoms"
    (lang     :accessor lang)
    (lang     :accessor lang)
    (quality  :accessor quality)))
    (quality  :accessor quality)))
 
 
-(defmethod initialize-instance :after ((me atom-mdhd) &key (mp4-file nil) &allow-other-keys)
+(defmethod initialize-instance :after ((me atom-mdhd) &key mp4-file &allow-other-keys)
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
   (with-slots (version flags c-time m-time scale duration lang quality) me
   (with-slots (version flags c-time m-time scale duration lang quality) me
     (setf version  (stream-read-u8 mp4-file)
     (setf version  (stream-read-u8 mp4-file)
@@ -359,7 +340,7 @@ Loop through this container and construct constituent atoms"
 (defconstant +mp4-extdescrtagsstart+       #x80)
 (defconstant +mp4-extdescrtagsstart+       #x80)
 (defconstant +mp4-extdescrtagsend+         #xfe)
 (defconstant +mp4-extdescrtagsend+         #xfe)
 
 
-(defmethod initialize-instance :after ((me atom-esds) &key (mp4-file nil) &allow-other-keys)
+(defmethod initialize-instance :after ((me atom-esds) &key mp4-file &allow-other-keys)
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
   (with-slots (version flags esid s-priority obj-id s-type buf-size max-bit-rate avg-bit-rate) me
   (with-slots (version flags esid s-priority obj-id s-type buf-size max-bit-rate avg-bit-rate) me
     (setf version (stream-read-u8 mp4-file)
     (setf version (stream-read-u8 mp4-file)
@@ -386,7 +367,7 @@ Loop through this container and construct constituent atoms"
    (version     :accessor version)
    (version     :accessor version)
    (num-entries :accessor num-entries)))
    (num-entries :accessor num-entries)))
 
 
-(defmethod initialize-instance :after ((me atom-stsd) &key (mp4-file nil) &allow-other-keys)
+(defmethod initialize-instance :after ((me atom-stsd) &key mp4-file &allow-other-keys)
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
   (log5:with-context "atom-stsd"
   (log5:with-context "atom-stsd"
     (with-slots (flags version num-entries) me
     (with-slots (flags version num-entries) me
@@ -395,7 +376,7 @@ Loop through this container and construct constituent atoms"
             num-entries (stream-read-u32 mp4-file))
             num-entries (stream-read-u32 mp4-file))
       (log-mp4-atom "atom-stsd: version = ~d, flags = ~x, num-fields = ~d" version flags num-entries))))
       (log-mp4-atom "atom-stsd: version = ~d, flags = ~x, num-fields = ~d" version flags num-entries))))
 
 
-(defclass atom-mp4a (mp4-atom)
+(defclass atom-mp4a (mp4-container-atom)
   ((reserved    :accessor reserved)    ; 6 bytes
   ((reserved    :accessor reserved)    ; 6 bytes
    (d-ref-idx   :accessor d-ref-idx)   ; 2 bytes
    (d-ref-idx   :accessor d-ref-idx)   ; 2 bytes
    (version     :accessor version)     ; 2 bytes
    (version     :accessor version)     ; 2 bytes
@@ -407,7 +388,9 @@ Loop through this container and construct constituent atoms"
    (packet-size :accessor packet-size) ; 2 bytes
    (packet-size :accessor packet-size) ; 2 bytes
    (samp-rate   :accessor samp-rate))) ; 4 bytes
    (samp-rate   :accessor samp-rate))) ; 4 bytes
 
 
-(defmethod initialize-instance :after ((me atom-mp4a) &key (mp4-file nil) &allow-other-keys)
+(defmethod initialize-instance :around ((me atom-mp4a) &key mp4-file &allow-other-keys)
+  "Note: this MUST be an AROUND method so that the atom's data can be read in before
+reading the container atoms"
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
   (log5:with-context "atom-mp4a"
   (log5:with-context "atom-mp4a"
     (with-slots (reserved d-ref-idx version revision vendor num-chans samp-size comp-id packet-size samp-rate) me
     (with-slots (reserved d-ref-idx version revision vendor num-chans samp-size comp-id packet-size samp-rate) me
@@ -420,19 +403,20 @@ Loop through this container and construct constituent atoms"
             samp-size   (stream-read-u16 mp4-file)
             samp-size   (stream-read-u16 mp4-file)
             comp-id     (stream-read-u16 mp4-file)
             comp-id     (stream-read-u16 mp4-file)
             packet-size (stream-read-u16 mp4-file)
             packet-size (stream-read-u16 mp4-file)
-            samp-rate   (stream-read-u32 mp4-file)) ; fixed 16.16 floating point number
-
-      (read-container-atoms mp4-file me))))
+            samp-rate   (stream-read-u32 mp4-file)))) ; fixed 16.16 floating point number
+  (call-next-method))
 
 
-(defclass atom-meta (mp4-atom)
+(defclass atom-meta (mp4-container-atom)
   ((version  :accessor version)
   ((version  :accessor version)
    (flags    :accessor flags)))
    (flags    :accessor flags)))
-(defmethod initialize-instance :after ((me atom-meta) &key (mp4-file nil) &allow-other-keys)
+
+(defmethod initialize-instance :around ((me atom-meta) &key mp4-file &allow-other-keys)
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
+  ;;(break "meta")
    (with-slots (version flags) me
    (with-slots (version flags) me
-     (setf version  (stream-read-u8 mp4-file)
-           flags    (stream-read-u24 mp4-file))
-     (read-container-atoms mp4-file me)))
+     (setf version (stream-read-u8 mp4-file)
+           flags   (stream-read-u24 mp4-file)))
+  (call-next-method))
 
 
 (defun find-atom-class (id)
 (defun find-atom-class (id)
   "Search by concatenating 'atom-' with ID and look for that symbol in this package"
   "Search by concatenating 'atom-' with ID and look for that symbol in this package"
@@ -453,7 +437,7 @@ Loop through this container and construct constituent atoms"
     'atom-skip))
     'atom-skip))
 (utils:memoize 'find-atom-class)
 (utils:memoize 'find-atom-class)
 
 
-(defun make-mp4-atom (mp4-file &optional parent-type)
+(defun make-mp4-atom (mp4-file parent)
   "Get current file position, read in size/type, then construct the correct atom."
   "Get current file position, read in size/type, then construct the correct atom."
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
   (log5:with-context "make-mp4-atom"
   (log5:with-context "make-mp4-atom"
@@ -461,7 +445,7 @@ Loop through this container and construct constituent atoms"
            (siz (stream-read-u32 mp4-file))
            (siz (stream-read-u32 mp4-file))
            (typ (stream-read-u32 mp4-file))
            (typ (stream-read-u32 mp4-file))
            (atom))
            (atom))
-      (declare (type integer pos siz typ))
+      (declare (type fixnum pos siz typ))
 
 
       (log-mp4-atom "make-mp4-atom: @ pos = ~:d of size = ~:d and type = ~a" pos siz (as-string typ))
       (log-mp4-atom "make-mp4-atom: @ pos = ~:d of size = ~:d and type = ~a" pos siz (as-string typ))
 
 
@@ -469,20 +453,25 @@ Loop through this container and construct constituent atoms"
         (error "trying to make an atom ~a with size of 0 at offset ~:d in file ~a"
         (error "trying to make an atom ~a with size of 0 at offset ~:d in file ~a"
                (as-string typ) pos (stream-filename mp4-file)))
                (as-string typ) pos (stream-filename mp4-file)))
 
 
-      (setf atom (make-instance (find-atom-class typ) :atom-size siz :atom-type typ :atom-file-position pos :mp4-file mp4-file :atom-parent-type parent-type))
+      (setf atom (make-instance (find-atom-class typ) :atom-size siz
+                                                      :atom-type typ
+                                                      :atom-file-pos pos
+                                                      :parent parent
+                                                      :mp4-file mp4-file))
       (log-mp4-atom "make-mp4-atom: made ~a" (vpprint atom nil))
       (log-mp4-atom "make-mp4-atom: made ~a" (vpprint atom nil))
       atom)))
       atom)))
 
 
 (defmethod vpprint ((me mp4-atom) stream)
 (defmethod vpprint ((me mp4-atom) stream)
+  (declare #.utils:*standard-optimize-settings*)
   (format stream "~a"
   (format stream "~a"
           (with-output-to-string (s)
           (with-output-to-string (s)
-            (with-slots (atom-children atom-file-position atom-size atom-type) me
-              (format s "ATOM: type: <~a> @ ~:d of size ~:d and child count of ~d"
-                      (as-string atom-type) atom-file-position atom-size (length atom-children)))
+            (with-mp4-atom-slots (me)
+              (format s "ATOM: type: <~a> @ ~:d of size ~:d"
+                      (as-string atom-type) atom-file-pos atom-size))
             (if (typep me 'atom-data)
             (if (typep me 'atom-data)
-                (with-slots (atom-version atom-flags atom-value atom-type atom-parent-type) me
-                  (format s " having ilst fields: atom-parent-type = ~a, verison = ~d, flags = ~x, data = ~x"
-                          (as-string atom-parent-type) atom-version atom-flags
+                (with-slots (atom-version atom-flags atom-value atom-type) me
+                  (format s " having ilst fields:verison = ~d, flags = ~x, data = ~x"
+                          atom-version atom-flags
                           (if (typep atom-value 'array) (printable-array atom-value) atom-value)))))))
                           (if (typep atom-value 'array) (printable-array atom-value) atom-value)))))))
 
 
 (defun is-valid-m4-file (mp4-file)
 (defun is-valid-m4-file (mp4-file)
@@ -513,97 +502,51 @@ Written in this fashion so as to be 'crash-proof' when passed an arbitrary file.
   (log5:with-context "find-mp4-atoms"
   (log5:with-context "find-mp4-atoms"
 
 
     (stream-seek mp4-file 0 :start)
     (stream-seek mp4-file 0 :start)
+    (setf *in-progress* nil)
     (log-mp4-atom "find-mp4-atoms: ~a, before read-file loop, file-position = ~:d, end = ~:d"
     (log-mp4-atom "find-mp4-atoms: ~a, before read-file loop, file-position = ~:d, end = ~:d"
                   (stream-filename mp4-file) (stream-here mp4-file) (stream-size mp4-file))
                   (stream-filename mp4-file) (stream-here mp4-file) (stream-size mp4-file))
 
 
-    (setf (mp4-atoms mp4-file)
-          (loop for end = (stream-size mp4-file)
-                for current = (stream-here mp4-file) then (stream-here mp4-file)
-                while (< current end)
-                collecting (make-mp4-atom mp4-file)))
+    ;; Construct our fake "root" for our tree, which recursively reads all atoms
+    (tree:make-node (make-instance 'mp4-container-atom
+                                   :atom-type +root+
+                                   :atom-file-pos 0
+                                   :atom-size (stream-size mp4-file)
+                                   :mp4-file mp4-file))
+    (setf (mp4-atoms mp4-file) *tree*)))
 
 
-    (log-mp4-atom "find-mp4-atoms: returning list of size ~d" (length (mp4-atoms mp4-file)))))
-
-(defmethod map-mp4-atom ((atoms list) &key (func nil) (depth nil))
-  "Given a list of atoms, call map-mp4-atom for each one"
-  (declare #.utils:*standard-optimize-settings*)
-  (log5:with-context "map-mp4-atom"
-    (dolist (a atoms)
-      (map-mp4-atom a :func func :depth depth))))
-
-(defmethod map-mp4-atom ((me mp4-atom) &key (func nil) (depth nil))
-  "Traverse all atoms under a given atom"
-  (declare #.utils:*standard-optimize-settings*)
-  (log5:with-context "map-mp4-atom(single)"
-    (labels ((_indented-atom (atom depth)
-               (format t "~vt~a~%"  (if (null depth) 0 depth) (vpprint atom nil))))
-      (with-slots (atom-type atom-children) me
-        (log-mp4-atom "map-mp4-atom: begining traversal with ~a, I have ~d children" (as-string atom-type) (length atom-children))
-        (when (null func)
-          (setf func #'_indented-atom))
-        (funcall func me depth)
-        (map-mp4-atom atom-children :func func :depth (if (null depth) nil (+ 1 depth)))))))
-
-(defmethod traverse ((me mp4-atom) path)
-  (declare #.utils:*standard-optimize-settings*)
-  (traverse (atom-children me) path))
-
-(defmethod traverse ((me list) path)
-  "Used in finding nested atoms. Search MP4-ATOMS and if we find a match with first of path,
-call traverse atom (unless length of path == 1, in which case, we've found our match)"
-  (declare #.utils:*standard-optimize-settings*)
-  (log5:with-context "traverse"
-    (log-mp4-atom "traverse: entering with ~a ~a" me path)
-    (dolist (sibling me)
-      (with-slots (atom-type atom-children) sibling
-        (log-mp4-atom "traverse: comparing ~a to ~a" (as-string atom-type) (as-string (first path)))
-        (when (= atom-type (first path))
-          (cond
-            ((= 1 (length path))
-             (log-mp4-atom "traverse: matched: ~a" sibling)
-             (return-from traverse sibling))
-            (t
-             (log-mp4-atom "traverse: path matches, recursing")
-             (let ((found (traverse atom-children (rest path))))
-               (if found (return-from traverse found))))))))
-    (log-mp4-atom "traverse: ~a not found" path)
-    nil))
 
 
 (defvar *ilst-data* (list +mp4-atom-moov+ +mp4-atom-udta+ +mp4-atom-meta+ +mp4-atom-ilst+ nil +itunes-ilst-data+))
 (defvar *ilst-data* (list +mp4-atom-moov+ +mp4-atom-udta+ +mp4-atom-meta+ +mp4-atom-ilst+ nil +itunes-ilst-data+))
 
 
 (defmethod tag-get-value (atoms node)
 (defmethod tag-get-value (atoms node)
   "Helper function to extract text from ILST atom's data atom"
   "Helper function to extract text from ILST atom's data atom"
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
-  (setf (nth 4 *ilst-data*) node)
-  (aif (traverse atoms *ilst-data*)
+  (aif (tree:find-tree atoms
+                       (lambda (x) (= (atom-type x) node)))
        (atom-value it)
        (atom-value it)
        nil))
        nil))
 
 
-(defconstant +path-to-ilst+ (list +mp4-atom-moov+ +mp4-atom-udta+ +mp4-atom-meta+ +mp4-atom-ilst+))
+;; (defun mp4-show-raw-tag-atoms (mp4-file-stream out-stream)
+;;   (declare #.utils:*standard-optimize-settings*)
+;;   (map-mp4-atom (traverse (mp4-atoms mp4-file-stream) +path-to-ilst+)
+;;                 :depth 0
+;;                 :func (lambda (atom depth)
+;;                         (when (= (atom-type atom) +itunes-ilst-data+)
+;;                           (format out-stream "~vt~a~%" depth (vpprint atom nil))))))
 
 
-(defun mp4-show-raw-tag-atoms (mp4-file-stream out-stream)
-  (declare #.utils:*standard-optimize-settings*)
-  (map-mp4-atom (traverse (mp4-atoms mp4-file-stream) +path-to-ilst+)
-                :depth 0
-                :func (lambda (atom depth)
-                        (when (= (atom-type atom) +itunes-ilst-data+)
-                          (format out-stream "~vt~a~%" depth (vpprint atom nil))))))
-
-;;; define these as constants to limit consing when get-audio-properties-atoms is called
-(defconstant +audio-prop-mdia+ (list +mp4-atom-moov+ +mp4-atom-trak+ +mp4-atom-mdia+))
-(defconstant +audio-prop-mdhd+ (list +audioprop-mdhd+))
-(defconstant +audio-prop-mp4a+ (list +mp4-atom-minf+ +mp4-atom-stbl+ +audioprop-mp4a+))
-(defconstant +audio-prop-esds+ (list +audioprop-esds+))
+;; ;;; define these as constants to limit consing when get-audio-properties-atoms is called
+;; (defconstant +audio-prop-mdia+ (list +mp4-atom-moov+ +mp4-atom-trak+ +mp4-atom-mdia+))
+;; (defconstant +audio-prop-mdhd+ (list +audioprop-mdhd+))
+;; (defconstant +audio-prop-mp4a+ (list +mp4-atom-minf+ +mp4-atom-stbl+ +audioprop-mp4a+))
+;; (defconstant +audio-prop-esds+ (list +audioprop-esds+))
 
 
 (defun get-audio-properties-atoms (mp4-file)
 (defun get-audio-properties-atoms (mp4-file)
   "Get the audio property atoms from MP4-FILE"
   "Get the audio property atoms from MP4-FILE"
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
-  (let* ((mdia       (traverse (mp4-atoms mp4-file) +audio-prop-mdia+))
-         (mdhd       (traverse mdia +audio-prop-mdhd+))
-         (audioprop1 (traverse mdia +audio-prop-mp4a+))
-         (audioprop2 (traverse audioprop1 +audio-prop-esds+)))
+  (let ((mdhd       (tree:find-tree (mp4-atoms mp4-file) (lambda (x) (= (atom-type x) +audioprop-mdhd+))))
+        (audioprop1 (tree:find-tree (mp4-atoms mp4-file) (lambda (x) (= (atom-type x) +audioprop-mp4a+))))
+        (audioprop2 (tree:find-tree (mp4-atoms mp4-file) (lambda (x) (= (atom-type x) +audioprop-esds+)))))
     (if (and mdhd audioprop1 audioprop2)
     (if (and mdhd audioprop1 audioprop2)
-        (values mdhd audioprop1 audioprop2)
+        (values (first mdhd) (first audioprop1) (first audioprop2))
         nil)))
         nil)))
 
 
 (defclass audio-info ()
 (defclass audio-info ()
@@ -616,6 +559,7 @@ call traverse atom (unless length of path == 1, in which case, we've found our m
   (:documentation "Holds extracted audio information about an MP4 file."))
   (:documentation "Holds extracted audio information about an MP4 file."))
 
 
 (defmethod vpprint ((me audio-info) stream)
 (defmethod vpprint ((me audio-info) stream)
+  (declare #.utils:*standard-optimize-settings*)
   (with-slots (seconds channels bits-per-sample sample-rate max-bit-rate avg-bit-rate) me
   (with-slots (seconds channels bits-per-sample sample-rate max-bit-rate avg-bit-rate) me
     (format stream "sample rate: ~:d Hz, # channels: ~d, bits-per-sample: ~:d, max bit-rate: ~:d Kbps, avg bit-rate: ~:d Kbps, duration: ~:d:~2,'0d"
     (format stream "sample rate: ~:d Hz, # channels: ~d, bits-per-sample: ~:d, max bit-rate: ~:d Kbps, avg bit-rate: ~:d Kbps, duration: ~:d:~2,'0d"
             (if sample-rate sample-rate 0)
             (if sample-rate sample-rate 0)
@@ -629,18 +573,19 @@ call traverse atom (unless length of path == 1, in which case, we've found our m
 (defun get-mp4-audio-info (mp4-file)
 (defun get-mp4-audio-info (mp4-file)
   "MP4A audio info is held in under the trak.mdia.mdhd/trak.mdia.minf.stbl/trak.mdia.minf.stbl.mp4a atoms."
   "MP4A audio info is held in under the trak.mdia.mdhd/trak.mdia.minf.stbl/trak.mdia.minf.stbl.mp4a atoms."
   (declare #.utils:*standard-optimize-settings*)
   (declare #.utils:*standard-optimize-settings*)
-  (let ((info (make-instance 'audio-info)))
-    (multiple-value-bind (mdhd mp4a esds) (get-audio-properties-atoms mp4-file)
-      (with-slots (seconds channels bits-per-sample sample-rate max-bit-rate avg-bit-rate) info
-        (when mdhd
-          (setf seconds (/ (float (duration mdhd)) (float (scale mdhd)))))
-        (when mp4a
-          (setf channels (num-chans mp4a)
-                bits-per-sample (samp-size mp4a))
-          (let* ((upper (ash (samp-rate mp4a) -16))
-                 (lower (logand (samp-rate mp4a) #xffff)))
-            (setf sample-rate (+ (float upper) (/ (float lower) 1000))))
-        (when esds
-          (setf avg-bit-rate (avg-bit-rate esds)
-                max-bit-rate (max-bit-rate esds))))))
-    info))
+  t)
+  ;; (let ((info (make-instance 'audio-info)))
+  ;;   (multiple-value-bind (mdhd mp4a esds) (get-audio-properties-atoms mp4-file)
+  ;;     (with-slots (seconds channels bits-per-sample sample-rate max-bit-rate avg-bit-rate) info
+  ;;       (when mdhd
+  ;;         (setf seconds (/ (float (duration mdhd)) (float (scale mdhd)))))
+  ;;       (when mp4a
+  ;;         (setf channels (num-chans mp4a)
+  ;;               bits-per-sample (samp-size mp4a))
+  ;;         (let* ((upper (ash (samp-rate mp4a) -16))
+  ;;                (lower (logand (samp-rate mp4a) #xffff)))
+  ;;           (setf sample-rate (+ (float upper) (/ (float lower) 1000))))
+  ;;       (when esds
+  ;;         (setf avg-bit-rate (avg-bit-rate esds)
+  ;;               max-bit-rate (max-bit-rate esds))))))
+  ;;   info))

+ 2 - 2
packages.lisp

@@ -44,7 +44,7 @@
 
 
 (defpackage #:mp4-atom
 (defpackage #:mp4-atom
   (:export #:mp4-atom #:map-mp4-atom #:find-mp4-atoms #:traverse #:mp4-atom-condition
   (:export #:mp4-atom #:map-mp4-atom #:find-mp4-atoms #:traverse #:mp4-atom-condition
-           #:atom-file-position #:atom-children #:atom-size #:atom-of-interest #:atom-decoded
+           #:atom-file-pos #:atom-children #:atom-size #:atom-of-interest #:atom-decoded
            #:atom-type #:vpprint #:*tag-path* #:tag-get-value #:mp4-atom-condition
            #:atom-type #:vpprint #:*tag-path* #:tag-get-value #:mp4-atom-condition
            #:mp4-show-raw-tag-atoms #:get-mp4-audio-info #:is-valid-m4-file
            #:mp4-show-raw-tag-atoms #:get-mp4-audio-info #:is-valid-m4-file
            #:+itunes-album+
            #:+itunes-album+
@@ -96,7 +96,7 @@
 
 
 
 
 (defpackage #:logging
 (defpackage #:logging
-  (:export #:with-logging)
+  (:export #:with-logging #:stop-logging)
   (:use #:common-lisp #:utils))
   (:use #:common-lisp #:utils))
 
 
 (defpackage #:mpeg
 (defpackage #:mpeg

+ 13 - 0
taglib-tests.lisp

@@ -154,3 +154,16 @@
   "Time parsing of DIR."
   "Time parsing of DIR."
   (let ((audio-streams:*get-audio-info* do-audio-processing))
   (let ((audio-streams:*get-audio-info* do-audio-processing))
     (time (mp-do-audio-dir dir :file-system-encoding file-system-encoding :func nil))))
     (time (mp-do-audio-dir dir :file-system-encoding file-system-encoding :func nil))))
+
+
+
+#|
+(defvar foo nil)
+(defun tst ()
+  (let ((*break-on-signals* t))
+    (setf foo (audio-streams:make-file-stream *song-m4a*))
+    (parse-audio-file foo)))
+
+(defun prt ()
+  (tree:traverse mp4-atom::*tree* (lambda (node depth) (format t "~v@tNode: ~a~%" depth (mp4-atom::vpprint node nil))) 1))
+|#

+ 1 - 1
tree.lisp

@@ -27,7 +27,7 @@
   "Depth-first traversal of TREE calling FUNC for each node"
   "Depth-first traversal of TREE calling FUNC for each node"
   (when tree
   (when tree
     (funcall func (data tree) depth)
     (funcall func (data tree) depth)
-    (traverse (first-child tree) func  (+ 2 depth))
+    (traverse (first-child tree) func (+ 2 depth))
     (traverse (next-sibling tree) func depth)))
     (traverse (next-sibling tree) func depth)))
 
 
 (defun print-tree (tree)
 (defun print-tree (tree)