-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaudio.js
More file actions
54 lines (45 loc) · 1.67 KB
/
Copy pathaudio.js
File metadata and controls
54 lines (45 loc) · 1.67 KB
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
const SAMPLE_RATE = 44100;
let audioContext = null;
function getAudioContext() {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
if (audioContext.state === 'suspended') {
audioContext.resume();
}
}
return audioContext;
}
function createWaveform(harmonicSeries) {
const normalizer = 1.0 / Object.values(harmonicSeries).reduce((sum, amplitude) => sum + amplitude, 0);
return (time, frequency) => {
return Object.entries(harmonicSeries).reduce((sum, [harmonic, amplitude]) => {
return sum + normalizer * amplitude * Math.sin(2 * Math.PI * frequency * harmonic * time);
}, 0);
};
}
function applyEnvelope(waveform, duration = 1.0, baseAmplitude = 1.0) {
return (time, frequency) => {
const amplitude = baseAmplitude * Math.max(0, 1.0 - time / duration);
return amplitude * waveform(time, frequency);
};
}
function combineWaves(wave, ratio, weight = 0.5) {
return (time, frequency) => {
return (1 - weight) * wave(time, frequency) + weight * wave(time, frequency * ratio);
};
}
function playSound(waveform, frequency, duration = 1.0) {
const context = getAudioContext();
const bufferSize = Math.ceil(SAMPLE_RATE * duration);
const buffer = context.createBuffer(1, bufferSize, SAMPLE_RATE);
const data = buffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) {
const time = i / SAMPLE_RATE;
data[i] = waveform(time, frequency);
}
const source = context.createBufferSource();
source.buffer = buffer;
source.connect(context.destination);
source.start();
return source;
}