~ubuntu-branches/ubuntu/karmic/rosegarden/karmic

« back to all changes in this revision

Viewing changes to src/base/SegmentPerformanceHelper.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Ebner
  • Date: 2008-05-02 00:33:44 UTC
  • mfrom: (1.1.7 upstream) (6.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080502003344-67vbfhgqx2yl0ksi
Tags: 1:1.7.0-1ubuntu1
* Merge from Debian unstable. (LP: #225849) Remaining Ubuntu changes:
  - Add usr/share/doc/kde/HTML to rosegarden-data, to provide online
    help documentation.
  - Change fftw3-dev to libfftw3-dev.
  - Update maintainer field as per spec.

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
    Rosegarden
5
5
    A sequencer and musical notation editor.
6
6
 
7
 
    This program is Copyright 2000-2007
 
7
    This program is Copyright 2000-2008
8
8
        Guillaume Laurent   <glaurent@telegraph-road.org>,
9
9
        Chris Cannam        <cannam@all-day-breakfast.com>,
10
10
        Richard Bown        <bownie@bownie.com>
47
47
    e->get<Bool>(TIED_BACKWARD, tiedBack);
48
48
    e->get<Bool>(TIED_FORWARD, tiedForward);
49
49
 
50
 
    timeT d = e->getDuration();
51
 
    timeT t = e->getAbsoluteTime();
 
50
    timeT d = e->getNotationDuration();
 
51
    timeT t = e->getNotationAbsoluteTime();
52
52
 
53
53
    if (!e->has(PITCH)) return c;
54
54
    int pitch = e->get<Int>(PITCH);
65
65
            if (!(*j)->isa(Note::EventType)) continue;
66
66
            e = *j; // can reuse e because this branch always returns
67
67
 
68
 
            timeT t2 = e->getAbsoluteTime() + e->getDuration();
 
68
            timeT t2 = e->getNotationAbsoluteTime() + e->getNotationDuration();
69
69
            if (t2 < t) break;
70
70
 
71
71
            if (t2 > t || !e->has(PITCH) ||
94
94
 
95
95
        e = *j;
96
96
 
97
 
        timeT t2 = e->getAbsoluteTime();
 
97
        timeT t2 = e->getNotationAbsoluteTime();
98
98
        
99
99
        if (t2 > t + d) break;
100
100
        else if (t2 < t + d || !e->has(PITCH) ||
103
103
        if (!e->get<Bool>(TIED_BACKWARD, tiedBack) ||
104
104
            !tiedBack) break;
105
105
 
106
 
        d += e->getDuration();
 
106
        d += e->getNotationDuration();
107
107
        c.push_back(j);
108
108
        valid = true;
109
109
 
121
121
}
122
122
 
123
123
 
 
124
bool
 
125
SegmentPerformanceHelper::getGraceAndHostNotes(iterator i,
 
126
                                               iteratorcontainer &graceNotes,
 
127
                                               iteratorcontainer &hostNotes,
 
128
                                               bool &isHostNote)
 
129
{
 
130
    if (i == end() || !(*i)->isa(Note::EventType)) return false;
 
131
 
 
132
    Segment::iterator j = i;
 
133
    Segment::iterator firstGraceNote = i;
 
134
    Segment::iterator firstHostNote = i;
 
135
 
 
136
    if ((*i)->has(IS_GRACE_NOTE) && (*i)->get<Bool>(IS_GRACE_NOTE)) {
 
137
 
 
138
        // i is a grace note.  Find the first host note following it
 
139
 
 
140
        j = i;
 
141
        while (++j != end()) {
 
142
            if ((*j)->getNotationAbsoluteTime() >
 
143
                (*i)->getNotationAbsoluteTime()) break;
 
144
            if ((*j)->getSubOrdering() < 0) continue;
 
145
            if ((*j)->isa(Note::EventType)) {
 
146
                firstHostNote = j;
 
147
                break;
 
148
            }
 
149
        }
 
150
 
 
151
        if (firstHostNote == i) {
 
152
            std::cerr << "SegmentPerformanceHelper::getGraceAndHostNotes: REMARK: Grace note at " << (*i)->getAbsoluteTime() << " has no host note" << std::endl;
 
153
            return false;
 
154
        }
 
155
    } else {
 
156
 
 
157
        // i is a host note, but we need to ensure we have the first
 
158
        // one, not just any one
 
159
 
 
160
        j = i;
 
161
 
 
162
        while (j != begin()) {
 
163
            --j;
 
164
            if ((*j)->getNotationAbsoluteTime() <
 
165
                (*i)->getNotationAbsoluteTime()) break;
 
166
            if ((*j)->getSubOrdering() < 
 
167
                (*i)->getSubOrdering()) break;
 
168
            if ((*j)->isa(Note::EventType)) {
 
169
                firstHostNote = j;
 
170
                break;
 
171
            }
 
172
        }
 
173
    }
 
174
 
 
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).
 
179
 
 
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;
 
182
        return false;
 
183
    }
 
184
 
 
185
    j = firstHostNote;
 
186
 
 
187
    while (j != begin()) {
 
188
        --j;
 
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;
 
195
            break;
 
196
        }
 
197
        firstGraceNote = j;
 
198
    }
 
199
    
 
200
    if (firstGraceNote == firstHostNote) {
 
201
        std::cerr << "SegmentPerformanceHelper::getGraceAndHostNotes: REMARK: Note at " << (*firstHostNote)->getAbsoluteTime() << " has no grace notes" << std::endl;
 
202
        return false;
 
203
    }
 
204
 
 
205
    j = firstGraceNote;
 
206
 
 
207
    // push all of the grace notes, and notes with the same time as
 
208
    // the first host note, onto the container
 
209
 
 
210
    isHostNote = false;
 
211
 
 
212
    while (j != end()) {
 
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);
 
217
                }
 
218
            } else {
 
219
                hostNotes.push_back(j);
 
220
                if (j == i) isHostNote = true;
 
221
            }
 
222
        }
 
223
        if ((*j)->getNotationAbsoluteTime() >
 
224
            (*firstHostNote)->getNotationAbsoluteTime()) break;
 
225
        ++j;
 
226
    }
 
227
 
 
228
    return true;
 
229
}
 
230
 
 
231
 
124
232
timeT
125
233
SegmentPerformanceHelper::getSoundingAbsoluteTime(iterator i)
126
234
{
 
235
    timeT t = 0;
 
236
 
 
237
    timeT discard;
 
238
 
 
239
//    std::cerr << "SegmentPerformanceHelper::getSoundingAbsoluteTime at " << (*i)->getAbsoluteTime() << std::endl;
 
240
 
 
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;
 
244
    }
 
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;
 
248
    }
 
249
 
127
250
    return (*i)->getAbsoluteTime();
128
251
}
129
252
 
132
255
{
133
256
    timeT d = 0;
134
257
 
 
258
    timeT discard;
 
259
 
 
260
//    std::cerr << "SegmentPerformanceHelper::getSoundingDuration at " << (*i)->getAbsoluteTime() << std::endl;
 
261
 
 
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;
 
265
    }
 
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;
 
269
    }
 
270
 
135
271
    if ((*i)->has(TIED_BACKWARD)) {
136
272
        
137
273
        // Formerly we just returned d in this case, but now we check
203
339
}
204
340
 
205
341
 
 
342
bool
 
343
SegmentPerformanceHelper::getGraceNoteTimeAndDuration(bool host, iterator i,
 
344
                                                      timeT &t, timeT &d)
 
345
{
 
346
    // [This code currently assumes appoggiatura.  Acciaccatura later.]
 
347
 
 
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
 
352
    // same proportion.
 
353
 
 
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.
 
357
 
 
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.
 
363
 
 
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.
 
374
 
 
375
    if (i == end()) return false;
 
376
 
 
377
    iteratorcontainer graceNotes, hostNotes;
 
378
    bool isHostNote;
 
379
 
 
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;
 
382
        return false;
 
383
    }
 
384
 
 
385
    if (!isHostNote) {
 
386
 
 
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;
 
389
            return false;
 
390
        }
 
391
    }
 
392
 
 
393
    if (hostNotes.empty()) {
 
394
        std::cerr << "SegmentPerformanceHelper::getGraceNoteTimeAndDuration: REMARK: Grace note at " << (*i)->getAbsoluteTime() << " has no host note" << std::endl;
 
395
        return false;
 
396
    }
 
397
 
 
398
    if (graceNotes.empty()) {
 
399
        std::cerr << "SegmentPerformanceHelper::getGraceNoteTimeAndDuration: REMARK: Note at " << (*i)->getAbsoluteTime() << " has no grace notes" << std::endl;
 
400
        return false;
 
401
    }
 
402
 
 
403
    timeT hostNoteEarliestTime = 0;
 
404
    timeT hostNoteShortestDuration = 0;
 
405
    timeT hostNoteNotationDuration = 0;
 
406
 
 
407
    for (iteratorcontainer::iterator j = hostNotes.begin();
 
408
         j != hostNotes.end(); ++j) {
 
409
 
 
410
        if (j == hostNotes.begin() ||
 
411
            (**j)->getAbsoluteTime() < hostNoteEarliestTime) {
 
412
            hostNoteEarliestTime = (**j)->getAbsoluteTime();
 
413
        }
 
414
        if (j == hostNotes.begin() ||
 
415
            (**j)->getDuration() < hostNoteShortestDuration) {
 
416
            hostNoteShortestDuration = (**j)->getDuration();
 
417
        }
 
418
        if (j == hostNotes.begin() ||
 
419
            (**j)->getNotationDuration() > hostNoteNotationDuration) {
 
420
            hostNoteNotationDuration = (**j)->getNotationDuration();
 
421
        }
 
422
        (**j)->set<Bool>(MAY_HAVE_GRACE_NOTES, true);
 
423
    }
 
424
 
 
425
    timeT graceNoteTime = hostNoteEarliestTime;
 
426
    timeT graceNoteDuration = hostNoteNotationDuration / 4;
 
427
    if (graceNoteDuration > hostNoteShortestDuration / 2) {
 
428
        graceNoteDuration = hostNoteShortestDuration / 2;
 
429
    }
 
430
 
 
431
    if (isHostNote) {
 
432
        t = (*i)->getAbsoluteTime() + graceNoteDuration;
 
433
        d = (*i)->getDuration() - graceNoteDuration;
 
434
    } else {
 
435
 
 
436
        int count = 0, index = 0;
 
437
        bool found = false;
 
438
        int prevSubOrdering = 0;
 
439
 
 
440
        for (iteratorcontainer::iterator j = graceNotes.begin();
 
441
             j != graceNotes.end(); ++j) {
 
442
 
 
443
            bool newChord = false;
 
444
 
 
445
            if ((**j)->getSubOrdering() != prevSubOrdering) {
 
446
                newChord = true;
 
447
                prevSubOrdering = (**j)->getSubOrdering();
 
448
            }
 
449
 
 
450
            if (newChord) ++count;
 
451
 
 
452
            if (*j == i) found = true;
 
453
 
 
454
            if (!found) {
 
455
                if (newChord) ++index;
 
456
            }
 
457
        }
 
458
 
 
459
        if (index == count) index = 0;
 
460
        if (count == 0) count = 1; // should not happen
 
461
 
 
462
        d = graceNoteDuration / count;
 
463
        t = hostNoteEarliestTime + d * index;
 
464
    }
 
465
 
 
466
    return true;
 
467
 
 
468
 
 
469
}
 
470
 
 
471
 
206
472
}