simple-synth/basic.js

218 lines
5.1 KiB
JavaScript

let osc = null;
let gain = null;
let selectedWave = "square";
let baseFreq = 440;
let currentFreq = 261.63;
let notes = ["C", "D", "E", "F", "G", "A", "B"];
let arpInterval = null;
function octavehz(hz, octave) {
const val = parseFloat(octave);
return hz * 2 ** val;
}
function noteToHz(note) {
switch (note) {
case "C":
return 261.63;
case "D":
return 293.66;
case "E":
return 329.63;
case "F":
return 349.23;
case "G":
return 392;
case "A":
return 440;
case "B":
return 493.88;
default:
return 0;
}
}
window.onload = function () {
const audioContext = new AudioContext();
function updateOscFrequency() {
let selectedNoteButton = document.querySelector(
"input[name='notechoice']:checked"
);
let selectedOctaveButton = document.querySelector(
"input[name='octavechoice']:checked"
);
if (selectedNoteButton && selectedOctaveButton) {
let selectedNote = selectedNoteButton.value;
let selectedOctave = parseFloat(selectedOctaveButton.value);
let noteFreq = noteToHz(selectedNote);
let freqOctaveChoice = octavehz(noteFreq, selectedOctave);
if (osc) {
osc.frequency.setValueAtTime(
freqOctaveChoice,
audioContext.currentTime
);
}
}
}
function handleWaveformSelectionChange() {
let selectedRadioButton = document.querySelector(
"input[name='wavechoice']:checked"
);
if (selectedRadioButton) {
selectedWave = selectedRadioButton.value;
if (osc) {
osc.type = selectedWave;
}
console.log(selectedWave);
} else {
console.log("No radio button is selected.");
}
}
document.querySelectorAll("input[name='notechoice']").forEach((rb) => {
rb.addEventListener("change", updateOscFrequency);
});
document
.querySelectorAll("input[name='wavechoice']")
.forEach((radioButton) => {
radioButton.addEventListener("change", handleWaveformSelectionChange);
});
document.querySelectorAll("input[name='octavechoice']").forEach((rb) => {
rb.addEventListener("change", updateOscFrequency);
});
// handle keyboard
window.addEventListener("keydown", (event) => {
if (event.repeat) return;
switch (event.key) {
// play/stop
case "s":
{
if (osc) {
osc.stop();
osc = null;
}
}
break;
// "piano roll"
case "1":
selectNote("C");
break;
case "2":
selectNote("D");
break;
case "3":
selectNote("E");
break;
case "4":
selectNote("F");
break;
case "5":
selectNote("G");
break;
case "6":
selectNote("A");
break;
case "7":
selectNote("B");
break;
default:
// If the key is not 1-7, do nothing
break;
}
});
function selectNote(note) {
const radioButton = document.querySelector(
`input[name='notechoice'][value='${note}']`
);
if (radioButton) {
radioButton.checked = true;
updateOscFrequency();
} else {
console.error(`Radio button for note ${note} not found`);
}
}
// gain slider
const gainSlider = document.getElementById("gain");
const gainDisplay = document.getElementById("gainDisplay");
gainSlider.addEventListener("input", () => {
const level = parseFloat(gainSlider.value);
console.log(level);
gain.gain.setTargetAtTime(level, audioContext.currentTime, 0.01);
gainDisplay.textContent = level;
});
// start button
document.getElementById("start").addEventListener("click", () => {
if (!osc) {
osc = audioContext.createOscillator();
console.log("new osc created!");
}
if (!gain) {
gain = audioContext.createGain();
}
osc.type = selectedWave;
osc.frequency.setValueAtTime(currentFreq, audioContext.currentTime);
gain.gain.setTargetAtTime(
parseFloat(gainSlider.value),
audioContext.currentTime,
0
);
osc.connect(gain);
gain.connect(audioContext.destination);
osc.start();
audioContext.resume();
});
// stop button
document.getElementById("stop").addEventListener("click", () => {
if (osc) {
osc.stop();
osc = null;
if (arpInterval) {
clearInterval(arpInterval);
arpInterval = null;
}
} else {
console.log("no osc to stop");
}
});
// arp - work in progress
function startArp() {
if (!arpInterval) {
baseNote = "C";
let currentOctave = -2;
if (osc) {
arpInterval = setInterval(() => {
if (currentOctave > 2) {
currentOctave = -2;
}
let noteFreq = noteToHz(baseNote);
let freqOctaveChoice = octavehz(noteFreq, currentOctave);
osc.frequency.setValueAtTime(
freqOctaveChoice,
audioContext.currentTime
);
currentOctave++;
}, 100);
} else {
console.log("no osc to run arp on");
}
}
}
document.getElementById("arp").addEventListener("click", startArp);
};