wavesurfer.js绘制音频波形图

1.查看效果图

向前选中:

向后选中:

代码如下(示例):

<template>
  <div class="waveSurfer">
    <div class="top">
      <span @click="leftSelect">向前选中</span>
      <span @click="rightSelect">向后选中</span>
      <span @click="Region">标注</span>
    </div>
    <!-- 时间轴 -->
    <div id="wave-timeline" />
    <!-- 频谱图 -->
    <div id="waveform">
      <progress
        id="progress"
        class="progress progress-striped"
        value="0"
        max="100"
      ></progress>
    </div>
    <div v-show="ppt" id="wave-spectrogram" class="mt-20" />
    <!-- 控制按钮 -->
    <div class="title">
      <ul>
        <li>
          <span @click="zoomIn"></span>
        </li>
        <li>
          <span @click="rew"></span>
        </li>
        <li>
          <span :class="{ on: isPlay }" @click="plays"></span>
        </li>
        <li>
          <span @click="speek"></span>
        </li>
        <li>
          <span @click="zoomOut"></span>
        </li>
        <li>
          <span @click="replay"></span>
        </li>
        <li @click="toggleMute" :class="{ on: toggleMutebutton }" class="sound">
          <span></span>
        </li>
        <li>
          <input
            @mouseup="volumeBarHandle"
            v-model="volValue"
            type="range"
            min="0"
            max="1"
            value="0.8"
            step="0.01"
          />
        </li>
        <li @click="DoubleSpeed(index)">
          {{ speed[index] + " X" }}
        </li>
      </ul>
    </div>
  </div>
</template>
<script>
import WaveSurfer from "wavesurfer.js";
import Timeline from "wavesurfer.js/dist/plugin/wavesurfer.timeline.js";
import Regions from "wavesurfer.js/dist/plugin/wavesurfer.regions.js";
export default {
  data: function () {
    return {
      index: 0,
      speed: [1.0, 1.5, 2.0, 0.5],
      isPlay: false,
      ppt: false,
      ds: 1.0,
      zoomValue: 100,
      zoomMin: 100,
      fast: 3,
      back: 3,
      noteData: [],
      toggleMutebutton: true,
      volValue: 0,
      audioUrl: "",
      loading: true,
    };
  },
  // computed: {
  //   // 计算属性的 getter
  //   getUrl: function() {
  //     // `this` 指向 vm 实例
  //     return this.$store.state.voicetrain.url
  //   }
  // },
  // watch: {
  //   getUrl(newUrl) {
  //     this.loading = true
  //     this.audioUrl = newUrl
  //     document.getElementById('waveform').innerHTML = ''
  //     this.init()
  //   }
  // },
  mounted() {
    this.audioUrl =
      "http://192.168.1.101:8080/api/files/20201104/62afa213458d44b0a99440b33fb694b9";
    this.init();
  },

  methods: {
    // 初始化
    init() {
      document.getElementById("progress").style.display = "block";
      this.$nextTick(() => {
        this.wavesurfer = WaveSurfer.create({
          container: "#waveform",
          cursorColor: "#DB7093", // 声波播放进度线color
          audioRate: 1,
          scrollParent: true,
          backend: "WebAudio",
          barHeight: 1.5,
          waveColor: "#43d996", // 声波color
          progressColor: "#43d996", // 已播放声波color
          loaderColor: "#8B0000",
          hideScrollbar: false,
          autoCenter: true,
          height: 120,
          splitChannels: true,
          responsive: true,
          minPxPerSec: 1,
          plugins: [
            Timeline.create({
              container: "#wave-timeline",
              fontSize: 14,
              primaryFontColor: "#9191a5",
              secondaryFontColor: "#9191a5",
              primaryColor: "#9191a5",
              secondaryColor: "#9191a5",
            }),
            Regions.create({}),
          ],
        });
        this.wavesurfer.addRegion({
          loop: false,
          drag: false,
          resize: false,
          color: "rgba(254, 255, 255, 0.4)",
        });
        // 加载进度条
        this.wavesurfer.on("loading", function (percents) {
          document.getElementById("progress").value = percents;
        });
        this.wavesurfer.load(this.audioUrl);
        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);
        let _this = this;
        _this.wavesurfer.on("ready", function () {
          _this.wavesurfer.enableDragSelection({
            color: "rgba(0, 180, 0, 0.3)",
          });
          _this.wavesurfer.clearRegions();
          _this.wavesurfer.zoom(_this.zoomValue);
          // 音频加载完成
          document.getElementById("progress").style.display = "none";
          document.getElementById("progress").value = 0;
          _this.isPlay = true;
          _this.wavesurfer.play(0);
        });
        document.getElementById("waveform").onclick = function () {
          _this.isPlay = false;
          _this.wavesurfer.clearRegions();
        };
        // 更新区域时。回调将接收该Region对象。
        // this.wavesurfer.on("region-updated", function (region) {
        //   region.playLoop(); // 循环播放选中区域
        //   _this.isPlay = true;
        // });
        _this.wavesurfer.on("region-created", _this.addRegion);
        _this.wavesurfer.on("region-click", _this.editAnnotation);

        _this.wavesurfer.on("finish", function () {
          _this.wavesurfer.play(0);
        });
      });
    },
    addRegion(params) {
      this.wavesurfer.clearRegions();
      params.handleLeftEl.style.backgroundColor = "transparent";
      params.handleRightEl.style.backgroundColor = "transparent";
    },
    toggleMute() {
      if (this.toggleMutebutton) {
        this.volumeCached = this.wavesurfer.getVolume();
        this.wavesurfer.setVolume(0);
        this.toggleMutebutton = false;
        this.volValue = 0;
      } else {
        if (this.volumeCached == 0) this.volumeCached = 1;
        this.wavesurfer.setVolume(this.volumeCached);
        this.toggleMutebutton = true;
        this.volValue = this.volumeCached;
      }
    },
    volumeBarHandle(e) {
      if (e.offsetX >= 0 && e.offsetX <= 80) {
        this.toggleMutebutton = true;
        this.wavesurfer.setVolume(e.offsetX / 80);
      } else if (e.offsetX < 0) {
        this.toggleMutebutton = false;
        this.wavesurfer.setVolume(0);
      } else {
        this.wavesurfer.setVolume(1);
        this.toggleMutebutton = true;
      }
    },
    // 标注
    Region() {
      console.log(
        Object.getOwnPropertyNames(this.wavesurfer.regions.list).length
      );
      if (
        Object.getOwnPropertyNames(this.wavesurfer.regions.list).length == 0
      ) {
        alert("请选择波纹");
        return;
      }
      let start = 0,
        end = 0;
      for (var k in this.wavesurfer.regions.list) {
        let obj = this.wavesurfer.regions.list[k];
        start = obj.start.toFixed(2) * 1000;
        end = obj.end.toFixed(2) * 1000;
      }
      console.log(this.wavesurfer);
      console.log("开始", start);
      console.log("结束", end);
    },
    // 播放
    plays() {
      this.isPlay = !this.isPlay;
      this.wavesurfer.playPause(); //切换播放,应用播放或暂停
    },
    // 回退
    rew() {
      this.wavesurfer.skip(-this.back);
      this.goPlay();
    },
    // 快进
    speek() {
      this.wavesurfer.skip(this.fast);
      this.goPlay();
    },
    // 重载
    replay() {
      this.isPlay = true;
      this.wavesurfer.stop();
      this.wavesurfer.clearRegions();
      this.wavesurfer.play(0);
    },
    // 倍速
    DoubleSpeed(index) {
      if (index === 3) {
        this.index = 0;
        this.wavesurfer.setPlaybackRate(this.speed[this.index]);
      } else {
        this.index = index + 1;
        this.wavesurfer.setPlaybackRate(this.speed[this.index]);
      }
      console.log(this.wavesurfer);
    },
    // 缩放百分比显示格式
    formatZoom(val) {
      return val + 100 + " 像素 / 秒";
    },
    // 点击缩小
    zoomIn() {
      if (this.zoomValue >= 100) {
        return;
      }
      this.zoomValue += 1;
      this.wavesurfer.zoom(this.zoomValue);
    },
    // 点击扩大
    zoomOut() {
      if (this.zoomValue < -100) {
        return;
      }
      this.zoomValue -= 1;
      this.wavesurfer.zoom(this.zoomValue);
    },
    // 缩放监听
    zoomChange() {
      this.wavesurfer.zoom(Number(this.zoomValue));
    },
    goPlay() {
      let start = this.wavesurfer.getCurrentTime();
      this.wavesurfer.play(start);
    },
    // 向前选中
    leftSelect() {
      let end = this.wavesurfer.getCurrentTime(); // 获取当前播放位置
      this.waveRegion(this.wavesurfer, 0, end, "rgba(0,180,0,.3)", true);
    },
    // 向后选中
    rightSelect() {
      let start = this.wavesurfer.getCurrentTime(); // 获取当前播放位置
      let end = this.wavesurfer.getDuration(); // 获取音频片段的持续时间
      this.waveRegion(this.wavesurfer, start, end, "rgba(0,180,0,.3)", true);
    },
    waveRegion(wavesurfer, start, end, color, clear) {
      if (!clear) {
        wavesurfer.clearRegions();
      }
      wavesurfer.addRegion({
        start: start,
        end: end,
        color: color,
        drag: false,
      });
    },
    // 区域点击事件新建
    saveRegions() {
      console.log("声纹点击---");
      this.noteData = [];
      const _this = this;
      this.noteData = Object.keys(_this.wavesurfer.regions.list).map(function (
        id
      ) {
        const region = _this.wavesurfer.regions.list[id];
        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 || "" },
        };
      });
    },
    // 区域点击
    editAnnotation() {
      this.isPlay = false;
    },
    showNote(region) {
      if (!this.showNote.el) {
        this.showNote.el = document.querySelector("#subtitle");
      }
      this.showNote.el.textContent = region.data.note || "–";
    },
    // 设置音量
    setVolume(val) {
      console.log(val);
      this.wavesurfer.setVolume(val / 100);
    },
    // 实例点击
    clearReagion() {
      this.wavesurfer.clearRegions();
    },
  },
};
</script>
<style  lang="scss" scoped>
#waveform {
  position: relative;
}
.top {
  width: 100%;
  flex-basis: 70px;
  line-height: 40px;
  flex-shrink: 0;
  color: white;
  text-indent: 15px;
  span,
  el-slider {
    color: rgb(39, 39, 39);
    font-size: 13px;
    font-weight: 700;
    margin-right: 20px;
    padding: 4px 10px;
    border: 1px solid #ccc;
    border-radius: 10px;
  }
}
.title {
  width: 100%;
  flex-basis: 70px;
  line-height: 40px;
  text-align: left;
  flex-shrink: 0;
  color: white;
  text-indent: 15px;
  ul {
    list-style-type: none;
    padding-inline-start: 0;
    .speed {
      display: flex;
      flex-direction: column;
    }
    li {
      position: relative;
      display: inline-block;
      cursor: default;
      &:hover {
      }
      &:active {
      }
      span {
        display: inline-block;
        width: 30px;
        height: 30px;
        line-height: 30px;
      }
      &:nth-child(1) span {
        width: 27px;
        height: 27px;
        background: url("img/缩小.png") right;
        background-size: cover;
      }
      &:nth-child(2) span {
        background: url("img/kuaitui_bg.png") right;
        background-size: cover;
      }
      &:nth-child(3) {
        span {
          background: url("img/bofang_bg.png") right;
          background-size: cover;
        }
        .on {
          background: url("img/zanting_bg.png") right;
          background-size: cover;
        }
      }
      &:nth-child(4) span {
        background: url("img/kuaijin_bg.png") right;
        background-size: cover;
      }
      &:nth-child(5) span {
        background: url("img/缩放.png") right;
        background-size: cover;
      }
      &:nth-child(6) span {
        background: url("img/zhongbo.png") right;
        background-size: cover;
      }
      &:nth-child(9) {
        color: rgb(39, 39, 39);
        font-size: 13px;
        font-weight: 700;
      }
      &:nth-child(7) {
        background: none;
        span {
          width: 25px;
          height: 25px;
          background: url("img/静音.png") no-repeat;
          background-size: cover;
        }
        &.on {
          span {
            width: 25px;
            height: 25px;
            background: url("img/喇叭.png") no-repeat;
            background-size: cover;
          }
        }
      }
      &:nth-child(8) {
        width: 80px;
        background: none;
        input {
          -webkit-appearance: none;
          -moz-appearance: none;
          -ms-appearance: none;
          width: 80px;
          height: 3px;
          background-color: #bbbbbb;
          position: absolute;
          left: 0;
          top: -14px;

          &::-webkit-slider-thumb {
            -webkit-appearance: none;
          }
          &::-moz-range-trackpseduo {
            -moz-appearance: none;
          }
          &::-ms-track {
            width: 100%;
            cursor: pointer;
            background: transparent; /* Hides the slider so custom styles can be added */
            border-color: transparent;
            color: transparent;
          }
          &:focus {
            outline: none;
          }
          &::-webkit-slider-thumb {
            -webkit-appearance: none;
            height: 9px;
            width: 9px;
            margin-top: -1px;
            background: #bbb;
            border-radius: 50%;
            border: solid 0.125em rgba(205, 224, 230, 0.5);
          }
          &::-moz-range-thumb {
            -moz-appearance: none;
            height: 6px;
            width: 6px;
            margin-top: -1px;
            background: #bbb;
            border-radius: 50%;
            border: solid 0.125em rgba(205, 224, 230, 0.5);
          }
          &::-ms-track {
            -moz-appearance: none;
            height: 6px;
            width: 6px;
            margin-top: -1px;
            background: #bbb;
            border-radius: 50%;
            border: solid 0.125em rgba(205, 224, 230, 0.5);
          }
        }
      }
    }
  }
}
#wave-timeline {
  height: 21px;
}
#waveform {
  width: 100%;
  flex-basis: 128px;
  flex-shrink: 0;
  position: relative;
}
#progress {
  position: absolute;
  width: 100%;
  height: 4px;
  background: #ccc;
  top: 48%;
  opacity: 0.7;
  z-index: 44;
}
.mt-20 {
  margin-top: 20px;
}
.mt-30 {
  margin-top: 30px;
}
.waveSurfer {
  width: 470px;
}
.waveSurfer >>> .el-slider__runway {
  margin: 6px 0;
}
</style>
链接:https://wavesurfer-js.org
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值