wavesurfer
JS 音频可视化插件Wavesurfer.js的使用教程
Wavesurfer.js音频播放器插件的使用教程
wavesurfer.js使用搭配vue
在:
组件:
src\components\music\mymusic.vue
父
src\views\video\videodemo.vue
<el-card class="waveform-warp" style="background-color: #ffffff">
<div id="waveform" />
<div id="wave-timeline" />
</el-card>
waveform对应1
wave-timeline对应2
<script>
import '@/assets/zy_icon/iconfont.css'
import WaveSurfer from 'wavesurfer.js'
import SpectrogramPlugin from 'wavesurfer.js/src/plugin/spectrogram'
import CursorPlugin from 'wavesurfer.js/dist/plugin/wavesurfer.cursor.js'
import Timeline from 'wavesurfer.js/dist/plugin/wavesurfer.timeline.js'
import Regions from 'wavesurfer.js/dist/plugin/wavesurfer.regions.js'
export default {
name: 'Audio',
components: {},
props: {
url: {
type: String,
default: '',
},
showRound: {
type: Boolean,
default: true,
},
showCurrentTime: {
type: Boolean,
default: true,
},
showSpeed: {
type: Boolean,
default: true,
},
currentT: {
type: String,
},
},
data() {
return {
zoomValue: 100,
zoomMin: 100,
value: 0,
isPlay: false,
ppt: false,
appointTime: 1,
}
},
mounted() {
this.$nextTick(() => {
this.wavesurfer = WaveSurfer.create({
// 特别提醒:此处需要使用require(相对路径),否则会报错
container: '#waveform',
// 未播放的颜色
waveColor: '#FF55C5',
// 已播放的颜色
progressColor: '#00BFBF',
split: false,
minPxPerSec: 8,
height: 180,
barWidth: 1,
barHeight: 1.5,
splitChannels: false,
// 播放音频的速度
audioRate: '1',
plugins: [
// 时间轴插件
Timeline.create({
container: '#wave-timeline',
}),
// SpectrogramPlugin.create({
// container: '#wave-spectrogram',
// labels: true,
// colorMap: this.colorMap,
// }),
// 光标插件
CursorPlugin.create({
showTime: true,
opacity: 0.2,
customShowTimeStyle: {
'background-color': '#000',
color: '#fff',
padding: '2px',
'font-size': '10px',
},
}),
Regions.create(),
],
})
// 导入声音
// 特别提醒:此处需要使用require(相对路径),否则会报错
this.wavesurfer.load(require('@/assets/music/music.mp3'))
this.loading = false
console.log(this.wavesurfer)
// this.wavesurfer.load('mp3/demo.wav')
this.value = this.wavesurfer.getVolume() * 100
this.zoomValue = this.wavesurfer.params.minPxPerSec
this.zoomMin = this.wavesurfer.params.minPxPerSec
this.wavesurfer.zoom(Number(this.zoomValue))
this.wavesurfer.panner = this.wavesurfer.backend.ac.createPanner()
this.wavesurfer.backend.setFilter(this.wavesurfer.panner)
const _this = this
this.wavesurfer.on('ready', function () {
_this.wavesurfer.enableDragSelection({
color: _this.randomColor(0.1),
})
// 这里是自定义的划分区域
// _this.loadRegions(_this.noteData)
})
// 区域插件的region-click事件
this.wavesurfer.on('region-click', function (region, e) {
// 阻止事件冒泡
e.stopPropagation()
e.shiftKey ? region.playLoop() : region.play()
})
this.wavesurfer.on('region-click', this.editAnnotation)
this.wavesurfer.on('region-updated', this.saveRegions)
this.wavesurfer.on('region-removed', this.saveRegions)
this.wavesurfer.on('region-in', this.showNote)
this.wavesurfer.on('region-play', function (region) {
region.once('out', function () {
this.wavesurfer.play(region.start)
this.wavesurfer.pause()
})
})
})
},
methods: {
modeSwitch() {
this.modeValue = !this.modeValue
},
plays() {
this.isPlay = !this.isPlay
this.wavesurfer.playPause()
},
rew() {
this.wavesurfer.skip(-3)
},
speek() {
this.wavesurfer.skip(3)
},
replay() {
this.isPlay = false
this.wavesurfer.stop()
},
DoubleSpeed(c, o) {
this.wavesurfer.setPlaybackRate(c)
},
// 声道
channelsChange(value) {
const _this = this
console.log(value)
switch (value) {
case 'dbChannels':
_this.wavesurfer.panner.setPosition(0, 0, 0)
break
case 'leftChannels':
_this.wavesurfer.panner.setPosition(-0.7, 0, 0)
break
case 'rightChannels':
_this.wavesurfer.panner.setPosition(0.7, 0, 0)
break
}
},
// 缩放百分比显示格式
formatZoom(val) {
return val + 100 + ' 像素 / 秒'
},
// 缩放监听
zoomChange() {
this.wavesurfer.zoom(Number(this.zoomValue))
},
// 新建
saveRegions() {
const _this = this
this.noteData = Object.keys(_this.wavesurfer.regions.list).map(function (
id
) {
console.log(id)
const region = _this.wavesurfer.regions.list[id]
// _this.noteForm.id = id
// _this.noteForm.edit = false
// _this.noteForm.startTime = Math.round(region.start * 10) / 10
// _this.noteForm.endTime = Math.round(region.end * 10) / 10
// _this.noteForm.data.note = region.data.note || ''
return {
id: id,
edit: false,
start: Math.round(region.start * 10) / 10,
end: Math.round(region.end * 10) / 10,
attributes: region.attributes,
data: { note: region.data.note || '' },
}
})
},
// 从localStorage加载区域
loadRegions(regions) {
const _this = this
regions.forEach(function (region) {
region.color = _this.randomColor(0.1)
_this.wavesurfer.addRegion(region)
})
},
// RGB颜色生成器
randomColor(alpha) {
return (
'rgba(' +
[
~~(Math.random() * 255),
~~(Math.random() * 255),
~~(Math.random() * 255),
alpha || 1,
] +
')'
)
},
// 编辑保存
editAnnotation(region) {
console.log("region:",region)
this.onSaveNote = function (row) {
row.edit = false
region.update({
start: Math.round(region.start * 10) / 10,
end: Math.round(region.end * 10) / 10,
data: {
note: row.note || '',
},
})
}
},
showNote(region) {
if (!this.showNote.el) {
this.showNote.el = document.querySelector('#subtitle')
}
this.showNote.el.textContent = region.data.note || '–'
},
onSaveNote(row) {
row.edit = !row.edit
const region = this.wavesurfer.regions.list[row.id]
console.log(row.data.note)
region.update({
start: row.start,
end: row.end,
data: {
note: row.data.note || '',
},
})
},
onDeleteNote() {},
// 音量
setVolume(val) {
this.wavesurfer.setVolume(val / 100)
},
formatS(s) {
const minute = Math.floor(s / 60)
const second = Math.floor(s - minute * 60)
const centisecond = Math.floor((s - minute * 60 - second) * 100)
return (
(minute.toString().length === 1 ? '0' + minute : minute) +
':' +
(second.toString().length === 1 ? '0' + second : second) +
':' +
centisecond +
"'"
)
},
// 指定播放
appointPlay() {
this.isPlay = true
this.wavesurfer.play([this.currentT])
},
submitAnswer() {},
},
}
</script>
// 区域插件的region-click事件
this.wavesurfer.on('region-click', function (region, e) {
// 阻止事件冒泡
e.stopPropagation()
e.shiftKey ? region.playLoop() : region.play()
})
注意,这里的 ‘region-click’ 不是指点击波形图,而是先选中区域:
然后点击区域中才会触发
参考资料:
wavesurfer官网
Wavesurfer.js音频播放器插件的使用教程
浅析wavesurfer.js中各大方法的使用
实现点击某处,就定位,并根据isPlay决定是否播放
this.$nextTick(() => {
this.wavesurfer = WaveSurfer.create({
// 特别提醒:此处需要使用require(相对路径),否则会报错
container: '#waveform',
// 未播放的颜色
waveColor: '#FF55C5',
// 已播放的颜色
progressColor: '#00BFBF',
split: false,
minPxPerSec: 8,
height: 180,
barWidth: 1,
barHeight: 1.5,
splitChannels: false,
// 播放音频的速度
audioRate: '1',
plugins: [
// 时间轴插件
Timeline.create({
container: '#wave-timeline',
}),
// SpectrogramPlugin.create({
// container: '#wave-spectrogram',
// labels: true,
// colorMap: this.colorMap,
// }),
// 光标插件
CursorPlugin.create({
showTime: true,
opacity: 0.2,
customShowTimeStyle: {
'background-color': '#000',
color: '#fff',
padding: '2px',
'font-size': '10px',
},
}),
Regions.create(),
],
})
// 导入声音
// 特别提醒:此处需要使用require(相对路径),否则会报错
this.wavesurfer.load(require('@/assets/music/music.mp3'))
this.loading = false
console.log(this.wavesurfer)
// this.wavesurfer.load('mp3/demo.wav')
this.value = this.wavesurfer.getVolume() * 100
this.zoomValue = this.wavesurfer.params.minPxPerSec
this.zoomMin = this.wavesurfer.params.minPxPerSec
this.wavesurfer.zoom(Number(this.zoomValue))
this.wavesurfer.panner = this.wavesurfer.backend.ac.createPanner()
this.wavesurfer.backend.setFilter(this.wavesurfer.panner)
const _this = this
this.wavesurfer.on('ready', function () {
_this.wavesurfer.enableDragSelection({
color: _this.randomColor(0.1),
})
// 这里是自定义的划分区域
// _this.loadRegions(_this.noteData)
})
// 光标移动后播放
this.wavesurfer.on('seek', () => {
if (this.isPlay) {
this.wavesurfer.play()
}
})
// console.log(this.wavesurfer.getCurrentTime())
/** audioprocess,获取当前时间 */
this.wavesurfer.on('audioprocess', () => {
this.currentTime = this.changeTime(this.wavesurfer.getCurrentTime())
})
// 区域插件的region-click事件
// 选中了区域的点击才会触发
this.wavesurfer.on('region-click', function (region, e) {
// 阻止事件冒泡
e.stopPropagation()
e.shiftKey ? region.playLoop() : region.play()
})
this.wavesurfer.on('region-click', this.editAnnotation)
this.wavesurfer.on('region-updated', this.saveRegions)
this.wavesurfer.on('region-removed', this.saveRegions)
this.wavesurfer.on('region-in', this.showNote)
this.wavesurfer.on('region-play', function (region) {
region.once('out', function () {
this.wavesurfer.play(region.start)
this.wavesurfer.pause()
})
})
})
主要是这个:
// 光标移动后播放
this.wavesurfer.on('seek', () => {
if (this.isPlay) {
this.wavesurfer.play()
}
})
实现根据自定义 currentTime 播放某处
watch: {
currentT(val, oldVal) {
//普通的watch监听
console.log('currentT: ' + val)
this.currentTime = this.currentT
this.appointPlay()
},
},
// 指定播放
appointPlay() {
this.isPlay = true
this.wavesurfer.play([this.currentT])
},
固定只一个region
Question: Limit the number of regions to one?
this.wavesurfer.on('region-created', () => {
this.wavesurfer.clearRegions()
})
遍历object
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>淡入</el-dropdown-item>
<el-dropdown-item>淡出</el-dropdown-item>
<el-dropdown-item>速度</el-dropdown-item>
<el-dropdown-item @click.native="channelsLeft">左声道</el-dropdown-item>
<el-dropdown-item @click.native="channelsRight">右声道</el-dropdown-item>
<el-dropdown-item @click.native="channelsDouble">双声道</el-dropdown-item>
</el-dropdown-menu>
要加一个native才可以触发成功
@click.native="channelsRight"
也许可以借鉴的
所有的基本操作都放在了audiomass的action.js中
录音
vue实现录音功能js-audio-recorder带波浪图
load加载
1、如果已经提取出了音频的,就直接加载,这个时候url已经有值
2、如果没提取的,就是url为空,暂时不加载,监听url变化,一有就开始加载,配合v-show不是v-if
Vue监听空格
主要通过:
document.onkeydown = (e) => {} 来监听,32对于空格
不再监听,就document.onkeydown = ‘’
openListen() {
console.log('1')
if (this.keyFrameFlag) {
document.onkeydown = (e) => {
let key = window.event.keyCode
if (key == 32) {
//== 83 && event.ctrlKey
window.event.preventDefault() //关闭浏览器快捷键
this.keyFrameSpace() //;saveProject1()
}
}
} else {
document.onkeydown = ''
}
},
// 空格监听,选区域
keyFrameSpace() {
// 判断是否在播放
var flag = this.wavesurfer.isPlaying()
console.log(flag)
if (flag) {
// 获取当前时间点
var cTime = this.wavesurfer.getCurrentTime()
var cTimeStr = this.format(cTime)
var len = this.regiontime.length
if (len <= 1) {
this.regiontime.push(cTimeStr)
} else {
this.regiontime.splice(0, 1, this.regiontime[1])
this.regiontime.splice(1, 1, cTimeStr)
}
len = this.regiontime.length
if (len == 2) {
this.createRegion()
}
console.log(this.regiontime)
} else {
this.$message({
message: '请先播放',
type: 'warning',
duration: 1000,
})
}
},
SpeechSynthesizer (可以网页读文本)
System.Speech.Synthesis 保存合成语音