From 7d6d40896bf3ff76a13ad7980c76ed3cb92af61c Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Thu, 6 Jul 2023 15:56:34 +0200 Subject: [PATCH] Improve tie handling for mxml --- src/importer/MusicXmlImporter.ts | 11 +- src/model/Note.ts | 5 +- test-data/musicxml3/tie-destination.musicxml | 158 +++++++++++++++++++ test/importer/MusicXmlImporter.test.ts | 20 +++ 4 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 test-data/musicxml3/tie-destination.musicxml diff --git a/src/importer/MusicXmlImporter.ts b/src/importer/MusicXmlImporter.ts index 7db938c44..8267f98ab 100644 --- a/src/importer/MusicXmlImporter.ts +++ b/src/importer/MusicXmlImporter.ts @@ -810,8 +810,15 @@ export class MusicXmlImporter extends ScoreImporter { this._tieStarts.push(note); } } else if (element.getAttribute('type') === 'stop' && this._tieStarts.length > 0 && !note.isTieDestination) { - note.isTieDestination = true; - note.tieOrigin = this._tieStarts[0]; + const tieOrigin = this._tieStarts[0]; + // no cross track/staff or voice ties supported for now + if(tieOrigin.beat.voice.index === note.beat.voice.index && + tieOrigin.beat.voice.bar.staff.index === note.beat.voice.bar.staff.index && + tieOrigin.beat.voice.bar.staff.track.index === note.beat.voice.bar.staff.track.index) { + note.isTieDestination = true; + note.tieOrigin = this._tieStarts[0]; + } + this._tieStarts.splice(0, 1); this._tieStartIds.delete(note.id); } diff --git a/src/model/Note.ts b/src/model/Note.ts index 46ad64952..6031f4b78 100644 --- a/src/model/Note.ts +++ b/src/model/Note.ts @@ -999,11 +999,12 @@ export class Note { this._noteIdBag = null; // not needed anymore } else { - if (!this.isTieDestination && this.tieOrigin == null) { + // no tie destination at all? + if (!this.isTieDestination && this.tieOrigin === null) { return; } - let tieOrigin = Note.findTieOrigin(this); + let tieOrigin = this.tieOrigin ?? Note.findTieOrigin(this); if (!tieOrigin) { this.isTieDestination = false; } else { diff --git a/test-data/musicxml3/tie-destination.musicxml b/test-data/musicxml3/tie-destination.musicxml new file mode 100644 index 000000000..38a139e5e --- /dev/null +++ b/test-data/musicxml3/tie-destination.musicxml @@ -0,0 +1,158 @@ + + + + + + Acoustic Guitar + + Acoustic Guitar + + A. Gtr. + + A. Gtr. + + + Acoustic Guitar + pluck.guitar.steel-string + + + General MIDI + Acoustic Guitar (steel) + + + + + + + + 256 + + 0 + major + + + 1 + + TAB + 2 + + + 6 + + E + 2 + + + A + 2 + + + D + 3 + + + G + 3 + + + B + 3 + + + E + 4 + + + + + + F + 1 + + minor + 1 + + + + C + 1 + 5 + + 384 + + 1 + quarter + + up + 1 + + + 9 + 1 + + + + + + A + 4 + + 128 + + + 1 + eighth + up + 1 + + + + 5 + 1 + + + + + + A + 4 + + 256 + + + 1 + quarter + up + 1 + + + + 5 + 1 + + + + + + G + 4 + + 256 + + 1 + quarter + up + 1 + + + 3 + 1 + + + + + + diff --git a/test/importer/MusicXmlImporter.test.ts b/test/importer/MusicXmlImporter.test.ts index 47ca28484..1673f2bd9 100644 --- a/test/importer/MusicXmlImporter.test.ts +++ b/test/importer/MusicXmlImporter.test.ts @@ -1,5 +1,6 @@ import { MusicXmlImporterTestHelper } from '@test/importer/MusicXmlImporterTestHelper'; import { Score } from '@src/model/Score'; +import { JsonConverter } from '@src/model'; describe('MusicXmlImporterTests', () => { it('track-volume', async () => { @@ -47,4 +48,23 @@ describe('MusicXmlImporterTests', () => { expect(score.masterBars[1].tempoAutomation).toBeTruthy(); expect(score.masterBars[1].tempoAutomation?.value).toBe(60); }); + it('tie-destination', async () => { + let score: Score = await MusicXmlImporterTestHelper.testReferenceFile( + 'test-data/musicxml3/tie-destination.musicxml' + ); + + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[1].notes[0].isTieOrigin).toBeTrue(); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[1].notes[0].tieDestination).toBeTruthy(); + + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[2].notes[0].isTieDestination).toBeTrue(); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[2].notes[0].tieOrigin).toBeTruthy(); + + score = JsonConverter.jsObjectToScore(JsonConverter.scoreToJsObject(score)); + + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[1].notes[0].isTieOrigin).toBeTrue(); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[1].notes[0].tieDestination).toBeTruthy(); + + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[2].notes[0].isTieDestination).toBeTrue(); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[2].notes[0].tieOrigin).toBeTruthy(); + }); });