<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://wiki.kram.nz/index.php?action=history&amp;feed=atom&amp;title=SE701%3AApril_11</id>
	<title>SE701:April 11 - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.kram.nz/index.php?action=history&amp;feed=atom&amp;title=SE701%3AApril_11"/>
	<link rel="alternate" type="text/html" href="https://wiki.kram.nz/index.php?title=SE701:April_11&amp;action=history"/>
	<updated>2026-04-29T07:22:26Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.3</generator>
	<entry>
		<id>https://wiki.kram.nz/index.php?title=SE701:April_11&amp;diff=12290&amp;oldid=prev</id>
		<title>Mark: 1 revision(s)</title>
		<link rel="alternate" type="text/html" href="https://wiki.kram.nz/index.php?title=SE701:April_11&amp;diff=12290&amp;oldid=prev"/>
		<updated>2008-11-03T05:27:41Z</updated>

		<summary type="html">&lt;p&gt;1 revision(s)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt; ;;; File:    music.lisp&lt;br /&gt;
 ;;; Author:  John Hamer&lt;br /&gt;
 ;;; Date:    11 April 2008&lt;br /&gt;
 ;;; Purpose: Illustrate Common Lisp generic functions and classes&lt;br /&gt;
 &lt;br /&gt;
 (defclass music () ())&lt;br /&gt;
 &lt;br /&gt;
 (defgeneric duration (music))&lt;br /&gt;
 &lt;br /&gt;
 ;; A single note&lt;br /&gt;
 (defclass note (music)&lt;br /&gt;
   ((key     :initarg :key&lt;br /&gt;
 	     :initform (error &amp;quot;Must specify the note key&amp;quot;)&lt;br /&gt;
 	     :reader note-key)&lt;br /&gt;
    (duration :initarg :duration&lt;br /&gt;
 	     :initform (error &amp;quot;Must specify the note duration&amp;quot;)&lt;br /&gt;
 	     :reader duration)))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 ;; Silence&lt;br /&gt;
 (defclass music-rest (music)&lt;br /&gt;
   ((duration :initarg :duration :initform 0 :reader duration)))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 ;; Sequential and parallel composition   &lt;br /&gt;
 (defclass music-composite (music)&lt;br /&gt;
   ((terms :initarg :terms :reader music-terms)))&lt;br /&gt;
 &lt;br /&gt;
 (defclass par (music-composite) ())&lt;br /&gt;
 (defclass seq (music-composite) ())&lt;br /&gt;
 &lt;br /&gt;
 (defmethod duration ((m seq))&lt;br /&gt;
   (reduce #&amp;#039;+ (music-terms m) :key #&amp;#039;duration))&lt;br /&gt;
 (defmethod duration ((m par))&lt;br /&gt;
   (reduce #&amp;#039;max (music-terms m) :key #&amp;#039;duration))&lt;br /&gt;
 &lt;br /&gt;
 (defun seq (&amp;amp;rest terms)&lt;br /&gt;
   (make-instance &amp;#039;seq :terms (collect-all-terms terms)))&lt;br /&gt;
 (defun par (&amp;amp;rest terms)&lt;br /&gt;
   (make-instance &amp;#039;par :terms (collect-all-terms terms)))&lt;br /&gt;
 &lt;br /&gt;
 (defgeneric collect-terms (terms result))&lt;br /&gt;
 &lt;br /&gt;
 (defmethod collect-terms ((terms list) result)&lt;br /&gt;
   (mapcar #&amp;#039;(lambda (term) (collect-terms term result)) terms))&lt;br /&gt;
 (defmethod collect-terms ((terms vector) result)&lt;br /&gt;
   (loop for term across terms&lt;br /&gt;
      do (collect-terms term result)))&lt;br /&gt;
 (defmethod collect-terms ((term t) result)&lt;br /&gt;
   (vector-push-extend term result))&lt;br /&gt;
 &lt;br /&gt;
 (defun collect-all-terms (terms)&lt;br /&gt;
   (let ((result (make-array 5 :fill-pointer 0 :adjustable t)))&lt;br /&gt;
     (collect-terms terms result)&lt;br /&gt;
     result))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 ;;; Musical decorators&lt;br /&gt;
 &lt;br /&gt;
 (defclass music-decorator (music)&lt;br /&gt;
   ((term :initarg :term&lt;br /&gt;
 	 :initform (error &amp;quot;Must specify the music term&amp;quot;)&lt;br /&gt;
 	 :reader music-term)))&lt;br /&gt;
 &lt;br /&gt;
 (defmethod duration ((m music-decorator))&lt;br /&gt;
   (duration (music-term m)))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 ;; Tempo&lt;br /&gt;
 (defclass music-tempo (music-decorator)&lt;br /&gt;
   ((tempo :initarg :tempo :reader music-tempo)))&lt;br /&gt;
 &lt;br /&gt;
 (defmethod duration ((m music-tempo))&lt;br /&gt;
   (* (duration (music-term m)) (music-tempo m)))&lt;br /&gt;
 &lt;br /&gt;
 (defun change-tempo (m r)&lt;br /&gt;
   (make-instance &amp;#039;music-tempo :term m :tempo r))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 ;; Transpose&lt;br /&gt;
 (defclass music-transpose (music-decorator)&lt;br /&gt;
   ((transpose :initarg :transpose :reader music-transpose)))&lt;br /&gt;
 &lt;br /&gt;
 (defun transpose (m d)&lt;br /&gt;
   (make-instance &amp;#039;music-transpose :term m :transpose d))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 ;; Instrument&lt;br /&gt;
 (defclass music-instrument (music-decorator)&lt;br /&gt;
   ((instrument :initarg :instrument :reader instrument)))&lt;br /&gt;
 &lt;br /&gt;
 (defun use-instrument (m i)&lt;br /&gt;
   (make-instance &amp;#039;instr :term m :instrument i))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 ;; Phrase&lt;br /&gt;
 (defclass music-phrase (music-decorator)&lt;br /&gt;
   ((phrase :initarg :phrase :reader music-phrase)))&lt;br /&gt;
 &lt;br /&gt;
 (defun phrasing (m p)&lt;br /&gt;
   (make-instance &amp;#039;phrase :term m :phrase p))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 ;;; Musical performance&lt;br /&gt;
 &lt;br /&gt;
 (defparameter *current-time* 0)&lt;br /&gt;
 (defparameter *current-tempo* 1)&lt;br /&gt;
 (defparameter *current-transpose* 0)&lt;br /&gt;
 (defparameter *current-instrument* &amp;quot;piano&amp;quot;)&lt;br /&gt;
 (defparameter *current-volume* 100)&lt;br /&gt;
 &lt;br /&gt;
 (defclass Event ()&lt;br /&gt;
   ((time    :initarg :time :reader event-time)&lt;br /&gt;
    (key     :initarg :key)&lt;br /&gt;
    (length  :initarg :length)&lt;br /&gt;
    (instr   :initarg :instr)&lt;br /&gt;
    (volume  :initarg :volume)))&lt;br /&gt;
 &lt;br /&gt;
 (defmethod print-object ((e Event) stream)&lt;br /&gt;
   (with-slots (time key length instr volume) e&lt;br /&gt;
     (format stream &amp;quot;#[Event :time ~a :key ~a :length ~a :instr ~a :volume ~a]&amp;quot;&lt;br /&gt;
             time key length instr volume)))&lt;br /&gt;
 &lt;br /&gt;
 (defun mkEvent (time k l i v)&lt;br /&gt;
   (make-instance &amp;#039;Event :time time :key k :length l :instr i :volume v))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 (defun do-perform (music)&lt;br /&gt;
   (let ((events (make-array 0 :adjustable t :fill-pointer t)))&lt;br /&gt;
     (perform music 0 events)&lt;br /&gt;
     (sort events #&amp;lt; :key #&amp;#039;event-time)&lt;br /&gt;
     events))&lt;br /&gt;
 &lt;br /&gt;
 (defgeneric perform (music time events))&lt;br /&gt;
 &lt;br /&gt;
 (defmethod perform ((m note) time events)&lt;br /&gt;
   (with-slots (key duration) m&lt;br /&gt;
     (vector-push-extend (mkEvent time&lt;br /&gt;
 				 (+ key *current-transpose*)&lt;br /&gt;
 				 (* duration *current-tempo*)&lt;br /&gt;
 				 *current-instrument*&lt;br /&gt;
 				 *current-volume*)&lt;br /&gt;
 			events)&lt;br /&gt;
     duration))&lt;br /&gt;
 &lt;br /&gt;
 (defmethod perform ((m music-rest) time events)&lt;br /&gt;
   (duration m))&lt;br /&gt;
 &lt;br /&gt;
 (defmethod perform ((m seq) time events)&lt;br /&gt;
   (let ((dur 0))&lt;br /&gt;
     (loop for mt across (music-terms m)&lt;br /&gt;
        do (incf dur (perform mt (+ time dur) events)))&lt;br /&gt;
     dur))&lt;br /&gt;
 &lt;br /&gt;
 (defmethod perform ((m par) time events)&lt;br /&gt;
   (let ((dur 0))&lt;br /&gt;
     (loop for e across (music-terms m)&lt;br /&gt;
        do (setf dur (max dur (perform e time events))))&lt;br /&gt;
     dur))&lt;br /&gt;
 &lt;br /&gt;
 (defmethod perform ((m music-tempo) time events)&lt;br /&gt;
   (let ((*current-tempo* (* *current-tempo* (music-tempo m))))&lt;br /&gt;
     (perform (music-term m) time events)))&lt;br /&gt;
   &lt;br /&gt;
 (defmethod perform ((m music-instrument) time events)&lt;br /&gt;
   (let ((*current-instrument* (instrument m)))&lt;br /&gt;
     (perform (music-term m) time events)))&lt;br /&gt;
   &lt;br /&gt;
 &lt;br /&gt;
 ;;; Retro&lt;br /&gt;
 (defgeneric retro (music)&lt;br /&gt;
   (:documentation &amp;quot;MUSIC played backwards&amp;quot;))&lt;br /&gt;
 &lt;br /&gt;
 (defmethod retro ((m music))&lt;br /&gt;
   m)&lt;br /&gt;
 (defmethod retro ((p par))&lt;br /&gt;
   (par (mapcar #&amp;#039;retro (music-terms p))))&lt;br /&gt;
 (defmethod retro ((s seq))&lt;br /&gt;
   (seq (nreverse (mapcar #&amp;#039;retro (music-terms s)))))&lt;br /&gt;
 (defmethod retro ((m music-tempo))&lt;br /&gt;
   (change-tempo (retro (music-term m)) (music-tempo m)))&lt;br /&gt;
 (defmethod retro ((m music-transpose))&lt;br /&gt;
   (transpose (retro (music-term m)) (music-transpose m)))&lt;br /&gt;
 (defmethod retro ((m music-instrument))&lt;br /&gt;
   (use-instrument (retro (music-term m)) (instrument m)))&lt;br /&gt;
 (defmethod retro ((m music-phrase))&lt;br /&gt;
   (phrasing (retro (music-term m)) (music-phrase m)))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 ;;; Reading and writing&lt;br /&gt;
 &lt;br /&gt;
 ;; Print using initialize-instance syntax: &amp;quot;#[type init-args]&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 (defun read-music-object (stream char n)&lt;br /&gt;
   (declare (ignore char n))&lt;br /&gt;
   (apply #&amp;#039;make-instance (read stream t) (read-delimited-list #\] stream t)))&lt;br /&gt;
 &lt;br /&gt;
 (set-syntax-from-char #\] #\))&lt;br /&gt;
 (set-dispatch-macro-character #\# #\[ #&amp;#039;read-music-object)&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 (defmethod print-object ((obj note) stream)&lt;br /&gt;
   (with-slots (key duration) obj&lt;br /&gt;
     (format stream &amp;quot;#[note :key ~a :duration ~a]&amp;quot; key duration)))&lt;br /&gt;
 &lt;br /&gt;
 (defmethod print-object ((obj music-rest) stream)&lt;br /&gt;
   (with-slots (duration) obj&lt;br /&gt;
     (format stream &amp;quot;#[music-rest :duration ~a]&amp;quot; duration)))&lt;br /&gt;
 &lt;br /&gt;
 (defmethod print-object ((obj music-composite) stream)&lt;br /&gt;
   (with-slots (terms) obj&lt;br /&gt;
     (format stream &amp;quot;#[~a :terms ~a]&amp;quot; (type-of obj) terms)))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 (defgeneric print-decoration (music-decorator stream))&lt;br /&gt;
 &lt;br /&gt;
 (defmethod print-object ((obj music-decorator) stream)&lt;br /&gt;
   (format stream &amp;quot;#[~a :term ~a &amp;quot; (type-of obj) (music-term obj))&lt;br /&gt;
   (print-decoration obj stream)&lt;br /&gt;
   (format stream &amp;quot;]&amp;quot;))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 (defmethod print-decoration ((obj music-tempo) stream)&lt;br /&gt;
   (format stream &amp;quot;:tempo ~a&amp;quot; (music-tempo obj)))&lt;br /&gt;
 (defmethod print-decoration ((obj music-transpose) stream)&lt;br /&gt;
   (format stream &amp;quot;:transpose ~a&amp;quot; (music-transpose obj)))&lt;br /&gt;
 (defmethod print-decoration ((obj music-instrument) stream)&lt;br /&gt;
   (format stream &amp;quot;:instr ~a&amp;quot; (instrument obj)))&lt;br /&gt;
 (defmethod print-decoration ((obj music-phrase) stream)&lt;br /&gt;
   (format stream &amp;quot;:phrase ~a&amp;quot; (music-phrase obj)))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 (defun key-code (name)&lt;br /&gt;
   (ccase name&lt;br /&gt;
     (:A 0)&lt;br /&gt;
     ((:As :Bf) 1)&lt;br /&gt;
     (:B 2)&lt;br /&gt;
     (:C 3)&lt;br /&gt;
     ((:Cs :Df) 4)&lt;br /&gt;
     (:D 5)&lt;br /&gt;
     ((:Ds :Ef) 6)&lt;br /&gt;
     (:E 7)&lt;br /&gt;
     (:F 8)&lt;br /&gt;
     ((:Fs :Gf) 9)&lt;br /&gt;
     (:G 10)&lt;br /&gt;
     ((:Gs :Af) 11)))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 (defun note (name octave duration)&lt;br /&gt;
   (make-instance &amp;#039;note :key (+ (* octave 12) (key-code name)) :duration duration))&lt;br /&gt;
 &lt;br /&gt;
 (defun repeat (n mus)&lt;br /&gt;
   (seq (make-array n :initial-element mus)))&lt;br /&gt;
 &lt;br /&gt;
 ;;; Example&lt;br /&gt;
 (defvar *three-blind-mice*&lt;br /&gt;
   (let* ((qn 1/4)&lt;br /&gt;
          (en 1/8)&lt;br /&gt;
          (en3 3/8)&lt;br /&gt;
          (en6 6/8)&lt;br /&gt;
          (qnr (make-instance &amp;#039;music-rest :duration qn))&lt;br /&gt;
          (t1 (seq (note :D 4 en3) (note :C 4 en3) (note :Bf 3 en6)))&lt;br /&gt;
          (t2 (seq (note :F 4 en3) (note :Ef 4 qn) (note :Ef 4 en)))&lt;br /&gt;
          (t3 (seq (note :F 4 en)  (note :Bf 4 qn) (note :Bf 4 en) (note :A 4 en) (note :G 4 en) (note :A 4 en) (note :Bf 4 qn) (note :F 4 en) (note :F 4 qn))))&lt;br /&gt;
     (seq (repeat 2 t1)&lt;br /&gt;
          t2 (note :D 4 en6)&lt;br /&gt;
          t2 (note :D 4 en3)&lt;br /&gt;
          qnr&lt;br /&gt;
          (repeat 3 t3)&lt;br /&gt;
          (note :Ef 4 en) t1)))&lt;/div&gt;</summary>
		<author><name>Mark</name></author>
	</entry>
</feed>