七夕了,用代码给心爱的人写一首曲子吧

web页面能发出声音的方法有两种,一种是 autio 、 video 这些标签,另外一种就是音频上下文 AudioContext 。接下来我们看一下如何使用 AudioContext ,写简易钢琴和曲子。然后赶在七夕之前,给心爱的人作一首曲子吧

1. AudioContext如何发出声音

Mdn上面有具体介绍,我们这里只用下面几个

// 创建音频上下文
      const audioCtx = new AudioContext();
      // 创建音调控制对象
      const oscillator = audioCtx.createOscillator();
      // 创建音量控制对象
      const gainNode = audioCtx.createGain();
      // 音调音量关联
      oscillator.connect(gainNode);
      // 音量和设备关联
      gainNode.connect(audioCtx.destination);
      // 音调类型指定为正弦波。sin好听一些
      oscillator.type = "sine";
      // 设置音调频率(作曲的关键)
      oscillator.frequency.value = 400;
      // 先把当前音量设为0
      gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
      // 0.01秒时间内音量从0到1线性变化,突然变化的话很生硬
      gainNode.gain.linearRampToValueAtTime(
        1,
        audioCtx.currentTime + 0.01
      );
      // 声音开始
      oscillator.start(audioCtx.currentTime);
复制代码

不,这还没完,直接copy这段代码放你js文件里面是没用的

这里还需要一步:地址栏中输入chrome://flags/#autoplay-policy,把autoplay-policy改成图中所示

ok,现在代码可以发出声音了,但是不会停下来,我们需要把音频停下来:

oscillator.stop(audioCtx.currentTime + 1);
复制代码

2. 简谱怎么来

现在我们知道怎么发出声音了,接下来是如何发出想要的声音,即是如何知道哆来咪发唆这些音所对应的频率是多少。

搜索关键词:简谱频率、乐谱频率。很快,就可以找到映射表格

我们要做的就是把 oscillator.frequency.value = 400; 这里的数字改成频率即可发出对应的声音。不妨先试一下

3. 根据简谱映射表输出对应的音频

上面那个表抄了一份,具体如下,代表着低中高的哆来咪发唆啦希

点击查看简谱数组

[[261.63, 293.67, 329.63, 349.23, 391.99, 440, 493.88], [523.25, 587.33, 659.26, 698.46, 783.99, 880, 987.77], [1046.5, 1174.66, 1318.51, 1396.92, 1567.98, 1760, 1975.52]]
复制代码

只要把它和点击事件联系起来,就可以做到一个小钢琴了。先使用js渲染出每一个按键

// 简谱映射
    const VOICE_MAP = {
      0: [261.63, 293.67, 329.63, 349.23, 391.99, 440, 493.88],
      1: [523.25, 587.33, 659.26, 698.46, 783.99, 880, 987.77],
      2: [1046.5, 1174.66, 1318.51, 1396.92, 1567.98, 1760, 1975.52]
    };
    function renderBtns(level) {
      let i = 0;
      let res = "";
      while (i < 7) {
        res += `<span class="btn level${level}" data-index=${i}>${i +
          1}</span>`; // 用data-属性辅助
        i++;
      }
      const container = document.createElement("section");
      container.className = `container${level}`;
      // ------------------------
      // 等下这里会加一些事件绑定
      // ------------------------
      container.innerHTML += res;
      document.body.appendChild(container);
    }

    // 渲染节点
    renderBtns(0);
    renderBtns(1);
    renderBtns(2);

复制代码

点击查看样式

.btn {
        cursor: pointer;
        display: inline-block;
        width: 100px;
        height: 30px;
        line-height: 30px;
        user-select: none;
        text-align: center;
        border: 1px #a12d21 solid;
        margin: 2px;
      }

      .level0::after {
        content: ".";
        position: relative;
        top: 4px;
        left: -7px;
      }

      .level2::before {
        content: ".";
        position: relative;
        top: -16px;
        left: 7px;
      }

复制代码

最终效果如下

绑定事件

renderBtns方法加上事件绑定,移动端只需手动换成touch系列事件。

// 音频开始
    function handleStart({ target }, level) {
      const {
        dataset: { index }
      } = target;
      if (index !== undefined) {
        console.log(index, "start");
        playAudio.call(target, index, level); // 后面加上playAudio的实现
      }
    }

    // 停止音频
    function handleStop({ target }) {
      const {
        dataset: { index }
      } = target;
      if (index !== undefined) {
        console.log(index, "stop");
        stopAudio.call(target); // 后面加上stopAudio的实现
      }
    }

    function renderBtns(level) {
      let i = 0;
      let res = "";
      while (i < 7) {
        res += `<span class="btn level${level}" data-index=${i}>${i +
          1}</span>`;
        i++;
      }
      const container = document.createElement("section");
      container.className = `container${level}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值