added very simple chord support

This commit is contained in:
Emanuel Rodriguez 2023-10-09 22:34:14 -07:00
parent e865c0ba87
commit e7ea3a5db8
2 changed files with 98 additions and 28 deletions

View File

@ -40,6 +40,12 @@
<input id="detunevoice1" type="range" min="-5" max="5" value="0" step=".1" class="slider bg-gray-300 h-2 rounded-full outline-none"/>
<span id="detunevoice1display" class="text-sm text-gray-700 ml-2">0</span>
</div>
<div style="padding: 5px">
<label for="filtervoice1" class="block text-sm font-medium text-gray-700 mb-1">filter voice</label>
<input id="filtervoice1" type="range" min="700" max="1500" value="1000" step="1" class="slider bg-gray-300 h-2 rounded-full outline-none"/>
<span id="filtervoice1display" class="text-sm text-gray-700 ml-2">0</span>
</div>
<button id="activateVoice1" class="bg-green-700 hover:bg-green-600 text-white font-bold text-sm py-1 px-2 rounded">On</button>
</div>
@ -127,34 +133,33 @@
</fieldset>
</form>
</div>
<div class="p-4">
<div class="flex">
<!-- White Keys -->
<button class="bg-white h-24 w-12 border border-gray-400 relative">
<span class="absolute top-2 left-1/2 transform -translate-x-1/2">C</span>
</button>
<button class="bg-white h-24 w-12 border border-gray-400 relative">
<span class="absolute top-2 left-1/2 transform -translate-x-1/2">D</span>
</button>
<button class="bg-white h-24 w-12 border border-gray-400 relative">
<span class="absolute top-2 left-1/2 transform -translate-x-1/2">E</span>
</button>
<button class="bg-white h-24 w-12 border border-gray-400 relative">
<span class="absolute top-2 left-1/2 transform -translate-x-1/2">F</span>
</button>
<button class="bg-white h-24 w-12 border border-gray-400 relative">
<span class="absolute top-2 left-1/2 transform -translate-x-1/2">G</span>
</button>
<button class="bg-white h-24 w-12 border border-gray-400 relative">
<span class="absolute top-2 left-1/2 transform -translate-x-1/2">A</span>
</button>
<button class="bg-white h-24 w-12 border border-gray-400 relative">
<span class="absolute top-2 left-1/2 transform -translate-x-1/2">B</span>
</button>
<button class="bg-white h-24 w-12 border border-gray-400 relative">
<span class="absolute top-2 left-1/2 transform -translate-x-1/2">C</span>
</button>
</div>
<div>
<form style="padding: 15px">
<fieldset>
<legend>Chords</legend>
<input type="radio" id="chordC" name="chordchoice" value="C" checked>
<label for="chordC">C</label>
<input type="radio" id="chordD" name="chordchoice" value="D">
<label for="chordD">D</label>
<input type="radio" id="chordE" name="chordchoice" value="E">
<label for="chordE">E</label>
<input type="radio" id="chordF" name="chordchoice" value="F">
<label for="chordF">F</label>
<input type="radio" id="chordG" name="chordchoice" value="G">
<label for="chordG">G</label>
<input type="radio" id="chordA" name="chordchoice" value="A">
<label for="chordA">A</label>
<input type="radio" id="chordB" name="chordchoice" value="B">
<label for="chordB">B</label>
</fieldset>
</form>
</div>

View File

@ -19,6 +19,26 @@ function noteToHz(note) {
}
}
function composeChord(chord) {
switch (chord) {
case "C": {
return ["C", "G", "E"];
}
case "D": {
return ["D", "F", "A"];
}
case "E": {
return ["E", "G", "B"];
}
case "B": {
return ["A", "C", "E"];
}
default: {
return ["C", "D", "E"];
}
}
}
class Synth {
constructor() {
this.audioContext = new AudioContext();
@ -80,6 +100,14 @@ class Synth {
this.stopOsc(osc);
}
}
createFilter(type, freq, Q) {
const filter = this.audioContext.createBiquadFilter();
filter.type = type;
filter.frequency.setValueAtTime(freq, this.audioContext.currentTime);
filter.Q.setValueAtTime(Q, this.audioContext.currentTime);
return filter;
}
}
function updateFrequency(
@ -114,6 +142,8 @@ function updateFrequency(
let octaveDisplay = document.getElementById(
"octavedisplay" + (voiceIndex + 1)
);
console.log(octaveDisplay);
console.log("octavedisplay" + (voiceIndex + 1));
octaveDisplay.value = 0;
console.log(noteInHz);
console.log("current octave for voice: " + oscContainer.currentOctave);
@ -268,4 +298,39 @@ window.onload = function () {
console.log(detune);
updateFrequency(event, synth, osc, 0, null, null, detune);
});
const filterSliderVoice1 = document.getElementById("filtervoice1");
const filtervoice1Display = document.getElementById("filtervoice1display");
filterSliderVoice1.addEventListener("input", (event) => {
const osc = synth.oscillators[0];
let selectedFreq = parseFloat(filterSliderVoice1.value);
const lpf = synth.createFilter("lowpass", 500, 1);
osc.osc.connect(lpf);
lpf.connect(synth.gain);
});
// handle chord changes
document.querySelectorAll("input[name='chordchoice']").forEach((rb) => {
rb.addEventListener("change", (event) => {
let selectedChord = document.querySelector(
"input[name='chordchoice']:checked"
).value;
let notesForChord = composeChord(selectedChord);
console.log(notesForChord);
for (let i = 0; i < synth.oscillators.length; i++) {
if (synth.oscillators[i].isPlaying) {
console.log("playing note: " + notesForChord[i] + " on voice: " + i);
updateFrequency(
event,
synth,
synth.oscillators[i],
i,
notesForChord[i],
null,
null
);
}
}
});
});
};