2017/12/01

Web Audio APIとVue.jsで複数音源をミックスしコードを鳴らす

初期のシンセサイザーは、単音しか発音できなかった。いわゆる管楽器みたいなポジション。なのでコード(和音)を鳴らしたい場合は複数台のシンセサイザーが必要だった。

ということで、今回はコードを鳴らすために複数のオシレーターを使い、それらの音源をミックスして鳴らそうと思う。


OscillatorNodeやGainNodeの詳しい説明は、以下の記事を参照してほしい。



音をミックスする


音のミックスは非常に簡単で、複数のOscillatorNodeAudioContext.destinationに繋ぐだけで良い。
ただ、そのまま繋ぐと音が割れてしまうことがあるので、OscillatorNodeとdestinationの間にGainNodeを挟み、音量の調整したほうが良いだろう。
const ctx = new AudioContext();

// Oscillator -> Gain
const vca1 = ctx.createGain();
const vco1 = ctx.createOscillator();
vco1.connect(vca1);

// Oscillator -> Gain
const vca2 = ctx.createGain();
const vco2 = ctx.createOscillator();
vco2.connect(vca2);

// Gain -> Speaker
vca1.connect(ctx.destination);
vca2.connect(ctx.destination);

// そのままミックスすると音が割れるため
vca1.gain.value = 0.5;
vca2.gain.value = 0.5;

// 440Hzと倍音の880Hzを鳴らす
vco1.frequency.value = 440;
vco2.frequency.value = 880;
vco1.start();
vco2.start();

上記の例では、440Hzと880Hzのサイン波を同じ音量でミックスしている。
これと同じ要領で複数の音源を接続すれば、もっと複雑なコード(和音)も鳴らせる。



複数のOscillatorをつかってコードを鳴らす


<div id="app">
  <div 
    v-for="(o, i) in osc"
    :key="o"
    class="synth-group">
    <h3>OSC {{ i+1 }}</h3>
    <div class="field-group">
      <label>Wave form</label>
      <template v-for="form in waveForms">
        <label>
          <input type="radio" :value="form" v-model.number="osc[i].form">
          {{ form }}
        </label>
      </template>
    </div>
    <div class="field-group">
      <label>Frequency</label>
      <input type="number" v-model.number="osc[i].freq">
    </div>
    <div class="field-group">
      <label>Volume</label>
      <input type="range" min="0" max="1" step="any" v-model.number="osc[i].volume">
    </div>
  </div>
  
  <button type="button" @click="start">Start</button>
  <button type="button" @click="stop">Stop</button>
</div>
new Vue({
  el: '#app',
  data() {
    return {
      waveForms: ['sine', 'square', 'sawtooth', 'triangle'],
      ctx: new AudioContext(),
      osc: [
        // osc1
        {
          node: null,
          gain: null,
          form: 'sine',
          freq: 523.25, // C5
          volume: 0.3
        },
        // osc2
        {
          node: null,
          gain: null,
          form: 'sine',
          freq: 659.25, // E5
          volume: 0.3
        },
        // osc3
        {
          node: null,
          gain: null,
          form: 'sine',
          freq: 783.99, // G5
          volume: 0.3
        }
      ]
    }
  },
  methods: {
    start() {
      this.osc.forEach((o, i) => {
        const gain = this.osc[i].gain = this.ctx.createGain();
        gain.connect(this.ctx.destination);
        gain.gain.value = o.volume;
      
        const osc = this.osc[i].node = this.ctx.createOscillator();
        osc.connect(gain);
        osc.frequency.value = o.freq;
        osc.type = o.form;
        
        osc.start();
      });
    },
    stop() {
      this.osc.forEach(o => o.node.stop());
    }
  }
});

3つのオシレーターからそれぞれC5、E5、G5(ドミソ)を発音し、それをミックスすることでCメジャーコードを鳴らすことができる。
もちろんFrequencyを変えれば、他のコードも鳴らすことができる。


割りと簡単にできるが、音源をミックスすればするほど音量調整が面倒になるので、このあたりは何か良い方法がないか試してみようと思う。



以上

written by @bc_rikko

0 件のコメント :

コメントを投稿