recorderjs-rails 1.0.0
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 +7 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +5 -0
- data/README.md +8 -0
- data/lib/recorderjs-rails.rb +1 -0
- data/lib/recorderjs/rails.rb +3 -0
- data/lib/recorderjs/rails/engine.rb +6 -0
- data/lib/recorderjs/rails/version.rb +6 -0
- data/recorderjs-rails.gemspec +22 -0
- data/vendor/assets/javascripts/recorder.js +92 -0
- data/vendor/assets/javascripts/recorderWorker.js +147 -0
- metadata +73 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d8041ec3672629dae5b6d6d765c5f185e5e800ef
|
4
|
+
data.tar.gz: 51746e2fb3fbd1363c47fd1e9f4fbdd2ee6ecebc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 53e1f69f2e5c35a389373eb4ceef0918a10857c292a4ef77a431ebd48c2dc83c842894822ce1af5e1e2cfa655af1a1151dc29752bd7fc2297cb966ed11e6f290
|
7
|
+
data.tar.gz: 537ecce15afc7ea5543d251209d3f80d8504d4a54bddfa853c03d2f528426fc31dcf2597554c4a08a20f7bb2a674d142e7444467df663b39cec877484aca48e3
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
recorderjs-rails
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.2.1
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'recorderjs/rails'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/recorderjs/rails/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "recorderjs-rails"
|
6
|
+
s.version = Recorderjs::Rails::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["Julien Defrance"]
|
9
|
+
s.homepage = "https://github.com/mattdiamond/Recorderjs"
|
10
|
+
|
11
|
+
s.summary = "Use Recorderjs with Rails 4+"
|
12
|
+
s.description = "A plugin for recording/exporting the output of Web Audio API nodes"
|
13
|
+
|
14
|
+
s.required_rubygems_version = ">= 1.3.6"
|
15
|
+
|
16
|
+
s.add_dependency "railties", ">= 3.0", "< 5.0"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
20
|
+
s.require_path = 'lib'
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,92 @@
|
|
1
|
+
(function(window){
|
2
|
+
|
3
|
+
var WORKER_PATH = 'recorderWorker.js';
|
4
|
+
|
5
|
+
var Recorder = function(source, cfg){
|
6
|
+
var config = cfg || {};
|
7
|
+
var bufferLen = config.bufferLen || 4096;
|
8
|
+
var numChannels = config.numChannels || 2;
|
9
|
+
this.context = source.context;
|
10
|
+
this.node = (this.context.createScriptProcessor ||
|
11
|
+
this.context.createJavaScriptNode).call(this.context,
|
12
|
+
bufferLen, numChannels, numChannels);
|
13
|
+
var worker = new Worker(config.workerPath || WORKER_PATH);
|
14
|
+
worker.postMessage({
|
15
|
+
command: 'init',
|
16
|
+
config: {
|
17
|
+
sampleRate: this.context.sampleRate,
|
18
|
+
numChannels: numChannels
|
19
|
+
}
|
20
|
+
});
|
21
|
+
var recording = false,
|
22
|
+
currCallback;
|
23
|
+
|
24
|
+
this.node.onaudioprocess = function(e){
|
25
|
+
if (!recording) return;
|
26
|
+
var buffer = [];
|
27
|
+
for (var channel = 0; channel < numChannels; channel++){
|
28
|
+
buffer.push(e.inputBuffer.getChannelData(channel));
|
29
|
+
}
|
30
|
+
worker.postMessage({
|
31
|
+
command: 'record',
|
32
|
+
buffer: buffer
|
33
|
+
});
|
34
|
+
}
|
35
|
+
|
36
|
+
this.configure = function(cfg){
|
37
|
+
for (var prop in cfg){
|
38
|
+
if (cfg.hasOwnProperty(prop)){
|
39
|
+
config[prop] = cfg[prop];
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
this.record = function(){
|
45
|
+
recording = true;
|
46
|
+
}
|
47
|
+
|
48
|
+
this.stop = function(){
|
49
|
+
recording = false;
|
50
|
+
}
|
51
|
+
|
52
|
+
this.clear = function(){
|
53
|
+
worker.postMessage({ command: 'clear' });
|
54
|
+
}
|
55
|
+
|
56
|
+
this.getBuffer = function(cb) {
|
57
|
+
currCallback = cb || config.callback;
|
58
|
+
worker.postMessage({ command: 'getBuffer' })
|
59
|
+
}
|
60
|
+
|
61
|
+
this.exportWAV = function(cb, type){
|
62
|
+
currCallback = cb || config.callback;
|
63
|
+
type = type || config.type || 'audio/wav';
|
64
|
+
if (!currCallback) throw new Error('Callback not set');
|
65
|
+
worker.postMessage({
|
66
|
+
command: 'exportWAV',
|
67
|
+
type: type
|
68
|
+
});
|
69
|
+
}
|
70
|
+
|
71
|
+
worker.onmessage = function(e){
|
72
|
+
var blob = e.data;
|
73
|
+
currCallback(blob);
|
74
|
+
}
|
75
|
+
|
76
|
+
source.connect(this.node);
|
77
|
+
this.node.connect(this.context.destination); //this should not be necessary
|
78
|
+
};
|
79
|
+
|
80
|
+
Recorder.forceDownload = function(blob, filename){
|
81
|
+
var url = (window.URL || window.webkitURL).createObjectURL(blob);
|
82
|
+
var link = window.document.createElement('a');
|
83
|
+
link.href = url;
|
84
|
+
link.download = filename || 'output.wav';
|
85
|
+
var click = document.createEvent("Event");
|
86
|
+
click.initEvent("click", true, true);
|
87
|
+
link.dispatchEvent(click);
|
88
|
+
}
|
89
|
+
|
90
|
+
window.Recorder = Recorder;
|
91
|
+
|
92
|
+
})(window);
|
@@ -0,0 +1,147 @@
|
|
1
|
+
var recLength = 0,
|
2
|
+
recBuffers = [],
|
3
|
+
sampleRate,
|
4
|
+
numChannels;
|
5
|
+
|
6
|
+
this.onmessage = function(e){
|
7
|
+
switch(e.data.command){
|
8
|
+
case 'init':
|
9
|
+
init(e.data.config);
|
10
|
+
break;
|
11
|
+
case 'record':
|
12
|
+
record(e.data.buffer);
|
13
|
+
break;
|
14
|
+
case 'exportWAV':
|
15
|
+
exportWAV(e.data.type);
|
16
|
+
break;
|
17
|
+
case 'getBuffer':
|
18
|
+
getBuffer();
|
19
|
+
break;
|
20
|
+
case 'clear':
|
21
|
+
clear();
|
22
|
+
break;
|
23
|
+
}
|
24
|
+
};
|
25
|
+
|
26
|
+
function init(config){
|
27
|
+
sampleRate = config.sampleRate;
|
28
|
+
numChannels = config.numChannels;
|
29
|
+
initBuffers();
|
30
|
+
}
|
31
|
+
|
32
|
+
function record(inputBuffer){
|
33
|
+
for (var channel = 0; channel < numChannels; channel++){
|
34
|
+
recBuffers[channel].push(inputBuffer[channel]);
|
35
|
+
}
|
36
|
+
recLength += inputBuffer[0].length;
|
37
|
+
}
|
38
|
+
|
39
|
+
function exportWAV(type){
|
40
|
+
var buffers = [];
|
41
|
+
for (var channel = 0; channel < numChannels; channel++){
|
42
|
+
buffers.push(mergeBuffers(recBuffers[channel], recLength));
|
43
|
+
}
|
44
|
+
if (numChannels === 2){
|
45
|
+
var interleaved = interleave(buffers[0], buffers[1]);
|
46
|
+
} else {
|
47
|
+
var interleaved = buffers[0];
|
48
|
+
}
|
49
|
+
var dataview = encodeWAV(interleaved);
|
50
|
+
var audioBlob = new Blob([dataview], { type: type });
|
51
|
+
|
52
|
+
this.postMessage(audioBlob);
|
53
|
+
}
|
54
|
+
|
55
|
+
function getBuffer(){
|
56
|
+
var buffers = [];
|
57
|
+
for (var channel = 0; channel < numChannels; channel++){
|
58
|
+
buffers.push(mergeBuffers(recBuffers[channel], recLength));
|
59
|
+
}
|
60
|
+
this.postMessage(buffers);
|
61
|
+
}
|
62
|
+
|
63
|
+
function clear(){
|
64
|
+
recLength = 0;
|
65
|
+
recBuffers = [];
|
66
|
+
initBuffers();
|
67
|
+
}
|
68
|
+
|
69
|
+
function initBuffers(){
|
70
|
+
for (var channel = 0; channel < numChannels; channel++){
|
71
|
+
recBuffers[channel] = [];
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
function mergeBuffers(recBuffers, recLength){
|
76
|
+
var result = new Float32Array(recLength);
|
77
|
+
var offset = 0;
|
78
|
+
for (var i = 0; i < recBuffers.length; i++){
|
79
|
+
result.set(recBuffers[i], offset);
|
80
|
+
offset += recBuffers[i].length;
|
81
|
+
}
|
82
|
+
return result;
|
83
|
+
}
|
84
|
+
|
85
|
+
function interleave(inputL, inputR){
|
86
|
+
var length = inputL.length + inputR.length;
|
87
|
+
var result = new Float32Array(length);
|
88
|
+
|
89
|
+
var index = 0,
|
90
|
+
inputIndex = 0;
|
91
|
+
|
92
|
+
while (index < length){
|
93
|
+
result[index++] = inputL[inputIndex];
|
94
|
+
result[index++] = inputR[inputIndex];
|
95
|
+
inputIndex++;
|
96
|
+
}
|
97
|
+
return result;
|
98
|
+
}
|
99
|
+
|
100
|
+
function floatTo16BitPCM(output, offset, input){
|
101
|
+
for (var i = 0; i < input.length; i++, offset+=2){
|
102
|
+
var s = Math.max(-1, Math.min(1, input[i]));
|
103
|
+
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
function writeString(view, offset, string){
|
108
|
+
for (var i = 0; i < string.length; i++){
|
109
|
+
view.setUint8(offset + i, string.charCodeAt(i));
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
function encodeWAV(samples){
|
114
|
+
var buffer = new ArrayBuffer(44 + samples.length * 2);
|
115
|
+
var view = new DataView(buffer);
|
116
|
+
|
117
|
+
/* RIFF identifier */
|
118
|
+
writeString(view, 0, 'RIFF');
|
119
|
+
/* RIFF chunk length */
|
120
|
+
view.setUint32(4, 36 + samples.length * 2, true);
|
121
|
+
/* RIFF type */
|
122
|
+
writeString(view, 8, 'WAVE');
|
123
|
+
/* format chunk identifier */
|
124
|
+
writeString(view, 12, 'fmt ');
|
125
|
+
/* format chunk length */
|
126
|
+
view.setUint32(16, 16, true);
|
127
|
+
/* sample format (raw) */
|
128
|
+
view.setUint16(20, 1, true);
|
129
|
+
/* channel count */
|
130
|
+
view.setUint16(22, numChannels, true);
|
131
|
+
/* sample rate */
|
132
|
+
view.setUint32(24, sampleRate, true);
|
133
|
+
/* byte rate (sample rate * block align) */
|
134
|
+
view.setUint32(28, sampleRate * 4, true);
|
135
|
+
/* block align (channel count * bytes per sample) */
|
136
|
+
view.setUint16(32, numChannels * 2, true);
|
137
|
+
/* bits per sample */
|
138
|
+
view.setUint16(34, 16, true);
|
139
|
+
/* data chunk identifier */
|
140
|
+
writeString(view, 36, 'data');
|
141
|
+
/* data chunk length */
|
142
|
+
view.setUint32(40, samples.length * 2, true);
|
143
|
+
|
144
|
+
floatTo16BitPCM(view, 44, samples);
|
145
|
+
|
146
|
+
return view;
|
147
|
+
}
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: recorderjs-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Julien Defrance
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: railties
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '5.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.0'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5.0'
|
33
|
+
description: A plugin for recording/exporting the output of Web Audio API nodes
|
34
|
+
email:
|
35
|
+
executables: []
|
36
|
+
extensions: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
files:
|
39
|
+
- ".ruby-gemset"
|
40
|
+
- ".ruby-version"
|
41
|
+
- Gemfile
|
42
|
+
- README.md
|
43
|
+
- lib/recorderjs-rails.rb
|
44
|
+
- lib/recorderjs/rails.rb
|
45
|
+
- lib/recorderjs/rails/engine.rb
|
46
|
+
- lib/recorderjs/rails/version.rb
|
47
|
+
- recorderjs-rails.gemspec
|
48
|
+
- vendor/assets/javascripts/recorder.js
|
49
|
+
- vendor/assets/javascripts/recorderWorker.js
|
50
|
+
homepage: https://github.com/mattdiamond/Recorderjs
|
51
|
+
licenses: []
|
52
|
+
metadata: {}
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 1.3.6
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 2.4.5
|
70
|
+
signing_key:
|
71
|
+
specification_version: 4
|
72
|
+
summary: Use Recorderjs with Rails 4+
|
73
|
+
test_files: []
|