黄琪勇 5 månader sedan
förälder
incheckning
43bc0c694e

+ 0 - 11
src/views/rhythm/components/firstTone/firstTone.vue

@@ -1,11 +0,0 @@
-<!--
-* @FileDescription: 固定调谱面
-* @Date:2025-01-03 13:45:37
--->
-<template>
-   <div class="firstTone"></div>
-</template>
-
-<script setup lang="ts"></script>
-
-<style lang="scss" scoped></style>

+ 0 - 2
src/views/rhythm/components/firstTone/index.ts

@@ -1,2 +0,0 @@
-import firstTone from "./firstTone.vue"
-export default firstTone

+ 0 - 11
src/views/rhythm/components/fixedTone/fixedTone.vue

@@ -1,11 +0,0 @@
-<!--
-* @FileDescription: 固定调谱面
-* @Date:2025-01-03 13:50:54
--->
-<template>
-   <div class="fixedTone"></div>
-</template>
-
-<script setup lang="ts"></script>
-
-<style lang="scss" scoped></style>

+ 0 - 2
src/views/rhythm/components/fixedTone/index.ts

@@ -1,2 +0,0 @@
-import fixedTone from "./fixedTone.vue"
-export default fixedTone

+ 2 - 0
src/views/rhythm/components/numberedTone/index.ts

@@ -0,0 +1,2 @@
+import numberedTone from "./numberedTone.vue"
+export default numberedTone

+ 132 - 0
src/views/rhythm/components/numberedTone/numberedTone.vue

@@ -0,0 +1,132 @@
+<!--
+* @FileDescription: 简谱
+* @Date:2025-01-03 13:45:37
+-->
+<template>
+   <div class="numberedTone">
+      <template v-for="(measure, index) in measuresData" :key="index">
+         <div
+            :style="{
+               color: 'red'
+            }"
+         >
+            {{ index + 1 }}
+         </div>
+         <div class="notes" v-for="(notes, i) in measure" :key="i">
+            <template v-for="(note, k) in notes" :key="k">
+               <!-- 连接音符 -->
+               <div v-if="note.beams.length" class="note">
+                  <div :class="['noteLine', `line${b}`]" v-for="(line, b) in note.beams" :key="b"></div>
+                  <svg_4Tem />
+                  <div :class="['dot']" v-if="note.dot"></div>
+                  <img class="rhythmImg" src="../imgs/paishou.png" />
+               </div>
+               <!-- 单个音符 -->
+               <div v-else class="note">
+                  <component :is="note.rest ? svg_rest4Tem : svg_4Tem" />
+                  <template v-if="note.type > 4">
+                     <div :class="['noteLine', `line${b}`]" v-for="(line, b) in Array.from({ length: note.type / 4 - 1 })" :key="b"></div>
+                  </template>
+                  <div :class="['dot', note.rest && `dotRest${note.type}`]" v-if="note.dot"></div>
+                  <img class="rhythmImg" src="../imgs/paishou.png" />
+               </div>
+            </template>
+            <div class="beatsType" v-if="i === 0 && notes[0].beatType && notes[0].beats">
+               <div>{{ notes[0].beats }}</div>
+               <div class="divide"></div>
+               <div>{{ notes[0].beatType }}</div>
+            </div>
+         </div>
+      </template>
+   </div>
+</template>
+
+<script setup lang="ts">
+import { type measuresType } from "../../tools/formatXml"
+import svg_4Tem from "./svgs/4.vue"
+import svg_rest4Tem from "./svgs/4rest.vue"
+
+defineProps<{
+   measuresData: measuresType[]
+}>()
+</script>
+
+<style lang="scss" scoped>
+.numberedTone {
+   width: calc(100% + 206px);
+   display: flex;
+   flex-wrap: wrap;
+   justify-content: space-between;
+   .notes {
+      display: flex;
+      margin-right: 180px;
+      margin-bottom: 304px;
+      position: relative;
+      .note {
+         position: relative;
+         width: 66px;
+         height: 93px;
+         margin-right: 64px;
+         &:last-child {
+            margin-right: 0;
+         }
+         .noteLine {
+            position: absolute;
+            width: 130px;
+            height: 8px;
+            background: #000000;
+            &.line0 {
+               left: -32px;
+               top: 102px;
+            }
+            &.line1 {
+               left: -32px;
+               top: 117px;
+            }
+            &.line2 {
+               left: -32px;
+               top: 132px;
+            }
+            &.line3 {
+               left: -32px;
+               top: 147px;
+            }
+            &.line4 {
+               left: -32px;
+               top: 162px;
+            }
+         }
+         .rhythmImg {
+            position: absolute;
+            top: 157px;
+            left: 50%;
+            transform: translateX(-50%);
+            width: 110px;
+            height: 110px;
+         }
+      }
+      .beatsType {
+         width: 45px;
+         height: 93px;
+         font-weight: 600;
+         font-size: 46px;
+         line-height: 46px;
+         color: #131415;
+         position: absolute;
+         left: -97px;
+         top: 0;
+         display: flex;
+         justify-items: center;
+         align-items: center;
+         flex-direction: column;
+         .divide {
+            margin: 4px 0;
+            width: 100%;
+            height: 5px;
+            background: #000000;
+            flex-shrink: 0;
+         }
+      }
+   }
+}
+</style>

+ 13 - 0
src/views/rhythm/components/numberedTone/svgs/4.vue

@@ -0,0 +1,13 @@
+<template>
+   <svg width="100%" height="100%" viewBox="0 0 66 93" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+      <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+         <g transform="translate(-162, -156)" fill="#000000" fill-rule="nonzero">
+            <g transform="translate(65, 153)">
+               <path
+                  d="M147.265954,3.07286842 L160.725851,3.01459786 C160.927388,3.01490114 161.113714,3.1217313 161.215635,3.2954167 C161.317556,3.46910209 161.31985,3.68370074 161.221665,3.85952087 L137.34967,47.606138 C137.253594,47.7781814 137.253594,47.9876648 137.34967,48.1597082 L162.927849,95.1549086 C163.027388,95.3330119 163.023709,95.5507524 162.91821,95.7253984 C162.812711,95.9000444 162.621585,96.0047881 162.417452,96 L148.972138,95.9852639 C148.757905,95.9874658 148.560612,95.8692126 148.461741,95.6793435 L130.481185,61.1831766 C130.385542,60.9888084 130.187594,60.8656699 129.970788,60.8656699 C129.753981,60.8656699 129.556034,60.9888084 129.460391,61.1831766 L111.552748,95.6647759 C111.453878,95.8546449 111.256584,95.9728982 111.042351,95.9706963 L97.5678714,96 C97.3663343,96 97.1800089,95.8926981 97.0780876,95.7190127 C96.9761662,95.5453273 96.9738721,95.3307287 97.0720572,95.1549086 L122.446078,48.1597082 C122.542154,47.9876648 122.542154,47.7781814 122.446078,47.606138 L98.734493,3.85952087 C98.6434527,3.68477048 98.6495305,3.47537959 98.750554,3.30619248 C98.8515774,3.13700537 99.033126,3.03217264 99.2303072,3.0291655 L112.748536,3 C112.962769,2.99782833 113.160062,3.11608158 113.258933,3.30595062 L129.474974,34.5972372 C129.570617,34.7916054 129.768564,34.9147439 129.985371,34.9147439 C130.202177,34.9147439 130.400124,34.7916054 130.495767,34.5972372 L146.755557,3.37878881 C146.854427,3.18891977 147.051721,3.07066652 147.265954,3.07286842 L147.265954,3.07286842 Z"
+               />
+            </g>
+         </g>
+      </g>
+   </svg>
+</template>

+ 13 - 0
src/views/rhythm/components/numberedTone/svgs/4rest.vue

@@ -0,0 +1,13 @@
+<template>
+   <svg width="100%" height="100%" viewBox="0 0 66 94" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+      <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+         <g transform="translate(-274, -156)" fill="#000000" fill-rule="nonzero">
+            <g transform="translate(274.314, 156.272)">
+               <path
+                  d="M32.712938,0 C22.1846361,0 14.0377358,4.26145553 8.2722372,13.0350404 C2.7574124,21.3072776 0,32.4622642 0,46.5 C0,60.5377358 2.7574124,71.6927224 8.2722372,79.9649596 C14.0377358,88.6132075 22.1846361,93 32.712938,93 C43.115903,93 51.2628032,88.6132075 57.1536388,79.9649596 C62.6684636,71.6927224 65.425876,60.5377358 65.425876,46.5 C65.425876,32.4622642 62.6684636,21.3072776 57.1536388,13.0350404 C51.2628032,4.26145553 43.115903,0 32.712938,0 Z M32.712938,12.4083558 C39.7318059,12.4083558 44.745283,16.2938005 47.7533693,24.3153639 C49.7587601,29.7048518 50.7614555,37.0997305 50.7614555,46.5 C50.7614555,55.7749326 49.7587601,63.1698113 47.7533693,68.6846361 C44.745283,76.5808625 39.7318059,80.5916442 32.712938,80.5916442 C25.5687332,80.5916442 20.5552561,76.5808625 17.6725067,68.6846361 C15.6671159,63.1698113 14.6644205,55.7749326 14.6644205,46.5 C14.6644205,37.0997305 15.6671159,29.7048518 17.6725067,24.3153639 C20.5552561,16.2938005 25.5687332,12.4083558 32.712938,12.4083558 Z"
+               />
+            </g>
+         </g>
+      </g>
+   </svg>
+</template>

+ 28 - 0
src/views/rhythm/components/staff/staff.vue

@@ -35,6 +35,11 @@
                   <img class="rhythmImg" src="../imgs/paishou.png" />
                </div>
             </template>
+            <div class="beatsType" v-if="i === 0 && notes[0].beatType && notes[0].beats">
+               <div>{{ notes[0].beats }}</div>
+               <div class="divide"></div>
+               <div>{{ notes[0].beatType }}</div>
+            </div>
          </div>
       </template>
    </div>
@@ -85,6 +90,7 @@ const beatSvgObj: Record<string, any> = {
       display: flex;
       margin-right: 206px;
       margin-bottom: 272px;
+      position: relative;
       .note {
          position: relative;
          height: 125px;
@@ -175,6 +181,28 @@ const beatSvgObj: Record<string, any> = {
       .note32rest {
          width: 55px;
       }
+      .beatsType {
+         width: 45px;
+         height: 93px;
+         font-weight: 600;
+         font-size: 46px;
+         line-height: 46px;
+         color: #131415;
+         position: absolute;
+         left: -97px;
+         top: 0;
+         display: flex;
+         justify-items: center;
+         align-items: center;
+         flex-direction: column;
+         .divide {
+            margin: 4px 0;
+            width: 100%;
+            height: 5px;
+            background: #000000;
+            flex-shrink: 0;
+         }
+      }
    }
 }
 </style>

+ 2 - 0
src/views/rhythm/rhythm.vue

@@ -3,6 +3,7 @@
       <div class="musicScoreCon">
          <div class="musicScoreBox">
             <staff :measuresData="measuresData" />
+            <!-- <numberedTone :measuresData="measuresData" /> -->
          </div>
       </div>
    </div>
@@ -10,6 +11,7 @@
 
 <script setup lang="ts">
 import staff from "./components/staff"
+import numberedTone from "./components/numberedTone"
 import axios from "axios"
 import { parseMusicXML, type measuresType } from "./tools/formatXml"
 import { ref } from "vue"

+ 9 - 1
src/views/rhythm/tools/formatXml.ts

@@ -17,15 +17,19 @@ export function parseMusicXML(xmlStr: string) {
 
 export type measuresType = {
    stem: "down" | "up"
-   type: 4
+   type: number
    dot: boolean
    rest: boolean
    beams: ("begin" | "continue" | "end" | "backward hook")[]
+   beats?: string
+   beatType?: string
 }[][]
 
 function parsePart(firstPart: Element): measuresType[] {
    const measuresData = []
    for (const measure of firstPart.children) {
+      const beats = measure.querySelector("time beats")
+      const beatType = measure.querySelector("time beat-type")
       const notesData = []
       const notes = measure.getElementsByTagName("note")
       let cacheNote = []
@@ -47,6 +51,10 @@ function parsePart(firstPart: Element): measuresType[] {
             dot,
             rest,
             beams
+         } as measuresType[0][0]
+         if (beats && beatType) {
+            noteData.beats = beats.textContent!
+            noteData.beatType = beatType.textContent!
          }
          // 根据beams信息把多个音符组成一个大类
          if (noteData.beams.length) {