streams.lisp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. ;;; -*- Mode: Lisp; show-trailing-whitespace: t; Base: 10; indent-tabs: nil; Syntax: ANSI-Common-Lisp; Package: STREAMS; -*-
  2. ;;; Copyright (c) 2013, Mark VandenBrink. All rights reserved.
  3. (in-package #:audio-streams)
  4. (log5:defcategory cat-log-stream)
  5. (defmacro log-stream (&rest log-stuff) `(log5:log-for (cat-log-stream) ,@log-stuff))
  6. (deftype octet () '(unsigned-byte 8))
  7. (defmacro make-octets (len) `(make-array ,len :element-type 'octet))
  8. (defclass base-stream ()
  9. ((stream :accessor stream)))
  10. (defclass base-file-stream (base-stream)
  11. ((stream-filename :accessor stream-filename)))
  12. (defclass mp3-file-stream (base-file-stream)
  13. ((mp3-header :accessor mp3-header)))
  14. (defclass mp4-file-stream (base-file-stream)
  15. ((mp4-atoms :accessor mp4-atoms :initform nil)))
  16. (defun make-file-stream (class-name filename &key (read-only t))
  17. (let ((new-stream (make-instance (find-class class-name))))
  18. (setf (stream new-stream) (if read-only
  19. (open filename :direction :input :element-type 'octet)
  20. (open filename :direction :io :if-exists :overwrite :element-type 'octet)))
  21. (setf (stream-filename new-stream) filename)
  22. new-stream))
  23. (defclass base-mem-stream (base-stream) ())
  24. (defun make-mem-stream (vector)
  25. (let ((new-stream (make-instance 'base-mem-stream)))
  26. (setf (stream new-stream) (ccl:make-vector-input-stream vector))
  27. new-stream))
  28. (defmethod stream-close ((in-stream base-file-stream))
  29. (with-slots (stream) in-stream
  30. (when stream
  31. (close stream)
  32. (setf stream nil))))
  33. (defmethod stream-close ((in-stream base-mem-stream))
  34. (with-slots (stream) in-stream
  35. (setf stream nil)))
  36. (defmethod stream-size ((in-stream base-stream))
  37. (ccl::stream-length (stream in-stream)))
  38. (defmethod stream-seek ((in-stream base-stream) offset from)
  39. (with-slots (stream) in-stream
  40. (ecase from
  41. (:start (ccl::stream-position stream offset))
  42. (:current (if (zerop offset)
  43. (ccl::stream-position stream)
  44. (ccl::stream-position stream (+ (ccl::stream-position stream) offset))))
  45. (:end (ccl::stream-position stream (- (ccl::stream-length stream) offset))))))
  46. (defun stream-read-octets (instream bytes &key (bits-per-byte 8))
  47. (loop with value = 0
  48. for low-bit downfrom (* bits-per-byte (1- bytes)) to 0 by bits-per-byte do
  49. (setf (ldb (byte bits-per-byte low-bit) value) (read-byte instream))
  50. finally (return value)))
  51. (defmethod stream-read-u8 ((in-stream base-stream) &key (bits-per-byte 8))
  52. "read 1 byte from file"
  53. (with-slots (stream) in-stream
  54. (stream-read-octets stream 1 :bits-per-byte bits-per-byte)))
  55. (defmethod stream-read-u16 ((in-stream base-stream) &key (bits-per-byte 8))
  56. "read 2 bytes from file"
  57. (with-slots (stream) in-stream
  58. (stream-read-octets stream 2 :bits-per-byte bits-per-byte)))
  59. (defmethod stream-read-u24 ((in-stream base-stream) &key (bits-per-byte 8))
  60. "read 3 bytes from file"
  61. (with-slots (stream) in-stream
  62. (stream-read-octets stream 3 :bits-per-byte bits-per-byte)))
  63. (defmethod stream-read-u32 ((in-stream base-stream) &key (bits-per-byte 8))
  64. "read 4 bytes from file"
  65. (with-slots (stream) in-stream
  66. (stream-read-octets stream 4 :bits-per-byte bits-per-byte)))
  67. ;; (defmethod stream-read-string ((stream base-stream) &key size (terminators nil))
  68. ;; "Read normal string from stream. If size is provided, read exactly that many octets.
  69. ;; If terminators is supplied, it is a list of characters that can terminate a string (and hence stop read)"
  70. ;; (with-output-to-string (s)
  71. ;; (with-slots (stream) stream
  72. ;; (let ((terminated nil)
  73. ;; (count 0)
  74. ;; (byte))
  75. ;; (loop
  76. ;; (when (if size (= count size) terminated) (return))
  77. ;; (setf byte (read-byte stream))
  78. ;; (incf count)
  79. ;; (when (member byte terminators :test #'=)
  80. ;; (setf terminated t))
  81. ;; (when (not terminated)
  82. ;; (write-char (code-char byte) s)))))))
  83. (defmethod stream-read-sequence ((stream base-stream) size &key (bits-per-byte 8))
  84. "Read SIZE octets from input-file in BIT-PER-BYTE sizes"
  85. (ecase bits-per-byte
  86. (8
  87. (let ((octets (make-octets size)))
  88. (read-sequence octets (slot-value stream 'stream))
  89. octets))
  90. (7
  91. (let* ((last-byte-was-FF nil)
  92. (byte nil)
  93. (octets (ccl:with-output-to-vector (out)
  94. (dotimes (i size)
  95. (setf byte (stream-read-u8 stream))
  96. (if last-byte-was-FF
  97. (if (not (zerop byte))
  98. (write-byte byte out))
  99. (write-byte byte out))
  100. (setf last-byte-was-FF (= byte #xFF))))))
  101. (format t "file pos is now: ~:d~%" (stream-seek stream 0 :current))
  102. (format t "length of data is ~:d~%" (length octets))
  103. octets))))
  104. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; STRINGS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  105. ;;
  106. ;; get rid of trailing nulls and blanks
  107. (defmacro trim-string (s) `(string-trim '(#\Null #\Space) ,s))
  108. ;;
  109. ;; decode octets as an iso-8859-1 string (encoding == 0)
  110. (defun stream-decode-iso-string (octets &key (start 0) (end nil))
  111. (ccl:decode-string-from-octets octets :start start :end end :external-format :iso-8859-1))
  112. ;;
  113. ;; decode octets as a ucs string (encoding == 1)
  114. ;; XXX: Coded this way because I can't seem to get a simple :external-format :ucs-2 to work correctly
  115. ;; AND some taggers encode a UCS-2 empty string w/o a byte-order mark (i.e. null strings are
  116. ;; sometimes encoded as #(00 00))
  117. (defun stream-decode-ucs-string (octets &key (start 0) (end nil))
  118. (labels ((get-byte-order-mark (octets)
  119. (let ((retval 0))
  120. (setf (ldb (byte 8 0) retval) (aref octets 1))
  121. (setf (ldb (byte 8 8) retval) (aref octets 0))
  122. (assert (or (= #xfffe retval) (= #xfeff retval)) () "decode-ucs: invalid byte order mark ~x" retval)
  123. retval)))
  124. ;; special case: empty (and mis-coded) string
  125. (cond ((zerop (length octets))
  126. (make-string 0))
  127. (t
  128. ;;
  129. ;; else, we have a (hopefully) properly encoded string
  130. (let ((bom (get-byte-order-mark octets)))
  131. (ecase (the fixnum bom)
  132. (#xfffe (ccl:decode-string-from-octets octets :start (+ 2 start) :end end :external-format :ucs-2le))
  133. (#xfeff (ccl:decode-string-from-octets octets :start (+ 2 start) :end end :external-format :ucs-2be))
  134. (0 (make-string 0))))))))
  135. ;;
  136. ;; decode octets as a ucs-be string (encoding == 2)
  137. (defun stream-decode-ucs-be-string (octets &key (start 0) (end nil))
  138. (ccl:decode-string-from-octets octets :start start :end end :external-format :ucs-2be))
  139. ;;
  140. ;; decode octets as a utf-8 string
  141. (defun stream-decode-utf-8-string (octets &key (start 0) (end nil))
  142. (ccl:decode-string-from-octets octets :start start :end end :external-format :utf-8))
  143. ;;
  144. ;; decode octets depending on encoding
  145. (defun stream-decode-string (octets &key (start 0) (end nil) (encoding 0))
  146. (ecase encoding
  147. (0 (stream-decode-iso-string octets :start start :end end))
  148. (1 (stream-decode-ucs-string octets :start start :end end))
  149. (2 (stream-decode-ucs-be-string octets :start start :end end))
  150. (3 (stream-decode-utf-8-string octets :start start :end end))))
  151. ;;
  152. ;; read an iso-8859-1 string of length 'len' (encoding = 0)
  153. (defmethod stream-read-iso-string-with-len ((instream base-stream) len)
  154. (let ((octets (stream-read-sequence instream len)))
  155. (stream-decode-iso-string octets)))
  156. ;;
  157. ;; read an ucs-2 string of length 'len' (encoding = 1)
  158. (defmethod stream-read-ucs-string-with-len ((instream base-stream) len)
  159. (let ((octets (stream-read-sequence instream len)))
  160. (stream-decode-ucs-string octets)))
  161. ;;
  162. ;; read an ucs-2-be string of length 'len' (encoding = 2)
  163. (defmethod stream-read-ucs-be-string-with-len ((instream base-stream) len)
  164. (let ((octets (stream-read-sequence instream len)))
  165. (stream-decode-ucs-be-string octets)))
  166. ;;
  167. ;; read an utf-8 string of length 'len' (encoding = 3)
  168. (defmethod stream-read-utf-8-string-with-len ((instream base-stream) len)
  169. (let ((octets (stream-read-sequence instream len)))
  170. (stream-decode-utf-8-string octets)))
  171. ;;
  172. ;; Read in a string of a given encoding of length 'len'
  173. (defmethod stream-read-string-with-len ((instream base-stream) len &key (encoding 0))
  174. ;(format t "s-wth-len: ~a, ~d, ~d~%" instream len encoding)
  175. (ecase encoding
  176. (0 (stream-read-iso-string-with-len instream len))
  177. (1 (stream-read-ucs-string-with-len instream len))
  178. (2 (stream-read-ucs-be-string-with-len instream len))
  179. (3 (stream-read-utf-8-string-with-len instream len))))
  180. ;;
  181. ;; Read in a null terminated iso-8859-1 string
  182. (defmethod stream-read-iso-string ((instream base-stream))
  183. (let ((octets (ccl:with-output-to-vector (out)
  184. (do ((b (stream-read-u8 instream) (stream-read-u8 instream)))
  185. (nil)
  186. (when (zerop b)
  187. (return)) ; leave loop w/o writing
  188. (write-byte b out)))))
  189. (stream-decode-iso-string octets)))
  190. ;;
  191. ;; Read in a null terminated ucs string
  192. (defmethod stream-read-ucs-string ((instream base-stream))
  193. (let ((octets (ccl:with-output-to-vector (out)
  194. (do* ((b0 (stream-read-u8 instream)
  195. (stream-read-u8 instream))
  196. (b1 (stream-read-u8 instream)
  197. (stream-read-u8 instream)))
  198. (nil)
  199. (when (and (zerop b0) (zerop b1))
  200. (return))
  201. (write-byte b0 out)
  202. (write-byte b1 out)))))
  203. (stream-decode-ucs-string octets)))
  204. ;;
  205. ;; Read in a null terminated ucs-be string
  206. (defmethod stream-read-ucs-be-string ((instream base-stream))
  207. (let ((octets (ccl:with-output-to-vector (out)
  208. (do* ((b0 (stream-read-u8 instream)
  209. (stream-read-u8 instream))
  210. (b1 (stream-read-u8 instream)
  211. (stream-read-u8 instream)))
  212. (nil)
  213. (when (and (zerop b0) (zerop b1))
  214. (return))
  215. (write-byte b0 out)
  216. (write-byte b1 out)))))
  217. (stream-decode-ucs-be-string octets)))
  218. ;;
  219. ;; Read in a null terminated utf-8 string (encoding == 3)
  220. (defmethod stream-read-utf-8-string ((instream base-stream))
  221. (let ((octets (ccl:with-output-to-vector (out)
  222. (do ((b (stream-read-u8 instream)
  223. (stream-read-u8 instream)))
  224. (nil)
  225. (when (zerop b)
  226. (return))
  227. (write-byte b out)))))
  228. (stream-decode-utf-8-string octets)))
  229. ;;
  230. ;; Read in a null terminated string of a given encoding
  231. (defmethod stream-read-string ((instream base-stream) &key (encoding 0))
  232. (ecase encoding
  233. (0 (stream-read-iso-string instream))
  234. (1 (stream-read-ucs-string instream))
  235. (2 (stream-read-ucs-be-string instream))
  236. (3 (stream-read-utf-8-string instream))))
  237. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; FILES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  238. (defun parse-mp4-file (filename)
  239. (let (stream)
  240. (handler-case
  241. (progn
  242. (setf stream (make-file-stream 'mp4-file-stream filename))
  243. (mp4-atom:find-mp4-atoms stream))
  244. (mp4-atom:mp4-atom-condition (c)
  245. (warn "make-mp4-stream got condition: ~a" c)
  246. (when stream (stream-close stream))
  247. (setf stream nil)))
  248. stream))
  249. (defun parse-mp3-file (filename)
  250. (let (stream)
  251. (handler-case
  252. (progn
  253. (setf stream (make-file-stream 'mp3-file-stream filename))
  254. (mp3-frame:find-mp3-frames stream))
  255. (mp3-frame:mp3-frame-condition (c)
  256. (warn "make-mp3-stream got condition: ~a" c)
  257. (when stream (stream-close stream))
  258. (setf stream nil)))
  259. stream))