瀏覽代碼

Merge branch 'iteration-1.0.1'

liushengqiang 1 年之前
父節點
當前提交
63acbe657f
共有 7 個文件被更改,包括 299 次插入135 次删除
  1. 2 0
      package.json
  2. 59 2
      pnpm-lock.yaml
  3. 0 21
      src/pc/component/keys/index.tsx
  4. 17 3
      src/pc/home/index.module.less
  5. 161 98
      src/pc/home/index.tsx
  6. 41 1
      src/pc/home/noteData.ts
  7. 19 10
      src/pc/home/runtime.ts

+ 2 - 0
package.json

@@ -14,6 +14,8 @@
     "@varlet/ui": "^2.13.4",
     "@vicons/fa": "^0.12.0",
     "@vicons/ionicons5": "^0.12.0",
+    "@vueuse/components": "^10.3.0",
+    "@vueuse/core": "^10.3.0",
     "abcjs": "^6.2.2",
     "clean-deep": "^3.4.0",
     "consola": "^2.15.3",

+ 59 - 2
pnpm-lock.yaml

@@ -19,6 +19,12 @@ dependencies:
   '@vicons/ionicons5':
     specifier: ^0.12.0
     version: 0.12.0
+  '@vueuse/components':
+    specifier: ^10.3.0
+    version: 10.3.0(vue@3.2.47)
+  '@vueuse/core':
+    specifier: ^10.3.0
+    version: 10.3.0(vue@3.2.47)
   abcjs:
     specifier: ^6.2.2
     version: 6.2.2
@@ -119,7 +125,7 @@ devDependencies:
     version: 4.9.3
   unplugin-auto-import:
     specifier: ^0.16.6
-    version: 0.16.6
+    version: 0.16.6(@vueuse/core@10.3.0)
   unplugin-vue-components:
     specifier: ^0.24.1
     version: 0.24.1(vue@3.2.47)
@@ -1853,6 +1859,9 @@ packages:
     resolution: {integrity: sha512-ZPHnXkzmGMfk+pHqAGzTSpA9CbsHmJLgkvOl5w52LZ0XTxB1ZIHWZzQ7lEtjTNWScBbsQekg8TjApMXkMe4nkw==}
     dev: true
 
+  /@types/web-bluetooth@0.0.17:
+    resolution: {integrity: sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==}
+
   /@vant/popperjs@1.3.0:
     resolution: {integrity: sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw==}
     dev: false
@@ -2155,6 +2164,39 @@ packages:
     resolution: {integrity: sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==}
     dev: true
 
+  /@vueuse/components@10.3.0(vue@3.2.47):
+    resolution: {integrity: sha512-EeZz3kjmJI7bH7JSxxMlLyk21LGl6GQjXfpl2n/GiI9QSJi+BVzIra5kEty5eM8McwAanx3e/HnK4drYTgFOWw==}
+    dependencies:
+      '@vueuse/core': 10.3.0(vue@3.2.47)
+      '@vueuse/shared': 10.3.0(vue@3.2.47)
+      vue-demi: 0.14.5(vue@3.2.47)
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+    dev: false
+
+  /@vueuse/core@10.3.0(vue@3.2.47):
+    resolution: {integrity: sha512-BEM5yxcFKb5btFjTSAFjTu5jmwoW66fyV9uJIP4wUXXU8aR5Hl44gndaaXp7dC5HSObmgbnR2RN+Un1p68Mf5Q==}
+    dependencies:
+      '@types/web-bluetooth': 0.0.17
+      '@vueuse/metadata': 10.3.0
+      '@vueuse/shared': 10.3.0(vue@3.2.47)
+      vue-demi: 0.14.5(vue@3.2.47)
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+
+  /@vueuse/metadata@10.3.0:
+    resolution: {integrity: sha512-Ema3YhNOa4swDsV0V7CEY5JXvK19JI/o1szFO1iWxdFg3vhdFtCtSTP26PCvbUpnUtNHBY2wx5y3WDXND5Pvnw==}
+
+  /@vueuse/shared@10.3.0(vue@3.2.47):
+    resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==}
+    dependencies:
+      vue-demi: 0.14.5(vue@3.2.47)
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+
   /abcjs@6.2.2:
     resolution: {integrity: sha512-M5pvTb+0yABqScZBEN/bZmrMgX+iTtgD8vxAVTaKNNVt+ivyCzx0SLNYlTXYErlXu7QvPIoIiSPRojne6M24PA==}
     dev: false
@@ -3703,7 +3745,7 @@ packages:
     engines: {node: '>= 10.0.0'}
     dev: true
 
-  /unplugin-auto-import@0.16.6:
+  /unplugin-auto-import@0.16.6(@vueuse/core@10.3.0):
     resolution: {integrity: sha512-M+YIITkx3C/Hg38hp8HmswP5mShUUyJOzpifv7RTlAbeFlO2Tyw0pwrogSSxnipHDPTtI8VHFBpkYkNKzYSuyA==}
     engines: {node: '>=14'}
     peerDependencies:
@@ -3717,6 +3759,7 @@ packages:
     dependencies:
       '@antfu/utils': 0.7.5
       '@rollup/pluginutils': 5.0.2
+      '@vueuse/core': 10.3.0(vue@3.2.47)
       fast-glob: 3.3.0
       local-pkg: 0.4.3
       magic-string: 0.30.1
@@ -3904,6 +3947,20 @@ packages:
       vue: 3.2.47
     dev: false
 
+  /vue-demi@0.14.5(vue@3.2.47):
+    resolution: {integrity: sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==}
+    engines: {node: '>=12'}
+    hasBin: true
+    requiresBuild: true
+    peerDependencies:
+      '@vue/composition-api': ^1.0.0-rc.1
+      vue: ^3.0.0-0 || ^2.6.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+    dependencies:
+      vue: 3.2.47
+
   /vue-router@4.1.6(vue@3.2.47):
     resolution: {integrity: sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==}
     peerDependencies:

+ 0 - 21
src/pc/component/keys/index.tsx

@@ -30,7 +30,6 @@ export default defineComponent({
 		};
 
 		const keyDown = (e: KeyboardEvent) => {
-			console.log("🚀 ~ e:", e);
 			data.keyDown = e.key.toLocaleUpperCase();
 		};
 		const keyUp = (e: KeyboardEvent) => {
@@ -94,26 +93,6 @@ export default defineComponent({
 									</div>
 								);
 							})}
-							{/* <div
-								class={styles.bkey}
-								onClick={() => {
-									// emit("click", { type: "note", value: item.key + productKey(index - 3) });
-								}}
-							>
-								<div class="keytip"></div>
-							</div>
-							<div class={styles.bkey}>
-								<div class="keytip"></div>
-							</div>
-							<div class={styles.bkey}>
-								<div class="keytip"></div>
-							</div>
-							<div class={styles.bkey}>
-								<div class="keytip"></div>
-							</div>
-							<div class={styles.bkey}>
-								<div class="keytip"></div>
-							</div> */}
 						</div>
 					</div>
 				))}

+ 17 - 3
src/pc/home/index.module.less

@@ -255,13 +255,27 @@
         }
     }
 }
-.titleName{
-    :global{
-        .n-input{
+
+.titleName {
+    :global {
+        .n-input {
             font-size: 18px;
             font-weight: 600;
             height: 40px;
             line-height: 40px;
         }
     }
+}
+
+.selectMearesBox {
+    position: fixed;
+    padding: 12px !important;
+    background: #FFFFFF;
+    box-shadow: 0px 2px 17px 0px rgba(0, 0, 0, 0.08);
+    border-radius: 16px;
+    border: 1px solid #F5F5F7;
+    cursor: move;
+}
+.selectMearesHidden{
+    display: none;
 }

+ 161 - 98
src/pc/home/index.tsx

@@ -25,7 +25,6 @@ import TheIcon from "/src/components/The-icon";
 import { cloneDeep } from "lodash";
 import TheSpeed from "./component/the-speed";
 import { getImage } from "./images";
-import { Dropdown, Dsubmenu, Doption, Trigger, Input, Select, Option } from "@arco-design/web-vue";
 import {
 	NButton,
 	NDropdown,
@@ -50,6 +49,9 @@ import TheSetting from "./component/the-setting";
 import { useRoute } from "vue-router";
 import { api_musicSheetCreationDetail, api_musicSheetCreationUpdate } from "../api";
 import instrumentsNames from "/src/constant/instrmentsNames.json";
+import { ALL_NOTES, NOTE_DOT } from "./noteData";
+import { Close } from "@vicons/ionicons5";
+import { UseDraggable } from "@vueuse/components";
 
 const allPitches = [
 	"C,,,,",
@@ -185,6 +187,7 @@ export default defineComponent({
 			mearseDeleteShow: false,
 			staffShow: false, // 五线谱弹窗
 			settingShow: false, // 设置弹窗
+			selectMearesShow: false, // 选择小节弹窗
 		});
 		const data = reactive({
 			drawCount: 0,
@@ -220,6 +223,11 @@ 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 +290,7 @@ export default defineComponent({
 			// 	abcData.visualObj.engraver.rangeHighlight(abcElem.startChar, abcElem.endChar);
 			// }
 			if (drag && drag.step) {
-				handleMoveNote("drag", drag.step);
+				handleChange({ type: "move", value: { action: "drag", step: drag.step } });
 				return;
 			}
 			if (!abcElem?.midiPitches) return;
@@ -295,6 +303,7 @@ export default defineComponent({
 			midiBuffer: null as unknown as ABCJS.MidiBuffer,
 			abcOptions: {
 				selectionColor: "#0f81ff",
+				jazzchords: true,
 				add_classes: true,
 				clickListener: clickListener,
 				responsive: "resize",
@@ -411,14 +420,24 @@ export default defineComponent({
 			},
 		};
 
-		const resetMidi = (useActive = false) => {
+		const staffNotes = ALL_NOTES();
+		const loadMiniMp3 = async () => {
 			data.loadingAudioSrouce = true;
 			const midiBuffer = new ABCJS.synth.CreateSynth();
-			// console.log(midiBuffer);
+			const str = `X: 1\nM:4/4\nL:1/4\n${staffNotes}`;
+			const visualObj = ABCJS.parseOnly(str);
+			await midiBuffer.init({
+				visualObj: visualObj[0],
+				options: { ...abcData.synthOptions },
+			});
+		};
+
+		const resetMidi = (useActive = false) => {
+			const midiBuffer = new ABCJS.synth.CreateSynth();
 			midiBuffer
 				.init({
 					visualObj: abcData.visualObj,
-					options: { ...abcData.synthOptions, midiTranspose: abcData.abc.visualTranspose },
+					options: { ...abcData.synthOptions },
 				})
 				.then(() => {
 					abcData.synthControl
@@ -456,7 +475,9 @@ export default defineComponent({
 				...abcData.abcOptions,
 				visualTranspose: abcData.abc.visualTranspose,
 			})[0];
-			console.log("🚀 ~ visualObj:", abcData.visualObj);
+			if (data.drawCount < 3) {
+				console.log("🚀 ~ visualObj:", abcData.visualObj);
+			}
 		};
 
 		const renderBoxRect = () => {
@@ -464,6 +485,7 @@ export default defineComponent({
 			const padding = 4;
 			for (let i = 0; i < abcData.visualObj.lines.length; i++) {
 				const line = abcData.visualObj.lines[i];
+				console.log("🚀 ~ line:", line);
 				for (let j = 0; j < line.staff.length; j++) {
 					const staff = line.staff[j];
 					const voices = [...staff.voices].flat();
@@ -489,10 +511,6 @@ export default defineComponent({
 					}
 				}
 			}
-			// const annotation = document.querySelectorAll("#paper .abcjs-annotation");
-			// annotation.forEach((n) => {
-			// 	n.setAttribute("color", "rgba(0,0,0,0)");
-			// })
 		};
 
 		/**
@@ -546,11 +564,15 @@ export default defineComponent({
 		 * @returns
 		 */
 		const handleChange = async (params: { type: string; value: any }) => {
+			abcData.synthControl.disable(true);
+			if (data.playState) {
+				data.playState = false;
+			}
 			const type = params.type;
 			const value = params.value;
 			const activeNote =
 				abcData.abc.measures[data.active?.measureIndex]?.notes[data.active?.noteIndex] || null;
-			console.log(params, activeNote);
+			// console.log(params, activeNote);
 			if (type === "type") {
 				// 设置音符类型
 				data.noteType = value;
@@ -595,59 +617,78 @@ export default defineComponent({
 						if (_values[1]) {
 							activeNote.accidental = _values[1] || "";
 						}
+						data.active.isFirstChecked = false;
+					}
+					await handleResetRender();
+					const oldNote = useIndexGetNote(`${data.active.measureIndex}.${data.active.noteIndex}`);
+					if (oldNote?.abselem?.beam?.elems?.length) {
+						// 判断是否需要分割beam
+						const elems: AbcElem[] = oldNote.abselem.beam.elems;
+						const beatDuration = abcData.visualObj.getBeatLength();
+						const beamLength = elems.map((n) => n.duration).reduce((a, b) => a + b);
+						if (beamLength >= beatDuration) {
+							abcData.abc.measures[data.active.measureIndex].notes[data.active.noteIndex].segno = " ";
+							await handleResetRender();
+						}
+					}
+					if (oldNote?.midiPitches) {
+						ABCJS.synth.playEvent(oldNote.midiPitches, oldNote.midiGraceNotePitches, 1000);
+					}
+					const nextNote =
+						abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex + 1];
+					if (nextNote) {
+						const abcNextElem: AbcElem = useIndexGetNote(
+							`${data.active.measureIndex}.${data.active.noteIndex + 1}`
+						);
+						rangeHighlight(abcNextElem.startChar);
+						data.active = {
+							...abcNextElem,
+							measureIndex: data.active.measureIndex,
+							noteIndex: data.active.noteIndex + 1,
+							isFirstChecked: true,
+						};
 					} else {
 						const notes = getMeasureNotes(data.active.measureIndex);
 						const duration = notes.map((n) => n.duration).reduce((a, b) => a + b);
 						if (duration >= 1) {
-							message.warning("小节内音符总时值过长");
-							return;
-						}
-
-						handleCreateNote(
-							data.active.measureIndex,
-							data.active.noteIndex,
-							createNote({
-								content: _values[0],
-								noteType: data.noteType,
-								accidental: _values[1] || "",
-							})
-						);
-					}
-					await handleResetRender();
-					let _abcElem: AbcElem;
-					if (data.active.isFirstChecked) {
-						data.active.isFirstChecked = false;
-						_abcElem = rangeHighlight(data.active.startChar);
-					} else {
-						const oldElem: AbcElem = abcData.visualObj.getElementFromChar(data.active.startChar);
-						const abcElem: AbcElem = abcData.visualObj.getElementFromChar(oldElem.endChar);
-						if (abcElem) {
-							let indexStr: any = abcElem.chord?.find((n) => n.position === "left")?.name || "";
-							indexStr = indexStr.split(".").map((n: string) => Number(n));
+							// 小节内音符总时值过长,自动跳转到下一小节
+							const nextMeasureNote = abcData.abc.measures[data.active.measureIndex + 1]?.notes[0];
+							if (nextMeasureNote) {
+								const abcNextElem: AbcElem = useIndexGetNote(`${data.active.measureIndex + 1}.${0}`);
+								rangeHighlight(abcNextElem.startChar);
+								data.active = {
+									...abcNextElem,
+									measureIndex: data.active.measureIndex + 1,
+									noteIndex: 0,
+									isFirstChecked: true,
+								};
+							} else {
+								// 到最后一个小节的最后一个音符了
+								rangeHighlight(data.active.startChar);
+								data.active.isFirstChecked = true;
+							}
+						} else {
+							handleCreateNote(
+								data.active.measureIndex,
+								data.active.noteIndex,
+								createNote({
+									content: "z",
+									noteType: data.noteType,
+								})
+							);
+							await handleResetRender();
+							const newNote = useIndexGetNote(
+								`${data.active.measureIndex}.${data.active.noteIndex + 1}`
+							);
+							rangeHighlight(newNote.startChar);
 							data.active = {
-								...abcElem,
-								measureIndex: indexStr[0],
-								noteIndex: indexStr[1],
-								isFirstChecked: false,
+								...newNote,
+								measureIndex: data.active.measureIndex,
+								noteIndex: data.active.noteIndex + 1,
+								isFirstChecked: true,
 							};
-							const beam = (abcElem.abselem as any).beam;
-							if (beam) {
-								const elems: AbcElem[] = beam.elems;
-								if (elems.length) {
-									const beatDuration = abcData.visualObj.getBeatLength();
-									const beamLength = elems.map((n) => n.duration).reduce((a, b) => a + b);
-									if (beamLength >= beatDuration) {
-										abcData.abc.measures[data.active.measureIndex].notes[data.active.noteIndex].segno =
-											" ";
-										await handleResetRender();
-									}
-								}
-							}
 						}
-						_abcElem = rangeHighlight(abcElem.startChar);
 					}
-					if (!_abcElem?.midiPitches) return;
-					ABCJS.synth.playEvent(_abcElem.midiPitches, _abcElem.midiGraceNotePitches, 1000);
 				}
 			}
 
@@ -705,6 +746,8 @@ export default defineComponent({
 					if (!activeNote) return;
 					activeNote.meter = `[${value}]`;
 					await handleResetRender();
+					const oldNote = useIndexGetNote(`${data.active.measureIndex}.${data.active.noteIndex}`);
+					rangeHighlight(oldNote.startChar);
 				} else {
 					abcData.abc.meter = value;
 					await handleResetRender();
@@ -870,10 +913,9 @@ export default defineComponent({
 					showToast("请先选择音符");
 					return;
 				}
-				const activeNote =
-					abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
 				if (!activeNote) return;
 				activeNote.dot = activeNote.dot ? "" : value;
+				// activeNote.dot = activeNote.dot ? "" : NOTE_DOT[activeNote.noteType];
 				await handleResetRender();
 				rangeHighlight(data.active.startChar);
 			}
@@ -887,6 +929,19 @@ export default defineComponent({
 				await handleResetRender();
 				rangeHighlight(data.active.startChar);
 			}
+
+			// 移动音符
+			if (type === "move") {
+				const step = value._step ? value._step : value.action === "up" ? -1 : 1;
+				if (!activeNote) return;
+				activeNote.content = moveNote(activeNote.content, step);
+				// arr now contains elements that are either a chord, a decoration, a note name, or anything else. It can be put back to its original string with .join("").
+
+				await handleResetRender();
+				const _abcElem = rangeHighlight(data.active.startChar);
+				if (!_abcElem?.midiPitches) return;
+				ABCJS.synth.playEvent(_abcElem.midiPitches, _abcElem.midiGraceNotePitches, 1000);
+			}
 		};
 
 		const getNextNote = (index: number): AbcElem => {
@@ -1007,27 +1062,6 @@ export default defineComponent({
 			await handleResetRender();
 		};
 
-		/**
-		 * 移动音符
-		 * @param note 音符
-		 * @param step 移动步数
-		 */
-		const handleMoveNote = async (type: "up" | "donw" | "drag", _step?: number) => {
-			if (!data.active) return;
-			const step = _step ? _step : type === "up" ? -1 : 1;
-			const activeNote =
-				abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
-			if (!activeNote) return;
-			activeNote.content = moveNote(activeNote.content, step);
-			// arr now contains elements that are either a chord, a decoration, a note name, or anything else. It can be put back to its original string with .join("").
-
-			await handleResetRender();
-			const _abcElem = rangeHighlight(data.active.startChar);
-			if (!_abcElem?.midiPitches) return;
-			console.log(_abcElem, abcData.visualObj.millisecondsPerMeasure());
-			ABCJS.synth.playEvent(_abcElem.midiPitches, _abcElem.midiGraceNotePitches, 1000);
-		};
-
 		const handleKeyUp = (e: KeyboardEvent) => {
 			if (!data.active) return false;
 			console.log(e.key);
@@ -1038,7 +1072,7 @@ export default defineComponent({
 			if (["ArrowUp", "ArrowDown"].includes(e.key)) {
 				e.preventDefault();
 				e.stopPropagation();
-				handleMoveNote(e.key === "ArrowUp" ? "up" : "donw");
+				handleChange({ type: "move", value: { action: e.key === "ArrowUp" ? "up" : "donw" } });
 				return false;
 			}
 		};
@@ -1079,7 +1113,7 @@ export default defineComponent({
 					const _instruments = ABCJS.synth.instrumentIndexToName.indexOf(abcData.abc.subjectCode as any);
 					abcData.synthOptions.program = _instruments > -1 ? _instruments : 0;
 					abcData.abc.measures = abc.measures || initMusic(30);
-					console.log("🚀 ~ abcData.abc:", abcData.abc);
+					// console.log("🚀 ~ abcData.abc:", abcData.abc);
 				}
 			}
 		};
@@ -1097,8 +1131,10 @@ export default defineComponent({
 		};
 		onMounted(async () => {
 			await getDetailData();
+			loadMiniMp3();
 			if (ABCJS.synth.supportsAudio()) {
 				abcData.synthControl = new ABCJS.synth.SynthController();
+				// console.log("🚀 ~ abcData.synthControl:", abcData.synthControl)
 				abcData.synthControl.load("#audio", cursorControl, {
 					displayLoop: true,
 					displayRestart: true,
@@ -1116,8 +1152,8 @@ export default defineComponent({
 					e.returnValue = "还有没保存的";
 				}
 			};
-
-			formateAbc(abcData.visualObj);
+			abcData.synthControl.restart();
+			// formateAbc(abcData.visualObj);
 		});
 		onUnmounted(() => {
 			document.removeEventListener("keyup", handleKeyUp);
@@ -1474,9 +1510,10 @@ export default defineComponent({
 											filterable
 											options={instruments.value}
 											v-model:value={abcData.synthOptions.program}
-											onUpdate:value={() => {
+											onUpdate:value={async () => {
 												abcData.synthControl.disable(true);
 												data.playState = false;
+												await loadMiniMp3();
 												resetMidi(true);
 												popup.selectSubjectShow = false;
 											}}
@@ -1826,12 +1863,16 @@ export default defineComponent({
 							</NSpin>
 							<div>{data.playState ? "暂停" : "播放"}</div>
 						</div>
-						<div class={[styles.topBtn, styles.btnDisabled]}>
-							<div class={styles.btnImg}>
+						<div
+							class={[styles.topBtn]}
+							onClick={() => (popup.selectMearesShow = !popup.selectMearesShow)}
+						>
+							<div class={[styles.btnImg, popup.selectMearesShow && styles.btnImgActive]}>
 								<img class={styles.topBtnIcon} src={getImage("icon_22.png")} />
 							</div>
 							<div>选段</div>
 						</div>
+
 						<div class={[styles.topBtn, styles.btnDisabled]}>
 							<div class={styles.btnImg}>
 								<img class={styles.topBtnIcon} src={getImage("icon_23.png")} />
@@ -2044,18 +2085,7 @@ export default defineComponent({
 						<div id="paper"></div>
 						<Keys show={data.active ? true : false} onClick={(val) => handleChange(val)} />
 
-						{/* <div>
-							<textarea
-								ref={textAreaRef}
-								class={styles.value}
-								id="abc"
-								onChange={() => {
-									console.log(textAreaRef.value.value);
-									data.music = textAreaRef.value.value;
-									handleResetRender();
-								}}
-							></textarea>
-						</div> */}
+						{/* <textarea ref={textAreaRef} class={styles.value} id="abc"></textarea> */}
 						<div id="audio" style={{ opacity: 0 }}></div>
 						<div id="warnings"></div>
 
@@ -2068,6 +2098,39 @@ export default defineComponent({
 				<div ref={downRef}></div>
 
 				<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> */}
 			</div>
 		);
 	},

+ 41 - 1
src/pc/home/noteData.ts

@@ -1,5 +1,35 @@
+export const ALL_NOTES = () => {
+	const keys = ["C", "^C", "D", "^D", "E", "F", "^F", "G", "^G", "A", "^A", "B"];
+	const notes = [];
+	const productKey = (total = 0) => {
+		if (total === 0) return "";
+		return new Array(Math.abs(total)).fill(total > 0 ? "'" : ",").join("");
+	};
+	for (let i = 0; i <= 6; i++) {
+		for (let j = 0; j < 12; j++) {
+			let note = keys[j];
+			if (i < 3) {
+				notes.push(note + productKey(i - 3));
+			} else if (i === 3) {
+				notes.push(note);
+			} else if (i === 4) {
+				note = note.toLocaleLowerCase();
+				notes.push(note);
+			} else {
+				note = note.toLocaleLowerCase();
+				notes.push(note + productKey(i - 4));
+			}
+		}
+	}
+	let str = "";
+	notes.forEach((note, index) => {
+		str += note + (index % 4 === 0 ? " |" : " ");
+	});
+	// console.log(notes);
+	return str;
+};
 export const ABC_NOTE_DATA = [
-	["^B,,,,,", "C,,,,"],
+	"C,,,,",
 	["^C,,,,", "_D,,,,"],
 	"D,,,,",
 	["^D,,,,", "_E,,,,"],
@@ -356,3 +386,13 @@ export const ABC_KEYS: { [_: string]: any } = {
 		"K:B": { up: 0, down: 0, move: 0 },
 	},
 };
+
+/** 附点音符 */
+export const NOTE_DOT: { [_: string]: string } = {
+	"4": "3",
+	"2": "3",
+	"": "3/2",
+	"/": "2/3",
+	"//": "1/3",
+	"///": "3/8",
+};

+ 19 - 10
src/pc/home/runtime.ts

@@ -213,8 +213,16 @@ export const renderMeasures = (abc: IAbc) => {
 			text += note.dynamics; // 力度符号
 			text += note.accidental; // 临时升降记号
 			text += note.content; // 音符
-			text += note.noteType; // 音符类型
-			text += note.dot; // 附点
+			// 音符时值
+			text += note.noteType;
+			text += note.dot;
+			
+			// if(note.dot){
+			// 	text += note.dot; // 附点
+			// } else {
+			// 	text += note.noteType; // 音符类型
+			// }
+
 			text += note.tieline; // 延音
 			if (note.tie.includes(")")) {
 				// 连音线 后
@@ -222,8 +230,9 @@ export const renderMeasures = (abc: IAbc) => {
 			}
 			text += note.segno; // 分割
 		}
+		let _i = i + 1;
+		// text += `${_i % 4 !== 0 ? `"${i + 1}"` : ""}${i === measures.length - 1 ? '|]' : measure.barline}`;
 		text += measure.barline;
-		// text += `"${i}"` + measure.barline;
 		if (i > 0 && i % 4 === 0) {
 			text += "\n";
 		}
@@ -286,14 +295,14 @@ export const formateAbc = (visualObj: TuneObject) => {
 		if (line.staff) {
 			for (let j = 0; j < line.staff.length; j++) {
 				const staff = line.staff[j];
-				if (i === 0){
-					if (staff.clef){
+				if (i === 0) {
+					if (staff.clef) {
 						abc.celf = `K:${staff.clef.type}`;
 					}
-					if (staff.key){
+					if (staff.key) {
 						abc.key = `K:${staff.key.root}${staff.key.acc}`;
 					}
-					if (staff.meter?.value?.[0]){
+					if (staff.meter?.value?.[0]) {
 						abc.meter = `M:${staff.meter.value[0].num}/${staff.meter.value[0].den}`;
 					}
 				}
@@ -302,8 +311,8 @@ export const formateAbc = (visualObj: TuneObject) => {
 						const voice = staff.voices[k];
 						for (let l = 0; l < voice.length; l++) {
 							const element = voice[l];
-							if (element.el_type === "bar"){
-								measureIndex++
+							if (element.el_type === "bar") {
+								measureIndex++;
 							}
 							if (element.el_type === "note") {
 								list.push(element);
@@ -314,5 +323,5 @@ export const formateAbc = (visualObj: TuneObject) => {
 			}
 		}
 	}
-	console.log(measureIndex)
+	console.log(measureIndex);
 };