125
SegmentPerformanceHelper::getGraceAndHostNotes(iterator i,
126
iteratorcontainer &graceNotes,
127
iteratorcontainer &hostNotes,
130
if (i == end() || !(*i)->isa(Note::EventType)) return false;
132
Segment::iterator j = i;
133
Segment::iterator firstGraceNote = i;
134
Segment::iterator firstHostNote = i;
136
if ((*i)->has(IS_GRACE_NOTE) && (*i)->get<Bool>(IS_GRACE_NOTE)) {
138
// i is a grace note. Find the first host note following it
141
while (++j != end()) {
142
if ((*j)->getNotationAbsoluteTime() >
143
(*i)->getNotationAbsoluteTime()) break;
144
if ((*j)->getSubOrdering() < 0) continue;
145
if ((*j)->isa(Note::EventType)) {
151
if (firstHostNote == i) {
152
std::cerr << "SegmentPerformanceHelper::getGraceAndHostNotes: REMARK: Grace note at " << (*i)->getAbsoluteTime() << " has no host note" << std::endl;
157
// i is a host note, but we need to ensure we have the first
158
// one, not just any one
162
while (j != begin()) {
164
if ((*j)->getNotationAbsoluteTime() <
165
(*i)->getNotationAbsoluteTime()) break;
166
if ((*j)->getSubOrdering() <
167
(*i)->getSubOrdering()) break;
168
if ((*j)->isa(Note::EventType)) {
175
// firstHostNote now points to the first host note, which is
176
// either the first non-grace note after i (if i was a grace note)
177
// or the first note with the same time and subordering as i (if i
178
// was not a grace note).
180
if ((*firstHostNote)->getSubOrdering() < 0) {
181
std::cerr << "SegmentPerformanceHelper::getGraceAndHostNotes: WARNING: Note at " << (*firstHostNote)->getAbsoluteTime() << " has subordering " << (*i)->getSubOrdering() << " but is not a grace note" << std::endl;
187
while (j != begin()) {
189
if ((*j)->getNotationAbsoluteTime() <
190
(*firstHostNote)->getNotationAbsoluteTime()) break;
191
if ((*j)->getSubOrdering() >= 0) continue;
192
if (!(*j)->isa(Note::EventType)) continue;
193
if (!(*j)->has(IS_GRACE_NOTE) || !(*j)->get<Bool>(IS_GRACE_NOTE)) {
194
std::cerr << "SegmentPerformanceHelper::getGraceAndHostNotes: WARNING: Note at " << (*j)->getAbsoluteTime() << " (in trackback) has subordering " << (*j)->getSubOrdering() << " but is not a grace note" << std::endl;
200
if (firstGraceNote == firstHostNote) {
201
std::cerr << "SegmentPerformanceHelper::getGraceAndHostNotes: REMARK: Note at " << (*firstHostNote)->getAbsoluteTime() << " has no grace notes" << std::endl;
207
// push all of the grace notes, and notes with the same time as
208
// the first host note, onto the container
213
if ((*j)->isa(Note::EventType)) {
214
if ((*j)->getSubOrdering() < 0) {
215
if ((*j)->has(IS_GRACE_NOTE) && (*j)->get<Bool>(IS_GRACE_NOTE)) {
216
graceNotes.push_back(j);
219
hostNotes.push_back(j);
220
if (j == i) isHostNote = true;
223
if ((*j)->getNotationAbsoluteTime() >
224
(*firstHostNote)->getNotationAbsoluteTime()) break;
125
233
SegmentPerformanceHelper::getSoundingAbsoluteTime(iterator i)
239
// std::cerr << "SegmentPerformanceHelper::getSoundingAbsoluteTime at " << (*i)->getAbsoluteTime() << std::endl;
241
if ((*i)->has(IS_GRACE_NOTE)) {
242
// std::cerr << "it's a grace note" << std::endl;
243
if (getGraceNoteTimeAndDuration(false, i, t, discard)) return t;
245
if ((*i)->has(MAY_HAVE_GRACE_NOTES)) {
246
// std::cerr << "it's a candidate host note" << std::endl;
247
if (getGraceNoteTimeAndDuration(true, i, t, discard)) return t;
127
250
return (*i)->getAbsoluteTime();
260
// std::cerr << "SegmentPerformanceHelper::getSoundingDuration at " << (*i)->getAbsoluteTime() << std::endl;
262
if ((*i)->has(IS_GRACE_NOTE)) {
263
// std::cerr << "it's a grace note" << std::endl;
264
if (getGraceNoteTimeAndDuration(false, i, discard, d)) return d;
266
if ((*i)->has(MAY_HAVE_GRACE_NOTES)) {
267
// std::cerr << "it's a candidate host note" << std::endl;
268
if (getGraceNoteTimeAndDuration(true, i, discard, d)) return d;
135
271
if ((*i)->has(TIED_BACKWARD)) {
137
273
// Formerly we just returned d in this case, but now we check
343
SegmentPerformanceHelper::getGraceNoteTimeAndDuration(bool host, iterator i,
346
// [This code currently assumes appoggiatura. Acciaccatura later.]
348
// For our present purposes, we will assume that grace notes start
349
// at the same time as their host note was intended to, and
350
// "steal" a proportion of the duration of their host note. This
351
// causes the host note to start later, and be shorter, by that
354
// If a host note has more than one (consecutive) grace note, they
355
// should take a single cut from the grace note and divide it
356
// amongst themselves.
358
// To begin with we will set the proportion to 1/4, but we will
359
// probably want it to be (a) something different [because I don't
360
// really know what I'm doing], (b) adaptive [e.g. shorter host
361
// note or more grace notes = longer proportion], (c)
362
// configurable, or (d) all of the above.
364
// Of course we also ought to be taking into account the notated
365
// duration of the grace notes -- though in my working examples it
366
// generally doesn't seem to be the case that we can always just
367
// follow those. I wonder if we can always use the grace notes'
368
// notated duration if the ratio of grace note duration to host
369
// note duration is less than some value? Whatever we do, we
370
// should be dividing the grace note duration up in proportion to
371
// the durations of the grace notes, in situations where we have
372
// more than one grace note consecutively of different durations;
373
// that isn't handled at all here.
375
if (i == end()) return false;
377
iteratorcontainer graceNotes, hostNotes;
380
if (!getGraceAndHostNotes(i, graceNotes, hostNotes, isHostNote)) {
381
std::cerr << "SegmentPerformanceHelper::getGraceNoteTimeAndDuration: REMARK: Note at " << (*i)->getAbsoluteTime() << " is not a grace note, or has no grace notes" << std::endl;
387
if (!(*i)->has(IS_GRACE_NOTE) || !(*i)->get<Bool>(IS_GRACE_NOTE)) {
388
std::cerr << "SegmentPerformanceHelper::getGraceNoteTimeAndDuration: WARNING: Note at " << (*i)->getAbsoluteTime() << " is neither grace nor host note, but was reported as suitable by getGraceAndHostNotes" << std::endl;
393
if (hostNotes.empty()) {
394
std::cerr << "SegmentPerformanceHelper::getGraceNoteTimeAndDuration: REMARK: Grace note at " << (*i)->getAbsoluteTime() << " has no host note" << std::endl;
398
if (graceNotes.empty()) {
399
std::cerr << "SegmentPerformanceHelper::getGraceNoteTimeAndDuration: REMARK: Note at " << (*i)->getAbsoluteTime() << " has no grace notes" << std::endl;
403
timeT hostNoteEarliestTime = 0;
404
timeT hostNoteShortestDuration = 0;
405
timeT hostNoteNotationDuration = 0;
407
for (iteratorcontainer::iterator j = hostNotes.begin();
408
j != hostNotes.end(); ++j) {
410
if (j == hostNotes.begin() ||
411
(**j)->getAbsoluteTime() < hostNoteEarliestTime) {
412
hostNoteEarliestTime = (**j)->getAbsoluteTime();
414
if (j == hostNotes.begin() ||
415
(**j)->getDuration() < hostNoteShortestDuration) {
416
hostNoteShortestDuration = (**j)->getDuration();
418
if (j == hostNotes.begin() ||
419
(**j)->getNotationDuration() > hostNoteNotationDuration) {
420
hostNoteNotationDuration = (**j)->getNotationDuration();
422
(**j)->set<Bool>(MAY_HAVE_GRACE_NOTES, true);
425
timeT graceNoteTime = hostNoteEarliestTime;
426
timeT graceNoteDuration = hostNoteNotationDuration / 4;
427
if (graceNoteDuration > hostNoteShortestDuration / 2) {
428
graceNoteDuration = hostNoteShortestDuration / 2;
432
t = (*i)->getAbsoluteTime() + graceNoteDuration;
433
d = (*i)->getDuration() - graceNoteDuration;
436
int count = 0, index = 0;
438
int prevSubOrdering = 0;
440
for (iteratorcontainer::iterator j = graceNotes.begin();
441
j != graceNotes.end(); ++j) {
443
bool newChord = false;
445
if ((**j)->getSubOrdering() != prevSubOrdering) {
447
prevSubOrdering = (**j)->getSubOrdering();
450
if (newChord) ++count;
452
if (*j == i) found = true;
455
if (newChord) ++index;
459
if (index == count) index = 0;
460
if (count == 0) count = 1; // should not happen
462
d = graceNoteDuration / count;
463
t = hostNoteEarliestTime + d * index;