瀏覽代碼

切换乐器

liushengqiang 1 年之前
父節點
當前提交
9f203adeb0

+ 62 - 0
public/osmd/index.html

@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Document</title>
+    <script src="./opensheetmusicdisplay.min.js"></script>
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+        }
+
+        body {
+            padding-bottom: 60px;
+            height: 600px;
+            overflow: hidden;
+        }
+
+        .vf-text {
+            display: none;
+        }
+    </style>
+</head>
+
+<body>
+    <div id="osmdContainer" />
+    <script>
+        var osmd = new opensheetmusicdisplay.OpenSheetMusicDisplay("osmdContainer");
+        osmd.setOptions({
+            backend: "svg",
+            drawTitle: false,
+            // drawingParameters: "compacttight" // don't display title, composer etc., smaller margins
+        });
+
+        function renderXml(xmlUrl, partIndex) {
+            osmd
+                .load(xmlUrl)
+                .then(
+                    function () {
+                        for (let i = 0; i < osmd.Sheet.Instruments.length; i++) {
+                            // console.log(osmd.Sheet.Instruments[i].Name);
+                            osmd.Sheet.Instruments[i].Visible = i === partIndex;
+                        }
+                        osmd.zoom = .5
+                        osmd.render();
+                    }
+                );
+        }
+        function resetRender(partIndex) {
+            for (let i = 0; i < osmd.Sheet.Instruments.length; i++) {
+                // console.log(osmd.Sheet.Instruments[i].Name);
+                osmd.Sheet.Instruments[i].Visible = i === partIndex;
+            }
+            osmd.render();
+        }
+    </script>
+</body>
+
+</html>

File diff suppressed because it is too large
+ 1 - 0
public/osmd/opensheetmusicdisplay.min.js


+ 228 - 0
src/constant/instruments.ts

@@ -0,0 +1,228 @@
+const instruments = {
+  'Acoustic Grand Piano': '大钢琴',
+  'Bright Acoustic Piano': '明亮的钢琴',
+  'Electric Grand Piano': '电钢琴',
+  'Rhodes Piano': '柔和的电钢琴',
+  'Chorused Piano': '加合唱效果的电钢琴',
+  Harpsichord: '羽管键琴',
+  Clavichord: '科拉维科特琴',
+  Celesta: '钢片琴',
+  Glockenspiel: '钢片琴',
+  'Music box': '八音盒',
+  Vibraphone: '颤音琴',
+  Marimba: '马林巴',
+  Xylophone: '木琴',
+  'Tubular Bells': '管钟',
+  Dulcimer: '大扬琴',
+  'Hammond Organ': '击杆风琴',
+  'Percussive Organ': '打击式风琴',
+  'Rock Organ': '摇滚风琴',
+  'Church Organ': '教堂风琴',
+  'Reed Organ': '簧管风琴',
+  Accordian: '手风琴',
+  Harmonica: '口琴',
+  'Tango Accordian': '探戈手风琴',
+  'Acoustic Guitar': '钢弦吉他',
+  'Electric Guitar': '闷音电吉他',
+  'Overdriven Guitar': '加驱动效果的电吉他',
+  'Distortion Guitar': '加失真效果的电吉他',
+  'Guitar Harmonics': '吉他和音',
+  'Acoustic Bass': '大贝司',
+  'Electric Bass': '电贝司',
+  'Fretless Bass': '无品贝司',
+  'Slap Bass': '掌击',
+  'Synth Bass': '电子合成',
+  Violin: '小提琴',
+  Viola: '中提琴',
+  Cello: '大提琴',
+  Contrabass: '低音大提琴',
+  'Tremolo Strings': '弦乐群颤音音色',
+  'Pizzicato Strings': '弦乐群拨弦音色',
+  'Orchestral Harp': '竖琴',
+  Timpani: '定音鼓',
+  'String Ensemble': '弦乐合奏音色',
+  'Synth Strings': '合成弦乐合奏音色',
+  'Choir Aahs': '人声合唱',
+  'Voice Oohs': '人声',
+  'Synth Voice': '合成人声',
+  'Orchestra Hit': '管弦乐敲击齐奏',
+  Trumpet: '小号',
+  Trombone: '长号',
+  Tuba: '大号',
+  'Muted Trumpet': '加弱音器小号',
+  'French Horn': '法国号',
+  'Brass Section': '铜管组',
+  'Synth Brass': '合成铜管音色',
+  'Soprano Sax': '高音萨克斯管',
+  'Alto Sax': '中音萨克斯管',
+  'Tenor Sax': '次中音萨克斯管',
+  'Baritone Sax': '低音萨克斯管',
+  Oboe: '双簧管',
+  'English Horn': '英国管',
+  Bassoon: '巴松',
+  Clarinet: '单簧管',
+  'Soprano Saxophone': '高音萨克斯管',
+  'Alto Saxophone': '中音萨克斯管',
+  'Tenor Saxophone': '次中音萨克斯管',
+  'Baritone Saxophone': '低音萨克斯管',
+  Piccolo: '短笛',
+  Flute: '长笛',
+  Recorder: '竖笛',
+  'Soprano Recorder': '高音竖笛',
+  'Pan Flute': '排箫',
+  'Bottle Blow': '瓶木管',
+  Whistle: '口哨声',
+  Ocarina: '陶笛',
+  Lead: '合成主音',
+  'Lead lead': '合成主音',
+  'Pad age': '合成音色',
+  Pad: '合成音色',
+  FX: '合成效果  科幻',
+  Sitar: '西塔尔',
+  Banjo: '班卓琴',
+  Shamisen: '三昧线',
+  Koto: '十三弦筝',
+  Kalimba: '卡林巴',
+  Bagpipe: '风笛',
+  Fiddle: '民族提琴',
+  Shanai: '山奈',
+  'Tinkle Bell': '叮当铃',
+  Agogos: '阿戈戈铃',
+  'Steel Drums': '钢鼓',
+  'Taiko Drum': '太鼓',
+  'Melodic Toms': '嗵嗵鼓',
+  'Synth Drums': '合成鼓',
+  'Reverse Cymbals': '反向镲',
+  'Agogo Bells': '阿戈戈铃',
+  'Taiko Drums': '太鼓',
+  Bongos: '邦戈鼓',
+  'Bongo Bell': '邦戈铃',
+  Congas: '康加鼓',
+  Guiro: '刮壶',
+  'Guitar Fret Noise': '吉他换把杂音',
+  'Breath Noise': '呼吸声',
+  Seashore: '海浪声',
+  'Bird Tweet': '鸟鸣',
+  'Telephone Ring': '电话铃',
+  Helicopter: '直升机',
+  Applause: '鼓掌声',
+  Gunshot: '枪声',
+  'Acoustic Bass Drum': '大鼓',
+  'Bass Drum': '大鼓',
+  'Side Drum': '小鼓鼓边',
+  'Acoustic Snare': '小鼓',
+  'Hand Claps': '拍手',
+  'Electric Snare': '小鼓',
+  'Low Floor Tom': '低音嗵鼓',
+  'Closed Hi-Hat': '闭合踩镲',
+  'High Floor Tom': '高音落地嗵鼓',
+  'Pedal Hi-Hat': '脚踏踩镲',
+  'Low Tom': '低音嗵鼓',
+  'Open Hi-Hat': '开音踩镲',
+  'Low-Mid Tom': '中低音嗵鼓',
+  'Hi Mid Tom': '高音鼓',
+  'Crash Cymbals': '对镲',
+  'High Tom': '高音嗵鼓',
+  'Ride Cymbals': '叮叮镲',
+  'Chinese Cymbals': '中国镲',
+  'Ride Bell': '圆铃',
+  Tambourine: '铃鼓',
+  'Splash Cymbal': '溅音镲',
+  Cowbell: '牛铃',
+  'Crash Cymbal': '强音钹',
+  'Vibra-Slap': '颤音器',
+  'Ride Cymbal': '打点钹',
+  'Hi Bongo': '高音邦戈鼓',
+  'Low Bongo': '低音邦戈鼓',
+  'Mute Hi Conga': '弱音高音康加鼓',
+  'Open Hi Conga': '强音高音康加鼓',
+  'Low Conga': '低音康加鼓',
+  'High Timbale': '高音天巴鼓',
+  'Low Timbale': '低音天巴鼓',
+  'High Agogo': '高音阿戈戈铃',
+  'Low Agogo': '低音阿戈戈铃',
+  Cabasa: '卡巴萨',
+  Maracas: '沙锤',
+  'Short Whistle': '短口哨',
+  'Long Whistle': '长口哨',
+  'Short Guiro': '短刮壶',
+  'Long Guiro': '长刮壶',
+  Claves: '响棒',
+  'Hi Wood Block': '高音木鱼',
+  'Low Wood Block': '低音木鱼',
+  'Mute Triangle': '弱音三角铁',
+  'Open Triangle': '强音三角铁',
+  'Drum Set': '架子鼓',
+  'Hulusi flute': '葫芦丝',
+  Melodica: '口风琴',
+  'Snare Drum': '小军鼓',
+  Cymbal: '镲',
+  Cymbals: '镲',
+  'Horn in F': '圆号',
+  Triangle: '三角铁',
+  Vibrato: '颤音琴',
+  'Suspend Cymbals': '吊镲',
+  'Suspended Cymbals': '吊镲',
+  'Tom-Toms': '嗵嗵鼓',
+  Bell: '铃铛',
+  Bells: '铃铛',
+  'Alto Clarinet': '中音单簧管',
+  'Bass Clarinet': '低音单簧管',
+  Cornet: '短号',
+  Euphonium: '上低音号',
+  'crash cymbals': '对镲',
+  Castanets: '响板',
+  Shaker: '沙锤',
+  'Mark tree': '音树',
+  Chimes: '管钟',
+  'Mark Tree': '音树',
+  'Tom-toms': '嗵嗵鼓',
+  'Hi-Hat': '踩镲',
+  'Sleigh Bells': '雪橇铃',
+  Flexatone: '弹音器',
+  'Brake drum': '闸鼓',
+  Gong: '锣',
+  'concert tom': '音乐会嗵嗵鼓',
+  'brake drum': '车轮鼓',
+  'finger cymbal': '指钹',
+  'ride cymbal': '叮叮镲',
+  'Concert Toms': '音乐会嗵嗵鼓',
+  Vibraslap: '弹音器',
+  'Wood Blocks': '木鱼',
+  'Temple Blocks': '木鱼',
+  'Wood Block': '木鱼',
+  'Field Drum': '军鼓',
+  'Quad-Toms': '筒鼓',
+  Quads: '筒鼓',
+  'Drums set': '架子鼓',
+  'High Bongo': '邦戈',
+  Timbales: '天巴鼓',
+  'rain stick': '雨棒',
+  'String Bass': '弦乐低音',
+  'Floor Tom': '侧嗵鼓',
+  'Brake Drum': '闸鼓',
+  'Tam-tam': '大锣'
+}
+
+/**
+ * 获取乐器名称
+ * @param instrumentName 乐器code
+ * @returns 
+ */
+export const getInstrumentName = (instrumentName: string) => {
+  const _instrumentName = instrumentName.replace(/ /g, ' ').toLocaleLowerCase()
+  const _instrument = Object.keys(instruments)
+  for (let i = 0; i < _instrument.length; i++) {
+    const _name = _instrument[i].replace(/ /g, ' ').toLocaleLowerCase()
+    if (_name === _instrumentName) {
+      return instruments[_instrument[i]] || ''
+    }
+  }
+  for (let i = 0; i < _instrument.length; i++) {
+    const _name = _instrument[i].replace(/ /g, ' ').toLocaleLowerCase()
+    if (_instrumentName.includes(_name)) {
+      return instruments[_instrument[i]] || ''
+    }
+  }
+  return ''
+}

+ 5 - 1
src/views/music/music-detail/index.module.less

@@ -94,7 +94,11 @@
   }
   :global {
     iframe {
-      visibility: hidden;
+      // visibility: hidden;
+      border: none;
+      width: 100%;
+      height: 500px;
+      overflow: hidden;
       body {
         ::-webkit-scrollbar-thumb {
           background-color: #efeff0;

+ 82 - 19
src/views/music/music-detail/index.tsx

@@ -25,7 +25,8 @@ import {
   Sticky,
   Tag,
   Radio,
-  Toast
+  Toast,
+  Picker
 } from 'vant'
 import styles from './index.module.less'
 // import Item from '../list/item'
@@ -61,6 +62,7 @@ import fixedActive from './images/fixed-active.png'
 import Plyr from 'plyr'
 import 'plyr/dist/plyr.css'
 import Download from './download'
+import { getInstrumentName } from '@/constant/instruments'
 
 export const getAssetsHomeFile = (fileName: string) => {
   const path = `../component/images/${fileName}`
@@ -166,6 +168,9 @@ export default defineComponent({
         //   false
         // )
         // }
+        nextTick(() => {
+          renderStaff()
+        })
       } catch (error) {
         isError.value = true
       }
@@ -490,6 +495,43 @@ export default defineComponent({
         return
       } catch {}
     }
+
+    const staffData = reactive({
+      open: false,
+      iframeSrc: '',
+      musicXml: '',
+      iframeRef: null as any,
+      partIndex: 0,
+      partList: [] as any[]
+    })
+    /** 渲染五线谱 */
+    const renderStaff = () => {
+      staffData.iframeSrc = `${location.origin}${location.pathname}osmd/index.html`
+      staffData.musicXml = musicDetail.value?.xmlFileUrl || ''
+      staffData.partList = musicDetail.value?.background || []
+      
+    }
+    const musicIframeLoad = () => {
+      const iframeRef: any = document.getElementById('staffIframeRef')
+      if (iframeRef && iframeRef.contentWindow.renderXml){
+        iframeRef.contentWindow.renderXml(staffData.musicXml, staffData.partIndex)
+      }
+    }
+    const resetRender = () => {
+      const iframeRef: any = document.getElementById('staffIframeRef')
+      if (iframeRef && iframeRef.contentWindow.renderXml){
+        iframeRef.contentWindow.resetRender(staffData.partIndex)
+      }
+    }
+    const partColumns = computed(() => {
+      return staffData.partList.map((item: any, index: number) => {
+        const instrumentName = getInstrumentName(item.track)
+        return {
+          text: item.track + (instrumentName ? `(${instrumentName})` : ''),
+          value: index
+        }
+      })
+    })
     return () => {
       return (
         <div class={styles.detail}>
@@ -581,44 +623,54 @@ export default defineComponent({
                 ),
                 value: () => (
                   <>
-                    {musicDetail.value?.notation ? (
+                    <div class="van-cell__value" style={{display: musicDetail.value?.musicSheetType === 'SINGLE' ? '' : 'none'}}>
+                      {musicDetail.value?.notation ? (
+                        <span
+                          class={styles.download}
+                          onClick={() => {
+                            staff.status = true
+                          }}
+                        >
+                          <img src={iconChangeStaff} />
+                          <span>转谱</span>
+                        </span>
+                      ) : null}
                       <span
                         class={styles.download}
                         onClick={() => {
-                          staff.status = true
+                          if (showImg.length > 0) {
+                            downloadStatus.value = true
+                          } else {
+                            Toast('暂无图片')
+                          }
                         }}
                       >
-                        <img src={iconChangeStaff} />
-                        <span>转谱</span>
+                        <img src={iconDownload} />
+                        <span>下载曲谱</span>
                       </span>
-                    ) : null}
+                    </div>
                     <span
+                      style={{display: musicDetail.value?.musicSheetType === 'CONCERT' ? '' : 'none'}}
                       class={styles.download}
                       onClick={() => {
-                        if (showImg.length > 0) {
-                          downloadStatus.value = true
-                        } else {
-                          Toast('暂无图片')
-                        }
+                        staffData.open = true
                       }}
                     >
-                      <img src={iconDownload} />
-                      <span>下载曲谱</span>
+                      <Icon style={{background: 'rgba(246,246,246,1)', borderRadius: '50%', padding: '4px'}} size="20px" name="exchange" />
+                      <span>切换乐器</span>
                     </span>
+                    
                   </>
                 )
               }}
             />
             <div class={styles.musicContent}>
-              {/* <iframe
-                id="containerPrint"
-                ref="print"
-                style="width: 540px;page-break-after:always; height: 0;"
-                src={accompanyUrl.value}
-              /> */}
               <p class={styles.musicTitle}>
                 {musicDetail.value?.musicSheetName}
               </p>
+              {musicDetail.value?.musicSheetType === 'CONCERT' ? (
+                <iframe id="staffIframeRef" src={staffData.iframeSrc} onLoad={musicIframeLoad}></iframe>
+              ) : null}
               {showImg.length > 0 ? (
                 <img src={showImg[0]} alt="" class={styles.musicImg} />
               ) : loading.value ? (
@@ -959,6 +1011,17 @@ export default defineComponent({
               </RadioGroup>
             </div>
           </Popup>
+
+          <Popup teleport="body"  position="bottom" round v-model:show={staffData.open}>
+              <Picker columns={partColumns.value} 
+                onConfirm={(value) => {
+                  staffData.partIndex = value.value
+                  resetRender()
+                  staffData.open = false
+                }} 
+                onCancel={() => staffData.open = false}
+               />
+          </Popup>
         </div>
       )
     }

Some files were not shown because too many files changed in this diff