@lls/lls-audio 0.0.59 → 0.0.61
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.
- package/package.json +27 -25
- package/player/Play.js +13 -7
- package/player/styles/styles.js +31 -14
- package/recorder/AudioWorker.js +134 -0
- package/recorder/Visualizer.js +33 -0
- package/recorder/index.js +202 -15
- package/stories/index.js +12 -6
- package/{recorder/AsyncLoader.js → stories/visualizer.js} +43 -50
- package/stories/wordDetector.js +97 -0
- package/utils/audio.js +26 -141
- package/utils/mediaDevices.js +33 -0
- package/wordDetector/index.js +139 -0
- package/recorder/DesktopAudioRecorder.js +0 -190
- package/recorder/DesktopRecorder.js +0 -143
- package/stories/recorder.js +0 -30
package/package.json
CHANGED
|
@@ -1,39 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lls/lls-audio",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.61",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"devDependencies": {
|
|
6
|
-
"@kadira/storybook": "
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"babel-
|
|
12
|
-
"babel-
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"conventional-changelog
|
|
16
|
-
"
|
|
17
|
-
"
|
|
6
|
+
"@kadira/storybook": "2.21.0",
|
|
7
|
+
"@kadira/storybook-deployer": "1.0.0",
|
|
8
|
+
"@lls/lls-icons": "*",
|
|
9
|
+
"@lls/lls-ui": "*",
|
|
10
|
+
"aphrodite": "0.5.0",
|
|
11
|
+
"babel-cli": "6.9.0",
|
|
12
|
+
"babel-preset-es2015": "6.3.13",
|
|
13
|
+
"babel-preset-react": "6.3.13",
|
|
14
|
+
"babel-preset-stage-0": "6.3.13",
|
|
15
|
+
"conventional-changelog": "1.1.0",
|
|
16
|
+
"conventional-changelog-cli": "1.2.0",
|
|
17
|
+
"css-loader": "0.26.1",
|
|
18
|
+
"file-saver": "^1.3.3",
|
|
18
19
|
"react": "15.3.1",
|
|
19
20
|
"react-dom": "15.3.1",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
21
|
+
"release-it": "2.4.0",
|
|
22
|
+
"similarity": "1.1.1",
|
|
23
|
+
"style-loader": "0.13.1",
|
|
24
|
+
"superheroes": "1.0.0"
|
|
23
25
|
},
|
|
24
26
|
"dependencies": {
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"react-input-range": "
|
|
29
|
-
"waveform-data": "
|
|
27
|
+
"hark": "1.1.5",
|
|
28
|
+
"inline-worker": "1.1.0",
|
|
29
|
+
"is_js": "0.9.0",
|
|
30
|
+
"react-input-range": "0.9.3",
|
|
31
|
+
"waveform-data": "2.0.0"
|
|
30
32
|
},
|
|
31
33
|
"peerDependencies": {
|
|
32
|
-
"aphrodite": "^0.5.0",
|
|
33
|
-
"react": "*",
|
|
34
|
-
"react-dom": "*",
|
|
35
34
|
"@lls/lls-icons": "*",
|
|
36
|
-
"@lls/lls-ui": "*"
|
|
35
|
+
"@lls/lls-ui": "*",
|
|
36
|
+
"aphrodite": "0.5.0",
|
|
37
|
+
"react": "*",
|
|
38
|
+
"react-dom": "*"
|
|
37
39
|
},
|
|
38
40
|
"engines": {
|
|
39
41
|
"node": ">=0.12.0"
|
package/player/Play.js
CHANGED
|
@@ -18,19 +18,25 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
18
18
|
|
|
19
19
|
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
|
|
20
20
|
|
|
21
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
22
|
-
|
|
23
21
|
var generateStyles = function generateStyles(_ref) {
|
|
24
|
-
var _play_button_wrapper;
|
|
25
|
-
|
|
26
22
|
var size = _ref.size,
|
|
27
23
|
invert = _ref.invert,
|
|
28
24
|
transitionDuration = _ref.transitionDuration;
|
|
29
25
|
return _noImportant.StyleSheet.create({
|
|
30
|
-
play_button_wrapper:
|
|
26
|
+
play_button_wrapper: {
|
|
31
27
|
height: '100%',
|
|
32
|
-
width: size * 2.5
|
|
33
|
-
|
|
28
|
+
width: size * 2.5,
|
|
29
|
+
height: size * 2.5,
|
|
30
|
+
color: '#6d6d6d',
|
|
31
|
+
textAlign: 'center',
|
|
32
|
+
boxSizing: 'border-box',
|
|
33
|
+
backgroundColor: invert ? 'white' : _colors.BLUE,
|
|
34
|
+
borderRadius: '50%',
|
|
35
|
+
display: 'flex',
|
|
36
|
+
alignItems: 'center',
|
|
37
|
+
justifyContent: 'center',
|
|
38
|
+
cursor: 'pointer'
|
|
39
|
+
},
|
|
34
40
|
play_button: {
|
|
35
41
|
'height': size,
|
|
36
42
|
'width': size,
|
package/player/styles/styles.js
CHANGED
|
@@ -29,10 +29,12 @@ exports.default = {
|
|
|
29
29
|
inline: {
|
|
30
30
|
width: '100%'
|
|
31
31
|
},
|
|
32
|
-
volume: {
|
|
32
|
+
volume: _defineProperty({
|
|
33
33
|
width: 100,
|
|
34
34
|
cursor: 'pointer'
|
|
35
|
-
},
|
|
35
|
+
}, _mediaQueries.MOBILE, {
|
|
36
|
+
width: 55
|
|
37
|
+
}),
|
|
36
38
|
iconAudio: {
|
|
37
39
|
color: _colors.BLUE,
|
|
38
40
|
marginRight: 20,
|
|
@@ -58,8 +60,7 @@ exports.default = {
|
|
|
58
60
|
width: 'calc(100% - 430px)',
|
|
59
61
|
display: 'flex'
|
|
60
62
|
}, _mediaQueries.MOBILE, {
|
|
61
|
-
|
|
62
|
-
order: 2,
|
|
63
|
+
width: 'calc(100% - 225px)',
|
|
63
64
|
margin: '0px 28px'
|
|
64
65
|
}),
|
|
65
66
|
content: {
|
|
@@ -88,20 +89,34 @@ exports.default = {
|
|
|
88
89
|
wavetimeline: _defineProperty({}, _mediaQueries.MOBILE, {
|
|
89
90
|
display: 'none'
|
|
90
91
|
}),
|
|
91
|
-
loader: {
|
|
92
|
+
loader: _defineProperty({
|
|
92
93
|
height: 60,
|
|
93
94
|
color: '#00b3df',
|
|
94
95
|
fontSize: 10,
|
|
95
96
|
fontWeight: 'bold',
|
|
96
97
|
lineHeight: '60px',
|
|
97
98
|
textAlign: 'center'
|
|
98
|
-
},
|
|
99
|
-
|
|
99
|
+
}, _mediaQueries.MOBILE, {
|
|
100
|
+
lineHeight: 1.5
|
|
101
|
+
}),
|
|
102
|
+
loaderText: _defineProperty({
|
|
100
103
|
textTransform: 'uppercase'
|
|
101
|
-
},
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
}, _mediaQueries.MOBILE, {
|
|
105
|
+
position: 'relative',
|
|
106
|
+
top: 30
|
|
107
|
+
}),
|
|
108
|
+
loaderOne: _defineProperty({}, _mediaQueries.MOBILE, {
|
|
109
|
+
position: 'relative',
|
|
110
|
+
top: 30
|
|
111
|
+
}),
|
|
112
|
+
loaderTwo: _defineProperty({}, _mediaQueries.MOBILE, {
|
|
113
|
+
position: 'relative',
|
|
114
|
+
top: 30
|
|
115
|
+
}),
|
|
116
|
+
loaderThree: _defineProperty({}, _mediaQueries.MOBILE, {
|
|
117
|
+
position: 'relative',
|
|
118
|
+
top: 30
|
|
119
|
+
}),
|
|
105
120
|
timeline: _defineProperty({
|
|
106
121
|
width: '100%',
|
|
107
122
|
margin: '0px 20px',
|
|
@@ -117,11 +132,13 @@ exports.default = {
|
|
|
117
132
|
fontSize: 23,
|
|
118
133
|
cursor: 'pointer'
|
|
119
134
|
}, _mediaQueries.MOBILE, {
|
|
120
|
-
|
|
135
|
+
display: 'none'
|
|
121
136
|
}),
|
|
122
|
-
speed_menu: {
|
|
137
|
+
speed_menu: _defineProperty({
|
|
123
138
|
marginLeft: 10
|
|
124
|
-
},
|
|
139
|
+
}, _mediaQueries.MOBILE, {
|
|
140
|
+
display: 'none'
|
|
141
|
+
}),
|
|
125
142
|
close: {
|
|
126
143
|
cursor: 'pointer',
|
|
127
144
|
position: 'absolute',
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var AudioWorker = function AudioWorker(self) {
|
|
7
|
+
var recLength = 0;
|
|
8
|
+
var recBuffers = [];
|
|
9
|
+
var audioBlob = null;
|
|
10
|
+
|
|
11
|
+
self.onmessage = function (e) {
|
|
12
|
+
var mergeBuffers = function mergeBuffers(recBuffers, recLength) {
|
|
13
|
+
var result = new Float32Array(recLength);
|
|
14
|
+
var offset = 0;
|
|
15
|
+
for (var i = 0; i < recBuffers.length; i++) {
|
|
16
|
+
result.set(recBuffers[i], offset);
|
|
17
|
+
offset += recBuffers[i].length;
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
var appendBuffer = function appendBuffer(timestamp, inputBuffer) {
|
|
23
|
+
for (var channel = 0; channel < inputBuffer.length; channel++) {
|
|
24
|
+
if (!recBuffers[channel]) recBuffers[channel] = [];
|
|
25
|
+
recBuffers[channel].push({ timestamp: timestamp, data: inputBuffer[channel], length: inputBuffer[channel].length });
|
|
26
|
+
}
|
|
27
|
+
recLength += inputBuffer[0].length;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function interleave(inputL, inputR) {
|
|
31
|
+
var length = inputL.length + inputR.length;
|
|
32
|
+
var result = new Float32Array(length);
|
|
33
|
+
|
|
34
|
+
var index = 0;
|
|
35
|
+
var inputIndex = 0;
|
|
36
|
+
|
|
37
|
+
while (index < length) {
|
|
38
|
+
result[index++] = inputL[inputIndex];
|
|
39
|
+
result[index++] = inputR[inputIndex];
|
|
40
|
+
inputIndex++;
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var writeString = function writeString(view, offset, string) {
|
|
46
|
+
for (var i = 0; i < string.length; i++) {
|
|
47
|
+
view.setUint8(offset + i, string.charCodeAt(i));
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
var floatTo16BitPCM = function floatTo16BitPCM(output, offset, input) {
|
|
52
|
+
for (var i = 0; i < input.length; i++, offset += 2) {
|
|
53
|
+
var s = Math.max(-1, Math.min(1, input[i]));
|
|
54
|
+
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
var encodeWAV = function encodeWAV(samples) {
|
|
59
|
+
console.log("samples", samples.length);
|
|
60
|
+
var buffer = new ArrayBuffer(44 + samples.length * 2);
|
|
61
|
+
var view = new DataView(buffer);
|
|
62
|
+
|
|
63
|
+
/* RIFF identifier */
|
|
64
|
+
writeString(view, 0, 'RIFF');
|
|
65
|
+
/* RIFF chunk length */
|
|
66
|
+
view.setUint32(4, 36 + samples.length * 2, true);
|
|
67
|
+
/* RIFF type */
|
|
68
|
+
writeString(view, 8, 'WAVE');
|
|
69
|
+
/* format chunk identifier */
|
|
70
|
+
writeString(view, 12, 'fmt ');
|
|
71
|
+
/* format chunk length */
|
|
72
|
+
view.setUint32(16, 16, true);
|
|
73
|
+
/* sample format (raw) */
|
|
74
|
+
view.setUint16(20, 1, true);
|
|
75
|
+
/* channel count */
|
|
76
|
+
view.setUint16(22, recBuffers.length, true);
|
|
77
|
+
/* sample rate */
|
|
78
|
+
view.setUint32(24, 44100, true);
|
|
79
|
+
/* byte rate (sample rate * block align) */
|
|
80
|
+
view.setUint32(28, 44100 * recBuffers.length * 2, true);
|
|
81
|
+
/* block align (channel count * bytes per sample) */
|
|
82
|
+
view.setUint16(32, recBuffers.length * 2, true);
|
|
83
|
+
/* bits per sample */
|
|
84
|
+
view.setUint16(34, 16, true);
|
|
85
|
+
/* data chunk identifier */
|
|
86
|
+
writeString(view, 36, 'data');
|
|
87
|
+
/* data chunk length */
|
|
88
|
+
view.setUint32(40, samples.length * 2, true);
|
|
89
|
+
|
|
90
|
+
floatTo16BitPCM(view, 44, samples);
|
|
91
|
+
|
|
92
|
+
return view;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
var exportWAV = function exportWAV(beginning, end) {
|
|
96
|
+
var buffers = [];
|
|
97
|
+
for (var channel = 0; channel < recBuffers.length; channel++) {
|
|
98
|
+
var length = 0;
|
|
99
|
+
var filtredRecBuffers = recBuffers[channel].filter(function (buffer) {
|
|
100
|
+
return buffer.timestamp >= beginning - 1000 && buffer.timestamp <= end;
|
|
101
|
+
}).map(function (buffer) {
|
|
102
|
+
length += buffer.length;
|
|
103
|
+
return buffer.data;
|
|
104
|
+
});
|
|
105
|
+
buffers.push(mergeBuffers(filtredRecBuffers, length));
|
|
106
|
+
}
|
|
107
|
+
var interleaved = recBuffers.length === 2 ? interleave(buffers[0], buffers[1]) : buffers[0];
|
|
108
|
+
var dataview = encodeWAV(interleaved);
|
|
109
|
+
audioBlob = new Blob([dataview], { type: 'audio/wav' });
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
switch (e.data.command) {
|
|
113
|
+
case 'append':
|
|
114
|
+
appendBuffer(e.data.timestamp, e.data.inputBuffer);
|
|
115
|
+
var buffers = [];
|
|
116
|
+
for (var channel = 0; channel < recBuffers.length; channel++) {
|
|
117
|
+
buffers.push(mergeBuffers(recBuffers[channel], recLength));
|
|
118
|
+
}
|
|
119
|
+
postMessage({ command: 'send_buffers', buffers: recBuffers });
|
|
120
|
+
break;
|
|
121
|
+
case 'exportWAV':
|
|
122
|
+
exportWAV(e.data.beginning, e.data.end);
|
|
123
|
+
postMessage({ command: 'send_WAV', audioBlob: audioBlob });
|
|
124
|
+
break;
|
|
125
|
+
case 'clean':
|
|
126
|
+
recLength = 0;
|
|
127
|
+
recBuffers = [];
|
|
128
|
+
audioBlob = null;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
exports.default = AudioWorker;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
var _react = require('react');
|
|
8
|
+
|
|
9
|
+
var _react2 = _interopRequireDefault(_react);
|
|
10
|
+
|
|
11
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
12
|
+
|
|
13
|
+
var Circle = function Circle(_ref) {
|
|
14
|
+
var radius = _ref.radius,
|
|
15
|
+
maxRadius = _ref.maxRadius,
|
|
16
|
+
color = _ref.color;
|
|
17
|
+
return _react2.default.createElement('circle', { r: radius, cx: 100, cy: 100, style: { 'transition': 'all 0.1s', 'fill': 'red', opacity: 0.2 + radius / maxRadius } });
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
var Visualizer = function Visualizer(_ref2) {
|
|
21
|
+
var volume = _ref2.volume;
|
|
22
|
+
|
|
23
|
+
var radius = (100 + volume) / 2;
|
|
24
|
+
radius = radius < 0 ? 0 : radius;
|
|
25
|
+
|
|
26
|
+
return _react2.default.createElement(
|
|
27
|
+
'svg',
|
|
28
|
+
null,
|
|
29
|
+
_react2.default.createElement(Circle, { radius: radius, maxRadius: 100 })
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
exports.default = Visualizer;
|
package/recorder/index.js
CHANGED
|
@@ -4,32 +4,219 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
|
|
7
|
+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
8
|
+
|
|
7
9
|
var _react = require('react');
|
|
8
10
|
|
|
9
11
|
var _react2 = _interopRequireDefault(_react);
|
|
10
12
|
|
|
11
|
-
var
|
|
13
|
+
var _CustomWave = require('../player/CustomWave');
|
|
14
|
+
|
|
15
|
+
var _CustomWave2 = _interopRequireDefault(_CustomWave);
|
|
16
|
+
|
|
17
|
+
var _audioContext = require('../utils/audioContext');
|
|
18
|
+
|
|
19
|
+
var _audioContext2 = _interopRequireDefault(_audioContext);
|
|
20
|
+
|
|
21
|
+
var _mediaDevices = require('../utils/mediaDevices');
|
|
12
22
|
|
|
13
|
-
var
|
|
23
|
+
var _hark = require('hark');
|
|
14
24
|
|
|
15
|
-
var
|
|
25
|
+
var _hark2 = _interopRequireDefault(_hark);
|
|
16
26
|
|
|
17
|
-
var
|
|
27
|
+
var _inlineWorker = require('inline-worker');
|
|
18
28
|
|
|
19
|
-
var
|
|
29
|
+
var _inlineWorker2 = _interopRequireDefault(_inlineWorker);
|
|
30
|
+
|
|
31
|
+
var _AudioWorker = require('./AudioWorker');
|
|
32
|
+
|
|
33
|
+
var _AudioWorker2 = _interopRequireDefault(_AudioWorker);
|
|
20
34
|
|
|
21
35
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
22
36
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
37
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
38
|
+
|
|
39
|
+
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
|
40
|
+
|
|
41
|
+
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
|
42
|
+
|
|
43
|
+
var INTERVAL = 100;
|
|
44
|
+
|
|
45
|
+
var audioContext = new _audioContext2.default();
|
|
46
|
+
|
|
47
|
+
var initRecorder = function initRecorder(_ref) {
|
|
48
|
+
var stream = _ref.stream,
|
|
49
|
+
audioContext = _ref.audioContext,
|
|
50
|
+
_ref$onAudioProcess = _ref.onAudioProcess,
|
|
51
|
+
onAudioProcess = _ref$onAudioProcess === undefined ? function () {} : _ref$onAudioProcess;
|
|
52
|
+
|
|
53
|
+
var bufferSize = 4096;
|
|
54
|
+
var numberOfInputChannels = 1; // for google cloud Speech to text, we must have one (and only one) channel
|
|
55
|
+
var numberOfOutputChannels = 1;
|
|
56
|
+
|
|
57
|
+
// creates an audio node from the microphone incoming stream
|
|
58
|
+
var mediaStream = audioContext.createMediaStreamSource(stream);
|
|
59
|
+
var recorder = audioContext.createScriptProcessor ? audioContext.createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels) : audioContext.createJavaScriptNode(bufferSize, numberOfInputChannels, numberOfOutputChannels);
|
|
60
|
+
|
|
61
|
+
recorder.onaudioprocess = onAudioProcess;
|
|
62
|
+
|
|
63
|
+
// we connect the recorder with the input stream
|
|
64
|
+
mediaStream.connect(recorder);
|
|
65
|
+
recorder.connect(audioContext.destination);
|
|
66
|
+
|
|
67
|
+
return recorder;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
var initWorker = function initWorker(_ref2) {
|
|
71
|
+
var _ref2$onMessage = _ref2.onMessage,
|
|
72
|
+
onMessage = _ref2$onMessage === undefined ? function () {} : _ref2$onMessage;
|
|
73
|
+
|
|
74
|
+
var worker = new _inlineWorker2.default(_AudioWorker2.default, {});
|
|
75
|
+
worker.onmessage = onMessage;
|
|
76
|
+
return worker;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
var initSpeechEvents = function initSpeechEvents(_ref3) {
|
|
80
|
+
var stream = _ref3.stream,
|
|
81
|
+
_ref3$onSpeaking = _ref3.onSpeaking,
|
|
82
|
+
onSpeaking = _ref3$onSpeaking === undefined ? function () {} : _ref3$onSpeaking,
|
|
83
|
+
_ref3$onStoppedSpeaki = _ref3.onStoppedSpeaking,
|
|
84
|
+
onStoppedSpeaking = _ref3$onStoppedSpeaki === undefined ? function () {} : _ref3$onStoppedSpeaki,
|
|
85
|
+
_ref3$onVolumeChange = _ref3.onVolumeChange,
|
|
86
|
+
onVolumeChange = _ref3$onVolumeChange === undefined ? function () {} : _ref3$onVolumeChange;
|
|
87
|
+
|
|
88
|
+
// Try hark
|
|
89
|
+
var options = {
|
|
90
|
+
interval: INTERVAL
|
|
91
|
+
//play: true // true: allow to hear the result for debug
|
|
92
|
+
};
|
|
93
|
+
var speechEvents = (0, _hark2.default)(stream, options);
|
|
26
94
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
) : _react2.default.createElement(_MobileRecorder2.default, null);
|
|
95
|
+
speechEvents.on('speaking', onSpeaking);
|
|
96
|
+
speechEvents.on('stopped_speaking', onStoppedSpeaking);
|
|
97
|
+
speechEvents.on('volume_change', onVolumeChange);
|
|
98
|
+
|
|
99
|
+
return speechEvents;
|
|
33
100
|
};
|
|
34
101
|
|
|
35
|
-
|
|
102
|
+
var DesktopAudioRecorder = function (_Component) {
|
|
103
|
+
_inherits(DesktopAudioRecorder, _Component);
|
|
104
|
+
|
|
105
|
+
function DesktopAudioRecorder(props) {
|
|
106
|
+
_classCallCheck(this, DesktopAudioRecorder);
|
|
107
|
+
|
|
108
|
+
// Instances
|
|
109
|
+
var _this = _possibleConstructorReturn(this, (DesktopAudioRecorder.__proto__ || Object.getPrototypeOf(DesktopAudioRecorder)).call(this, props));
|
|
110
|
+
|
|
111
|
+
_this.worker = null;
|
|
112
|
+
_this.recorder = null;
|
|
113
|
+
_this.speechEvents = null;
|
|
114
|
+
|
|
115
|
+
// Data
|
|
116
|
+
_this.recordStart = null;
|
|
117
|
+
_this.audioBuffer = [];
|
|
118
|
+
|
|
119
|
+
// Methods
|
|
120
|
+
_this.init = _this.init.bind(_this);
|
|
121
|
+
_this.initStream = _this.initStream.bind(_this);
|
|
122
|
+
return _this;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
_createClass(DesktopAudioRecorder, [{
|
|
126
|
+
key: 'componentDidMount',
|
|
127
|
+
value: function componentDidMount() {
|
|
128
|
+
this.init(this.props);
|
|
129
|
+
}
|
|
130
|
+
}, {
|
|
131
|
+
key: 'init',
|
|
132
|
+
value: function init(props) {
|
|
133
|
+
var _this2 = this;
|
|
134
|
+
|
|
135
|
+
var _props$onError = props.onError,
|
|
136
|
+
onError = _props$onError === undefined ? function () {} : _props$onError,
|
|
137
|
+
_props$onVolumeChange = props.onVolumeChange,
|
|
138
|
+
onVolumeChange = _props$onVolumeChange === undefined ? function () {} : _props$onVolumeChange,
|
|
139
|
+
_props$onRecordComple = props.onRecordComplete,
|
|
140
|
+
onRecordComplete = _props$onRecordComple === undefined ? function () {} : _props$onRecordComple;
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
(0, _mediaDevices.shimMediaDevices)();
|
|
144
|
+
|
|
145
|
+
window.navigator.mediaDevices.getUserMedia({ audio: true }).then(function (stream) {
|
|
146
|
+
_this2.initStream({
|
|
147
|
+
stream: stream,
|
|
148
|
+
onError: onError,
|
|
149
|
+
onVolumeChange: onVolumeChange,
|
|
150
|
+
onRecordComplete: onRecordComplete
|
|
151
|
+
});
|
|
152
|
+
}).catch(function (err) {
|
|
153
|
+
onError(err);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}, {
|
|
157
|
+
key: 'initStream',
|
|
158
|
+
value: function initStream(_ref4) {
|
|
159
|
+
var _this3 = this;
|
|
160
|
+
|
|
161
|
+
var stream = _ref4.stream,
|
|
162
|
+
onError = _ref4.onError,
|
|
163
|
+
_onVolumeChange = _ref4.onVolumeChange,
|
|
164
|
+
onRecordComplete = _ref4.onRecordComplete;
|
|
165
|
+
|
|
166
|
+
// Init worker that will do heavy calculation
|
|
167
|
+
this.worker = initWorker({ onMessage: function onMessage(e) {
|
|
168
|
+
switch (e.data.command) {
|
|
169
|
+
case 'send_buffers':
|
|
170
|
+
_this3.audioBuffer = e.data.buffers;
|
|
171
|
+
break;
|
|
172
|
+
case 'send_WAV':
|
|
173
|
+
//const url = (window.URL || window.webkitURL).createObjectURL(e.data.audioBlob)
|
|
174
|
+
onRecordComplete(e.data.audioBlob);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
} });
|
|
178
|
+
|
|
179
|
+
// Init recorder
|
|
180
|
+
this.recorder = initRecorder({
|
|
181
|
+
stream: stream,
|
|
182
|
+
audioContext: audioContext,
|
|
183
|
+
onAudioProcess: function onAudioProcess(e) {
|
|
184
|
+
var inputBuffer = [];
|
|
185
|
+
for (var channel = 0; channel < e.inputBuffer.numberOfChannels; channel++) {
|
|
186
|
+
inputBuffer.push(e.inputBuffer.getChannelData(channel));
|
|
187
|
+
}
|
|
188
|
+
_this3.worker.postMessage({ command: 'append', timestamp: Date.now(), inputBuffer: inputBuffer });
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Initialize hark for silence recognition
|
|
193
|
+
this.speechEvents = initSpeechEvents({
|
|
194
|
+
stream: stream,
|
|
195
|
+
onStoppedSpeaking: function onStoppedSpeaking() {
|
|
196
|
+
try {
|
|
197
|
+
_this3.worker.postMessage({ command: 'exportWAV', buffers: _this3.audioBuffer, beginning: _this3.recordStart, end: Date.now() });
|
|
198
|
+
_this3.worker.postMessage({ command: 'clean' });
|
|
199
|
+
_this3.audioBuffer = [];
|
|
200
|
+
} catch (e) {
|
|
201
|
+
onError(e);
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
onSpeaking: function onSpeaking() {
|
|
205
|
+
_this3.recordStart = Date.now() - INTERVAL * 3; // give it a bit of extra time
|
|
206
|
+
},
|
|
207
|
+
onVolumeChange: function onVolumeChange(volume) {
|
|
208
|
+
_onVolumeChange(volume);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}, {
|
|
213
|
+
key: 'render',
|
|
214
|
+
value: function render() {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
}]);
|
|
218
|
+
|
|
219
|
+
return DesktopAudioRecorder;
|
|
220
|
+
}(_react.Component);
|
|
221
|
+
|
|
222
|
+
exports.default = DesktopAudioRecorder;
|
package/stories/index.js
CHANGED
|
@@ -14,12 +14,17 @@ var _playerRange = require('./playerRange');
|
|
|
14
14
|
|
|
15
15
|
var _playerRange2 = _interopRequireDefault(_playerRange);
|
|
16
16
|
|
|
17
|
-
var
|
|
17
|
+
var _visualizer = require('./visualizer');
|
|
18
18
|
|
|
19
|
-
var
|
|
19
|
+
var _visualizer2 = _interopRequireDefault(_visualizer);
|
|
20
|
+
|
|
21
|
+
var _wordDetector = require('./wordDetector');
|
|
22
|
+
|
|
23
|
+
var _wordDetector2 = _interopRequireDefault(_wordDetector);
|
|
20
24
|
|
|
21
25
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
22
26
|
|
|
27
|
+
//import PlayerCustom from './playerCustom'
|
|
23
28
|
(0, _storybook.storiesOf)('Player', module).add('Custom waveform', function () {
|
|
24
29
|
return _react2.default.createElement(_player2.default, null);
|
|
25
30
|
}).add('Ranges', function () {
|
|
@@ -31,8 +36,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
31
36
|
}).add('Caption', function () {
|
|
32
37
|
return _react2.default.createElement(_player2.default, { caption: 'Je suis une caption :)' });
|
|
33
38
|
});
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
(0, _storybook.storiesOf)('Recorder', module).add('Visualizer', function () {
|
|
40
|
+
return _react2.default.createElement(_visualizer2.default, null);
|
|
41
|
+
});
|
|
42
|
+
(0, _storybook.storiesOf)('Word detector', module).add('Normal', function () {
|
|
43
|
+
return _react2.default.createElement(_wordDetector2.default, null);
|
|
38
44
|
});
|