فهرست منبع

重播,暂停播放问题

liushengqiang 1 سال پیش
والد
کامیت
1104632130
4فایلهای تغییر یافته به همراه249 افزوده شده و 151 حذف شده
  1. 119 110
      src/pc/home/component/file-btn/index.tsx
  2. 1 0
      src/pc/home/index.module.less
  3. 38 15
      src/pc/home/index.tsx
  4. 91 26
      src/pc/home/runtime.ts

+ 119 - 110
src/pc/home/component/file-btn/index.tsx

@@ -5,116 +5,125 @@ import { getImage } from "../../images";
 import { DropdownMixedOption } from "naive-ui/es/dropdown/src/interface";
 
 /** 新建 | 保存 | 导入 | 上传 | 导出 | 打印 | 退出*/
-export type IFileBtnType = "newMusic" | "save" | "xml" | "upload" | "png" | "wav" | "midi" | "print" | "exit";
+export type IFileBtnType =
+	| "newMusic"
+	| "save"
+	| "xml"
+	| "upload"
+	| "png"
+	| "wav"
+	| "midi"
+	| "print"
+	| "exit";
 
 export default defineComponent({
-  name: "FileBtn",
-  emits: ["select"],
-  setup(props, { emit }) {
-    const options: DropdownMixedOption[] = [
-      {
-        label: () => (
-          <div class={styles.dropItem}>
-            <img class={styles.dropIcon} src={getImage("icon_26_4.png")} />
-            <span>新建曲谱</span>
-          </div>
-        ),
-        key: "newMusic",
-      },
-      {
-        label: () => (
-          <div class={styles.dropItem}>
-            <img class={styles.dropIcon} src={getImage("icon_26_0.png")} />
-            <span>保存</span>
-          </div>
-        ),
-        key: "save",
-      },
-      // {
-      // 	label: () => (
-      // 		<div class={styles.dropItem}>
-      // 			<img class={styles.dropIcon} src={getImage("icon_26_0.png")} />
-      // 			<span>导入</span>
-      // 		</div>
-      // 	),
-      // 	key: "import",
-      // 	disabled: true,
-      // 	children: [
-      // 		{
-      // 			label: "xml",
-      //             key: 'xml',
-      // 			disabled: true
-      // 		},
-      // 	],
-      // },
-      {
-        label: () => (
-          <div class={styles.dropItem}>
-            <img class={styles.dropIcon} src={getImage("icon_26_1.png")} />
-            <span>上传到我的资源</span>
-          </div>
-        ),
-        key: "upload",
-        disabled: true,
-      },
-      {
-        label: () => (
-          <div class={styles.dropItem}>
-            <img class={styles.dropIcon} src={getImage("icon_26_2.png")} />
-            <span>导出</span>
-          </div>
-        ),
-        key: "export",
-        children: [
-          {
-            label: "PNG",
-            key: "png",
-          },
-          {
-            label: "WAV",
-            key: "wav",
-          },
-          {
-            label: "MIDI",
-            key: "midi",
-          },
-        ],
-      },
-      {
-        label: () => (
-          <div class={styles.dropItem}>
-            <img class={styles.dropIcon} src={getImage("icon_26_3.png")} />
-            <span>打印</span>
-          </div>
-        ),
-        key: "print",
-        disabled: true,
-      },
-      // {
-      // 	label: () => (
-      // 		<div class={styles.dropItem}>
-      // 			<img class={styles.dropIcon} src={getImage("icon_26_5.png")} />
-      // 			<span>退出</span>
-      // 		</div>
-      // 	),
-      // 	key: "exit",
-      // 	disabled: false,
-      // },
-    ];
-    return () => (
-      <NDropdown
-        class={styles.dropWrap}
-        options={options}
-        trigger="click"
-        onSelect={(val) => {
-          console.log("🚀 ~ val:", val);
-          emit("select", val);
-        }}
-      >
-        <div class={styles.btnImg}>
-          <img class={styles.topBtnIcon} src={getImage("icon_0.png")} />
-        </div>
-      </NDropdown>
-    );
-  },
+	name: "FileBtn",
+	emits: ["select"],
+	setup(props, { emit }) {
+		const options: DropdownMixedOption[] = [
+			{
+				label: () => (
+					<div class={styles.dropItem}>
+						<img class={styles.dropIcon} src={getImage("icon_26_4.png")} />
+						<span>新建曲谱</span>
+					</div>
+				),
+				key: "newMusic",
+			},
+			{
+				label: () => (
+					<div class={styles.dropItem}>
+						<img class={styles.dropIcon} src={getImage("icon_26_0.png")} />
+						<span>保存</span>
+					</div>
+				),
+				key: "save",
+			},
+			// {
+			// 	label: () => (
+			// 		<div class={styles.dropItem}>
+			// 			<img class={styles.dropIcon} src={getImage("icon_26_0.png")} />
+			// 			<span>导入</span>
+			// 		</div>
+			// 	),
+			// 	key: "import",
+			// 	// disabled: true,
+			// 	children: [
+			// 		{
+			// 			label: "XML",
+			// 			key: "xml",
+			// 			// disabled: true,
+			// 		},
+			// 	],
+			// },
+			{
+				label: () => (
+					<div class={styles.dropItem}>
+						<img class={styles.dropIcon} src={getImage("icon_26_1.png")} />
+						<span>上传到我的资源</span>
+					</div>
+				),
+				key: "upload",
+				disabled: true,
+			},
+			{
+				label: () => (
+					<div class={styles.dropItem}>
+						<img class={styles.dropIcon} src={getImage("icon_26_2.png")} />
+						<span>导出</span>
+					</div>
+				),
+				key: "export",
+				children: [
+					{
+						label: "PNG",
+						key: "png",
+					},
+					{
+						label: "WAV",
+						key: "wav",
+					},
+					{
+						label: "MIDI",
+						key: "midi",
+					},
+				],
+			},
+			{
+				label: () => (
+					<div class={styles.dropItem}>
+						<img class={styles.dropIcon} src={getImage("icon_26_3.png")} />
+						<span>打印</span>
+					</div>
+				),
+				key: "print",
+				disabled: true,
+			},
+			// {
+			// 	label: () => (
+			// 		<div class={styles.dropItem}>
+			// 			<img class={styles.dropIcon} src={getImage("icon_26_5.png")} />
+			// 			<span>退出</span>
+			// 		</div>
+			// 	),
+			// 	key: "exit",
+			// 	disabled: false,
+			// },
+		];
+		return () => (
+			<NDropdown
+				class={styles.dropWrap}
+				options={options}
+				trigger="click"
+				onSelect={(val) => {
+					console.log("🚀 ~ val:", val);
+					emit("select", val);
+				}}
+			>
+				<div class={styles.btnImg}>
+					<img class={styles.topBtnIcon} src={getImage("icon_0.png")} />
+				</div>
+			</NDropdown>
+		);
+	},
 });

+ 1 - 0
src/pc/home/index.module.less

@@ -324,6 +324,7 @@
     display: flex;
     justify-content: center;
     align-items: center;
+    z-index: 100;
 }
 .exportPng{
     position: fixed;

+ 38 - 15
src/pc/home/index.tsx

@@ -163,6 +163,7 @@ export default defineComponent({
 			loadingAudioSrouce: false, // 加载音频资源
 			/** 移调类型 */
 			moveKeyType: "inset" as "inset" | "up" | "down", // 移调类型
+			activePlayNote: null as any, // 当前演奏音符
 		});
 		const noteTypes = ABC_DATA.types.map((item) => item.value).filter(Boolean);
 		const accidentals = ABC_DATA.accidentals.map((item) => item.value).filter(Boolean);
@@ -311,7 +312,6 @@ export default defineComponent({
 				metronomeData.metro.sound(time);
 			},
 			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) {
@@ -331,6 +331,7 @@ export default defineComponent({
 						}
 					}
 				}
+				data.activePlayNote = {...ev};
 				var cursor = document.querySelector("#paper svg .ABCJS-cursor");
 				if (cursor) {
 					cursor.setAttribute("x1", ev.left + ev.width / 2);
@@ -392,10 +393,23 @@ export default defineComponent({
 				data.playState = true;
 			} else if (type === "pause") {
 				abcData.synthControl.play();
+				// abcData.synthControl.pause();
 				data.playState = false;
 				hideCursor();
+				const totalTime = (abcData.synthControl as any).visualObj.getTotalTime();
+				if (totalTime && data.activePlayNote?.milliseconds !== undefined) {
+					const progress = data.activePlayNote.milliseconds / 1000 / totalTime;
+					nextTick(() => {
+						(abcData.synthControl as any).seek(progress);
+					});
+				}
 			} else {
 				abcData.synthControl.restart();
+				nextTick(() => {
+					if (!data.playState){
+						abcData.synthControl.play();
+					}
+				})
 			}
 			// console.log("🚀 ~ abcData.synthControl:", abcData.synthControl.timer.noteTimings);
 		};
@@ -449,6 +463,14 @@ export default defineComponent({
 			data.selectMeasures.max = measureNumber;
 		};
 
+		let saveTimer: any = null;
+		const autoSave = () => {
+			saveTimer && clearTimeout(saveTimer);
+			saveTimer = setTimeout(() => {
+				handleSaveMusic(false);
+			}, 5000);
+		};
+
 		/**
 		 * @param isProduct 是否是生成曲谱
 		 */
@@ -473,6 +495,11 @@ export default defineComponent({
 					}
 
 					resolve(1);
+					if (data.drawCount > 0) {
+						const host = location.host;
+						if (host.includes("localhost") || host.includes("192")) return;
+						autoSave();
+					}
 
 					textAreaRef.value && (textAreaRef.value.value = data.music);
 					data.drawCount++;
@@ -512,7 +539,7 @@ export default defineComponent({
 					});
 				}
 			}
-			console.log("abcData.abc.measures", list);
+			// console.log("abcData.abc.measures", list);
 			if (!metronomeData.metro) {
 				metronomeData.metro = new Metronome();
 			}
@@ -1134,7 +1161,7 @@ export default defineComponent({
 
 					abcData.abc.celf = abc.celf || "K:treble";
 					abcData.abc.key = abc.key.value || abc.key || "K:C";
-					abcData.abc.meter = abc.meter.value|| abc.meter || "M:4/4";
+					abcData.abc.meter = abc.meter.value || abc.meter || "M:4/4";
 					abcData.abc.speed = abc.speed || "Q:1/4=60";
 					abcData.abc.visualTranspose = abc.visualTranspose || 0;
 					abcData.abc.subjectCode = abc.subjectCode || "acoustic_grand_piano";
@@ -1184,7 +1211,6 @@ export default defineComponent({
 				}
 			};
 			abcData.synthControl.restart();
-			// formateAbc(abcData.visualObj);
 			const selectMearesBtn = document.querySelector("#selectMearesBtn");
 			if (selectMearesBtn) {
 				const rect = selectMearesBtn.getBoundingClientRect();
@@ -1352,13 +1378,15 @@ export default defineComponent({
 				const reader = new FileReader();
 				reader.onload = (e: any) => {
 					let abc = e.target.result;
-					console.log("🚀 ~ abc:", abc);
+					// console.log("🚀 ~ abc:", abc);
 					abc = new DOMParser().parseFromString(abc, "text/xml");
-					console.log("🚀 ~ abc:", abc);
+					// 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);
+					// console.log(abc);
+					const parseData = ABCJS.renderAbc("importRef", abc[0], { responsive: "resize" });
+					console.log("🚀 ~ parseData:", parseData);
+					abcData.abc = formateAbc(parseData[0], { subjectCode: abcData.abc.subjectCode });
+					handleResetRender();
 				};
 				reader.readAsText(file);
 			};
@@ -2226,13 +2254,8 @@ export default defineComponent({
 							)}
 
 							{/* <textarea ref={textAreaRef} class={styles.value} id="abc"></textarea> */}
+							<div id="importRef"></div>
 							<div id="audio" style={{ display: "none" }}></div>
-							<div id="warnings"></div>
-
-							<p class="beat"></p>
-							<pre class="clicked-info"></pre>
-							<pre class="feedback"></pre>
-							<div id="container"></div>
 							{data.loadingAudioSrouce && (
 								<div class={styles.loading}>
 									<NSpin></NSpin>

+ 91 - 26
src/pc/home/runtime.ts

@@ -185,10 +185,10 @@ interface IRenderMeasuresOption {
 	showTitle?: boolean;
 	showCreator?: boolean;
 }
-/** 
+/**
  * 生成小节
  * @param abc
- * 
+ *
  * @returns
  */
 export const renderMeasures = (abc: IAbc, option?: IRenderMeasuresOption) => {
@@ -196,7 +196,7 @@ export const renderMeasures = (abc: IAbc, option?: IRenderMeasuresOption) => {
 	let wrap = 1;
 	let text = `X:1\n`;
 
-	if (option?.showTitle){
+	if (option?.showTitle) {
 		abc.title && (text += abc.title + "\n");
 	}
 	if (option?.showCreator) {
@@ -211,43 +211,43 @@ export const renderMeasures = (abc: IAbc, option?: IRenderMeasuresOption) => {
 	const measures = abc.measures;
 	for (let i = 0; i < measures.length; i++) {
 		const measure = measures[i];
-		text += measure.repeat ?? '';// 重复
-		text += measure.meter ?? '';// 拍号
+		text += measure.repeat ?? ""; // 重复
+		text += measure.meter ?? ""; // 拍号
 		for (let j = 0; j < measure.notes.length; j++) {
 			const note = measure.notes[j];
 			const playStr = note.play?.join("") ?? "";
 
-			text += note.clef ?? ''; // 谱号
-			text += note.key ?? ''; // 调号
-			text += note.speed ?? ''; // 速度
-			text += note.slus ?? ''; // 3连音
+			text += note.clef ?? ""; // 谱号
+			text += note.key ?? ""; // 调号
+			text += note.speed ?? ""; // 速度
+			text += note.slus ?? ""; // 3连音
 			if (note.tie?.includes("(")) {
 				// 连音线 前
-				text += note.tie ?? '';
+				text += note.tie ?? "";
 			}
-			if (!option?.hiddenIndex){
+			if (!option?.hiddenIndex) {
 				text += `"<${i + "." + j}"`; // 音符 id
 			}
-			text += playStr ?? ''; // 演奏技法
-			text += note.dynamics ?? ''; // 力度符号
-			text += note.accidental ?? ''; // 临时升降记号
-			text += note.content ?? ''; // 音符
+			text += playStr ?? ""; // 演奏技法
+			text += note.dynamics ?? ""; // 力度符号
+			text += note.accidental ?? ""; // 临时升降记号
+			text += note.content ?? ""; // 音符
 			// 音符时值
-			text += note.noteType ?? '';
-			text += note.dot ?? ''; // 点
+			text += note.noteType ?? "";
+			text += note.dot ?? ""; // 点
 
-			text += note.tieline ?? ''; // 延音
+			text += note.tieline ?? ""; // 延音
 			if (note.tie?.includes(")")) {
 				// 连音线 后
-				text += note.tie ?? '';
+				text += note.tie ?? "";
 			}
-			text += note.segno ?? ''; // 分割
+			text += note.segno ?? ""; // 分割
 		}
 		let _i = i + 1;
 		if (!option?.hiddenIndex) {
-			text += `"<${_i}"`
+			text += `"<${_i}"`;
 		}
-		text += measure.barline ?? '';
+		text += measure.barline ?? "";
 		if (wrap % 4 === 0) {
 			text += "\n";
 		}
@@ -294,7 +294,23 @@ export const moveNoteKey = (note: string, moveData: { step: number; move: number
 	return note;
 };
 
-export const formateAbc = (visualObj: TuneObject) => {
+const formateGetData = {
+	getNoteType: (duration: number) => {
+		const type = 0.25 / duration;
+		console.log(type);
+		const noteType = [
+			{ name: 0.25, value: "4" },
+			{ name: 0.5, value: "2" },
+			{ name: 1, value: "" },
+			{ name: 2, value: "/" },
+			{ name: 4, value: "//" },
+			{ name: 8, value: "///" },
+		];
+		return noteType.find((n) => n.name === type)?.value || "";
+	},
+};
+
+export const formateAbc = (visualObj: TuneObject, option: any) => {
 	const abc = {
 		celf: "K:treble",
 		minUnit: "L:1/4",
@@ -302,9 +318,10 @@ export const formateAbc = (visualObj: TuneObject) => {
 		speed: "Q:1/4=60",
 		key: "K:C",
 		visualTranspose: 0,
-		subjectCode: "acoustic_grand_piano",
+		subjectCode: option.subjectCode ?? "acoustic_grand_piano",
 	};
 	const list = [];
+	let notes = [];
 	let measureIndex = 0;
 	for (let i = 0; i < visualObj.lines.length; i++) {
 		const line = visualObj.lines[i];
@@ -323,15 +340,59 @@ export const formateAbc = (visualObj: TuneObject) => {
 					}
 				}
 				if (staff.voices) {
+					let measure = {
+						notes: [] as INote[],
+						barline: "|",
+						repeat: "",
+						measureNumber: measureIndex,
+						celf: "",
+						key: "",
+						meter: "",
+					};
 					for (let k = 0; k < staff.voices.length; k++) {
 						const voice = staff.voices[k];
 						for (let l = 0; l < voice.length; l++) {
 							const element = voice[l];
 							if (element.el_type === "bar") {
 								measureIndex++;
+								list.push(measure);
+								notes = [];
+								measure = {
+									notes: [] as INote[],
+									barline: "|",
+									repeat: "",
+									measureNumber: measureIndex,
+									celf: "",
+									key: "",
+									meter: "",
+								};
 							}
 							if (element.el_type === "note") {
-								list.push(element);
+								// const abcEle = visualObj.getElementFromChar(element.startChar);
+								console.log("🚀 ~ abcEle:", element);
+								let content = ''
+								if (element.rest) {
+									content = 'z';
+								} else {
+									content = element.pitches?.[0]?.name ?? "";
+								}
+								console.log(content)
+								const note = createNote({
+									clef: "", //// 谱号
+									key: "", // 调号
+									speed: "", // 速度
+									slus: "", // 3连音
+									tie: "", // 连音线 前,连音线 后
+									content: content, // 音符
+									noteType: formateGetData.getNoteType(element.duration), // 音符时值
+									play: [],
+									dynamics: "", // 力度符号
+									accidental: "", // 临时升降记号
+									dot: "", //附点
+									tieline: "", // 延音线
+									segno: "", // 分割
+								});
+								measure.notes.push(note);
 							}
 						}
 					}
@@ -339,5 +400,9 @@ export const formateAbc = (visualObj: TuneObject) => {
 			}
 		}
 	}
-	console.log(measureIndex);
+	console.log(measureIndex, list);
+	return {
+		...abc,
+		measures: list,
+	};
 };