js 根据声音绘制声音图

发布时间 2023-07-17 15:08:30作者: 波仔、

js 获取麦克风,根据声音大小绘制图形   条状图

//麦克风测试
    showaudiotset() {
      let that = this;//setInfo.mikeId 当前麦克风设备id
      let curaudio = that.mikeArr.filter(
        (v) => v.deviceId == that.setInfo.mikeId
      )[0];
      // 老的浏览器可能根本没有实现 mediaDevices,所以我们可以先设置一个空的对象
      if (navigator.mediaDevices === undefined) {
        navigator.mediaDevices = {};
      }
      if (navigator.mediaDevices.getUserMedia === undefined) {
        navigator.mediaDevices.getUserMedia = function (constraints) {
          // 首先,如果有getUserMedia的话,就获得它
          var getUserMedia =
            navigator.webkitGetUserMedia ||
            navigator.mozGetUserMedia ||
            navigator.msGetUserMedia;
          // 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
          if (!getUserMedia) {
            return Promise.reject(
              new Error("getUserMedia is not implemented in this browser")
            );
          }
          // 否则,为老的navigator.getUserMedia方法包裹一个Promise
          return new Promise(function (resolve, reject) {
            getUserMedia.call(navigator, constraints, resolve, reject);
          });
        };
      }
      const constraints = {
        audio: {
          deviceId: curaudio.deviceId,
          groupId: curaudio.groupId
        },
        video: false
      };
      let promise = navigator.mediaDevices.getUserMedia(constraints);
      promise.then((stream) => {
        var context = new window.AudioContext();
        var source = context.createMediaStreamSource(stream);
        var analyser = context.createAnalyser();
        source.connect(analyser);
        analyser.fftSize = 2048;
        analyser.minDecibels = -100;
        analyser.maxDecibels = 100;
        analyser.smoothingTimeConstant = 0;
        var maxDecibels = 0;
        let themecolor = this.$store.state.themeObj.themecolor || "#960200";
        let canvas = document.getElementById("audio_canvas");
        if (this.time2) {
          clearInterval(this.time2);
        }
        this.time2 = setInterval(() => {
          var dataArr = new Uint8Array(analyser.frequencyBinCount);
          analyser.getByteFrequencyData(dataArr);
          var mcVolume =
            dataArr.reduce(function (a, b) {
              return a + b;
            }) / analyser.frequencyBinCount;
          maxDecibels = maxDecibels > mcVolume ? maxDecibels : mcVolume;
          var p = parseInt((mcVolume / maxDecibels) * 100);
          let domwidth = 300;
          let domheight = 30;
          canvas.width = domwidth;
          canvas.height = domheight;
          let width = canvas.width,
            height = canvas.height,
            g = canvas.getContext("2d");
          let num = 15;
          let space = 12;
          let barwidth = (width - (num - 1) * space) / num;
          g.clearRect(0, 0, width, height);
          let shounum = parseInt((p * num) / 255 + "");
          for (let i = 0; i < num; i++) {
            let x = space * i + i * barwidth;
            let colorstr = "#DDDDDD";
            if (i < shounum) {
              colorstr = themecolor;
            }
            this.fillRoundRect(
              g,
              x,
              0,
              barwidth,
              height,
              barwidth / 2,
              colorstr
            );
          }
        }, 200);
      });
    },
    fillRoundRect(cxt, x, y, width, height, radius, /*optional*/ fillColor) {
      //圆的直径必然要小于矩形的宽高
      radius = Math.min(width / 2, height / 2, radius);
      if (radius < 0) {
        radius = 0;
      }
      cxt.save();
      cxt.translate(x, y);
      //绘制圆角矩形的各个边
      this.drawRoundRectPath(cxt, width, height, radius);
      cxt.fillStyle = fillColor || "#000";
      cxt.fill();
      cxt.restore();
    },
    drawRoundRectPath(cxt, width, height, radius) {
      cxt.beginPath();
      //从右下角顺时针绘制,弧度从0到1/2PI
      cxt.arc(width - radius, height - radius, radius, 0, Math.PI / 2);

      //矩形下边线
      cxt.lineTo(radius, height);

      //左下角圆弧,弧度从1/2PI到PI
      cxt.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);

      //矩形左边线
      cxt.lineTo(0, radius);

      //左上角圆弧,弧度从PI到3/2PI
      cxt.arc(radius, radius, radius, Math.PI, (Math.PI * 3) / 2);

      //上边线
      cxt.lineTo(width - radius, 0);

      //右上角圆弧
      cxt.arc(width - radius, radius, radius, (Math.PI * 3) / 2, Math.PI * 2);

      //右边线
      cxt.lineTo(width, height - radius);
      cxt.closePath();
    },