Skip to content

Commit

Permalink
Merge pull request #97 from strangarnenad/nested_tuplets
Browse files Browse the repository at this point in the history
Fix on json and xml import (tuplets)
  • Loading branch information
AaronDavidNewman authored Sep 19, 2024
2 parents 6ca9e64 + f6ef6cc commit 2145848
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 12 deletions.
29 changes: 29 additions & 0 deletions src/smo/data/measure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,35 @@ export class SmoMeasure implements SmoMeasureParams, TickMappable {
if ((jsonObj as any).tuplets !== undefined) {
for (j = 0; j < (jsonObj as any).tuplets.length; ++j) {
const tupJson = (jsonObj as any).tuplets[j];

// Legacy schema had attrs.id, now it is just id
if ((tupJson as any).attrs && (tupJson as any).attrs.id) {
tupJson.id = (tupJson as any).attrs.id;
}

const tupletNotes: SmoNote[] = [];
let startIndex: number | null = null;
params.voices.forEach((voice) => {
voice.notes.forEach((note, index) => {
if (note.isTuplet && note.tupletId === tupJson.attrs.id) {
tupletNotes.push(note);
//we cannot trust startIndex coming from legacy json
//we need to count index of the first note in the tuplet
if (startIndex === null) {
startIndex = index;
}
}
});
});

// Bug fix: A tuplet with no notes may be been overwritten
// in a copy/paste operation
if (tupletNotes.length > 0) {
tupJson.notes = tupletNotes;
tupJson.startIndex = startIndex;
tupJson.endIndex = tupJson.startIndex + tupletNotes.length - 1;
}

const tuplet: SmoTuplet = SmoTuplet.deserialize(tupJson);
const tupletTree: SmoTupletTree = new SmoTupletTree({tuplet: tuplet});
params.tupletTrees.push(tupletTree);
Expand Down
9 changes: 3 additions & 6 deletions src/smo/data/tuplet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,16 +301,13 @@ export class SmoTuplet {

static deserialize(jsonObj: SmoTupletParamsSer): SmoTuplet {
const tupJson = SmoTuplet.defaults;
// We need to calculate the endIndex based on length of notes array
// Legacy schema had notes array, but we now demarcate tuplet with startIndex and endIndex
smoSerialize.serializedMerge(SmoTuplet.parameterArray, jsonObj, tupJson);
// Legacy schema did not have notesOccupied, we need to calculate it.
if ((jsonObj as any).notes !== undefined) {
const numberOfNotes = (jsonObj as any).notes.length;
tupJson.endIndex = jsonObj.startIndex + numberOfNotes - 1;
tupJson.notesOccupied = jsonObj.totalTicks / jsonObj.stemTicks;
//todo: notesOccupied can probably be removed
tupJson.notesOccupied = tupJson.totalTicks / tupJson.stemTicks;
}

smoSerialize.serializedMerge(SmoTuplet.parameterArray, jsonObj, tupJson);
const tuplet = new SmoTuplet(tupJson);
tuplet.parentTuplet = jsonObj.parentTuplet ? jsonObj.parentTuplet : null;
if (jsonObj.childrenTuplets !== undefined) {
Expand Down
8 changes: 7 additions & 1 deletion src/smo/mxml/xmlHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,13 @@ export class XmlHelpers {
const actualNotesNode = timeModificationNode.querySelector('actual-notes');
const normalNotesNode = timeModificationNode.querySelector('normal-notes');
const normalTypeNode = timeModificationNode.querySelector('normal-type');
const normalType = normalTypeNode?.textContent ? XmlHelpers.noteTypesToSmoMap[normalTypeNode?.textContent] ?? null : null;
const noteTypeNode = noteNode.querySelector('type');
let normalType: number | null = null;
if (normalTypeNode) {
normalType = normalTypeNode.textContent ? XmlHelpers.noteTypesToSmoMap[normalTypeNode.textContent] ?? null : null;
} else if (noteTypeNode) {
normalType = noteTypeNode.textContent ? XmlHelpers.noteTypesToSmoMap[noteTypeNode.textContent] ?? null : null;
}
if (actualNotesNode?.textContent && normalNotesNode?.textContent && normalType) {
const actualNotes = parseInt(actualNotesNode.textContent, 10);
const normalNotes = parseInt(normalNotesNode.textContent, 10);
Expand Down
14 changes: 9 additions & 5 deletions src/smo/mxml/xmlState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -611,19 +611,23 @@ export class XmlState {
});
}
addTupletsToMeasure(smoMeasure: SmoMeasure, staffId: number, voiceId: number) {
const tupletStates = this.findCompletedTupletStatesByStaffAndVoice(staffId, voiceId);
const tupletStates = this.findAndRemoveCompletedTupletStatesByStaffAndVoice(staffId, voiceId);
const xmlTupletStateTrees = this.buildXmlTupletStateTrees(tupletStates);
const notes: SmoNote[] = smoMeasure.voices[voiceId].notes;
smoMeasure.tupletTrees = this.buildSmoTupletTreesFromXmlTupletStateTrees(xmlTupletStateTrees, notes);
}
private findCompletedTupletStatesByStaffAndVoice(staffId: number, voiceId: number): XmlTupletState[] {
const tupletStates: XmlTupletState[] = [];
private findAndRemoveCompletedTupletStatesByStaffAndVoice(staffId: number, voiceId: number): XmlTupletState[] {
const remainingXmlTupletStates: XmlCompletedTupletState[] = [];
const tupletStatesForReturn: XmlTupletState[] = [];
this.completedTupletStates.forEach((completedTupletState) => {
if (completedTupletState.staffId === staffId && completedTupletState.voiceId === voiceId) {
tupletStates.push(completedTupletState.tupletState);
tupletStatesForReturn.push(completedTupletState.tupletState);
} else {
remainingXmlTupletStates.push(completedTupletState)
}
});
return tupletStates;
this.completedTupletStates = remainingXmlTupletStates;
return tupletStatesForReturn;
}
private buildXmlTupletStateTrees(tupletStates: XmlTupletState[]): XmlTupletStateTreeNode[] {
let sortedTupletStates = this.sortTupletStates(tupletStates);
Expand Down

0 comments on commit 2145848

Please sign in to comment.