c@43
|
1 (in-package :amuse-tabcode)
|
c@43
|
2
|
c@43
|
3 (defun word-duration (word default)
|
d@179
|
4 (if (typep word 'rhythmic-word)
|
c@43
|
5 (let ((flag (tabcode::flag word))
|
c@43
|
6 (dots (tabcode::dots word)))
|
c@43
|
7 (if flag
|
c@43
|
8 (* (car (rassoc flag tabcode::*rhythms*))
|
c@43
|
9 (if dots 3/2 1))
|
c@43
|
10 default))
|
c@43
|
11 0))
|
c@43
|
12
|
c@43
|
13 (defun word-causes-stop-p (word course)
|
c@43
|
14 (or (typep word 'tabcode::rest)
|
d@179
|
15 (typep word 'barline)
|
d@179
|
16 (and (typep word 'chord)
|
d@179
|
17 (member course (playing word) :key #'course))))
|
d@179
|
18 #+nil
|
c@43
|
19 (defun duration-for-course (course buffer start initial-duration)
|
c@43
|
20 (let ((duration initial-duration)
|
c@43
|
21 (default-duration initial-duration))
|
c@43
|
22 (do ((i start (+ i 1)))
|
c@43
|
23 ((>= i (drei-buffer:size buffer)) duration)
|
c@43
|
24 (let* ((object (drei-buffer:buffer-object buffer i))
|
c@43
|
25 (word (tabcode-syntax::tabword-word object)))
|
c@43
|
26 (when (word-causes-stop-p word course)
|
c@43
|
27 (return-from duration-for-course duration))
|
c@43
|
28 (let ((word-duration (word-duration word default-duration)))
|
c@43
|
29 (incf duration word-duration)
|
c@43
|
30 (when (> word-duration 0)
|
c@43
|
31 (setf default-duration word-duration)))))))
|
c@43
|
32
|
c@43
|
33 ;;; FIXME: like GET-COURSE-TUNING/GET-TUNING only more hardcoded
|
c@43
|
34 (defun fret-to-number (char)
|
c@43
|
35 (let ((fret-num (- (char-code char) 97)))
|
c@43
|
36 (cond
|
c@43
|
37 ((> fret-num 20) (- fret-num 2))
|
c@43
|
38 ((> fret-num 8) (- fret-num 1))
|
c@43
|
39 (t fret-num))))
|
c@43
|
40 (defun midi-pitch-for-playing (course fret)
|
c@43
|
41 (let ((tuning #(67 62 57 53 48 43)))
|
c@43
|
42 (+ (aref tuning (1- course))
|
c@43
|
43 (fret-to-number fret))))
|
d@179
|
44 (defvar *default-tuning* #(67 -5 -5 -4 -5 -5 -2 -3))
|
d@179
|
45 (defun midi-pitch-with-tuning (course fret current-tuning)
|
d@179
|
46 (unless current-tuning
|
d@179
|
47 (setf current-tuning *default-tuning*))
|
d@179
|
48 (let ((open-course (aref current-tuning 0)))
|
d@179
|
49 (when (= open-course 0)
|
d@179
|
50 (case (aref current-tuning 1)
|
d@179
|
51 (0 ;; no info
|
d@179
|
52 (setf current-tuning *default-tuning*
|
d@179
|
53 open-course (aref current-tuning 0)))
|
d@179
|
54 (-5 ;; prob renaissance
|
d@179
|
55 (setf open-course 67))
|
d@179
|
56 (-3 ;; prob baroque
|
d@179
|
57 (setf open-course 65))
|
d@179
|
58 (t ;; probably weird transitional. Just guess.
|
d@179
|
59 (setf open-course 67))))
|
d@179
|
60 (do ((i 1 (1+ i)))
|
d@179
|
61 ((< course i) (+ (fret-to-number fret) open-course))
|
d@179
|
62 (setf open-course (+ open-course (aref current-tuning i))))))
|
d@179
|
63
|
d@179
|
64 (defparameter *current-tuning* nil)
|
d@179
|
65 (defmethod get-composition ((identifier tabcode-file-identifier))
|
d@179
|
66 (get-composition-from-tabwords
|
d@179
|
67 (parse-tabcode-file (tabcode-pathname identifier))))
|
c@43
|
68
|
d@179
|
69 (defun get-composition-from-tabwords (tabwords)
|
d@179
|
70 (let ((time 0)
|
d@179
|
71 (notes)
|
d@179
|
72 (result)
|
d@179
|
73 (current-duration 1)
|
d@179
|
74 (current-tuning (copy-seq *current-tuning*))
|
d@179
|
75 (rules)
|
d@179
|
76 (metres)
|
d@179
|
77 (bars (list (make-instance 'tabcode-bar :start nil
|
d@179
|
78 :time 0 :interval 0))))
|
d@179
|
79 (do* ((tabwords tabwords (cdr tabwords))
|
d@179
|
80 (tabword (car tabwords) (car tabwords)))
|
d@179
|
81 ((null tabwords)
|
d@179
|
82 (setq notes (nreverse result)))
|
d@179
|
83 (let* ((duration (word-duration tabword current-duration)))
|
d@179
|
84 (when (typep tabword 'rhythmic-word)
|
d@179
|
85 (setf current-duration duration))
|
d@179
|
86 (typecase tabword
|
d@179
|
87 (barline
|
d@179
|
88 (setf (end-tabword (car bars)) tabword
|
d@179
|
89 (duration (car bars)) (- time
|
d@179
|
90 (timepoint
|
d@179
|
91 (onset
|
d@179
|
92 (car bars))))
|
d@179
|
93 bars (cons (make-instance 'tabcode-bar
|
d@179
|
94 :start tabword
|
d@179
|
95 :time time)
|
d@179
|
96 bars)))
|
d@179
|
97 (comment
|
d@179
|
98 (when (rulep tabword)
|
d@179
|
99 (when rules
|
d@179
|
100 (setf (duration (car rules))
|
d@179
|
101 (- time
|
d@179
|
102 (timepoint (onset (car rules))))))
|
d@179
|
103 (push (make-instance 'tabcode-ruleset
|
d@179
|
104 :rules (parse-rules tabword)
|
d@179
|
105 :time time)
|
d@179
|
106 rules)
|
d@179
|
107 (setf current-tuning (update-tuning (ruleset-rules (car rules))
|
d@179
|
108 current-tuning))))
|
d@179
|
109 (metre
|
d@179
|
110 (when metres
|
d@179
|
111 (setf (duration (car metres))
|
d@179
|
112 (- time (timepoint (onset (car metres))))))
|
d@179
|
113 (push (make-instance 'tabcode-time-signature
|
d@179
|
114 :time time
|
d@179
|
115 :word tabword)
|
d@179
|
116 metres))
|
d@179
|
117 (chord
|
d@179
|
118 (dolist (playing (playing tabword))
|
d@179
|
119 (let* ((course (course playing))
|
d@179
|
120 (fret (fret playing))
|
d@179
|
121 (note-duration current-duration))
|
d@179
|
122 (push (make-instance 'tabcode-pitched-event
|
d@179
|
123 :course course
|
d@179
|
124 :fret fret
|
d@179
|
125 :word tabword ; object?
|
d@179
|
126 :number (midi-pitch-with-tuning (1- course) fret current-tuning)
|
d@179
|
127 :time time
|
d@179
|
128 :interval note-duration
|
d@179
|
129 :bar (car bars))
|
d@179
|
130 result)))))
|
d@179
|
131 (incf time duration)))
|
d@179
|
132 (if (= (timepoint (car bars)) time)
|
d@179
|
133 (setf bars (cdr bars))
|
d@179
|
134 (setf (duration (car bars))
|
d@179
|
135 (- time (timepoint (onset (car bars))))))
|
d@179
|
136 (when rules
|
d@179
|
137 (setf (duration (car rules))
|
d@179
|
138 (- time (timepoint (onset (car rules))))))
|
d@179
|
139 (when metres
|
d@179
|
140 (setf (duration (car metres))
|
d@179
|
141 (- time (timepoint (onset (car metres))))))
|
d@179
|
142 (let ((composition (make-instance 'tabcode-composition
|
d@179
|
143 :time 0
|
d@179
|
144 :interval time
|
d@179
|
145 :bars (reverse bars)
|
d@179
|
146 :rules rules
|
d@179
|
147 :metres metres)))
|
d@179
|
148 (sequence:adjust-sequence composition (length notes)
|
d@179
|
149 :initial-contents notes))))
|
d@179
|
150 #+nil
|
c@43
|
151 (defun make-tabcode-composition (tabword-buffer)
|
c@43
|
152 (let ((time 0)
|
c@43
|
153 (notes)
|
c@43
|
154 (result)
|
c@43
|
155 (current-duration 1))
|
c@43
|
156 (dotimes (i (drei-buffer:size tabword-buffer) (setq notes (nreverse result)))
|
c@43
|
157 (let* ((object (drei-buffer:buffer-object tabword-buffer i))
|
c@43
|
158 (tabword (tabcode-syntax::tabword-word object))
|
c@43
|
159 (duration (word-duration tabword current-duration)))
|
c@43
|
160 (when (typep tabword 'tabcode::rhythmic-word)
|
c@43
|
161 (setf current-duration duration))
|
c@43
|
162 (when (typep tabword 'tabcode::chord)
|
c@43
|
163 (dolist (playing (tabcode::playing tabword))
|
c@43
|
164 (let* ((course (tabcode::course playing))
|
c@43
|
165 (fret (tabcode::fret playing))
|
c@43
|
166 (note-duration (duration-for-course course tabword-buffer (1+ i) current-duration)))
|
c@43
|
167 (push (make-instance 'tabcode-pitched-event
|
c@43
|
168 :course course
|
c@43
|
169 :fret fret
|
c@43
|
170 :word tabword ; object?
|
c@43
|
171 :number (midi-pitch-for-playing course fret)
|
c@43
|
172 :time time
|
c@43
|
173 :interval note-duration)
|
c@43
|
174 result))))
|
c@43
|
175 (incf time duration)))
|
c@43
|
176 (let ((composition (make-instance 'tabcode-composition
|
c@43
|
177 :time 0
|
c@43
|
178 :interval time)))
|
c@43
|
179 (sequence:adjust-sequence composition (length notes)
|
c@43
|
180 :initial-contents notes))))
|
c@43
|
181
|
d@179
|
182 (defun update-tuning (rules current-tuning)
|
d@179
|
183 (unless current-tuning
|
d@179
|
184 (setf current-tuning (make-array 15 :element-type 'integer)))
|
d@179
|
185 ;; First, get reference pitch
|
d@179
|
186 (when (assoc "pitch" rules :test #'string=)
|
d@179
|
187 (setf (aref current-tuning 0)
|
d@179
|
188 (parse-integer (cdr (assoc "pitch" rules :test #'string=)) :junk-allowed t)))
|
d@179
|
189 (cond
|
d@179
|
190 ((assoc "tuning" rules :test #'string=)
|
d@179
|
191 (setf current-tuning
|
d@179
|
192 (apply-tuning (cdr (assoc "tuning" rules :test #'string=))
|
d@179
|
193 current-tuning)))
|
d@182
|
194 ((or (assoc "tuning-named" rules :test #'string=)
|
d@182
|
195 (assoc "tuning_named" rules :test #'string=))
|
d@179
|
196 (setf current-tuning
|
d@182
|
197 (apply-tuning (cdr (assoc (string-downcase
|
d@182
|
198 (cdr (or (assoc "tuning-named"
|
d@182
|
199 rules :test #'string=)
|
d@182
|
200 (assoc "tuning_named"
|
d@182
|
201 rules :test #'string=))))
|
d@179
|
202 *tuning-names* :test #'string=))
|
d@179
|
203 current-tuning))))
|
d@179
|
204 (cond
|
d@182
|
205 ((or (assoc "bass-tuning" rules :test #'string=)
|
d@182
|
206 (assoc "bass_tuning" rules :test #'string=))
|
d@179
|
207 (setf current-tuning
|
d@182
|
208 (apply-tuning (cdr (or (assoc "bass-tuning" rules :test #'string=)
|
d@182
|
209 (assoc "bass_tuning" rules :test #'string=)))
|
d@182
|
210 current-tuning 6)))
|
d@182
|
211 ((or (assoc "bass-tuning-named" rules :test #'string=)
|
d@182
|
212 (assoc "bass_tuning_named" rules :test #'string=))
|
d@179
|
213 (setf current-tuning
|
d@182
|
214 (apply-tuning (cdr (assoc (string-downcase
|
d@182
|
215 (cdr (or (assoc "bass-tuning-named"
|
d@182
|
216 rules :test #'string=)
|
d@182
|
217 (assoc "bass_tuning_named"
|
d@182
|
218 rules :test #'string=))))
|
d@179
|
219 *tuning-names* :test #'string=))
|
d@179
|
220 current-tuning
|
d@179
|
221 6))))
|
d@179
|
222 current-tuning)
|
d@179
|
223
|
d@179
|
224 (defun apply-tuning (interval-string current-tuning &optional (start-course 1))
|
d@179
|
225 (do* ((pointer (1+ (or (position #\( interval-string)
|
d@179
|
226 -1))
|
d@179
|
227 (+ 1 pointer (length (princ-to-string interval))))
|
d@179
|
228 (course start-course (1+ course))
|
d@179
|
229 (interval (parse-integer interval-string :start pointer :junk-allowed t)
|
d@179
|
230 (parse-integer interval-string :start pointer :junk-allowed t)))
|
d@179
|
231 ((not interval) current-tuning)
|
d@179
|
232 (when (>= course (length current-tuning))
|
d@179
|
233 (setf current-tuning (adjust-array current-tuning (1+ course))))
|
d@179
|
234 (setf (aref current-tuning course) interval)))
|
d@179
|
235
|
d@179
|
236
|
d@179
|
237
|
c@43
|
238 #|
|
c@43
|
239 (in-package :clim-user)
|
c@43
|
240
|
c@43
|
241 (defvar *composition*)
|
c@43
|
242
|
c@43
|
243 (define-command (com-set-amuse-composition
|
c@43
|
244 :name t :command-table tabcode-syntax::tabcode-table)
|
c@43
|
245 ()
|
c@43
|
246 (let* ((window (esa:current-window))
|
c@43
|
247 (buffer (drei-buffer:buffer window))
|
c@43
|
248 (syntax (climacs::syntax buffer))
|
c@43
|
249 (tabwords (slot-value syntax 'tabcode-syntax::tabwords)))
|
c@43
|
250 (setq *composition* (amuse-tabcode::make-tabcode-composition tabwords))))
|
csr21@58
|
251
|
csr21@58
|
252 (define-command (com-amuse-play
|
csr21@58
|
253 :name t :command-table tabcode-syntax::tabcode-table)
|
csr21@58
|
254 ()
|
csr21@58
|
255 (let* ((window (esa:current-window))
|
csr21@58
|
256 (buffer (drei-buffer:buffer window))
|
csr21@58
|
257 (syntax (climacs::syntax buffer))
|
csr21@58
|
258 (tabwords (slot-value syntax 'tabcode-syntax::tabwords))
|
csr21@58
|
259 (composition (amuse-tabcode::make-tabcode-composition tabwords)))
|
csr21@58
|
260 ;; HACK: emulate background playing.
|
csr21@58
|
261 (sb-thread:make-thread (lambda () (amuse-utils:play composition)))))
|
csr21@58
|
262
|
csr21@58
|
263 (define-command (com-infer-key
|
csr21@58
|
264 :name t :command-table tabcode-syntax::tabcode-table)
|
csr21@58
|
265 ()
|
csr21@58
|
266 (let* ((window (esa:current-window))
|
csr21@58
|
267 (buffer (drei-buffer:buffer window))
|
csr21@58
|
268 (syntax (climacs::syntax buffer))
|
csr21@58
|
269 (tabwords (slot-value syntax 'tabcode-syntax::tabwords))
|
csr21@58
|
270 (composition (amuse-tabcode::make-tabcode-composition tabwords))
|
c@94
|
271 (result (amuse-harmony:krumhansl-key-finder composition composition))
|
csr21@58
|
272 (name (aref #("C" "C#" "D" "Eb" "E" "F" "F#" "G" "Ab" "A" "Bb" "B") (car result)))
|
csr21@58
|
273 (string (format nil "{<key>~A ~(~A~)</key>}~%" name (cadr result))))
|
csr21@58
|
274 (drei-buffer:insert-buffer-sequence buffer 0 string)))
|
csr21@55
|
275 |#
|