wavesurfer-rails 0.1.12 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,223 @@
1
+ 'use strict';
2
+
3
+ WaveSurfer.Spectrogram = {
4
+ init: function (params) {
5
+ this.params = params;
6
+ var wavesurfer = this.wavesurfer = params.wavesurfer;
7
+
8
+ if (!this.wavesurfer) {
9
+ throw Error('No WaveSurfer instance provided');
10
+ }
11
+
12
+ this.frequenciesDataUrl = params.frequenciesDataUrl;
13
+
14
+ var drawer = this.drawer = this.wavesurfer.drawer;
15
+ this.buffer = this.wavesurfer.backend.buffer;
16
+
17
+ this.container = 'string' == typeof params.container ?
18
+ document.querySelector(params.container) : params.container;
19
+
20
+ if (!this.container) {
21
+ throw Error('No container for WaveSurfer spectrogram');
22
+ }
23
+
24
+ this.width = drawer.width;
25
+ this.pixelRatio = this.params.pixelRatio || wavesurfer.params.pixelRatio;
26
+ this.fftSamples = this.params.fftSamples || wavesurfer.params.fftSamples || 512;
27
+ this.height = this.fftSamples / 2;
28
+
29
+ this.createWrapper();
30
+ this.createCanvas();
31
+ this.render();
32
+
33
+ wavesurfer.drawer.wrapper.onscroll = this.updateScroll.bind(this);
34
+ wavesurfer.on('destroy', this.destroy.bind(this));
35
+ },
36
+
37
+ destroy: function () {
38
+ this.unAll();
39
+ if (this.wrapper) {
40
+ this.wrapper.parentNode.removeChild(this.wrapper);
41
+ this.wrapper = null;
42
+ }
43
+ },
44
+
45
+ createWrapper: function () {
46
+ var prevSpectrogram = this.container.querySelector('spectrogram');
47
+ if (prevSpectrogram) {
48
+ this.container.removeChild(prevSpectrogram);
49
+ }
50
+
51
+ var wsParams = this.wavesurfer.params;
52
+
53
+ this.wrapper = this.container.appendChild(
54
+ document.createElement('spectrogram')
55
+ );
56
+ this.drawer.style(this.wrapper, {
57
+ display: 'block',
58
+ position: 'relative',
59
+ userSelect: 'none',
60
+ webkitUserSelect: 'none',
61
+ height: this.height + 'px'
62
+ });
63
+
64
+ if (wsParams.fillParent || wsParams.scrollParent) {
65
+ this.drawer.style(this.wrapper, {
66
+ width: '100%',
67
+ overflowX: 'hidden',
68
+ overflowY: 'hidden'
69
+ });
70
+ }
71
+
72
+ var my = this;
73
+ this.wrapper.addEventListener('click', function (e) {
74
+ e.preventDefault();
75
+ var relX = 'offsetX' in e ? e.offsetX : e.layerX;
76
+ my.fireEvent('click', (relX / my.scrollWidth) || 0);
77
+ });
78
+ },
79
+
80
+ createCanvas: function () {
81
+ var canvas = this.canvas = this.wrapper.appendChild(
82
+ document.createElement('canvas')
83
+ );
84
+
85
+ this.spectrCc = canvas.getContext('2d');
86
+
87
+ this.wavesurfer.drawer.style(canvas, {
88
+ position: 'absolute',
89
+ zIndex: 4
90
+ });
91
+ },
92
+
93
+ render: function () {
94
+ this.updateCanvasStyle();
95
+
96
+ if (this.frequenciesDataUrl) {
97
+ this.loadFrequenciesData(this.frequenciesDataUrl);
98
+ }
99
+ else {
100
+ this.getFrequencies(this.drawSpectrogram);
101
+ }
102
+ },
103
+
104
+ updateCanvasStyle: function () {
105
+ var width = Math.round(this.width / this.pixelRatio) + 'px';
106
+ this.canvas.width = this.width;
107
+ this.canvas.height = this.height;
108
+ this.canvas.style.width = width;
109
+ },
110
+
111
+ drawSpectrogram: function(frequenciesData, my) {
112
+ var spectrCc = my.spectrCc;
113
+
114
+ var length = my.wavesurfer.backend.getDuration();
115
+ var height = my.height;
116
+
117
+ var pixels = my.resample(frequenciesData);
118
+
119
+ var heightFactor = 2 / my.buffer.numberOfChannels;
120
+
121
+ for (var i = 0; i < pixels.length; i++) {
122
+ for (var j = 0; j < pixels[i].length; j++) {
123
+ var colorValue = 255 - pixels[i][j];
124
+ my.spectrCc.fillStyle = 'rgb(' + colorValue + ', ' + colorValue + ', ' + colorValue + ')';
125
+ my.spectrCc.fillRect(i, height - j * heightFactor, 1, 1 * heightFactor);
126
+ }
127
+ }
128
+ },
129
+
130
+ getFrequencies: function(callback) {
131
+ var fftSamples = this.fftSamples;
132
+ var buffer = this.buffer;
133
+
134
+ var frequencies = [];
135
+ var context = new window.OfflineAudioContext(1, buffer.length, buffer.sampleRate);
136
+ var source = context.createBufferSource();
137
+ var processor = context.createScriptProcessor(0, 1, 1);
138
+
139
+ var analyser = context.createAnalyser();
140
+ analyser.fftSize = fftSamples;
141
+ analyser.smoothingTimeConstant = (this.width / buffer.duration < 10) ? 0.75 : 0.25;
142
+
143
+ source.buffer = buffer;
144
+
145
+ source.connect(analyser);
146
+ analyser.connect(processor);
147
+ processor.connect(context.destination);
148
+
149
+ processor.onaudioprocess = function () {
150
+ var array = new Uint8Array(analyser.frequencyBinCount);
151
+ analyser.getByteFrequencyData(array);
152
+ frequencies.push(array);
153
+ };
154
+
155
+ source.start(0);
156
+ context.startRendering();
157
+
158
+ var my = this;
159
+ context.oncomplete = function() { callback(frequencies, my); };
160
+ },
161
+
162
+ loadFrequenciesData: function (url) {
163
+ var my = this;
164
+
165
+ var ajax = WaveSurfer.util.ajax({ url: url });
166
+
167
+ ajax.on('success', function(data) { my.drawSpectrogram(JSON.parse(data), my); });
168
+ ajax.on('error', function (e) {
169
+ my.fireEvent('error', 'XHR error: ' + e.target.statusText);
170
+ });
171
+
172
+ return ajax;
173
+ },
174
+
175
+ updateScroll: function(e) {
176
+ this.wrapper.scrollLeft = e.target.scrollLeft;
177
+ },
178
+
179
+ resample: function(oldMatrix, columnsNumber) {
180
+ var columnsNumber = this.width;
181
+ var newMatrix = [];
182
+
183
+ var oldPiece = 1 / oldMatrix.length;
184
+ var newPiece = 1 / columnsNumber;
185
+
186
+ for (var i = 0; i < columnsNumber; i++) {
187
+ var column = new Array(oldMatrix[0].length);
188
+
189
+ for (var j = 0; j < oldMatrix.length; j++) {
190
+ var oldStart = j * oldPiece;
191
+ var oldEnd = oldStart + oldPiece;
192
+ var newStart = i * newPiece;
193
+ var newEnd = newStart + newPiece;
194
+
195
+ var overlap = (oldEnd <= newStart || newEnd <= oldStart) ?
196
+ 0 :
197
+ Math.min(Math.max(oldEnd, newStart), Math.max(newEnd, oldStart)) -
198
+ Math.max(Math.min(oldEnd, newStart), Math.min(newEnd, oldStart));
199
+
200
+ if (overlap > 0) {
201
+ for (var k = 0; k < oldMatrix[0].length; k++) {
202
+ if (column[k] == null) {
203
+ column[k] = 0;
204
+ }
205
+ column[k] += (overlap / newPiece) * oldMatrix[j][k];
206
+ }
207
+ }
208
+ }
209
+
210
+ var intColumn = new Uint8Array(oldMatrix[0].length);
211
+
212
+ for (var k = 0; k < oldMatrix[0].length; k++) {
213
+ intColumn[k] = column[k];
214
+ }
215
+
216
+ newMatrix.push(intColumn);
217
+ }
218
+
219
+ return newMatrix;
220
+ }
221
+ };
222
+
223
+ WaveSurfer.util.extend(WaveSurfer.Spectrogram, WaveSurfer.Observer);
@@ -0,0 +1,196 @@
1
+ (function (root, factory) {
2
+ if (typeof define === 'function' && define.amd) {
3
+ define(['wavesurfer'], factory);
4
+ } else {
5
+ root.WaveSurfer.Timeline = factory(root.WaveSurfer);
6
+ }
7
+ }(this, function (WaveSurfer) {
8
+ 'use strict';
9
+
10
+ WaveSurfer.Timeline = {
11
+ init: function (params) {
12
+ this.params = params;
13
+ var wavesurfer = this.wavesurfer = params.wavesurfer;
14
+
15
+ if (!this.wavesurfer) {
16
+ throw Error('No WaveSurfer intance provided');
17
+ }
18
+
19
+ var drawer = this.drawer = this.wavesurfer.drawer;
20
+
21
+ this.container = 'string' == typeof params.container ?
22
+ document.querySelector(params.container) : params.container;
23
+
24
+ if (!this.container) {
25
+ throw Error('No container for WaveSurfer timeline');
26
+ }
27
+
28
+ this.width = drawer.width;
29
+ this.height = this.params.height || 20;
30
+ this.notchPercentHeight = this.params.notchPercentHeight || 90;
31
+ this.primaryColor = this.params.primaryColor || '#000';
32
+ this.secondaryColor = this.params.secondaryColor || '#c0c0c0';
33
+ this.primaryFontColor = this.params.primaryFontColor || '#000';
34
+ this.secondaryFontColor = this.params.secondaryFontColor || '#000';
35
+ this.fontFamily = this.params.fontFamily || 'Arial';
36
+ this.fontSize = this.params.fontSize || 10;
37
+
38
+ this.createWrapper();
39
+ this.createCanvas();
40
+ this.render();
41
+
42
+ wavesurfer.drawer.wrapper.onscroll = this.updateScroll.bind(this);
43
+ wavesurfer.on('redraw', this.render.bind(this));
44
+ wavesurfer.on('destroy', this.destroy.bind(this));
45
+ },
46
+
47
+ destroy: function () {
48
+ this.unAll();
49
+ if (this.wrapper && this.wrapper.parentNode) {
50
+ this.wrapper.parentNode.removeChild(this.wrapper);
51
+ this.wrapper = null;
52
+ }
53
+ },
54
+
55
+ createWrapper: function () {
56
+ var prevTimeline = this.container.querySelector('timeline');
57
+ if (prevTimeline) {
58
+ this.container.removeChild(prevTimeline);
59
+ }
60
+
61
+ var wsParams = this.wavesurfer.params;
62
+ this.wrapper = this.container.appendChild(
63
+ document.createElement('timeline')
64
+ );
65
+ this.drawer.style(this.wrapper, {
66
+ display: 'block',
67
+ position: 'relative',
68
+ userSelect: 'none',
69
+ webkitUserSelect: 'none',
70
+ height: this.height + 'px'
71
+ });
72
+
73
+ if (wsParams.fillParent || wsParams.scrollParent) {
74
+ this.drawer.style(this.wrapper, {
75
+ width: '100%',
76
+ overflowX: 'hidden',
77
+ overflowY: 'hidden'
78
+ });
79
+ }
80
+
81
+ var my = this;
82
+ this.wrapper.addEventListener('click', function (e) {
83
+ e.preventDefault();
84
+ var relX = 'offsetX' in e ? e.offsetX : e.layerX;
85
+ my.fireEvent('click', (relX / my.wrapper.scrollWidth) || 0);
86
+ });
87
+ },
88
+
89
+ createCanvas: function () {
90
+ var canvas = this.canvas = this.wrapper.appendChild(
91
+ document.createElement('canvas')
92
+ );
93
+
94
+ this.timeCc = canvas.getContext('2d');
95
+
96
+ this.wavesurfer.drawer.style(canvas, {
97
+ position: 'absolute',
98
+ zIndex: 4
99
+ });
100
+ },
101
+
102
+ render: function () {
103
+ this.updateCanvasStyle();
104
+ this.drawTimeCanvas();
105
+ },
106
+
107
+ updateCanvasStyle: function () {
108
+ var width = this.drawer.wrapper.scrollWidth;
109
+ this.canvas.width = width * this.wavesurfer.params.pixelRatio;
110
+ this.canvas.height = this.height * this.wavesurfer.params.pixelRatio;
111
+ this.canvas.style.width = width + 'px';
112
+ this.canvas.style.height = this.height + 'px';
113
+ },
114
+
115
+ drawTimeCanvas: function() {
116
+ var backend = this.wavesurfer.backend,
117
+ wsParams = this.wavesurfer.params,
118
+ duration = backend.getDuration();
119
+
120
+ if (wsParams.fillParent && !wsParams.scrollParent) {
121
+ var width = this.drawer.getWidth();
122
+ } else {
123
+ width = this.drawer.wrapper.scrollWidth * wsParams.pixelRatio;
124
+ }
125
+ var pixelsPerSecond = width/duration;
126
+
127
+ if (duration > 0) {
128
+ var curPixel = 0,
129
+ curSeconds = 0,
130
+ totalSeconds = parseInt(duration, 10) + 1,
131
+ formatTime = function(seconds) {
132
+ if (seconds/60 > 1) {
133
+ var minutes = parseInt(seconds / 60),
134
+ seconds = parseInt(seconds % 60);
135
+ seconds = (seconds < 10) ? '0' + seconds : seconds;
136
+ return '' + minutes + ':' + seconds;
137
+ } else {
138
+ return seconds;
139
+ }
140
+ };
141
+
142
+ if (pixelsPerSecond * 1 >= 25) {
143
+ var timeInterval = 1;
144
+ var primaryLabelInterval = 10;
145
+ var secondaryLabelInterval = 5;
146
+ } else if (pixelsPerSecond * 5 >= 25) {
147
+ var timeInterval = 5;
148
+ var primaryLabelInterval = 6;
149
+ var secondaryLabelInterval = 2;
150
+ } else if (pixelsPerSecond * 15 >= 25) {
151
+ var timeInterval = 15;
152
+ var primaryLabelInterval = 4;
153
+ var secondaryLabelInterval = 2;
154
+ } else {
155
+ var timeInterval = 60;
156
+ var primaryLabelInterval = 4;
157
+ var secondaryLabelInterval = 2;
158
+ }
159
+
160
+ var height1 = this.height - 4,
161
+ height2 = (this.height * (this.notchPercentHeight / 100.0)) - 4,
162
+ fontSize = this.fontSize * wsParams.pixelRatio;
163
+
164
+ for (var i = 0; i < totalSeconds/timeInterval; i++) {
165
+ if (i % primaryLabelInterval == 0) {
166
+ this.timeCc.fillStyle = this.primaryColor;
167
+ this.timeCc.fillRect(curPixel, 0, 1, height1);
168
+ this.timeCc.font = fontSize + 'px ' + this.fontFamily;
169
+ this.timeCc.fillStyle = this.primaryFontColor;
170
+ this.timeCc.fillText(formatTime(curSeconds), curPixel + 5, height1);
171
+ } else if (i % secondaryLabelInterval == 0) {
172
+ this.timeCc.fillStyle = this.secondaryColor;
173
+ this.timeCc.fillRect(curPixel, 0, 1, height1);
174
+ this.timeCc.font = fontSize + 'px ' + this.fontFamily;
175
+ this.timeCc.fillStyle = this.secondaryFontColor;
176
+ this.timeCc.fillText(formatTime(curSeconds), curPixel + 5, height1);
177
+ } else {
178
+ this.timeCc.fillStyle = this.secondaryColor;
179
+ this.timeCc.fillRect(curPixel, 0, 1, height2);
180
+ }
181
+
182
+ curSeconds += timeInterval;
183
+ curPixel += pixelsPerSecond * timeInterval;
184
+ }
185
+ }
186
+ },
187
+
188
+ updateScroll: function () {
189
+ this.wrapper.scrollLeft = this.drawer.wrapper.scrollLeft;
190
+ }
191
+ };
192
+
193
+ WaveSurfer.util.extend(WaveSurfer.Timeline, WaveSurfer.Observer);
194
+
195
+ return WaveSurfer.Timeline;
196
+ }));
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wavesurfer-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.12
4
+ version: 0.1.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Taylor Daugherty
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-09-28 00:00:00.000000000 Z
11
+ date: 2015-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -55,15 +55,15 @@ files:
55
55
  - lib/wavesurfer/rails.rb
56
56
  - lib/wavesurfer/rails/engine.rb
57
57
  - lib/wavesurfer/rails/version.rb
58
- - vendor/assets/javascripts/plugin/wavesurfer.elan.min.js
59
- - vendor/assets/javascripts/plugin/wavesurfer.microphone.min.js
60
- - vendor/assets/javascripts/plugin/wavesurfer.minimap.min.js
61
- - vendor/assets/javascripts/plugin/wavesurfer.regions.min.js
62
- - vendor/assets/javascripts/plugin/wavesurfer.spectrogram.min.js
63
- - vendor/assets/javascripts/plugin/wavesurfer.timeline.min.js
64
58
  - vendor/assets/javascripts/wavesurfer-plugins.js
65
59
  - vendor/assets/javascripts/wavesurfer.js
66
60
  - vendor/assets/javascripts/wavesurfer.min.js
61
+ - vendor/assets/javascripts/ws-plugins/wavesurfer.elan.js
62
+ - vendor/assets/javascripts/ws-plugins/wavesurfer.microphone.js
63
+ - vendor/assets/javascripts/ws-plugins/wavesurfer.minimap.js
64
+ - vendor/assets/javascripts/ws-plugins/wavesurfer.regions.js
65
+ - vendor/assets/javascripts/ws-plugins/wavesurfer.spectrogram.js
66
+ - vendor/assets/javascripts/ws-plugins/wavesurfer.timeline.js
67
67
  - wavesurfer-rails.gemspec
68
68
  homepage: http://gdclifford.info/
69
69
  licenses: