liushengqiang před 1 rokem
rodič
revize
5df3106176

+ 5 - 2
src/pc/component/keys/index.tsx

@@ -55,7 +55,10 @@ export default defineComponent({
 									key={index}
 									onClick={() => {
 										let key = index > 3 ? item.key.toLocaleLowerCase() : item.key;
-										emit("click", { type: "note", value: key + productKey(index - 3) });
+										emit("click", {
+											type: "note",
+											value: key + productKey([3, 4].includes(index) ? 0 : index - 3),
+										});
 									}}
 								>
 									<div class={styles.keytip}>
@@ -83,7 +86,7 @@ export default defineComponent({
 											let key = index > 3 ? item.key.toLocaleLowerCase() : item.key;
 											emit("click", {
 												type: "note",
-												value: key + productKey(index - 3) + "-" + "^",
+												value: key + productKey([3, 4].includes(index) ? 0 : index - 3) + "-" + "^",
 											});
 										}}
 									>

+ 0 - 6
src/pc/component/notes/index.module.less

@@ -1,6 +0,0 @@
-.noteTypes{
-    display: flex;
-    & > div {
-        margin: 0 10px;
-    }
-}

+ 0 - 78
src/pc/component/notes/index.tsx

@@ -1,78 +0,0 @@
-import { defineComponent, reactive } from "vue";
-import styles from "./index.module.less";
-import { Checkbox, CheckboxGroup, Radio, RadioGroup } from "vant";
-import { ABC_DATA } from "../../home/runtime";
-
-
-export default defineComponent({
-	name: "Notes",
-	emits: ["change"],
-	setup(props, { emit }) {
-		const data = reactive({
-			type: "",
-			clef: "[K:treble]",
-			key: "C",
-			meter: "4/4",
-		});
-		return () => (
-			<div>
-				<RadioGroup
-					v-model={data.type}
-					class={styles.noteTypes}
-					onChange={() => {
-						emit("change", { type: "type", value: data.type });
-					}}
-				>
-					{ABC_DATA.types.map((item) => {
-						return <Radio name={item.value}>{item.name}</Radio>;
-					})}
-				</RadioGroup>
-				<div>
-					<div>临时升降记号</div>
-					{ABC_DATA.accidentals.map((item) => (
-						<button onClick={() => emit("change", { type: "accidentals", value: item.value })}>
-							{item.name}
-						</button>
-					))}
-					<div>谱号</div>
-					{ABC_DATA.clef.map((item) => (
-						<button onClick={() => emit("change", { type: "clef", value: item.value })}>
-							{item.name}
-						</button>
-					))}
-					<div>调号</div>
-					{ABC_DATA.key.map((item) => (
-						<button onClick={() => emit("change", { type: "key", value: item.value })}>
-							{item.name}
-						</button>
-					))}
-					<div>拍号</div>
-					{ABC_DATA.meter.map((item) => (
-						<button onClick={() => emit("change", { type: "meter", value: item.value })}>
-							{item.name}
-						</button>
-					))}
-					<div>演奏技法</div>
-					{ABC_DATA.play.map((item) => (
-						<button onClick={() => emit("change", { type: "play", value: item.value })}>
-							{item.name}
-						</button>
-					))}
-
-					<div>连线</div>
-					{ABC_DATA.tie.map((item) => (
-						<button onClick={() => emit("change", { type: "tie", value: item.value })}>
-							{item.name}
-						</button>
-					))}
-					<div>力度记号</div>
-					{ABC_DATA.dynamics.map((item) => (
-						<button onClick={() => emit("change", { type: "dynamics", value: item.value })}>
-							{item.name}
-						</button>
-					))}
-				</div>
-			</div>
-		);
-	},
-});

+ 26 - 20
src/pc/home/component/file-btn/index.tsx

@@ -5,7 +5,7 @@ import { getImage } from "../../images";
 import { DropdownMixedOption } from "naive-ui/es/dropdown/src/interface";
 
 /** 新建 | 保存 | 导入 | 上传 | 导出 | 打印 */
-export type IFileBtnType = 'newMusic' | 'save' | 'xml' | 'upload' | 'png' | 'wav' | 'midi' | 'print'
+export type IFileBtnType = "newMusic" | "save" | "xml" | "upload" | "png" | "wav" | "midi" | "print";
 
 export default defineComponent({
 	name: "FileBtn",
@@ -13,34 +13,40 @@ export default defineComponent({
 	setup(props, { emit }) {
 		const options: DropdownMixedOption[] = [
 			{
-				label: "新建曲谱",
-				key: "newMusic",
-			},
-			{
 				label: () => (
 					<div class={styles.dropItem}>
-						<img class={styles.dropIcon} src={getImage("icon_26_0.png")} />
-						<span>保存</span>
+						<img class={styles.dropIcon} src={getImage("icon_26_4.png")} />
+						<span>新建曲谱</span>
 					</div>
 				),
-				key: "save",
+				key: "newMusic",
 			},
 			{
 				label: () => (
 					<div class={styles.dropItem}>
 						<img class={styles.dropIcon} src={getImage("icon_26_0.png")} />
-						<span>导入</span>
+						<span>保存</span>
 					</div>
 				),
-				key: "import",
-				children: [
-					{
-						label: "xml",
-                        key: 'xml',
-						disabled: true
-					},
-				],
+				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}>
@@ -49,7 +55,7 @@ export default defineComponent({
 					</div>
 				),
 				key: "upload",
-				disabled: true
+				disabled: true,
 			},
 			{
 				label: () => (
@@ -82,7 +88,7 @@ export default defineComponent({
 					</div>
 				),
 				key: "print",
-				disabled: true
+				disabled: true,
 			},
 		];
 		return () => (
@@ -92,7 +98,7 @@ export default defineComponent({
 				trigger="click"
 				onSelect={(val) => {
 					console.log("🚀 ~ val:", val);
-                    emit("select", val);
+					emit("select", val);
 				}}
 			>
 				<div class={styles.btnImg}>

binární
src/pc/home/images/icon_26_4.png


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

@@ -223,6 +223,7 @@
     flex-direction: column;
     justify-content: center;
     align-items: center;
+    
 
     .btnItemIcon {
         display: flex;
@@ -242,4 +243,10 @@
     .btnItemName {
         font-size: 12px;
     }
+
+    &.btnItemActive{
+        .btnItemIcon{
+            background-color: rgba(193, 219, 251, 1);
+        }
+    }
 }

+ 100 - 93
src/pc/home/index.tsx

@@ -8,9 +8,9 @@ import ABCJS, {
 } from "abcjs";
 import "ABCJS/ABCJS-audio.css";
 import styles from "./index.module.less";
-import { showConfirmDialog } from "vant";
+import { showConfirmDialog, showToast } from "vant";
 import Keys from "../component/keys";
-import { Collapse, CollapseItem, Snackbar } from "@varlet/ui";
+import { Collapse, CollapseItem } from "@varlet/ui";
 import { IAbc, IMeasure, INote, INoteActive } from "../types";
 import { ABC_DATA, createMeasure, createNote, renderMeasures } from "./runtime";
 import TheIcon from "/src/components/The-icon";
@@ -34,7 +34,7 @@ import {
 	NSpin,
 	useMessage,
 } from "naive-ui";
-import { LongArrowAltDown, LongArrowAltUp } from "@vicons/fa";
+import { LongArrowAltDown, LongArrowAltUp, GripLinesVertical } from "@vicons/fa";
 import { svg2canvas } from "/src/utils/svg2canvas";
 import { downloadFile } from "/src/utils";
 import FileBtn, { IFileBtnType } from "./component/file-btn";
@@ -206,6 +206,8 @@ export default defineComponent({
 
 			deleteMearseType: "ing" as "ing" | "finish", // 删除小节类型
 			loadingAudioSrouce: false, // 加载音频资源
+			/** 移调类型 */
+			moveKeyType: "inset" as "inset" | "up" | "down", // 移调类型
 		});
 		const noteTypes = ABC_DATA.types.map((item) => item.value).filter(Boolean);
 		const accidentals = ABC_DATA.accidentals.map((item) => item.value).filter(Boolean);
@@ -240,7 +242,7 @@ export default defineComponent({
 			if (data.select.state) {
 				data.select.list.push(active);
 				if (data.select.list.length === 1) {
-					Snackbar("请先选择结束音符");
+					showToast("请先选择结束音符");
 				}
 				if (data.select.list.length === 2) {
 					data.select.list = data.select.list.sort((a, b) => a.startChar - b.startChar);
@@ -294,6 +296,8 @@ export default defineComponent({
 				meter: "M:4/4",
 				speed: "Q:1/4=60",
 				key: "K:C",
+				visualTranspose: 0,
+				transposeKey: "K:C",
 				measures: initMusic(30),
 			} as IAbc,
 		});
@@ -399,14 +403,14 @@ export default defineComponent({
 			});
 
 			const midiBuffer = new ABCJS.synth.CreateSynth();
-			console.log(midiBuffer);
+			// console.log(midiBuffer);
 			midiBuffer.init({
 				visualObj: abcData.visualObj,
-				options: abcData.synthOptions,
+				options: { ...abcData.synthOptions, midiTranspose: abcData.abc.visualTranspose },
 			});
 			abcData.synthControl
 				.setTune(abcData.visualObj, false, {
-					midiTranspose: abcData.abcOptions.visualTranspose,
+					midiTranspose: abcData.abc.visualTranspose,
 					...abcData.synthOptions,
 				})
 				.then(function (response) {
@@ -444,7 +448,10 @@ export default defineComponent({
 		};
 
 		const renderSvg = () => {
-			abcData.visualObj = ABCJS.renderAbc("paper", data.music, abcData.abcOptions)[0];
+			abcData.visualObj = ABCJS.renderAbc("paper", data.music, {
+				...abcData.abcOptions,
+				visualTranspose: abcData.abc.visualTranspose,
+			})[0];
 			console.log("🚀 ~ visualObj:", abcData.visualObj);
 		};
 
@@ -490,11 +497,12 @@ export default defineComponent({
 		const handleResetRender = (isProduct = true) => {
 			return new Promise((resolve) => {
 				nextTick(() => {
-					textAreaRef.value.value = data.music = isProduct ? renderMeasures(abcData.abc) : data.music;
+					data.music = isProduct ? renderMeasures(abcData.abc) : data.music;
 					renderSvg();
 					resetMidi();
 					renderBoxRect();
 					resolve(1);
+					textAreaRef.value && (textAreaRef.value.value = data.music);
 				});
 			});
 		};
@@ -549,7 +557,7 @@ export default defineComponent({
 						abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
 					// console.log(activeNote, data.active.isFirstChecked);
 					const _values = value.split("-");
-					console.log("🚀 ~ _value:", _values);
+					// console.log("🚀 ~ _value:", _values);
 					if (data.active.isFirstChecked) {
 						activeNote.content = _values[0];
 						activeNote.noteType = data.noteType;
@@ -607,18 +615,13 @@ export default defineComponent({
 			// 临时升降记号
 			if (type === "accidentals") {
 				if (!data.active) {
-					Snackbar({
-						content: "请先选择音符",
-						position: "top",
-					});
+					showToast("请先选择音符");
 					return;
 				}
 				const activeNote =
 					abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
 				if (activeNote.content === "z") {
-					Snackbar({
-						content: "休止符无法添加临时升降记号",
-					});
+					showToast("休止符无法添加临时升降记号");
 					return;
 				}
 				activeNote.accidental = activeNote.accidental == value ? "" : value;
@@ -680,9 +683,7 @@ export default defineComponent({
 			//  演奏技法
 			if (type === "play") {
 				if (!data.active) {
-					Snackbar({
-						content: "请先选择音符",
-					});
+					showToast("请先选择音符");
 					return;
 				}
 				const activeNote =
@@ -704,16 +705,11 @@ export default defineComponent({
 					data.select.list = [];
 					data.select.state = true;
 					data.select.parmas = params;
-					Snackbar({
-						content: "请先选择开始音符",
-						position: "top",
-					});
+					showToast("请先选择开始音符");
 					return;
 				}
 				if (!data.active) {
-					Snackbar({
-						content: "请先选择音符",
-					});
+					showToast("请先选择音符");
 					return;
 				}
 
@@ -737,15 +733,11 @@ export default defineComponent({
 					data.select.list = [];
 					data.select.state = true;
 					data.select.parmas = params;
-					Snackbar({
-						content: "请先选择开始音符",
-					});
+					showToast("请先选择开始音符");
 					return;
 				}
 				if (!data.active) {
-					Snackbar({
-						content: "请先选择音符",
-					});
+					showToast("请先选择音符");
 					return;
 				}
 
@@ -819,9 +811,7 @@ export default defineComponent({
 			//  附点
 			if (type === "dot") {
 				if (!data.active) {
-					Snackbar({
-						content: "请先选择音符",
-					});
+					showToast("请先选择音符");
 					return;
 				}
 				const activeNote =
@@ -904,10 +894,16 @@ export default defineComponent({
 		};
 
 		/** 移调 */
-		const handleMoveKey = (step: number) => {
-			console.log("移调", step);
-			const oldStep = abcData.abcOptions.visualTranspose || 0;
-			abcData.abcOptions.visualTranspose = oldStep + step;
+		const handleMoveKey = (item: (typeof ABC_DATA.key)[0]) => {
+			if (data.moveKeyType === "down") {
+				abcData.abc.visualTranspose = item.step < 0 ? item.step : item.step - 12;
+			} else if (data.moveKeyType === "up") {
+				abcData.abc.visualTranspose = item.step >= 0 ? item.step : item.step + 12;
+			} else {
+				abcData.abc.visualTranspose = item.step;
+			}
+			// console.log(abcData.abc.visualTranspose, item.step, item.value)
+			abcData.abc.transposeKey = item.value;
 			popup.moveKeyShow = false;
 			handleResetRender();
 		};
@@ -934,14 +930,13 @@ export default defineComponent({
 		};
 
 		const handleKeyUp = (e: KeyboardEvent) => {
-			if (e.key === "Backspace") handleDeleteNote();
-
 			if (!data.active) return false;
+			console.log(e.key);
+			if (e.key === "Backspace") handleDeleteNote();
 			if (/^[A-Ga-g]$/.test(e.key)) {
 				handleChange({ type: "note", value: e.key.toLocaleUpperCase() });
 			}
 			if (["ArrowUp", "ArrowDown"].includes(e.key)) {
-				console.log(e.key);
 				e.preventDefault();
 				e.stopPropagation();
 				handleMoveNote(e.key === "ArrowUp" ? "up" : "donw");
@@ -971,18 +966,13 @@ export default defineComponent({
 				}
 				if (abc) {
 					console.log("🚀 ~ abc:", abc);
-					if (abc.celf) {
-						abcData.abc.celf = abc.celf;
-					}
-					if (abc.key?.value) {
-						abcData.abc.key = abc.key.value;
-					}
-					if (abc.meter?.value) {
-						abcData.abc.meter = abc.meter.value;
-					}
-					if (abc.speed) {
-						abcData.abc.speed = abc.speed;
-					}
+
+					abcData.abc.celf = abc.celf || "K:treble";
+					abcData.abc.key = abc.key.value || "K:C";
+					abcData.abc.meter = abc.meter.value || "M:4/4";
+					abcData.abc.speed = abc.speed || "Q:1/4=60";
+					abcData.abc.visualTranspose = abc.visualTranspose || 0;
+					abcData.abc.transposeKey = abc.transposeKey || "K:C";
 					abcData.abc.measures = abc.measures || initMusic(30);
 					console.log("🚀 ~ abcData.abc:", abcData.abc);
 				}
@@ -1003,7 +993,6 @@ export default defineComponent({
 			await getDetailData();
 			console.log(ABCJS);
 			await handleResetRender();
-			console.log(ABCJS.extractMeasures(data.music));
 			document.addEventListener("keyup", handleKeyUp);
 			window.onbeforeunload = (e) => {
 				if (!data.isSave) {
@@ -1260,38 +1249,38 @@ export default defineComponent({
 							</div>
 						))}
 
-						<Trigger trigger="click">
+						<NPopover trigger="click" contentStyle={{ width: "400px" }}>
 							{{
-								default: () => (
+								trigger: () => (
 									<div class={styles.topDownArrow}>
 										<img src={getImage("icon_arrow.png")} />
 									</div>
 								),
-								content: () => (
-									<div class={[styles.wrapBox, styles.dropDownWrap]}>
+								default: () => (
+									<NGrid cols={4} yGap={8}>
 										{ABC_DATA.play.slice(4).map((item) => (
-											<div
-												class={[styles.topBtn]}
-												onClick={() => {
-													data.morePlay = false;
-													handleChange({ type: "play", value: item.value });
-												}}
-											>
+											<NGi>
 												<div
 													class={[
-														styles.btnImg,
-														noteComputed.value.play?.includes(item.value) && styles.btnImgActive,
+														styles.btnItem,
+														noteComputed.value.play?.includes(item.value) && styles.btnItemActive,
 													]}
+													onClick={() => {
+														data.morePlay = false;
+														handleChange({ type: "play", value: item.value });
+													}}
 												>
-													<TheIcon iconClassName={item.icon} />
+													<div class={styles.btnItemIcon}>
+														<TheIcon iconClassName={item.icon} />
+													</div>
+													<div>{item.name}</div>
 												</div>
-												<div>{item.name}</div>
-											</div>
+											</NGi>
 										))}
-									</div>
+									</NGrid>
 								),
 							}}
-						</Trigger>
+						</NPopover>
 
 						<div class={styles.topLine}></div>
 
@@ -1372,11 +1361,27 @@ export default defineComponent({
 										<div class={styles.btnLineTitle}>移调方式</div>
 
 										<NSpace>
-											<NButton secondary onClick={() => handleMoveKey(-1)}>
+											<NButton
+												secondary
+												type={data.moveKeyType === "inset" ? "primary" : "default"}
+												onClick={() => (data.moveKeyType = "inset")}
+											>
+												<NIcon component={GripLinesVertical} />
+												最靠近
+											</NButton>
+											<NButton
+												secondary
+												type={data.moveKeyType === "down" ? "primary" : "default"}
+												onClick={() => (data.moveKeyType = "down")}
+											>
 												<NIcon component={LongArrowAltDown} />
 												向下移调
 											</NButton>
-											<NButton secondary onClick={() => handleMoveKey(1)}>
+											<NButton
+												secondary
+												type={data.moveKeyType === "up" ? "primary" : "default"}
+												onClick={() => (data.moveKeyType = "up")}
+											>
 												<NIcon component={LongArrowAltUp} />
 												向上移调
 											</NButton>
@@ -1385,19 +1390,24 @@ export default defineComponent({
 										<div class={styles.btnLineTitle}>目标音调</div>
 
 										<NGrid cols={5} yGap={8}>
-											{ABC_DATA.key.map((item) => (
-												<NGi>
-													<div
-														class={styles.btnItem}
-														onClick={() => handleChange({ type: "key", value: item.value })}
-													>
-														<div class={[styles.btnItemIcon]}>
-															<TheIcon iconClassName={item.icon} />
+											{ABC_DATA.key
+												.sort((a, b) => b.step - a.step)
+												.map((item) => (
+													<NGi>
+														<div
+															class={[
+																styles.btnItem,
+																abcData.abc.transposeKey === item.value && styles.btnItemActive,
+															]}
+															onClick={() => handleMoveKey(item)}
+														>
+															<div class={[styles.btnItemIcon]}>
+																<TheIcon iconClassName={item.icon} />
+															</div>
+															<div class={styles.btnItemName}>{item.name}</div>
 														</div>
-														<div class={styles.btnItemName}>{item.name}</div>
-													</div>
-												</NGi>
-											))}
+													</NGi>
+												))}
 										</NGrid>
 									</>
 								),
@@ -1822,11 +1832,8 @@ export default defineComponent({
 						</div>
 						<div id="paper"></div>
 						<Keys show={data.active ? true : false} onClick={(val) => handleChange(val)} />
-						{/* <div>
-							<button onClick={handleCreateSvg}>重置曲谱</button>
-						</div> */}
 
-						<div style={{ display: "none" }}>
+						{/* <div>
 							<textarea
 								ref={textAreaRef}
 								class={styles.value}
@@ -1837,7 +1844,7 @@ export default defineComponent({
 									handleResetRender();
 								}}
 							></textarea>
-						</div>
+						</div> */}
 						<div id="audio" style={{ opacity: 0 }}></div>
 						<div id="warnings"></div>
 

+ 22 - 23
src/pc/home/runtime.ts

@@ -32,21 +32,21 @@ export const ABC_DATA = {
 	],
 	/** 调号 */
 	key: [
-		{ name: "C大调", value: "K:C", icon: "icon-a-diaohao-cdadiaoaxiaodiao1" },
-		{ name: "G大调", value: "K:G", icon: "icon-a-diaohao-Gdadiaoexiaodiao" },
-		{ name: "D大调", value: "K:D", icon: "icon-a-diaohao-Ddaxiaoexiaodiao" },
-		{ name: "A大调", value: "K:A", icon: "icon-a-diaohao-Adadiaofxiaodiao" },
-		{ name: "E大调", value: "K:E", icon: "icon-a-diaohao-edadiaocxiaodiao" },
-		{ name: "B大调", value: "K:B", icon: "icon-a-diaohao-bdadiaogxiaodiao" },
-		{ name: "F#大调", value: "K:F#", icon: "icon-a-diaohao-fdadiaodxiaodiao" },
-		{ name: "C#大调", value: "K:C#", icon: "icon-a-diaohao-cdadiaoaxiaodiao" },
-		{ name: "F大调", value: "K:F", icon: "icon-a-diaohao-fdadiaodxiaodiao1" },
-		{ name: "Bb大调", value: "K:Bb", icon: "icon-a-diaohao-bbdadiaogxiaodiao" },
-		{ name: "Eb大调", value: "K:Eb", icon: "icon-a-diaohao-ebdadiaocxiaodiao" },
-		{ name: "Ab大调", value: "K:Ab", icon: "icon-a-diaohao-abdadiaofxiaodiao" },
-		{ name: "Db大调", value: "K:Db", icon: "icon-a-diaohao-dbdadiaobbxiaodiao" },
-		{ name: "Gb大调", value: "K:Gb", icon: "icon-a-diaohao-gbdadiaoebxiaodiao" },
-		{ name: "Cb大调", value: "K:Cb", icon: "icon-a-diaohao-cbdadiaoabxiaodiao" },
+		{ name: "F#大调", value: "K:F#", step: 6, icon: "icon-a-diaohao-fdadiaodxiaodiao" },
+		{ name: "F大调", value: "K:F", step: 5, icon: "icon-a-diaohao-fdadiaodxiaodiao1" },
+		{ name: "E大调", value: "K:E", step: 4, icon: "icon-a-diaohao-edadiaocxiaodiao" },
+		{ name: "Eb大调", value: "K:Eb", step: 3, icon: "icon-a-diaohao-ebdadiaocxiaodiao" },
+		{ name: "D大调", value: "K:D", step: 2, icon: "icon-a-diaohao-Ddaxiaoexiaodiao" },
+		{ name: "C#大调", value: "K:C#", step: 1, icon: "icon-a-diaohao-cdadiaoaxiaodiao" },
+		{ name: "C大调", value: "K:C", step: 0, icon: "icon-a-diaohao-cdadiaoaxiaodiao1" },
+		{ name: "B大调", value: "K:B", step: -1, icon: "icon-a-diaohao-bdadiaogxiaodiao" },
+		{ name: "Cb大调", value: "K:Cb", step: -1, icon: "icon-a-diaohao-cbdadiaoabxiaodiao" },
+		{ name: "Db大调", value: "K:Db", step: -1, icon: "icon-a-diaohao-dbdadiaobbxiaodiao" },
+		{ name: "Bb大调", value: "K:Bb", step: -2, icon: "icon-a-diaohao-bbdadiaogxiaodiao" },
+		{ name: "A大调", value: "K:A", step: -3, icon: "icon-a-diaohao-Adadiaofxiaodiao" },
+		{ name: "Ab大调", value: "K:Ab", step: -4, icon: "icon-a-diaohao-abdadiaofxiaodiao" },
+		{ name: "G大调", value: "K:G", step: -5, icon: "icon-a-diaohao-Gdadiaoexiaodiao" },
+		{ name: "Gb大调", value: "K:Gb", step: -6, icon: "icon-a-diaohao-gbdadiaoebxiaodiao" },
 	],
 	/** 拍号 */
 	meter: [
@@ -124,11 +124,11 @@ export const ABC_DATA = {
 		{ name: "120", value: "Q:1/4=120", icon: "" },
 	],
 	slus: [
-		{ name: "3连音", value: '(3', icon: '' },
-		{ name: "4连音", value: '(4', icon: '' },
-		{ name: "5连音", value: '(5', icon: '' },
-		{ name: "6连音", value: '(6', icon: '' },
-		{ name: "7连音", value: '(7', icon: '' },
+		{ name: "3连音", value: "(3", icon: "" },
+		{ name: "4连音", value: "(4", icon: "" },
+		{ name: "5连音", value: "(5", icon: "" },
+		{ name: "6连音", value: "(6", icon: "" },
+		{ name: "7连音", value: "(7", icon: "" },
 	],
 	/** 3连音等多连音
 	 * 1. 将连音的音符小括号起来,并在括号前加上数字表示连音的音符数
@@ -137,8 +137,8 @@ export const ABC_DATA = {
 
 export const settings = reactive({
 	/** 光标跟随 音符, 节拍 */
-	cursorType: 'note' as 'note' | 'beat',
-})
+	cursorType: "note" as "note" | "beat",
+});
 
 export const createNote = (options: Partial<INote>): INote => {
 	return {
@@ -227,4 +227,3 @@ export const renderMeasures = (abc: IAbc) => {
 	// console.log(text)
 	return text;
 };
-

+ 3 - 0
src/pc/types.ts

@@ -61,6 +61,9 @@ export interface IAbc {
 	/** 速度 */
 	speed: string;
 	measures: IMeasure[];
+	/** 移调 */
+	visualTranspose?: number;
+	transposeKey?: string;
 }
 export interface INoteActive extends AbcElem {
 	/** 小节 index */