wavesurfer.js播放pcm音頻


前言

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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM