added very simple chord support
This commit is contained in:
parent
e865c0ba87
commit
e7ea3a5db8
61
synth.html
61
synth.html
|
@ -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"/>
|
<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>
|
<span id="detunevoice1display" class="text-sm text-gray-700 ml-2">0</span>
|
||||||
</div>
|
</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>
|
<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>
|
</div>
|
||||||
|
@ -127,34 +133,33 @@
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-4">
|
<div>
|
||||||
<div class="flex">
|
<form style="padding: 15px">
|
||||||
<!-- White Keys -->
|
<fieldset>
|
||||||
<button class="bg-white h-24 w-12 border border-gray-400 relative">
|
<legend>Chords</legend>
|
||||||
<span class="absolute top-2 left-1/2 transform -translate-x-1/2">C</span>
|
<input type="radio" id="chordC" name="chordchoice" value="C" checked>
|
||||||
</button>
|
<label for="chordC">C</label>
|
||||||
<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>
|
<input type="radio" id="chordD" name="chordchoice" value="D">
|
||||||
</button>
|
<label for="chordD">D</label>
|
||||||
<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>
|
<input type="radio" id="chordE" name="chordchoice" value="E">
|
||||||
</button>
|
<label for="chordE">E</label>
|
||||||
<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>
|
<input type="radio" id="chordF" name="chordchoice" value="F">
|
||||||
</button>
|
<label for="chordF">F</label>
|
||||||
<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>
|
<input type="radio" id="chordG" name="chordchoice" value="G">
|
||||||
</button>
|
<label for="chordG">G</label>
|
||||||
<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>
|
<input type="radio" id="chordA" name="chordchoice" value="A">
|
||||||
</button>
|
<label for="chordA">A</label>
|
||||||
<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>
|
<input type="radio" id="chordB" name="chordchoice" value="B">
|
||||||
</button>
|
<label for="chordB">B</label>
|
||||||
<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>
|
</fieldset>
|
||||||
</button>
|
</form>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
65
synth.js
65
synth.js
|
@ -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 {
|
class Synth {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.audioContext = new AudioContext();
|
this.audioContext = new AudioContext();
|
||||||
|
@ -80,6 +100,14 @@ class Synth {
|
||||||
this.stopOsc(osc);
|
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(
|
function updateFrequency(
|
||||||
|
@ -114,6 +142,8 @@ function updateFrequency(
|
||||||
let octaveDisplay = document.getElementById(
|
let octaveDisplay = document.getElementById(
|
||||||
"octavedisplay" + (voiceIndex + 1)
|
"octavedisplay" + (voiceIndex + 1)
|
||||||
);
|
);
|
||||||
|
console.log(octaveDisplay);
|
||||||
|
console.log("octavedisplay" + (voiceIndex + 1));
|
||||||
octaveDisplay.value = 0;
|
octaveDisplay.value = 0;
|
||||||
console.log(noteInHz);
|
console.log(noteInHz);
|
||||||
console.log("current octave for voice: " + oscContainer.currentOctave);
|
console.log("current octave for voice: " + oscContainer.currentOctave);
|
||||||
|
@ -268,4 +298,39 @@ window.onload = function () {
|
||||||
console.log(detune);
|
console.log(detune);
|
||||||
updateFrequency(event, synth, osc, 0, null, null, 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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue