主要工具:wavesurfer.js

通过Web Audio Api 来对音频进行处理。

文档资料:

Web Audio API
AudioMass源码
AudioMass在线网页 (这个AudioMass编辑器跟一些专业的音频编辑器相比,还是差了很多东西)
Web Audio 简易教程 (没了解过WebAudio的瞧瞧这个~)

AudioMass源码目录结构:
index.html引入文件:
各种音频效果的数据计算 —去看–>actions.js文件最下面var FXBank = {...这里面的内容...}

<!-- 根据音频文件绘制音频波形图 -->
<script src="dist/wavesurfer.js"></script>
<!-- 绘制音频波形图选框 -->
<script src="dist/plugin/wavesurfer.regions.js"></script>
<!-- 创建dom元素(传入内容,时间,类名),插入document -->
<script src="oneup.js"></script>
<!-- 音频编辑器实例 -->
<script src="app.js"></script>
<!-- 音频编辑器按键事件监听 -->
<script src="keys.js"></script>
<!-- 创建编辑器菜单 -->
<script src="contextmenu.js"></script>
<!-- 菜单栏点击后的弹窗 -->
<script src="ui-fx.js"></script>
<!-- 创建菜单栏 -->
<script src="ui.js"></script>
<!-- 弹窗等通用组件模型封装 -->
<script src="modal.js"></script>
<!-- 对操作进行历史记录 -->
<script src="state.js"></script>
<!-- 音频处理总的逻辑方法 -->
<script src="engine.js"></script>
<!-- 音频处理具体实现方法 -->
<script src="actions.js"></script>
<!-- 文件拖拽功能 -->
<script src="drag.js"></script>
<!-- 录音机功能 -->
<script src="recorder.js"></script>
<!-- 欢迎页面弹窗 -->
<script src="welcome.js"></script>
<!-- 麦克风录音 -->
<script src="fx-pg-eq.js"></script>
<!-- 源码里没有使用,注释了 -->
<script src="fx-auto.js"></script>
<!-- 本地存储功能 -->
<script src="local.js"></script>
<!-- 音频文件信息ID3解析 -->
<script src="id3.js"></script>
<!-- 实现编码/解码 LZ4 格式 -->
<script src="lzma.js"></script>

各个功能模块实现:

1. 下载音频

格式: mp3, wav(44100hz)
比特率:128kbps 192kbps 256kbps
声道:Mono 单声道 Stereo 立体声
范围:导出全部/选中部分

方法使用Worker创建后台任务将音频转换为二进制流,拿到blob url后,通过a标签进行下载。

2. 音频导入

2-1、 本地文件夹上传/url输入

const wavesurfer = WaveSurfer.create ({container: '#waveform', // dom容器scrollParent: false, // 是否滚动长波形容器hideScrollbar:true, // 是否隐藏滚动条partialRender:false, // 是否缓存解码的峰值数据以提高波形渲染速度fillParent:false, // 是否填充整个容器还是根据音频每秒最小像素数minPxPerSec绘制pixelRatio:1, // 像素比progressColor:'rgba(255,0,0,0.8)', splitChannels: true, // 是否渲染多声道autoCenter:true, // 如果有滚动条,则波形居中放置height:w.innerHeight - 168, // 波形高度plugins: [    // 注册插件WaveSurfer.regions.create({  // 波形区域选框插件dragSelection: {slop: 5}})]
});// 音频url导入
wavesurfer.load(url, peaks, preload)
// 音频Blob or File 导入
wavesurfer.loadBlob(url)

2-2、打开已保存的音频

2-3、 麦克风录音

使用MediaDevices.getUserMedia()拿到录音设备音频流。

3. 编辑

3-1、翻转通道 flip

方法概述:通过Web Audio Api 中的AudioBuffer.getChannelData() 分别拿到左右声道的Float32Array格式数据,循环依次替换左右声道的数据,来实现左右声道的翻转。
原始:

flip:

示例代码:

if (val === 'flip')
{const chan0 = source.buffer.getChannelData (0);const chan1 = source.buffer.getChannelData (1);const tmp   = 0;for (let j = 0; j < chan0.length; ++j){tmp = chan0[j];chan0[j] = chan1[j];chan1[j] = tmp;}
}

3-2、播放/暂停

示例代码:

// 暂停
wavesurfer.stop ();
// 播放
wavesurfer.play ();

3-3、全选/取消全选/选取片段

使用wavesurfer的插件Regions
示例代码:

// 绘制全选框, 同选取片段
wavesurfer.regions.add({start:0.000,end:wavesurfer.getDuration() - 0.00,id:'t'
});
// 取消全选框
wavesurfer.regions.clear ();

3-4、单次/循环播放

wavesurfer.seekTo( val );跳转进度。

3-5、播放进度:前进/后退,开头/末尾

前进:wavesurfer.skipForward ( val );
后退:wavesurfer.skipBackward ( val );
开头/末尾: wavesurfer.seekTo( val );

3-6、拷贝/粘贴/裁剪/静音

拷贝

// 拿到选中段落的开始和结束时间
const region = wavesurfer.regions.list[0];
const start = q.TrimTo (region.start, 3);
const end = q.TrimTo ((region.end - region.start), 3);// 拿到拷贝的数据
function CopyBufferSegment( _offset, _duration ) {const originalBuffer = wavesurfer.backend.buffer;const new_len    = ((_duration/1) * originalBuffer.sampleRate) >> 0;const new_offset = ((_offset/1)   * originalBuffer.sampleRate) >> 0;const emptySegment = wavesurfer.backend.ac.createBuffer (wavesurfer.SelectedChannelsLen,new_len,originalBuffer.sampleRate);for (let i = 0, u = 0; i < wavesurfer.ActiveChannels.length; ++i) {if (wavesurfer.ActiveChannels[ i ] === 0) continue;emptySegment.getChannelData ( u ).set (originalBuffer.getChannelData ( i ).slice ( new_offset, new_len + new_offset ));++u;}return (emptySegment);
};

粘贴/裁剪/静音:同 4-14、插入/移除静音(Insert/Remove Silence)

4. 效果

4-1、设置音量大小(Gain)

方法概述:通过BaseAudioContext.createGain() 创建GainNode。通过GainNode提供的方法设置音量大小。
原始:

设置音量0.5倍:

示例代码:

const gain = audio_ctx.createGain ();
// curr.val:音量大小0 - 1
gain.gain.setValueAtTime ( curr.val, audio_ctx.currentTime );

4-2、淡入/淡出

原图----淡入-----淡出

方法概述:使用AudioParam.linearRampToValueAtTime() 来实现音量的淡入淡出。
示例代码:

const gain = audio_ctx.createGain ();
// 淡入
gain.gain.setValueAtTime (0, audio_ctx.currentTime);
gain.gain.linearRampToValueAtTime (1, audio_ctx.currentTime + duration/1);
// 淡出
gain.gain.setValueAtTime (1, audio_ctx.currentTime);
gain.gain.linearRampToValueAtTime (0, audio_ctx.currentTime + duration/1);

4-(3,4)、 均衡器

在介绍参数均衡器和图形均衡器之前,需要先了解下均衡器。
均衡器,指通过调节输入信号不同频率成分的振幅来达到对声音的修饰,补偿等作用。本质就是:分析出声音的各个频率段,再对每个频段的音量进行调整。

因为,一个声音是混杂着低频,中频和高频。如果直接调节音量,那么这三个频率的音量都会被一起调节。

调节参数如下:
ⅰ. Type (模式)
ⅱ. Freq(频点)
ⅲ. Gain(增益)
ⅳ. Q(影响范围)

1. Type (模式)
声音可分为四部分:Low(低频80Hz—350Hz)、Low Mid(中低频350Hz—2000Hz)、High Mid(中高频2000Hz—6000Hz)、High(高频6000Hz—12000Hz)
2. Freq(频点)
可以直接在均衡器图中左右移动鼠标来修改频点,用来标明中心频率。
3. Gain(增益)
用于把设定好的频点提升或衰减多少音量。
4. Q(影响范围)
表示你要进行增益或衰减的频段的宽度。
Q值越大,频段越窄。Q值越小,频段越宽。

参考资料:
EQ调节介绍以及Cubase中的EQ处理方法及操作
Au中的EQ处理方法——图形均衡器和参数均衡器

4-3、参数均衡器(paragraphic EQ) (注意区分,参数均衡器和图形均衡器)

用参数均衡器处理的音频在各频段衔接的连续性较好。
如下图:左右两边各有一个滑块,分别控制低通和高通的提升衰减量。

如下图:横坐标为频率,纵坐标为音量
高通:频率5800Hz,影响范围5.8,比这个频点高的都通过,低的全部切掉。
低通:频率7060Hz,影响范围5,比这个频点低的区域都通过,高的全部切掉。

原始音波图:

如上图配置后音波图:

代码示例:自己看源码~

4-4、图形均衡器(Graphic EQ)注意区分,参数均衡器和图形均衡器

图形均衡器通常由一组用于增强或削减固定频带的滑块控件组成,如下图,可以直接通过拖拽按钮来调整对应频率的音量。
图形均衡器的Q值和频率都是固定的,有10段,20段和30段,按自己的喜好使用。30段划分的频率段最细。
图形均衡器10段:

图形均衡器20段:

一般来讲,100Hz以下是噪音,如果一开始去除了底噪,就不需要在EQ中修改噪音。
提升125Hz和200Hz的频率可以使人声变得浑厚低沉。
提升1kHz以上的频率会使声音变得明亮、空旷,但提升太多会带来磁带般尖锐的感觉,且同时会加大嗡嗡的噪音声。
所以尽量不要将EQ调整的太多,以防声音失真,适当的提升声音中不足的成分即可。

代码示例:同 4-3、参数均衡器(paragraphic EQ)
参考资料:什么是图形均衡器

4-5、音频/音量标准化(Normalize)

最大不失真音量,将当前波形振幅值的最大值调整到最大电平规定的值内。
可分为:对左右声道分别计算比例进行标准化 和 对左右声道计算总的比例进行标准化。
方式概述:
通过AudioBuffer.getChannelData() 拿到声道数据,循环数据获取最大值,根据normalize值计算得到调整比例。循环音频数据乘与调整比例,最后得到标准化后的音频数据。

代码示例:

// 输入的调整大小
const max_val = val[1] || 1.0;
// 双声道是否一起计算调整比例
const equally = val[0];
// 最大峰值
const max_peak = 0;for (let i = 0; i < source.buffer.numberOfChannels; ++i) {const chan_data = source.buffer.getChannelData (i);// 取间隔10 以加速计算for (let k = 1, len = chan_data.length; k < len; k = k + 10) {const curr = Math.abs ( chan_data [ k ] );if (max_peak < curr)max_peak = curr;}const diff = max_val / max_peak;if (!equally) {for (let k = 0, len = chan_data.length; k < len; ++k) {chan_data[ k ] *= diff;}max_peak = 0;}
}if (equally) {const diff = max_val / max_peak;for (let i = 0; i < source.buffer.numberOfChannels; ++i) {const chan_data = source.buffer.getChannelData (i);for (let k = 0, len = chan_data.length; k < len; ++k) {chan_data[ k ] *= diff;}}
}

4-6、压缩器(Compressor)

压缩器有6个参数,前4个跟效果相关,后2个跟时间相关。
ⅰ. 门限(Threshold)压缩器的工作起点。只有当电平超过门限后,压缩器才会开始工作。
ⅱ. 压缩比(Ratio)压缩器以什么样的量来压缩超过门限的电平。
ⅲ. 提升(Make up)是将电平整体提升。因为压缩在工作的过程中的原理是将高于门限的电平压低,因此肯定会不可避免地降低整体的音量。为了让音量的平均值恢复到原本的听觉水平甚至更高,我们就要使用Make up 将所有电平共同提升。
ⅳ. 拐点(Knee)在门限上下交界的地方,是以一种非黑即白的方式压缩,还是有一条渐进的曲线连接起压缩与不压缩的区间。
ⅴ. 启动时间(Attack)
当一个声音超过了Threshold的时候,压缩器并不是立刻把压缩作用在这些超过部分的信号上,压缩比例是在一段时间内一点一点增加到我们设定的值。这一段时间就是Attack。
ⅵ. 释放时间(Release)
同上,当声音回落到Threshold的时候,压缩效果也不是立刻停止,而是一点一点从最大压缩比例回落。这一段时间就是Release。

方法概述:
使用BaseAudioContext.createDynamicsCompressor() 设置相应属性
示例代码:

const compressor = audioCtx.createDynamicsCompressor();
compressor.threshold.setValueAtTime(-50, audioCtx.currentTime);
compressor.knee.setValueAtTime(40, audioCtx.currentTime);
compressor.ratio.setValueAtTime(12, audioCtx.currentTime);
compressor.attack.setValueAtTime(0, audioCtx.currentTime);
compressor.release.setValueAtTime(0.25, audioCtx.currentTime);

4-7、 强硬限制(Hard Limiting)

**也称限幅器,压限器,将声音信号限制在最大电平内。**
ⅰ. Limit
ⅱ. Ratio
ⅲ. 预测时间(Look Ahead)

解决的问题:对超出起奏时间设置的大声信号开始时可能出现的瞬时峰值进行处理。
延长预测时间会使压缩在音频变大声之前触发,从而确保振幅不会超过特定电平。相反的,要增强打击乐(如鼓乐)的效果,可能需要减少预测时间。

代码示例:

const max_val = 1;  // limit to
const ratio = 0.0;    // ratio
const look_ahead = 15; // ms
const max_peak = 0;const buffer = audio_ctx.createBuffer(source.buffer.numberOfChannels,source.buffer.length,source.buffer.sampleRate
);look_ahead = (look_ahead * buffer.sampleRate / 1000) >> 0; //  >> 0 取整数值for (let i = 0; i < buffer.numberOfChannels; ++i) {const chan_data = buffer.getChannelData(i);chan_data.set(source.buffer.getChannelData(i));for (let b = 0, len = chan_data.length; b < len; ++b) {for (let k = 0; k < look_ahead; k = k + 10) {const curr = Math.abs(chan_data[b + k]);if (max_peak < curr)max_peak = curr;}const diff = (max_val / max_peak);for (let k = 0; k < look_ahead; ++k) {const orig_val = chan_data[b + k];const new_val = orig_val * diff;let peak_diff = max_val - Math.abs(new_val);peak_diff *= orig_val < 0 ? -ratio : ratio;chan_data[b + k] = (new_val + peak_diff);}b += look_ahead;max_peak = 0;}
}

4-8、延时(Delay)

单纯的把音频重复播放,起到把声音延长和重复的作用。
注意区分:Delay(延时) 和 Reverb(混响)的区别。Reverb是制造出空间效果来。

代码示例:内容过多不贴,去看源码儿~

4-9、失真效果(Distortion)

输入和输出不相等,就代表信号出现了失真。
失真效果器
AudioContext.createWaveShaper()

Distortion音效参数有:edge(临界值), gain(增益),低通剪切值等。
AudioMass里失真效果只有gain参数。

方法概述:

const wave_shaper = audio_ctx.createWaveShaper ();
// val: [{val: 0.5}] Gain值
const compute_dist = function ( val ) {const gain = parseInt ( (val / 1) * 100, 10);const n_samples = 44100;const curve = new Float32Array (n_samples);const deg = Math.PI / 180;let x;for (let i = 0; i < n_samples; ++i ) {x = i * 2 / n_samples - 1;curve[i] = (3 + gain) * x * 20 * deg / (Math.PI + gain * Math.abs(x));}return (curve);
};for (let k = 0; k < val.length; ++k)
{const curr = val[k];if (curr.length){for (let i = 0; i < curr.length; ++i) {wave_shaper.curve.linearRampToValueAtTime (compute_dist(curr[i].val), audio_ctx.currentTime + curr[i].time);}}else{wave_shaper.curve = compute_dist (curr.val);}
}source.connect (wave_shaper);
wave_shaper.connect (destination);

4-10、混响(Reverb)

虚拟各种空间的特效:在一个大房间,大教堂,体育场或演唱会,各种不同环境造成的回音,空间感。
Reverb详细大解说

代码示例:内容过多不贴,去看源码儿~

4-11、倒置(Reverse)

 音频从后往前播放代码示例:
for (let i = 0; i < source.buffer.numberOfChannels; ++i) {Array.prototype.reverse.call( source.buffer.getChannelData (i) );
}

4-12、播放速度(Speed)

HTMLMediaElement.playbackRate
浮点数1.0 是 “正常速度”, 比 1.0 小的值使媒体文件播放的慢于正常速度,比1.0大的值使播放变得快于正常速度。

const val = 1.5; // 1.5倍速
source.playbackRate.value = val;

4-13、反相(Invert)

将波形中的采样数据点以横轴为对称轴反相。
反相前 -----> 反相后

for (let i = 0; i < source.buffer.numberOfChannels; ++i) {const channel = source.buffer.getChannelData (i);for (let j = 0; j < channel.length; ++j)channel[j] *= -1;
}

4-14、插入/移除静音(Insert/Remove Silence)

方法概述:创建一段静音音频数据插入到原音频数据指定位置
代码示例:

// 创建静音数据
function MakeSilenceBuffer ( _duration ) {const originalBuffer = wavesurfer.backend.buffer;const emptySegment = wavesurfer.backend.ac.createBuffer(originalBuffer.numberOfChannels,_duration * originalBuffer.sampleRate,originalBuffer.sampleRate);return (emptySegment);
}// 设置new_buffer为Wavesurfer渲染波形
wavesurfer.loadDecodedBuffer ( new_buffer );
// 波形图插入静音段落
wavesurfer.regions.clear();
wavesurfer.regions.add({start:dims[0], // 静音开始时间end:dims[1],   // 静音结束时间id:'t'
});

4-15、降噪

简易demo:
提取码:ytgl

二:视图

  1. Frequency Analyser(频率分析器)
    拿到wavesurfer.backend.FreqArr,用canvas绘制。

  2. Spectrum Analyser(频谱分析器)
    拿到wavesurfer.backend.FreqArr,用canvas绘制。

  3. Tempo Tools(节拍器)
    节拍器是一种规律发出声音的工具,用于帮助音乐人稳定拍速,也会运用在现场表演和录音室。
    打拍子的测量单位称为BPM(每分钟拍速),60BPM等于每秒打一拍,120BPM等于每秒打两拍。

  4. ID3 Tags (音频文件信息)
    音频文件格式结构

前端音频处理之AudioMass调研相关推荐

  1. 【page-monitor 前端自动化 上篇】初步调研

    转载文章:来源(靠谱崔小拽) 前端自动化测试主要在于:变化快,不稳定,兼容性复杂:故而,想通过较低的成本维护较为通用的自动化case比较困难.本文旨在通过page-monitor获取和分析dom结构, ...

  2. pcm转mp3_前端音频可视化——PCM数据解决方案

    一.概述 本文的需求来自于标注团队对于音频文件的标注,需要将音频准确定位到毫秒位置进行内容标注,方便团队训练Ai模型 而产品也对标注功能提出了三项不可妥协的需求: 1.波形图必须基于音频原WAV无损格 ...

  3. web前端-纯前端音频剪辑,vue音频编辑组件

    本文包含内容概述: 整理总结的音频相关资料 音频相关jsapi说明及示例 vue编写的组件及git项目地址 在线预览: http://123.57.178.145:5007/audio_edit/in ...

  4. 【css】前端换肤功能方案调研 css变量换肤实践

    场景:应用要做深浅两套主题,内嵌h5页面要根据用户当前选择的主题渲染对应的主题样式. 技术栈:vue-cli3 + less + Vant 接到需求后,上网调研了几种方案:切换className.切换 ...

  5. ffmpeg js转换音频_实践!实现纯前端下的音频剪辑处理

    前言 最近在做一个项目,需要对 webRTC 录制的音频进行处理,包括音频的裁剪.多音频合并,甚至要将某个音频的某一部分替换成另一个音频. 原本笔者打算将这件工作交给服务端去完成,但考虑,其实无论是前 ...

  6. 2021 大前端技术回顾及未来展望

    作者:腾讯 IMWeb 前端团队 2021 年大前端领域没有出现革命性的明星项目,但在各个细分的技术领域都有一定的拓展与深耕,有很多新技术或者新特性有望在 2022 年迎来爆发.在互联网 " ...

  7. 【今日头条】【抖音火山】前端开发实习生

    今日头条成立于2012年,致力于成为最懂你的信息平台,连接人与信息,促进内容的创作和交流.通过技术,来改变整个内容生产.消费领域. 5年的时间内,我们已经成为了一个估值过百亿美元,用户数亿,DAU过亿 ...

  8. vue 微信录音倒计时_vue的微信语音功能,录音+对接口返回amr音频播放-Go语言中文社区...

    vue的微信语音功能,录音+对接口返回amr音频播放 最近的新项目需要调用微信的录音功能,但是后台又不给音频转码,无奈之下就踏上了研究前端音频编码器这东西. 参考的GitHub仓库--Recorder ...

  9. 一个优秀的前端工程师年薪会有多少?

    用户体验为王,是互联网时代的座右铭.人们在享受互联网带来的便捷的同时也对互联网产品的用户体验有了更高的要求,这意味着前端开发人员也会有更多的挑战和机会.近几年,前端的框架类库层出不穷,正处于工程化的新 ...

最新文章

  1. Office 365管理员指引 9 ——Lync 自定义会议邀请
  2. “加班文化“到底是如何流行起来的
  3. 模板库 | 销售管理类报表,邀您提反馈
  4. 图像特征 可视化_使用卫星图像可视化建筑区域
  5. Linux性能调优集合
  6. 网页开发者模式调整到手机模式_苹果全球开发者大会将于6月22日召开 全线上模式...
  7. echarts自定义象形图,矢量图标
  8. 数列极限:无穷量与待定型
  9. 联想微型计算机装Win10,联想小新 潮5000重装win10系统教程
  10. 安卓开发日记1——虫虫新闻
  11. 运维自动化之-----ansible之intnet和http协议技术 (10)
  12. 软件测试必学的16个高频数据库操作及命令
  13. 山东大学项目实训开发日志——基于vue+springboot的医院耗材管理系统(4)
  14. signature=4a882a48c4a4b2b41835e11b6fafa69f,ABB 38SC980002R375
  15. 学计算机买电脑显卡1605ti够吗,GTX1650和GTX1050Ti哪个好?GTX1050ti和GTX1650性能差距对比评测...
  16. pytorch中tensor转numpy
  17. 将csv格式转换为excel后缀为xlsx
  18. 前端中push数组元素到新数组方法
  19. 在家做什么兼职最靠谱?不去上班做什么好?
  20. gm220s路由器怎么设置_二级路由器怎么设置_二级路由器设置图解教程-192路由网...

热门文章

  1. 利用计算机将一种自然语言,()是利用计算机将一种自然语言(源语言)转换为另一种自然语言(目标语言)的过程。...
  2. 2018计算机专业高考人数,2018高考报名人数创八年来新高,高考竞争会越来越激烈吗?...
  3. Hyperlegder Fabric 1.4.4 手动搭建BYFN网络
  4. hyperledger fabric 网络操作基本操作和概念
  5. C语言写一个生日贺卡
  6. 人的气场是怎样炼成的
  7. 侯捷 C++内存管理 (一)
  8. 【Unity面试】 Lua语言基础核心 | 面试真题 | 全面总结 | 建议收藏
  9. 特朗普将接管奥巴马所有社交网络账号 继承上千万粉丝
  10. 20221208 QT----新建工程