Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 72 additions & 11 deletions src/engraving/editing/cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4172,6 +4172,20 @@ bool Score::cmdImplode()
// if single staff selected, combine voices
// otherwise combine staves
if (dstStaff == endStaff - 1) {
// find first voice with actual notes to use as destination
track_idx_t actualDstTrack = dstTrack;
for (voice_idx_t v = 0; v < VOICES; ++v) {
track_idx_t testTrack = dstStaff * VOICES + v;
for (Measure* m = startMeasure; m && m->tick() < endTick; m = m->nextMeasure()) {
if (m->hasVoice(testTrack) && !m->isOnlyRests(testTrack)) {
actualDstTrack = testTrack;
goto found_voice;
}
}
}
found_voice:
dstTrack = actualDstTrack;

// loop through segments adding notes to chord on top staff
for (Segment* s = startSegment; s && s != endSegment; s = s->next1()) {
if (!s->isChordRestType()) {
Expand All @@ -4190,7 +4204,10 @@ bool Score::cmdImplode()
}
// loop through each subsequent staff (or track within staff)
// looking for notes to add
for (track_idx_t srcTrack = startTrack + 1; srcTrack < endTrack; srcTrack++) {
for (track_idx_t srcTrack = startTrack; srcTrack < endTrack; srcTrack++) {
if (srcTrack == dstTrack) {
continue;
}
EngravingItem* src = s->element(srcTrack);
if (src && src->isChord()) {
Chord* srcChord = toChord(src);
Expand Down Expand Up @@ -4231,22 +4248,66 @@ bool Score::cmdImplode()
undoRemoveElement(src);
}
}
}
// TODO - use first voice that actually has a note and implode remaining voices on it?
// see https://musescore.org/en/node/174111
else if (dst) {
// destination track has something, but it isn't a chord
// remove rests from other voices if in "voice mode"
for (voice_idx_t i = 1; i < VOICES; ++i) {
EngravingItem* e = s->element(dstTrack + i);
if (e && e->isRest()) {
undoRemoveElement(e);
} else {
// destination track has rest or nothing - find first chord in other voices and move it to dstTrack
Chord* firstChord = nullptr;
track_idx_t firstChordTrack = muse::nidx;
for (track_idx_t track = startTrack; track < endTrack; track++) {
EngravingItem* e = s->element(track);
if (e && e->isChord()) {
firstChord = toChord(e);
firstChordTrack = track;
break;
}
}

if (firstChord) {
// move first chord to dstTrack and merge others into it
if (firstChordTrack != dstTrack) {
firstChord->undoChangeProperty(Pid::TRACK, dstTrack);
}

for (track_idx_t srcTrack = startTrack; srcTrack < endTrack; srcTrack++) {
if (srcTrack == firstChordTrack) {
continue;
}
EngravingItem* src = s->element(srcTrack);
if (src && src->isChord()) {
Chord* srcChord = toChord(src);
if (srcChord->ticks() != firstChord->ticks()) {
continue;
}
for (Note* n : srcChord->notes()) {
NoteVal nv(n->pitch());
nv.tpc1 = n->tpc1();
if (firstChord->findNote(nv.pitch)) {
continue;
}
bool forceAccidental = n->accidental() && n->accidental()->role() == AccidentalRole::USER;
addNote(firstChord, nv, forceAccidental);
}
}
if (src && src->voice()) {
undoRemoveElement(src);
}
}

// remove rest from dstTrack if present
if (dst && dst->isRest()) {
undoRemoveElement(dst);
}
}
}
}
// delete orphaned spanners (TODO: figure out solution to reconnect orphaned spanners to their cloned notes)
checkSpanner(startTick, endTick);

// if destination is not voice 1, swap it to voice 1
if (dstTrack != startTrack) {
for (Measure* m = startMeasure; m && m->tick() < endTick; m = m->nextMeasure()) {
undo(new ExchangeVoice(m, startTrack, dstTrack, dstStaff));
}
}
} else {
track_idx_t tracks[VOICES];
for (voice_idx_t i = 0; i < VOICES; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,15 @@
</Chord>
<Chord>
<eid>o_o</eid>
<track>0</track>
<durationType>quarter</durationType>
<Note>
<eid>p_p</eid>
<track>0</track>
<Accidental>
<subtype>accidentalFlat</subtype>
<eid>q_q</eid>
<track>0</track>
</Accidental>
<pitch>68</pitch>
<tpc>10</tpc>
Expand Down Expand Up @@ -320,39 +323,75 @@
<durationType>half</durationType>
</Rest>
</voice>
<voice>
<location>
<fractions>1/2</fractions>
</location>
<Rest>
<eid>w_w</eid>
<durationType>half</durationType>
</Rest>
</voice>
<voice>
<location>
<fractions>1/2</fractions>
</location>
<Rest>
<eid>x_x</eid>
<durationType>half</durationType>
</Rest>
</voice>
</Measure>
<Measure>
<eid>w_w</eid>
<eid>y_y</eid>
<voice>
<Chord>
<eid>x_x</eid>
<eid>z_z</eid>
<durationType>half</durationType>
<Note>
<eid>y_y</eid>
<eid>0_0</eid>
<pitch>64</pitch>
<tpc>18</tpc>
</Note>
<Note>
<eid>z_z</eid>
<eid>1_1</eid>
<pitch>67</pitch>
<tpc>15</tpc>
</Note>
<Note>
<eid>0_0</eid>
<eid>2_2</eid>
<pitch>72</pitch>
<tpc>14</tpc>
</Note>
</Chord>
<Rest>
<eid>1_1</eid>
<eid>3_3</eid>
<durationType>half</durationType>
</Rest>
<BarLine>
<subtype>end</subtype>
<span>1</span>
<eid>2_2</eid>
<eid>4_4</eid>
</BarLine>
</voice>
<voice>
<location>
<fractions>1/2</fractions>
</location>
<Rest>
<eid>5_5</eid>
<durationType>half</durationType>
</Rest>
</voice>
<voice>
<location>
<fractions>1/2</fractions>
</location>
<Rest>
<eid>6_6</eid>
<durationType>half</durationType>
</Rest>
</voice>
</Measure>
</Staff>
</Score>
Expand Down
Loading
Loading