wavesurfer.js是基于Web Audio API 和HTML5 Canvas实现的一个可定制化的音频波形可视化组件,在需要音频波形展示及音频波形交互的场景有广泛的应用。本文经过实践之后,通过官方文档的翻译以及自己的理解做了一个整理工作(接下来还会有具体实践相关的详细文章出来)
1. 使用场景
在某些需要对音频进行波形展示及交互的场景如:
支持音频波形展示
- 可以对波形进行选择并填写标注信息
- 随意修改或者拖动选中波形区间
- 支持打标数据反向渲染波形,并可以修改已打标数据
经过调研之后,发现wavesurfer.js是一款应用十分广泛并且强大、可灵活定制的音频波形可视化组件,可以完全满足我们的音频打标组件需求。
2. wavesurfer.js引入
1. script标签引入:
<script src="https://unpkg.com/wavesurfer.js"></script>
2. 一般我们推荐npm 安装引入:
npm install wavesurfer.js
复制代码
代码import:
import WaveSurfer from 'wavesurfer.js'
// 创建wavesurfer 实例
var wavesurfer = WaveSurfer.create({
container: '#waveform',
scrollParent: true
});
复制代码
3. wavesurfer介绍
通过其官方文档可以发现,wavesurfer 由一些创建实例时的选项(Options)、实例方法(Methods)、监听事件(Events)及一些插件(Plugins)组成。了解了这三点基本上就可以算是完全掌握了wavesurfer,可以来实现音频波形展示及交互的基本需求。
3.1 选项
Options 就是创建wavesurfer 实例时可以传的一些配置参数,通过create创建wavesurfer实例时传入,是对wavesurfer实例的一些基本设置,传入形式如下:
var wavesurfer = WaveSurfer.create({
container: this.$refs.wavesurfer,
progressColor: '#fff',
backend: 'MediaElement',
waveColor: '#666',
height: 80,
width: 400,
normalize: true,
mediaControls: true,
preload: true,
...
})
复制代码
选项参数如下:
option | type | default | description | |
---|---|---|---|---|
audioRate | float | 1 | 音频播放速度,数值越小越慢 | |
audioContext | object | none | 自己的音频上下文,可以类比于canvas中的context,其中包含一些列 | api,可以留空 |
audioScriptProcessor | object | none | 使用自己先前初始化的ScriptProcessorNode,就是自定义javaScript生成、处理或者分析音频 | |
autoCenter | boolean | true | 如果有滚动条,将波形根据进度居中 | |
backend | string | WebAudio | 可选WebAudio, MediaElement or MediaElementWebAudio. | |
backgroundColor | string | none | 波形图容器的背景色 | |
barGap | number | none | 波形条间距,如未提供将自动计算 | |
barHeight | number | 1 | 波形条的高度,大于1的数字将增加波形条的高度 | |
barMinHeight | number | null | 绘制波形条的最小高度,默认在静音期间不绘制波形条 | |
barRadius | number | 0 | 波形条的radius | |
barWidth | number | none | 如果指定,波形将如下展示: ▁ ▂ ▇ ▃ ▅ ▂ | |
closeAudioContext | boolean | false | 调用destroy方法时,关闭并取消所有音频上下文 | |
container | mixed | none | 音频 波形容器的CSS选择器或HTML元素,这是唯一必传的参数 | |
cursorColor | string | #333 | 光标的填充颜色,指示播放头的位置 | |
cursorWidth | integer | 1 | 光标宽度,单位pixels | |
drawingContextAttributes | object | {desynchronized: true} | 指定canvas 2d 绘图 上下文属性 | |
fillParent | boolean | true | 是否填充整个容器或仅根据 minPxPerSec进行绘制 | |
forceDecode | boolean | false | 缩放以获得更详细的波形时,是否使用web音频强制解码音频 | |
height | integer | 128 | 波形的高度,以像素为单位 | |
hideScrollbar | boolean | false | 是否隐藏水平滚动条 | |
interact | boolean | true | 初始化时是否启用鼠标交互。之后可以随时切换该参数 | |
loopSelection | boolean | true | (与区域插件一起使用)启用选定区域的循环 | |
maxCanvasWidth | integer | 4000 | 单个画布的最大宽度(以像素为单位),不包括小的重叠 (2 * pixelRatio,四舍五入到下一个偶数整数)。如果波形的长度大于此值,则将使用其他画布来渲染该波形,这对于非常大的波形很有用,对于浏览器而言太大的波形可能无法在单个画布上绘制,次参数用于 MultiCanvas 绘制 | |
mediaControls | boolean | false | (与 MediaElement一起使用) 为true则将启动媒体元素的本机控件 | |
mediaType | string | audio | 'audio' 或者 'video'. 与 MediaElement一起使用 | |
minPxPerSec | integer | 50 | 音频每秒最小像素数 | |
normalize | boolean | false | 如果为true,则以最大峰值而非1.0进行归一化 | |
partialRender | boolean | false | 使用PeakCache改善大波形的渲染速度. | |
pixelRatio | integer | window.devicePixelRatio | 可以设置为1以加快渲染速度 | |
plugins | array | [] | 实例化期间要注册的一组插件定义。除非将 deferInit 属性设置为 true.否则他们将被直接初始化 | |
progressColor | string | #555 | 光标后面的波形部分的填充色.当 progressColor 和 waveColor 一样时完全不渲染进度波. | |
regionsMinLength | number | null | 区域的默认 minLength 以秒为单位.创建区域时,为该区域指定 minLength 将覆盖此参数 | |
removeMediaElementOnDestroy | boolean | true | 为false时当player被销毁时在DOM中保留media 元素.通过loadMediaElement方法重用现有媒体元素时,此功能很有用 | |
renderer | Object | MultiCanvas | 可用于注入自定义渲染器. | |
responsive | boolean or float | false | 如果为 true ,则在调整窗口大小时,调整波形大小,默认情况下会以每100ms去抖,如果此参数传入的是数字则表示去抖的时间频率 | |
scrollParent | boolean | false | 是否以较长的波形滚动容器,否则波形将缩小到容器的宽度 (参考参数 fillParent). | |
skipLength | float | 2 | 使用 skipForward() 和 skipBackward() 方法跳过的秒数. | |
splitChannels | boolean | false | 对于不同通道的音频使用分开的波形渲染 | |
splitChannelsOptions | object | {} | 分离音频通道的选项. 仅在 splitChannels=true时有效.请参阅下面的选项. | |
splitChannelsOptions.overlay | boolean | false | 叠加通道的波形,而不是在单独的行上渲染它们 | |
splitChannelsOptions.relativeNormalization | boolean | false | 归一化可保持通道之间的比例,仅在 normalize=true 时适用 | |
splitChannelsOptions.filterChannels | array | [] | 从渲染波形中排除的通道号列表. 通道以0开始索引 | |
splitChannelsOptions.channelColors | object | {} | 覆盖每个通道的颜色,每个key指示一个通道号,而对应的值是一个描述其颜色特征的对象.例如: channelColors={ 0: { progressColor: 'green', waveColor: 'pink' }, 1: { progressColor: 'orange', waveColor: 'purple' } } | |
waveColor | string | #999 | 光标后的波形填充颜色. | |
xhr | Object | {} | XHR 选项. 例如: let xhr = { cache: 'default', mode: 'cors', method: 'GET', credentials: 'same-origin', redirect: 'follow', referrer: 'client', headers: [ { key: 'Authorization', value: 'my-token' } ]}; (因为音频波形的解析是要发异步请求的,所以可能存在一些网络请求的问题需要设置的,这个选项就可以用到) |
3.2 方法
创建完wavesurfer实例之后,就可以通过创建的实例来调用这些方法了。下面梳理了所有方法及其含义和用法。
- cancelAjax() – 取消音频文件加载过程.
- destroy() – 移除事件、 元素 以及 断开Web Audio节点的连接.
- empty() – 清空波形.
- getActivePlugins() – 返回当前已初始化插件的map.
- getBackgroundColor() –返回波形容器的背景色.
- getCurrentTime() – 以秒为单位返回当前进度.
- getCursorColor() – 返回指示播放头位置的光标填充颜色.
- getDuration() – 返回音频的时长.
- getPlaybackRate() – 返回音频片段的播放速度.
- getProgressColor() – 返回光标后面波形的填充颜色.
- getVolume() – 返回当前音频段的音量.
- getMute() – 返回当前的静音状态.
- getFilters() – 返回当前设置的过滤器数组.
- getWaveColor() –返回光标后的波形填充颜色.
- exportPCM(length, accuracy, noWindow, start) –导出 PCM data 为一个json数组. 参数: length [number] - default: 1024, accuracy [number] - default: 10000, noWindow [true|false] - default: false, start [number] - default: 0
- exportImage(format, quality, type) – 以data URI 或 Blob的方式返回波形图的图片.
- isPlaying() – 返回当前是否正在播放.
- load(url, peaks, preload) – 加载音频URL 通过 XHR. 可选的参数:峰值 peaks 数组,preload [none|metadata|auto], 如果使用MediaElement将传给Audio元素.
- loadBlob(url) –通过 Blob 或 File 对象加载音频.
- on(eventName, callback) – 事件监听. 参考 WaveSurfer Events 查看所有事件列表.
- un(eventName, callback) – 取消事件监听.
- unAll() – 取消所有事件监听.
- pause() – 暂停.
- play([start[, end]]) – 从当前位置播放.可选的以秒为单位的开始和结束可用于设置要播放的音频范围.
- playPause() – 如果处于暂停状态就播放, 如果处于播放状态就暂停.
- seekAndCenter(progress) – 进度跳转并居中当前进度试图居中(0 = beginning, 1 = end).
- seekTo(progress) – 进度跳转 (0 = beginning, 1 = end).
- setBackgroundColor(color) – 设置波形容器的背景色.
- setCursorColor(color) – 设置播放光标的背景色.
- setHeight(height) – 设置波形高度.
- setFilter(filters) - 用于将自己的WebAudio 节点插入图中. 具体见Connecting Filters .
- setPlaybackRate(rate) – 设置重放速度 (0.5 半速, 1 正常速度, 2 倍速 如此类推).
- setPlayEnd(position) – 设置以秒为单位的播放暂停点.
- setVolume(newVolume) – 设置播放音量[0..1] (0 静音, 1 最高音量).
- setMute(mute) – 将当前声音静音,布尔值true静音,false取消静音.
- setProgressColor(color) – 设置光标前面波形的填充颜色.
- setWaveColor(color) – 设置光标后面波形的填充颜色.
- skip(offset) – 从当前位置跳过几秒钟(使用负值像后移动)
- skipBackward() - 倒带跳过的 skipLength 的秒数.
- skipForward() - 向前跳过的 skipLength 的秒数.
- setSinkId(deviceId) - 设置接收器ID以更改音频输出设备.
- stop() – 暂停并回到起点.
- toggleMute() – 切换声音开关.
- toggleInteraction() – 切换鼠标交互开关.
- toggleScroll() – 切换 scrollParent.
- zoom(pxPerSec) – 水平放大或缩小波形,参数是每秒音频的水平像素,设置这个会更改参数minPxPerSec 并启用scrollParent选项
3.3 事件
wavesufer同样提供了很多事件,供我们再不同场景灵活使用。事件的订阅和取消订阅通过on()和un()
wavesurfer.on('pause', function () { wavesurfer.params.container.style.opacity = 0.9; });
wavesufer所有事件如下:
- audioprocess – 音频进度监听,在音频播放时持续出发seeking时也会触发.
- dblclick – 当实例被双击时触发.
- destroy – 当实例被销毁时触发.
- error – 错误监听,出现错误时触发. 回调函数会将字符串类型的错误信息带回。.
- finish – 播放完成时触发.
- interaction – 与波形交互时触发.
- loading – 使用fetch、drag或drop的时候会持续触发. 回调函数将接收加载(整数)进度的百分比 [0..100].
- mute – 静音状态改变时触发. 回调接收新的静音状态.
- pause – 音频暂停时触发.
- play – 开始播放时触发.
- ready – 音频加载后,解码并绘制波形时触发. 在使用MediaElement时在波形绘制前触发, 详情参考waveform-ready.
- scroll - 当滚筒条移动时触发,回调接收ScrollEvent对象.
- seek – seeking时触发. 回调接收(浮点) 进度 [0..1].
- volume – 音量改变时触发. 回调接收 (整数) 新音量值.
- waveform-ready – 使用MediaElement时绘制波形之后触发; 如果使用的是WebAudio, 可以使用ready 监听.
- zoom – 波形缩放时触发. 回调函数将接收(整数) minPxPerSec值.
3.4 插件
到此其实就已经可以灵活使用wavesurfer来生成音频波形了。为了更好的用户体验wavesurfer还提供了很多插件来满足不同的需求,比如区域选择,时间线等。下面就就介绍一下常用的一些插件: Regions 、Timeline、Minimap、Cursor
如果要使用插件,首先需要引入插件,插件的引入如下
#html全局引入
<script src="https://unpkg.com/wavesurfer.js"></script>
<script src="https://unpkg.com/wavesurfer.js/dist/plugin/wavesurfer.minimap.min.js"></script>
#js动态引入
import MinimapPlugin from 'wavesurfer.js/dist/plugin/wavesurfer.minimap.min'
import CursorPlugin from 'wavesurfer.js/dist/plugin/wavesurfer.cursor.min'
import RegionsPlugin from 'wavesurfer.js/dist/plugin/wavesurfer.regions.min'
import TimelinePlugin from 'wavesurfer.js/dist/plugin/wavesurfer.timeline.min'
复制代码
并且在创建WaveSurfer实例的时候,需要引入plugins的配置。各种插件在被引入之后要在plugins参数里配置。如下:
var wavesurfer = WaveSurfer.create({
container: '#waveform',
plugins: [
WaveSurfer.regions.create({})
// TimelinePlugin.create({}) //按照import引入写法
]
});
复制代码
3.4.1 Regions 插件
Regions插件是通过在波形上叠加一层来标识用于循环播放的片段,可以拖动位置或者调整大小。可以感受一下官方提供的实例
3.4.1.1 直接添加到WaveSurfer实例上的方法
Regions提供一些直接添到WaveSurfer实例上的方法(也就是可以直接通过wavesurfer实例直接调用的方法):
addRegion(options) – 在波形上创建一个区域并返回一个Region对象.Region对象的属性参考下面的Region的选项, Region 的方法 和 Region的事件。(注意:在音频加载完成之前不能添加区域片段,否则新片段的start和end属性将被设置为0,或者一个意外的值) clearRegions() – 移除所有的region片段. enableDragSelection(options) – 允许在创建region片段的时候通过鼠标选择波形区域. options 参考下面的regions options的配置. 备注:通过 wavesurfer.regions.list可以获取所有的region列表。
如下代码,在创建完包含Regions插件的wavesurfer实例之后,就可以直接基于wavesurfer实例来调用上面的这些方法方法,如下示例:
var wavesurfer = WaveSurfer.create({
container: '#waveform',
plugins: [
WaveSurfer.regions.create({...regionsOptions})
]
});
//创建region
const curRegion = wavesurfer.addRegion({
start: 10,
end: 20,
loop: false,
drag: false,
resize: false,
color: 'rgb(217, 184, 241, 0.8)'
})
复制代码
3.4.1.2 Options选项
Region对象 有如下 options,在创建region实例的时候可以使用这些选项设置:
option | type | default | description |
---|---|---|---|
id | string | random | region 区域的id |
start | float | 0 | region 的开始时间(秒) |
end | float | 0 | region 的结束时间(秒) |
loop | boolean | false | 是否循环播放region. |
drag | boolean | true | 是否允许拖动region. |
resize | boolean | true | 是否允许调整区域大小. |
color | string | "rgba(0, 0, 0, 0.1)" | 区域的色值. |
minLength | number | null | 区域的最小长度 (单位秒). |
maxLength | number | null | 区域的最大长度(单位秒). |
3.4.1.3 Region实例的方法
通过addRegion创建的Region实例的方法。
- play() - 从头到尾播放region一次.
- playLoop() - 循环播放 该region.
- remove() - 移除该region.
- onDrag(timeInSeconds) -将 timeInSeconds值 做加法加到 start 和 end 参数上.
- onResize(timeInSeconds, 'start') - 默认将 timeInSeconds 加到 end 参数上. 可选参数'start' 会将 timeInSeconds 加到 start上去.
3.4.1.4 事件
每一个 region 对象 都有如下 事件:
一般事件:
- in - 当播放进入区域时。
- out - 当播放离开区域.
- remove - 区域被移除之前触发.
- update - 当区域的选项options被更新.
- update-end - 当dragging 或resizing 完成之后.
鼠标事件:
- click - 当鼠标点击区域时.回调将接收一个鼠标事件.
- dblclick - 双击区域时触发. 回调将接收一个鼠标事件.
- over -鼠标移动过该区域时触发.回调将接收一个鼠标事件.
- leave - 鼠标离开区域时触发.回调将接收一个鼠标事件.
WaveSurfer事件:
WaveSurfer 实例还会触发一组匹配事件(传递区域对象):
- region-created
- region-updated
- region-update-end
- region-removed
- region-play
- region-in
- region-out
- region-mouseenter
- region-mouseleave
- region-click
- region-dblclick
3.4.2 Timeline 插件
Timeline是给wavesurfer添加时间线
如图:
同Regions插件的引入,在创建Wavesurfer实例时需要引入插件,基本用法如下:
var wavesurfer = WaveSurfer.create({
container: '#waveform',
plugins: [
WaveSurfer.timeline.create({
container: "#wave-timeline"
})
]
});
复制代码
timeline的选项:
- container - 必传- 放置时间轴的元素,或用于查找它的 CSS 选择器
- height - 时间线的高度(以像素为单位)。默认值为 20.
- notchPercentHeight - 时间线中次要缺口线的高度(以百分比表示)。默认值为 90。
- primaryColor - 模十凹口线的颜色(例如 10 秒、20 秒)。默认值为“#000”。
- secondaryColor - 非模十凹口线的颜色. 默认值为'#c0c0c0'.
- primaryFontColor - 主要凹口旁边的标签颜色(例如 10 秒、20 秒)。默认值为“#000”。
- secondaryFontColor - 次要槽口旁边的标签颜色(例如 5 秒、15 秒)。默认值为“#c0c0c0”。
- timeInterval -number of intervals that records consists of. Usually it is equal to - the duration in minutes. (Integer or function which receives pxPerSec value and reurns value) (英文更好理解,暂不翻译)
- primaryLabelInterval - number of primary time labels. (Integer or function which - receives pxPerSec value and reurns value)
- secondaryLabelInterval - number of secondary time labels (Time labels between primary labels, integer or function which receives pxPerSec value and reurns value). (英文更好理解,暂不翻译)
- formatTimeCallback - 自定义时间格式回调。 (接收秒数并返回格式化字符串的函数)
- offset - 时间轴开始的偏移量(以秒为单位)。该值也可能为负数,默认为 0.
3.4.3 Minimap 插件
如图下图,为整个音频波形增加一个缩略图的展示,可以通过实例Minimap-demo来感受一下。
引入方式如下:
var wavesurfer = WaveSurfer.create({
// your options here
plugins: [
WaveSurfer.minimap.create({
container: '#wave-minimap', // 缩略图容器id
waveColor: '#777', //缩略图波形颜色
progressColor: '#222', //播放过的波形颜色
height: 50 //缩略图高度
})
]
});
复制代码
3.4.4 Cursor 插件
如图下图,Cursor插件主要用处是为wavesurfer增加鼠标位悬停处时间的展示如图:可以看到鼠标右边有展示当前位置的具体时间精确到毫秒数,也可以通过demo实际感受一下Cursor-demo
具体用法如下:
let wavesurfer = WaveSurfer.create({
container: document.querySelector('#waveform'),
plugins: [
WaveSurfer.cursor.create({
showTime: true, //是否显示时间
opacity: 1, //光标及时间整个组件的透明度
customShowTimeStyle: { //时间展示的设置
'background-color': '#000', //时间展示块的背景色
color: '#fff', //时间展示文字的颜色
padding: '2px', //时间展示块的padding
'font-size': '10px' //时间展示文字的font-size
}
})
]
});
复制代码
除了以上一些常用的插件,wavesurfer还有其它一些插件,如果有需要可以参考wavesurfer-js.org/plugins/
文章参考:wavesurfer-js.org/