Instruments

Introduction

Instruments generate sound internally, usually triggered by MIDI, DAW playback, or user gestures such as clicking or keyboard input.

The goal of this guide is to demonstrate simple and reliable patterns for building each of these using the standard Web Audio API. These examples intentionally avoid complex frameworks and focus on the core audio building blocks that work well inside WAX.

Generating sound

Common audio sources:

  • AudioBufferSourceNode (samples)
  • OscillatorNode (synth tones)
// Oscillator example

const ctx = new AudioContext()

const osc = ctx.createOscillator()
const gain = ctx.createGain()

gain.gain.value = 0.2

osc.connect(gain)
gain.connect(ctx.destination)

// start the oscillator
osc.start()


// -----------------------------
// Buffer source example (sample playback)

const ctx2 = new AudioContext()

fetch("kick.wav")
  .then(r => r.arrayBuffer())
  .then(data => ctx2.decodeAudioData(data))
  .then(buffer => {

    const src = ctx2.createBufferSource()
    const gain2 = ctx2.createGain()

    src.buffer = buffer

    src.connect(gain2)
    gain2.connect(ctx2.destination)

    src.start()

  })

Master Gain

Route instruments through a master gain node before the final output.

source → voiceGain → masterGain → ctx.destination

MIDI

// Master output gain (can be controlled via MIDI CC)
const masterGain = ctx.createGain()
masterGain.gain.value = 0.5
masterGain.connect(ctx.destination)

// Request MIDI access
navigator.requestMIDIAccess().then(access => {

  access.inputs.forEach(input => {

    input.onmidimessage = e => {

      const status = e.data[0]   // status byte tells us the MIDI message type
      const data1  = e.data[1]
      const data2  = e.data[2]

      // Status byte 0x90 = Note On
      // Status byte 0x80 = Note Off
      // Status byte 0xB0 = Control Change

      // NOTE ON
      if((status & 0xF0) === 0x90 && data2 > 0){

        const note = data1
        const velocity = data2

        const osc = ctx.createOscillator()
        const gain = ctx.createGain()

        osc.frequency.value =
          440 * Math.pow(2, (note - 69) / 12)

        gain.gain.value = velocity / 127

        osc.connect(gain)
        gain.connect(masterGain)

        osc.start()
      }

      // MIDI CC example (CC1 controls master gain)
      if((status & 0xF0) === 0xB0){

        const cc = data1
        const value = data2

        if(cc === 1){
          masterGain.gain.value = value / 127
        }

      }

    }

  })

})
Was this article helpful?
Dislike