|
@@ -208,9 +208,16 @@ export default defineComponent({
|
|
|
isClickNote: false,
|
|
|
/** 音符类型 */
|
|
|
noteType: "",
|
|
|
- selectMeasure: {
|
|
|
- start: "",
|
|
|
- end: "",
|
|
|
+ /** 选择小节范围 */
|
|
|
+ selectMeasures: {
|
|
|
+ state: false,
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ start: 1,
|
|
|
+ startNote: null as any,
|
|
|
+ end: 0,
|
|
|
+ endNote: null as any,
|
|
|
+ max: 30,
|
|
|
},
|
|
|
slide: ["note", "meter", "dynamics"],
|
|
|
|
|
@@ -223,11 +230,6 @@ export default defineComponent({
|
|
|
loadingAudioSrouce: false, // 加载音频资源
|
|
|
/** 移调类型 */
|
|
|
moveKeyType: "inset" as "inset" | "up" | "down", // 移调类型
|
|
|
- selectMearesDrag: {
|
|
|
- state: false,
|
|
|
- x: 0,
|
|
|
- y: 0,
|
|
|
- }, // 选择小节拖拽状态
|
|
|
});
|
|
|
const noteTypes = ABC_DATA.types.map((item) => item.value).filter(Boolean);
|
|
|
const accidentals = ABC_DATA.accidentals.map((item) => item.value).filter(Boolean);
|
|
@@ -282,7 +284,7 @@ export default defineComponent({
|
|
|
const totalTime = (abcData.synthControl as any).visualObj.getTotalTime();
|
|
|
if (totalTime) {
|
|
|
const progress = (data.active as any).currentTrackMilliseconds / 1000 / totalTime;
|
|
|
- // console.log("🚀 ~ data.active:", data.active, progress);
|
|
|
+ // console.log("🚀 ~ data.active:", progress);
|
|
|
(abcData.synthControl as any).seek(progress);
|
|
|
}
|
|
|
}
|
|
@@ -344,27 +346,6 @@ export default defineComponent({
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- /**
|
|
|
- * 分词
|
|
|
- * @param str 字符串
|
|
|
- * @returns
|
|
|
- * @description
|
|
|
- */
|
|
|
- const tokenize = (str: string) => {
|
|
|
- const arr = str.split(/(!.+?!|".+?")/);
|
|
|
- let output: string[] = [];
|
|
|
- for (let i = 0; i < arr.length; i++) {
|
|
|
- const token = arr[i];
|
|
|
- if (token.length > 0) {
|
|
|
- if (token[0] !== '"' && token[0] !== "!") {
|
|
|
- const arr2 = arr[i].split(/([A-Ga-gz][,']*)/);
|
|
|
- output = output.concat(arr2);
|
|
|
- } else output.push(token);
|
|
|
- }
|
|
|
- }
|
|
|
- return output;
|
|
|
- };
|
|
|
-
|
|
|
const hideCursor = () => {
|
|
|
const cursor = document.querySelector("#paper svg .ABCJS-cursor");
|
|
|
if (cursor) {
|
|
@@ -376,13 +357,7 @@ export default defineComponent({
|
|
|
};
|
|
|
|
|
|
const cursorControl = {
|
|
|
- // self.onReady = function () {
|
|
|
- // var downloadLink = document.querySelector(".download");
|
|
|
- // downloadLink.addEventListener("click", download);
|
|
|
- // downloadLink.setAttribute("style", "");
|
|
|
- // var clickEl = document.querySelector(".click-explanation");
|
|
|
- // clickEl.setAttribute("style", "");
|
|
|
- // };
|
|
|
+ onReady: function () {},
|
|
|
onStart: function () {
|
|
|
console.log("开始");
|
|
|
data.playState = true;
|
|
@@ -395,12 +370,28 @@ export default defineComponent({
|
|
|
cursor.setAttributeNS(null, "y2", "0");
|
|
|
svg?.appendChild(cursor);
|
|
|
},
|
|
|
- // self.beatSubdivisions = 2;
|
|
|
onBeat: function (beatNumber: any, totalBeats: any, totalTime: any) {},
|
|
|
onEvent: (ev: any) => {
|
|
|
+ // console.log("🚀 ~ ev:", ev);
|
|
|
if (!data.playState) return;
|
|
|
if (ev.measureStart && ev.left === null) return; // this was the second part of a tie across a measure line. Just ignore it.
|
|
|
-
|
|
|
+ if (popup.selectMearesShow) {
|
|
|
+ const startTime = data.selectMeasures.startNote?.currentTrackMilliseconds || 0;
|
|
|
+ const endNote: any = data.selectMeasures.endNote ? data.selectMeasures.endNote : null;
|
|
|
+ // console.log("🚀 ~ endNote:", ev.milliseconds , endNote.currentTrackMilliseconds)
|
|
|
+ if (
|
|
|
+ ev.milliseconds < startTime ||
|
|
|
+ (endNote && ev.milliseconds > endNote.currentTrackMilliseconds)
|
|
|
+ ) {
|
|
|
+ const totalTime = (abcData.synthControl as any).visualObj.getTotalTime();
|
|
|
+ if (totalTime) {
|
|
|
+ const progress = startTime / 1000 / totalTime;
|
|
|
+ nextTick(() => {
|
|
|
+ (abcData.synthControl as any).seek(progress);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
var cursor = document.querySelector("#paper svg .ABCJS-cursor");
|
|
|
if (cursor) {
|
|
|
cursor.setAttribute("x1", ev.left + ev.width / 2);
|
|
@@ -447,7 +438,7 @@ export default defineComponent({
|
|
|
})
|
|
|
.then(function (response) {
|
|
|
data.loadingAudioSrouce = false;
|
|
|
- // console.log("Audio successfully loaded.");
|
|
|
+ // console.log("Audio successfully loaded.", {...abcData.synthControl});
|
|
|
// console.log("🚀 ~ abcData.synthControl:", abcData.synthControl);
|
|
|
})
|
|
|
.catch((err) => {
|
|
@@ -457,7 +448,6 @@ export default defineComponent({
|
|
|
};
|
|
|
|
|
|
const togglePlay = (type: "play" | "pause" | "reset") => {
|
|
|
- console.log("🚀 ~ abcData.synthControl:", abcData.synthControl);
|
|
|
if (type === "play") {
|
|
|
abcData.synthControl.play();
|
|
|
data.playState = true;
|
|
@@ -468,6 +458,7 @@ export default defineComponent({
|
|
|
} else {
|
|
|
abcData.synthControl.restart();
|
|
|
}
|
|
|
+ // console.log("🚀 ~ abcData.synthControl:", abcData.synthControl.timer.noteTimings);
|
|
|
};
|
|
|
|
|
|
const renderSvg = () => {
|
|
@@ -483,14 +474,18 @@ export default defineComponent({
|
|
|
const renderBoxRect = () => {
|
|
|
const svg = document.querySelector("#paper svg");
|
|
|
const padding = 4;
|
|
|
+ let measureNumber = 0;
|
|
|
for (let i = 0; i < abcData.visualObj.lines.length; i++) {
|
|
|
const line = abcData.visualObj.lines[i];
|
|
|
- console.log("🚀 ~ line:", line);
|
|
|
+ // console.log("🚀 ~ line:", line);
|
|
|
for (let j = 0; j < line.staff.length; j++) {
|
|
|
const staff = line.staff[j];
|
|
|
const voices = [...staff.voices].flat();
|
|
|
for (let l = 0; l < voices.length; l++) {
|
|
|
const item = voices[l];
|
|
|
+ if (item.el_type === "bar") {
|
|
|
+ measureNumber++;
|
|
|
+ }
|
|
|
// console.log(item.el_type);
|
|
|
if (["note", "keySignature", "clef", "timeSignature"].includes(item.el_type)) {
|
|
|
const box = item.abselem.elemset?.[0]?.getBBox?.() || null;
|
|
@@ -511,21 +506,26 @@ export default defineComponent({
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ console.log(measureNumber);
|
|
|
+ data.selectMeasures.max = measureNumber;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* @param isProduct 是否是生成曲谱
|
|
|
*/
|
|
|
- const handleResetRender = (isProduct = true) => {
|
|
|
+ const handleResetRender = () => {
|
|
|
return new Promise((resolve) => {
|
|
|
nextTick(() => {
|
|
|
- data.music = isProduct ? renderMeasures(abcData.abc) : data.music;
|
|
|
+ data.music = renderMeasures(abcData.abc);
|
|
|
renderSvg();
|
|
|
resetMidi(data.drawCount > 0 ? true : false);
|
|
|
renderBoxRect();
|
|
|
resolve(1);
|
|
|
textAreaRef.value && (textAreaRef.value.value = data.music);
|
|
|
data.drawCount++;
|
|
|
+
|
|
|
+ const times = new ABCJS.TimingCallbacks(abcData.visualObj);
|
|
|
+ console.log("🚀 ~ times:", times)
|
|
|
});
|
|
|
});
|
|
|
};
|
|
@@ -1154,6 +1154,13 @@ export default defineComponent({
|
|
|
};
|
|
|
abcData.synthControl.restart();
|
|
|
// formateAbc(abcData.visualObj);
|
|
|
+ const selectMearesBtn = document.querySelector("#selectMearesBtn");
|
|
|
+ if (selectMearesBtn) {
|
|
|
+ const rect = selectMearesBtn.getBoundingClientRect();
|
|
|
+ data.selectMeasures.x = document.body.clientWidth - 320;
|
|
|
+ data.selectMeasures.y = rect.top + 70;
|
|
|
+ data.selectMeasures.state = true;
|
|
|
+ }
|
|
|
});
|
|
|
onUnmounted(() => {
|
|
|
document.removeEventListener("keyup", handleKeyUp);
|
|
@@ -1309,14 +1316,49 @@ export default defineComponent({
|
|
|
console.log("🚀 ~ abc:", abc);
|
|
|
abc = (window as any).vertaal(abc, { p: "f", t: 1, u: 0, v: 3, mnum: 0 });
|
|
|
console.log(abc);
|
|
|
- data.music = abc[0];
|
|
|
- handleResetRender(false);
|
|
|
+ // data.music = abc[0];
|
|
|
+ // handleResetRender(false);
|
|
|
};
|
|
|
reader.readAsText(file);
|
|
|
};
|
|
|
input.click();
|
|
|
};
|
|
|
|
|
|
+ /** 设置选段小节 */
|
|
|
+ const handleSetSelectMeares = (index: number | null, type: "start" | "end") => {
|
|
|
+ console.log("🚀 ~ index:", index);
|
|
|
+ if (type === "start") {
|
|
|
+ const note = index ? useIndexGetNote(`${index - 1}.0`) : null;
|
|
|
+ // console.log("🚀 ~ note:", note);
|
|
|
+ data.selectMeasures.start = index ? index - 1 : 0;
|
|
|
+ data.selectMeasures.startNote = note;
|
|
|
+ if (
|
|
|
+ data.selectMeasures.start &&
|
|
|
+ data.selectMeasures.end &&
|
|
|
+ data.selectMeasures.end < data.selectMeasures.start
|
|
|
+ ) {
|
|
|
+ data.selectMeasures.end = 0;
|
|
|
+ data.selectMeasures.endNote = null;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const note = index
|
|
|
+ ? useIndexGetNote(`${index - 1}.${abcData.abc.measures[index - 1]?.notes.length - 1}`)
|
|
|
+ : null;
|
|
|
+ // console.log("🚀 ~ note:", note);
|
|
|
+ data.selectMeasures.end = index ? index - 1 : 0;
|
|
|
+ data.selectMeasures.endNote = note;
|
|
|
+ if (
|
|
|
+ data.selectMeasures.start &&
|
|
|
+ data.selectMeasures.end &&
|
|
|
+ data.selectMeasures.start > data.selectMeasures.end
|
|
|
+ ) {
|
|
|
+ // console.log(data.selectMeasures.start, data.selectMeasures.end);
|
|
|
+ data.selectMeasures.start = 0;
|
|
|
+ data.selectMeasures.startNote = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
return () => (
|
|
|
<div class={styles.container}>
|
|
|
<div class={styles.containerTop} onKeyup={(e: Event) => e.stopPropagation()}>
|
|
@@ -1877,6 +1919,7 @@ export default defineComponent({
|
|
|
<div>{data.playState ? "暂停" : "播放"}</div>
|
|
|
</div>
|
|
|
<div
|
|
|
+ id="selectMearesBtn"
|
|
|
class={[styles.topBtn]}
|
|
|
onClick={() => (popup.selectMearesShow = !popup.selectMearesShow)}
|
|
|
>
|
|
@@ -2112,38 +2155,59 @@ export default defineComponent({
|
|
|
|
|
|
<TheSetting v-model:show={popup.settingShow} />
|
|
|
|
|
|
- {/* <UseDraggable
|
|
|
- initialValue={{ x: 320, y: 60 }}
|
|
|
- class={[styles.selectMearesBox, !popup.selectMearesShow && styles.selectMearesHidden]}
|
|
|
- >
|
|
|
- <NSpace justify="space-between">
|
|
|
- <div class={styles.btnLineTitle}>输入小节范围</div>
|
|
|
- <NButton circle quaternary size="small" onClick={() => (popup.selectMearesShow = false)}>
|
|
|
- <NIcon size={16} component={<Close />} />
|
|
|
- </NButton>
|
|
|
- </NSpace>
|
|
|
- <NSpace align="center">
|
|
|
- <div style={{ width: "200px" }}>
|
|
|
- <NInput pair placeholder={["开始小节", "结束小节"]}></NInput>
|
|
|
- </div>
|
|
|
- <div class={styles.topBtn}>
|
|
|
- <NSpin show={data.loadingAudioSrouce} size="small">
|
|
|
- <div class={styles.btnImg} onClick={() => togglePlay(data.playState ? "pause" : "play")}>
|
|
|
- <img
|
|
|
- style={{ display: data.playState ? "" : "none" }}
|
|
|
- class={styles.topBtnIcon}
|
|
|
- src={getImage("icon_21_1.png")}
|
|
|
- />
|
|
|
- <img
|
|
|
- style={{ display: data.playState ? "none" : "" }}
|
|
|
- class={styles.topBtnIcon}
|
|
|
- src={getImage("icon_21.png")}
|
|
|
- />
|
|
|
- </div>
|
|
|
- </NSpin>
|
|
|
- </div>
|
|
|
- </NSpace>
|
|
|
- </UseDraggable> */}
|
|
|
+ {data.selectMeasures.state && (
|
|
|
+ <UseDraggable
|
|
|
+ initialValue={{ x: data.selectMeasures.x, y: data.selectMeasures.y }}
|
|
|
+ class={[styles.selectMearesBox, !popup.selectMearesShow && styles.selectMearesHidden]}
|
|
|
+ >
|
|
|
+ <NSpace justify="space-between">
|
|
|
+ <div class={styles.btnLineTitle}>输入小节范围</div>
|
|
|
+ <NButton circle quaternary size="small" onClick={() => (popup.selectMearesShow = false)}>
|
|
|
+ <NIcon size={16} component={<Close />} />
|
|
|
+ </NButton>
|
|
|
+ </NSpace>
|
|
|
+ <NSpace align="center" wrap={false} wrapItem={false}>
|
|
|
+ <div class={styles.mearesInput}>
|
|
|
+ <NInputNumber
|
|
|
+ min={1}
|
|
|
+ max={data.selectMeasures.max}
|
|
|
+ bordered={false}
|
|
|
+ placeholder="开始小节"
|
|
|
+ showButton={false}
|
|
|
+ onUpdate:value={(val) => handleSetSelectMeares(val, "start")}
|
|
|
+ ></NInputNumber>
|
|
|
+ -
|
|
|
+ <NInputNumber
|
|
|
+ min={data.selectMeasures.start}
|
|
|
+ max={data.selectMeasures.max}
|
|
|
+ bordered={false}
|
|
|
+ placeholder="结束小节"
|
|
|
+ showButton={false}
|
|
|
+ onUpdate:value={(val) => handleSetSelectMeares(val, "end")}
|
|
|
+ ></NInputNumber>
|
|
|
+ </div>
|
|
|
+ <div class={styles.topBtn}>
|
|
|
+ <NSpin show={data.loadingAudioSrouce} size="small">
|
|
|
+ <div
|
|
|
+ class={styles.btnImg}
|
|
|
+ onClick={() => togglePlay(data.playState ? "pause" : "play")}
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ style={{ display: data.playState ? "" : "none" }}
|
|
|
+ class={styles.topBtnIcon}
|
|
|
+ src={getImage("icon_21_1.png")}
|
|
|
+ />
|
|
|
+ <img
|
|
|
+ style={{ display: data.playState ? "none" : "" }}
|
|
|
+ class={styles.topBtnIcon}
|
|
|
+ src={getImage("icon_21.png")}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </NSpin>
|
|
|
+ </div>
|
|
|
+ </NSpace>
|
|
|
+ </UseDraggable>
|
|
|
+ )}
|
|
|
</div>
|
|
|
);
|
|
|
},
|