MMitB - OscillatorNode / GainNode
by Keith McMillen
HTML
<div class='controls'>
<button class='start'>Start</button>
<button class='stop' disabled>Stop</button>
</div>
<hr>
<div class='waveforms'>
<button data-waveform='sine'>Sine</button>
<button data-waveform='square'>Square</button>
<button data-waveform='sawtooth'>Sawtooth</button>
<button data-waveform='triangle'>Triangle</button>
</div>
<hr>
<div class='notes'>
<button data-note='0'>unison</button>
<button data-note='300'>minor-third</button>
<button data-note='600'>tritone</button>
<button data-note='900'>minor-seventh</button>
<button data-note='1200'>octave</button>
</div>
<div class='display'>
<label for='freq'>Frequency <span class='freq'>220Hz</span>
<input class='freq-slider' name='freq' type='range' min='0' max='20000' step='1' value='220' />
</label>
<label for='detune'>Detune <span class='detune'>0 cents</span>
<input class='detune-slider' name='detune' type='range' min='-1000' max='1000' step='1' value='0' />
</label>
<label for='gain'>Gain <span class='gain'>0.25</span>
<input class='gain-slider' name='gain' type='range' min='0' max='1' step='0.1' value='0.25' />
</label>
</div>
CSS
body {
background-color: rgb(250, 250, 250);
}
button {
display: inline-block;
margin-bottom: 20px;
}
label {
display: block;
font-family: monospace;
line-height: 20px;
text-shadow: 1px 1px 3px #ccc;
}
input {
display: inline-block;
float: right;
width: 45%;
}
span {
display: inline-block;
width: 90px;
text-align: center;
font-weight: bold;
border: 1px solid #efefef;
border-radius: 3px;
background-color: white;
}
hr {
border-color: rgba(200, 200, 200, 0.1);
}
JavaScript
// create our AudioContext and Oscillator Nodes
var audioContext, osc, gain;
// assign our sliders and buttons to variables
var startButton = document.querySelector('.start'),
stopButton = document.querySelector('.stop'),
waveformButtons = document.querySelectorAll('.waveforms button'),
freqSlider = document.querySelector('.freq-slider'),
detuneSlider = document.querySelector('.detune-slider'),
gainSlider = document.querySelector('.gain-slider'),
gainDisplay = document.querySelector('.gain'),
freqDisplay = document.querySelector('.freq'),
detuneDisplay = document.querySelector('.detune');
// load our default value
init();
// setup start/stop
startButton.onclick = start;
stopButton.onclick = stop;
// setup waveform changes
addEventListenerBySelector('.waveforms button', 'click', function (event) {
var type = event.target.dataset.waveform;
changeType(type);
});
// setup note changes using detune
addEventListenerBySelector('.notes button', 'click', function (event) {
var note = event.target.dataset.note;
changeDetune(note);
});
// update frequency when slider moves
freqSlider.oninput = function () {
changeFreq(freqSlider.value);
}
// detune frequency when slider moves
detuneSlider.oninput = function () {
changeDetune(detuneSlider.value);
}
// update gain when slider moves
gainSlider.oninput = function () {
changeGain(gainSlider.value);
}
function init() {
audioContext = new(window.AudioContext || window.webkitAudioContext)();
gain = audioContext.createGain();
gain.gain.value = 0.25;
osc = audioContext.createOscillator();
osc.type = 'sine';
osc.frequency.value = 440;
osc.detune.value = 0;
osc.connect(gain);
osc.start(0);
}
// start everything by connecting to destination
function start() {
UI('start');
gain.connect(audioContext.destination);
}
// stop everything by connecting to destination
function stop() {
UI('stop');
...