Mercurial > hg > amuse
changeset 179:88089258e08d
initial tabcode work
darcs-hash:20080708152042-40ec0-f6bf9befa5dc8d6eaf51dd1cbff68c78a09de896.gz
author | d.lewis <d.lewis@gold.ac.uk> |
---|---|
date | Tue, 08 Jul 2008 16:20:42 +0100 |
parents | 057e8ab413f9 |
children | 1a2b876b5587 |
files | base/package.lisp implementations/tabcode/amuse-tabcode.asd implementations/tabcode/classes.lisp implementations/tabcode/methods.lisp implementations/tabcode/package.lisp implementations/tabcode/tabcode-import.lisp |
diffstat | 6 files changed, 283 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/base/package.lisp Mon Jun 30 10:10:21 2008 +0100 +++ b/base/package.lisp Tue Jul 08 16:20:42 2008 +0100 @@ -148,4 +148,6 @@ #:crotchet #:diatonic-pitch-cp #:diatonic-pitch-mp + #:current-beat + #:current-bar ))
--- a/implementations/tabcode/amuse-tabcode.asd Mon Jun 30 10:10:21 2008 +0100 +++ b/implementations/tabcode/amuse-tabcode.asd Tue Jul 08 16:20:42 2008 +0100 @@ -1,5 +1,5 @@ (asdf:defsystem amuse-tabcode - :depends-on (amuse tabcode-gui) + :depends-on (amuse tabcode) :components ((:file "package") (:file "classes" :depends-on ("package"))
--- a/implementations/tabcode/classes.lisp Mon Jun 30 10:10:21 2008 +0100 +++ b/implementations/tabcode/classes.lisp Tue Jul 08 16:20:42 2008 +0100 @@ -1,9 +1,62 @@ (cl:in-package #:amuse-tabcode) -(defclass tabcode-composition (amuse:standard-composition) - ()) +(defclass tabcode-object (amuse-object) ()) -(defclass tabcode-pitched-event (standard-chromatic-pitched-event) +(defclass tabcode-composition (standard-composition tabcode-object) + ((bars :initarg :bars :reader tabcode-bars) + (rules :initarg :rules :reader tabcode-rules) + (metres :initarg :metres :reader metrical-signs))) + +(defclass tabcode-pitched-event (standard-chromatic-pitched-event tabcode-object) ((course :initarg :course :reader course) (fret :initarg :fret :reader fret) - (word :initarg :word :reader word))) + (word :initarg :word :reader word) + (bar :initarg :bar :reader in-bar))) + +(defclass tabcode-time-signature (standard-anchored-period tabcode-object) + ((word :initarg :word :reader word) + (ul)(ll)(ur)(lr))) +(defmethod ul ((timesig tabcode-time-signature)) + (unless (slot-boundp timesig 'ul) + (let ((ul (tabcode::ul (word timesig)))) + (setf (slot-value timesig 'ul) + (when ul + (or (parse-integer ul :junk-allowed t) + ul))))) + (slot-value timesig 'ul)) +(defmethod ll ((timesig tabcode-time-signature)) + (unless (slot-boundp timesig 'll) + (let ((ll (tabcode::ll (word timesig)))) + (setf (slot-value timesig 'll) + (when ll + (or (parse-integer ll :junk-allowed t) + ll))))) + (slot-value timesig 'll)) +(defmethod ur ((timesig tabcode-time-signature)) + (unless (slot-boundp timesig 'ur) + (let ((ur (tabcode::ur (word timesig)))) + (setf (slot-value timesig 'ur) + (when ur + (or (parse-integer ur :junk-allowed t) + ur))))) + (slot-value timesig 'ur)) +(defmethod lr ((timesig tabcode-time-signature)) + (unless (slot-boundp timesig 'lr) + (let ((lr (tabcode::lr (word timesig)))) + (setf (slot-value timesig 'lr) + (when lr + (or (parse-integer lr :junk-allowed t) + lr))))) + (slot-value timesig 'lr)) + +(defclass tabcode-file-identifier (identifier tabcode-object) + ((pathname :initarg :pathname :reader tabcode-pathname))) + +(defclass tabcode-bar (standard-anchored-period tabcode-object) + ((start :initarg :start :accessor start-tabword) + (end :initarg :end :accessor end-tabword))) + +(defclass tabcode-ruleset (standard-anchored-period tabcode-object) + ((rules :initarg :rules :accessor ruleset-rules) + (tuning :initarg :tuning :accessor ruleset-tuning :initform nil))) +
--- a/implementations/tabcode/methods.lisp Mon Jun 30 10:10:21 2008 +0100 +++ b/implementations/tabcode/methods.lisp Tue Jul 08 16:20:42 2008 +0100 @@ -5,3 +5,68 @@ (defmethod time-signatures ((composition tabcode-composition)) ()) +(defmethod get-applicable-key-signatures (object (composition tabcode-composition)) + ()) + +(defmethod crotchet ((object tabcode-object)) + (make-standard-period 1)) + +(defmethod current-bar ((moment standard-moment) (composition tabcode-composition)) + (find-if #'(lambda (x) (and (time< moment (cut-off x)) + (time>= moment (onset x)))) + (tabcode-bars composition))) + +(defmethod current-beat ((moment standard-moment) (composition tabcode-composition)) + ;; clearly broken, but can unbreak unusual cases as they arise (?!) + (let ((bar (current-bar moment composition)) + (metre (find-if #'(lambda (x) (and (time< moment (cut-off x)) + (time>= moment (onset x)))) + (metrical-signs composition)))) + (unless (and bar metre) + (error 'insufficient-information + :operation 'beat-period + :datatype (class-of composition))) + (let ((beats-in-bar) (beat-duration)) + (cond + ((ur metre) + ;; we have a weird compound signature, goodness knows what to + ;; do. This probably means that one of them is a proportion + ;; sign. + (error 'insufficient-information + :operation 'beat-period + :datatype (class-of composition))) + ((and (ll metre) + (numberp (ll metre)) ;; we have a `standard + (numberp (ul metre)));; time sig' + (setf beats-in-bar (ul metre) + beat-duration (/ 4 (ll metre))) + (when (and (> beats-in-bar 3) + (= (rem beats-in-bar 3) 0)) + (setf beats-in-bar (/ beats-in-bar 3) + beat-duration (* beat-duration 3)))) + ((and (null (ll metre)) + (numberp (ul metre))) + (setf beats-in-bar (ul metre)) + (do ((proportion 4 (/ proportion 2))) + ((= (rem (/ (duration bar) proportion) + beats-in-bar) 0) + (setf beat-duration proportion)))) + ((null (ll metre)) + (cond + ((string= (ul metre) "C") + (setf beats-in-bar 4) + (setf beat-duration 1)) + ((string= (ul metre) "C/") + (setf beats-in-bar 2) + (setf beat-duration 2))))) + (unless (= (rem (duration bar) + (* beat-duration beats-in-bar)) + 0) + (error "Bar length doesn't match metrical symbol, I think")) + (let ((beat-period (make-standard-anchored-period + (timepoint bar) beat-duration))) + (do () + ((time> (cut-off beat-period) moment) beat-period) + (setf (timepoint beat-period) + (timepoint (cut-off beat-period)))))))) + \ No newline at end of file
--- a/implementations/tabcode/package.lisp Mon Jun 30 10:10:21 2008 +0100 +++ b/implementations/tabcode/package.lisp Tue Jul 08 16:20:42 2008 +0100 @@ -1,3 +1,3 @@ (cl:defpackage "AMUSE-TABCODE" - (:use "CL" "AMUSE" "AMUSE-UTILS") + (:use "CL" "AMUSE" "AMUSE-UTILS" "TABCODE") (:export "COURSE" "WORD" "TABCODE-PITCHED-EVENT" "TABCODE-COMPOSITION"))
--- a/implementations/tabcode/tabcode-import.lisp Mon Jun 30 10:10:21 2008 +0100 +++ b/implementations/tabcode/tabcode-import.lisp Tue Jul 08 16:20:42 2008 +0100 @@ -1,7 +1,7 @@ (in-package :amuse-tabcode) (defun word-duration (word default) - (if (typep word 'tabcode::rhythmic-word) + (if (typep word 'rhythmic-word) (let ((flag (tabcode::flag word)) (dots (tabcode::dots word))) (if flag @@ -12,10 +12,10 @@ (defun word-causes-stop-p (word course) (or (typep word 'tabcode::rest) - (typep word 'tabcode::barline) - (and (typep word 'tabcode::chord) - (member course (tabcode::playing word) :key #'tabcode::course)))) - + (typep word 'barline) + (and (typep word 'chord) + (member course (playing word) :key #'course)))) +#+nil (defun duration-for-course (course buffer start initial-duration) (let ((duration initial-duration) (default-duration initial-duration)) @@ -41,7 +41,113 @@ (let ((tuning #(67 62 57 53 48 43))) (+ (aref tuning (1- course)) (fret-to-number fret)))) +(defvar *default-tuning* #(67 -5 -5 -4 -5 -5 -2 -3)) +(defun midi-pitch-with-tuning (course fret current-tuning) + (unless current-tuning + (setf current-tuning *default-tuning*)) + (let ((open-course (aref current-tuning 0))) + (when (= open-course 0) + (case (aref current-tuning 1) + (0 ;; no info + (setf current-tuning *default-tuning* + open-course (aref current-tuning 0))) + (-5 ;; prob renaissance + (setf open-course 67)) + (-3 ;; prob baroque + (setf open-course 65)) + (t ;; probably weird transitional. Just guess. + (setf open-course 67)))) + (do ((i 1 (1+ i))) + ((< course i) (+ (fret-to-number fret) open-course)) + (setf open-course (+ open-course (aref current-tuning i)))))) + +(defparameter *current-tuning* nil) +(defmethod get-composition ((identifier tabcode-file-identifier)) + (get-composition-from-tabwords + (parse-tabcode-file (tabcode-pathname identifier)))) +(defun get-composition-from-tabwords (tabwords) + (let ((time 0) + (notes) + (result) + (current-duration 1) + (current-tuning (copy-seq *current-tuning*)) + (rules) + (metres) + (bars (list (make-instance 'tabcode-bar :start nil + :time 0 :interval 0)))) + (do* ((tabwords tabwords (cdr tabwords)) + (tabword (car tabwords) (car tabwords))) + ((null tabwords) + (setq notes (nreverse result))) + (let* ((duration (word-duration tabword current-duration))) + (when (typep tabword 'rhythmic-word) + (setf current-duration duration)) + (typecase tabword + (barline + (setf (end-tabword (car bars)) tabword + (duration (car bars)) (- time + (timepoint + (onset + (car bars)))) + bars (cons (make-instance 'tabcode-bar + :start tabword + :time time) + bars))) + (comment + (when (rulep tabword) + (when rules + (setf (duration (car rules)) + (- time + (timepoint (onset (car rules)))))) + (push (make-instance 'tabcode-ruleset + :rules (parse-rules tabword) + :time time) + rules) + (setf current-tuning (update-tuning (ruleset-rules (car rules)) + current-tuning)))) + (metre + (when metres + (setf (duration (car metres)) + (- time (timepoint (onset (car metres)))))) + (push (make-instance 'tabcode-time-signature + :time time + :word tabword) + metres)) + (chord + (dolist (playing (playing tabword)) + (let* ((course (course playing)) + (fret (fret playing)) + (note-duration current-duration)) + (push (make-instance 'tabcode-pitched-event + :course course + :fret fret + :word tabword ; object? + :number (midi-pitch-with-tuning (1- course) fret current-tuning) + :time time + :interval note-duration + :bar (car bars)) + result))))) + (incf time duration))) + (if (= (timepoint (car bars)) time) + (setf bars (cdr bars)) + (setf (duration (car bars)) + (- time (timepoint (onset (car bars)))))) + (when rules + (setf (duration (car rules)) + (- time (timepoint (onset (car rules)))))) + (when metres + (setf (duration (car metres)) + (- time (timepoint (onset (car metres)))))) + (let ((composition (make-instance 'tabcode-composition + :time 0 + :interval time + :bars (reverse bars) + :rules rules + :metres metres))) + (sequence:adjust-sequence composition (length notes) + :initial-contents notes)))) +#+nil (defun make-tabcode-composition (tabword-buffer) (let ((time 0) (notes) @@ -73,6 +179,52 @@ (sequence:adjust-sequence composition (length notes) :initial-contents notes)))) +(defun update-tuning (rules current-tuning) + (unless current-tuning + (setf current-tuning (make-array 15 :element-type 'integer))) + ;; First, get reference pitch + (when (assoc "pitch" rules :test #'string=) + (setf (aref current-tuning 0) + (parse-integer (cdr (assoc "pitch" rules :test #'string=)) :junk-allowed t))) + (cond + ((assoc "tuning" rules :test #'string=) + (setf current-tuning + (apply-tuning (cdr (assoc "tuning" rules :test #'string=)) + current-tuning))) + ((assoc "tuning-named" rules :test #'string=) + (setf current-tuning + (apply-tuning (cdr (assoc (string-downcase (cdr (assoc "tuning-named" + rules :test #'string=))) + *tuning-names* :test #'string=)) + current-tuning)))) + (cond + ((assoc "bass-tuning" rules :test #'string=) + (setf current-tuning + (apply-tuning (cdr (assoc "bass-tuning" rules :test #'string=)) + current-tuning 6))) + ((assoc "bass-tuning-named" rules :test #'string=) + (setf current-tuning + (apply-tuning (cdr (assoc (string-downcase (cdr (assoc "bass-tuning-named" + rules :test #'string=))) + *tuning-names* :test #'string=)) + current-tuning + 6)))) + current-tuning) + +(defun apply-tuning (interval-string current-tuning &optional (start-course 1)) + (do* ((pointer (1+ (or (position #\( interval-string) + -1)) + (+ 1 pointer (length (princ-to-string interval)))) + (course start-course (1+ course)) + (interval (parse-integer interval-string :start pointer :junk-allowed t) + (parse-integer interval-string :start pointer :junk-allowed t))) + ((not interval) current-tuning) + (when (>= course (length current-tuning)) + (setf current-tuning (adjust-array current-tuning (1+ course)))) + (setf (aref current-tuning course) interval))) + + + #| (in-package :clim-user)