wavesurfer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,385 @@
1
+ 'use strict';
2
+
3
+ WaveSurfer.WebAudio = {
4
+ scriptBufferSize: 256,
5
+ PLAYING_STATE: 0,
6
+ PAUSED_STATE: 1,
7
+ FINISHED_STATE: 2,
8
+
9
+ supportsWebAudio: function () {
10
+ return !!(window.AudioContext || window.webkitAudioContext);
11
+ },
12
+
13
+ getAudioContext: function () {
14
+ if (!WaveSurfer.WebAudio.audioContext) {
15
+ WaveSurfer.WebAudio.audioContext = new (
16
+ window.AudioContext || window.webkitAudioContext
17
+ );
18
+ }
19
+ return WaveSurfer.WebAudio.audioContext;
20
+ },
21
+
22
+ getOfflineAudioContext: function (sampleRate) {
23
+ if (!WaveSurfer.WebAudio.offlineAudioContext) {
24
+ WaveSurfer.WebAudio.offlineAudioContext = new (
25
+ window.OfflineAudioContext || window.webkitOfflineAudioContext
26
+ )(1, 2, sampleRate);
27
+ }
28
+ return WaveSurfer.WebAudio.offlineAudioContext;
29
+ },
30
+
31
+ init: function (params) {
32
+ this.params = params;
33
+ this.ac = params.audioContext || this.getAudioContext();
34
+
35
+ this.lastPlay = this.ac.currentTime;
36
+ this.startPosition = 0;
37
+ this.scheduledPause = null;
38
+
39
+ this.states = [
40
+ Object.create(WaveSurfer.WebAudio.state.playing),
41
+ Object.create(WaveSurfer.WebAudio.state.paused),
42
+ Object.create(WaveSurfer.WebAudio.state.finished)
43
+ ];
44
+
45
+ this.setState(this.PAUSED_STATE);
46
+
47
+ this.createVolumeNode();
48
+ this.createScriptNode();
49
+ this.createAnalyserNode();
50
+ this.setPlaybackRate(this.params.audioRate);
51
+ },
52
+
53
+ disconnectFilters: function () {
54
+ if (this.filters) {
55
+ this.filters.forEach(function (filter) {
56
+ filter && filter.disconnect();
57
+ });
58
+ this.filters = null;
59
+ // Reconnect direct path
60
+ this.analyser.connect(this.gainNode);
61
+ }
62
+ },
63
+
64
+ setState: function (state) {
65
+ if (this.state !== this.states[state]) {
66
+ this.state = this.states[state];
67
+ this.state.init.call(this);
68
+ }
69
+ },
70
+
71
+ // Unpacked filters
72
+ setFilter: function () {
73
+ this.setFilters([].slice.call(arguments));
74
+ },
75
+
76
+ /**
77
+ * @param {Array} filters Packed ilters array
78
+ */
79
+ setFilters: function (filters) {
80
+ // Remove existing filters
81
+ this.disconnectFilters();
82
+
83
+ // Insert filters if filter array not empty
84
+ if (filters && filters.length) {
85
+ this.filters = filters;
86
+
87
+ // Disconnect direct path before inserting filters
88
+ this.analyser.disconnect();
89
+
90
+ // Connect each filter in turn
91
+ filters.reduce(function (prev, curr) {
92
+ prev.connect(curr);
93
+ return curr;
94
+ }, this.analyser).connect(this.gainNode);
95
+ }
96
+
97
+ },
98
+
99
+ createScriptNode: function () {
100
+ var my = this;
101
+ var bufferSize = this.scriptBufferSize;
102
+ if (this.ac.createScriptProcessor) {
103
+ this.scriptNode = this.ac.createScriptProcessor(bufferSize);
104
+ } else {
105
+ this.scriptNode = this.ac.createJavaScriptNode(bufferSize);
106
+ }
107
+ this.scriptNode.connect(this.ac.destination);
108
+
109
+ this.scriptNode.onaudioprocess = function () {
110
+ var time = my.getCurrentTime();
111
+
112
+ if (my.buffer && time >= my.getDuration()) {
113
+ my.setState(my.FINISHED_STATE);
114
+ } else if (my.buffer && time >= my.scheduledPause) {
115
+ my.setState(my.PAUSED_STATE);
116
+ } else if (my.state === my.states[my.PLAYING_STATE]) {
117
+ my.fireEvent('audioprocess', time);
118
+ }
119
+ };
120
+ },
121
+
122
+ createAnalyserNode: function () {
123
+ this.analyser = this.ac.createAnalyser();
124
+ this.analyser.connect(this.gainNode);
125
+ },
126
+
127
+ /**
128
+ * Create the gain node needed to control the playback volume.
129
+ */
130
+ createVolumeNode: function () {
131
+ // Create gain node using the AudioContext
132
+ if (this.ac.createGain) {
133
+ this.gainNode = this.ac.createGain();
134
+ } else {
135
+ this.gainNode = this.ac.createGainNode();
136
+ }
137
+ // Add the gain node to the graph
138
+ this.gainNode.connect(this.ac.destination);
139
+ },
140
+
141
+ /**
142
+ * Set the gain to a new value.
143
+ *
144
+ * @param {Number} newGain The new gain, a floating point value
145
+ * between 0 and 1. 0 being no gain and 1 being maximum gain.
146
+ */
147
+ setVolume: function (newGain) {
148
+ this.gainNode.gain.value = newGain;
149
+ },
150
+
151
+ /**
152
+ * Get the current gain.
153
+ *
154
+ * @returns {Number} The current gain, a floating point value
155
+ * between 0 and 1. 0 being no gain and 1 being maximum gain.
156
+ */
157
+ getVolume: function () {
158
+ return this.gainNode.gain.value;
159
+ },
160
+
161
+ decodeArrayBuffer: function (arraybuffer, callback, errback) {
162
+ if (!this.offlineAc) {
163
+ this.offlineAc = this.getOfflineAudioContext(this.ac ? this.ac.sampleRate : 44100);
164
+ }
165
+ this.offlineAc.decodeAudioData(arraybuffer, (function (data) {
166
+ callback(data);
167
+ }).bind(this), errback);
168
+ },
169
+
170
+ /**
171
+ * @returns {Array} Array of peaks or array of arrays of peaks.
172
+ */
173
+ getPeaks: function (length) {
174
+ var sampleSize = this.buffer.length / length;
175
+ var sampleStep = ~~(sampleSize / 10) || 1;
176
+ var channels = this.buffer.numberOfChannels;
177
+ var splitPeaks = [];
178
+ var mergedPeaks = [];
179
+
180
+ for (var c = 0; c < channels; c++) {
181
+ var peaks = splitPeaks[c] = [];
182
+ var chan = this.buffer.getChannelData(c);
183
+
184
+ for (var i = 0; i < length; i++) {
185
+ var start = ~~(i * sampleSize);
186
+ var end = ~~(start + sampleSize);
187
+ var max = 0;
188
+ for (var j = start; j < end; j += sampleStep) {
189
+ var value = chan[j];
190
+ if (value > max) {
191
+ max = value;
192
+ // faster than Math.abs
193
+ } else if (-value > max) {
194
+ max = -value;
195
+ }
196
+ }
197
+ peaks[i] = max;
198
+
199
+ if (c == 0 || max > mergedPeaks[i]) {
200
+ mergedPeaks[i] = max;
201
+ }
202
+ }
203
+ }
204
+
205
+ return this.params.splitChannels ? splitPeaks : mergedPeaks;
206
+ },
207
+
208
+ getPlayedPercents: function () {
209
+ return this.state.getPlayedPercents.call(this);
210
+ },
211
+
212
+ disconnectSource: function () {
213
+ if (this.source) {
214
+ this.source.disconnect();
215
+ }
216
+ },
217
+
218
+ destroy: function () {
219
+ if (!this.isPaused()) {
220
+ this.pause();
221
+ }
222
+ this.unAll();
223
+ this.buffer = null;
224
+ this.disconnectFilters();
225
+ this.disconnectSource();
226
+ this.gainNode.disconnect();
227
+ this.scriptNode.disconnect();
228
+ this.analyser.disconnect();
229
+ },
230
+
231
+ load: function (buffer) {
232
+ this.startPosition = 0;
233
+ this.lastPlay = this.ac.currentTime;
234
+ this.buffer = buffer;
235
+ this.createSource();
236
+ },
237
+
238
+ createSource: function () {
239
+ this.disconnectSource();
240
+ this.source = this.ac.createBufferSource();
241
+
242
+ //adjust for old browsers.
243
+ this.source.start = this.source.start || this.source.noteGrainOn;
244
+ this.source.stop = this.source.stop || this.source.noteOff;
245
+
246
+ this.source.playbackRate.value = this.playbackRate;
247
+ this.source.buffer = this.buffer;
248
+ this.source.connect(this.analyser);
249
+ },
250
+
251
+ isPaused: function () {
252
+ return this.state !== this.states[this.PLAYING_STATE];
253
+ },
254
+
255
+ getDuration: function () {
256
+ if (!this.buffer) {
257
+ return 0;
258
+ }
259
+ return this.buffer.duration;
260
+ },
261
+
262
+ seekTo: function (start, end) {
263
+ this.scheduledPause = null;
264
+
265
+ if (start == null) {
266
+ start = this.getCurrentTime();
267
+ if (start >= this.getDuration()) {
268
+ start = 0;
269
+ }
270
+ }
271
+ if (end == null) {
272
+ end = this.getDuration();
273
+ }
274
+
275
+ this.startPosition = start;
276
+ this.lastPlay = this.ac.currentTime;
277
+
278
+ if (this.state === this.states[this.FINISHED_STATE]) {
279
+ this.setState(this.PAUSED_STATE);
280
+ }
281
+
282
+ return { start: start, end: end };
283
+ },
284
+
285
+ getPlayedTime: function () {
286
+ return (this.ac.currentTime - this.lastPlay) * this.playbackRate;
287
+ },
288
+
289
+ /**
290
+ * Plays the loaded audio region.
291
+ *
292
+ * @param {Number} start Start offset in seconds,
293
+ * relative to the beginning of a clip.
294
+ * @param {Number} end When to stop
295
+ * relative to the beginning of a clip.
296
+ */
297
+ play: function (start, end) {
298
+ // need to re-create source on each playback
299
+ this.createSource();
300
+
301
+ var adjustedTime = this.seekTo(start, end);
302
+
303
+ start = adjustedTime.start;
304
+ end = adjustedTime.end;
305
+
306
+ this.scheduledPause = end;
307
+
308
+ this.source.start(0, start, end - start);
309
+
310
+ this.setState(this.PLAYING_STATE);
311
+ },
312
+
313
+ /**
314
+ * Pauses the loaded audio.
315
+ */
316
+ pause: function () {
317
+ this.scheduledPause = null;
318
+
319
+ this.startPosition += this.getPlayedTime();
320
+ this.source && this.source.stop(0);
321
+
322
+ this.setState(this.PAUSED_STATE);
323
+ },
324
+
325
+ /**
326
+ * Returns the current time in seconds relative to the audioclip's duration.
327
+ */
328
+ getCurrentTime: function () {
329
+ return this.state.getCurrentTime.call(this);
330
+ },
331
+
332
+ /**
333
+ * Set the audio source playback rate.
334
+ */
335
+ setPlaybackRate: function (value) {
336
+ value = value || 1;
337
+ if (this.isPaused()) {
338
+ this.playbackRate = value;
339
+ } else {
340
+ this.pause();
341
+ this.playbackRate = value;
342
+ this.play();
343
+ }
344
+ }
345
+ };
346
+
347
+ WaveSurfer.WebAudio.state = {};
348
+
349
+ WaveSurfer.WebAudio.state.playing = {
350
+ init: function () {
351
+ },
352
+ getPlayedPercents: function () {
353
+ var duration = this.getDuration();
354
+ return (this.getCurrentTime() / duration) || 0;
355
+ },
356
+ getCurrentTime: function () {
357
+ return this.startPosition + this.getPlayedTime();
358
+ }
359
+ };
360
+
361
+ WaveSurfer.WebAudio.state.paused = {
362
+ init: function () {
363
+ },
364
+ getPlayedPercents: function () {
365
+ var duration = this.getDuration();
366
+ return (this.getCurrentTime() / duration) || 0;
367
+ },
368
+ getCurrentTime: function () {
369
+ return this.startPosition;
370
+ }
371
+ };
372
+
373
+ WaveSurfer.WebAudio.state.finished = {
374
+ init: function () {
375
+ this.fireEvent('finish');
376
+ },
377
+ getPlayedPercents: function () {
378
+ return 1;
379
+ },
380
+ getCurrentTime: function () {
381
+ return this.getDuration();
382
+ }
383
+ };
384
+
385
+ WaveSurfer.util.extend(WaveSurfer.WebAudio, WaveSurfer.Observer);
@@ -0,0 +1,6 @@
1
+ //= require plugin/wavesurfer.elan
2
+ //= require plugin/wavesurfer.microphone
3
+ //= require plugin/wavesurfer.minimap
4
+ //= require plugin/wavesurfer.regions
5
+ //= require plugin/wavesurfer.spectrogram
6
+ //= require plugin/wavesurfer.timeline
@@ -0,0 +1,6 @@
1
+ //= require src/wavesurfer
2
+ //= require src/util
3
+ //= require src/webaudio
4
+ //= require src/mediaelement
5
+ //= require src/drawer
6
+ //= require src/drawer.canvas
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wavesurfer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Viktor Oleksyn
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: wavesurfer.js for the Rails asset pipeline
42
+ email:
43
+ - bartezic@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/wavesurfer.rb
49
+ - lib/wavesurfer/version.rb
50
+ - vendor/assets/javascripts/plugin/wavesurfer.elan.js
51
+ - vendor/assets/javascripts/plugin/wavesurfer.microphone.js
52
+ - vendor/assets/javascripts/plugin/wavesurfer.minimap.js
53
+ - vendor/assets/javascripts/plugin/wavesurfer.regions.js
54
+ - vendor/assets/javascripts/plugin/wavesurfer.spectrogram.js
55
+ - vendor/assets/javascripts/plugin/wavesurfer.timeline.js
56
+ - vendor/assets/javascripts/src/drawer.canvas.js
57
+ - vendor/assets/javascripts/src/drawer.js
58
+ - vendor/assets/javascripts/src/mediaelement.js
59
+ - vendor/assets/javascripts/src/util.js
60
+ - vendor/assets/javascripts/src/wavesurfer.js
61
+ - vendor/assets/javascripts/src/webaudio.js
62
+ - vendor/assets/javascripts/wavesurfer-plugins.js
63
+ - vendor/assets/javascripts/wavesurfer.js
64
+ homepage: https://github.com/bartezic/wavesurfer
65
+ licenses:
66
+ - MIT
67
+ metadata: {}
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project:
84
+ rubygems_version: 2.2.2
85
+ signing_key:
86
+ specification_version: 4
87
+ summary: wavesurfer.js for the Rails asset pipeline.
88
+ test_files: []