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

« back to all changes in this revision

Viewing changes to src/gui/editors/notation/NotationGroup.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 MIDI and audio 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        <richard.bown@ferventsoftware.com>
28
28
 
29
29
#include "base/Equation.h"
30
30
#include "base/Event.h"
 
31
#include "base/NotationRules.h"
31
32
#include "base/NotationTypes.h"
32
33
#include "base/Quantizer.h"
33
34
#include "NotationChord.h"
46
47
                             std::pair<timeT, timeT> barRange,
47
48
                             const NotationProperties &p,
48
49
                             const Clef &clef, const Key &key) :
49
 
        AbstractSet<NotationElement, NotationElementList>(nel, i, q),
50
 
        m_barRange(barRange),
51
 
        //!!! What if the clef and/or key change in the course of the group?
52
 
        m_clef(clef),
53
 
        m_key(key),
54
 
        m_weightAbove(0),
55
 
        m_weightBelow(0),
56
 
        m_userSamples(false),
57
 
        m_type(Beamed),
58
 
        m_properties(p)
 
50
    AbstractSet<NotationElement, NotationElementList>(nel, i, q),
 
51
    m_barRange(barRange),
 
52
    //!!! What if the clef and/or key change in the course of the group?
 
53
    m_clef(clef),
 
54
    m_key(key),
 
55
    m_weightAbove(0),
 
56
    m_weightBelow(0),
 
57
    m_userSamples(false),
 
58
    m_type(Beamed),
 
59
    m_properties(p)
59
60
{
60
 
    if (!(*i)->event()->get
61
 
            <Int>
62
 
            (BaseProperties::BEAMED_GROUP_ID, m_groupNo)) m_groupNo = -1;
 
61
    if (!(*i)->event()->get<Int>
 
62
        (BaseProperties::BEAMED_GROUP_ID, m_groupNo)) m_groupNo = -1;
63
63
 
64
64
    initialise();
65
65
 
124
124
        m_final = i;
125
125
 
126
126
    std::string t;
127
 
    if (!(*i)->event()->get
128
 
            <String>(BaseProperties::BEAMED_GROUP_TYPE, t)) {
129
 
        //      NOTATION_DEBUG << "NotationGroup::NotationGroup: Rejecting sample() for non-beamed element" << endl;
 
127
    if (!(*i)->event()->get<String>(BaseProperties::BEAMED_GROUP_TYPE, t)) {
 
128
        NOTATION_DEBUG << "NotationGroup::NotationGroup: Rejecting sample() for non-beamed element" << endl;
130
129
        return false;
131
130
    }
132
131
 
133
132
    long n;
134
 
    if (!(*i)->event()->get
135
 
            <Int>(BaseProperties::BEAMED_GROUP_ID, n)) return false;
 
133
    if (!(*i)->event()->get<Int>(BaseProperties::BEAMED_GROUP_ID, n)) return false;
136
134
    if (m_groupNo == -1) {
137
135
        m_groupNo = n;
138
136
    } else if (n != m_groupNo) {
139
 
        //      NOTATION_DEBUG << "NotationGroup::NotationGroup: Rejecting sample() for event with group id " << n << " (mine is " << m_groupNo << ")" << endl;
 
137
        NOTATION_DEBUG << "NotationGroup::NotationGroup: Rejecting sample() for event with group id " << n << " (mine is " << m_groupNo << ")" << endl;
140
138
        return false;
141
139
    }
142
140
 
145
143
    } else if (t == BaseProperties::GROUP_TYPE_TUPLED) {
146
144
        m_type = Tupled;
147
145
    } else if (t == BaseProperties::GROUP_TYPE_GRACE) {
148
 
        m_type = Grace;
 
146
        std::cerr << "NotationGroup::NotationGroup: WARNING: Obsolete group type Grace found" << std::endl;
 
147
        return false;
149
148
    } else {
150
149
        NOTATION_DEBUG << "NotationGroup::NotationGroup: Warning: Rejecting sample() for unknown GroupType \"" << t << "\"" << endl;
151
150
        return false;
152
151
    }
153
152
 
154
 
    //    NOTATION_DEBUG << "NotationGroup::sample: group id is " << m_groupNo << endl;
 
153
    NOTATION_DEBUG << "NotationGroup::sample: group id is " << m_groupNo << endl;
155
154
 
156
155
    AbstractSet<NotationElement, NotationElementList>::sample
157
 
    (i, goingForwards);
 
156
        (i, goingForwards);
158
157
 
159
158
    // If the sum of the distances from the middle line to the notes
160
159
    // above the middle line exceeds the sum of the distances from the
164
163
    if (!static_cast<NotationElement*>(*i)->isNote())
165
164
        return true;
166
165
    if (m_userSamples) {
167
 
        if (m_initialNote == getContainer().end())
168
 
            m_initialNote = i;
 
166
        if (m_initialNote == getContainer().end()) m_initialNote = i;
169
167
        m_finalNote = i;
170
168
    }
171
169
 
205
203
NotationGroup::height(const NELIterator &i) const
206
204
{
207
205
    long h = 0;
208
 
    if ((*i)->event()->get
209
 
            <Int>(NotationProperties::HEIGHT_ON_STAFF, h)) {
 
206
    if ((*i)->event()->get<Int>(NotationProperties::HEIGHT_ON_STAFF, h)) {
210
207
        return h;
211
208
    }
212
209
 
222
219
    }
223
220
 
224
221
    // not setMaybe, as we know the property is absent:
225
 
    (*i)->event()->set
226
 
    <Int>(NotationProperties::HEIGHT_ON_STAFF, h, false);
 
222
    (*i)->event()->set<Int>(NotationProperties::HEIGHT_ON_STAFF, h, false);
227
223
    return h;
228
224
}
229
225
 
230
226
void
231
227
NotationGroup::applyStemProperties()
232
228
{
233
 
    NELIterator initialNote(getInitialNote()),
234
 
    finalNote( getFinalNote());
 
229
    NotationRules rules;
 
230
 
 
231
    NELIterator
 
232
        initialNote(getInitialNote()),
 
233
        finalNote(getFinalNote());
235
234
 
236
235
    if (initialNote == getContainer().end() ||
237
 
            initialNote == finalNote) {
 
236
        initialNote == finalNote) {
 
237
        //!!! This is not true -- if initialNote == finalNote there is
 
238
        // one note in the group, not none.  But we still won't have a
 
239
        // beam.
238
240
        NOTATION_DEBUG << "NotationGroup::applyStemProperties: no notes in group"
239
 
        << endl;
240
 
        return ; // no notes, no case to answer
 
241
                       << endl;
 
242
        return; // no notes, no case to answer
 
243
    }
 
244
 
 
245
    if (getHighestNote() == getContainer().end()) {
 
246
        std::cerr << "ERROR: NotationGroup::applyStemProperties: no highest note!" << std::endl;
 
247
        abort();
 
248
    }
 
249
 
 
250
    if (getLowestNote() == getContainer().end()) {
 
251
        std::cerr << "ERROR: NotationGroup::applyStemProperties: no lowest note!" << std::endl;
 
252
        abort();
241
253
    }
242
254
 
243
255
    int up = 0, down = 0;
246
258
        NotationElement* el = static_cast<NotationElement*>(*i);
247
259
        if (el->isNote()) {
248
260
            if (el->event()->has(NotationProperties::STEM_UP)) {
249
 
                if (el->event()->get
250
 
                        <Bool>(NotationProperties::STEM_UP)) ++up;
251
 
                else
252
 
                    ++down;
 
261
                if (el->event()->get<Bool>(NotationProperties::STEM_UP)) ++up;
 
262
                else ++down;
253
263
            }
254
264
        }
255
265
 
256
 
        if (i == finalNote)
257
 
            break;
 
266
        if (i == finalNote) break;
258
267
    }
259
268
 
260
269
    NOTATION_DEBUG << "NotationGroup::applyStemProperties: weightAbove "
261
 
    << m_weightAbove << ", weightBelow " << m_weightBelow
262
 
    << ", up " << up << ", down " << down << endl;
 
270
                   << m_weightAbove << ", weightBelow " << m_weightBelow
 
271
                   << ", up " << up << ", down " << down << endl;
263
272
 
264
 
    bool aboveNotes = !(m_weightAbove > m_weightBelow);
 
273
    bool aboveNotes = rules.isBeamAbove(height(getHighestNote()),
 
274
                                        height(getLowestNote()),
 
275
                                        m_weightAbove,
 
276
                                        m_weightBelow);
265
277
    if (up != down) {
266
 
        if (up > down)
267
 
            aboveNotes = true;
268
 
        else
269
 
            aboveNotes = false;
 
278
        if (up > down) aboveNotes = true;
 
279
        else aboveNotes = false;
270
280
    }
271
281
 
272
282
    NOTATION_DEBUG << "NotationGroup::applyStemProperties: hence aboveNotes "
273
 
    << aboveNotes << endl;
 
283
                   << aboveNotes << endl;
274
284
 
275
285
    /*!!!
276
286
        if ((*initialNote)->event()->has(STEM_UP) &&
285
295
        }
286
296
    */
287
297
    for (NELIterator i = initialNote; i != getContainer().end(); ++i) {
 
298
 
288
299
        NotationElement* el = static_cast<NotationElement*>(*i);
289
300
 
290
301
        el->event()->setMaybe<Bool>(NotationProperties::BEAM_ABOVE, aboveNotes);
291
302
 
292
303
        if (el->isNote() &&
293
 
                el->event()->has(BaseProperties::NOTE_TYPE) &&
294
 
                el->event()->get
295
 
                <Int>(BaseProperties::NOTE_TYPE) < Note::Crotchet &&
296
 
                el->event()->has(BaseProperties::BEAMED_GROUP_ID) &&
297
 
                el->event()->get<Int>(BaseProperties::BEAMED_GROUP_ID) == m_groupNo) {
 
304
            el->event()->has(BaseProperties::NOTE_TYPE) &&
 
305
            el->event()->get<Int>(BaseProperties::NOTE_TYPE) < Note::Crotchet &&
 
306
            el->event()->has(BaseProperties::BEAMED_GROUP_ID) &&
 
307
            el->event()->get<Int>(BaseProperties::BEAMED_GROUP_ID) == m_groupNo) {
298
308
 
299
309
            el->event()->setMaybe<Bool>(NotationProperties::BEAMED, true);
300
310
            //      el->event()->setMaybe<Bool>(m_properties.VIEW_LOCAL_STEM_UP, aboveNotes);
301
311
 
302
 
        }
303
 
        else if (el->isNote()) {
 
312
        } else if (el->isNote()) {
304
313
 
305
314
            if (i == initialNote || i == finalNote) {
306
315
                (*i)->event()->setMaybe<Bool>
307
 
                (m_properties.VIEW_LOCAL_STEM_UP, aboveNotes);
 
316
                    (m_properties.VIEW_LOCAL_STEM_UP, aboveNotes);
308
317
            } else {
309
318
                (*i)->event()->setMaybe<Bool>
310
 
                (m_properties.VIEW_LOCAL_STEM_UP, !aboveNotes);
 
319
                    (m_properties.VIEW_LOCAL_STEM_UP, !aboveNotes);
311
320
            }
312
321
        }
313
322
 
327
336
 
328
337
        if (el->isNote() &&
329
338
                el->event()->has(BaseProperties::NOTE_TYPE) &&
330
 
                el->event()->get
331
 
                <Int>(BaseProperties::NOTE_TYPE) < Note::Crotchet &&
 
339
                el->event()->get<Int>(BaseProperties::NOTE_TYPE) < Note::Crotchet &&
332
340
                el->event()->has(BaseProperties::BEAMED_GROUP_ID) &&
333
341
                el->event()->get<Int>(BaseProperties::BEAMED_GROUP_ID) == m_groupNo) {
334
342
            if (found) return true; // a rest is wholly enclosed by beamed notes
344
352
}
345
353
 
346
354
NotationGroup::Beam
347
 
 
348
355
NotationGroup::calculateBeam(NotationStaff &staff)
349
356
{
 
357
    NotationRules rules;
 
358
 
350
359
    Beam beam;
351
 
    beam.aboveNotes = !(m_weightAbove > m_weightBelow);
 
360
    beam.aboveNotes = true;
352
361
    beam.startY = 0;
353
362
    beam.gradient = 0;
354
363
    beam.necessary = false;
355
364
 
356
 
    NELIterator initialNote(getInitialNote()),
357
 
    finalNote( getFinalNote());
 
365
    NELIterator 
 
366
        initialNote(getInitialNote()),
 
367
        finalNote(getFinalNote());
358
368
 
359
369
    if (initialNote == getContainer().end() ||
360
 
            initialNote == finalNote) {
 
370
        initialNote == finalNote) {
361
371
        return beam; // no notes, or at most one: no case to answer
362
372
    }
363
373
 
 
374
    beam.aboveNotes = rules.isBeamAbove(height(getHighestNote()),
 
375
                                        height(getLowestNote()),
 
376
                                        m_weightAbove,
 
377
                                        m_weightBelow);
 
378
 
364
379
    if ((*initialNote)->event()->has(NotationProperties::BEAM_ABOVE)) {
365
380
        beam.aboveNotes = (*initialNote)->event()->get
366
381
                          <Bool>
368
383
    }
369
384
 
370
385
    timeT crotchet = Note(Note::Crotchet).getDuration();
 
386
 
371
387
    beam.necessary =
372
 
        (*initialNote)->getViewDuration() < crotchet
373
 
        && (*finalNote)->getViewDuration() < crotchet
374
 
        && (*finalNote)->getViewAbsoluteTime() >
375
 
        (*initialNote)->getViewAbsoluteTime();
 
388
        (*initialNote)->getViewDuration() < crotchet &&
 
389
        (*finalNote)->getViewDuration() < crotchet;
 
390
 
 
391
    beam.necessary = beam.necessary &&
 
392
        (((*finalNote)->getViewAbsoluteTime() >
 
393
          (*initialNote)->getViewAbsoluteTime()) ||
 
394
         (((*finalNote)->getViewAbsoluteTime() ==
 
395
           (*initialNote)->getViewAbsoluteTime()) &&
 
396
          ((*finalNote)->event()->getSubOrdering() >
 
397
           (*initialNote)->event()->getSubOrdering())));
376
398
 
377
399
    // We continue even if the beam is not necessary, because the
378
400
    // same data is used to generate the tupling line in tupled
380
402
 
381
403
    // if (!beam.necessary) return beam;
382
404
 
 
405
    NOTATION_DEBUG << "NotationGroup::calculateBeam: beam necessariness: " << beam.necessary << endl;
 
406
 
383
407
    NotationChord initialChord(getContainer(), initialNote, &getQuantizer(),
384
408
                               m_properties, m_clef, m_key),
385
409
    finalChord(getContainer(), finalNote, &getQuantizer(),
389
413
        return beam;
390
414
    }
391
415
 
 
416
    bool isGrace =
 
417
        (*initialNote)->event()->has(BaseProperties::IS_GRACE_NOTE) &&
 
418
        (*initialNote)->event()->get<Bool>(BaseProperties::IS_GRACE_NOTE);
 
419
 
392
420
    int initialHeight, finalHeight, extremeHeight;
393
421
    NELIterator extremeNote;
394
422
 
407
435
    }
408
436
 
409
437
    int diff = initialHeight - finalHeight;
410
 
    if (diff < 0)
411
 
        diff = -diff;
 
438
    if (diff < 0) diff = -diff;
412
439
 
413
440
    bool linear =
414
441
        (beam.aboveNotes ?
439
466
    int finalDX = (int) (*finalNote)->getLayoutX() - initialX;
440
467
    int extremeDX = (int)(*extremeNote)->getLayoutX() - initialX;
441
468
 
442
 
    int spacing = staff.getNotePixmapFactory(m_type == Grace).getLineSpacing();
 
469
    int spacing = staff.getNotePixmapFactory(isGrace).getLineSpacing();
443
470
 
444
471
    beam.gradient = 0;
445
472
    if (finalDX > 0) {
479
506
    }
480
507
 
481
508
    // minimal stem lengths at start, middle-extreme and end of beam
482
 
    int sl = staff.getNotePixmapFactory(m_type == Grace).getStemLength();
 
509
    int sl = staff.getNotePixmapFactory(isGrace).getStemLength();
483
510
    int ml = spacing * 2;
484
511
    int el = sl;
485
512
 
498
525
 
499
526
        if ((c0 - sl > topY) || (c1 - ml > topY) || (c2 - el > topY)) {
500
527
            if (haveInternalRest()) {
501
 
                if (c0 - sl > topY)
502
 
                    sl = c0 - topY;
503
 
                if (c1 - ml > topY)
504
 
                    ml = c1 - topY;
505
 
                if (c2 - el > topY)
506
 
                    el = c2 - topY;
 
528
                if (c0 - sl > topY) sl = c0 - topY;
 
529
                if (c1 - ml > topY) ml = c1 - topY;
 
530
                if (c2 - el > topY) el = c2 - topY;
507
531
                NOTATION_DEBUG << "made internal rest adjustment for above notes" << endl;
508
532
                NOTATION_DEBUG << "sl: " << sl << ", ml: " << ml << ", el: " << el << endl;
509
533
            }
513
537
 
514
538
        if ((c0 + sl < bottomY) || (c1 + ml < bottomY) || (c2 + el < bottomY)) {
515
539
            if (haveInternalRest()) {
516
 
                if (c0 + sl < bottomY)
517
 
                    sl = bottomY - c0;
518
 
                if (c1 + ml < bottomY)
519
 
                    ml = bottomY - c1;
520
 
                if (c2 + el < bottomY)
521
 
                    el = bottomY - c2;
 
540
                if (c0 + sl < bottomY) sl = bottomY - c0;
 
541
                if (c1 + ml < bottomY) ml = bottomY - c1;
 
542
                if (c2 + el < bottomY) el = bottomY - c2;
522
543
                NOTATION_DEBUG << "made internal rest adjustment for below notes" << endl;
523
544
                NOTATION_DEBUG << "sl: " << sl << ", ml: " << ml << ", el: " << el << endl;
524
545
            }
542
563
 
543
564
    // ensure extended to middle line if necessary, and assign suitable stem length
544
565
    if (beam.aboveNotes) {
545
 
        if (c0 - sl > midY)
546
 
            sl = c0 - midY;
547
 
        if (c1 - ml > midY)
548
 
            ml = c1 - midY;
549
 
        if (c2 - el > midY)
550
 
            el = c2 - midY;
 
566
        if (c0 - sl > midY) sl = c0 - midY;
 
567
        if (c1 - ml > midY) ml = c1 - midY;
 
568
        if (c2 - el > midY) el = c2 - midY;
551
569
        if (extremeDX > 1.0 || extremeDX < -1.0) {
552
570
            //      beam.gradient = int(100 * double(c2 - c0) / double(extremeDX));
553
571
        }
554
572
        beam.startY = min(min(c0 - sl, c1 - ml), c2 - el);
555
573
    } else {
556
 
        if (c0 + sl < midY)
557
 
            sl = midY - c0;
558
 
        if (c1 + ml < midY)
559
 
            ml = midY - c1;
560
 
        if (c2 + el < midY)
561
 
            el = midY - c2;
 
574
        if (c0 + sl < midY) sl = midY - c0;
 
575
        if (c1 + ml < midY) ml = midY - c1;
 
576
        if (c2 + el < midY) el = midY - c2;
562
577
        if (extremeDX > 1.0 || extremeDX < -1.0) {
563
578
            //      beam.gradient = int(100 * double(c2 - c0) / double(extremeDX));
564
579
        }
841
856
 
842
857
    Beam beam(calculateBeam(staff));
843
858
 
844
 
    NELIterator initialNote(getInitialNote()),
845
 
    finalNote( getFinalNote()),
846
 
 
847
 
    initialElement(getInitialElement()),
848
 
    finalElement( getFinalElement());
849
 
 
 
859
    NELIterator
 
860
        initialNote(getInitialNote()),
 
861
        finalNote(getFinalNote()),
 
862
        initialElement(getInitialElement()),
 
863
        finalElement(getFinalElement());
 
864
    
850
865
    NELIterator initialNoteOrRest(initialElement);
851
866
    NotationElement* initialNoteOrRestEl = static_cast<NotationElement*>(*initialNoteOrRest);
852
867
 
862
877
        initialNoteOrRestEl = static_cast<NotationElement*>(*initialNoteOrRest);
863
878
    }
864
879
 
865
 
    if (initialNoteOrRest == staff.getViewElementList()->end())
866
 
        return ;
 
880
    if (initialNoteOrRest == staff.getViewElementList()->end()) return;
 
881
 
 
882
    bool isGrace = false;
 
883
    if (initialNote != staff.getViewElementList()->end()) {
 
884
        isGrace =
 
885
            (*initialNote)->event()->has(BaseProperties::IS_GRACE_NOTE) &&
 
886
            (*initialNote)->event()->get<Bool>(BaseProperties::IS_GRACE_NOTE);
 
887
    }
867
888
 
868
889
    //    NOTATION_DEBUG << "NotationGroup::applyTuplingLine: first element is " << (initialNoteOrRestEl->isNote() ? "Note" : "Non-Note") << ", last is " << (static_cast<NotationElement*>(*finalElement)->isNote() ? "Note" : "Non-Note") << endl;
869
890
 
871
892
    int finalX = (int)(*finalElement)->getLayoutX();
872
893
 
873
894
    if (initialNote == staff.getViewElementList()->end() &&
874
 
            finalNote == staff.getViewElementList()->end()) {
 
895
          finalNote == staff.getViewElementList()->end()) {
875
896
 
876
897
        Event *e = (*initialNoteOrRest)->event();
877
898
        e->setMaybe<Int>(m_properties.TUPLING_LINE_MY_Y,
903
924
 
904
925
        //      NOTATION_DEBUG << "applyTuplingLine: beam.startY is " << beam.startY << ", initialY is " << initialY << " so my startY is " << startY << ", endY " << endY << ", beam.gradient " << beam.gradient << endl;
905
926
 
906
 
        int nh = staff.getNotePixmapFactory(m_type == Grace).getNoteBodyHeight();
 
927
        int nh = staff.getNotePixmapFactory(isGrace).getNoteBodyHeight();
907
928
 
908
929
        if (followBeam) { // adjust to move text slightly away from beam
909
930
 
910
931
            int maxEndBeamCount = 1;
911
932
            long bc;
912
 
            if ((*initialNoteOrRest)->event()->get
913
 
                    <Int>
914
 
                    (m_properties.BEAM_NEXT_BEAM_COUNT, bc)) {
 
933
            if ((*initialNoteOrRest)->event()->get<Int>
 
934
                (m_properties.BEAM_NEXT_BEAM_COUNT, bc)) {
915
935
                if (bc > maxEndBeamCount)
916
936
                    maxEndBeamCount = bc;
917
937
            }
918
 
            if ((*finalNote)->event()->get
919
 
                    <Int>
920
 
                    (m_properties.BEAM_NEXT_BEAM_COUNT, bc)) {
 
938
            if ((*finalNote)->event()->get<Int>
 
939
                (m_properties.BEAM_NEXT_BEAM_COUNT, bc)) {
921
940
                if (bc > maxEndBeamCount)
922
941
                    maxEndBeamCount = bc;
923
942
            }