[gsharp-cvs] CVS gsharp

rstrandh rstrandh at common-lisp.net
Mon Oct 22 11:45:37 UTC 2007


Update of /project/gsharp/cvsroot/gsharp
In directory clnet:/tmp/cvs-serv25693

Modified Files:
	buffer.lisp gsharp.asd 
Added Files:
	melody.lisp 
Log Message:
I moved melody-related functionality from buffer.lisp to a new file. 


--- /project/gsharp/cvsroot/gsharp/buffer.lisp	2007/10/22 10:03:40	1.56
+++ /project/gsharp/cvsroot/gsharp/buffer.lisp	2007/10/22 11:45:36	1.57
@@ -33,6 +33,8 @@
       (save-object obj stream)
       (print-unreadable-object (obj stream :type t :identity t))))
 
+(define-condition gsharp-condition (error) ())
+
 (defgeneric name (obj))
 
 (defclass name-mixin ()
@@ -43,296 +45,12 @@
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;
-;;; Clef
-
-;;; The line number on which the clef is located on the staff. 
-;;; The bottom line of the staff is number 1. 
-(defgeneric lineno (clef))
-
-;;; for key signature drawing calcluations.  FIXME: in fact the layout
-;;; of key signatures isn't the same across all clefs.
-(defgeneric b-position (clef))
-(defgeneric f-position (clef))
-
-;;; the note number of the bottom line of this clef.
-(defgeneric bottom-line (clef))
-
-(defclass clef (gsharp-object name-mixin)
-  ((lineno :reader lineno :initarg :lineno
-           :type (or (integer 0 8) null))))
-
-(defun make-clef (name &key lineno)
-  (declare (type (member :treble :treble8 :bass :c :percussion) name)
-           (type (or (integer 0 8) null) lineno))
-  (when (null lineno)
-    (setf lineno
-          (ecase name
-            ((:treble :treble8) 2)
-            (:bass 6)
-            (:c 4)
-            (:percussion 3))))
-  (make-instance 'clef :name name :lineno lineno))
-
-(defmethod slots-to-be-saved append ((c clef))
-  '(lineno))
-
-(defun read-clef-v3 (stream char n)
-  (declare (ignore char n))
-  (apply #'make-instance 'clef (read-delimited-list #\] stream t)))
-
-(set-dispatch-macro-character #\[ #\K
-  #'read-clef-v3
-  *gsharp-readtable-v3*)
-
-;;; given a clef, return the staff step of the B that should have
-;;; the first flat sign in key signatures with flats
-(defmethod b-position ((clef clef))
-  (ecase (name clef)
-    (:bass (- (lineno clef) 4))
-    ((:treble :treble8) (+ (lineno clef) 2))
-    (:c (- (lineno clef) 1))))
-
-
-;;; given a clef, return the staff step of the F that should have
-;;; the first sharp sign in key signatures with sharps
-(defmethod f-position ((clef clef))
-  (ecase (name clef)
-    (:bass (lineno clef))
-    ((:treble :treble8) (+ (lineno clef) 6))
-    (:c (+ (lineno clef) 3))))
-
-(defmethod bottom-line ((clef clef))
-  (- (ecase (name clef)
-       (:treble 32)
-       (:bass 24)
-       (:c 28)
-       (:treble8 25))
-     (lineno clef)))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;
 ;;; Staff
 
 (defclass staff (gsharp-object name-mixin)
   ((buffer :initarg :buffer :accessor buffer))
   (:default-initargs :name "default staff"))
 
-;;; fiveline
-
-(defgeneric clef (fiveline-staff))
-
-(defclass fiveline-staff (staff)
-  ((clef :accessor clef :initarg :clef :initform (make-clef :treble))
-   (%keysig :accessor keysig :initarg :keysig
-            :initform (make-array 7 :initial-element :natural))
-   (key-signatures :accessor key-signatures :initform nil)))
-           
-(defmethod initialize-instance :after ((obj fiveline-staff) &rest args)
-  (declare (ignore args))
-  (with-slots (%keysig) obj
-    (when (vectorp %keysig)
-      (setf %keysig
-            (make-instance 'key-signature :staff obj :alterations %keysig)))))
-
-(defun make-fiveline-staff (&rest args &key name clef keysig)
-  (declare (ignore name clef keysig))
-  (apply #'make-instance 'fiveline-staff args))
-
-(defmethod slots-to-be-saved append ((s fiveline-staff))
-  '(clef %keysig))
-
-(defun read-fiveline-staff-v3 (stream char n)
-  (declare (ignore char n))
-  (apply #'make-instance 'fiveline-staff (read-delimited-list #\] stream t)))
-
-(set-dispatch-macro-character #\[ #\=
-  #'read-fiveline-staff-v3
-  *gsharp-readtable-v3*)
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;
-;;; Note
-
-;;; Notes are immutable objets.  If you want to alter (say) the staff
-;;; or the pitch of a note, you have to delete it and add a new note
-;;; with the right characteristics.
-
-;;; Return the pitch of the note. 
-(defgeneric pitch (note))
-
-;;; Return the accidentals of the note.  The value returned is one of
-;;; :natural :flat :double-flat :sharp or :double-sharp.
-(defgeneric accidentals (note))
-
-;;; Return a non-negative integer indicating the number of dots of the
-;;; note.  The value nil is returned whenever the note takes its
-;;; number of dots from the cluster to which it belongs.
-(defgeneric dots (note))
-
-;;; Returns the cluster to which the note belongs, or nil if the note
-;;; currently does not belong to any cluster. 
-(defgeneric cluster (note))
-
-;;; The pitch is a number from 0 to 128
-;;; 
-;;; The staff is a staff object. 
-;;; 
-;;; Head can be :long, :breve, :whole, :half, :filled, or nil.  A
-;;; value of nil means that the notehead is determined by that of the
-;;; cluster to which the note belongs.
-;;; 
-;;; Accidentals can be :natural :flat :double-flat :sharp or :double-sharp.
-;;; The default is :natural.  Whether a note is actually displayed
-;;; preceded by one of the corresponding signs is a matter of context and
-;;; display style. 
-;;; 
-;;; The number of dots can be an integer or nil, meaning that the number
-;;; of dots is taken from the cluster.  The default value is nil.
-;;; 
-;;; The actual duration of the note is computed from the note head, the
-;;; number of beams of the cluster to which the note belongs, and the
-;;; number of dots in the usual way. 
-
-(defclass note (gsharp-object)
-  ((cluster :initform nil :initarg :cluster :accessor cluster)
-   (pitch :initarg :pitch :reader pitch :type (integer 0 127))
-   (staff :initarg :staff :reader staff :type staff)
-   (head :initform nil :initarg :head :reader head
-         :type (or (member :long :breve :whole :half :filled) null))
-   (accidentals :initform :natural :initarg :accidentals :reader accidentals
-		;; FIXME: we want :TYPE ACCIDENTAL here but need to
-		;; sort out order of definition for that to be useful.
-		#+nil #+nil 
-                :type (member :natural :flat :double-flat :sharp :double-sharp))
-   (dots :initform nil :initarg :dots :reader dots
-         :type (or (integer 0 3) null))
-   (%tie-right :initform nil :initarg :tie-right :accessor tie-right)
-   (%tie-left :initform nil :initarg :tie-left :accessor tie-left)))
-
-(defun make-note (pitch staff &rest args &key head (accidentals :natural) dots)
-  (declare (type (integer 0 127) pitch)
-           (type staff staff)
-           (type (or (member :long :breve :whole :half :filled) null) head)
-	   ;; FIXME: :TYPE ACCIDENTAL
-	   #+nil #+nil
-           (type (member :natural :flat :double-flat :sharp :double-sharp)
-                 accidentals)
-           (type (or (integer 0 3) null) dots)
-           (ignore head accidentals dots))
-  (apply #'make-instance 'note :pitch pitch :staff staff args))
-
-(defmethod slots-to-be-saved append ((n note))
-  '(pitch staff head accidentals dots %tie-right %tie-left))
-
-(defun read-note-v3 (stream char n)
-  (declare (ignore char n))
-  (apply #'make-instance 'note (read-delimited-list #\] stream t)))
-
-(set-dispatch-macro-character #\[ #\N
-  #'read-note-v3
-  *gsharp-readtable-v3*)
-
-;;; Return true if note1 is considered less than note2.
-(defun note-less (note1 note2)
-  (< (pitch note1) (pitch note2)))
-
-;;; Return true if note1 is considered equal to note2.
-(defun note-equal (note1 note2)
-  (= (pitch note1) (pitch note2)))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;
-;;; Tuning (support for microtonal and historical tunings/temperaments)
-
-;;; FIXME: add name-mixin also?
-(defclass tuning (gsharp-object)
-  ((master-pitch-note :initform (make-instance 'note :pitch 33 ; a above middle c
-                                                     :staff (make-instance 'staff))
-                      :initarg :master-pitch-note
-                      :type note
-                      :accessor master-pitch-note)
-   (master-pitch-freq :initform 440
-                      :initarg :master-pitch-freq
-                      :accessor master-pitch-freq)))
-
-(defmethod slots-to-be-saved append ((tuning tuning))
-  '(master-pitch-note master-pitch-freq))
-
-;;; Returns how a note should be tuned in a given tuning
-;;; in terms of a cent value.
-(defgeneric note-cents (note tuning))
-
-;;; 12-edo is provided for efficiency only. It is a 
-;;; special case of a regular temperament. Perhaps it
-;;; should be removed?
-(defclass 12-edo (tuning)
-  ())
-
-(defmethod slots-to-be-saved append ((tuning 12-edo))
-  '())
-
-(defmethod note-cents ((note note) (tuning 12-edo))
-  (multiple-value-bind (octave pitch) (floor (pitch note) 7)
-    (+ (* 1200 (1+ octave))
-       (ecase pitch (0 0) (1 200) (2 400) (3 500) (4 700) (5 900) (6 1100))
-       (ecase (accidentals note)
-         (:double-flat -200)
-	 (:sesquiflat -150)
-         (:flat -100)
-	 (:semiflat -50)
-         (:natural 0)
-	 (:semisharp 50)
-         (:sharp 100)
-	 (:sesquisharp 150)
-         (:double-sharp 200)))))
-
-;;; regular temperaments are temperaments that
-;;; retain their interval sizes regardless of modulation, as opposed to
-;;; irregular temperaments.
-(defclass regular-temperament (tuning)
-  ((octave-cents :initform 1200 :initarg :octave-cents :accessor octave-cents)
-   (fifth-cents :initform 700 :initarg :fifth-cents :accessor fifth-cents)
-   (quartertone-cents :initform 50 :initarg :quartertone-cents :accessor quartertone-cents)
-   ;; TODO: Add cent sizes of various microtonal accidentals, perhaps in an alist?
-   ))
-
-(defmethod slots-to-be-saved append ((tuning regular-temperament))
-  '(octave-cents fifth-cents))
-
-(defmethod note-cents ((note note) (tuning regular-temperament))
-  (let ((octaves 1)
-        (fifths 0)
-        (sharps 0) ;; short for 7 fifths up and 4 octaves down
-        (quartertones 0))
-    (incf octaves (floor (pitch note) 7))
-    (ecase (mod (pitch note) 7)
-      (0 (progn))
-      (1 (progn (incf octaves -1) (incf fifths 2)))
-      (2 (progn (incf octaves -2) (incf fifths 4)))
-      (3 (progn (incf octaves 1) (incf fifths -1)))
-      (4 (progn (incf fifths 1)))
-      (5 (progn (incf octaves -1) (incf fifths 3)))
-      (6 (progn (incf octaves -2) (incf fifths 5))))
-    (ecase (accidentals note)
-      (:double-flat (incf sharps -2))
-      (:sesquiflat (incf sharps -1) (incf quartertones -1))
-      (:flat (incf sharps -1))
-      (:semiflat (incf quartertones -1))
-      (:natural)
-      (:semisharp (incf quartertones 1))
-      (:sharp (incf sharps 1))
-      (:sesquisharp (incf sharps 1) (incf quartertones 1))
-      (:double-sharp (incf sharps 2)))
-    (incf octaves (* -4 sharps))
-    (incf fifths (* 7 sharps))
-    (+ (* octaves (octave-cents tuning))
-       (* fifths (fifth-cents tuning))
-       (* quartertones (quartertone-cents tuning)))))
- 
-;;; TODO: (defclass irregular-temperament ...)
- 
-
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;
 ;;; Element
@@ -404,216 +122,6 @@
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;
-;;; Melody element
-
-(defclass melody-element (rhythmic-element) ())
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;
-;;; Key signature
-
-(defgeneric alterations (key-signature)
-  (:documentation "return the alterations in the form of a 
-7-element array where each element is either :natural,
-:sharp, or :flat according to how each staff position 
-should be altered"))
-
-(defgeneric more-sharps (key-signature &optional n)
-  (:documentation "make the key signature N alterations
-sharper by removing some flats and/or adding some sharps"))
-
-(defgeneric more-flats (key-signature &optional n)
-  (:documentation "make the key signature N alterations
-flatter by removing some sharps and/or adding some flats"))
-
-(defclass key-signature (element)
-  ((%staff :initarg :staff :reader staff)
-   (%alterations :initform (make-array 7 :initial-element :natural) 
-                 :initarg :alterations :reader alterations)))
-
-(defun make-key-signature (staff &rest args &key alterations)
-  (declare (type (or null (simple-vector 7)) alterations)
-           (ignore alterations))
-  (apply #'make-instance 'key-signature :staff staff args))
-
-(defmethod slots-to-be-saved append ((k key-signature))
-  '(%staff %alterations))
-
-(defmethod more-sharps ((sig key-signature) &optional (n 1))
-  (let ((alt (alterations sig)))
-    (loop repeat n
-          do (cond ((eq (aref alt 3) :flat) (setf (aref alt 3) :natural))
-                   ((eq (aref alt 0) :flat) (setf (aref alt 0) :natural))
-                   ((eq (aref alt 4) :flat) (setf (aref alt 4) :natural))
-                   ((eq (aref alt 1) :flat) (setf (aref alt 1) :natural))
-                   ((eq (aref alt 5) :flat) (setf (aref alt 5) :natural))
-                   ((eq (aref alt 2) :flat) (setf (aref alt 2) :natural))
-                   ((eq (aref alt 6) :flat) (setf (aref alt 6) :natural))
-                   ((eq (aref alt 3) :natural) (setf (aref alt 3) :sharp))
-                   ((eq (aref alt 0) :natural) (setf (aref alt 0) :sharp))
-                   ((eq (aref alt 4) :natural) (setf (aref alt 4) :sharp))
-                   ((eq (aref alt 1) :natural) (setf (aref alt 1) :sharp))
-                   ((eq (aref alt 5) :natural) (setf (aref alt 5) :sharp))
-                   ((eq (aref alt 2) :natural) (setf (aref alt 2) :sharp))
-                   ((eq (aref alt 6) :natural) (setf (aref alt 6) :sharp))))))
-
-(defmethod more-flats ((sig key-signature) &optional (n 1))
-  (let ((alt (alterations sig)))
-    (loop repeat n
-          do (cond ((eq (aref alt 6) :sharp) (setf (aref alt 6) :natural))
-                   ((eq (aref alt 2) :sharp) (setf (aref alt 2) :natural))
-                   ((eq (aref alt 5) :sharp) (setf (aref alt 5) :natural))
-                   ((eq (aref alt 1) :sharp) (setf (aref alt 1) :natural))
-                   ((eq (aref alt 4) :sharp) (setf (aref alt 4) :natural))
-                   ((eq (aref alt 0) :sharp) (setf (aref alt 0) :natural))
-                   ((eq (aref alt 3) :sharp) (setf (aref alt 3) :natural))
-                   ((eq (aref alt 6) :natural) (setf (aref alt 6) :flat))
-                   ((eq (aref alt 2) :natural) (setf (aref alt 2) :flat))
-                   ((eq (aref alt 5) :natural) (setf (aref alt 5) :flat))
-                   ((eq (aref alt 1) :natural) (setf (aref alt 1) :flat))
-                   ((eq (aref alt 4) :natural) (setf (aref alt 4) :flat))
-                   ((eq (aref alt 0) :natural) (setf (aref alt 0) :flat))
-                   ((eq (aref alt 3) :natural) (setf (aref alt 3) :flat))))))
-                                                                              
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;
-;;; Cluster
-
-;;; Return a list of the notes of the cluster
-(defgeneric notes (cluster))
-
-;;; Add a note to the cluster.  It is an error if there is already a
-;;; note in the cluster with the same staff and the same pitch.
-(defgeneric add-note (cluster note))
-
-;;; Find a note in a cluster.  The comparison is made using only the 
-;;; pitch of the supplied note.  If the note does not exist nil is returned.
-(defgeneric find-note (cluster note))
-
-;;; Delete a note from the cluster to which it belongs.  It is an
-;;; error to call this function if the note currently does not belong

[199 lines skipped]
--- /project/gsharp/cvsroot/gsharp/gsharp.asd	2007/10/22 09:39:23	1.18
+++ /project/gsharp/cvsroot/gsharp/gsharp.asd	2007/10/22 11:45:37	1.19
@@ -27,6 +27,7 @@
    "sdl"
    "score-pane"
    "buffer"
+   "melody"
    "lyrics"
    "numbering"
    "Obseq/obseq"

--- /project/gsharp/cvsroot/gsharp/melody.lisp	2007/10/22 11:45:37	NONE
+++ /project/gsharp/cvsroot/gsharp/melody.lisp	2007/10/22 11:45:37	1.1
(in-package :gsharp-buffer)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Clef

;;; The line number on which the clef is located on the staff. 
;;; The bottom line of the staff is number 1. 
(defgeneric lineno (clef))

;;; for key signature drawing calcluations.  FIXME: in fact the layout
;;; of key signatures isn't the same across all clefs.
(defgeneric b-position (clef))
(defgeneric f-position (clef))

;;; the note number of the bottom line of this clef.
(defgeneric bottom-line (clef))

(defclass clef (gsharp-object name-mixin)
  ((lineno :reader lineno :initarg :lineno
           :type (or (integer 0 8) null))))

(defun make-clef (name &key lineno)
  (declare (type (member :treble :treble8 :bass :c :percussion) name)
           (type (or (integer 0 8) null) lineno))
  (when (null lineno)
    (setf lineno
          (ecase name
            ((:treble :treble8) 2)
            (:bass 6)
            (:c 4)
            (:percussion 3))))
  (make-instance 'clef :name name :lineno lineno))

(defmethod slots-to-be-saved append ((c clef))
  '(lineno))

(defun read-clef-v3 (stream char n)
  (declare (ignore char n))
  (apply #'make-instance 'clef (read-delimited-list #\] stream t)))

(set-dispatch-macro-character #\[ #\K
  #'read-clef-v3
  *gsharp-readtable-v3*)

;;; given a clef, return the staff step of the B that should have
;;; the first flat sign in key signatures with flats
(defmethod b-position ((clef clef))
  (ecase (name clef)
    (:bass (- (lineno clef) 4))
    ((:treble :treble8) (+ (lineno clef) 2))
    (:c (- (lineno clef) 1))))


;;; given a clef, return the staff step of the F that should have
;;; the first sharp sign in key signatures with sharps
(defmethod f-position ((clef clef))
  (ecase (name clef)
    (:bass (lineno clef))
    ((:treble :treble8) (+ (lineno clef) 6))
    (:c (+ (lineno clef) 3))))

(defmethod bottom-line ((clef clef))
  (- (ecase (name clef)
       (:treble 32)
       (:bass 24)
       (:c 28)
       (:treble8 25))
     (lineno clef)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Fiveline staff

(defgeneric clef (fiveline-staff))

(defclass fiveline-staff (staff)
  ((clef :accessor clef :initarg :clef :initform (make-clef :treble))
   (%keysig :accessor keysig :initarg :keysig
            :initform (make-array 7 :initial-element :natural))
   (key-signatures :accessor key-signatures :initform nil)))
           
(defmethod initialize-instance :after ((obj fiveline-staff) &rest args)
  (declare (ignore args))
  (with-slots (%keysig) obj
    (when (vectorp %keysig)
      (setf %keysig
            (make-instance 'key-signature :staff obj :alterations %keysig)))))

(defun make-fiveline-staff (&rest args &key name clef keysig)
  (declare (ignore name clef keysig))
  (apply #'make-instance 'fiveline-staff args))

(defmethod slots-to-be-saved append ((s fiveline-staff))
  '(clef %keysig))

(defun read-fiveline-staff-v3 (stream char n)
  (declare (ignore char n))
  (apply #'make-instance 'fiveline-staff (read-delimited-list #\] stream t)))

(set-dispatch-macro-character #\[ #\=
  #'read-fiveline-staff-v3
  *gsharp-readtable-v3*)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Note

;;; Notes are immutable objets.  If you want to alter (say) the staff
;;; or the pitch of a note, you have to delete it and add a new note
;;; with the right characteristics.

;;; Return the pitch of the note. 
(defgeneric pitch (note))

;;; Return the accidentals of the note.  The value returned is one of
;;; :natural :flat :double-flat :sharp or :double-sharp.
(defgeneric accidentals (note))

;;; Return a non-negative integer indicating the number of dots of the
;;; note.  The value nil is returned whenever the note takes its
;;; number of dots from the cluster to which it belongs.
(defgeneric dots (note))

;;; Returns the cluster to which the note belongs, or nil if the note
;;; currently does not belong to any cluster. 
(defgeneric cluster (note))

;;; The pitch is a number from 0 to 128
;;; 
;;; The staff is a staff object. 
;;; 
;;; Head can be :long, :breve, :whole, :half, :filled, or nil.  A
;;; value of nil means that the notehead is determined by that of the
;;; cluster to which the note belongs.
;;; 
;;; Accidentals can be :natural :flat :double-flat :sharp or :double-sharp.
;;; The default is :natural.  Whether a note is actually displayed
;;; preceded by one of the corresponding signs is a matter of context and
;;; display style. 
;;; 
;;; The number of dots can be an integer or nil, meaning that the number
;;; of dots is taken from the cluster.  The default value is nil.
;;; 
;;; The actual duration of the note is computed from the note head, the
;;; number of beams of the cluster to which the note belongs, and the
;;; number of dots in the usual way. 

(defclass note (gsharp-object)
  ((cluster :initform nil :initarg :cluster :accessor cluster)
   (pitch :initarg :pitch :reader pitch :type (integer 0 127))
   (staff :initarg :staff :reader staff :type staff)
   (head :initform nil :initarg :head :reader head
         :type (or (member :long :breve :whole :half :filled) null))
   (accidentals :initform :natural :initarg :accidentals :reader accidentals
		;; FIXME: we want :TYPE ACCIDENTAL here but need to
		;; sort out order of definition for that to be useful.
		#+nil #+nil 
                :type (member :natural :flat :double-flat :sharp :double-sharp))
   (dots :initform nil :initarg :dots :reader dots
         :type (or (integer 0 3) null))
   (%tie-right :initform nil :initarg :tie-right :accessor tie-right)
   (%tie-left :initform nil :initarg :tie-left :accessor tie-left)))

(defun make-note (pitch staff &rest args &key head (accidentals :natural) dots)
  (declare (type (integer 0 127) pitch)
           (type staff staff)
           (type (or (member :long :breve :whole :half :filled) null) head)
	   ;; FIXME: :TYPE ACCIDENTAL
	   #+nil #+nil
           (type (member :natural :flat :double-flat :sharp :double-sharp)
                 accidentals)
           (type (or (integer 0 3) null) dots)
           (ignore head accidentals dots))
  (apply #'make-instance 'note :pitch pitch :staff staff args))

(defmethod slots-to-be-saved append ((n note))
  '(pitch staff head accidentals dots %tie-right %tie-left))

(defun read-note-v3 (stream char n)
  (declare (ignore char n))
  (apply #'make-instance 'note (read-delimited-list #\] stream t)))

(set-dispatch-macro-character #\[ #\N
  #'read-note-v3
  *gsharp-readtable-v3*)

;;; Return true if note1 is considered less than note2.
(defun note-less (note1 note2)
  (< (pitch note1) (pitch note2)))

;;; Return true if note1 is considered equal to note2.
(defun note-equal (note1 note2)
  (= (pitch note1) (pitch note2)))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Tuning (support for microtonal and historical tunings/temperaments)

;;; FIXME: add name-mixin also?
(defclass tuning (gsharp-object)
  ((master-pitch-note :initform (make-instance 'note :pitch 33 ; a above middle c
                                                     :staff (make-instance 'staff))
                      :initarg :master-pitch-note
                      :type note
                      :accessor master-pitch-note)
   (master-pitch-freq :initform 440
                      :initarg :master-pitch-freq
                      :accessor master-pitch-freq)))

(defmethod slots-to-be-saved append ((tuning tuning))
  '(master-pitch-note master-pitch-freq))

;;; Returns how a note should be tuned in a given tuning
;;; in terms of a cent value.
(defgeneric note-cents (note tuning))

;;; 12-edo is provided for efficiency only. It is a 
;;; special case of a regular temperament. Perhaps it
;;; should be removed?
(defclass 12-edo (tuning)
  ())

(defmethod slots-to-be-saved append ((tuning 12-edo))
  '())

(defmethod note-cents ((note note) (tuning 12-edo))
  (multiple-value-bind (octave pitch) (floor (pitch note) 7)
    (+ (* 1200 (1+ octave))
       (ecase pitch (0 0) (1 200) (2 400) (3 500) (4 700) (5 900) (6 1100))
       (ecase (accidentals note)
         (:double-flat -200)
	 (:sesquiflat -150)
         (:flat -100)
	 (:semiflat -50)
         (:natural 0)
	 (:semisharp 50)
         (:sharp 100)
	 (:sesquisharp 150)
         (:double-sharp 200)))))

;;; regular temperaments are temperaments that
;;; retain their interval sizes regardless of modulation, as opposed to
;;; irregular temperaments.
(defclass regular-temperament (tuning)
  ((octave-cents :initform 1200 :initarg :octave-cents :accessor octave-cents)
   (fifth-cents :initform 700 :initarg :fifth-cents :accessor fifth-cents)
   (quartertone-cents :initform 50 :initarg :quartertone-cents :accessor quartertone-cents)
   ;; TODO: Add cent sizes of various microtonal accidentals, perhaps in an alist?
   ))

(defmethod slots-to-be-saved append ((tuning regular-temperament))
  '(octave-cents fifth-cents))

(defmethod note-cents ((note note) (tuning regular-temperament))
  (let ((octaves 1)
        (fifths 0)
        (sharps 0) ;; short for 7 fifths up and 4 octaves down
        (quartertones 0))
    (incf octaves (floor (pitch note) 7))
    (ecase (mod (pitch note) 7)
      (0 (progn))
      (1 (progn (incf octaves -1) (incf fifths 2)))
      (2 (progn (incf octaves -2) (incf fifths 4)))
      (3 (progn (incf octaves 1) (incf fifths -1)))
      (4 (progn (incf fifths 1)))
      (5 (progn (incf octaves -1) (incf fifths 3)))
      (6 (progn (incf octaves -2) (incf fifths 5))))
    (ecase (accidentals note)
      (:double-flat (incf sharps -2))
      (:sesquiflat (incf sharps -1) (incf quartertones -1))
      (:flat (incf sharps -1))
      (:semiflat (incf quartertones -1))
      (:natural)
      (:semisharp (incf quartertones 1))
      (:sharp (incf sharps 1))
      (:sesquisharp (incf sharps 1) (incf quartertones 1))
      (:double-sharp (incf sharps 2)))
    (incf octaves (* -4 sharps))
    (incf fifths (* 7 sharps))
    (+ (* octaves (octave-cents tuning))
       (* fifths (fifth-cents tuning))
       (* quartertones (quartertone-cents tuning)))))
 
;;; TODO: (defclass irregular-temperament ...)
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Melody element

(defclass melody-element (rhythmic-element) ())

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Key signature

(defgeneric alterations (key-signature)
  (:documentation "return the alterations in the form of a 
7-element array where each element is either :natural,
:sharp, or :flat according to how each staff position 
should be altered"))

(defgeneric more-sharps (key-signature &optional n)
  (:documentation "make the key signature N alterations
sharper by removing some flats and/or adding some sharps"))

(defgeneric more-flats (key-signature &optional n)
  (:documentation "make the key signature N alterations
flatter by removing some sharps and/or adding some flats"))

(defclass key-signature (element)
  ((%staff :initarg :staff :reader staff)
   (%alterations :initform (make-array 7 :initial-element :natural) 
                 :initarg :alterations :reader alterations)))

(defun make-key-signature (staff &rest args &key alterations)
  (declare (type (or null (simple-vector 7)) alterations)
           (ignore alterations))
  (apply #'make-instance 'key-signature :staff staff args))

(defmethod slots-to-be-saved append ((k key-signature))
  '(%staff %alterations))

(defmethod more-sharps ((sig key-signature) &optional (n 1))
  (let ((alt (alterations sig)))
    (loop repeat n
          do (cond ((eq (aref alt 3) :flat) (setf (aref alt 3) :natural))
                   ((eq (aref alt 0) :flat) (setf (aref alt 0) :natural))
                   ((eq (aref alt 4) :flat) (setf (aref alt 4) :natural))
                   ((eq (aref alt 1) :flat) (setf (aref alt 1) :natural))
                   ((eq (aref alt 5) :flat) (setf (aref alt 5) :natural))
                   ((eq (aref alt 2) :flat) (setf (aref alt 2) :natural))
                   ((eq (aref alt 6) :flat) (setf (aref alt 6) :natural))
                   ((eq (aref alt 3) :natural) (setf (aref alt 3) :sharp))
                   ((eq (aref alt 0) :natural) (setf (aref alt 0) :sharp))
                   ((eq (aref alt 4) :natural) (setf (aref alt 4) :sharp))
                   ((eq (aref alt 1) :natural) (setf (aref alt 1) :sharp))
                   ((eq (aref alt 5) :natural) (setf (aref alt 5) :sharp))
                   ((eq (aref alt 2) :natural) (setf (aref alt 2) :sharp))
                   ((eq (aref alt 6) :natural) (setf (aref alt 6) :sharp))))))

(defmethod more-flats ((sig key-signature) &optional (n 1))
  (let ((alt (alterations sig)))
    (loop repeat n
          do (cond ((eq (aref alt 6) :sharp) (setf (aref alt 6) :natural))
                   ((eq (aref alt 2) :sharp) (setf (aref alt 2) :natural))
                   ((eq (aref alt 5) :sharp) (setf (aref alt 5) :natural))
                   ((eq (aref alt 1) :sharp) (setf (aref alt 1) :natural))
                   ((eq (aref alt 4) :sharp) (setf (aref alt 4) :natural))
                   ((eq (aref alt 0) :sharp) (setf (aref alt 0) :natural))
                   ((eq (aref alt 3) :sharp) (setf (aref alt 3) :natural))
                   ((eq (aref alt 6) :natural) (setf (aref alt 6) :flat))
                   ((eq (aref alt 2) :natural) (setf (aref alt 2) :flat))
                   ((eq (aref alt 5) :natural) (setf (aref alt 5) :flat))
                   ((eq (aref alt 1) :natural) (setf (aref alt 1) :flat))
                   ((eq (aref alt 4) :natural) (setf (aref alt 4) :flat))
                   ((eq (aref alt 0) :natural) (setf (aref alt 0) :flat))
                   ((eq (aref alt 3) :natural) (setf (aref alt 3) :flat))))))
                                                                              
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Cluster

;;; Return a list of the notes of the cluster
(defgeneric notes (cluster))

;;; Add a note to the cluster.  It is an error if there is already a
;;; note in the cluster with the same staff and the same pitch.
(defgeneric add-note (cluster note))

;;; Find a note in a cluster.  The comparison is made using only the 
;;; pitch of the supplied note.  If the note does not exist nil is returned.
(defgeneric find-note (cluster note))

;;; Delete a note from the cluster to which it belongs.  It is an
;;; error to call this function if the note currently does not belong
;;; to any cluster. 
(defgeneric remove-note (note))

(defclass cluster (melody-element)
  ((notes :initform '() :initarg :notes :accessor notes)
   (stem-direction :initform :auto :initarg :stem-direction :accessor stem-direction)))

(defmethod initialize-instance :after ((c cluster) &rest args)
  (declare (ignore args))
  (loop for note in (notes c)
        do (setf (cluster note) c)))

(defun make-cluster (&rest args

[156 lines skipped]



More information about the Gsharp-cvs mailing list