From f1a5e2a8ec80a5b8a6c9bb4a83537b41a8cb6e2c Mon Sep 17 00:00:00 2001 From: Andrea Coluzzi Date: Tue, 21 Nov 2023 19:09:38 +0100 Subject: [PATCH 1/4] feat: Adds support for chords in MusicXML importer --- src/importer/MusicXmlImporter.ts | 326 ++++++++------ src/model/Note.ts | 1 + test-data/musicxml3/chord-diagram.musicxml | 466 +++++++++++++++++++++ test/importer/MusicXmlImporter.test.ts | 24 ++ 4 files changed, 697 insertions(+), 120 deletions(-) create mode 100644 test-data/musicxml3/chord-diagram.musicxml diff --git a/src/importer/MusicXmlImporter.ts b/src/importer/MusicXmlImporter.ts index 8267f98ab..573561c46 100644 --- a/src/importer/MusicXmlImporter.ts +++ b/src/importer/MusicXmlImporter.ts @@ -241,6 +241,7 @@ export class MusicXmlImporter extends ScoreImporter { } } + let chordsByIdForTrack = new Map(); if (masterBar) { let attributesParsed: boolean = false; for (let c of element.childNodes) { @@ -262,7 +263,7 @@ export class MusicXmlImporter extends ScoreImporter { } break; case 'harmony': - this.parseHarmony(c, track); + this.parseHarmony(c, track, chordsByIdForTrack); break; case 'sound': // TODO @@ -414,131 +415,25 @@ export class MusicXmlImporter extends ScoreImporter { private _currentChord: string | null = null; private _divisionsPerQuarterNote: number = 0; - private parseHarmony(element: XmlNode, track: Track): void { - let rootStep: string | null = null; - let rootAlter: string = ''; - // let kind: string | null = null; - // let kindText: string | null = null; - for (let c of element.childNodes) { - if (c.nodeType === XmlNodeType.Element) { - switch (c.localName) { + private parseHarmony(element: XmlNode, track: Track, chordsByIdForTrack: Map): void { + let chord: Chord = new Chord(); + const harmonyId = element.getAttribute('id'); + for (let childNode of element.childNodes) { + if (childNode.nodeType === XmlNodeType.Element) { + switch (childNode.localName) { case 'root': - for (let rootChild of c.childNodes) { - if (rootChild.nodeType === XmlNodeType.Element) { - switch (rootChild.localName) { - case 'root-step': - rootStep = rootChild.innerText; - break; - case 'root-alter': - switch (parseInt(c.innerText)) { - case -2: - rootAlter = ' bb'; - break; - case -1: - rootAlter = ' b'; - break; - case 0: - rootAlter = ''; - break; - case 1: - rootAlter = ' #'; - break; - case 2: - rootAlter = ' ##'; - break; - } - break; - } - } - } + chord.name = this.parseHarmonyRoot(childNode); break; case 'kind': - // kindText = c.getAttribute('text'); - // kind = c.innerText; + chord.name = chord.name + this.parseHarmonyKind(childNode); + break; + case 'frame': + this.parseHarmonyFrame(childNode, chord); break; } } - } - let chord: Chord = new Chord(); - chord.name = rootStep + rootAlter; - // TODO: find proper names for the rest - // switch (kind) - // { - // // triads - // case "major": - // break; - // case "minor": - // chord.Name += "m"; - // break; - // // Sevenths - // case "augmented": - // break; - // case "diminished": - // break; - // case "dominant": - // break; - // case "major-seventh": - // chord.Name += "7M"; - // break; - // case "minor-seventh": - // chord.Name += "m7"; - // break; - // case "diminished-seventh": - // break; - // case "augmented-seventh": - // break; - // case "half-diminished": - // break; - // case "major-minor": - // break; - // // Sixths - // case "major-sixth": - // break; - // case "minor-sixth": - // break; - // // Ninths - // case "dominant-ninth": - // break; - // case "major-ninth": - // break; - // case "minor-ninth": - // break; - // // 11ths - // case "dominant-11th": - // break; - // case "major-11th": - // break; - // case "minor-11th": - // break; - // // 13ths - // case "dominant-13th": - // break; - // case "major-13th": - // break; - // case "minor-13th": - // break; - // // Suspended - // case "suspended-second": - // break; - // case "suspended-fourth": - // break; - // // Functional sixths - // case "Neapolitan": - // break; - // case "Italian": - // break; - // case "French": - // break; - // case "German": - // break; - // // Other - // case "pedal": - // break; - // case "power": - // break; - // case "Tristan": - // break; - // } + } + // var degree = element.GetElementsByTagName("degree"); // if (degree.Length > 0) // { @@ -555,9 +450,200 @@ export class MusicXmlImporter extends ScoreImporter { // } // } this._currentChord = ModelUtils.newGuid(); + const chordKey = harmonyId || chord.name; + if (chordsByIdForTrack.has(chordKey)) { + // check if the chord is already present + chord.showDiagram = false; + } for (let staff of track.staves) { staff.addChord(this._currentChord, chord); } + chordsByIdForTrack.set(chordKey, chord); + } + + private parseHarmonyRoot(xmlNode: XmlNode): string { + let rootStep: string | null = null; + let rootAlter: string = ''; + for (let rootChild of xmlNode.childNodes) { + if (rootChild.nodeType === XmlNodeType.Element) { + switch (rootChild.localName) { + case 'root-step': + rootStep = rootChild.innerText; + break; + case 'root-alter': + switch (parseInt(xmlNode.innerText)) { + case -2: + rootAlter = 'bb'; + break; + case -1: + rootAlter = 'b'; + break; + case 0: + rootAlter = ''; + break; + case 1: + rootAlter = '#'; + break; + case 2: + rootAlter = '##'; + break; + } + break; + } + } + } + return rootStep + rootAlter; + } + + private parseHarmonyKind(xmlNode: XmlNode): string { + const kindText = xmlNode.getAttribute('text'); + const kindContent = xmlNode.innerText; + let resultKind = ''; + if (kindText) { + // the abbreviation is already provided + resultKind = kindText; + } else { + switch (kindContent) { + // triads + case "major": + break; + case "minor": + resultKind = "m"; + break; + // Sevenths + case "augmented": + resultKind = "+"; + break; + case "diminished": + resultKind = "\u25CB"; + break; + case "dominant": + resultKind = "7"; + break; + case "major-seventh": + resultKind = "7M"; + break; + case "minor-seventh": + resultKind = "m7"; + break; + case "diminished-seventh": + resultKind = "\u25CB7"; + break; + case "augmented-seventh": + resultKind = "+7"; + break; + case "half-diminished": + resultKind = "\u2349"; + break; + case "major-minor": + resultKind = "mMaj"; + break; + // Sixths + case "major-sixth": + resultKind = "maj6"; + break; + case "minor-sixth": + resultKind = "m6"; + break; + // Ninths + case "dominant-ninth": + resultKind = "9"; + break; + case "major-ninth": + resultKind = "maj9"; + break; + case "minor-ninth": + resultKind = "m9"; + break; + // 11ths + case "dominant-11th": + resultKind = "11"; + break; + case "major-11th": + resultKind = "maj11"; + break; + case "minor-11th": + resultKind = "m11"; + break; + // 13ths + case "dominant-13th": + resultKind = "13"; + break; + case "major-13th": + resultKind = "maj13"; + break; + case "minor-13th": + resultKind = "m13"; + break; + // Suspended + case "suspended-second": + resultKind = "sus2"; + break; + case "suspended-fourth": + resultKind = "sus4"; + break; + // TODO: find proper names for the rest + // Functional sixths + // case "Neapolitan": + // break; + // case "Italian": + // break; + // case "French": + // break; + // case "German": + // break; + // // Other + // case "pedal": + // break; + // case "power": + // break; + // case "Tristan": + // break; + } + } + + return resultKind; + } + + private parseHarmonyFrame(xmlNode: XmlNode, chord: Chord) { + for (let frameChild of xmlNode.childNodes) { + if (frameChild.nodeType === XmlNodeType.Element) { + switch (frameChild.localName) { + case 'frame-strings': + const stringsCount: number = parseInt(frameChild.innerText); + chord.strings = new Array(stringsCount); + for (let i = 0; i < stringsCount; i++) { // set strings unplayed as default + chord.strings[i] = -1; + } + break; + case 'first-fret': + chord.firstFret = parseInt(frameChild.innerText); + break; + case 'frame-note': + let stringNo: number | null = null; + let fretNo: number | null = null; + for (let noteChild of frameChild.childNodes) { + switch (noteChild.localName) { + case 'string': + stringNo = parseInt(noteChild.innerText); + break; + case 'fret': + fretNo = parseInt(noteChild.innerText); + if (stringNo && fretNo >= 0) { + chord.strings[stringNo - 1] = fretNo; + } + break; + case 'barre': + if (stringNo && fretNo && noteChild.getAttribute('type') === "start") { + chord.barreFrets.push(fretNo); + } + break; + } + } + break; + } + } + } } private parseBarline(element: XmlNode, masterBar: MasterBar): void { diff --git a/src/model/Note.ts b/src/model/Note.ts index 6031f4b78..1ae049027 100644 --- a/src/model/Note.ts +++ b/src/model/Note.ts @@ -103,6 +103,7 @@ export class Note { /** * Gets or sets the fret on which this note is played on the instrument. + * 0 is the nut. */ public fret: number = -1; diff --git a/test-data/musicxml3/chord-diagram.musicxml b/test-data/musicxml3/chord-diagram.musicxml new file mode 100644 index 000000000..510ae1c5a --- /dev/null +++ b/test-data/musicxml3/chord-diagram.musicxml @@ -0,0 +1,466 @@ + + + + + 雅俗共赏 + + + 许嵩 + 许嵩 + + 2021-09-28 + Guitar Pro 7.5.2 + + + + + 6.4 + 40 + + + 1850 + 1310 + + + + 雅俗共赏 + + + 许嵩 + + + 许嵩 + + + 许嵩 + + + + 伴奏 + s.guit. + + 1 + 1 + 26 + 80 + 0 + + + + + + + 2 + + 0 + major + + + + TAB + 5 + + + 6 + + E + 2 + + + A + 2 + + + D + 3 + + + G + 3 + + + B + 3 + + + E + 4 + + + + + + C + 0 + + major + + 6 + 5 + 1 + + 5 + 3 + + + 4 + 2 + + + 3 + 0 + + + 2 + 1 + + + 1 + 0 + + + + + + + quarter + 65 + + + + + + + C + 3 + + 1 + 1 + eighth + up + begin + + + + + + 5 + 3 + + + + + + E + 3 + + 1 + 1 + eighth + up + end + + + + + + 4 + 2 + + + + + + G + 3 + + 1 + 1 + eighth + up + begin + + + + + + 3 + 0 + + + + + + C + 4 + + 1 + 1 + eighth + up + end + + + + + + 2 + 1 + + + + + + F + 0 + + minor + + 6 + 5 + 1 + + 6 + 1 + + + 5 + 3 + + + 4 + 3 + + + 3 + 1 + + + 2 + 1 + + + 1 + 1 + + + + + + F + 2 + + 1 + 1 + eighth + up + begin + + + + + + 6 + 1 + + + + + + G + 1 + 3 + + 1 + 1 + eighth + sharp + up + end + + + + + + 3 + 1 + + + + + + C + 4 + + 2 + 1 + quarter + up + + + + + + 2 + 1 + + + + + + + 4 + + + + G + 0 + + major + + 6 + 5 + 2 + + 6 + 3 + + + 5 + 2 + + + 4 + 0 + + + 3 + 0 + + + 2 + 0 + + + 1 + 3 + + + + + + G + 2 + + 2 + 1 + eighth + up + begin + + + 6 + 3 + + + + + + D + 3 + + 2 + 1 + eighth + up + end + + + 4 + 0 + + + + + + B + 3 + + 1 + 1 + 16th + up + begin + begin + + + H + 2 + 0 + + + + + + + C + 4 + + 1 + 1 + 16th + up + continue + end + + + + 2 + 1 + + + + + + + G + 4 + + 2 + + 1 + eighth + up + end + + + 1 + 3 + + + + + + + G + 4 + + 8 + + 1 + half + up + + + 1 + 3 + + + + + + + diff --git a/test/importer/MusicXmlImporter.test.ts b/test/importer/MusicXmlImporter.test.ts index 1673f2bd9..f4dc9b248 100644 --- a/test/importer/MusicXmlImporter.test.ts +++ b/test/importer/MusicXmlImporter.test.ts @@ -67,4 +67,28 @@ describe('MusicXmlImporterTests', () => { 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(); }); + it('chord-diagram', async () => { + let score: Score = await MusicXmlImporterTestHelper.testReferenceFile( + 'test-data/musicxml3/chord-diagram.musicxml' + ); + + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.name).toBe("C"); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[0]).toBe(0); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[1]).toBe(1); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[2]).toBe(0); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[3]).toBe(2); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[4]).toBe(3); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[5]).toBe(-1); + + + score = JsonConverter.jsObjectToScore(JsonConverter.scoreToJsObject(score)); + + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.name).toBe("C"); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[0]).toBe(0); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[1]).toBe(1); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[2]).toBe(0); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[3]).toBe(2); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[4]).toBe(3); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[5]).toBe(-1); + }); }); From 34210de8bc28d50f908b082b6726359141616791 Mon Sep 17 00:00:00 2001 From: Andrea Coluzzi Date: Sat, 9 Dec 2023 15:26:06 +0100 Subject: [PATCH 2/4] fix: Addressed comments --- src/importer/MusicXmlImporter.ts | 133 ++++++++++++++++--------------- 1 file changed, 68 insertions(+), 65 deletions(-) diff --git a/src/importer/MusicXmlImporter.ts b/src/importer/MusicXmlImporter.ts index 573561c46..00b78526a 100644 --- a/src/importer/MusicXmlImporter.ts +++ b/src/importer/MusicXmlImporter.ts @@ -417,7 +417,6 @@ export class MusicXmlImporter extends ScoreImporter { private parseHarmony(element: XmlNode, track: Track, chordsByIdForTrack: Map): void { let chord: Chord = new Chord(); - const harmonyId = element.getAttribute('id'); for (let childNode of element.childNodes) { if (childNode.nodeType === XmlNodeType.Element) { switch (childNode.localName) { @@ -432,8 +431,8 @@ export class MusicXmlImporter extends ScoreImporter { break; } } - } - + } + // var degree = element.GetElementsByTagName("degree"); // if (degree.Length > 0) // { @@ -450,7 +449,7 @@ export class MusicXmlImporter extends ScoreImporter { // } // } this._currentChord = ModelUtils.newGuid(); - const chordKey = harmonyId || chord.name; + const chordKey: string = chord.uniqueId; if (chordsByIdForTrack.has(chordKey)) { // check if the chord is already present chord.showDiagram = false; @@ -462,7 +461,7 @@ export class MusicXmlImporter extends ScoreImporter { } private parseHarmonyRoot(xmlNode: XmlNode): string { - let rootStep: string | null = null; + let rootStep: string = ''; let rootAlter: string = ''; for (let rootChild of xmlNode.childNodes) { if (rootChild.nodeType === XmlNodeType.Element) { @@ -496,91 +495,92 @@ export class MusicXmlImporter extends ScoreImporter { } private parseHarmonyKind(xmlNode: XmlNode): string { - const kindText = xmlNode.getAttribute('text'); - const kindContent = xmlNode.innerText; - let resultKind = ''; + const kindText: string = xmlNode.getAttribute('text'); + let resultKind: string = ''; if (kindText) { // the abbreviation is already provided resultKind = kindText; } else { + const kindContent: string = xmlNode.innerText; switch (kindContent) { // triads - case "major": + case 'major': + resultKind = ''; break; - case "minor": - resultKind = "m"; + case 'minor': + resultKind = 'm'; break; // Sevenths - case "augmented": - resultKind = "+"; + case 'augmented': + resultKind = '+'; break; - case "diminished": - resultKind = "\u25CB"; + case 'diminished': + resultKind = '\u25CB'; break; - case "dominant": - resultKind = "7"; + case 'dominant': + resultKind = '7'; break; - case "major-seventh": - resultKind = "7M"; + case 'major-seventh': + resultKind = '7M'; break; - case "minor-seventh": - resultKind = "m7"; + case 'minor-seventh': + resultKind = 'm7'; break; - case "diminished-seventh": - resultKind = "\u25CB7"; + case 'diminished-seventh': + resultKind = '\u25CB7'; break; - case "augmented-seventh": - resultKind = "+7"; + case 'augmented-seventh': + resultKind = '+7'; break; - case "half-diminished": - resultKind = "\u2349"; + case 'half-diminished': + resultKind = '\u2349'; break; - case "major-minor": - resultKind = "mMaj"; + case 'major-minor': + resultKind = 'mMaj'; break; // Sixths - case "major-sixth": - resultKind = "maj6"; + case 'major-sixth': + resultKind = 'maj6'; break; - case "minor-sixth": - resultKind = "m6"; + case 'minor-sixth': + resultKind = 'm6'; break; // Ninths - case "dominant-ninth": - resultKind = "9"; + case 'dominant-ninth': + resultKind = '9'; break; - case "major-ninth": - resultKind = "maj9"; + case 'major-ninth': + resultKind = 'maj9'; break; - case "minor-ninth": - resultKind = "m9"; + case 'minor-ninth': + resultKind = 'm9'; break; // 11ths - case "dominant-11th": - resultKind = "11"; + case 'dominant-11th': + resultKind = '11'; break; - case "major-11th": - resultKind = "maj11"; + case 'major-11th': + resultKind = 'maj11'; break; - case "minor-11th": - resultKind = "m11"; + case 'minor-11th': + resultKind = 'm11'; break; // 13ths - case "dominant-13th": - resultKind = "13"; + case 'dominant-13th': + resultKind = '13'; break; - case "major-13th": - resultKind = "maj13"; + case 'major-13th': + resultKind = 'maj13'; break; - case "minor-13th": - resultKind = "m13"; + case 'minor-13th': + resultKind = 'm13'; break; // Suspended - case "suspended-second": - resultKind = "sus2"; + case 'suspended-second': + resultKind = 'sus2'; break; - case "suspended-fourth": - resultKind = "sus4"; + case 'suspended-fourth': + resultKind = 'sus4'; break; // TODO: find proper names for the rest // Functional sixths @@ -612,7 +612,8 @@ export class MusicXmlImporter extends ScoreImporter { case 'frame-strings': const stringsCount: number = parseInt(frameChild.innerText); chord.strings = new Array(stringsCount); - for (let i = 0; i < stringsCount; i++) { // set strings unplayed as default + for (let i = 0; i < stringsCount; i++) { + // set strings unplayed as default chord.strings[i] = -1; } break; @@ -634,7 +635,7 @@ export class MusicXmlImporter extends ScoreImporter { } break; case 'barre': - if (stringNo && fretNo && noteChild.getAttribute('type') === "start") { + if (stringNo && fretNo && noteChild.getAttribute('type') === 'start') { chord.barreFrets.push(fretNo); } break; @@ -898,9 +899,11 @@ export class MusicXmlImporter extends ScoreImporter { } else if (element.getAttribute('type') === 'stop' && this._tieStarts.length > 0 && !note.isTieDestination) { 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) { + 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]; } @@ -941,9 +944,9 @@ export class MusicXmlImporter extends ScoreImporter { slurNumber = '1'; } - // slur numbers are unique in the way that they have the same ID across - // staffs/tracks etc. as long they represent the logically same slur. - // but in our case it must be globally unique to link the correct notes. + // slur numbers are unique in the way that they have the same ID across + // staffs/tracks etc. as long they represent the logically same slur. + // but in our case it must be globally unique to link the correct notes. // adding the staff ID should be enough to achieve this slurNumber = beat.voice.bar.staff.index + '_' + slurNumber; @@ -1158,7 +1161,7 @@ export class MusicXmlImporter extends ScoreImporter { tempoAutomation.type = AutomationType.Tempo; tempoAutomation.value = parseInt(tempo); masterBar.tempoAutomation = tempoAutomation; - if(masterBar.index === 0) { + if (masterBar.index === 0) { masterBar.score.tempo = tempoAutomation.value; } } @@ -1198,7 +1201,7 @@ export class MusicXmlImporter extends ScoreImporter { tempoAutomation.type = AutomationType.Tempo; tempoAutomation.value = perMinute * ((unit / 4) | 0); masterBar.tempoAutomation = tempoAutomation; - if(masterBar.index === 0) { + if (masterBar.index === 0) { masterBar.score.tempo = tempoAutomation.value; } } From e123c7a7e53b882f5983fe79b13f4d0f802f886b Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sat, 9 Dec 2023 17:07:11 +0100 Subject: [PATCH 3/4] Update tests --- test/importer/MusicXmlImporter.test.ts | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/importer/MusicXmlImporter.test.ts b/test/importer/MusicXmlImporter.test.ts index 4c73d84dd..645eb373e 100644 --- a/test/importer/MusicXmlImporter.test.ts +++ b/test/importer/MusicXmlImporter.test.ts @@ -73,23 +73,23 @@ describe('MusicXmlImporterTests', () => { 'test-data/musicxml3/chord-diagram.musicxml' ); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.name).toBe("C"); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[0]).toBe(0); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[1]).toBe(1); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[2]).toBe(0); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[3]).toBe(2); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[4]).toBe(3); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[5]).toBe(-1); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.name).to.equal("C"); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[0]).to.equal(0); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[1]).to.equal(1); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[2]).to.equal(0); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[3]).to.equal(2); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[4]).to.equal(3); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[5]).to.equal(-1); score = JsonConverter.jsObjectToScore(JsonConverter.scoreToJsObject(score)); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.name).toBe("C"); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[0]).toBe(0); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[1]).toBe(1); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[2]).toBe(0); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[3]).toBe(2); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[4]).toBe(3); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[5]).toBe(-1); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.name).to.equal("C"); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[0]).to.equal(0); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[1]).to.equal(1); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[2]).to.equal(0); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[3]).to.equal(2); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[4]).to.equal(3); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[5]).to.equal(-1); }); }); From 53557ea391d4f6bb7a385f449d0dc0296ba34cf1 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sat, 9 Dec 2023 17:17:40 +0100 Subject: [PATCH 4/4] Add assert for nullability (kotlin is a bit sensitive) --- test/importer/MusicXmlImporter.test.ts | 30 ++++++++++++++------------ 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/test/importer/MusicXmlImporter.test.ts b/test/importer/MusicXmlImporter.test.ts index 645eb373e..aaf57c480 100644 --- a/test/importer/MusicXmlImporter.test.ts +++ b/test/importer/MusicXmlImporter.test.ts @@ -73,23 +73,25 @@ describe('MusicXmlImporterTests', () => { 'test-data/musicxml3/chord-diagram.musicxml' ); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.name).to.equal("C"); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[0]).to.equal(0); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[1]).to.equal(1); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[2]).to.equal(0); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[3]).to.equal(2); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[4]).to.equal(3); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[5]).to.equal(-1); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord).to.be.ok; + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.name).to.equal("C"); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.strings[0]).to.equal(0); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.strings[1]).to.equal(1); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.strings[2]).to.equal(0); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.strings[3]).to.equal(2); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.strings[4]).to.equal(3); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.strings[5]).to.equal(-1); score = JsonConverter.jsObjectToScore(JsonConverter.scoreToJsObject(score)); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.name).to.equal("C"); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[0]).to.equal(0); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[1]).to.equal(1); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[2]).to.equal(0); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[3]).to.equal(2); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[4]).to.equal(3); - expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord?.strings[5]).to.equal(-1); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord).to.be.ok; + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.name).to.equal("C"); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.strings[0]).to.equal(0); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.strings[1]).to.equal(1); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.strings[2]).to.equal(0); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.strings[3]).to.equal(2); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.strings[4]).to.equal(3); + expect(score.tracks[0].staves[0].bars[0].voices[0].beats[0].chord!.strings[5]).to.equal(-1); }); });