webdaw-modules
Version:
a set of modules for building a web-based DAW
243 lines (225 loc) • 7.06 kB
text/typescript
import {
OpenSheetMusicDisplay,
GraphicalMeasure,
GraphicalStaffEntry,
GraphicalVoiceEntry,
GraphicalNote,
VerticalGraphicalStaffEntryContainer,
} from "opensheetmusicdisplay";
export type MusicSystemData = {
index: number;
x: number;
y: number;
};
export type NoteData = {
index: number;
x: number;
y: number;
width: number;
height: number;
center: { x: number; y: number };
ticks: number;
noteNumber: number;
isRestFlag: boolean;
noteLength: { numerator: number; denominator: number; wholeValue: number; realValue: number };
measureIndex: number;
staffIndex: number;
};
export type StaveData = {
index: number;
measureIndex: number;
timestamp: {
numerator: number;
denominator: number;
wholeValue: number;
realValue: number;
};
ticks: number;
x: number;
y: number;
width: number;
height: number;
notes: NoteData[];
};
export type OSMDEntityData = {
measureIndex: number;
containerIndex: number;
startX: number; // smallest x-position of all notes in this container
notes: NoteData[]; //
staves: StaveData[];
musicSystem: MusicSystemData;
};
const ppq = 960;
const getMusicSystemData = (
entryContainer: VerticalGraphicalStaffEntryContainer
): MusicSystemData => {
// console.log(entryContainer);
let staffEntry = (entryContainer as any).staffEntries[0];
let i = 1;
while (typeof staffEntry === "undefined" && i < (entryContainer as any).staffEntries.length) {
staffEntry = (entryContainer as any).staffEntries[i];
i++;
}
const {
boundingBox: {
absolutePosition: { x, y },
size: { width, height },
borderTop,
borderBottom,
},
id,
} = (staffEntry.parentMeasure as any).parentMusicSystem as any;
return {
index: id,
x,
y,
width,
height,
};
};
const getMeasureData = (entryContainer: VerticalGraphicalStaffEntryContainer): MeasureData[] => {
const measureData: MeasureData[] = [];
(entryContainer as any).staffEntries.forEach((staffEntry: GraphicalStaffEntry) => {
const {
boundingBox: {
absolutePosition: { x, y },
size: { width, height },
borderTop,
borderBottom,
},
measureNumber,
} = staffEntry.parentMeasure as any;
measureData.push({
index: measureNumber,
x: x * 10,
y: y * 10,
width: width * 10,
height: (y + borderBottom - (y - borderTop)) * 10,
});
});
return measureData;
};
const getNoteData = (entryContainer: VerticalGraphicalStaffEntryContainer): NoteData[] => {
const notes: NoteData[] = [];
(entryContainer as any).staffEntries.forEach(
(staffEntry: GraphicalStaffEntry, staffIndex: number) => {
staffEntry.graphicalVoiceEntries.forEach(voiceEntry => {
const measureIndex = (voiceEntry.parentStaffEntry.parentMeasure as any).measureNumber;
voiceEntry.notes.forEach((note: GraphicalNote) => {
const {
boundingBox: {
absolutePosition: { x, y },
borderLeft,
},
sourceNote,
} = note as any;
const { numerator, denominator, wholeValue, realValue } = note.graphicalNoteLength as any;
const relPosInMeasure = (note.sourceNote as any).voiceEntry.timestamp.realValue;
const data: NoteData = {
center: { x: x * 10, y: 0 },
x: (x + borderLeft) * 10,
y: y * 10,
ticks: measureIndex * ppq * 4 + relPosInMeasure * ppq * 4,
noteNumber: sourceNote.halfTone + 12,
isRestFlag: sourceNote.isRestFlag,
noteLength: { numerator, denominator, wholeValue, realValue },
};
notes.push(data);
});
});
}
);
return notes;
};
const getStaveData = (measure: GraphicalMeasure, measureIndex: number): StaveData[] => {
const staveData = measure.staffEntries.map(
(staffEntry: GraphicalStaffEntry, staffIndex: number) => {
const {
boundingBox: {
absolutePosition: { x, y },
size: { width, height },
borderTop,
borderBottom,
borderLeft,
},
} = staffEntry as any;
const notes: NoteData[] = [];
staffEntry.graphicalVoiceEntries.forEach(voiceEntry => {
voiceEntry.notes.forEach((note: GraphicalNote, noteIndex: number) => {
const {
boundingBox: {
absolutePosition: { x, y },
size: { width, height },
borderLeft,
},
sourceNote,
} = note as any;
const { numerator, denominator, wholeValue, realValue } = note.graphicalNoteLength as any;
const relPosInMeasure = (note.sourceNote as any).voiceEntry.timestamp.realValue;
const data: NoteData = {
index: noteIndex,
center: { x: x * 10, y: 0 },
x: (x + borderLeft) * 10,
y: y * 10,
width: width * 10,
height: height * 10,
ticks: measureIndex * ppq * 4 + relPosInMeasure * ppq * 4,
noteNumber: sourceNote.halfTone + 12,
isRestFlag: sourceNote.isRestFlag,
noteLength: { numerator, denominator, wholeValue, realValue },
staffIndex,
measureIndex,
};
notes.push(data);
});
});
const timestamp = staffEntry.relInMeasureTimestamp;
const ticks = measureIndex * ppq * 4 + timestamp.RealValue * ppq * 4;
return {
notes,
index: staffIndex,
ticks,
timestamp: {
numerator: timestamp.Numerator,
denominator: timestamp.Denominator,
realValue: timestamp.RealValue,
wholeValue: timestamp.WholeValue,
},
measureIndex,
x: (x + borderLeft) * 10,
y: (y + borderTop) * 10,
width: width * 10,
height: height * 10,
} as StaveData;
}
);
return staveData;
};
const getData = (entryContainer: VerticalGraphicalStaffEntryContainer, containerIndex: number) => {
return {
containerIndex,
notes: getNoteData(entryContainer),
measures: getMeasureData(entryContainer),
staves: getStaveData(entryContainer),
musicSystem: getMusicSystemData(entryContainer),
};
};
export const getEntries = (osmd: OpenSheetMusicDisplay, ppq: number = 960): OSMDEntityData[] => {
const entityData: OSMDEntityData[] = [];
osmd.GraphicSheet.VerticalGraphicalStaffEntryContainers.forEach(
(entryContainer: VerticalGraphicalStaffEntryContainer, containerIndex: number) => {
entityData.push(getData(entryContainer, containerIndex));
}
);
return entityData;
};
export const firstTest = (osmd: OpenSheetMusicDisplay, ppq: number = 960): StaveData[][] => {
const entries: StaveData[][] = [];
osmd.GraphicSheet.MeasureList.forEach((staves: GraphicalMeasure[], measureIndex: number) => {
staves.forEach(staff => {
const s = getStaveData(staff, measureIndex);
entries.push(s);
});
});
return entries;
};