前言
wavesurfer.js 是一个音频可视化插件,这里是一篇使用方式。
但wavesurfer.js不可直接load格式为pcm的音频文件。参考js转化pcm到wav格式与播放,wav格式实质在pcm格式前面加上44字节的文件头。这里加上文件头后由wavesurfer.js插件进行播放。
1.HTML
<!-- 时间线容器 --> <div id="timeline" ref="timeline" /> <!-- 音频容器 --> <div id="waveform" ref="waveform" /> <!-- 选择文件按钮 --> <input type="file" @change="addFile($event)" ref="file">
2. js
script标签里的内容
2.1 import
import WaveSurfer from ‘wavesurfer.js‘ import Timeline from ‘wavesurfer.js/dist/plugin/wavesurfer.timeline‘//Timeline插件 import Region from ‘wavesurfer.js/dist/plugin/wavesurfer.regions‘//regions插件
2.2 data
data () { return { url: ‘@/assets/music/ring.pcm‘, //wavesurfer加载的文件路径 wavesurfer: ‘‘, speed: 1, //播放速度 } }
2.3 mounted
mounted () { this.wavesurfer = WaveSurfer.create({ container: this.$refs.waveform,//绑定容器,第一种方法 // container: document.querySelector(‘#waveform‘),//第二种方法 // container: ‘#waveform‘,//第三种方法 audioRate: this.speed,//控制播放速度 forceDecode: true, waveColor: ‘#A8DBA8‘, progressColor: ‘#3B8686‘, backend: ‘MediaElement‘, plugins: [ Timeline.create({ container: ‘#timeline‘,//绑定容器 labelPadding: 2 }) ] }) this.wavesurfer.load(this.url)// 加载音频 this.wavesurfer.zoom(500) // 可以调整 }
2.4 method、
选择文件 事件
addFile(event){ let file = this.$refs.file.files[0] let _this = this if (file) { let url = null if (window.createObjectURL != undefined) { // basic url = window.createObjectURL(file) } else if (window.webkitURL != undefined) { // webkit or chrome url = window.webkitURL.createObjectURL(file) } else if (window.URL != undefined) { // mozilla(firefox) url = window.URL.createObjectURL(file) } var index = file.name.lastIndexOf(‘.‘) var fileType = file.name.substr(index + 1) if (fileType === ‘pcm‘) { var reader = new FileReader() reader.readAsArrayBuffer(file) reader.onload = function () { var data = reader.result var arrayBuffer = _this.addWavHeader(data, 8000, 8, 1) // 这里要根据音频文件配置对应的参数 var blob = new Blob([arrayBuffer]) _this.wavesurfer.loadBlob(blob) _this.url = URL.createObjectURL(blob) _this.wavesurfer.load(_this.url) } } else { // 不是pcm文件就直接load _this.url = url _this.wavesurfer.load(this.url) } } }
为pcm加头部
/** * 将pcm音频添加头部信息转换为wav音频 * @ date: 2019年10月17日 * @ param ArrayBuffer samples Uint8Array || Uint16Array || Uint32Array * @ param int sampleRateTmp 采样率(8000 - ???) * @ param int sampleBits 采样精度(8 || 16 || 32)和samples对应 * @ param int channelCount 声道(单声道1,双声道2) * @ author: 月光下的魔术师 * @ return: ArrayBuffer */ addWavHeader(samples, sampleRateTmp, sampleBits, channelCount){ var dataLength = samples.byteLength; var buffer = new ArrayBuffer(44 + dataLength); var view = new DataView(buffer); function writeString(view, offset, string) { for (var i = 0; i < string.length; i++) { view.setUint8(offset + i, string.charCodeAt(i)); } } var offset = 0; /* 资源交换文件标识符 */ writeString(view, offset, ‘RIFF‘); offset += 4; /* 下个地址开始到文件尾总字节数,即文件大小-8 */ view.setUint32(offset, /*32*/ 36 + dataLength, true); offset += 4; /* WAV文件标志 */ writeString(view, offset, ‘WAVE‘); offset += 4; /* 波形格式标志 */ writeString(view, offset, ‘fmt ‘); offset += 4; /* 过滤字节,一般为 0x10 = 16 */ view.setUint32(offset, 16, true); offset += 4; /* 格式类别 (PCM形式采样数据) */ view.setUint16(offset, 1, true); offset += 2; /* 通道数 */ view.setUint16(offset, channelCount, true); offset += 2; /* 采样率,每秒样本数,表示每个通道的播放速度 */ view.setUint32(offset, sampleRateTmp, true); offset += 4; /* 波形数据传输率 (每秒平均字节数) 通道数×每秒数据位数×每样本数据位/8 */ view.setUint32(offset, sampleRateTmp * channelCount * (sampleBits / 8), true); offset += 4; /* 快数据调整数 采样一次占用字节数 通道数×每样本的数据位数/8 */ view.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2; /* 每样本数据位数 */ view.setUint16(offset, sampleBits, true); offset += 2; /* 数据标识符 */ writeString(view, offset, ‘data‘); offset += 4; /* 采样数据总数,即数据总大小-44 */ view.setUint32(offset, dataLength, true); offset += 4; function floatTo32BitPCM(output, offset, input) { input = new Int32Array(input); for (var i = 0; i < input.length; i++, offset += 4) { output.setInt32(offset, input[i], true); } } function floatTo16BitPCM(output, offset, input) { input = new Int16Array(input); for (var i = 0; i < input.length; i++, offset += 2) { output.setInt16(offset, input[i], true); } } function floatTo8BitPCM(output, offset, input) { input = new Int8Array(input); for (var i = 0; i < input.length; i++, offset++) { output.setInt8(offset, input[i], true); } } if (sampleBits == 16) { floatTo16BitPCM(view, 44, samples); } else if (sampleBits == 8) { floatTo8BitPCM(view, 44, samples); } else { floatTo32BitPCM(view, 44, samples); } return view.buffer; }
转载于https://blog.csdn.net/qq_42136929/article/details/110235235
前言
wavesurfer.js 是一个音频可视化插件,这里是一篇使用方式。
但wavesurfer.js不可直接load格式为pcm的音频文件。参考js转化pcm到wav格式与播放,wav格式实质在pcm格式前面加上44字节的文件头。这里加上文件头后由wavesurfer.js插件进行播放。
1.HTML
<!-- 时间线容器 -->
<div id="timeline" ref="timeline" />
<!-- 音频容器 -->
<div id="waveform" ref="waveform" />
<!-- 选择文件按钮 -->
<input type="file" @change="addFile($event)" ref="file">
2. js
script标签里的内容
2.1 import
import WaveSurfer from ‘wavesurfer.js‘
import Timeline from ‘wavesurfer.js/dist/plugin/wavesurfer.timeline‘//Timeline插件
import Region from ‘wavesurfer.js/dist/plugin/wavesurfer.regions‘//regions插件
2.2 data
data () {
return {
url: ‘@/assets/music/ring.pcm‘, //wavesurfer加载的文件路径
wavesurfer: ‘‘,
speed: 1, //播放速度
}
}
2.3 mounted
mounted () {
this.wavesurfer = WaveSurfer.create({
container: this.$refs.waveform,//绑定容器,第一种方法
// container: document.querySelector(‘#waveform‘),//第二种方法
// container: ‘#waveform‘,//第三种方法
audioRate: this.speed,//控制播放速度
forceDecode: true,
waveColor: ‘#A8DBA8‘,
progressColor: ‘#3B8686‘,
backend: ‘MediaElement‘,
plugins: [
Timeline.create({
container: ‘#timeline‘,//绑定容器
labelPadding: 2
})
]
})
this.wavesurfer.load(this.url)// 加载音频
this.wavesurfer.zoom(500) // 可以调整
}
2.4 method
选择文件 事件
addFile(event){
let file = this.$refs.file.files[0]
let _this = this
if (file) {
let url = null
if (window.createObjectURL != undefined) { // basic
url = window.createObjectURL(file)
} else if (window.webkitURL != undefined) { // webkit or chrome
url = window.webkitURL.createObjectURL(file)
} else if (window.URL != undefined) { // mozilla(firefox)
url = window.URL.createObjectURL(file)
}
var index = file.name.lastIndexOf(‘.‘)
var fileType = file.name.substr(index + 1)
if (fileType === ‘pcm‘) {
var reader = new FileReader()
reader.readAsArrayBuffer(file)
reader.onload = function () {
var data = reader.result
var arrayBuffer = _this.addWavHeader(data, 8000, 8, 1) // 这里要根据音频文件配置对应的参数
var blob = new Blob([arrayBuffer])
_this.wavesurfer.loadBlob(blob)
_this.url = URL.createObjectURL(blob)
_this.wavesurfer.load(_this.url)
}
}
else {
// 不是pcm文件就直接load
_this.url = url
_this.wavesurfer.load(this.url)
}
}
}
为pcm加头部
/**
* 将pcm音频添加头部信息转换为wav音频
* @ date: 2019年10月17日
* @ param ArrayBuffer samples Uint8Array || Uint16Array || Uint32Array
* @ param int sampleRateTmp 采样率(8000 - ???)
* @ param int sampleBits 采样精度(8 || 16 || 32)和samples对应
* @ param int channelCount 声道(单声道1,双声道2)
* @ author: 月光下的魔术师
* @ return: ArrayBuffer
*/
addWavHeader(samples, sampleRateTmp, sampleBits, channelCount){
var dataLength = samples.byteLength;
var buffer = new ArrayBuffer(44 + dataLength);
var view = new DataView(buffer);
function writeString(view, offset, string) {
for (var i = 0; i < string.length; i++) {
view.setUint8(offset + i, string.charCodeAt(i));
}
}
var offset = 0;
/* 资源交换文件标识符 */
writeString(view, offset, ‘RIFF‘); offset += 4;
/* 下个地址开始到文件尾总字节数,即文件大小-8 */
view.setUint32(offset, /*32*/ 36 + dataLength, true); offset += 4;
/* WAV文件标志 */
writeString(view, offset, ‘WAVE‘); offset += 4;
/* 波形格式标志 */
writeString(view, offset, ‘fmt ‘); offset += 4;
/* 过滤字节,一般为 0x10 = 16 */
view.setUint32(offset, 16, true); offset += 4;
/* 格式类别 (PCM形式采样数据) */
view.setUint16(offset, 1, true); offset += 2;
/* 通道数 */
view.setUint16(offset, channelCount, true); offset += 2;
/* 采样率,每秒样本数,表示每个通道的播放速度 */
view.setUint32(offset, sampleRateTmp, true); offset += 4;
/* 波形数据传输率 (每秒平均字节数) 通道数×每秒数据位数×每样本数据位/8 */
view.setUint32(offset, sampleRateTmp * channelCount * (sampleBits / 8), true); offset += 4;
/* 快数据调整数 采样一次占用字节数 通道数×每样本的数据位数/8 */
view.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2;
/* 每样本数据位数 */
view.setUint16(offset, sampleBits, true); offset += 2;
/* 数据标识符 */
writeString(view, offset, ‘data‘); offset += 4;
/* 采样数据总数,即数据总大小-44 */
view.setUint32(offset, dataLength, true); offset += 4;
function floatTo32BitPCM(output, offset, input) {
input = new Int32Array(input);
for (var i = 0; i < input.length; i++, offset += 4) {
output.setInt32(offset, input[i], true);
}
}
function floatTo16BitPCM(output, offset, input) {
input = new Int16Array(input);
for (var i = 0; i < input.length; i++, offset += 2) {
output.setInt16(offset, input[i], true);
}
}
function floatTo8BitPCM(output, offset, input) {
input = new Int8Array(input);
for (var i = 0; i < input.length; i++, offset++) {
output.setInt8(offset, input[i], true);
}
}
if (sampleBits == 16) {
floatTo16BitPCM(view, 44, samples);
} else if (sampleBits == 8) {
floatTo8BitPCM(view, 44, samples);
} else {
floatTo32BitPCM(view, 44, samples);
}
return view.buffer;
}