Skip to content

Commit

Permalink
feat: create synth classes
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasmafra committed Jan 6, 2024
1 parent 8a77fc5 commit 771af92
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 102 deletions.
59 changes: 59 additions & 0 deletions piano/synth/AudioPlayer.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import Timbre from "./Timbre.mjs";

export default class AudioPlayer {
/** @type {Timbre} */
timbre = null;
frequency = null;
oscillatorNode = null;
gainNode = null;

constructor(timbre, frequency) {
this.timbre = timbre;
this.frequency = frequency;

this.oscillatorNode = timbre.audioCtx.createOscillator();
if (this.timbre.type === 'custom') {
this.oscillatorNode.setPeriodicWave(timbre.wave);
} else {
this.oscillatorNode.type = timbre.type;
}
this.oscillatorNode.frequency.value = frequency;

this.gainNode = timbre.audioCtx.createGain();
this.gainNode.gain.value = 0;

this.oscillatorNode
.connect(this.gainNode)
.connect(timbre.audioCtx.destination);
this.oscillatorNode.start();
}

start() {
const adsr = this.timbre.adsr;
let time = this.timbre.audioCtx.currentTime;
this.gainNode.gain.cancelScheduledValues(time);

this.gainNode.gain.setValueAtTime(0, time);

time += adsr.attackDuration;
this.gainNode.gain.linearRampToValueAtTime(adsr.attackAmplitude, time);

time += adsr.decayDuration;
this.gainNode.gain.linearRampToValueAtTime(adsr.decayAmplitude, time);

if (adsr.sustainDuration) {
time += adsr.sustainDuration;
this.gainNode.gain.linearRampToValueAtTime(0, time);
}
}

stop() {
const adsr = this.timbre.adsr;
let time = this.timbre.audioCtx.currentTime;
this.gainNode.gain.cancelScheduledValues(time);

time += adsr.releaseDuration;
this.gainNode.gain.linearRampToValueAtTime(0, time);
}

};
27 changes: 27 additions & 0 deletions piano/synth/Timbre.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export default class Timbre {
audioCtx = null;
type = 'sine';
wave = null;
adsr = {
attackAmplitude: 1,
attackDuration: 0.1,
decayAmplitude: 0.5,
decayDuration: 0.2,
sustainDuration: 3,
releaseDuration: 1,
};

constructor() {
this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
}

setWithHarmonics(harmonics) {
this.harmonics = harmonics;

this.type = 'custom';
this.wave = new PeriodicWave(this.audioCtx, {
real: new Float32Array(harmonics),
imag: new Float32Array(harmonics.length),
});
}
};
45 changes: 20 additions & 25 deletions piano/synth/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,51 +28,46 @@
</fieldset>
<br />
<fieldset>
<input id="config" type="button" value="Set Config" />
<br />
<input id="play" type="button" value="Start" />
<input id="stop" type="button" value="Stop" />
<br />
<input id="short" type="button" value="Play Short" />
</fieldset>

<script type="module">
import Synth from './synth.mjs';
import Timbre from './Timbre.mjs';
import AudioPlayer from './AudioPlayer.mjs';

const freq = 440;
const frequency = 440;
let audioPlayer = null;

function start() {
document.getElementById("config").onclick = () => {
if (audioPlayer) {
audioPlayer.stop();
} else {
Synth.start();
}
let harmonics = [
const timbre = new Timbre();
timbre.setWithHarmonics([
document.getElementById("h1").value/100,
document.getElementById("h2").value/100,
document.getElementById("h3").value/100,
document.getElementById("h4").value/100,
document.getElementById("h5").value/100,
];
let adsr = {
attackAmplitude: document.getElementById("aa").value/100,
attackDuration: document.getElementById("ad").value/100,
decayAmplitude: document.getElementById("da").value/100,
decayDuration: document.getElementById("dd").value/100,
sustainDuration: document.getElementById("sd").value/20,
releaseDuration: document.getElementById("rd").value/20,
};
audioPlayer = Synth.createAudioPlayer(freq, harmonics, adsr);
audioPlayer.start();
]);
timbre.adsr.attackAmplitude = document.getElementById("aa").value/100;
timbre.adsr.attackDuration = document.getElementById("ad").value/100;
timbre.adsr.decayAmplitude = document.getElementById("da").value/100;
timbre.adsr.decayDuration = document.getElementById("dd").value/100;
timbre.adsr.sustainDuration = document.getElementById("sd").value/20;
timbre.adsr.releaseDuration = document.getElementById("rd").value/20;
audioPlayer = new AudioPlayer(timbre, frequency);
};
function stop() {
if (audioPlayer)
audioPlayer.stop();
};
document.getElementById("play").onclick = start;
document.getElementById("stop").onclick = stop;
document.getElementById("play").onclick = () => audioPlayer.start();
document.getElementById("stop").onclick = () => audioPlayer.stop();
document.getElementById("short").onclick = () => {
start();
setTimeout(() => stop(), 200);
audioPlayer.start();
setTimeout(() => audioPlayer.stop(), 200);
};
</script>
</body>
Expand Down
77 changes: 0 additions & 77 deletions piano/synth/synth.mjs

This file was deleted.

0 comments on commit 771af92

Please sign in to comment.