Web Audio API Experimentation
Learning about sound and stuff
by wio_dude
HTML
<canvas id="player"></canvas>
<br/>
<label for="volume">Volume</label>
<input type="range" id="volume" name="volume" min="0" max="1.5" step="0.01" value="0" />
<span id="volume-out"></span>
<br />
<label for="frequency">Frequency</label>
<input type="range" id="frequency" name="frequency" min="1" max="4" value="2.34" step="0.01" />
<span id="frequency-out"></span>
<br/>
<label for="type">Wave Type</label>
<select id="type" name="type">
<option value="sine">Sine</option>
<option value="square">Square</option>
<option value="sawtooth">Sawtooth</option>
<option value="triangle">Triangle</option>
</select>
<br/>
<label for="attack">Attack</label>
<input type="range" id="attack" name="attack" min="0" max="0.5" value="0.05" step="0.001" />
<span id="attack-out"></span>
<br/>
<label for="decay">Decay</label>
<input type="range" id="decay" name="decay" min="0" max="0.5" value="0.1" step="0.001" />
<span id="decay-out"></span>
<br/>
<label for="sustain">Sustain</label>
<input type="range" id="sustain" name="sustain" min="0" max="0.5" value="0.3" step="0.001" />
<span id="sustain-out"></span>
<br/>
<label for="release">Release</label>
<input type="range" id="release" name="release" min="0" max="1" value="0.5" step="0.001" />
<span id="release-out"></span>
<br/>
CSS
canvas {
background-color: black
}
JavaScript
const rangeIds = [
'attack',
'decay',
'sustain',
'release'
]
const ranges = {}
for (const rangeId of rangeIds) {
const elem = document.getElementById(rangeId)
const elemOut = document.getElementById(rangeId + '-out')
elemOut.innerHTML = elem.value
ranges[rangeId] = elem
elem.addEventListener('input', (evt) => {
elemOut.innerHTML = elem.value
})
}
const player = document.getElementById('player')
const volume = document.getElementById('volume')
const volumeOut = document.getElementById('volume-out')
const frequency = document.getElementById('frequency')
const frequencyOut = document.getElementById('frequency-out')
const type = document.getElementById('type')
const context = player.getContext('2d')
const audioCtx = new(window.AudioContext || window.webkitAudioContext)()
function sliderToFrequency(value) {
return 2 * Math.pow(10, value)
}
function nearestPianoKey(frequency) {
const keyNum = Math.round(12 * Math.log2(frequency / 440) + 49)
return 440 * Math.pow(2, ((keyNum - 49) / 12))
}
const gain = audioCtx.createGain()
gain.gain.value = volume.value
gain.connect(audioCtx.destination)
volumeOut.innerHTML = volume.value
frequencyOut.innerHTML = nearestPianoKey(sliderToFrequency(frequency.value))
volume.addEventListener('input', (evt) => {
gain.gain.value = volume.value
volumeOut.innerHTML = volume.value
})
frequency.addEventListener('input', (evt) => {
frequencyOut.innerHTML = nearestPianoKey(sliderToFrequency(frequency.value))
})
let OGain
function playSound() {
// create Oscillator node
const oscillator = audioCtx.createOscillator()
const ngain = audioCtx.createGain()
OGain = ngain
ngain.connect(gain)
const t = audioCtx.currentTime
const f = nearestPianoKey(sliderToFrequency(frequency.value))
let ct = t
let at = ct + parseFloat(ranges.attack.value)
let dt = at + parseFloat(ranges.decay.value)
let st = dt + parseFloat(ranges.sustain.value)
let rt = st + parseFloat(ranges.release.value)
...