]> git.donarmstrong.com Git - lilypond.git/blob - ly/event-listener.ly
event-listener.ly: durations of rests and notes.
[lilypond.git] / ly / event-listener.ly
1 %%%% This file is part of LilyPond, the GNU music typesetter.
2 %%%%
3 %%%% Copyright (C) 2011 Graham Percival <graham@percival-music.ca>
4 %%%%
5 %%%% LilyPond is free software: you can redistribute it and/or modify
6 %%%% it under the terms of the GNU General Public License as published by
7 %%%% the Free Software Foundation, either version 3 of the License, or
8 %%%% (at your option) any later version.
9 %%%%
10 %%%% LilyPond is distributed in the hope that it will be useful,
11 %%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
12 %%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 %%%% GNU General Public License for more details.
14 %%%%
15 %%%% You should have received a copy of the GNU General Public License
16 %%%% along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
17 %
18 %
19 %
20 % This file is used for Vivi, the Virtual Violinist:
21 %   http://percival-music.ca/vivi.html
22 % but it may be helpful to other researchers, either with the same
23 % output, or as a basis for other work in extracting music events
24 % from lilypond.
25 %
26 % Output format is tab-separated lines, like this:
27 %0.00000000     note    57      0.25000000      point-and-click 2 38
28 %0.00000000     dynamic f
29 %0.25000000     note    62      0.25000000      point-and-click 7 38
30 %0.50000000     note    66      0.12500000      point-and-click 9 38
31 %0.50000000     script  staccato
32
33
34
35 \version "2.15.0"
36
37 %%%% Helper functions
38
39 #(define (filename-from-staffname engraver)
40    "Constructs a filename in the form
41 @file{@var{original_filename}-@var{staff_instrument_name}.notes} if the
42 staff has an instrument name.  If the staff has no instrument
43 name, it uses "unnamed-staff" for that part of the filename."
44    (let* ((inst-name (ly:context-property
45                       (ly:translator-context engraver)
46                       'instrumentName)))
47      (string-concatenate (list
48                           (substring (object->string (command-line))
49                            ;; filename without .ly part
50                            (+ (string-rindex (object->string (command-line)) #\sp) 2)
51                            (- (string-length (object->string (command-line))) 5))
52                           "-"
53                           (if (string? inst-name)
54                               inst-name
55                             "unnamed-staff")
56                           ".notes"))))
57
58 #(define (format-moment moment)
59    (exact->inexact
60     (/ (ly:moment-main-numerator moment)
61        (ly:moment-main-denominator moment))))
62
63 #(define (adjust-for-grace moment)
64    "Adjusts any moment with a grace note by subtracting half of
65 the grace note duration.  For example, an eighth note grace note
66 which would otherwise occur at score time 0.5 will now occur at
67 score time 0.375."
68    (if
69        (eq? 0 (ly:moment-grace-numerator moment))
70        moment
71        ;; get moment including grace note
72        ;; grace notes have a negative numerator, so add
73        (ly:moment-add moment
74                       ;; make the "grace duration" half as long
75                       (ly:moment-mul
76                        (ly:make-moment 1 2)
77                        (ly:make-moment
78                         (ly:moment-grace-numerator moment)
79                         (ly:moment-grace-denominator moment))))))
80
81 #(define (get-moment moment)
82    (format-moment (adjust-for-grace
83                    moment)))
84
85 #(define (make-output-string-line engraver values)
86    "Constructs a tab-separated string beginning with the
87 score time (derived from the engraver) and then adding all the
88 values.  The string ends with a newline."
89    (let* ((context (ly:translator-context engraver))
90           (moment (ly:context-current-moment context)))
91     (string-append
92      (string-join
93       (map
94        (lambda (x) (ly:format "~a" x))
95         (append
96          (list (get-moment moment))
97           values))
98         "\t")
99      "\n")))
100
101
102 #(define (print-line engraver . values)
103    "Prints the list of values (plus the score time) to a file, and
104 optionally outputs to the console as well."
105    (let* ((p (open-file (filename-from-staffname engraver) "a")))
106      ;; for regtest comparison
107     (if (defined? 'EVENT_LISTENER_CONSOLE_OUTPUT)
108      (ly:progress
109       (make-output-string-line engraver values)))
110     (display
111      (make-output-string-line engraver values)
112      p)
113     (close p)))
114
115
116 %%% main functions
117
118 #(define (format-rest engraver event)
119    (print-line engraver
120                "rest"
121                (ly:duration->string
122                 (ly:event-property event 'duration))
123                (format-moment (ly:duration-length
124                                (ly:event-property event 'duration)))))
125
126 #(define (format-note engraver event)
127    (let* ((origin (ly:input-file-line-char-column
128                    (ly:event-property event 'origin))))
129      (print-line engraver
130                  "note"
131                  ;; get a MIDI pitch value.
132                  (+ 60 (ly:pitch-semitones
133                         (ly:event-property event 'pitch)))
134                  (ly:duration->string
135                   (ly:event-property event 'duration))
136                  (format-moment (ly:duration-length
137                                  (ly:event-property event 'duration)))
138                  ;; point and click info
139                  (ly:format "point-and-click ~a ~a"
140                             (caddr origin)
141                             (cadr origin)))))
142
143 #(define (format-tempo engraver event)
144    (print-line engraver
145                "tempo"
146                ; get length of quarter notes, in seconds
147                (/ (ly:event-property event 'metronome-count)
148                    (format-moment (ly:duration-length (ly:event-property
149                                                        event
150                                                        'tempo-unit))))))
151
152
153 #(define (format-breathe engraver event)
154    (print-line engraver
155                "breathe"))
156
157 #(define (format-articulation engraver event)
158    (print-line engraver
159                "script"
160                (ly:event-property event 'articulation-type)))
161
162 #(define (format-text engraver event)
163    (print-line engraver
164                "text"
165                (ly:event-property event 'text)))
166
167 #(define (format-slur engraver event)
168    (print-line engraver
169                "slur"
170                (ly:event-property event 'span-direction)))
171
172 #(define (format-dynamic engraver event)
173    (print-line engraver
174                "dynamic"
175                (ly:event-property event 'text)))
176
177 #(define (format-cresc engraver event)
178    (print-line engraver
179                "cresc"
180                (ly:event-property event 'span-direction)))
181
182 #(define (format-decresc engraver event)
183    (print-line engraver
184                "decresc"
185                (ly:event-property event 'span-direction)))
186
187 #(define (format-textspan engraver event)
188    (let* ((context (ly:translator-context engraver))
189           (moment (ly:context-current-moment context))
190           (spanner-props (ly:context-property context 'TextSpanner))
191           (details (chain-assoc-get 'bound-details spanner-props))
192           (left-props (assoc-get 'left details '()))
193           (left-text (assoc-get 'text left-props '())))
194      (print-line engraver
195                  "set_string"
196                  (ly:event-property event 'span-direction)
197                  left-text)))
198
199
200 %%%% The actual engraver definition: We just install some listeners so we
201 %%%% are notified about all notes and rests. We don't create any grobs or
202 %%%% change any settings.
203
204 \layout {
205   \context {
206   \Voice
207   \consists #(list
208               (cons 'listeners
209                     (list
210                      (cons 'tempo-change-event format-tempo)
211                      (cons 'rest-event format-rest)
212                      (cons 'note-event format-note)
213                      (cons 'articulation-event format-articulation)
214                      (cons 'text-script-event format-text)
215                      (cons 'slur-event format-slur)
216                      (cons 'breathing-event format-breathe)
217                      (cons 'dynamic-event format-dynamic)
218                      (cons 'crescendo-event format-cresc)
219                      (cons 'decrescendo-event format-decresc)
220                      (cons 'text-span-event format-textspan)
221                      )))
222   }
223 }