Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 /* | 1 /* |
2 This file is part of LilyPond, the GNU music typesetter. | 2 This file is part of LilyPond, the GNU music typesetter. |
3 | 3 |
4 Copyright (C) 2000--2015 Jan Nieuwenhuizen <janneke@gnu.org> | 4 Copyright (C) 2000--2015 Jan Nieuwenhuizen <janneke@gnu.org> |
5 | 5 |
6 LilyPond is free software: you can redistribute it and/or modify | 6 LilyPond is free software: you can redistribute it and/or modify |
7 it under the terms of the GNU General Public License as published by | 7 it under the terms of the GNU General Public License as published by |
8 the Free Software Foundation, either version 3 of the License, or | 8 the Free Software Foundation, either version 3 of the License, or |
9 (at your option) any later version. | 9 (at your option) any later version. |
10 | 10 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
43 void close_and_enqueue_span (); | 43 void close_and_enqueue_span (); |
44 Real compute_departure_volume (Direction depart_dir, | 44 Real compute_departure_volume (Direction depart_dir, |
45 Real start_vol, | 45 Real start_vol, |
46 Real end_vol, | 46 Real end_vol, |
47 Real min_vol, | 47 Real min_vol, |
48 Real max_vol); | 48 Real max_vol); |
49 bool drive_state_machine (Direction next_grow_dir); | 49 bool drive_state_machine (Direction next_grow_dir); |
50 // next_vol < 0 means select a target dynamic based on growth direction. | 50 // next_vol < 0 means select a target dynamic based on growth direction. |
51 // return actual next volume (computed if not provided) | 51 // return actual next volume (computed if not provided) |
52 Real finish_queued_spans (Real next_vol = -1.0); | 52 Real finish_queued_spans (Real next_vol = -1.0); |
53 Real look_up_absolute_volume(SCM dynamicString, | 53 Real look_up_absolute_volume (SCM dynamicString, |
ht
2016/07/09 18:16:50
missing space after open parenthesis
Dan Eble
2016/07/12 05:01:15
Thank you. I've run fixcc.py on dynamic-performer
| |
54 Real defaultValue); | 54 Real defaultValue); |
55 | 55 |
56 private: | 56 private: |
57 // This performer queues a number of dynamic spans waiting for the following | 57 // This performer queues a number of dynamic spans waiting for the following |
58 // pattern before computing their volume levels. | 58 // pattern before computing their volume levels. |
59 // | 59 // |
60 // 1. the first (de)crescendo, followed by ... | 60 // 1. the first (de)crescendo, followed by ... |
61 // 2. zero or more spans that either change in the same direction as the | 61 // 2. zero or more spans that either change in the same direction as the |
62 // first or do not change, followed by ... | 62 // first or do not change, followed by ... |
63 // 3. zero or more spans that either change in the opposite direction as the | 63 // 3. zero or more spans that either change in the opposite direction as the |
64 // first or do not change | 64 // first or do not change |
65 // | 65 // |
66 // The search may be cut short by an absolute dynamic or the end of the | 66 // The search may be cut short by an absolute dynamic or the end of the |
67 // context. | 67 // context. |
68 enum State | 68 enum State |
69 { | 69 { |
70 STATE_INITIAL = 0, // waiting for a (de)crescendo | 70 STATE_INITIAL = 0, // waiting for a (de)crescendo |
71 STATE_DEPART, // enqueued the first span, gathering same-direction spans | 71 STATE_DEPART, // enqueued the first span, gathering same-direction spans |
72 STATE_RETURN // gathering opposite-direction spans | 72 STATE_RETURN // gathering opposite-direction spans |
73 }; | 73 }; |
74 | 74 |
75 struct UnfinishedSpan | 75 struct UnfinishedSpan |
76 { | 76 { |
77 Audio_span_dynamic *dynamic_; | 77 Audio_span_dynamic *dynamic_; |
78 Direction grow_dir_; | 78 Direction grow_dir_; |
79 | 79 |
80 UnfinishedSpan () : dynamic_ (0), grow_dir_ (CENTER) {} | 80 UnfinishedSpan () : dynamic_ (0), grow_dir_ (CENTER) {} |
81 }; | 81 }; |
82 | 82 |
83 struct DynamicQueue | 83 struct DynamicQueue |
84 { | 84 { |
85 vector<UnfinishedSpan> spans_; | 85 vector<UnfinishedSpan> spans_; |
86 // total duration of (de)crescendi (i.e. excluding fixed-volume spans) | 86 // total duration of (de)crescendi (i.e. excluding fixed-volume spans) |
87 Real change_duration_; | 87 Real change_duration_; |
88 Real min_target_vol_; | 88 Real min_target_vol_; |
89 Real max_target_vol_; | 89 Real max_target_vol_; |
90 | 90 |
91 DynamicQueue () : change_duration_ (0) {} | 91 DynamicQueue () : change_duration_ (0) {} |
92 | 92 |
93 void clear () | 93 void clear () |
94 { | 94 { |
95 spans_.clear (); | 95 spans_.clear (); |
96 change_duration_ = 0; | 96 change_duration_ = 0; |
97 } | 97 } |
98 | 98 |
99 void push_back (const UnfinishedSpan& span, | 99 void push_back (const UnfinishedSpan &span, |
100 Real min_target_vol, | 100 Real min_target_vol, |
101 Real max_target_vol) | 101 Real max_target_vol) |
ht
2016/07/09 18:16:50
Assuming that equalizer settings do not change bet
Dan Eble
2016/07/12 05:01:15
Assuming that context properties do not change in
| |
102 { | 102 { |
103 if (span.grow_dir_ != CENTER) | 103 if (span.grow_dir_ != CENTER) |
104 change_duration_ += span.dynamic_->get_duration (); | 104 change_duration_ += span.dynamic_->get_duration (); |
105 min_target_vol_ = min_target_vol; | 105 min_target_vol_ = min_target_vol; |
106 max_target_vol_ = max_target_vol; | 106 max_target_vol_ = max_target_vol; |
107 spans_.push_back (span); | 107 spans_.push_back (span); |
108 } | 108 } |
109 | 109 |
110 void set_volume (Real start_vol, Real target_vol); | 110 void set_volume (Real start_vol, Real target_vol); |
111 }; | 111 }; |
112 | 112 |
113 private: | 113 private: |
114 Stream_event *script_event_; | 114 Stream_event *script_event_; |
115 Drul_array<Stream_event *> span_events_; | 115 Drul_array<Stream_event *> span_events_; |
116 Direction next_grow_dir_; | 116 Direction next_grow_dir_; |
117 Direction depart_dir_; | 117 Direction depart_dir_; |
118 UnfinishedSpan open_span_; | 118 UnfinishedSpan open_span_; |
119 DynamicQueue depart_queue_; | 119 DynamicQueue depart_queue_; |
120 DynamicQueue return_queue_; | 120 DynamicQueue return_queue_; |
121 State state_; | 121 State state_; |
122 }; | 122 }; |
123 | 123 |
124 Dynamic_performer::Dynamic_performer () | 124 Dynamic_performer::Dynamic_performer () |
125 : script_event_ (0), | 125 : script_event_ (0), |
126 next_grow_dir_ (CENTER), | 126 next_grow_dir_ (CENTER), |
127 depart_dir_ (CENTER), | 127 depart_dir_ (CENTER), |
128 state_ (STATE_INITIAL) | 128 state_ (STATE_INITIAL) |
129 { | 129 { |
130 span_events_[LEFT] | 130 span_events_[LEFT] |
131 = span_events_[RIGHT] = 0; | 131 = span_events_[RIGHT] = 0; |
132 } | 132 } |
133 | 133 |
134 bool | 134 bool |
135 Dynamic_performer::drive_state_machine (Direction next_grow_dir) | 135 Dynamic_performer::drive_state_machine (Direction next_grow_dir) |
136 { | 136 { |
137 switch (state_) | 137 switch (state_) |
138 { | 138 { |
139 case STATE_INITIAL: | 139 case STATE_INITIAL: |
140 if (next_grow_dir != CENTER) | 140 if (next_grow_dir != CENTER) |
141 { | 141 { |
142 state_ = STATE_DEPART; | 142 state_ = STATE_DEPART; |
143 depart_dir_ = next_grow_dir; | 143 depart_dir_ = next_grow_dir; |
144 } | 144 } |
145 break; | 145 break; |
146 | 146 |
147 case STATE_DEPART: | 147 case STATE_DEPART: |
148 if (next_grow_dir == -depart_dir_) | 148 if (next_grow_dir == -depart_dir_) |
149 state_ = STATE_RETURN; | 149 state_ = STATE_RETURN; |
150 break; | 150 break; |
151 | 151 |
152 case STATE_RETURN: | 152 case STATE_RETURN: |
153 if (next_grow_dir == depart_dir_) | 153 if (next_grow_dir == depart_dir_) |
154 { | 154 { |
155 state_ = STATE_DEPART; | 155 state_ = STATE_DEPART; |
156 depart_dir_ = next_grow_dir; | |
ht
2016/07/09 18:16:50
This looks like a redundant assignment due to the
Dan Eble
2016/07/12 05:01:15
Yes. I appreciate your attention to detail.
| |
157 return true; | 156 return true; |
158 } | 157 } |
159 break; | 158 break; |
160 } | 159 } |
161 | 160 |
162 return false; | 161 return false; |
163 } | 162 } |
164 | 163 |
165 void | 164 void |
166 Dynamic_performer::close_and_enqueue_span () | 165 Dynamic_performer::close_and_enqueue_span () |
167 { | 166 { |
168 if (!open_span_.dynamic_) | 167 if (!open_span_.dynamic_) |
169 programming_error("no open dynamic span"); | 168 programming_error ("no open dynamic span"); |
170 else | 169 else |
171 { | 170 { |
172 DynamicQueue& dq = | 171 DynamicQueue &dq |
173 (state_ == STATE_RETURN) ? return_queue_ : depart_queue_; | 172 = (state_ == STATE_RETURN) ? return_queue_ : depart_queue_; |
174 | 173 |
175 // Changing equalizer settings in the course of the performance does not | 174 // Changing equalizer settings in the course of the performance does not |
176 // seem very likely. This is a fig leaf: Equalize these limit volumes | 175 // seem very likely. This is a fig leaf: Equalize these limit volumes |
177 // now as the required context properties are current. Note that only | 176 // now as the required context properties are current. Note that only |
178 // the limits at the end of the last span in the queue are kept. | 177 // the limits at the end of the last span in the queue are kept. |
179 | 178 |
180 // Resist diminishing to silence. (Idea: Look up "ppppp" | 179 // Resist diminishing to silence. (Idea: Look up "ppppp" |
181 // with dynamicAbsoluteVolumeFunction, however that would yield 0.25.) | 180 // with dynamicAbsoluteVolumeFunction, however that would yield 0.25.) |
182 const Real min_target = equalize_volume (0.1); | 181 const Real min_target = equalize_volume (0.1); |
183 const Real max_target = | 182 const Real max_target |
184 equalize_volume (Audio_span_dynamic::MAXIMUM_VOLUME); | 183 = equalize_volume (Audio_span_dynamic::MAXIMUM_VOLUME); |
185 | 184 |
186 open_span_.dynamic_->set_end_moment (now_mom ()); | 185 open_span_.dynamic_->set_end_moment (now_mom ()); |
187 dq.push_back (open_span_, min_target, max_target); | 186 dq.push_back (open_span_, min_target, max_target); |
188 } | 187 } |
189 | 188 |
190 open_span_ = UnfinishedSpan (); | 189 open_span_ = UnfinishedSpan (); |
191 } | 190 } |
192 | 191 |
193 // Set the starting and target volume for each span in the queue. The gain | 192 // Set the starting and target volume for each span in the queue. The gain |
194 // (loss) of any (de)crescendo is proportional to its share of the total time | 193 // (loss) of any (de)crescendo is proportional to its share of the total time |
(...skipping 12 matching lines...) Expand all Loading... | |
207 if (it->grow_dir_ != CENTER) | 206 if (it->grow_dir_ != CENTER) |
208 { | 207 { |
209 // grant this (de)crescendo its portion of the gain | 208 // grant this (de)crescendo its portion of the gain |
210 dur += it->dynamic_->get_duration (); | 209 dur += it->dynamic_->get_duration (); |
211 vol = start_vol + gain * (dur / change_duration_); | 210 vol = start_vol + gain * (dur / change_duration_); |
212 } | 211 } |
213 it->dynamic_->set_volume (prev_vol, vol); | 212 it->dynamic_->set_volume (prev_vol, vol); |
214 } | 213 } |
215 } | 214 } |
216 | 215 |
217 // Return a volume which is reasonably distant from the given volumes in the | 216 // Return a volume which is reasonably distant from the given start and end |
ht
2016/07/09 18:16:50
I guess that the "given volumes" mean only start_
Dan Eble
2016/07/12 05:01:15
Yes. I added max and min parameters after documen
| |
218 // given direction, for use as a peak volume in a passage with a crescendo | 217 // volumes in the given direction, for use as a peak volume in a passage with a |
219 // followed by a decrescendo (or vice versa). If the given volumes are equal, | 218 // crescendo followed by a decrescendo (or vice versa). If the given volumes |
220 // the returned volume is a also reasonable target volume for a single | 219 // are equal, the returned volume is a also reasonable target volume for a |
221 // (de)crescendo. | 220 // single (de)crescendo. |
221 // | |
222 // The given minimum and maximum volumes are the allowable dynamic range. | |
222 Real | 223 Real |
223 Dynamic_performer::compute_departure_volume (Direction depart_dir, | 224 Dynamic_performer::compute_departure_volume (Direction depart_dir, |
224 Real start_vol, | 225 Real start_vol, |
225 Real end_vol, | 226 Real end_vol, |
226 Real min_vol, | 227 Real min_vol, |
227 Real max_vol) | 228 Real max_vol) |
228 { | 229 { |
229 if (depart_dir == CENTER) | 230 if (depart_dir == CENTER) |
230 return start_vol; | 231 return start_vol; |
231 | 232 |
232 // Try to find a volume that is a minimum distance from the starting and | 233 // Try to find a volume that is a minimum distance from the starting and |
233 // ending volumes. If the endpoint volumes differ, the nearer one is padded | 234 // ending volumes. If the endpoint volumes differ, the nearer one is padded |
234 // less than the farther one. | 235 // less than the farther one. |
ht
2016/07/09 18:16:50
I believe I eventually understood what this functi
Dan Eble
2016/07/12 05:01:15
That was my intent. Consider mf < ... > p. The p
| |
235 | 236 |
236 // Idea: Use a context property or callback, e.g. the difference between two | 237 // Idea: Use a context property or callback, e.g. the difference between two |
237 // dynamics in dynamicAbsoluteVolumeFunction. 0.25 is the default difference | 238 // dynamics in dynamicAbsoluteVolumeFunction. 0.25 is the default difference |
238 // between "p" and "ff". (Isn't that rather wide for this purpose?) | 239 // between "p" and "ff". (Isn't that rather wide for this purpose?) |
ht
2016/07/09 18:16:50
I think using "0.25 * the available volume range"
| |
239 const Real far_padding = 0.25; | 240 const Real far_padding = 0.25; |
240 const Real near_padding = 0.07; | 241 const Real near_padding = 0.07; |
241 | 242 |
242 // If for some reason one of the endpoints is already below the supposed | 243 // If for some reason one of the endpoints is already below the supposed |
243 // minimum or maximum, just accept it. | 244 // minimum or maximum, just accept it. |
244 // TODO: If this is impossible, programming_error. | |
ht
2016/07/09 18:16:50
Is there still something left to be done here?
Dan Eble
2016/07/12 05:01:15
I've removed the comment.
| |
245 min_vol = min (min (min_vol, start_vol), end_vol); | 245 min_vol = min (min (min_vol, start_vol), end_vol); |
246 max_vol = max (max (max_vol, start_vol), end_vol); | 246 max_vol = max (max (max_vol, start_vol), end_vol); |
247 | 247 |
248 const Real vol_range = max_vol - min_vol; | 248 const Real vol_range = max_vol - min_vol; |
249 | 249 |
250 const Real near = minmax (depart_dir, start_vol, end_vol) | 250 const Real near = minmax (depart_dir, start_vol, end_vol) |
251 + depart_dir * near_padding * vol_range; | 251 + depart_dir * near_padding * vol_range; |
252 const Real far = minmax (-depart_dir, start_vol, end_vol) | 252 const Real far = minmax (-depart_dir, start_vol, end_vol) |
253 + depart_dir * far_padding * vol_range; | 253 + depart_dir * far_padding * vol_range; |
254 const Real depart_vol = minmax (depart_dir, near, far); | 254 const Real depart_vol = minmax (depart_dir, near, far); |
255 return max (min (depart_vol, max_vol), min_vol); | 255 return max (min (depart_vol, max_vol), min_vol); |
256 } | 256 } |
257 | 257 |
258 Real | 258 Real |
259 Dynamic_performer::finish_queued_spans (Real next_vol) | 259 Dynamic_performer::finish_queued_spans (Real next_vol) |
260 { | 260 { |
261 if (depart_queue_.spans_.empty ()) | 261 if (depart_queue_.spans_.empty ()) |
262 { | 262 { |
263 programming_error("no dynamic span to finish"); | 263 programming_error ("no dynamic span to finish"); |
ht
2016/07/09 18:16:50
missing whitespace before open parenthesis
| |
264 return next_vol; | 264 return next_vol; |
265 } | 265 } |
266 | 266 |
267 const Real start_vol = depart_queue_.spans_.front ().dynamic_->get_start_volum e (); | 267 const Real start_vol = depart_queue_.spans_.front ().dynamic_->get_start_volum e (); |
268 | 268 |
269 if (return_queue_.spans_.empty ()) | 269 if (return_queue_.spans_.empty ()) |
270 { | 270 { |
271 Real depart_vol = next_vol; | 271 Real depart_vol = next_vol; |
272 | 272 |
273 // If the next dynamic is not specified or is inconsistent with the | 273 // If the next dynamic is not specified or is inconsistent with the |
274 // direction of growth, choose a reasonable target. | 274 // direction of growth, choose a reasonable target. |
275 if ((next_vol < 0) || (depart_dir_ != sign (next_vol - start_vol))) | 275 if ((next_vol < 0) || (depart_dir_ != sign (next_vol - start_vol))) |
276 { | 276 { |
277 depart_vol = compute_departure_volume (depart_dir_, | 277 depart_vol = compute_departure_volume (depart_dir_, |
278 start_vol, start_vol, | 278 start_vol, start_vol, |
279 depart_queue_.min_target_vol_, | 279 depart_queue_.min_target_vol_, |
280 depart_queue_.max_target_vol_); | 280 depart_queue_.max_target_vol_); |
281 } | 281 } |
282 | 282 |
283 depart_queue_.set_volume(start_vol, depart_vol); | 283 depart_queue_.set_volume (start_vol, depart_vol); |
ht
2016/07/09 18:16:50
missing whitespace before open parenthesis
| |
284 depart_queue_.clear (); | 284 depart_queue_.clear (); |
285 return (next_vol >= 0) ? next_vol : depart_vol; | 285 return (next_vol >= 0) ? next_vol : depart_vol; |
286 } | 286 } |
287 else | 287 else |
288 { | 288 { |
289 // If the next dynamic is not specified, return to the starting volume. | 289 // If the next dynamic is not specified, return to the starting volume. |
290 const Real return_vol = (next_vol >= 0) ? next_vol : start_vol; | 290 const Real return_vol = (next_vol >= 0) ? next_vol : start_vol; |
291 Real depart_vol = compute_departure_volume(depart_dir_, | 291 Real depart_vol = compute_departure_volume (depart_dir_, |
ht
2016/07/09 18:16:50
missing whitespace before open parenthesis
| |
292 start_vol, return_vol, | 292 start_vol, return_vol, |
293 depart_queue_.min_target_vol_, | 293 depart_queue_.min_target_vol_, |
294 depart_queue_.max_target_vol_); | 294 depart_queue_.max_target_vol_) ; |
295 depart_queue_.set_volume (start_vol, depart_vol); | 295 depart_queue_.set_volume (start_vol, depart_vol); |
296 depart_queue_.clear (); | 296 depart_queue_.clear (); |
297 return_queue_.set_volume (depart_vol, return_vol); | 297 return_queue_.set_volume (depart_vol, return_vol); |
298 return_queue_.clear (); | 298 return_queue_.clear (); |
299 return return_vol; | 299 return return_vol; |
300 } | 300 } |
301 } | 301 } |
302 | 302 |
303 Real | 303 Real |
304 Dynamic_performer::equalize_volume (Real volume) | 304 Dynamic_performer::equalize_volume (Real volume) |
(...skipping 30 matching lines...) Expand all Loading... | |
335 if (ly_is_procedure (eq)) | 335 if (ly_is_procedure (eq)) |
336 s = scm_call_1 (eq, s); | 336 s = scm_call_1 (eq, s); |
337 | 337 |
338 if (is_number_pair (s)) | 338 if (is_number_pair (s)) |
339 { | 339 { |
340 Interval iv = ly_scm2interval (s); | 340 Interval iv = ly_scm2interval (s); |
341 volume = iv[MIN] + iv.length () * volume; | 341 volume = iv[MIN] + iv.length () * volume; |
342 } | 342 } |
343 } | 343 } |
344 return std::max (std::min (volume, Audio_span_dynamic::MAXIMUM_VOLUME), | 344 return std::max (std::min (volume, Audio_span_dynamic::MAXIMUM_VOLUME), |
345 Audio_span_dynamic::MINIMUM_VOLUME); | 345 Audio_span_dynamic::MINIMUM_VOLUME); |
ht
2016/07/09 18:16:50
max and min are usually used without namespace
Dan Eble
2016/07/12 05:01:15
That's currently true in Lilypond, but someone has
| |
346 } | 346 } |
347 | 347 |
348 void | 348 void |
349 Dynamic_performer::finalize () | 349 Dynamic_performer::finalize () |
350 { | 350 { |
351 if (open_span_.dynamic_) | 351 if (open_span_.dynamic_) |
352 close_and_enqueue_span (); | 352 close_and_enqueue_span (); |
353 finish_queued_spans (); | 353 finish_queued_spans (); |
354 } | 354 } |
355 | 355 |
356 Real | 356 Real |
357 Dynamic_performer::look_up_absolute_volume(SCM dynamicString, | 357 Dynamic_performer::look_up_absolute_volume (SCM dynamicString, |
358 Real defaultValue) | 358 Real defaultValue) |
359 { | 359 { |
360 SCM proc = get_property ("dynamicAbsoluteVolumeFunction"); | 360 SCM proc = get_property ("dynamicAbsoluteVolumeFunction"); |
361 | 361 |
362 SCM svolume = SCM_EOL; | 362 SCM svolume = SCM_EOL; |
363 if (ly_is_procedure (proc)) | 363 if (ly_is_procedure (proc)) |
364 svolume = scm_call_1 (proc, dynamicString); | 364 svolume = scm_call_1 (proc, dynamicString); |
365 | 365 |
366 return robust_scm2double (svolume, defaultValue); | 366 return robust_scm2double (svolume, defaultValue); |
367 } | 367 } |
368 | 368 |
369 void | 369 void |
370 Dynamic_performer::process_music () | 370 Dynamic_performer::process_music () |
371 { | 371 { |
372 Real volume = -1; | 372 Real volume = -1; |
373 | 373 |
374 if (script_event_) // explicit dynamic | 374 if (script_event_) // explicit dynamic |
375 { | 375 { |
376 volume = look_up_absolute_volume (script_event_->get_property ("text"), | 376 volume = look_up_absolute_volume (script_event_->get_property ("text"), |
377 Audio_span_dynamic::DEFAULT_VOLUME); | 377 Audio_span_dynamic::DEFAULT_VOLUME); |
378 volume = equalize_volume (volume); | 378 volume = equalize_volume (volume); |
379 } | 379 } |
380 else if (!open_span_.dynamic_) // first time only | 380 else if (!open_span_.dynamic_) // first time only |
381 { | 381 { |
ht
2016/07/09 18:16:50
Could this case be combined with the code further
Dan Eble
2016/07/12 05:01:16
This block is executed the first time only, but th
| |
382 // Idea: look_up_absolute_volume (ly_symbol2scm ("mf")). | 382 // Idea: look_up_absolute_volume (ly_symbol2scm ("mf")). |
ht
2016/07/09 18:16:50
Actually, the value 90.0/127.0 for Audio_span_dyna
Dan Eble
2016/07/12 05:01:16
I know. Did you mean to suggest that this idea is
| |
383 // It is likely to change regtests. | 383 // It is likely to change regtests. |
384 volume = equalize_volume (Audio_span_dynamic::DEFAULT_VOLUME); | 384 volume = equalize_volume (Audio_span_dynamic::DEFAULT_VOLUME); |
385 } | 385 } |
386 | 386 |
387 // end the current span at relevant points | 387 // end the current span at relevant points |
388 if (open_span_.dynamic_ | 388 if (open_span_.dynamic_ |
389 && (span_events_[START] || span_events_[STOP] || script_event_)) | 389 && (span_events_[START] || span_events_[STOP] || script_event_)) |
390 { | 390 { |
391 close_and_enqueue_span (); | 391 close_and_enqueue_span (); |
392 if (script_event_) | 392 if (script_event_) |
393 { | 393 { |
394 state_ = STATE_INITIAL; | 394 state_ = STATE_INITIAL; |
395 volume = finish_queued_spans (volume); | 395 volume = finish_queued_spans (volume); |
396 } | 396 } |
397 } | 397 } |
398 | 398 |
399 // start a new span so that some dynamic is always in effect | 399 // start a new span so that some dynamic is always in effect |
400 if (!open_span_.dynamic_) | 400 if (!open_span_.dynamic_) |
401 { | 401 { |
402 if (drive_state_machine (next_grow_dir_)) | 402 if (drive_state_machine (next_grow_dir_)) |
403 volume = finish_queued_spans (volume); | 403 volume = finish_queued_spans (volume); |
404 | 404 |
405 // if not known by now, use a default volume for robustness | 405 // if not known by now, use a default volume for robustness |
406 if (volume < 0) | 406 if (volume < 0) |
407 volume = Audio_span_dynamic::DEFAULT_VOLUME; | 407 volume = equalize_volume (Audio_span_dynamic::DEFAULT_VOLUME); |
ht
2016/07/09 18:16:50
Should equalization be applied to this default vol
Dan Eble
2016/07/12 05:01:16
I believe it makes no difference because in the ca
| |
408 | 408 |
409 Stream_event *cause = | 409 Stream_event *cause |
410 span_events_[START] ? span_events_[START] : | 410 = span_events_[START] ? span_events_[START] |
411 script_event_ ? script_event_ : | 411 : script_event_ ? script_event_ |
412 span_events_[STOP]; | 412 : span_events_[STOP]; |
413 | 413 |
414 open_span_.dynamic_ = new Audio_span_dynamic (now_mom (), volume); | 414 open_span_.dynamic_ = new Audio_span_dynamic (now_mom (), volume); |
415 open_span_.grow_dir_ = next_grow_dir_; | 415 open_span_.grow_dir_ = next_grow_dir_; |
416 announce_element (Audio_element_info (open_span_.dynamic_, cause)); | 416 announce_element (Audio_element_info (open_span_.dynamic_, cause)); |
417 } | 417 } |
418 } | 418 } |
419 | 419 |
420 void | 420 void |
421 Dynamic_performer::stop_translation_timestep () | 421 Dynamic_performer::stop_translation_timestep () |
422 { | 422 { |
423 script_event_ = 0; | 423 script_event_ = 0; |
424 span_events_[LEFT] | 424 span_events_[LEFT] |
425 = span_events_[RIGHT] = 0; | 425 = span_events_[RIGHT] = 0; |
426 next_grow_dir_ = CENTER; | 426 next_grow_dir_ = CENTER; |
427 } | 427 } |
428 | 428 |
429 void | 429 void |
430 Dynamic_performer::listen_decrescendo (Stream_event *r) | 430 Dynamic_performer::listen_decrescendo (Stream_event *r) |
431 { | 431 { |
432 Direction d = to_dir (r->get_property ("span-direction")); | 432 Direction d = to_dir (r->get_property ("span-direction")); |
433 if (ASSIGN_EVENT_ONCE (span_events_[d], r) && (d == START)) | 433 if (ASSIGN_EVENT_ONCE (span_events_[d], r) && (d == START)) |
434 next_grow_dir_ = SMALLER; | 434 next_grow_dir_ = SMALLER; |
435 } | 435 } |
(...skipping 15 matching lines...) Expand all Loading... | |
451 void | 451 void |
452 Dynamic_performer::boot () | 452 Dynamic_performer::boot () |
453 { | 453 { |
454 ADD_LISTENER (Dynamic_performer, decrescendo); | 454 ADD_LISTENER (Dynamic_performer, decrescendo); |
455 ADD_LISTENER (Dynamic_performer, crescendo); | 455 ADD_LISTENER (Dynamic_performer, crescendo); |
456 ADD_LISTENER (Dynamic_performer, absolute_dynamic); | 456 ADD_LISTENER (Dynamic_performer, absolute_dynamic); |
457 } | 457 } |
458 | 458 |
459 ADD_TRANSLATOR (Dynamic_performer, | 459 ADD_TRANSLATOR (Dynamic_performer, |
460 /* doc */ | 460 /* doc */ |
461 "", | 461 "", |
ht
2016/07/09 18:16:50
Now that the logic of Dynamic_performer is being r
Dan Eble
2016/07/12 05:01:15
If someone can point me to a good example of IM do
| |
462 | 462 |
463 /* create */ | 463 /* create */ |
464 "", | 464 "", |
465 | 465 |
466 /* read */ | 466 /* read */ |
467 "dynamicAbsoluteVolumeFunction " | 467 "dynamicAbsoluteVolumeFunction " |
468 "instrumentEqualizer " | 468 "instrumentEqualizer " |
469 "midiMaximumVolume " | 469 "midiMaximumVolume " |
470 "midiMinimumVolume " | 470 "midiMinimumVolume " |
471 "midiInstrument ", | 471 "midiInstrument ", |
472 | 472 |
473 /* write */ | 473 /* write */ |
474 "" | 474 "" |
475 ); | 475 ); |
LEFT | RIGHT |