123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- import { OpenSheetMusicDisplay, SourceMeasure } from "/osmd-extended/src";
- import { onlyVisible } from "/src/helpers/formateMusic";
- export const noteDuration = {
- "1/2": 2,
- w: 1,
- h: 0.5,
- q: 0.25,
- "8": 0.125,
- "16": 0.0625,
- "32": 0.03125,
- "64": 0.015625,
- "128": 0.0078125,
- };
- export type GradualChange = {
- resetXmlNoteIndex: number;
- startXmlNoteIndex: number;
- endXmlNoteIndex: number;
- startWord: string;
- startMeasureListIndex: number;
- endMeasureListIndex: number;
- resetMeasureListIndex: number;
- };
- export const speedInfo: { [key in string]: number } = {
- "rall.": 1.333333333,
- "poco rit.": 1.333333333,
- "rit.": 1.333333333,
- "molto rit.": 1.333333333,
- "molto rall": 1.333333333,
- molto: 1.333333333,
- lentando: 1.333333333,
- allargando: 1.333333333,
- morendo: 1.333333333,
- "accel.": 0.8,
- calando: 2,
- "poco accel.": 0.8,
- "gradually slowing": 1.333333333,
- slowing: 1.333333333,
- slow: 1.333333333,
- slowly: 1.333333333,
- faster: 1.333333333,
- "molto allargando": 1.333333333,
- stringendo: 0.8,
- };
- /**
- * 计算渐变速度
- */
- export const calcGradual = () => {};
- /**
- * 2022年9月14日版本 计算渐变速度,此方法不兼容之前的选择范围。
- */
- export const calcGradual2 = () => {};
- /**
- * 获取指定元素下一个Note元素
- * @param ele 指定元素
- * @param selectors 选择器
- */
- const getNextNote = (ele: Element, selectors: string) => {
- let index = 0;
- const parentEle = ele.closest(selectors);
- let pointer = parentEle;
- const measure = parentEle?.closest("measure");
- let siblingNote: Element | null | undefined = null;
- // 查找到相邻的第一个note元素
- while (!siblingNote && index < (measure?.childNodes.length || 50)) {
- index++;
- if (pointer?.nextElementSibling?.tagName === "note") {
- siblingNote = pointer?.nextElementSibling;
- }
- pointer = pointer?.nextElementSibling!;
- }
- return siblingNote;
- };
- export type GradualElement = {
- ele: Element;
- index: number;
- noteInMeasureIndex: number;
- textContent: string;
- measureIndex: number;
- type: "words" | "metronome";
- allDuration: number;
- leftDuration: number;
- };
- export type GradualNote = GradualItem[];
- export type GradualItem = {
- start: number;
- measureIndex: number;
- noteInMeasureIndex: number;
- allDuration: number;
- leftDuration: number;
- type: string;
- closedMeasureIndex: number;
- };
- // export type GradualItem = {
- // start: number
- // startMeasureIndex: number
- // startNoteInMeasureIndex: number
- // allDuration: number
- // leftDuration: number
- // endNoteInMeasureIndex?: number
- // endMeasureIndex?: number
- // end?: number
- // }
- /**
- * 按照xml进行减慢速度的计算
- * @param xml 始终按照第一分谱进行减慢速度的计算
- */
- export const getGradualLengthByXml = (xml: string) => {
- const firstPartXml = onlyVisible(xml, 0, 'calc')
- const xmlParse = new DOMParser().parseFromString(firstPartXml, "text/xml");
- const measures = Array.from(xmlParse.querySelectorAll("measure"));
- const notes = Array.from(xmlParse.querySelectorAll("note"));
- const words = Array.from(xmlParse.querySelectorAll("words"));
- const metronomes = Array.from(xmlParse.querySelectorAll("metronome"));
- const eles: GradualElement[] = [];
- for (const ele of [...words, ...metronomes]) {
- const note = getNextNote(ele, "direction");
- // console.log(ele, note)
- if (note) {
- const measure = note?.closest("measure")!;
- const measureNotes = Array.from(measure.querySelectorAll("note"));
- const noteInMeasureIndex = Array.from(measure.childNodes)
- .filter((item) => item.nodeName === "note")
- .findIndex((item) => item === note);
- let allDuration = 0;
- let leftDuration = 0;
- for (let i = 0; i < measureNotes.length; i++) {
- const n = measureNotes[i];
- const duration = +(n.querySelector("duration")?.textContent || "0");
- allDuration += duration;
- if (i < noteInMeasureIndex) {
- leftDuration = allDuration;
- }
- }
- eles.push({
- ele,
- index: notes.indexOf(note!),
- noteInMeasureIndex,
- textContent: ele.textContent!,
- measureIndex: measures.indexOf(measure!),
- type: ele.tagName as GradualElement["type"],
- allDuration,
- leftDuration,
- });
- }
- }
- // 结尾处手动插入一个音符节点
- eles.push({
- ele: notes[notes.length - 1],
- index: notes.length,
- noteInMeasureIndex: 0,
- textContent: "",
- type: "metronome",
- allDuration: 1,
- leftDuration: 0,
- measureIndex: measures.length,
- });
- const gradualNotes: GradualNote[] = [];
- eles.sort((a, b) => a.index - b.index);
- const keys = Object.keys(speedInfo).map((w) => w.toLocaleLowerCase());
- for (const ele of eles) {
- // 是否是同时也是关闭标签
- let isLastNoteAndNotClosed = false;
- let closed = 0;
- const textContent = ele.textContent?.toLocaleLowerCase().trim();
- if (ele === eles[eles.length - 1]) {
- if (gradualNotes[gradualNotes.length - 1]?.length === 1) {
- isLastNoteAndNotClosed = true;
- }
- }
- const isKeyWork = keys.find((k) => {
- const ks = k.split(" ");
- return textContent && ks.includes(textContent) || k === textContent;
- });
- if (ele.type === "metronome" || (ele.type === "words" && (textContent.startsWith("a tempo") || isKeyWork)) || isLastNoteAndNotClosed) {
- const indexOf = gradualNotes.findIndex((item) => item.length === 1);
- if (indexOf > -1 && ele.index > gradualNotes[indexOf]?.[0].start) {
- closed = -1;
- gradualNotes[indexOf][1] = {
- start: ele.index,
- measureIndex: ele.measureIndex,
- closedMeasureIndex: ele.measureIndex,
- noteInMeasureIndex: ele.noteInMeasureIndex,
- allDuration: ele.allDuration,
- leftDuration: ele.leftDuration,
- type: textContent,
- };
- }
- }
- if (ele.type === "words" && isKeyWork) {
- gradualNotes.push([
- {
- start: ele.index,
- measureIndex: ele.measureIndex,
- closedMeasureIndex: ele.measureIndex + closed,
- noteInMeasureIndex: ele.noteInMeasureIndex,
- allDuration: ele.allDuration,
- leftDuration: ele.leftDuration,
- type: textContent,
- },
- ]);
- }
- }
- return gradualNotes;
- };
- export const getGradualLength = (gradualChange: GradualChange, speed: number, osdm: OpenSheetMusicDisplay) => {
- const { startMeasureListIndex, endMeasureListIndex, endXmlNoteIndex, startWord } = gradualChange;
- const measures: SourceMeasure[] = [];
- for (let index = startMeasureListIndex; index <= endMeasureListIndex; index++) {
- const measure = osdm.Sheet.SourceMeasures[index];
- measures.push(measure);
- }
- const allNoteDurations: number[] = [];
- for (const measure of measures) {
- if (allNoteDurations.length >= endXmlNoteIndex) {
- break;
- }
- // @ts-ignore
- measure.VerticalMeasureList[0]?.vfVoices["1"]?.tickables?.forEach((item) =>
- allNoteDurations.push(noteDuration[item.duration as keyof typeof noteDuration])
- );
- }
- const minDuration = Math.min(...allNoteDurations);
- const parts = allNoteDurations.map((item) => item / minDuration);
- const allParts = parts.reduce((total, val) => val + total, 0);
- // const startMeasure = osdm.Sheet.SourceMeasures[startMeasureListIndex]
- // const endMeasure = osdm.Sheet.SourceMeasures[endMeasureListIndex]
- let surplusSpeed = speed / speedInfo[startWord?.toLocaleLowerCase()] || 1;
- const diffSpeed = speed - surplusSpeed;
- let useSpeed = 0;
- const speeds: number[] = parts.map((item) => {
- const s = ((diffSpeed - useSpeed) * item) / allParts;
- return s;
- });
- // 120 111.9 104.4 96.9
- // 8.1 7.5 7.2 6.9
- // 0.6 0.3 0.3
- const lingerSpeed: number[] = [];
- for (let index = 0; index < speeds.length; index++) {
- const s = speeds[index];
- let beforeSpeed = 0;
- let afterSpeed = 0;
- for (let j = 0; j < index; j++) {
- beforeSpeed += speeds[j];
- }
- afterSpeed += beforeSpeed;
- afterSpeed += s;
- lingerSpeed.push((afterSpeed + beforeSpeed) / 2);
- }
- // console.log(lingerSpeed, speeds[0], speeds, parts, allParts)
- return lingerSpeed;
- };
|