This repository has been archived by the owner on Nov 3, 2021. It is now read-only.
/
tone_player.js
98 lines (81 loc) · 2.49 KB
/
tone_player.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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
'use strict';
const kMasterVolume = 0.5;
const kToneVolume = 0.7;
const kShortPressDuration = 0.25;
var TonePlayer = {
_audioContext: null,
_gainNode: null,
_playingNode: null,
init: function tp_init(channel) {
this.setChannel(channel);
},
ensureAudio: function tp_ensureAudio() {
if (this._audioContext)
return;
this._audioContext = new AudioContext();
this._gainNode = this._audioContext.createGain();
this._gainNode.gain.value = kMasterVolume;
this._gainNode.connect(this._audioContext.destination);
},
trashAudio: function tp_trashAudio() {
this.stop();
this._gainNode = null;
this._audioContext = null;
},
start: function tp_start(frequencies, shortPress) {
var now = this._audioContext.currentTime;
this._playingNode = this._audioContext.createGain();
var gain = this._playingNode.gain;
gain.setValueAtTime(0.0, now);
gain.linearRampToValueAtTime(1.0, now + 0.025);
gain.linearRampToValueAtTime(kToneVolume, now + 0.05);
if (shortPress) {
gain.setValueAtTime(kToneVolume, now + kShortPressDuration - 0.025);
gain.linearRampToValueAtTime(0.0, now + kShortPressDuration);
}
this._playingNode.connect(this._gainNode);
for (var i = 0; i < frequencies.length; ++i) {
var oscNode = this._audioContext.createOscillator();
oscNode.type = 'sine';
oscNode.frequency.value = frequencies[i];
oscNode.start(now);
if (shortPress) {
oscNode.stop(now + kShortPressDuration);
}
oscNode.connect(this._playingNode);
}
},
stop: function tp_stop() {
if (this._playingNode) {
this._playingNode.disconnect();
this._playingNode = null;
}
},
// Takes an array of steps, a step being:
// - frequency for channel 1
// - frequency for channel 2
// - duration
playSequence: function tp_playSequence(sequence, index) {
if (typeof index === 'undefined') {
index = 0;
}
if (index >= sequence.length) {
return;
}
this.ensureAudio();
var step = sequence[index];
var frequencies = step.slice(0, 2);
var duration = step[2];
this.start(frequencies, false);
setTimeout(function nextStep(self) {
self.stop();
self.playSequence(sequence, (index + 1));
}, duration, this);
},
setChannel: function tp_setChannel(channel) {
this.ensureAudio();
if (channel && (this._audioContext.mozAudioChannelType !== channel)) {
this._audioContext.mozAudioChannelType = channel;
}
}
};