【WaveView小程序版】微信小程序实现录音实时显示波形

阅前须知

本片不包含真实音量的波形,是固定分片长度4096,音量40的基础去做的一个音频波形效果。在waveview.js的基础上翻译/重构为了小程序的版本,确切的说为了用这个插件代码变得更复杂了,但是这也是没办法的事。

先贴代码

文件名 waveview.js 源自 https://github.com/xiangyuecn/Recorder/blob/master/src/extensions/waveview.js

export class WaveView {
  constructor(set) {
    var This = this;
    var o = {
      scale: 2, //缩放系数,应为正整数,使用2(3? no!)倍宽高进行绘制,避免移动端绘制模糊
      speed: 8, //移动速度系数,越大越快
      lineWidth: 3, //线条基础粗细
      //渐变色配置:[位置,css颜色,...] 位置: 取值0.0-1.0之间
      linear1: [0, "rgba(150,96,238,1)", 0.2, "rgba(170,79,249,1)", 1, "rgba(53,199,253,1)"], //线条渐变色1,从左到右
      linear2: [0, "rgba(209,130,255,0.6)", 1, "rgba(53,199,255,0.6)"], //线条渐变色2,从左到右
      linearBg: [0, "rgba(255,255,255,0.2)", 1, "rgba(54,197,252,0.2)"] //背景渐变色,从上到下
    };
    for (var k in set) {
      o[k] = set[k];
    };
    This.set = set = o;
    var scale = set.scale;
    var width = set.width * scale;
    var height = set.height * scale;
    var canvas = set.elem;
    canvas.width = width;
      canvas.height = height;
    var ctx = This.ctx = canvas.getContext("2d");
    This.linear1 = This.genLinear(ctx, width, set.linear1);
    This.linear2 = This.genLinear(ctx, width, set.linear2);
    This.linearBg = This.genLinear(ctx, height, set.linearBg, true);
    This._phase = 0;
  }
  genLinear(ctx, size, colors, top) {
    var rtv = ctx.createLinearGradient(0, 0, top ? 0 : size, top ? size : 0);
    for (var i = 0; i < colors.length;) {
      rtv.addColorStop(colors[i++], colors[i++]);
    };
    return rtv;
  }
  genPath(frequency, amplitude, phase) {
    //曲线生成算法参考 https://github.com/HaloMartin/MCVoiceWave/blob/f6dc28975fbe0f7fc6cc4dbc2e61b0aa5574e9bc/MCVoiceWave/MCVoiceWaveView.m#L268
    var rtv = [];
    var This = this, set = This.set;
    var scale = set.scale;
    var width = set.width * scale;
    var maxAmplitude = set.height * scale / 2;

    for (var x = 0; x < width; x += scale) {
      var scaling = (1 + Math.cos(Math.PI + (x / width) * 2 * Math.PI)) / 2;
      var y = scaling * maxAmplitude * amplitude * Math.sin(2 * Math.PI * (x / width) * frequency + phase) + maxAmplitude;
      rtv.push(y);
    }
    return rtv;
  }
  input(dataLength = 4096, powerLevel = 40, sampleRate = 16000) {
    var This = this, set = This.set;
    var ctx = This.ctx;
    var scale = set.scale;
    var width = set.width * scale;
    var height = set.height * scale;
    var speedx = set.speed * dataLength / sampleRate;
    var phase = This._phase -= speedx; //位移速度
    var amplitude = powerLevel / 100;
    var path1 = This.genPath(2, amplitude, phase);
    var path2 = This.genPath(1.8, amplitude, phase + speedx * 5);
    //开始绘制图形
    ctx.clearRect(0, 0, width, height);
    //绘制包围背景
    ctx.beginPath();
    for (var i = 0, x = 0; x < width; i++, x += scale) {
      if (x == 0) {
        ctx.moveTo(x, path1[i]);
      } else {
        ctx.lineTo(x, path1[i]);
      };
    };
    i--;
    for (var x = width - 1; x >= 0; i--, x -= scale) {
      ctx.lineTo(x, path2[i]);
    };
    ctx.closePath();
    ctx.fillStyle = This.linearBg;
    ctx.fill();
    //绘制线
    This.drawPath(path2, This.linear2);
    This.drawPath(path1, This.linear1);
  }
  drawPath(path, linear) {
    var This = this, set = This.set;
    var ctx = This.ctx;
    var scale = set.scale;
    var width = set.width * scale;
    ctx.beginPath();
    for (var i = 0, x = 0; x < width; i++, x += scale) {
      if (x == 0) {
        ctx.moveTo(x, path[i]);
      } else {
        ctx.lineTo(x, path[i]);
      };
    };
    ctx.lineWidth = set.lineWidth * scale;
    ctx.strokeStyle = linear;
    ctx.stroke();
  }
}

我将它翻译为了支持小程序的版本,如何使用这个代码呢,请看下面。

wxml部分

因为微信不支持动态append一个view到视图中(简单查了查这样说,反正代码一定需要改,所以不管它,原则上不合理,未深究),所以这里我们需要手动定义好一个canvas

<View class="wave" id="wave_parent">
  <canvas id="wave" type="2d" class="canvas"></canvas>
</View>

CSS部分

.wave{
  position: absolute;
  left: 0;
  top: 0;
  z-index: 9999;
  width: 100vw;
  height: 100px;
  overflow: hidden;
}
.canvas {
  width: 100vw;
  height: 100px;
}

JS部分

引入

把最上面的JS代码全部赋值放在一个文件中,放在哪里就从哪里引入就行

import { WaveView } from '../../js/waveview';

初始化

initWave() {
    const _this = this;
    const query = this.createSelectorQuery();
    query.select('#wave')
      .fields({ node: true, size: true })
      .exec((res) => {
        const canvas = res[0].node
        const waveView = new WaveView({
          elem: canvas,
          width:wx.getSystemInfoSync().windowWidth,
          height:100,
          scale: 1
        });
        _this.setData({
          waveView: waveView
        });
      })
  }

这个的宽度和高度根据实际情况来决定,可以写的更符合小程序规范一些,其中css和这里的保持一致为最佳实践,目前能说明问题即可。

回调

  const _this = this;
  this.data.recorderManager.start(this.data.options);
  this.data.recorderManager.onStart(function (){
  });
  this.data.recorderManager.onFrameRecorded(function (res){
    _this.setData({
      recordImage: _this.data.baseRecordImage + (Math.floor(Math.random()*5) + 2) + ".png",
      hiddenImage: false
    });
    if (_this.data.waveView) {
      _this.data.waveView.input();
    }
  });

强调一下:目前我无法根据原始PCM切片获取到音量数据,有尝试过类似方式,重新处理的话性能太差直接不考虑,故这里的input全部采用默认值的方式,具体请查看waveview.js的input方法的参数。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容