Coverage report: /home/ellis/comp/core/lib/dat/id3.lisp

KindCoveredAll%
expression087 0.0
branch00nil
Key
Not instrumented
Conditionalized out
Executed
Not executed
 
Both branches taken
One branch taken
Neither branch taken
1
 ;;; id3.lisp --- ID3 Metadata
2
 
3
 ;; ID3 Metadata container serialization
4
 
5
 ;;; Commentary:
6
 
7
 ;; https://en.wikipedia.org/wiki/ID3
8
 
9
 #| 
10
 ID3 is a metadata container most often used in conjunction with the MP3 audio
11
 file format. It allows information such as the title, artist, album, track
12
 number, and other information about the file to be stored in the file itself.
13
 
14
 ID3 is a de facto standard for metadata in MP3 files; no standardization body
15
 was involved in its creation nor has such an organization given it a formal
16
 approval status.
17
 |#
18
 ;;; Code:
19
 (in-package :dat/id3)
20
 
21
 (defun mp3-p (file)
22
   (string-equal "mp3" (pathname-type file)))
23
 
24
 ;; (simple-array (unsigned-byte 7) (4))
25
 (deftype u28 () '(unsigned-byte 28))
26
 
27
 (defstruct id3-header 
28
   (version 0 :type octet) 
29
   (revision 0 :type octet)
30
   (flags 0 :type octet)
31
   (size 0 :type u28))
32
 
33
 (define-constant +id3-magic+ #(73 68 51) :test 'equalp)
34
 
35
 ;; FIX 2025-02-07: 
36
 (defun decode-u28 (bytes)
37
   "Decode a sequence of 7-bit bytes as an ID3-compliant unsigned 28-bit integer."
38
   (declare ((array (unsigned-byte 7)) bytes))
39
   (octets-to-integer bytes))
40
 
41
 (defun read-id3-header (file)
42
   (with-open-file (in file :element-type '(unsigned-byte 8))
43
     (let ((magic (make-octets 3)))
44
       (read-sequence magic in)
45
       (assert (equalp magic +id3-magic+)))
46
     (let ((header (make-id3-header 
47
                    :version (read-byte in) 
48
                    :revision (read-byte in)
49
                    :flags (read-byte in))))
50
       (let ((size (make-array 4 :element-type '(unsigned-byte 7))))
51
         (read-sequence size in)
52
         (setf (id3-header-size header) (decode-u28 size))
53
         header))))
54
 
55
 ;; (read-id3-header "/mnt/z/music/05 - Clear.mp3")
56
 
57
 (defun show-id3-header (file)
58
   (with-slots (major-version revision flags size) (read-id3-header file)
59
     (format t "ID3 ~d.~d ~8,'0b ~d bytes -- ~a~%"
60
             major-version revision flags size (enough-namestring file))))
61
 
62
 (defun show-id3-headers (dir) 
63
   (std/path:walk-directory dir #'mp3-p (constantly t) #'show-id3-header))
64
 
65
 (defun id3-p (file)
66
   (with-open-file (in file :element-type '(unsigned-byte 8))
67
     (let ((magic (make-octets 3)))
68
       (read-sequence magic in)
69
       (equalp magic +id3-magic+))))
70
 
71
 (defclass id3-frame (id)
72
   (data size))
73
 
74
 (defun find-id3-frame-class (id)
75
   (declare (ignore id))
76
   'id3-frame)