@@ -4172,6 +4172,20 @@ bool Score::cmdImplode()
41724172 // if single staff selected, combine voices
41734173 // otherwise combine staves
41744174 if (dstStaff == endStaff - 1 ) {
4175+ // find first voice with actual notes to use as destination
4176+ track_idx_t actualDstTrack = dstTrack;
4177+ for (voice_idx_t v = 0 ; v < VOICES; ++v) {
4178+ track_idx_t testTrack = dstStaff * VOICES + v;
4179+ for (Measure* m = startMeasure; m && m->tick () < endTick; m = m->nextMeasure ()) {
4180+ if (m->hasVoice (testTrack) && !m->isOnlyRests (testTrack)) {
4181+ actualDstTrack = testTrack;
4182+ goto found_voice;
4183+ }
4184+ }
4185+ }
4186+ found_voice:
4187+ dstTrack = actualDstTrack;
4188+
41754189 // loop through segments adding notes to chord on top staff
41764190 for (Segment* s = startSegment; s && s != endSegment; s = s->next1 ()) {
41774191 if (!s->isChordRestType ()) {
@@ -4190,7 +4204,10 @@ bool Score::cmdImplode()
41904204 }
41914205 // loop through each subsequent staff (or track within staff)
41924206 // looking for notes to add
4193- for (track_idx_t srcTrack = startTrack + 1 ; srcTrack < endTrack; srcTrack++) {
4207+ for (track_idx_t srcTrack = startTrack; srcTrack < endTrack; srcTrack++) {
4208+ if (srcTrack == dstTrack) {
4209+ continue ;
4210+ }
41944211 EngravingItem* src = s->element (srcTrack);
41954212 if (src && src->isChord ()) {
41964213 Chord* srcChord = toChord (src);
@@ -4231,22 +4248,66 @@ bool Score::cmdImplode()
42314248 undoRemoveElement (src);
42324249 }
42334250 }
4234- }
4235- // TODO - use first voice that actually has a note and implode remaining voices on it?
4236- // see https://musescore.org/en/node/174111
4237- else if (dst) {
4238- // destination track has something, but it isn't a chord
4239- // remove rests from other voices if in "voice mode"
4240- for (voice_idx_t i = 1 ; i < VOICES; ++i) {
4241- EngravingItem* e = s->element (dstTrack + i);
4242- if (e && e->isRest ()) {
4243- undoRemoveElement (e);
4251+ } else {
4252+ // destination track has rest or nothing - find first chord in other voices and move it to dstTrack
4253+ Chord* firstChord = nullptr ;
4254+ track_idx_t firstChordTrack = muse::nidx;
4255+ for (track_idx_t track = startTrack; track < endTrack; track++) {
4256+ EngravingItem* e = s->element (track);
4257+ if (e && e->isChord ()) {
4258+ firstChord = toChord (e);
4259+ firstChordTrack = track;
4260+ break ;
4261+ }
4262+ }
4263+
4264+ if (firstChord) {
4265+ // move first chord to dstTrack and merge others into it
4266+ if (firstChordTrack != dstTrack) {
4267+ firstChord->undoChangeProperty (Pid::TRACK, dstTrack);
4268+ }
4269+
4270+ for (track_idx_t srcTrack = startTrack; srcTrack < endTrack; srcTrack++) {
4271+ if (srcTrack == firstChordTrack) {
4272+ continue ;
4273+ }
4274+ EngravingItem* src = s->element (srcTrack);
4275+ if (src && src->isChord ()) {
4276+ Chord* srcChord = toChord (src);
4277+ if (srcChord->ticks () != firstChord->ticks ()) {
4278+ continue ;
4279+ }
4280+ for (Note* n : srcChord->notes ()) {
4281+ NoteVal nv (n->pitch ());
4282+ nv.tpc1 = n->tpc1 ();
4283+ if (firstChord->findNote (nv.pitch )) {
4284+ continue ;
4285+ }
4286+ bool forceAccidental = n->accidental () && n->accidental ()->role () == AccidentalRole::USER;
4287+ addNote (firstChord, nv, forceAccidental);
4288+ }
4289+ }
4290+ if (src && src->voice ()) {
4291+ undoRemoveElement (src);
4292+ }
4293+ }
4294+
4295+ // remove rest from dstTrack if present
4296+ if (dst && dst->isRest ()) {
4297+ undoRemoveElement (dst);
42444298 }
42454299 }
42464300 }
42474301 }
42484302 // delete orphaned spanners (TODO: figure out solution to reconnect orphaned spanners to their cloned notes)
42494303 checkSpanner (startTick, endTick);
4304+
4305+ // if destination is not voice 1, swap it to voice 1
4306+ if (dstTrack != startTrack) {
4307+ for (Measure* m = startMeasure; m && m->tick () < endTick; m = m->nextMeasure ()) {
4308+ undo (new ExchangeVoice (m, startTrack, dstTrack, dstStaff));
4309+ }
4310+ }
42504311 } else {
42514312 track_idx_t tracks[VOICES];
42524313 for (voice_idx_t i = 0 ; i < VOICES; i++) {
0 commit comments