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

« back to all changes in this revision

Viewing changes to src/commands/notation/NoteInsertionCommand.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>
25
25
 
26
26
#include "NoteInsertionCommand.h"
27
27
 
 
28
#include <cmath>
28
29
#include <klocale.h>
29
30
#include "base/Event.h"
30
31
#include "base/NotationTypes.h"
43
44
using namespace BaseProperties;
44
45
 
45
46
NoteInsertionCommand::NoteInsertionCommand(Segment &segment, timeT time,
46
 
        timeT endTime, Note note, int pitch,
47
 
        Accidental accidental,
48
 
        bool autoBeam,
49
 
        bool matrixType,
50
 
        NoteStyleName noteStyle) :
 
47
                                           timeT endTime, Note note, int pitch,
 
48
                                           Accidental accidental,
 
49
                                           AutoBeamMode autoBeam,
 
50
                                           MatrixMode matrixType,
 
51
                                           GraceMode grace,
 
52
                                           float targetSubordering,
 
53
                                           NoteStyleName noteStyle) :
51
54
        BasicCommand(i18n("Insert Note"), segment,
52
55
                     getModificationStartTime(segment, time),
53
56
                     (autoBeam ? segment.getBarEndForTime(endTime) : endTime)),
55
58
        m_note(note),
56
59
        m_pitch(pitch),
57
60
        m_accidental(accidental),
58
 
        m_autoBeam(autoBeam),
59
 
        m_matrixType(matrixType),
 
61
        m_autoBeam(autoBeam == AutoBeamOn),
 
62
        m_matrixType(matrixType == MatrixModeOn),
 
63
        m_grace(grace),
 
64
        m_targetSubordering(targetSubordering),
60
65
        m_noteStyle(noteStyle),
61
66
        m_lastInsertedEvent(0)
62
67
{
94
99
{
95
100
    Segment &segment(getSegment());
96
101
    SegmentNotationHelper helper(segment);
97
 
 
98
 
    // If we're attempting to insert at the same time and pitch as an
99
 
    // existing note, then we remove the existing note first (so as to
100
 
    // change its duration, if the durations differ)
101
102
    Segment::iterator i, j;
102
 
    segment.getTimeSlice(m_insertionTime, i, j);
103
 
    while (i != j) {
104
 
        if ((*i)->isa(Note::EventType)) {
105
 
            long pitch;
106
 
            if ((*i)->get
107
 
                    <Int>(PITCH, pitch) && pitch == m_pitch) {
108
 
                helper.deleteNote(*i);
109
 
                break;
110
 
            }
111
 
        }
112
 
        ++i;
113
 
    }
114
103
 
115
104
    // insert via a model event, so as to apply the note style
116
105
 
117
 
    Event *e = new Event
118
 
               (Note::EventType, m_insertionTime, m_note.getDuration());
119
 
 
120
 
    e->set
121
 
    <Int>(PITCH, m_pitch);
122
 
    e->set
123
 
    <Int>(VELOCITY, 100);
 
106
    // subordering is always negative for these insertions; round it down
 
107
    int actualSubordering = lrintf(floorf(m_targetSubordering + 0.01));
 
108
    if ((m_grace != GraceModeOff) && actualSubordering >= 0) {
 
109
        actualSubordering = -1;
 
110
    }
 
111
 
 
112
    // this is true if the subordering is "more or less" an integer,
 
113
    // as opposed to something like -0.5
 
114
    bool suborderingExact = (actualSubordering != 
 
115
                             (lrintf(floorf(m_targetSubordering - 0.01))));
 
116
 
 
117
    std::cerr << "actualSubordering = " << actualSubordering
 
118
              << " suborderingExact = " << suborderingExact << std::endl;
 
119
 
 
120
    Event *e;
 
121
 
 
122
    if (m_grace == GraceModeOff) {
 
123
 
 
124
        e = new Event
 
125
            (Note::EventType,
 
126
             m_insertionTime,
 
127
             m_note.getDuration(),
 
128
             0,
 
129
             m_insertionTime,
 
130
             m_note.getDuration());
 
131
 
 
132
    } else {
 
133
 
 
134
        e = new Event
 
135
            (Note::EventType,
 
136
             m_insertionTime,
 
137
             0,
 
138
             actualSubordering == 0 ? -1 : actualSubordering,
 
139
             m_insertionTime,
 
140
             m_note.getDuration());
 
141
    }
 
142
 
 
143
    e->set<Int>(PITCH, m_pitch);
 
144
    e->set<Int>(VELOCITY, 100);
124
145
 
125
146
    if (m_accidental != Accidentals::NoAccidental) {
126
 
        e->set
127
 
        <String>(ACCIDENTAL, m_accidental);
 
147
        e->set<String>(ACCIDENTAL, m_accidental);
128
148
    }
129
149
 
130
150
    if (m_noteStyle != NoteStyleFactory::DefaultStyle) {
131
 
        e->set
132
 
        <String>(NotationProperties::NOTE_STYLE, m_noteStyle);
 
151
        e->set<String>(NotationProperties::NOTE_STYLE, m_noteStyle);
133
152
    }
134
153
 
135
 
    if (m_matrixType) {
136
 
        i = SegmentMatrixHelper(segment).insertNote(e);
 
154
    if (m_grace != GraceModeOff) {
 
155
 
 
156
        if (!suborderingExact) {
 
157
 
 
158
            // Adjust suborderings of any existing grace notes, if there
 
159
            // is at least one with the same subordering and
 
160
            // suborderingExact is not set
 
161
 
 
162
            segment.getTimeSlice(m_insertionTime, i, j);
 
163
            bool collision = false;
 
164
            for (Segment::iterator k = i; k != j; ++k) {
 
165
                if ((*k)->getSubOrdering() == actualSubordering) {
 
166
                    collision = true;
 
167
                    break;
 
168
                }
 
169
            }
 
170
            
 
171
            if (collision) {
 
172
                std::vector<Event *> toInsert, toErase;
 
173
                for (Segment::iterator k = i; k != j; ++k) {
 
174
                    if ((*k)->isa(Note::EventType) &&
 
175
                        (*k)->getSubOrdering() <= actualSubordering) {
 
176
                        toErase.push_back(*k);
 
177
                        toInsert.push_back
 
178
                            (new Event(**k,
 
179
                                       (*k)->getAbsoluteTime(),
 
180
                                       (*k)->getDuration(),
 
181
                                       (*k)->getSubOrdering() - 1,
 
182
                                       (*k)->getNotationAbsoluteTime(),
 
183
                                       (*k)->getNotationDuration()));
 
184
                    }
 
185
                }
 
186
                for (std::vector<Event *>::iterator k = toErase.begin();
 
187
                     k != toErase.end(); ++k) segment.eraseSingle(*k);
 
188
                for (std::vector<Event *>::iterator k = toInsert.begin();
 
189
                     k != toInsert.end(); ++k) segment.insert(*k);
 
190
            }
 
191
        }
 
192
 
 
193
        e->set<Bool>(IS_GRACE_NOTE, true);
 
194
        i = segment.insert(e);
 
195
 
 
196
        Segment::iterator k;
 
197
        segment.getTimeSlice(m_insertionTime, j, k);
 
198
        Segment::iterator bg0 = segment.end(), bg1 = segment.end();
 
199
        while (j != k) {
 
200
            std::cerr << "testing for truthiness: time " << (*j)->getAbsoluteTime() << ", subordering " << (*j)->getSubOrdering() << std::endl;
 
201
            if ((*j)->isa(Note::EventType) &&
 
202
                (*j)->getSubOrdering() < 0 &&
 
203
                (*j)->has(IS_GRACE_NOTE) &&
 
204
                (*j)->get<Bool>(IS_GRACE_NOTE)) {
 
205
                std::cerr << "truthiful" << std::endl;
 
206
                if (bg0 == segment.end()) bg0 = j;
 
207
                bg1 = j;
 
208
            }
 
209
            ++j;
 
210
        }
 
211
 
 
212
        if (bg0 != segment.end() && bg1 != bg0) {
 
213
            if (bg1 != segment.end()) ++bg1;
 
214
            int count = 0;
 
215
            int pso = 0;
 
216
            for (Segment::iterator i = bg0; i != bg1; ++i) {
 
217
                (*i)->unset(BEAMED_GROUP_ID);
 
218
                (*i)->unset(BEAMED_GROUP_TYPE);
 
219
                (*i)->unset(BEAMED_GROUP_TUPLED_COUNT);
 
220
                (*i)->unset(BEAMED_GROUP_UNTUPLED_COUNT);
 
221
                if ((*i)->getSubOrdering() != pso) {
 
222
                    ++count;
 
223
                    pso = (*i)->getSubOrdering();
 
224
                }
 
225
            }
 
226
            if (m_grace == GraceAndTripletModesOn) {
 
227
                helper.makeBeamedGroupExact(bg0, bg1, GROUP_TYPE_TUPLED);
 
228
                if (count > 1) {
 
229
                    for (Segment::iterator i = bg0; i != bg1; ++i) {
 
230
                        (*i)->set<Int>(BEAMED_GROUP_TUPLED_COUNT, count-1);
 
231
                        (*i)->set<Int>(BEAMED_GROUP_UNTUPLED_COUNT, count);
 
232
                    }
 
233
                }
 
234
            } else {
 
235
                helper.makeBeamedGroupExact(bg0, bg1, GROUP_TYPE_BEAMED);
 
236
            }
 
237
        }
 
238
            
137
239
    } else {
138
 
        i = helper.insertNote(e);
139
 
        // e is just a model for SegmentNotationHelper::insertNote
140
 
        delete e;
 
240
 
 
241
        // If we're attempting to insert at the same time and pitch as
 
242
        // an existing note, then we remove the existing note first
 
243
        // (so as to change its duration, if the durations differ)
 
244
        segment.getTimeSlice(m_insertionTime, i, j);
 
245
        while (i != j) {
 
246
            if ((*i)->isa(Note::EventType)) {
 
247
                long pitch;
 
248
                if ((*i)->get<Int>(PITCH, pitch) && pitch == m_pitch) {
 
249
                    helper.deleteNote(*i);
 
250
                    break;
 
251
                }
 
252
            }
 
253
            ++i;
 
254
        }
 
255
        
 
256
        if (m_matrixType) {
 
257
            i = SegmentMatrixHelper(segment).insertNote(e);
 
258
        } else {
 
259
            i = helper.insertNote(e);
 
260
            // e is just a model for SegmentNotationHelper::insertNote
 
261
            delete e;
 
262
        }
141
263
    }
142
264
 
143
 
    if (i != segment.end())
144
 
        m_lastInsertedEvent = *i;
 
265
    if (i != segment.end()) m_lastInsertedEvent = *i;
145
266
 
146
267
    if (m_autoBeam) {
147
268