-
Notifications
You must be signed in to change notification settings - Fork 220
/
synth.js
62 lines (53 loc) · 1.86 KB
/
synth.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import { slurp } from './util.js';
import { normaliseWave, getWaveFunction } from './wave-things.js';
export const SAMPLE_RATE = 44100;
export const baseFrequency = 220;
let audioContext = null;
function getAudioContext() {
if (audioContext === null) {
const AudioContext = window.AudioContext || window.webkitAudioContext || false;
if (!AudioContext) {
// Web Audio API not supported :(
return null;
}
audioContext = new AudioContext();
}
return audioContext;
}
/**
*
* @param {function(number):number|Array<number>} wave
*/
export function playSoundWave(wave) {
if (wave.length == 0) {
// Do nothing if we have a nothing-lengthed wave.
return;
}
const baseVolume = 0.8;
const decay = 3;
if (wave.constructor === Array) {
// transform our wave array into a function we can call
wave = getWaveFunction(normaliseWave(wave));
}
const audioContext = getAudioContext();
if (audioContext === null) {
return false;
}
const buffer = audioContext.createBuffer(1, SAMPLE_RATE, SAMPLE_RATE);
const channel = buffer.getChannelData(0);
for (let i = 0; i < buffer.length; i ++) {
// Where we are in the sound, in seconds.
const t = i / SAMPLE_RATE;
// The waves are visually at a very low frequency, we need to bump that up a bunch
channel[i] += wave(baseFrequency * t);
}
const source = audioContext.createBufferSource();
source.buffer = buffer;
const gainNode = audioContext.createGain();
gainNode.gain.setValueAtTime(baseVolume, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.0001, audioContext.currentTime + decay);
source.connect(gainNode);
gainNode.connect(audioContext.destination);
source.start();
source.stop(audioContext.currentTime + decay);
}