Projets d'informatique musicale
Licence-Maîtrise d'informatique - Université de Caen
Marc Chemillier
;;; ===================================
;;; Liremidifile.lisp / 26 octobre 1998
;;; ===================================
;;; GRAMMAIRE REGULIERE:
;;; ====================
;;; header chunk = 14 octets
;;; track chunk = entete ( deltatime evenement )*
;;; entete = 8 octets
;;; deltatime = ( octet1 )* octet0
;;; evenement = note ou meta-evenement
;;; note = #x90 ou #x80 + 2 octets
;;; meta-evenement = signature ou tempo ou end-of-track
;;; signature = #xFF #x58 + 4 octets
;;; tempo = #xFF #x51 + 3 octets
;;; end-of-track = #xFF #x2F + 1 octet
;;; EXEMPLE:
;;; ((4D 54 68 64 0 0 0 6 0 1 0 4 0 60) ;;; M T h d + entete
;;; (4D 54 72 6B 0 0 0 2C) ;;; M T r k + entete
;;; (0 FF 58 4 4 2 18 8) ;;; signature
;;; (0 FF 51 3 7 A1 20) ;;; tempo
;;; (0 90 3C 3C) (60 80 3C 0) ;;; do3
;;; (0 90 3E 3C) (60 80 3E 0) ;;; re3
;;; (0 90 40 3C) (81 40 80 40 0) ;;; mi3
;;; (0 FF 2F 0)) Midifile accepté
;;; Chaque fonction de lecture ramene
;;; un booleen nil si fin de fichier et t sinon,
;;; une liste d'octets lus par la fonction
(setq resultat " Midifile accepté")
(defun lecture-midifile (fich)
(setq resultat " Midifile non reconnu")
(with-open-file (flot fich :direction :input)
(let* ((res1 (lecture-header-chunk flot))
(bool (car res1)))
(when bool
(let ((res2 (lecture-track-chunk flot)))
(write (cons (cadr res1) (cadr res2)) :base 16)
(format t resultat))))))
(defun lecture-header-chunk (flot) (lire-n-octets 14 flot))
(defun lecture-track-chunk (flot)
(let* ((res1 (lecture-entete-track-chunk flot))
(bool (car res1))
(res-notes ()))
(until (not bool)
(let ((res2* (lecture-evenement-track-chunk flot)))
(setq bool (car res2*))
(when bool (push (cadr res2*) res-notes))))
(list bool (cons (cadr res1) (reverse res-notes)))))
(defun lecture-entete-track-chunk (flot) (lire-n-octets 8 flot))
(defun lecture-evenement-track-chunk (flot)
(let* ((res1 (lecture-deltatime flot))
(bool (car res1)))
(when bool
(let ((res2 (lecture-evenement flot)))
(setq bool (car res2))
(list bool (append (cadr res1) (cadr res2)))))))
(defun lecture-deltatime (flot)
(let* ((octet (read-octet flot ()))
(res (list octet)))
(when (not octet) (setq resultat " Midifile accepté")) ;;; ETAT TERMINAL
(until (or (not octet) (< octet #x80))
(setq octet (read-octet flot ()))
(push octet res))
(list octet (reverse res))))
(defun lecture-evenement (flot)
(let ((statut (read-octet flot ())))
(cond ((= statut #xFF) (lecture-meta-evenement flot))
((or (= statut #x90) (= statut #x80)) (lecture-note statut flot)))))
(defun lecture-note (statut flot)
(let ((res (lire-n-octets 2 flot)))
(list (car res) (cons statut (cadr res)))))
(defun lecture-meta-evenement (flot)
(let ((type (read-octet flot ())))
(case type
(#x58 (let ((res (lire-n-octets 5 flot))) ;;; signature
(list (car res) (append (list #xFF #x58) (cadr res)))))
(#x51 (let ((res (lire-n-octets 4 flot))) ;;; tempo
(list (car res) (append (list #xFF #x51) (cadr res)))))
(#x2F (let ((res (lire-n-octets 1 flot))) ;;; end-of-track
(list (car res) (append (list #xFF #x2F) (cadr res))))))))
;;; Lecture des n premiers octets dans le flot:
(defun lire-n-octets (n flot)
(let* ((octet (read-octet flot ()))
(res (list octet)))
(do ((i n (- i 1)))
((or (= i 1) (not octet)) (list octet (reverse res)))
(setq octet (read-octet flot ()))
(push octet res))))
;;; Ascii: (char-code #\a) = 97, (code-char 97) = #\a
(defun read-octet (flot bool)
(let ((x (read-char flot bool)))
(if (not x) x (char-code x))))