m@46
|
1 (cl:in-package #:amuse-mtp)
|
m@46
|
2
|
jeremy@329
|
3 ;;; Are we using cents to represent chromatc pitch, or MIDI values?
|
jeremy@329
|
4 ;;; A hack to allow backwards compatibility with old MIDI value databases.
|
jeremy@329
|
5 (defvar *cpitch-cents* t)
|
jeremy@329
|
6
|
m@46
|
7 ;;; Compositions
|
m@46
|
8
|
m@46
|
9 #.(clsql:locally-enable-sql-reader-syntax)
|
m@46
|
10
|
m@87
|
11 (defvar *event-attributes*
|
m@87
|
12 (list [dataset-id] [composition-id] [event-id]
|
jeremy@330
|
13 [onset] [dur] [deltast] [cpitch]
|
jeremy@328
|
14 [mpitch] [accidental] [keysig] [mode]
|
marcus@326
|
15 [barlength] [pulses] [phrase] [tempo] [dyn] [voice] [bioi]
|
marcus@326
|
16 [ornament] [comma] [articulation]))
|
m@87
|
17
|
m@53
|
18 (defgeneric get-dataset (identifer))
|
m@53
|
19
|
m@53
|
20 (defmethod get-dataset ((identifier mtp-dataset-identifier))
|
m@53
|
21 (let* ((dataset-id (dataset-id identifier))
|
m@53
|
22 (where-clause [= [dataset-id] dataset-id])
|
m@149
|
23 (db-dataset (car (clsql:select [*] :from [mtp-dataset] :where where-clause)))
|
marcus@326
|
24 (db-compositions (clsql:select [composition-id][description][timebase]
|
m@87
|
25 :from [mtp-composition]
|
m@87
|
26 :order-by '(([composition-id] :asc))
|
m@87
|
27 :where where-clause))
|
m@87
|
28 (db-events (apply #'clsql:select
|
m@87
|
29 (append *event-attributes*
|
m@87
|
30 (list :from [mtp-event]
|
m@87
|
31 :order-by '(([composition-id] :asc)
|
m@87
|
32 ([event-id] :asc))
|
m@87
|
33 :where where-clause))))
|
m@87
|
34 (dataset (make-mtp-dataset :dataset-id (first db-dataset)
|
m@87
|
35 :description (second db-dataset)
|
m@87
|
36 :timebase (third db-dataset)
|
m@87
|
37 :midc (fourth db-dataset)))
|
m@53
|
38 (compositions nil)
|
m@87
|
39 (events nil))
|
m@87
|
40 ;; for each db-composition
|
m@87
|
41 (dolist (dbc db-compositions)
|
marcus@326
|
42 (let ((composition-id (first dbc))
|
marcus@326
|
43 (description (second dbc))
|
marcus@326
|
44 (timebase (third dbc)))
|
m@87
|
45 ;; for each db-event
|
m@87
|
46 (do* ((dbes db-events (cdr dbes))
|
m@87
|
47 (dbe (car dbes) (car dbes))
|
m@87
|
48 (cid (second dbe) (second dbe)))
|
m@87
|
49 ((or (null dbes) (not (= cid composition-id)))
|
m@87
|
50 (setf db-events dbes))
|
m@87
|
51 (when dbe
|
marcus@326
|
52 (push (db-event->mtp-event dbe timebase) events)))
|
m@149
|
53 (when events
|
m@149
|
54 (let* ((interval (+ (timepoint (car events)) (duration (car events))))
|
m@149
|
55 (composition
|
m@149
|
56 (make-mtp-composition :dataset-id dataset-id
|
m@149
|
57 :composition-id composition-id
|
m@149
|
58 :description description
|
marcus@326
|
59 :timebase timebase
|
m@149
|
60 :time 0
|
m@149
|
61 :interval interval)))
|
m@149
|
62 (sequence:adjust-sequence composition (length events)
|
m@149
|
63 :initial-contents (nreverse events))
|
m@149
|
64 (setf events nil)
|
m@149
|
65 (push composition compositions)))))
|
m@53
|
66 (sequence:adjust-sequence dataset (length compositions)
|
m@53
|
67 :initial-contents (nreverse compositions))
|
m@53
|
68 dataset))
|
m@53
|
69
|
m@46
|
70 (defmethod get-composition ((identifier mtp-composition-identifier))
|
m@46
|
71 (let* ((dataset-id (dataset-id identifier))
|
m@46
|
72 (composition-id (composition-id identifier))
|
m@46
|
73 (where-clause [and [= [dataset-id] dataset-id]
|
m@46
|
74 [= [composition-id] composition-id]])
|
m@46
|
75 (description
|
m@51
|
76 (car (clsql:select [description] :from [mtp-composition]
|
m@46
|
77 :where where-clause :flatp t :field-names nil)))
|
marcus@326
|
78 (timebase
|
marcus@326
|
79 (car (clsql:select [timebase] :from [mtp-composition]
|
marcus@326
|
80 :where where-clause :flatp t :field-names nil)))
|
m@87
|
81 (db-events (apply #'clsql:select
|
m@87
|
82 (append *event-attributes*
|
m@87
|
83 (list :from [mtp-event]
|
m@87
|
84 :order-by '(([event-id] :asc))
|
m@87
|
85 :where where-clause))))
|
m@46
|
86 (events nil))
|
m@87
|
87 (dolist (e db-events)
|
marcus@326
|
88 (push (db-event->mtp-event e timebase) events))
|
m@46
|
89 (let* ((interval (+ (timepoint (car events)) (duration (car events))))
|
m@46
|
90 (composition
|
m@46
|
91 (make-mtp-composition :dataset-id dataset-id
|
m@46
|
92 :composition-id composition-id
|
m@46
|
93 :description description
|
marcus@326
|
94 :timebase timebase
|
m@46
|
95 :time 0
|
m@46
|
96 :interval interval)))
|
m@46
|
97 (sequence:adjust-sequence composition (length events)
|
m@46
|
98 :initial-contents (nreverse events))
|
m@46
|
99 composition)))
|
m@46
|
100
|
m@90
|
101 #.(clsql:restore-sql-reader-syntax-state)
|
m@90
|
102
|
marcus@326
|
103 (defun db-event->mtp-event (db-event timebase)
|
m@87
|
104 (let* ((slots ; the order must match *event-attributes*
|
jeremy@330
|
105 '(amuse::time amuse::interval deltast cpitch mpitch accidental
|
marcus@326
|
106 keysig mode barlength pulses phrase tempo dyn voice bioi
|
marcus@326
|
107 ornament comma articulation))
|
marcus@326
|
108 (time-slots '(amuse::time amuse::interval deltast barlength bioi))
|
m@46
|
109 (mtp-event
|
m@87
|
110 (make-mtp-event :dataset-id (first db-event)
|
m@87
|
111 :composition-id (second db-event)
|
m@87
|
112 :event-id (third db-event))))
|
m@87
|
113 (do* ((slts slots (cdr slts))
|
m@87
|
114 (db-atts (nthcdr 3 db-event) (cdr db-atts)))
|
m@87
|
115 ((null slts) mtp-event)
|
marcus@326
|
116 (if (member (car slts) time-slots :test #'eql)
|
marcus@326
|
117 (setf (slot-value mtp-event (car slts)) (convert-time-slot (car db-atts) timebase))
|
marcus@326
|
118 (setf (slot-value mtp-event (car slts)) (car db-atts))))))
|
marcus@326
|
119
|
marcus@326
|
120 (defun convert-time-slot (value timebase)
|
marcus@326
|
121 "Convert native representation of time into a representation where
|
marcus@326
|
122 a crotchet has a value of 96."
|
marcus@326
|
123 (if (or (null value) (null timebase))
|
marcus@326
|
124 nil
|
marcus@326
|
125 (let ((multiplier (/ 96 timebase)))
|
marcus@326
|
126 (* value multiplier))))
|
m@90
|
127
|
m@90
|
128 ;;; Monodies
|
m@90
|
129
|
m@90
|
130 (defmethod monody ((identifier mtp-composition-identifier))
|
m@90
|
131 (monody (get-composition identifier)))
|
m@90
|
132
|
m@90
|
133 (defmethod monody ((c mtp-composition))
|
m@292
|
134 ;; using the voice of the first event in the piece
|
m@90
|
135 (let ((monody (make-instance 'mtp-monody
|
m@90
|
136 :dataset-id (dataset-id c)
|
m@90
|
137 :composition-id (composition-id c)
|
m@90
|
138 :description (description c)
|
marcus@326
|
139 :timebase (composition-timebase c)
|
m@90
|
140 :time 0
|
m@90
|
141 :interval (duration c)))
|
m@90
|
142 (events nil)
|
m@292
|
143 (monody-voice nil))
|
m@90
|
144 (sequence:dosequence (event c)
|
m@292
|
145 (when (null monody-voice)
|
m@292
|
146 (setf monody-voice (%mtp-voice event)))
|
m@90
|
147 (when (= (%mtp-voice event) monody-voice)
|
m@90
|
148 (push event events)))
|
m@90
|
149 (sequence:adjust-sequence
|
m@90
|
150 monody (length events)
|
m@90
|
151 :initial-contents (sort events #'< :key #'amuse:timepoint))
|
m@90
|
152 monody))
|
m@46
|
153
|
marcus@326
|
154
|
m@46
|
155 ;;; Constituents from compositions: time-signatures
|
m@46
|
156
|
m@96
|
157 (defmethod crotchet ((dataset mtp-dataset))
|
d@136
|
158 (amuse:make-standard-period
|
m@96
|
159 (/ (dataset-timebase dataset) 4)))
|
m@87
|
160
|
marcus@326
|
161 (defmethod crotchet ((composition mtp-composition))
|
marcus@326
|
162 (amuse:make-standard-period
|
marcus@326
|
163 (/ (composition-timebase composition) 4)))
|
marcus@326
|
164
|
m@46
|
165 #.(clsql:locally-enable-sql-reader-syntax)
|
m@96
|
166 (defmethod crotchet ((event mtp-event))
|
m@96
|
167 (let ((timebase
|
marcus@326
|
168 (car (clsql:select [timebase] :from [mtp-composition]
|
marcus@326
|
169 :where [and [= [dataset-id] (dataset-id event)] [= [composition-id] (composition-id event)]]
|
m@96
|
170 :flatp t
|
m@96
|
171 :field-names nil))))
|
d@136
|
172 (amuse:make-standard-period (/ timebase 4))))
|
m@46
|
173 #.(clsql:restore-sql-reader-syntax-state)
|
m@46
|
174
|
m@69
|
175 (defmethod get-applicable-time-signatures ((e mtp-event) c)
|
m@69
|
176 (declare (ignore c))
|
m@291
|
177 ;(format t "~&GATS ~A ~A ~A: pulses = ~A; barlength = ~A.~%" (dataset-id e) (composition-id e) (event-id e) (%mtp-pulses e) (%mtp-barlength e))
|
m@291
|
178 (let* ((pulses (%mtp-pulses e))
|
m@291
|
179 (barlength (%mtp-barlength e))
|
m@291
|
180 (timebase (* 4 (duration (crotchet e))))
|
m@291
|
181 (numerator (if (null pulses) 0 pulses))
|
m@291
|
182 (denominator (if (null barlength)
|
m@291
|
183 1
|
m@291
|
184 (/ timebase (/ barlength pulses)))))
|
m@291
|
185 (list
|
m@291
|
186 (amuse:make-standard-time-signature-period numerator
|
m@291
|
187 denominator
|
d@136
|
188 (timepoint e)
|
d@136
|
189 (duration e)))))
|
m@69
|
190
|
m@46
|
191 (defmethod time-signatures ((c mtp-composition))
|
m@46
|
192 (let ((results nil)
|
m@46
|
193 (interval 0)
|
m@46
|
194 (current nil))
|
m@46
|
195 (sequence:dosequence (event c)
|
m@70
|
196 (let ((ts (car (get-applicable-time-signatures event c))))
|
m@46
|
197 (when (and (%mtp-barlength event)
|
m@46
|
198 (%mtp-pulses event)
|
m@46
|
199 (or (null current)
|
m@46
|
200 (not (time-signature-equal ts current))))
|
m@46
|
201 (unless (null current)
|
m@46
|
202 (setf (duration current) interval)
|
m@46
|
203 (push current results))
|
m@46
|
204 (setf interval 0
|
m@46
|
205 current ts)))
|
m@46
|
206 (incf interval (%mtp-deltast event))
|
m@46
|
207 (incf interval (duration event)))
|
m@46
|
208 (when current
|
m@46
|
209 (setf (duration current) interval)
|
m@46
|
210 (push current results))
|
m@46
|
211 (nreverse results)))
|
m@46
|
212
|
m@46
|
213 ;;; Constituents from compositions: key-signatures
|
m@46
|
214
|
m@69
|
215 (defmethod get-applicable-key-signatures ((e mtp-event) c)
|
m@69
|
216 (declare (ignore c))
|
m@69
|
217 (let* ((sharps (%mtp-keysig e))
|
m@68
|
218 (mode (%mtp-mode e))
|
m@69
|
219 (midi-mode (and mode (if (= mode 0) 0 1))))
|
d@136
|
220 (list (amuse:make-midi-key-signature-period sharps midi-mode
|
d@136
|
221 (timepoint e)
|
d@136
|
222 (duration e)))))
|
m@46
|
223
|
m@68
|
224 (defmethod key-signatures ((c mtp-composition))
|
m@46
|
225 (let ((results nil)
|
m@46
|
226 (interval 0)
|
m@46
|
227 (current nil))
|
m@46
|
228 (sequence:dosequence (event c)
|
m@69
|
229 (let ((ks (car (get-applicable-key-signatures event c))))
|
m@46
|
230 (when (and (%mtp-keysig event)
|
m@46
|
231 (%mtp-mode event)
|
m@46
|
232 (or (null current)
|
m@46
|
233 (not (key-signature-equal ks current))))
|
m@46
|
234 (unless (null current)
|
m@46
|
235 (setf (duration current) interval)
|
m@46
|
236 (push current results))
|
m@46
|
237 (setf interval 0
|
m@46
|
238 current ks)))
|
m@46
|
239 (incf interval (%mtp-deltast event))
|
m@46
|
240 (incf interval (duration event)))
|
m@46
|
241 (when current
|
m@46
|
242 (setf (duration current) interval)
|
m@46
|
243 (push current results))
|
m@46
|
244 (nreverse results)))
|
m@46
|
245
|
m@46
|
246 ;;; Constituents from compositions: tempi
|
m@46
|
247
|
m@69
|
248 (defmethod get-applicable-tempi ((e mtp-event) c)
|
m@69
|
249 (declare (ignore c))
|
d@136
|
250 (list (amuse:make-standard-tempo-period (%mtp-tempo e)
|
d@136
|
251 (timepoint e)
|
d@136
|
252 (duration e))))
|
m@69
|
253
|
m@46
|
254 (defmethod tempi ((c mtp-composition))
|
m@46
|
255 (let ((results nil)
|
m@46
|
256 (interval 0)
|
m@46
|
257 (current nil))
|
m@46
|
258 (sequence:dosequence (event c)
|
m@46
|
259 (when (and (%mtp-tempo event)
|
m@46
|
260 (or (null current)
|
m@46
|
261 (not (= (bpm current) (%mtp-tempo event)))))
|
m@46
|
262 (unless (null current)
|
m@46
|
263 (setf (duration current) interval)
|
m@46
|
264 (push current results))
|
m@69
|
265 (let ((new (car (get-applicable-tempi event c))))
|
m@46
|
266 (setf interval 0
|
m@46
|
267 current new)))
|
m@46
|
268 (incf interval (%mtp-deltast event))
|
m@46
|
269 (incf interval (duration event)))
|
m@46
|
270 (when current
|
m@46
|
271 (setf (duration current) interval)
|
m@46
|
272 (push current results))
|
m@46
|
273 (nreverse results)))
|
m@46
|
274
|
m@46
|
275 ;;; Events: Pitch
|
m@46
|
276
|
m@46
|
277 (defmethod chromatic-pitch ((e mtp-event))
|
m@46
|
278 (make-chromatic-pitch (%mtp-cpitch e)))
|
m@46
|
279
|
m@46
|
280 (defmethod midi-pitch-number ((e mtp-event))
|
m@46
|
281 (%mtp-cpitch e))
|
m@46
|
282
|
m@110
|
283 (defmethod diatonic-pitch-cp ((e mtp-event))
|
m@110
|
284 ;; MIPS morphetic pitch is relative to An0 while cpitch is relative to Cn2
|
jeremy@329
|
285 ;; Make sure MIDI value is used
|
jeremy@329
|
286 (- (if *cpitch-cents* (/ (%mtp-cpitch e) 100) (%mtp-cpitch e))
|
jeremy@329
|
287 21))
|
m@110
|
288
|
m@110
|
289 (defmethod diatonic-pitch-mp ((e mtp-event))
|
m@82
|
290 ;; MIPS morphetic pitch is relative to An0 while mpitch is relative to Cn2
|
m@82
|
291 (- (%mtp-mpitch e) 12))
|
m@82
|
292
|
m@46
|
293 (defmethod diatonic-pitch ((e mtp-event))
|
m@110
|
294 (make-mips-pitch (diatonic-pitch-cp e)
|
m@110
|
295 (diatonic-pitch-mp e)))
|
m@82
|
296
|
m@84
|
297 (defmethod asa-pitch-string ((e mtp-event))
|
m@110
|
298 (asa-pitch-string (diatonic-pitch e)))
|
m@84
|
299
|
m@82
|
300 #.(clsql:locally-enable-sql-reader-syntax)
|
m@82
|
301 (defmethod middle-c ((e mtp-event))
|
m@82
|
302 (let ((cpitch (car (clsql:select [midc] :from [dataset]
|
m@82
|
303 :where [= [dataset-id] (dataset-id e)]
|
m@82
|
304 :flatp t :field-names nil))))
|
m@82
|
305 (make-mtp-event :cpitch cpitch :mpitch (* (/ cpitch 12) 7))))
|
m@82
|
306 #.(clsql:restore-sql-reader-syntax-state)
|
m@79
|
307
|
m@79
|
308 ;;; Phrase boundaries
|
m@79
|
309
|
m@98
|
310 (defmethod ground-truth-segmenter-before ((c mtp-composition))
|
m@98
|
311 (declare (ignore c))
|
m@98
|
312 (make-instance 'mtp-before-segmenter))
|
m@98
|
313
|
m@98
|
314 (defmethod ground-truth-segmenter-after ((c mtp-composition))
|
m@98
|
315 (declare (ignore c))
|
m@99
|
316 (make-instance 'mtp-after-segmenter))
|
m@98
|
317
|
m@98
|
318 (defmethod ground-truth-segmenter-before ((e mtp-event))
|
m@98
|
319 (declare (ignore e))
|
m@98
|
320 (make-instance 'mtp-before-segmenter))
|
m@98
|
321
|
m@98
|
322 (defmethod ground-truth-segmenter-after ((e mtp-event))
|
m@98
|
323 (declare (ignore e))
|
m@99
|
324 (make-instance 'mtp-after-segmenter))
|
m@98
|
325
|
m@79
|
326 (defmethod boundary-strength ((s mtp-before-segmenter) (e mtp-event) c)
|
m@79
|
327 (declare (ignore s c))
|
m@79
|
328 (let ((phrase (%mtp-phrase e)))
|
m@79
|
329 (case phrase
|
m@79
|
330 (-1 1)
|
m@79
|
331 (t 0))))
|
m@79
|
332
|
m@79
|
333 (defmethod boundary-strength ((s mtp-after-segmenter) (e mtp-event) c)
|
m@79
|
334 (declare (ignore s c))
|
m@79
|
335 (let ((phrase (%mtp-phrase e)))
|
m@79
|
336 (case phrase
|
m@79
|
337 (1 1)
|
m@79
|
338 (t 0))))
|