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.
- checksums.yaml +4 -4
- data/README.md +12 -1
- data/lib/wavesurfer/rails/version.rb +1 -1
- data/vendor/assets/javascripts/wavesurfer-plugins.js +6 -6
- data/vendor/assets/javascripts/ws-plugins/wavesurfer.elan.js +252 -0
- data/vendor/assets/javascripts/ws-plugins/wavesurfer.microphone.js +173 -0
- data/vendor/assets/javascripts/ws-plugins/wavesurfer.minimap.js +213 -0
- data/vendor/assets/javascripts/ws-plugins/wavesurfer.regions.js +416 -0
- data/vendor/assets/javascripts/ws-plugins/wavesurfer.spectrogram.js +223 -0
- data/vendor/assets/javascripts/ws-plugins/wavesurfer.timeline.js +196 -0
- metadata +8 -8
- data/vendor/assets/javascripts/plugin/wavesurfer.elan.min.js +0 -3
- data/vendor/assets/javascripts/plugin/wavesurfer.microphone.min.js +0 -3
- data/vendor/assets/javascripts/plugin/wavesurfer.minimap.min.js +0 -3
- data/vendor/assets/javascripts/plugin/wavesurfer.regions.min.js +0 -3
- data/vendor/assets/javascripts/plugin/wavesurfer.spectrogram.min.js +0 -3
- data/vendor/assets/javascripts/plugin/wavesurfer.timeline.min.js +0 -3
@@ -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.
|
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-
|
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:
|