Browse Source

feat: 合奏切换分轨逻辑

TIANYONG 1 year ago
parent
commit
6046dd0976
3 changed files with 350 additions and 8 deletions
  1. 275 0
      src/helpers/utils.ts
  2. 3 3
      src/views/co-ai/change-voice/index.tsx
  3. 72 5
      src/views/co-ai/index.tsx

+ 275 - 0
src/helpers/utils.ts

@@ -236,3 +236,278 @@ export const dateFormat = (
 ) => {
   return dayjs(value).format(format);
 };
+
+
+const instruments: any = {
+	"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: "口风琴",
+	Nai: "口风琴",
+	"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: "天巴鼓",
+};
+
+/** 获取分轨名称 */
+export const getInstrumentName = (name = '') => {
+  name = name.toLocaleLowerCase().replace(/ /g, '')
+  if (!name) return ''
+  for(let key in instruments){
+    const _key = key.toLocaleLowerCase().replace(/ /g, '')
+    if (_key.includes(name)){
+      return instruments[key]
+    }
+  }
+  for(let key in instruments){
+    const _key = key.toLocaleLowerCase().replace(/ /g, '')
+    if (name.includes(_key)){
+      return instruments[key]
+    }
+  }
+  return ''
+};
+
+/**
+ * 乐器排序
+ * 排序顺序:长笛、单簧管、中音单簧管、低音单簧管、高音萨克斯风、中音萨克斯风、次中音萨克斯风、低音萨克斯风、小号、长号、圆号、大号、上低音号
+ * */ 
+export const sortMusical = (name: string, index: number) => {
+	let sortId = 0
+	switch (name) {
+	  case '长笛':
+		sortId = 1
+		break;
+	  case '单簧管':
+		sortId = 2
+		break;
+	  case '中音单簧管':
+		sortId = 3
+		break;
+	  case '低音单簧管':
+		sortId = 4
+		break;
+	  case '高音萨克斯风':
+		sortId = 5
+		break;
+	  case '中音萨克斯风':
+		sortId = 6
+		break;
+	  case '次中音萨克斯风':
+		sortId = 7
+		break;
+	  case '低音萨克斯风':
+		sortId = 8  
+		break;  
+	  case '小号':
+		sortId = 9  
+		break;     
+	  case '长号':
+		sortId = 10 
+		break;       
+	  case '圆号':
+		sortId =11  
+		break;       
+	  case '大号':
+		sortId = 12  
+		break; 
+	  case '上低音号':
+		sortId = 13 
+		break; 
+	  default:
+		sortId = index + 14
+		break;
+	}
+	return sortId
+}

+ 3 - 3
src/views/co-ai/change-voice/index.tsx

@@ -22,11 +22,11 @@ export default defineComponent({
         <div class={styles.changeVoiceContainer}>
           {props.musicalInstruments?.map((item: any, index: number) => (
             <div
-              class={[styles.item, musicIndex.value === index && styles.active]}
+              class={[styles.item, musicIndex.value === item.value && styles.active]}
               onClick={() => {
-                musicIndex.value = index;
+                musicIndex.value = item.value;
               }}>
-              {item.name}
+              {item.text}
             </div>
           ))}
         </div>

+ 72 - 5
src/views/co-ai/index.tsx

@@ -48,6 +48,8 @@ import { addWatermark, convasToImg, imgToCanvas } from './imageFunction';
 import ChangeVoice from './change-voice';
 import { storage } from '@/helpers/storage';
 import { ACCESS_TOKEN } from '@/store/mutation-types';
+import { sortMusical, getInstrumentName } from '@/helpers/utils'
+
 export default defineComponent({
   name: 'co-ai',
   setup() {
@@ -98,7 +100,8 @@ export default defineComponent({
       vipMember: state.user.data?.vipMember,
       subjectStatus: false,
       subjectList: [],
-      subjectItem: {} as any // 当前乐器
+      subjectItem: {} as any, // 当前乐器,
+      trackList: [] as any, // 可筛选的分轨信息
     });
     const downRef = ref();
     const showGuide = ref(false);
@@ -267,10 +270,11 @@ export default defineComponent({
     const musicIframeLoad = () => {
       const token = storage.get(ACCESS_TOKEN);
       const details = data.musics[data.musicIndex];
+      const musicRenderType = data.showMusicImg === 'first' ? 'firstTone' : data.showMusicImg === 'fixed' ? 'fixedTone' : data.showMusicImg === 'staff' ? 'staff' : 'firstTone'
       const origin = /(localhost|192)/.test(location.host)
         ? 'https://test.lexiaoya.cn'
         : location.origin;
-      data.iframeSrc = `${origin}/instrument/?id=${details.id}&modelType=practise&modeType=json&Authorization=${token}&isPreView=true&part-index=${data.selectMusicInstrumentIndex}`;
+      data.iframeSrc = `${origin}/instrument/?id=${details.id}&modelType=practise&modeType=json&Authorization=${token}&isPreView=true&part-index=${data.selectMusicInstrumentIndex}&musicRenderType=${musicRenderType}`;
     };
 
     const setSearchBox = () => {
@@ -286,6 +290,13 @@ export default defineComponent({
 
     const isEnsemble = computed(() => {
       const musics = data.musics[data.musicIndex]?.musicalInstruments;
+      if (musics && musics.length) {
+        let list: any = []
+        const arr = musics.forEach((item: any) => {
+          list.push({'name': item.name,'code': item.code})
+        })
+        console.log(999,list)
+      }
       if (musics && musics.length > 1) {
         return true;
       } else {
@@ -331,7 +342,61 @@ export default defineComponent({
         //
       }
     };
+    // 解析xml,获取分轨信息
+    const analyzeXml = async () => {
+      const details = data.musics[data.musicIndex];
+      if (details.xmlFileUrl) {
+        const res = await fetch(details.xmlFileUrl).then((response) => response.text());
+        filterTracks(res)
+      }
+    }
 
+    // 过滤出能切换的分轨
+    const filterTracks = (xml: any) => {
+      const xmlParse = new DOMParser().parseFromString(xml, "text/xml");
+      const partList = xmlParse.getElementsByTagName("part-list")?.[0]?.getElementsByTagName("score-part") || [];
+      const partListNames = Array.from(partList).map((item) => item.getElementsByTagName("part-name")?.[0]?.textContent?.trim() || "");
+      const parts: any = xmlParse.getElementsByTagName("part");
+    
+      /** 第一分谱如果是约定的配置分谱则跳过 */
+      if (partListNames[0]?.toLocaleUpperCase?.() === "COMMON") {
+        partListNames.shift();
+      }
+      // 根据后台已选择的分轨筛选出能切换的声轨
+      const multiTracksSelection = data.musics[data.musicIndex]?.multiTracksSelection
+      const canSelectTracks = multiTracksSelection ? multiTracksSelection?.split(',') : []
+      const arr =  partListNames.map((item: any, index: number) => {
+        // 该声轨能否被选
+        const canselect = canSelectTracks.length == 0 || canSelectTracks.includes(item) ? true : false
+        // console.log(canselect,index)
+        const instrumentName = getInstrumentName(item)
+        const sortId = sortMusical(instrumentName, index)
+        return {
+          text: item + (instrumentName ? `(${instrumentName})` : ''),
+          value: index,
+          sortId,
+          canselect,
+          track: item,
+        }
+      }).filter((item: any) => item.canselect).sort((a: any, b: any) => a.sortId - b.sortId)      
+      data.trackList = arr;    
+      let track = arr.find((item: any) => item.value === data.selectMusicInstrumentIndex)?.track
+      track = track.replace(/[0-9]+/g,"").replace(/\s/g, '').toLocaleLowerCase()
+      let musicRenderType: 'staff' | 'first' | 'fixed' = 'first'
+      data.musics[data.musicIndex]?.musicalInstruments.forEach((item: any) => {
+        if (item.code.toLocaleLowerCase() === track) {
+          musicRenderType = item.defaultScore === 'STAVE' ? 'staff' : item.defaultScore === 'JIAN' ? 'fixed' : item.defaultScore === 'FIRST' ? 'first' : 'first'
+        }
+      }) 
+      data.showMusicImg = musicRenderType
+    }
+		watch(
+			() => data.musicIndex,
+		 	async () => {
+        data.selectMusicInstrumentIndex = 0
+        analyzeXml()
+			}
+		);
     onMounted(async () => {
       // 安卓的状态栏
       postMessage({
@@ -363,6 +428,7 @@ export default defineComponent({
           data.vipMember = res.data.vipMember;
         }
       };
+      analyzeXml();
       listenerMessage('webViewOnResume', () => {
         console.log('页面显示');
         getUserInfo();
@@ -631,6 +697,7 @@ export default defineComponent({
                 onSelect={(item: any) => {
                   data.showMusicImg = item.value;
                   data.popoverShow = false;
+                  musicIframeLoad();
                 }}
                 // onSelect={onSelect}
               >
@@ -710,13 +777,13 @@ export default defineComponent({
           v-model:show={data.showChangeVoice}>
           <ChangeVoice
             musicalInstruments={
-              data.musics[data.musicIndex]?.musicalInstruments || []
+              data.trackList || []
             }
             musicalInstrumentIndex={data.selectMusicInstrumentIndex}
             onClose={() => (data.showChangeVoice = false)}
-            onConfirm={(index: number) => {
+            onConfirm={ async (index: number) => {
               data.selectMusicInstrumentIndex = index;
-
+              await analyzeXml();
               musicIframeLoad();
               data.showChangeVoice = false;
             }}