纯前端技术裁切合并音频方式实现

随着5G时代的来临,音视频的领域的必将嫌弃新的浪潮,只有不断的学习才能跟的上步伐,吧啦吧啦....

好吧前面真的编不下去了~~~,快速进入正题,这篇文章主要介绍的功能
1、选择本地音频文件 (多段)
2、选择音频区间播放 (多段)
3、合并audiobuffer
4、下载编辑后的音频
整体例子功能比较单一,不过后面可以思考视频是否可以沿用方式,拼接多段,可以肯定的应该能提取视频的声音,视频画面部分没有尝试,目前只测试了音频功能正常; 注意这个是纯前端的技术并不是把音频文件上传到服务端 用 ffmpeg方式进行裁切

demo早就做了,今天终于有时间整理下,同时也自己复习下,如果有错误的地方希望大神能指出来 。

主要的知识点:

  • AudioContext 前面的文章已经讲过了,
    • decodeAudioData 把filedata 转换为 audiobuffer
    • createBuffer 创建空的audiobuffer
  • AudioBuffers 主要是编辑该数据
    • getChannelData 获取buffer的实际数据
    • ChannerlData.set 设置buffer数据

先贴下体验地址: http://works.ibeeger.com/learn/audioctx/merge.html

在这里插入图片描述
选择多段,选择区间试听,完成后可以点击下载,下载的音频文件就是你所选择的区间范围。
当然还有很大的提升空间,这里只作为一个demo演示

还是看代码把。

decode转换

const decodecFile = function(fileContent, id) {
    
    
				audioContext.decodeAudioData(fileContent, function(buffer) {
    
    
                    let index = id.replace(/choose/g,'');
                    buffers[index] = Object.assign({
    
    buffer: buffer},showBuffer(buffer, index));
				});
            }

可视化

function showBuffer(buffer, index) {
    
    
             var cs = '';
             var ctx = '';
             var item = document.querySelectorAll('section>div')[index];
             if(item.querySelector('canvas')){
    
    
                 cs = buffers[index]['cs']
                 ctx = buffers[index]['ctx'];
             } else {
    
    
                cs = document.createElement('canvas');
                cs.width = window.innerWidth;
                ctx = cs.getContext('2d');
             }
             ctx.clearRect(0,0, cs.width, cs.height);
	const lth = buffer.getChannelData(1).length;
	const arr = buffer.getChannelData(1);
             let w = Math.floor(lth/cs.width/2);
	ctx.fillStyle ='#efefef'
	const list = []
	for(let i =0; i<cs.width; i++) {
    
    
		list.push(arr[i*w]*cs.height);
		ctx.fillRect(i,(cs.height-arr[i*w]*cs.height)/2,1,arr[i*w]*cs.height);
	};
             ctx.save();
             cs.dataset['index'] = index;
             cs.addEventListener('mousedown', mousedown, false);
             cs.addEventListener('touchstart', mousedown, false);
             cs.addEventListener('mousemove', mousemove, false);
             cs.addEventListener('touchmove', mousemove, false);
             cs.addEventListener('mouseup', mouseup, false);
             cs.addEventListener('touchend', mouseup, false);
             document.querySelectorAll("section>div")[index].appendChild(cs);
	return {
    
    
        cs: cs,
        ctx: ctx,
		step: w,
		list: list
	}
}

播放指定的应的audiobuffer

function start(buffer) {
    
    
             
             if (audioBufferSourceNode) {
    
    
				audioBufferSourceNode.stop();
             }
             audioContext = new AudioContext();
	const analyser = audioContext.createAnalyser();
                     audioBufferSourceNode = audioContext.createBufferSource();
	                 audioBufferSourceNode.connect(analyser);
                     analyser.connect(audioContext.destination);
	                 audioBufferSourceNode.buffer = buffer;
	                 audioBufferSourceNode.start(0);

					audioBufferSourceNode.onended = function() {
    
    
						isplay = false;
						cancelAnimationFrame(req);
					};
}

最后一步下载,说实话 这个方法还没有下来分析,只是从 google 找到了对应的方式
里面应该也有很多参数值得去研究


    function bufferToWave(abuffer, len) {
    
    
        var numOfChan = abuffer.numberOfChannels,
            length = len * numOfChan * 2 + 44,
            buffer = new ArrayBuffer(length),
            view = new DataView(buffer),
            channels = [], i, sample,
            offset = 0,
            pos = 0;
      
        // write WAVE header
        setUint32(0x46464952);                         // "RIFF"
        setUint32(length - 8);                         // file length - 8
        setUint32(0x45564157);                         // "WAVE"
      
        setUint32(0x20746d66);                         // "fmt " chunk
        setUint32(16);                                 // length = 16
        setUint16(1);                                  // PCM (uncompressed)
        setUint16(numOfChan);
        setUint32(abuffer.sampleRate);
        setUint32(abuffer.sampleRate * 2 * numOfChan); // avg. bytes/sec
        setUint16(numOfChan * 2);                      // block-align
        setUint16(16);                                 // 16-bit (hardcoded in this demo)
      
        setUint32(0x61746164);                         // "data" - chunk
        setUint32(length - pos - 4);                   // chunk length
      
        // write interleaved data
        for(i = 0; i < abuffer.numberOfChannels; i++)
          channels.push(abuffer.getChannelData(i));
      
        while(pos < length) {
    
    
          for(i = 0; i < numOfChan; i++) {
    
                 // interleave channels
            sample = Math.max(-1, Math.min(1, channels[i][offset])); // clamp
            sample = (0.5 + sample < 0 ? sample * 32768 : sample * 32767)|0; // scale to 16-bit signed int
            view.setInt16(pos, sample, true);          // write 16-bit sample
            pos += 2;
          }
          offset++                                     // next source sample
        }
      
        // create Blob
        return new Blob([buffer], {
    
    type: "audio/wav"});
      
        function setUint16(data) {
    
    
          view.setUint16(pos, data, true);
          pos += 2;
        }
      
        function setUint32(data) {
    
    
          view.setUint32(pos, data, true);
          pos += 4;
        }
      }

到此我觉得比较重要的几点代码已经贴出来了,目前下载下的音频格式文件较大,应该跟我所说的参数设置有关系在这里插入图片描述
大概一分钟10MB的样子。后面有时间再跟大家一块聊,拜了个拜~~
(更正下 具体大小根据音频的数据决定)

猜你喜欢

转载自blog.csdn.net/uk_51/article/details/106882352
今日推荐