/
Float32ArrayWavetablePlayerWithGain.js
184 lines (155 loc) · 4.8 KB
/
Float32ArrayWavetablePlayerWithGain.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// + Construction {{{
Float32ArrayWavetablePlayerWithGain = function (i_audioContext, i_userSampleRate)
// Plays Float32Array wavetables.
//
// Params:
// i_audioContext:
// (AudioContext)
// i_userSampleRate:
// Either (integer number)
// The sample rate that the arrays that will be later supplied should be played at.
// or (null or undefined)
// use default of i_audioContext.sampleRate.
{
// Apply default arguments
if (!i_userSampleRate)
i_userSampleRate = i_audioContext.sampleRate;
//
this.m_audioContext = i_audioContext;
// m_audioContext
// (AudioContext)
this.m_userSampleRate = i_userSampleRate;
// m_userSampleRate
// (integer number)
this.m_useBufferPool = true;
// m_useBufferPool
// (boolean)
// Whether to reuse AudioBuffer objects.
this.m_freeBuffers = [];
// m_freeBuffers
// (array of AudioBuffer)
// Audio buffers which were previously used to play a Float32Array which has now finished playing.
// They are kept for possible reuse with subsequent Float32Arrays.
};
// + }}}
// + Settings {{{
Float32ArrayWavetablePlayerWithGain.prototype.setUserSampleRate = function (i_sampleRate)
{
// Save value
this.m_userSampleRate = i_sampleRate;
// Make new array for AudioBuffer objects
// (existing ones can't be reused if the sample rate has changed)
this.m_freeBuffers = [];
//this._updateUserBuffers(this.m_userSampleRate, this.m_noteLengthInSeconds);
//// Re-prerender the formula into all the new buffers
//this.setUserCode(this.m_userCode);
};
Float32ArrayWavetablePlayerWithGain.prototype.getUserSampleRate = function ()
{
return this.m_userSampleRate;
};
Float32ArrayWavetablePlayerWithGain.prototype.useBufferPool = function (i_usePool)
// Params:
// i_usePool:
// (boolean)
{
this.m_useBufferPool = i_usePool;
};
// + }}}
// + Playing {{{
Float32ArrayWavetablePlayerWithGain.prototype._getFreeAudioBuffer = function (i_sampleCount)
// Returns:
// (AudioBuffer)
{
// If using the buffer pool and
// if there is a previously used buffer that is big enough,
// remove it from the free list and return it
if (this.m_useBufferPool)
{
for (var bufferNo = 0; bufferNo < this.m_freeBuffers.length; ++bufferNo)
{
if (this.m_freeBuffers[bufferNo].length >= i_sampleCount)
{
return this.m_freeBuffers.splice(bufferNo, 1)[0];
}
}
}
// Otherwise just create a new buffer and return it
return this.m_audioContext.createBuffer(1, i_sampleCount, this.m_userSampleRate);
};
Float32ArrayWavetablePlayerWithGain.prototype.play = function (i_srcSamples, i_gain)
// Params:
// i_srcSamples:
// (Float32Array)
// i_gain:
// Either (float number)
// Gain in range [0 .. 1]
// or (null or undefined)
// Use default of 1
//
// Returns:
// (AudioBufferSourceNode)
// You can call .stop() on this if you want to stop the sound early.
{
// Apply default arguments
if (i_gain === null || i_gain === undefined)
i_gain = 1;
// Get AudioBuffer
var audioBuffer = this._getFreeAudioBuffer(i_srcSamples.length);
// Copy sound from input Float32Array to AudioBuffer
if (audioBuffer.copyToChannel)
{
audioBuffer.copyToChannel(i_srcSamples, 0, 0);
}
else
{
var channel = audioBuffer.getChannelData(0);
for (var sampleNo = 0, end = i_srcSamples.length; sampleNo < end; ++sampleNo)
{
channel[sampleNo] = i_srcSamples[sampleNo];
}
}
// Zero out any excess capacity in the buffer
if (i_srcSamples.length < audioBuffer.length)
{
var channel = audioBuffer.getChannelData(0);
for (var sampleNo = i_srcSamples.length, end = audioBuffer.length; sampleNo < end; ++sampleNo)
{
channel[sampleNo] = 0;
}
}
// Play the first i_srcSamples of the AudioBuffer once
var node = this.m_audioContext.createBufferSource();
node.buffer = audioBuffer;
//
var gainNode = this.m_audioContext.createGain();
gainNode.gain.value = i_gain;
node.connect(gainNode);
//
gainNode.connect(this.m_audioContext.destination);
// If using the buffer pool then reclaim the buffer when it finishes playing
if (this.m_useBufferPool)
{
var me = this;
node.onended = function (i_event) {
me.m_freeBuffers.push(audioBuffer);
};
}
//
node.start(0, 0, i_srcSamples.length / this.m_userSampleRate);
//
return node;
};
// + }}}
/*
Float32ArrayWavetablePlayerWithGain.prototype._destroyFloat32ArrayWavetablePlayerWithGain = function ()
{
this._destroyNonRealtimeBuffers();
}
*/
/*
Float32ArrayWavetablePlayerWithGain.prototype._destroyNonRealtimeBuffers = function ()
{
this.m_freeBuffers = null;
};
*/