ソースを参照

计算空白时间 没有伴奏的音源处理

黄琪勇 1 年間 前
コミット
c3e4c6a63a
3 ファイル変更54 行追加17 行削除
  1. 28 4
      src/utils/crunker.ts
  2. 24 11
      src/view/audio-list/index.tsx
  3. 2 2
      vite.config.ts

+ 28 - 4
src/utils/crunker.ts

@@ -51,10 +51,16 @@ export default class Crunker {
                })
             }
             /* 这里有个坑 safa浏览器老一点的版本不支持decodeAudioData返回promise 所以用这种老式写法 */
-            return await new Promise(res => {
-               this._context.decodeAudioData(buffer, buffer => {
-                  res(buffer)
-               })
+            return await new Promise((res, rej) => {
+               this._context.decodeAudioData(
+                  buffer,
+                  buffer => {
+                     res(buffer)
+                  },
+                  err => {
+                     rej(err)
+                  }
+               )
             })
          })
       )
@@ -97,6 +103,24 @@ export default class Crunker {
       const audioBlob = new Blob([dataview], { type })
       return this._renderAudioElement(audioBlob)
    }
+   /**
+    * 计算音频前面的空白
+    */
+   calculateSilenceDuration(buffer: AudioBuffer) {
+      const threshold = 0.01 // 静音阈值,低于此值的部分认为是静音
+      const sampleRate = buffer.sampleRate
+      const channelData = buffer.getChannelData(0) // 只处理单声道数据
+      let silenceDuration = 0
+      for (let i = 0; i < channelData.length; i++) {
+         if (Math.abs(channelData[i]) > threshold) {
+            break
+         }
+         silenceDuration++
+      }
+      // 将样本数转换为秒
+      silenceDuration = silenceDuration / sampleRate
+      return silenceDuration
+   }
    private _maxNumberOfChannels(buffers: AudioBuffer[]): number {
       return Math.max(...buffers.map(buffer => buffer.numberOfChannels))
    }

+ 24 - 11
src/view/audio-list/index.tsx

@@ -127,20 +127,23 @@ export const detectTheNumberOfSoundSources = () => {
 /** 切换节拍器音源 */
 export const changeSongSourceByBate = (isDisBate:boolean) => {
 	// isDisBate 为true 切换到不带节拍的,为false 切换到带节拍的
-	if(audioData.songCollection.songEle && audioData.songCollection.backgroundEle && audioData.songCollection.beatSongEle && audioData.songCollection.bateBackgroundEle){
+	if(audioData.songCollection.songEle && audioData.songCollection.beatSongEle){
 		const songEleCurrentTime = audioData.songEle.currentTime
-		const backgroundEleCurrentTime = audioData.backgroundEle.currentTime
-		console.log("当前音乐时间:",songEleCurrentTime,backgroundEleCurrentTime)
+		console.log("当前音乐时间:",songEleCurrentTime)
 		if(isDisBate){
 			audioData.songEle = audioData.songCollection.songEle
-			audioData.backgroundEle = audioData.songCollection.backgroundEle
 			audioData.songEle.currentTime = songEleCurrentTime
-			audioData.backgroundEle.currentTime = backgroundEleCurrentTime
+			if(audioData.songCollection.backgroundEle){
+				audioData.backgroundEle = audioData.songCollection.backgroundEle
+				audioData.backgroundEle.currentTime = songEleCurrentTime
+			}
 		}else{
 			audioData.songEle = audioData.songCollection.beatSongEle
-			audioData.backgroundEle = audioData.songCollection.bateBackgroundEle
 			audioData.songEle.currentTime = songEleCurrentTime
-			audioData.backgroundEle.currentTime = backgroundEleCurrentTime
+			if(audioData.songCollection.bateBackgroundEle){
+				audioData.backgroundEle = audioData.songCollection.bateBackgroundEle
+				audioData.backgroundEle.currentTime = songEleCurrentTime
+			}
 		}
 	}
 }
@@ -237,26 +240,36 @@ export default defineComponent({
 		// 合成节拍器音源
 		function loadMergeAudioBetas() {
 			console.time("音频加载时间")
-			return crunker.fetchAudio(state.music+'?v='+Date.now(), state.accompany+'?v='+Date.now(), tickWav, tockWav).then(([musicBuff,accompanyBuff,tickWavBuff,tockWavBuff])=>{
+			const audioList = [state.music+'?v='+Date.now()]
+			if(state.accompany){   // 可能存在没有伴奏的音源
+				audioList.push(state.accompany+'?v='+Date.now()) 
+			}
+			return crunker.fetchAudio(tickWav, tockWav, ...audioList).then(([tickWavBuff,tockWavBuff,musicBuff,accompanyBuff])=>{
 				console.timeEnd("音频加载时间")
+				// 计算音频空白时间
+				const silenceDuration = crunker.calculateSilenceDuration(musicBuff)
+				const silenceBgDuration = accompanyBuff && crunker.calculateSilenceDuration(accompanyBuff) 
+				console.log(`音频空白时间:${silenceDuration},${silenceBgDuration}`)
 				const beats:AudioBuffer[] = []
 				const beatsTime:number[] = []
+				const beatsBgTime:number[] = []
 				metronomeData.metroMeasure.map(Measures=>{
 					Measures.map((item:any)=>{
 						beats.push(item.index===0?tickWavBuff:tockWavBuff)
-						beatsTime.push(item.time)
+						beatsTime.push(item.time + silenceDuration) // xml 计算的时候 加上空白的时间
+						accompanyBuff && beatsBgTime.push(item.time + silenceBgDuration) // xml 计算的时候 加上空白的时间
 					})
 				})
 				//合并
 				console.time("音频合并时间")
 				const musicBuffMeg = crunker.mergeAudioBuffers([musicBuff,...beats],[0,...beatsTime])
-				const accompanyBuffMeg = crunker.mergeAudioBuffers([accompanyBuff,...beats],[0,...beatsTime])
+				const accompanyBuffMeg = accompanyBuff && crunker.mergeAudioBuffers([accompanyBuff,...beats],[0,...beatsBgTime])
 				console.timeEnd("音频合并时间")
 				return [musicBuffMeg,accompanyBuffMeg]
 			}).then(([musicBuffMeg,accompanyBuffMeg])=>{
 				console.time("音频audioDom生成时间")
 				const musicAudio = crunker.exportAudioElement(musicBuffMeg)
-				const accompanyAudio = crunker.exportAudioElement(accompanyBuffMeg)
+				const accompanyAudio = accompanyBuffMeg && crunker.exportAudioElement(accompanyBuffMeg)
 				console.timeEnd("音频audioDom生成时间")
 				return [musicAudio,accompanyAudio]
 			})

+ 2 - 2
vite.config.ts

@@ -78,8 +78,8 @@ export default defineConfig({
         // target: "https://kt.colexiu.com",
         // target: "https://test.resource.colexiu.com", // 内容平台开发环境,内容平台开发,需在url链接上加上isCbs=true
         // target: "https://dev.resource.colexiu.com",
-        // target: "https://test.kt.colexiu.com",
-        target: "https://mec.colexiu.com",
+        target: "https://test.kt.colexiu.com",
+        //target: "https://mec.colexiu.com",
         changeOrigin: true,
         rewrite: (path) => path.replace(/^\/instrument/, ""),
       },