wobbulator
parent
f6b3f603f5
commit
539f6262a7
@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||||||
|
<title>Untitled</title>
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>A remake (2024) of <a href="https://webaudio.prototyping.bbc.co.uk/wobbulator/">this artcle on the wobbulator from the BBC Radiophonic workshop</a>.</p>
|
||||||
|
<input type="checkbox" id="power">
|
||||||
|
<input type="range" id="modfreq" min="0" max="50" value="10" step="1">
|
||||||
|
<input type="range" id="moddepth" min="0" max="200" value="100" step="1">
|
||||||
|
<input type="range" id="freq" min="50" max="5000" value="440" step="1">
|
||||||
|
<input type="range" id="vol" min="0" max="1" value="1" step="0.01">
|
||||||
|
<select id="waveform">
|
||||||
|
<option>sine</option>
|
||||||
|
<option>square</option>
|
||||||
|
<option>sawtooth</option>
|
||||||
|
</select>
|
||||||
|
<script src="wobbulator.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,50 @@
|
|||||||
|
let ac = new AudioContext();
|
||||||
|
|
||||||
|
// There are four main audio nodes in our webaudio API patchbay
|
||||||
|
// The primary oscillator + the modulating oscillator.
|
||||||
|
// The amplitude of the modulation oscillator (its 'depth') is modified by passing the output through a GainNode.
|
||||||
|
// Another GainNode controls the main volume.
|
||||||
|
let oscillator = ac.createOscillator();
|
||||||
|
let modulator = ac.createOscillator();
|
||||||
|
let modulation_gain = ac.createGain();
|
||||||
|
let main_gain = ac.createGain();
|
||||||
|
|
||||||
|
// Make the patches!
|
||||||
|
modulator.connect(modulation_gain);
|
||||||
|
modulation_gain.connect(oscillator.frequency);
|
||||||
|
oscillator.connect(main_gain);
|
||||||
|
main_gain.connect(ac.destination);
|
||||||
|
|
||||||
|
// Once an OscillatorNode is stopped it cannot be restarted.
|
||||||
|
// We turn both oscillators on from the beginning,
|
||||||
|
// and achieve the on/off effect by modifying the main gain.
|
||||||
|
oscillator.start(0);
|
||||||
|
modulator.start(0);
|
||||||
|
|
||||||
|
// inputs
|
||||||
|
let freq_input = document.querySelector("#freq");
|
||||||
|
let modfreq_input = document.querySelector("#modfreq")
|
||||||
|
let moddepth_input = document.querySelector("#moddepth")
|
||||||
|
let vol_input = document.querySelector("#vol");
|
||||||
|
let power_checkbox = document.querySelector("#power");
|
||||||
|
let waveform_select = document.querySelector("#waveform");
|
||||||
|
|
||||||
|
oscillator.frequency.value = freq_input.value;
|
||||||
|
modulation_gain.gain.value = moddepth_input.value;
|
||||||
|
modulator.frequency.value = modfreq_input.value;
|
||||||
|
main_gain.gain.value = power_checkbox.checked ? vol_input.value : 0;
|
||||||
|
|
||||||
|
freq_input.addEventListener("input", e => { oscillator.frequency.value = freq_input.value; });
|
||||||
|
power_checkbox.addEventListener("change", e => {
|
||||||
|
main_gain.gain.value = power_checkbox.checked ? vol_input.value : 0;
|
||||||
|
// check if context is in suspended state (autoplay policy)
|
||||||
|
if (ac.state === "suspended") { ac.resume(); }
|
||||||
|
});
|
||||||
|
modfreq_input.addEventListener("input", e => { modulator.frequency.value = modfreq_input.value });
|
||||||
|
moddepth_input.addEventListener("input", e => { modulation_gain.gain.value = moddepth_input.value });
|
||||||
|
vol_input.addEventListener("input", e => { main_gain.gain.value = power_checkbox.checked ? vol_input.value : 0 });
|
||||||
|
|
||||||
|
oscillator.type = waveform_select.value;
|
||||||
|
waveform_select.addEventListener("input", e => {
|
||||||
|
oscillator.type = waveform_select.value;
|
||||||
|
});
|
Loading…
Reference in New Issue