taglib-tests.lisp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. ;;; -*- Mode: Lisp; show-trailing-whitespace: t; Base: 10; indent-tabs: nil; Syntax: ANSI-Common-Lisp; Package: TAGLIB-TESTS; -*-
  2. ;;; Copyright (c) 2013, Mark VandenBrink. All rights reserved.
  3. (in-package #:cl-user)
  4. (defpackage #:taglib-tests
  5. (:use #:common-lisp #:logging #:audio-streams))
  6. (in-package #:taglib-tests)
  7. ;;; some convenient songs to parse
  8. (defparameter *song-m4a* "Queen/Queen I/01 Keep Yourself Alive.m4a")
  9. (defparameter *song-mp3* "Queen/Sheer Heart Attack/07 In The Lap Of The Gods.mp3")
  10. ;;;
  11. ;;; Set the pathname (aka filename) encoding in CCL for appropriate platorm
  12. (defun set-pathname-encoding (enc) (setf (ccl:pathname-encoding-name) enc))
  13. (defun set-pathname-encoding-for-osx () (set-pathname-encoding :utf-8))
  14. (defun set-pathname-encoding-for-linux () (set-pathname-encoding nil))
  15. ;;; A note re filesystem encoding: my music collection is housed on a Mac and shared via SAMBA.
  16. ;;; In order to make sure we get valid pathnames, we need to set CCL's filesystem encoding to
  17. ;;; :UTF-8
  18. (defun do-audio-file (&optional (file *song-m4a*) &key (func (constantly t)))
  19. "Parse one audio file (with condition handling)."
  20. (let ((foo))
  21. (unwind-protect
  22. (handler-case
  23. (progn
  24. (setf foo (make-file-stream file))
  25. (when foo
  26. (parse-audio-file foo)) ; only call parse-audio if we got back a MP3/M4A
  27. (funcall func foo)) ; call func even is foo is null so it can account for non MP3/M4A files
  28. (condition (c)
  29. (utils:warn-user "File: ~a~%Got condition: <~a>" file c)))
  30. (when foo
  31. (stream-close foo)))))
  32. (defun do-audio-dir (&optional (dir "Queen") &key (file-system-encoding :utf-8)
  33. (mp3-func #'mp3-tag:show-tags)
  34. (mp4-func #'mp4-tag:show-tags))
  35. "Walk :DIR and FUNCALL specified function for each file (MP4/MP3) found."
  36. (set-pathname-encoding file-system-encoding)
  37. (let ((mp3-count 0)
  38. (mp4-count 0)
  39. (other-count 0))
  40. (cl-fad:walk-directory dir (lambda (f)
  41. (do-audio-file f :func (lambda (s)
  42. (cond ((typep s 'mp3-file-stream)
  43. (incf mp3-count)
  44. (when mp3-func
  45. (funcall mp3-func s)))
  46. ((typep s 'mp4-file-stream)
  47. (incf mp4-count)
  48. (when mp4-func
  49. (funcall mp4-func s)))
  50. ((null s) (incf other-count)))))))
  51. (format t "~&~:d MP3s, ~:d MP4s, ~:d Others, for a total of ~:d~%"
  52. mp3-count mp4-count other-count (+ mp3-count mp4-count other-count))))
  53. (defun time-test (&optional (dir "Queen") &key (file-system-encoding :utf-8) (do-audio-processing t))
  54. "Time parsing of DIR."
  55. (let ((audio-streams:*get-audio-info* do-audio-processing))
  56. (time (do-audio-dir dir :file-system-encoding file-system-encoding :mp3-func nil :mp4-func nil))))
  57. ;;;;;;;;;;;;;;;;;;;; Experimental multi-thread code below ;;;;;;;;;;;;;;;;;;;;
  58. (defparameter *channel* nil)
  59. (defparameter *dead-channel* nil)
  60. (defparameter *END-THREAD* #xdeadbeef)
  61. (defparameter *MAX-THREADS* 4)
  62. (defun mp-do-audio-dir (&optional (dir "Queen") &key (file-system-encoding :utf-8)
  63. (mp3-func #'mp3-tag:show-tags)
  64. (mp4-func #'mp4-tag:show-tags))
  65. "Walk :DIR and FUNCALL specified function for each file (MP4/MP3) found."
  66. (set-pathname-encoding file-system-encoding)
  67. (let ((mp3-count 0)
  68. (mp4-count 0)
  69. (other-count 0))
  70. (setf *channel* (make-instance 'chanl:unbounded-channel))
  71. (setf *dead-channel* (make-instance 'chanl:unbounded-channel))
  72. (labels ((thread-reader ()
  73. (let ((me (chanl:thread-name (chanl:current-thread)))
  74. (f))
  75. ;(format t "Thread ~a starting~%" me)
  76. (loop
  77. (setf f (chanl:recv *channel*))
  78. ;(format t "Thread ~a read: ~a~%" me f)
  79. (when (and (typep f 'integer)
  80. (= f *END-THREAD*))
  81. ;(format t "Thread ~a exiting~%" me)
  82. (chanl:send *dead-channel* me)
  83. (return-from thread-reader nil))
  84. (do-audio-file f)))))
  85. (cl-fad:walk-directory dir (lambda (f)
  86. (chanl:send *channel* f)))
  87. (dotimes (i *MAX-THREADS*)
  88. (chanl:send *channel* *END-THREAD*))
  89. (dotimes (i *MAX-THREADS*)
  90. (chanl:pcall #'thread-reader :name (format nil "reader-thread-~d" i)))
  91. (block thread-reap
  92. (let ((i 0))
  93. (loop
  94. (format t "Waiting on ~d threads~%" *MAX-THREADS*)
  95. (format t "~a died~%" (chanl:recv *dead-channel*))
  96. (incf i)
  97. (when (= i *MAX-THREADS*)
  98. (return-from thread-reap *MAX-THREADS*)))))
  99. (format t "All threads done~%"))))
  100. ;; (do-audio-file f :func (lambda (s)
  101. ;; (cond ((typep s 'mp3-file-stream)
  102. ;; (incf mp3-count)
  103. ;; (when mp3-func
  104. ;; (funcall mp3-func s)))
  105. ;; ((typep s 'mp4-file-stream)
  106. ;; (incf mp4-count)
  107. ;; (when mp4-func
  108. ;; (funcall mp4-func s)))
  109. ;; ((null s) (incf other-count)))))))
  110. ;; (format t "~&~:d MP3s, ~:d MP4s, ~:d Others, for a total of ~:d~%"
  111. ;; mp3-count mp4-count other-count (+ mp3-count mp4-count other-count))))
  112. (defun mp-time-test (&optional (dir "Queen") &key (file-system-encoding :utf-8) (do-audio-processing t))
  113. "Time parsing of DIR."
  114. (let ((audio-streams:*get-audio-info* do-audio-processing))
  115. (time (mp-do-audio-dir dir :file-system-encoding file-system-encoding :mp3-func nil :mp4-func nil))))