annotate base/methods.lisp @ 266:d605fd37b0ee

fix mtp description again - return the string not '(string)
author Jamie Forth <j.forth@gold.ac.uk>
date Sun, 10 Apr 2011 18:28:27 +0100
parents 8e5f306b7e47
children 89c20fd8abc0
rev   line source
m@24 1 (cl:in-package #:amuse)
m@24 2
m@89 3 ;;; monody
m@89 4
m@143 5 (defmethod ensure-monody ((m standard-monody))
m@89 6 (let ((result t))
m@89 7 (dotimes (i (1- (length m)) result)
m@89 8 ;; assumes the events are time ordered which (since monody is a
m@89 9 ;; subclass of time-ordered-constituent) they ought to be.
m@89 10 (let ((e1 (elt m i))
m@89 11 (e2 (elt m (1+ i))))
m@89 12 (unless (or (before e1 e2) (meets e1 e2))
m@89 13 (setf result nil))))))
m@89 14
c@109 15 ;;; diatonic pitch (represented using MIPS)
m@81 16
c@109 17 (defmethod asa-pitch-string ((mp diatonic-pitch))
c@106 18 (mips:p-pn (list (%p-pc mp) (%p-pm mp))))
c@106 19
c@109 20 (defmethod diatonic-pitch-octave ((mp diatonic-pitch))
c@106 21 (let* ((asa-string (asa-pitch-string mp))
c@106 22 (start (position-if #'digit-char-p asa-string)))
c@106 23 (values (parse-integer asa-string :start start))))
m@86 24
c@109 25 (defmethod diatonic-pitch-accidental ((mp diatonic-pitch))
c@106 26 (let* ((asa-string (asa-pitch-string mp))
c@106 27 (start 1)
c@106 28 (end (position-if #'digit-char-p asa-string))
c@106 29 (malist '((#\n . 0) (#\s . +1) (#\f . -1)))
c@106 30 (multiplier (cdr (assoc (char asa-string 1) malist))))
c@106 31 (* multiplier (- end start))))
c@106 32
c@109 33 (defmethod diatonic-pitch-name ((mp diatonic-pitch))
c@106 34 (elt (asa-pitch-string mp) 0))
m@86 35
c@109 36 (defmethod middle-c ((mp diatonic-pitch))
j@187 37 (make-diatonic-pitch #\C 0 4))
m@81 38
c@109 39 (defmethod midi-pitch-number ((mp diatonic-pitch))
c@106 40 (+ (%p-pc mp) 21))
c@106 41
c@109 42 (defmethod octave ((mp diatonic-pitch))
c@106 43 (1- (floor (midi-pitch-number mp) 12)))
c@106 44
c@109 45 (defmethod diatonic-pitch ((mp diatonic-pitch))
m@81 46 mp)
m@81 47
c@109 48 (defmethod print-object ((o diatonic-pitch) stream)
c@106 49 (print-unreadable-object (o stream :type t)
c@106 50 (let ((asa-string (asa-pitch-string o)))
c@106 51 (write asa-string :stream stream))))
m@81 52
c@111 53 (defmethod asa-interval-string ((mpi diatonic-pitch-interval))
c@111 54 (mips:pi-pin (%diatonic-pitch-interval-span mpi)))
c@111 55
c@111 56 (defmethod print-object ((o diatonic-pitch-interval) stream)
c@111 57 (print-unreadable-object (o stream :type t)
c@111 58 (let ((asa-string (asa-interval-string o)))
c@111 59 (write asa-string :stream stream))))
c@111 60
m@81 61 ;;; Chromatic pitch
m@81 62
m@86 63 (defmethod octave ((cp chromatic-pitch))
c@106 64 (1- (floor (%chromatic-pitch-number cp) 12)))
m@86 65
m@81 66 (defmethod middle-c ((cp chromatic-pitch))
m@81 67 (make-chromatic-pitch 60))
m@81 68
d@136 69 (defmethod chromatic-pitch ((pitch chromatic-pitch))
d@136 70 pitch)
m@24 71
d@136 72 (defmethod midi-pitch-number ((pitch chromatic-pitch))
d@136 73 (%chromatic-pitch-number pitch))
m@24 74
d@136 75 (defmethod midi-pitch-number ((pitch pitch))
d@136 76 (%chromatic-pitch-number (chromatic-pitch pitch)))
m@24 77
m@113 78 (defmethod print-object ((o chromatic-pitch) stream)
m@113 79 (print-unreadable-object (o stream :type t)
m@113 80 (write (midi-pitch-number o) :stream stream)))
m@113 81
m@113 82 (defmethod print-object ((o chromatic-pitch-interval) stream)
m@113 83 (print-unreadable-object (o stream :type t)
m@113 84 (write (span o) :stream stream)))
m@113 85
m@113 86
d@136 87 (defmethod span ((pitch-interval chromatic-pitch-interval))
d@136 88 (%chromatic-pitch-interval-span pitch-interval))
m@24 89
d@136 90 (defmethod duration ((period standard-period))
d@136 91 (%period-interval period))
m@24 92
d@136 93 (defmethod (setf duration) ((value real) (period standard-period))
d@136 94 (setf (%period-interval period) value))
d@33 95
d@136 96 (defmethod timepoint ((moment standard-moment))
d@136 97 (%moment-time moment))
m@24 98
d@136 99 (defmethod (setf timepoint) ((value real) (moment standard-moment))
d@136 100 (setf (%moment-time moment) value))
d@33 101
d@136 102 (defmethod cut-off ((anchored-period standard-anchored-period))
d@136 103 (make-instance 'standard-moment
d@136 104 :time (+ (%moment-time anchored-period)
d@136 105 (%period-interval anchored-period))))
d@73 106
d@136 107 (defmethod print-object ((o standard-moment) stream)
m@113 108 (print-unreadable-object (o stream :type t)
m@113 109 (write (timepoint o) :stream stream)))
m@113 110
d@136 111 (defmethod print-object ((o standard-period) stream)
m@113 112 (print-unreadable-object (o stream :type t)
m@113 113 (write (duration o) :stream stream)))
m@113 114
d@136 115 (defmethod print-object ((o standard-anchored-period) stream)
m@126 116 (print-unreadable-object (o stream :type t)
m@126 117 (format stream "~A ~A" (timepoint o) (duration o))))
m@113 118
d@136 119 (defmethod beat-units-per-bar ((time-signature standard-time-signature))
m@24 120 (%basic-time-signature-numerator time-signature))
m@24 121
d@136 122 (defmethod beat-units ((time-signature standard-time-signature))
m@24 123 (%basic-time-signature-denominator time-signature))
m@24 124
d@136 125 (defmethod time-signature-equal ((ts1 standard-time-signature)
d@136 126 (ts2 standard-time-signature))
m@67 127 (let ((n1 (time-signature-numerator ts1))
m@67 128 (n2 (time-signature-numerator ts2))
m@67 129 (d1 (time-signature-denominator ts1))
m@67 130 (d2 (time-signature-denominator ts2)))
m@67 131 (and n1 n2 (= n1 n2)
m@67 132 d1 d2 (= d1 d2))))
m@67 133
d@136 134 (defmethod print-object ((sts standard-time-signature) stream)
d@136 135 (print-unreadable-object (sts stream :type t)
d@136 136 (format stream "~A/~A" (beat-units-per-bar sts) (beat-units sts))))
m@113 137
d@136 138 (defmethod key-signature-sharps ((key-signature standard-key-signature))
m@24 139 (%basic-key-signature-sharp-count key-signature))
m@24 140
m@45 141 (defmethod key-signature-mode ((ks midi-key-signature))
m@45 142 (%midi-key-signature-mode ks))
m@45 143
m@113 144 (defmethod print-object ((mks midi-key-signature) stream)
m@113 145 (print-unreadable-object (mks stream :type t)
m@113 146 (format stream "~A ~A"
m@113 147 (%basic-key-signature-sharp-count mks)
m@113 148 (%midi-key-signature-mode mks))))
m@113 149
d@136 150 (defmethod key-signature-equal ((ks1 standard-key-signature)
d@136 151 (ks2 standard-key-signature))
m@67 152 (let ((s1 (key-signature-sharps ks1))
m@67 153 (s2 (key-signature-sharps ks2)))
m@67 154 (and s1 s2 (= s1 s2))))
m@67 155
m@67 156 (defmethod key-signature-equal ((ks1 midi-key-signature)
m@67 157 (ks2 midi-key-signature))
m@67 158 (let ((s1 (key-signature-sharps ks1))
m@67 159 (s2 (key-signature-sharps ks2))
m@67 160 (m1 (key-signature-mode ks1))
m@67 161 (m2 (key-signature-mode ks2)))
m@67 162 (and s1 s2 (= s1 s2)
m@67 163 m1 m2 (= m1 m2))))
m@67 164
d@136 165 (defmethod bpm ((tempo standard-tempo))
m@24 166 (%tempo-bpm tempo))
m@24 167
j@260 168 (defmethod bps ((tempo standard-tempo))
j@260 169 (/ (%tempo-bpm tempo) 60))
j@260 170
d@136 171 (defmethod print-object ((tempo standard-tempo) stream)
m@113 172 (print-unreadable-object (tempo stream :type t)
m@113 173 (write (bpm tempo) :stream stream)))
m@113 174
m@67 175 (defmethod tempo-equal ((t1 tempo) (t2 tempo))
m@67 176 (and (bpm t1) (bpm t2) (= t1 t2)))
m@67 177
m@67 178
m@24 179 ;; Time protocol
m@24 180
d@136 181 (defmethod time+ ((moment standard-moment) (period standard-period))
d@136 182 "Returns a <standard-moment>. Implemented as a straightforward
d@121 183 summation."
d@136 184 (make-standard-moment (+ (timepoint moment) (duration period))))
m@24 185
d@136 186 (defmethod time+ ((period standard-period) (moment standard-moment)) ;?
d@136 187 "Returns a <standard-moment>. Implemented as a straightforward
d@136 188 summation and defined by default as (time+ <moment> <period>)."
d@137 189 (time+ moment period))
m@24 190
d@136 191 (defmethod time+ ((period1 standard-period)
d@136 192 (period2 standard-period))
d@136 193 "Returns a <standard-period>. Implemented as a straightforward
d@121 194 summation."
d@136 195 (make-standard-period (+ (duration period1)
d@136 196 (duration period2))))
m@24 197
d@136 198 (defmethod time+ ((moment1 moment) (moment2 moment))
d@121 199 "Returns <condition:undefined-action>. The question makes no
d@121 200 sense."
d@136 201 (error 'undefined-action :operation 'time+
d@137 202 :datatype (list (class-of moment1) (class-of moment2))))
m@24 203
d@136 204 (defmethod time- ((moment1 standard-moment) (moment2 standard-moment))
d@136 205 "Returns <standard-anchored-period> with an onset at moment2 and
d@136 206 extending to moment1"
d@136 207 (make-standard-anchored-period (timepoint moment2)
d@136 208 (- (timepoint moment1)
d@136 209 (timepoint moment2))))
m@24 210
d@136 211 (defmethod time- ((moment standard-moment) (period standard-period))
d@136 212 "Returns <standard-moment>. Simple subtraction."
d@136 213 (make-standard-moment (- (timepoint moment)
d@136 214 (duration period))))
m@24 215
d@136 216 (defmethod time- ((period period) (moment moment)) ;?
d@121 217 "Returns <condition:undefined-action>. The question makes no
d@121 218 sense"
m@24 219 (error 'undefined-action
m@24 220 :operation 'time-
d@137 221 :datatype (list (class-of period) (class-of moment))))
m@24 222
d@136 223 (defmethod time- ((period1 standard-period) (period2 standard-period))
d@136 224 "Returns <standard-period> spanning the difference of the
d@121 225 periods"
d@136 226 (make-standard-period (- (duration period2)
d@136 227 (duration period1))))
m@24 228
m@24 229 ;; these ones are less certain. I've just put them in, but think I
m@24 230 ;; should remove them and force the user to specify what they mean
m@24 231 ;; when they give objects that are both moments *and* periods to these
m@24 232 ;; functions.
m@24 233
m@24 234 (defmethod time- ((object1 anchored-period) (object2 anchored-period)) ;?
m@24 235 (time- (moment object1) (moment object2)))
m@24 236
m@24 237 (defmethod time- (object1 (object2 anchored-period)) ;?
m@24 238 (time- object1 (moment object2)))
m@24 239
m@24 240 (defmethod time- ((object1 anchored-period) object2) ;?
m@24 241 (time- (moment object1) object2))
m@24 242
m@24 243 (defmethod time> ((object1 moment) (object2 moment))
m@24 244 (> (timepoint object1) (timepoint object2)))
m@24 245
d@73 246 (defmethod time< ((object1 moment) (object2 moment))
d@73 247 (< (timepoint object1) (timepoint object2)))
d@73 248
m@24 249 (defmethod time= ((object1 moment) (object2 moment))
m@24 250 (= (timepoint object1) (timepoint object2)))
m@24 251
d@136 252 (defmethod duration> ((period1 standard-period) (period2 standard-period))
d@136 253 (> (duration period1) (duration period2)))
m@24 254
d@136 255 (defmethod duration= ((period1 standard-period) (period2 standard-period))
d@136 256 (= (duration period1) (duration period2)))
m@24 257
d@136 258 (defmethod duration* ((period1 standard-period) (object2 number))
d@137 259 (make-standard-period (* (duration period1) object2)))
m@24 260
d@136 261 (defmethod duration* ((object1 number) (period standard-period))
d@136 262 (duration* period object1))
m@24 263
d@136 264 (defmethod duration/ ((period standard-period) (object2 number))
d@137 265 (make-standard-period (/ (duration period) object2)))
m@24 266
c@111 267 ;;;; Pitch protocol
m@24 268
c@111 269 ;;; Some catch-all methods for undefined operations and cases where we
c@111 270 ;;; don't have enough information:
c@111 271 (macrolet ((def (name class1 class2)
c@111 272 `(defmethod ,name ((object1 ,class1) (object2 ,class2))
c@111 273 (error 'undefined-action :operation ',name
c@111 274 :datatype (list (class-of object1) (class-of object2))))))
d@136 275 (def pitch+ pitch pitch)
d@136 276 (def pitch- pitch-interval pitch))
m@24 277
c@111 278 (macrolet ((def (name class1 class2)
c@111 279 `(defmethod ,name ((object1 ,class1) (object2 ,class2))
c@111 280 (error 'insufficient-information :operation ',name
c@111 281 :datatype (list (class-of object1) (class-of object2))))))
d@136 282 (def pitch+ pitch pitch-interval)
d@136 283 (def pitch+ pitch-interval pitch)
d@136 284 (def pitch+ pitch-interval pitch-interval)
d@136 285 (def pitch- pitch pitch)
d@136 286 (def pitch- pitch pitch-interval)
d@136 287 (def pitch- pitch-interval pitch-interval))
m@24 288
c@111 289 ;;; chromatic pitch intervals
m@24 290
c@111 291 (defmethod pitch+ ((object1 chromatic-pitch)
c@111 292 (object2 chromatic-pitch-interval))
c@111 293 (make-chromatic-pitch (+ (midi-pitch-number object1) (span object2))))
c@111 294
c@111 295 (defmethod pitch+ ((object1 chromatic-pitch-interval)
c@111 296 (object2 chromatic-pitch))
c@111 297 (make-chromatic-pitch (+ (span object1) (midi-pitch-number object2))))
c@111 298
c@111 299 (defmethod pitch+ ((object1 chromatic-pitch-interval)
c@111 300 (object2 chromatic-pitch-interval))
c@105 301 (make-chromatic-pitch-interval (+ (span object1) (span object2))))
m@24 302
c@111 303 (defmethod pitch- ((object1 chromatic-pitch)
c@111 304 (object2 chromatic-pitch))
c@111 305 (make-chromatic-pitch-interval
c@105 306 (- (midi-pitch-number object1) (midi-pitch-number object2))))
m@24 307
c@111 308 (defmethod pitch- ((object1 chromatic-pitch)
c@111 309 (object2 chromatic-pitch-interval))
c@105 310 (make-chromatic-pitch (- (midi-pitch-number object1) (span object2))))
m@24 311
c@111 312 (defmethod pitch- ((object1 chromatic-pitch-interval)
c@111 313 (object2 chromatic-pitch-interval))
c@105 314 (make-chromatic-pitch-interval (- (span object1) (span object2))))
m@24 315
c@111 316 (defmethod pitch> ((object1 chromatic-pitch)
c@111 317 (object2 chromatic-pitch))
c@111 318 (> (midi-pitch-number object1) (midi-pitch-number object2)))
m@24 319
c@111 320 (defmethod pitch= ((object1 chromatic-pitch)
c@111 321 (object2 chromatic-pitch))
c@111 322 (= (midi-pitch-number object1) (midi-pitch-number object2)))
m@24 323
c@111 324 (defmethod interval> ((object1 chromatic-pitch-interval)
c@111 325 (object2 chromatic-pitch-interval))
c@111 326 (> (span object1) (span object2)))
m@24 327
c@111 328 (defmethod interval= ((object1 chromatic-pitch-interval)
c@111 329 (object2 chromatic-pitch-interval))
c@111 330 (= (span object1) (span object2)))
m@24 331
c@111 332 ;;; diatonic pitch intervals
m@24 333
c@111 334 (defmethod pitch+ ((object1 diatonic-pitch) (object2 diatonic-pitch-interval))
c@111 335 (let* ((cp (%p-pc object1))
c@111 336 (mp (%p-pm object1))
c@111 337 (span (span object2))
c@111 338 (cps (first span))
c@111 339 (mps (second span)))
c@111 340 (make-mips-pitch (+ cp cps) (+ mp mps))))
c@111 341
c@111 342 (defmethod pitch+ ((object1 diatonic-pitch-interval) (object2 diatonic-pitch))
c@111 343 (let* ((cp (%p-pc object2))
c@111 344 (mp (%p-pm object2))
c@111 345 (span (span object1))
c@111 346 (cps (first span))
c@111 347 (mps (second span)))
c@111 348 (make-mips-pitch (+ cp cps) (+ mp mps))))
c@111 349
c@111 350 (defmethod pitch+ ((object1 diatonic-pitch-interval)
c@111 351 (object2 diatonic-pitch-interval))
c@111 352 (let* ((span1 (span object1))
c@111 353 (span2 (span object2)))
c@111 354 (make-mips-pitch-interval (+ (first span1) (first span2))
c@111 355 (+ (second span1) (second span2)))))
c@111 356
c@111 357 (defmethod pitch- ((object1 diatonic-pitch) (object2 diatonic-pitch))
c@111 358 (let ((cp1 (%p-pc object1))
c@111 359 (mp1 (%p-pm object1))
c@111 360 (cp2 (%p-pc object2))
c@111 361 (mp2 (%p-pm object2)))
c@111 362 (make-mips-pitch-interval (- cp1 cp2) (- mp1 mp2))))
c@111 363
c@111 364 (defmethod pitch- ((object1 diatonic-pitch) (object2 diatonic-pitch-interval))
c@111 365 (let* ((cp (%p-pc object1))
c@111 366 (mp (%p-pm object1))
c@111 367 (span (span object2))
c@111 368 (cps (first span))
c@111 369 (mps (second span)))
c@111 370 (make-mips-pitch (- cp cps) (- mp mps))))
c@111 371
c@111 372 (defmethod pitch- ((object1 diatonic-pitch-interval)
c@111 373 (object2 diatonic-pitch-interval))
c@111 374 (let ((span1 (span object1))
c@111 375 (span2 (span object2)))
c@111 376 (make-mips-pitch-interval (- (first span1) (first span2))
c@111 377 (- (second span1) (second span2)))))
c@111 378
c@111 379 (defmethod pitch> ((p1 diatonic-pitch) (p2 diatonic-pitch))
c@111 380 (error 'undefined-action :operation 'pitch>
c@111 381 :datatype (list (class-of p1) (class-of p2))))
c@111 382
c@111 383 (defmethod pitch= ((p1 diatonic-pitch) (p2 diatonic-pitch))
c@111 384 (let ((c1 (%p-pc p1)) (m1 (%p-pm p1))
c@111 385 (c2 (%p-pc p2)) (m2 (%p-pm p2)))
c@111 386 (and c1 c2 (= c1 c2)
c@111 387 m1 m2 (= m1 m2))))
m@24 388
m@24 389
m@24 390 ;; Allen
m@24 391
m@24 392 (defmethod meets ((object1 anchored-period)
m@24 393 (object2 anchored-period))
m@24 394 (or (time= (cut-off object1) object2)
m@24 395 (time= (cut-off object2) object1)))
m@24 396
m@24 397 (defmethod before ((object1 anchored-period)
m@24 398 (object2 anchored-period))
m@24 399 (time> object2 (cut-off object1)))
m@24 400
m@24 401 (defmethod overlaps ((object1 anchored-period)
m@24 402 (object2 anchored-period))
m@24 403 ;; FIXME: Is there a tidier method?
m@24 404 (or (and (time> object2 object1) ; object1 starts before object2
m@24 405 (time> (cut-off object1) object2) ; object1 ends after object2 starts
m@24 406 (time> (cut-off object2) (cut-off object1))) ; object1 ends before object2 does
m@24 407 (and (time> object1 object2) ; object1 starts after object2
m@24 408 (time> (cut-off object2) object1) ; object1 starts before object2 ends
m@24 409 (time> (cut-off object1) (cut-off object2))))) ; object1 ends after object2 does
m@24 410
m@24 411 (defmethod during ((object1 anchored-period)
m@24 412 (object2 anchored-period))
j@205 413 (or (and (time> object1 object2)
j@205 414 (time<= (cut-off object1) (cut-off object2)))
j@205 415 (and (time>= object1 object2)
j@205 416 (time< (cut-off object1) (cut-off object2)))))
m@24 417
m@24 418 (defmethod starts ((object1 anchored-period)
m@24 419 (object2 anchored-period))
m@24 420 (time= object1 object2))
m@24 421
m@24 422 (defmethod ends ((object1 anchored-period)
m@24 423 (object2 anchored-period))
m@24 424 (time= (cut-off object1) (cut-off object2)))
m@24 425
j@261 426 ;; Does Allen cover this? Anyway, they are useful for me -JF.
j@261 427 (defmethod onset-within ((object1 moment)
j@261 428 (object2 standard-anchored-period))
j@261 429 (and (time>= object1 object2)
j@261 430 (time<= object1 (cut-off object2))))
j@261 431
j@261 432 (defmethod onset-within-fuzzy ((object1 moment)
j@261 433 (object2 standard-anchored-period)
j@261 434 (period standard-period))
j@261 435 (and (time>= object1 (time- (onset object2) period))
j@261 436 (time<= object1 (time- (cut-off object2) period))))
j@261 437
m@24 438 ;; ...and
m@24 439
d@33 440 (defmethod period= ((object1 anchored-period)
c@105 441 (object2 anchored-period))
d@33 442 (and (time= object1 object2)
d@33 443 (duration= object1 object2)))
d@136 444 (defmethod period= ((object1 period)
d@136 445 (object2 period))
d@33 446 (duration= object1 object2))
d@33 447
d@136 448 (defmethod period-intersection ((object1 standard-anchored-period)
d@136 449 (object2 standard-anchored-period))
m@24 450 (cond
m@24 451 ((disjoint object1 object2)
m@24 452 ;; if they don't overlap, return nil, not a negative-valued
m@24 453 ;; period
m@24 454 nil)
m@24 455 ((let* ((start (if (time> (onset object2) (onset object1))
m@24 456 (onset object2)
m@24 457 (onset object1)))
m@24 458 (duration (duration (time- (if (time> (cut-off object2) (cut-off object1))
m@24 459 (cut-off object1)
m@24 460 (cut-off object2))
m@24 461 start))))
m@24 462 (make-anchored-period (timepoint start) duration)))))
m@24 463
d@136 464 ;; Time constructors
d@136 465 (defmethod make-moment ((time-value real))
d@136 466 "Returns STANDARD-MOMENT given a real"
d@136 467 (make-standard-moment time-value))
d@136 468 (defmethod make-period ((duration-value real))
d@136 469 "Returns STANDARD-PERIOD given a real"
d@136 470 (make-standard-period duration-value))
d@136 471 (defmethod make-anchored-period ((onset-value real) (duration-value real))
d@136 472 "Returns STANDARD-ANCHORED-PERIOD given a real"
m@143 473 (make-standard-anchored-period onset-value duration-value))
d@151 474
d@151 475 ;; Needed by some sequence functions, notably remove-if.
d@151 476 (defmethod sequence:make-sequence-like :around ((o standard-composition) length
d@151 477 &key (initial-element nil iep)
d@151 478 (initial-contents nil icp))
d@152 479 "Around method for make-sequence-like, only with all slots
d@151 480 preserved from the source sequence (except onset and duration,
d@151 481 which are calculated afresh)."
d@151 482 (declare (ignore length initial-element initial-contents iep icp))
d@178 483 (let ((new-sequence (call-next-method)) (slot-name))
d@151 484 ;; Get timing information
d@153 485 (setf new-sequence (%recompute-standard-composition-period new-sequence))
d@153 486 (dolist (slotd (sb-mop:class-slots (class-of new-sequence)) new-sequence)
d@178 487 (setf slot-name (sb-mop:slot-definition-name slotd))
d@178 488 (unless (or (equal slot-name '%data)
d@178 489 (equal slot-name 'time)
d@178 490 (equal slot-name 'interval)
d@178 491 (not (slot-boundp o slot-name)))
d@153 492 (setf (sb-mop:slot-value-using-class (class-of new-sequence)
d@153 493 new-sequence
d@153 494 slotd)
d@153 495 (sb-mop:slot-value-using-class (class-of new-sequence)
d@153 496 o ;; if this isn't the same, we're lost anyway
d@153 497 slotd))))))
d@153 498
d@153 499 (defun %recompute-standard-composition-period (composition)
d@153 500 "Find onset and duration times for newly-made composition object."
d@153 501 (let ((start) (finish))
d@153 502 (sequence:dosequence (element composition)
d@151 503 ;; Actually, this next bit is pretty stupid - I know this is
d@151 504 ;; ordered, so this bit could be replaced by
d@151 505 ;; (setf (timepoint new-sequence)
d@151 506 ;; (timepoint (elt new-sequence 0)))
d@151 507 ;; outside of the loop.
d@152 508 (when (and element
d@152 509 (or (null start)
d@152 510 (< (timepoint element) start)))
d@152 511 (setf start (timepoint element)))
d@152 512 (when (and element
d@152 513 (or (null finish)
d@152 514 (> (timepoint (cut-off element))
d@152 515 finish)))
d@152 516 (setf finish (timepoint (cut-off element)))))
d@152 517 (unless start
d@152 518 (setf start 0))
d@152 519 (unless finish
d@152 520 (setf finish 0))
d@153 521 (setf (timepoint composition) start
d@153 522 (duration composition) (- finish start))
d@153 523 composition))
d@153 524
d@153 525
d@153 526 (defmethod sequence:adjust-sequence :around ((o standard-composition) length
d@153 527 &key initial-element
d@153 528 (initial-contents nil icp))
d@153 529 (declare (ignore length o initial-element initial-contents icp))
d@175 530 (%recompute-standard-composition-period (call-next-method)))
d@175 531
j@193 532 (defmethod get-constituents ((identifier composition-identifier))
j@193 533 (list (get-composition identifier)))
d@175 534
d@175 535 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
d@175 536 ;;
d@175 537 ;; Experimental:
d@175 538 ;;
d@175 539
d@175 540 ;; Some not obviously correct implementations of the new metre
d@175 541 ;; functions. These are no worse than we're already using (they should
d@175 542 ;; be more or less equivalent)
d@175 543
d@175 544 (defmethod bar-period ((time-signature standard-time-signature)
d@175 545 object)
d@175 546 (make-standard-period (* (duration (crotchet object))
d@175 547 (time-signature-numerator time-signature)
d@175 548 (/ 4 (time-signature-denominator time-signature)))))
d@175 549
d@175 550 (defmethod current-bar ((moment standard-moment) (composition composition))
d@175 551 (let* ((time-sig (car (get-applicable-time-signatures
d@175 552 (make-standard-anchored-period (timepoint moment)
d@175 553 (duration (crotchet composition)))
d@175 554 composition)))
d@175 555 (bar-duration (bar-period time-sig composition)))
d@175 556 (do* ((start (onset time-sig) next-start)
d@175 557 (next-start (time+ start bar-duration) (time+ start bar-duration)))
d@175 558 ((time> next-start moment)
d@175 559 (make-standard-anchored-period (timepoint start)
d@175 560 (duration bar-duration))))))
d@175 561
j@233 562 (defmethod ioi-from-bar ((event event))
j@258 563 "Within-short-bar-p here is for catching anacruses. The correct IOI
j@258 564 of the event(s) from the barline can be calculated by finding the
j@258 565 corresponding position of timepoint 0 relative to the bar, and then
j@258 566 calculating the event IOI relative to that. FIXME: This will almost
j@258 567 certainly not be the desired behaviour if 'short bars' are found
j@258 568 within a piece. Also, what about 'long bars'? Also, more generally,
j@258 569 what should we do if get-app-time-sig gives us multiple
j@258 570 time-signatures? We should at least be checking."
j@258 571 (cond
j@258 572 ((within-short-bar-p event)
j@258 573 (+ (timepoint (onset event))
j@258 574 (- (duration (bar-period (car (get-applicable-time-signatures
j@258 575 event (composition event)))
j@258 576 event))
j@258 577 (duration (current-bar event (composition event))))))
j@258 578 (t
j@258 579 (- (timepoint (onset event))
j@258 580 (timepoint (current-bar event (composition event)))))))
j@233 581
j@233 582 (defmethod ioi-from-bar ((constituent constituent))
j@258 583 "FIXME: Check for short bars, or maybe just use the first event?"
j@233 584 (- (timepoint (onset constituent))
j@233 585 (timepoint (current-bar constituent constituent))))
j@233 586
j@233 587 (defmethod onset-in-bar ((o moment))
j@250 588 "FIXME: Won't actually work for standard-moments because they do not
j@250 589 have a composition slot! So either we allow for 'linked moments', or
j@250 590 change the method to have an optional composition parameter."
j@233 591 (1+ (ioi-from-bar o)))
j@233 592
j@250 593 (defmethod onset-in-bar-relative-to-tactus ((o moment))
j@250 594 (1+ (/ (ioi-from-bar o)
j@250 595 (tactus-duration
j@250 596 (car (get-applicable-time-signatures o (composition o)))))))
j@250 597
j@258 598 (defmethod within-short-bar-p ((event linked-event))
j@258 599 (let ((time-sig (get-applicable-time-signatures event
j@258 600 (composition event))))
j@258 601 (assert (= (length time-sig) 1))
j@258 602 (setf time-sig (car time-sig))
j@258 603 (let ((bar-duration (bar-period time-sig (composition event)))
j@258 604 (current-bar (current-bar event (composition event))))
j@258 605 (duration< current-bar bar-duration))))
j@258 606
d@175 607 (defmethod beat-period ((moment standard-moment)
d@175 608 (time-signature standard-time-signature)
d@175 609 (composition composition))
d@175 610 ;; Simple example - standard-time-signature has constant tactus
d@175 611 (let* ((containing-bar (current-bar moment composition))
d@175 612 (beat-duration (* (duration (crotchet composition))
d@175 613 (tactus-duration time-signature)))
d@175 614 (beat-period (make-standard-anchored-period (timepoint containing-bar)
d@175 615 beat-duration)))
d@175 616 (do ()
d@175 617 ((time> (cut-off beat-period) moment) beat-period)
d@175 618 (setf (timepoint beat-period) (timepoint (cut-off beat-period))))))
d@175 619
d@175 620 (defmethod current-beat ((moment standard-moment) (composition composition))
d@175 621 ;; Assume at most one time signature per bar (otherwise, this is hell)
d@175 622 (let* ((time-sig (car (get-applicable-time-signatures (current-bar moment composition) composition))))
d@175 623 (if time-sig
d@175 624 (beat-period moment time-sig composition)
d@175 625 ;; If no time-sig, there's no way of answering this
d@175 626 ;; directly. There may be sensible defaults, but it's the job
d@175 627 ;; of an implementation's author to solve that.
d@175 628 (error 'insufficient-information :operation 'beat-period :datatype (class-of composition)))))
d@175 629
j@208 630
j@245 631 ;;;=====================================================================
j@230 632 ;;; Copying events in time
j@245 633 ;;;=====================================================================
j@208 634
j@208 635 (defmethod move-to-first-bar ((composition composition))
j@226 636 (let ((offset (floor (timepoint (elt composition 0)))))
j@208 637 (loop
j@209 638 for event in (%list-slot-sequence-data composition)
j@208 639 do (setf event (copy-event event))
j@208 640 do (setf (timepoint event)
j@208 641 (- (timepoint event) offset))
j@208 642 collect event into shifted-events
j@259 643 finally (return
j@259 644 (sequence:make-sequence-like
j@259 645 composition
j@259 646 (length composition)
j@259 647 :initial-contents shifted-events)))))
j@230 648
j@230 649
j@245 650 ;;;=====================================================================
j@230 651 ;;; Searching for events
j@245 652 ;;;=====================================================================
j@230 653
j@230 654 (defmethod find-next-event ((source-event event) &key predicate test
j@230 655 break-test search-list)
j@230 656 "Ideally a sorted search list that begins with the first event after
j@230 657 the source-event should be provided, otherwise, the search will begin
j@230 658 from the beginning."
j@230 659 (unless search-list (setf search-list (composition source-event)))
j@230 660 (cond
j@230 661 ((and test predicate)
j@230 662 (error "Supplied both a test and a predicate."))
j@230 663 (test
j@230 664 (sequence:dosequence (e search-list nil)
j@230 665 (when (and (time> (onset e) (onset source-event))
j@230 666 (funcall test source-event e))
j@230 667 (return e))
j@230 668 (when break-test
j@230 669 (when (funcall break-test source-event e)
j@230 670 (return nil)))))
j@230 671 (predicate
j@230 672 (sequence:dosequence (e search-list nil)
j@230 673 (when (and (time> (onset e) (onset source-event))
j@230 674 (funcall predicate e))
j@230 675 (return e))
j@230 676 (when break-test
j@230 677 (when (funcall break-test source-event e)
j@230 678 (return nil)))))))
j@230 679
j@230 680
j@245 681 ;;;=====================================================================
j@230 682 ;;; Sorting Compositions
j@245 683 ;;;=====================================================================
j@230 684
j@230 685 (defmethod event< ((event1 event) (event2 event) attribute-list)
j@230 686 (dolist (attribute attribute-list nil) ;nil if equal
j@230 687 (if (< (funcall attribute event1) (funcall attribute event2))
j@230 688 (return t)
j@230 689 (if (> (funcall attribute event1) (funcall attribute event2))
j@230 690 (return nil)))))
j@230 691
j@230 692 (defun make-event< (attribute-list)
j@230 693 (lambda (event1 event2)
j@230 694 (funcall #'event< event1 event2 attribute-list)))
j@230 695
j@230 696 (defmethod sort-composition ((composition composition) dimension-spec)
j@230 697 (sequence:make-sequence-like composition
j@230 698 (length composition)
j@230 699 :initial-contents
j@230 700 (stable-sort
j@230 701 (copy-seq composition)
j@230 702 (make-event< dimension-spec))))