Basic undo implemented for simple operations.
[gsharp.git] / melody.lisp
blob54e80c68d52cd22d679fc0b5d7f6b3fdce45fb14
1 (in-package :gsharp-buffer)
3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4 ;;;
5 ;;; Clef
7 ;;; The line number on which the clef is located on the staff.
8 ;;; The bottom line of the staff is number 1.
9 (defgeneric lineno (clef))
11 ;;; for key signature drawing calcluations. FIXME: in fact the layout
12 ;;; of key signatures isn't the same across all clefs.
13 (defgeneric b-position (clef))
14 (defgeneric f-position (clef))
16 ;;; the note number of the bottom line of this clef.
17 (defgeneric bottom-line (clef))
19 (defclass clef (staffwise-element gsharp-object name-mixin)
20 ((lineno :reader lineno :initarg :lineno
21 :type (or (integer 0 8) null))))
23 (defun make-clef (name &key lineno)
24 (declare (type (member :treble :treble8 :bass :c :percussion) name)
25 (type (or (integer 0 8) null) lineno))
26 (when (null lineno)
27 (setf lineno
28 (ecase name
29 ((:treble :treble8) 2)
30 (:bass 6)
31 (:c 4)
32 (:percussion 3))))
33 (make-instance 'clef :name name :lineno lineno))
35 (defmethod slots-to-be-saved append ((c clef))
36 '(lineno))
38 (defun read-clef-v3 (stream char n)
39 (declare (ignore char n))
40 (apply #'make-instance 'clef (read-delimited-list #\] stream t)))
42 (set-dispatch-macro-character #\[ #\K
43 #'read-clef-v3
44 *gsharp-readtable-v3*)
46 ;;; given a clef, return the staff step of the B that should have
47 ;;; the first flat sign in key signatures with flats
48 (defmethod b-position ((clef clef))
49 (ecase (name clef)
50 (:bass (- (lineno clef) 4))
51 ((:treble :treble8) (+ (lineno clef) 2))
52 (:c (- (lineno clef) 1))))
55 ;;; given a clef, return the staff step of the F that should have
56 ;;; the first sharp sign in key signatures with sharps
57 (defmethod f-position ((clef clef))
58 (ecase (name clef)
59 (:bass (lineno clef))
60 ((:treble :treble8) (+ (lineno clef) 6))
61 (:c (+ (lineno clef) 3))))
63 (defmethod bottom-line ((clef clef))
64 (- (ecase (name clef)
65 (:treble 32)
66 (:bass 24)
67 (:c 28)
68 (:treble8 25))
69 (lineno clef)))
71 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
72 ;;;
73 ;;; Fiveline staff
75 (defgeneric clef (fiveline-staff))
77 (defclass fiveline-staff (staff)
78 ((clef :accessor clef :initarg :clef :initform (make-clef :treble))
79 (%keysig :accessor keysig :initarg :keysig
80 :initform (make-array 7 :initial-element :natural))
81 (staffwise-elements :accessor staffwise-elements :initform nil)))
83 (defgeneric key-signatures (staff)
84 (:method ((s fiveline-staff))
85 (remove-if #'(lambda (x) (not (typep x 'key-signature)))
86 (staffwise-elements s))))
87 (defgeneric time-signatures (staff)
88 (:method ((s fiveline-staff))
89 (remove-if #'(lambda (x) (not (typep x 'time-signature)))
90 (staffwise-elements s))))
92 (defmethod initialize-instance :after ((obj fiveline-staff) &rest args)
93 (declare (ignore args))
94 (with-slots (%keysig) obj
95 (when (vectorp %keysig)
96 (setf %keysig
97 (make-instance 'key-signature :staff obj :alterations %keysig)))))
99 (defun make-fiveline-staff (&rest args &key name clef keysig)
100 (declare (ignore name clef keysig))
101 (apply #'make-instance 'fiveline-staff args))
103 (defmethod slots-to-be-saved append ((s fiveline-staff))
104 '(clef %keysig))
106 (defun read-fiveline-staff-v3 (stream char n)
107 (declare (ignore char n))
108 (apply #'make-instance 'fiveline-staff (read-delimited-list #\] stream t)))
110 (set-dispatch-macro-character #\[ #\=
111 #'read-fiveline-staff-v3
112 *gsharp-readtable-v3*)
114 (defgeneric set-contents (element contents)
115 (:documentation "Sets note in an element"))
119 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
121 ;;; Note
123 ;;; Notes are immutable objets. If you want to alter (say) the staff
124 ;;; or the pitch of a note, you have to delete it and add a new note
125 ;;; with the right characteristics.
127 ;;; Return the pitch of the note.
128 (defgeneric pitch (note))
130 ;;; Return the accidentals of the note. The value returned is one of
131 ;;; :natural :flat :double-flat :sharp or :double-sharp.
132 (defgeneric accidentals (note))
134 ;;; Return a non-negative integer indicating the number of dots of the
135 ;;; note. The value nil is returned whenever the note takes its
136 ;;; number of dots from the cluster to which it belongs.
137 (defgeneric dots (note))
139 ;;; Returns the cluster to which the note belongs, or nil if the note
140 ;;; currently does not belong to any cluster.
141 (defgeneric cluster (note))
143 ;;; The pitch is a number from 0 to 128
144 ;;;
145 ;;; The staff is a staff object.
146 ;;;
147 ;;; Head can be :long, :breve, :whole, :half, :filled, or nil. A
148 ;;; value of nil means that the notehead is determined by that of the
149 ;;; cluster to which the note belongs.
150 ;;;
151 ;;; Accidentals can be :natural :flat :double-flat :sharp or :double-sharp.
152 ;;; The default is :natural. Whether a note is actually displayed
153 ;;; preceded by one of the corresponding signs is a matter of context and
154 ;;; display style.
155 ;;;
156 ;;; The number of dots can be an integer or nil, meaning that the number
157 ;;; of dots is taken from the cluster. The default value is nil.
158 ;;;
159 ;;; The actual duration of the note is computed from the note head, the
160 ;;; number of beams of the cluster to which the note belongs, and the
161 ;;; number of dots in the usual way.
163 (defclass note (gsharp-object)
164 ((cluster :initform nil :initarg :cluster :accessor cluster)
165 (pitch :initarg :pitch :reader pitch :type (integer 0 127))
166 (staff :initarg :staff :reader staff :type staff)
167 (head :initform nil :initarg :head :reader head
168 :type (or (member :long :breve :whole :half :filled) null))
169 (accidentals :initform :natural :initarg :accidentals :reader accidentals
170 ;; FIXME: we want :TYPE ACCIDENTAL here but need to
171 ;; sort out order of definition for that to be useful.
172 #+nil #+nil
173 :type (member :natural :flat :double-flat :sharp :double-sharp))
174 (dots :initform nil :initarg :dots :reader dots
175 :type (or (integer 0 3) null))
176 (%tie-right :initform nil :initarg :tie-right :accessor tie-right)
177 (%tie-left :initform nil :initarg :tie-left :accessor tie-left)))
179 (defun make-note (pitch staff &rest args &key head (accidentals :natural) dots)
180 (declare (type (integer 0 127) pitch)
181 (type staff staff)
182 (type (or (member :long :breve :whole :half :filled) null) head)
183 ;; FIXME: :TYPE ACCIDENTAL
184 #+nil #+nil
185 (type (member :natural :flat :double-flat :sharp :double-sharp)
186 accidentals)
187 (type (or (integer 0 3) null) dots)
188 (ignore head accidentals dots))
189 (apply #'make-instance 'note :pitch pitch :staff staff args))
191 (defmethod slots-to-be-saved append ((n note))
192 '(pitch staff head accidentals dots %tie-right %tie-left))
194 (defun read-note-v3 (stream char n)
195 (declare (ignore char n))
196 (apply #'make-instance 'note (read-delimited-list #\] stream t)))
198 (set-dispatch-macro-character #\[ #\N
199 #'read-note-v3
200 *gsharp-readtable-v3*)
202 ;;; Return true if note1 is considered less than note2.
203 (defun note-less (note1 note2)
204 (< (pitch note1) (pitch note2)))
206 ;;; Return true if note1 is considered equal to note2.
207 (defun note-equal (note1 note2)
208 (= (pitch note1) (pitch note2)))
211 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
213 ;;; Tuning (support for microtonal and historical tunings/temperaments)
215 ;;; FIXME: add name-mixin also?
216 (defclass tuning (gsharp-object)
217 ((master-pitch-note :initform (make-instance 'note :pitch 33 ; a above middle c
218 :staff (make-instance 'staff))
219 :initarg :master-pitch-note
220 :type note
221 :accessor master-pitch-note)
222 (master-pitch-freq :initform 440
223 :initarg :master-pitch-freq
224 :accessor master-pitch-freq)))
226 (defmethod slots-to-be-saved append ((tuning tuning))
227 '(master-pitch-note master-pitch-freq))
229 ;;; Returns how a note should be tuned in a given tuning
230 ;;; in terms of a cent value.
231 (defgeneric note-cents (note tuning))
233 ;;; 12-edo is provided for efficiency only. It is a
234 ;;; special case of a regular temperament. Perhaps it
235 ;;; should be removed?
236 (defclass 12-edo (tuning)
239 (defmethod slots-to-be-saved append ((tuning 12-edo))
240 '())
242 (defmethod note-cents ((note note) (tuning 12-edo))
243 (multiple-value-bind (octave pitch) (floor (pitch note) 7)
244 (+ (* 1200 (1+ octave))
245 (ecase pitch (0 0) (1 200) (2 400) (3 500) (4 700) (5 900) (6 1100))
246 (ecase (accidentals note)
247 (:double-flat -200)
248 (:sesquiflat -150)
249 (:flat -100)
250 (:semiflat -50)
251 (:natural 0)
252 (:semisharp 50)
253 (:sharp 100)
254 (:sesquisharp 150)
255 (:double-sharp 200)))))
257 ;;; regular temperaments are temperaments that
258 ;;; retain their interval sizes regardless of modulation, as opposed to
259 ;;; irregular temperaments.
260 (defclass regular-temperament (tuning)
261 ((octave-cents :initform 1200 :initarg :octave-cents :accessor octave-cents)
262 (fifth-cents :initform 700 :initarg :fifth-cents :accessor fifth-cents)
263 (quartertone-cents :initform 50 :initarg :quartertone-cents :accessor quartertone-cents)
264 ;; TODO: Add cent sizes of various microtonal accidentals, perhaps in an alist?
267 (defmethod slots-to-be-saved append ((tuning regular-temperament))
268 '(octave-cents fifth-cents))
270 (defmethod note-cents ((note note) (tuning regular-temperament))
271 (let ((octaves 1)
272 (fifths 0)
273 (sharps 0) ;; short for 7 fifths up and 4 octaves down
274 (quartertones 0))
275 (incf octaves (floor (pitch note) 7))
276 (ecase (mod (pitch note) 7)
277 (0 (progn))
278 (1 (progn (incf octaves -1) (incf fifths 2)))
279 (2 (progn (incf octaves -2) (incf fifths 4)))
280 (3 (progn (incf octaves 1) (incf fifths -1)))
281 (4 (progn (incf fifths 1)))
282 (5 (progn (incf octaves -1) (incf fifths 3)))
283 (6 (progn (incf octaves -2) (incf fifths 5))))
284 (ecase (accidentals note)
285 (:double-flat (incf sharps -2))
286 (:sesquiflat (incf sharps -1) (incf quartertones -1))
287 (:flat (incf sharps -1))
288 (:semiflat (incf quartertones -1))
289 (:natural)
290 (:semisharp (incf quartertones 1))
291 (:sharp (incf sharps 1))
292 (:sesquisharp (incf sharps 1) (incf quartertones 1))
293 (:double-sharp (incf sharps 2)))
294 (incf octaves (* -4 sharps))
295 (incf fifths (* 7 sharps))
296 (+ (* octaves (octave-cents tuning))
297 (* fifths (fifth-cents tuning))
298 (* quartertones (quartertone-cents tuning)))))
300 ;;; TODO: (defclass irregular-temperament ...)
302 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
304 ;;; Melody element
306 (defclass melody-element (rhythmic-element) ())
308 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
310 ;;; Key signature
312 (defgeneric alterations (key-signature)
313 (:documentation "return the alterations in the form of a
314 7-element array where each element is either :natural,
315 :sharp, or :flat according to how each staff position
316 should be altered"))
318 (defgeneric more-sharps (key-signature &optional n)
319 (:documentation "make the key signature N alterations
320 sharper by removing some flats and/or adding some sharps"))
322 (defgeneric more-flats (key-signature &optional n)
323 (:documentation "make the key signature N alterations
324 flatter by removing some sharps and/or adding some flats"))
326 (defclass staffwise-element (element)
327 ((%staff :initarg :staff :reader staff)))
328 (defmethod slots-to-be-saved append ((s-e staffwise-element))
329 '(%staff))
331 (defclass key-signature (staffwise-element)
332 ((%alterations :initform (make-array 7 :initial-element :natural)
333 :initarg :alterations :reader alterations)))
335 (defun make-key-signature (staff &rest args &key alterations)
336 (declare (type (or null (simple-vector 7)) alterations)
337 (ignore alterations))
338 (apply #'make-instance 'key-signature :staff staff args))
340 (defmethod slots-to-be-saved append ((k key-signature))
341 '(%alterations))
343 (defmethod more-sharps ((sig key-signature) &optional (n 1))
344 (let ((alt (alterations sig)))
345 (loop repeat n
346 do (cond ((eq (aref alt 3) :flat) (setf (aref alt 3) :natural))
347 ((eq (aref alt 0) :flat) (setf (aref alt 0) :natural))
348 ((eq (aref alt 4) :flat) (setf (aref alt 4) :natural))
349 ((eq (aref alt 1) :flat) (setf (aref alt 1) :natural))
350 ((eq (aref alt 5) :flat) (setf (aref alt 5) :natural))
351 ((eq (aref alt 2) :flat) (setf (aref alt 2) :natural))
352 ((eq (aref alt 6) :flat) (setf (aref alt 6) :natural))
353 ((eq (aref alt 3) :natural) (setf (aref alt 3) :sharp))
354 ((eq (aref alt 0) :natural) (setf (aref alt 0) :sharp))
355 ((eq (aref alt 4) :natural) (setf (aref alt 4) :sharp))
356 ((eq (aref alt 1) :natural) (setf (aref alt 1) :sharp))
357 ((eq (aref alt 5) :natural) (setf (aref alt 5) :sharp))
358 ((eq (aref alt 2) :natural) (setf (aref alt 2) :sharp))
359 ((eq (aref alt 6) :natural) (setf (aref alt 6) :sharp))))))
361 (defmethod more-flats ((sig key-signature) &optional (n 1))
362 (let ((alt (alterations sig)))
363 (loop repeat n
364 do (cond ((eq (aref alt 6) :sharp) (setf (aref alt 6) :natural))
365 ((eq (aref alt 2) :sharp) (setf (aref alt 2) :natural))
366 ((eq (aref alt 5) :sharp) (setf (aref alt 5) :natural))
367 ((eq (aref alt 1) :sharp) (setf (aref alt 1) :natural))
368 ((eq (aref alt 4) :sharp) (setf (aref alt 4) :natural))
369 ((eq (aref alt 0) :sharp) (setf (aref alt 0) :natural))
370 ((eq (aref alt 3) :sharp) (setf (aref alt 3) :natural))
371 ((eq (aref alt 6) :natural) (setf (aref alt 6) :flat))
372 ((eq (aref alt 2) :natural) (setf (aref alt 2) :flat))
373 ((eq (aref alt 5) :natural) (setf (aref alt 5) :flat))
374 ((eq (aref alt 1) :natural) (setf (aref alt 1) :flat))
375 ((eq (aref alt 4) :natural) (setf (aref alt 4) :flat))
376 ((eq (aref alt 0) :natural) (setf (aref alt 0) :flat))
377 ((eq (aref alt 3) :natural) (setf (aref alt 3) :flat))))))
379 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
381 ;;; Time signature
382 ;; * no make function (no type checking)
383 ;; * slots-to-be-saved only 'cos it's there
384 ;; * What accessors do we need (if any)?
385 ;; * Should I copy the (keysig) functionality from gui.lisp?
387 (defclass time-signature (staffwise-element)
388 ((%components :initarg :components :reader time-signature-components
389 :initform nil)))
390 (defmethod slots-to-be-saved append ((t-s time-signature))
391 '(%components))
392 (defun make-time-signature (staff &rest args)
393 (apply #'make-instance 'time-signature :staff staff args))
395 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
397 ;;; Cluster
399 ;;; Return a list of the notes of the cluster
400 (defgeneric notes (cluster))
402 ;;; Add a note to the cluster. It is an error if there is already a
403 ;;; note in the cluster with the same staff and the same pitch.
404 (defgeneric add-note (cluster note))
406 ;;; Find a note in a cluster. The comparison is made using only the
407 ;;; pitch of the supplied note. If the note does not exist nil is returned.
408 (defgeneric find-note (cluster note))
410 ;;; Delete a note from the cluster to which it belongs. It is an
411 ;;; error to call this function if the note currently does not belong
412 ;;; to any cluster.
413 (defgeneric remove-note (note))
415 (defclass cluster (melody-element)
416 ((notes :initform '() :initarg :notes :accessor notes)
417 (stem-direction :initform :auto :initarg :stem-direction :accessor stem-direction)))
419 (defmethod initialize-instance :after ((c cluster) &rest args)
420 (declare (ignore args))
421 (loop for note in (notes c)
422 do (setf (cluster note) c)))
424 (defun make-cluster (&rest args
425 &key (notehead :filled) (lbeams 0) (rbeams 0) (dots 0)
426 (xoffset 0) notes (stem-direction :auto))
427 (declare (type (member :long :breve :whole :half :filled) notehead)
428 (type (integer 0 5) lbeams)
429 (type (integer 0 5) rbeams)
430 (type (integer 0 3) dots)
431 (type number xoffset)
432 (type list notes)
433 (type (member :up :down :auto) stem-direction)
434 (ignore notehead lbeams rbeams dots xoffset notes stem-direction))
435 (apply #'make-instance 'cluster args))
437 (defmethod slots-to-be-saved append ((c cluster))
438 '(stem-direction notes))
440 (defun read-cluster-v3 (stream char n)
441 (declare (ignore char n))
442 (apply #'make-instance 'cluster (read-delimited-list #\] stream t)))
444 (set-dispatch-macro-character #\[ #\%
445 #'read-cluster-v3
446 *gsharp-readtable-v3*)
448 (define-condition note-already-in-cluster (gsharp-condition) ()
449 (:report
450 (lambda (condition stream)
451 (declare (ignore condition))
452 (format stream "Attempt to add a note already in a cluster"))))
454 (defmethod set-contents ((cluster cluster) contents)
455 (setf (notes cluster) contents))
457 (defmethod add-note ((cluster cluster) (note note))
458 (with-slots (notes) cluster
459 (assert (not (find note notes :test #'note-equal))
461 'note-already-in-cluster)
462 (set-contents cluster (merge 'list notes (list note) #'note-less))
463 (setf (cluster note) cluster)))
465 (defmethod find-note ((cluster cluster) (note note))
466 (with-slots (notes) cluster
467 (car (member (pitch note) notes :key #'pitch))))
469 (define-condition note-not-in-cluster (gsharp-condition) ()
470 (:report
471 (lambda (condition stream)
472 (declare (ignore condition))
473 (format stream "Attempt to delete a note not in a cluster"))))
475 (defmethod remove-note ((note note))
476 (with-slots (cluster) note
477 (assert cluster () 'note-not-in-cluster)
478 (set-contents cluster (delete note (notes cluster) :test #'eq))))
480 (defun lower-bound (bound list &key (test #'<))
481 "Return the `largest' element in the sorted list LIST such that
482 \(TEST element BOUND) is true."
483 (let ((last nil))
484 (dolist (item list)
485 (unless (funcall test item bound)
486 (return-from lower-bound last))
487 (setf last item))
488 last))
490 (defmethod cluster-lower-bound ((cluster cluster) (bound note))
491 (with-slots (notes) cluster
492 (lower-bound bound notes :test #'note-less)))
494 (defmethod cluster-upper-bound ((cluster cluster) (bound note))
495 (with-slots (notes) cluster
496 (lower-bound bound (reverse notes) :test (complement #'note-less))))
498 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
500 ;;; Rest
502 (defclass rest (melody-element)
503 ((staff :initarg :staff :reader staff)
504 (staff-pos :initarg :staff-pos :initform 4 :reader staff-pos)))
506 (defun make-rest (staff &rest args
507 &key (staff-pos 4) (notehead :filled) (lbeams 0) (rbeams 0)
508 (dots 0) (xoffset 0))
509 (declare (type staff staff)
510 (type integer staff-pos)
511 (type (member :long :breve :whole :half :filled) notehead)
512 (type (integer 0 5) lbeams)
513 (type (integer 0 5) rbeams)
514 (type (integer 0 3) dots)
515 (type number xoffset)
516 (ignore staff-pos notehead lbeams rbeams dots xoffset))
517 (apply #'make-instance 'rest
518 :staff staff args))
520 (defmethod slots-to-be-saved append ((s rest))
521 '(staff staff-pos))
523 (defun read-rest-v3 (stream char n)
524 (declare (ignore char n))
525 (apply #'make-instance 'rest (read-delimited-list #\] stream t)))
527 (set-dispatch-macro-character #\[ #\-
528 #'read-rest-v3
529 *gsharp-readtable-v3*)
531 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
533 ;;; Melody bar
535 (defclass melody-bar (bar) ())
537 (defun make-melody-bar (&rest args &key elements)
538 (declare (type list elements)
539 (ignore elements))
540 (apply #'make-instance 'melody-bar args))
542 (defmethod make-bar-for-staff ((staff fiveline-staff) &rest args &key elements)
543 (declare (ignore elements))
544 (apply #'make-instance 'melody-bar args))
546 (defun read-melody-bar-v3 (stream char n)
547 (declare (ignore char n))
548 (apply #'make-instance 'melody-bar (read-delimited-list #\] stream t)))
550 (set-dispatch-macro-character #\[ #\|
551 #'read-melody-bar-v3
552 *gsharp-readtable-v3*)
554 (defmethod remove-bar ((bar melody-bar))
555 (with-slots (slice) bar
556 (assert slice () 'bar-not-in-slice)
557 (with-slots (bars) slice
558 (setf bars (delete bar bars :test #'eq))
559 (unless bars
560 ;; make sure there is one bar left
561 (add-bar (make-melody-bar) slice 0)))
562 (setf slice nil)))
564 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
566 ;;; Melody layer
568 (defclass melody-layer (layer) ())
570 (defun read-melody-layer-v3 (stream char n)
571 (declare (ignore char n))
572 (apply #'make-instance 'melody-layer (read-delimited-list #\] stream t)))
574 (set-dispatch-macro-character #\[ #\_
575 #'read-melody-layer-v3
576 *gsharp-readtable-v3*)
578 (defmethod make-layer-for-staff ((staff fiveline-staff) &rest args &key staves head body tail &allow-other-keys)
579 (declare (ignore staves head body tail))
580 (apply #'make-instance 'melody-layer args))
582 (defgeneric clefs (staff)
583 (:method ((s t)) nil)
584 (:method ((s fiveline-staff))
585 (remove-if #'(lambda (x) (not (typep x 'clef)))
586 (staffwise-elements s))))