import { Measure, MeasureData, NormalizedMeasureData } from './Measure.js'; import { Score } from './Score.js'; interface MeasureAsObject { maxDuration: number; data: Array; } interface ScoreAsObject { name: string, voices: Record , timeSignature: [number, number], bpm: number } /** * @class ScoreHandler * Static class that can convert scores to objects and back. */ export class ScoreHandler { /** * Convert a measure to object literal. * @param {Measure} measure * @return {{duration: string, data: {}, maxDuration: (number)}} */ static measureToObject(measure: Measure): MeasureAsObject { const notes = measure.data.map(notesMember => this.notesToObject(notesMember)); return { maxDuration: measure.maxDuration, data: notes, }; } /** * Convert a measure's notes member to object literal. * @param notesMember * @return {{duration: *, notes: any[]}} */ static notesToObject(notesMember: NormalizedMeasureData): MeasureData { const notes: MeasureData = { notes: Array.from(notesMember.notes), duration: notesMember.duration, }; if(notesMember.name) { notes.name = notesMember.name; } return notes; } /** * Convert object literal representing a measure to an instance of Measure. * @param {object} measureObject * @return {Measure} */ static objectToMeasure(measureObject: MeasureAsObject): Measure { const measure = new Measure(measureObject.maxDuration); measureObject.data.forEach((notesMember: MeasureData, position: number) => { if(notesMember.name) { measure.addChord({ ...notesMember }, position); } else { measure.addNotes({ ...notesMember }, position); } }); return measure; } /** * Convert a measure to object literal. * @param {Score} score * @return {{duration: string, voices: array, timeSignature: array, bpm: number}} */ static scoreToObject(score: Score): ScoreAsObject { const voices: Record = {}; Object.entries(score.voices).map(([voiceName, voiceData]) => voices[voiceName] = voiceData.map(measure => this.measureToObject(measure)), ); return { name: score.name, timeSignature: score.timeSignature, bpm: score.bpm, voices, }; } /** * Convert object literal representing a Score to an instance of Score. * @param {object} scoreObject * @return {Score} */ static objectToScore(scoreObject: ScoreAsObject): Score { const score = new Score({ timeSignature: scoreObject.timeSignature, bpm: scoreObject.bpm, name: scoreObject.name, }); Object.entries(scoreObject.voices).forEach(([voiceName, voiceData]: [string, MeasureAsObject[]]) => { score.addVoice(voiceName); voiceData.forEach((measureObject: MeasureAsObject, measureIndex: number) => { score.addMeasure(voiceName, { index: measureIndex, measure: this.objectToMeasure(measureObject) }); }); }); return score; } static cloneScore(score: Score): Score { return this.objectToScore(this.scoreToObject(score)); } }