@lls/lls-audio 0.0.58 → 0.0.60

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 CHANGED
@@ -1,37 +1,39 @@
1
1
  {
2
2
  "name": "@lls/lls-audio",
3
- "version": "0.0.58",
3
+ "version": "0.0.60",
4
4
  "main": "index.js",
5
5
  "devDependencies": {
6
- "@kadira/storybook": "^2.21.0",
7
- "css-loader": "^0.26.1",
8
- "style-loader": "^0.13.1",
9
- "babel-preset-es2015": "^6.3.13",
10
- "babel-preset-react": "^6.3.13",
11
- "babel-preset-stage-0": "^6.3.13",
12
- "babel-cli": "^6.9.0",
13
- "superheroes": "^1.0.0",
14
- "conventional-changelog": "^1.1.0",
15
- "conventional-changelog-cli": "^1.2.0",
16
- "@kadira/storybook-deployer": "^1.0.0",
17
- "release-it": "^2.4.0",
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
18
  "react": "15.3.1",
19
19
  "react-dom": "15.3.1",
20
- "@lls/lls-icons": "1.0.49"
20
+ "release-it": "2.4.0",
21
+ "style-loader": "0.13.1",
22
+ "superheroes": "1.0.0"
21
23
  },
22
24
  "dependencies": {
23
- "@lls/lls-ui": "0.1.33",
24
- "aphrodite": "^1.1.0",
25
- "is_js": "^0.9.0",
26
- "merge-audio-buffers": "^1.0.0",
27
- "msr": "^1.3.4",
28
- "react-input-range": "^0.9.3",
29
- "waveform-data": "^2.0.0"
25
+ "hark": "1.1.5",
26
+ "inline-worker": "1.1.0",
27
+ "is_js": "0.9.0",
28
+ "react-input-range": "0.9.3",
29
+ "waveform-data": "2.0.0"
30
30
  },
31
31
  "peerDependencies": {
32
- "react": "15.3.1",
33
- "react-dom": "15.3.1",
34
- "@lls/lls-icons": "1.0.49"
32
+ "@lls/lls-icons": "*",
33
+ "@lls/lls-ui": "*",
34
+ "aphrodite": "0.5.0",
35
+ "react": "*",
36
+ "react-dom": "*"
35
37
  },
36
38
  "engines": {
37
39
  "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: (_play_button_wrapper = {
26
+ play_button_wrapper: {
31
27
  height: '100%',
32
- width: size * 2.5
33
- }, _defineProperty(_play_button_wrapper, 'height', size * 2.5), _defineProperty(_play_button_wrapper, 'color', '#6d6d6d'), _defineProperty(_play_button_wrapper, 'textAlign', 'center'), _defineProperty(_play_button_wrapper, 'boxSizing', 'border-box'), _defineProperty(_play_button_wrapper, 'backgroundColor', invert ? 'white' : _colors.BLUE), _defineProperty(_play_button_wrapper, 'borderRadius', '50%'), _defineProperty(_play_button_wrapper, 'display', 'flex'), _defineProperty(_play_button_wrapper, 'alignItems', 'center'), _defineProperty(_play_button_wrapper, 'justifyContent', 'center'), _defineProperty(_play_button_wrapper, 'cursor', 'pointer'), _play_button_wrapper),
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,
@@ -0,0 +1,133 @@
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
+ var buffer = new ArrayBuffer(44 + samples.length * 2);
60
+ var view = new DataView(buffer);
61
+
62
+ /* RIFF identifier */
63
+ writeString(view, 0, 'RIFF');
64
+ /* RIFF chunk length */
65
+ view.setUint32(4, 36 + samples.length * 2, true);
66
+ /* RIFF type */
67
+ writeString(view, 8, 'WAVE');
68
+ /* format chunk identifier */
69
+ writeString(view, 12, 'fmt ');
70
+ /* format chunk length */
71
+ view.setUint32(16, 16, true);
72
+ /* sample format (raw) */
73
+ view.setUint16(20, 1, true);
74
+ /* channel count */
75
+ view.setUint16(22, recBuffers.length, true);
76
+ /* sample rate */
77
+ view.setUint32(24, 44100, true);
78
+ /* byte rate (sample rate * block align) */
79
+ view.setUint32(28, 44100 * 4, true);
80
+ /* block align (channel count * bytes per sample) */
81
+ view.setUint16(32, recBuffers.length * 2, true);
82
+ /* bits per sample */
83
+ view.setUint16(34, 16, true);
84
+ /* data chunk identifier */
85
+ writeString(view, 36, 'data');
86
+ /* data chunk length */
87
+ view.setUint32(40, samples.length * 2, true);
88
+
89
+ floatTo16BitPCM(view, 44, samples);
90
+
91
+ return view;
92
+ };
93
+
94
+ var exportWAV = function exportWAV(beginning, end) {
95
+ var buffers = [];
96
+ for (var channel = 0; channel < recBuffers.length; channel++) {
97
+ var length = 0;
98
+ var filtredRecBuffers = recBuffers[channel].filter(function (buffer) {
99
+ return buffer.timestamp >= beginning - 1000 && buffer.timestamp <= end;
100
+ }).map(function (buffer) {
101
+ length += buffer.length;
102
+ return buffer.data;
103
+ });
104
+ buffers.push(mergeBuffers(filtredRecBuffers, length));
105
+ }
106
+ var interleaved = recBuffers.length === 2 ? interleave(buffers[0], buffers[1]) : buffers[0];
107
+ var dataview = encodeWAV(interleaved);
108
+ audioBlob = new Blob([dataview], { type: 'audio/wav' });
109
+ };
110
+
111
+ switch (e.data.command) {
112
+ case 'append':
113
+ appendBuffer(e.data.timestamp, e.data.inputBuffer);
114
+ var buffers = [];
115
+ for (var channel = 0; channel < recBuffers.length; channel++) {
116
+ buffers.push(mergeBuffers(recBuffers[channel], recLength));
117
+ }
118
+ postMessage({ command: 'send_buffers', buffers: recBuffers });
119
+ break;
120
+ case 'exportWAV':
121
+ exportWAV(e.data.beginning, e.data.end);
122
+ postMessage({ command: 'send_WAV', audioBlob: audioBlob });
123
+ break;
124
+ case 'clean':
125
+ recLength = 0;
126
+ recBuffers = [];
127
+ audioBlob = null;
128
+ break;
129
+ }
130
+ };
131
+ };
132
+
133
+ exports.default = AudioWorker;
@@ -10,19 +10,27 @@ var _react = require('react');
10
10
 
11
11
  var _react2 = _interopRequireDefault(_react);
12
12
 
13
- var _msr = require('msr');
13
+ var _CustomWave = require('../player/CustomWave');
14
14
 
15
- var _msr2 = _interopRequireDefault(_msr);
16
-
17
- var _Wave = require('../player/Wave');
18
-
19
- var _Wave2 = _interopRequireDefault(_Wave);
15
+ var _CustomWave2 = _interopRequireDefault(_CustomWave);
20
16
 
21
17
  var _audioContext = require('../utils/audioContext');
22
18
 
23
19
  var _audioContext2 = _interopRequireDefault(_audioContext);
24
20
 
25
- var _audio = require('../utils/audio');
21
+ var _mediaDevices = require('../utils/mediaDevices');
22
+
23
+ var _hark = require('hark');
24
+
25
+ var _hark2 = _interopRequireDefault(_hark);
26
+
27
+ var _inlineWorker = require('inline-worker');
28
+
29
+ var _inlineWorker2 = _interopRequireDefault(_inlineWorker);
30
+
31
+ var _AudioWorker = require('./AudioWorker');
32
+
33
+ var _AudioWorker2 = _interopRequireDefault(_AudioWorker);
26
34
 
27
35
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
28
36
 
@@ -32,112 +40,175 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen
32
40
 
33
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; }
34
42
 
43
+ var INTERVAL = 100;
44
+
35
45
  var audioContext = new _audioContext2.default();
36
46
 
37
- var DesktopRecorder = function (_Component) {
38
- _inherits(DesktopRecorder, _Component);
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 initSpeechEvents = function initSpeechEvents(_ref2) {
71
+ var stream = _ref2.stream,
72
+ _ref2$onSpeaking = _ref2.onSpeaking,
73
+ onSpeaking = _ref2$onSpeaking === undefined ? function () {} : _ref2$onSpeaking,
74
+ _ref2$onStoppedSpeaki = _ref2.onStoppedSpeaking,
75
+ onStoppedSpeaking = _ref2$onStoppedSpeaki === undefined ? function () {} : _ref2$onStoppedSpeaki,
76
+ _ref2$onVolumeChange = _ref2.onVolumeChange,
77
+ onVolumeChange = _ref2$onVolumeChange === undefined ? function () {} : _ref2$onVolumeChange;
78
+
79
+ // Try hark
80
+ var options = {
81
+ interval: INTERVAL
82
+ };
83
+ var speechEvents = (0, _hark2.default)(stream, options);
84
+
85
+ speechEvents.on('speaking', onSpeaking);
86
+ speechEvents.on('stopped_speaking', onStoppedSpeaking);
87
+ speechEvents.on('volume_change', onVolumeChange);
88
+
89
+ return speechEvents;
90
+ };
39
91
 
40
- function DesktopRecorder(props) {
41
- _classCallCheck(this, DesktopRecorder);
92
+ var DesktopAudioRecorder = function (_Component) {
93
+ _inherits(DesktopAudioRecorder, _Component);
42
94
 
43
- var _this = _possibleConstructorReturn(this, (DesktopRecorder.__proto__ || Object.getPrototypeOf(DesktopRecorder)).call(this, props));
95
+ function DesktopAudioRecorder(props) {
96
+ _classCallCheck(this, DesktopAudioRecorder);
44
97
 
45
- _this.state = {
46
- isRecording: false,
47
- recordedData: null
48
- };
49
- _this.mediaRecorder = null;
50
- _this.buffers = [];
98
+ var _this = _possibleConstructorReturn(this, (DesktopAudioRecorder.__proto__ || Object.getPrototypeOf(DesktopAudioRecorder)).call(this, props));
99
+
100
+ _this.recordStart = null;
101
+ _this.audioBuffer = [];
102
+ _this.init = _this.init.bind(_this);
103
+ _this.initStream = _this.initStream.bind(_this);
51
104
  return _this;
52
105
  }
53
106
 
54
- _createClass(DesktopRecorder, [{
55
- key: 'render',
56
- value: function render() {
107
+ _createClass(DesktopAudioRecorder, [{
108
+ key: 'componentDidMount',
109
+ value: function componentDidMount() {
110
+ this.init(this.props);
111
+ }
112
+ }, {
113
+ key: 'init',
114
+ value: function init(props) {
57
115
  var _this2 = this;
58
116
 
59
- var _state = this.state,
60
- isRecording = _state.isRecording,
61
- recordedData = _state.recordedData;
62
-
63
- return _react2.default.createElement(
64
- 'div',
65
- null,
66
- 'Desktop recorder',
67
- isRecording ? _react2.default.createElement(
68
- 'button',
69
- { onClick: function onClick() {
70
- return _this2.stopRecording();
71
- } },
72
- ' stop recording '
73
- ) : _react2.default.createElement(
74
- 'button',
75
- { onClick: function onClick() {
76
- return _this2.record();
77
- } },
78
- ' record '
79
- ),
80
- recordedData ? _react2.default.createElement(_Wave2.default, {
81
- width: 500,
82
- currentTime: 0,
83
- height: 40,
84
- isLoading: false,
85
- buffer: recordedData }) : null
86
- );
117
+ var _props$onError = props.onError,
118
+ onError = _props$onError === undefined ? function () {} : _props$onError,
119
+ _props$onVolumeChange = props.onVolumeChange,
120
+ onVolumeChange = _props$onVolumeChange === undefined ? function () {} : _props$onVolumeChange,
121
+ _props$onRecordComple = props.onRecordComplete,
122
+ onRecordComplete = _props$onRecordComple === undefined ? function () {} : _props$onRecordComple;
123
+
124
+
125
+ (0, _mediaDevices.shimMediaDevices)();
126
+ window.navigator.mediaDevices.getUserMedia({ audio: true }).then(function (stream) {
127
+ _this2.initStream({
128
+ stream: stream,
129
+ onError: onError,
130
+ onVolumeChange: onVolumeChange,
131
+ onRecordComplete: onRecordComplete
132
+ });
133
+ }).catch(function (err) {
134
+ onError(err);
135
+ });
136
+
137
+ this.initWorker();
87
138
  }
88
139
  }, {
89
- key: 'record',
90
- value: function record() {
140
+ key: 'initStream',
141
+ value: function initStream(_ref3) {
91
142
  var _this3 = this;
92
143
 
93
- window.navigator.getUserMedia({ audio: true }, function (stream) {
94
- return _this3.onMediaSuccess(stream);
95
- }, function (stream) {
96
- return _this3.onMediaError(stream);
144
+ var stream = _ref3.stream,
145
+ onError = _ref3.onError,
146
+ _onVolumeChange = _ref3.onVolumeChange,
147
+ onRecordComplete = _ref3.onRecordComplete;
148
+
149
+ // Init recorder
150
+ var recorder = initRecorder({
151
+ stream: stream,
152
+ audioContext: audioContext,
153
+ onAudioProcess: function onAudioProcess(e) {
154
+ var inputBuffer = [];
155
+ for (var channel = 0; channel < e.inputBuffer.numberOfChannels; channel++) {
156
+ inputBuffer.push(e.inputBuffer.getChannelData(channel));
157
+ }
158
+ _this3.worker.postMessage({ command: 'append', timestamp: Date.now(), inputBuffer: inputBuffer });
159
+ }
97
160
  });
98
- this.setState({
99
- isRecording: true
161
+
162
+ // Initialize hark for silence recognition
163
+ var speechEvents = initSpeechEvents({
164
+ stream: stream,
165
+ onStoppedSpeaking: function onStoppedSpeaking() {
166
+ console.log('stop');
167
+ try {
168
+ _this3.worker.postMessage({ command: 'exportWAV', buffers: _this3.audioBuffer, beginning: _this3.recordStart, end: Date.now() });
169
+ _this3.worker.postMessage({ command: 'clean' });
170
+ _this3.audioBuffer = [];
171
+ } catch (e) {
172
+ onError(e);
173
+ }
174
+ },
175
+ onSpeaking: function onSpeaking() {
176
+ console.log('start');
177
+ _this3.recordStart = Date.now() - INTERVAL * 3; // give it a bit of extra time
178
+ },
179
+ onVolumeChange: function onVolumeChange(volume) {
180
+ _onVolumeChange(volume);
181
+ }
100
182
  });
101
183
  }
102
184
  }, {
103
- key: 'onMediaSuccess',
104
- value: function onMediaSuccess(stream) {
185
+ key: 'initWorker',
186
+ value: function initWorker() {
105
187
  var _this4 = this;
106
188
 
107
- this.mediaRecorder = new _msr2.default(stream);
108
- this.mediaRecorder.mimeType = 'audio/wav'; // check this line for audio/wav
109
- this.mediaRecorder.bufferSize = 256; // check this line for audio/wav
110
- this.mediaRecorder.ondataavailable = function (blob) {
111
- (0, _audio.convertBlobToAudioBuffer)(blob, _this4.onRecordingConverted.bind(_this4));
189
+ this.worker = new _inlineWorker2.default(_AudioWorker2.default, {});
190
+
191
+ this.worker.onmessage = function (e) {
192
+ switch (e.data.command) {
193
+ case 'send_buffers':
194
+ _this4.audioBuffer = e.data.buffers;
195
+ break;
196
+ case 'send_WAV':
197
+ console.log('send_WAV');
198
+ //const url = (window.URL || window.webkitURL).createObjectURL(e.data.audioBlob)
199
+ _this4.props.onRecordComplete(e.data.audioBlob);
200
+ break;
201
+ }
112
202
  };
113
- this.mediaRecorder.start();
114
203
  }
115
204
  }, {
116
- key: 'onRecordingConverted',
117
- value: function onRecordingConverted(audioBuffer) {
118
- var recordedData = this.state.recordedData;
119
-
120
- var mergedBuffer = (0, _audio.appendBuffer)(recordedData, audioBuffer);
121
- this.setState({
122
- recordedData: mergedBuffer
123
- });
124
- }
125
- }, {
126
- key: 'onMediaError',
127
- value: function onMediaError(e) {
128
- console.error('media error', e);
129
- }
130
- }, {
131
- key: 'stopRecording',
132
- value: function stopRecording() {
133
- this.mediaRecorder.stop();
134
- this.setState({
135
- isRecording: false
136
- });
205
+ key: 'render',
206
+ value: function render() {
207
+ return null;
137
208
  }
138
209
  }]);
139
210
 
140
- return DesktopRecorder;
211
+ return DesktopAudioRecorder;
141
212
  }(_react.Component);
142
213
 
143
- exports.default = DesktopRecorder;
214
+ exports.default = DesktopAudioRecorder;
package/recorder/index.js CHANGED
@@ -10,9 +10,9 @@ var _react2 = _interopRequireDefault(_react);
10
10
 
11
11
  var _is_js = require('is_js');
12
12
 
13
- var _DesktopAudioRecorder = require('./DesktopAudioRecorder');
13
+ var _DesktopRecorder = require('./DesktopRecorder');
14
14
 
15
- var _DesktopAudioRecorder2 = _interopRequireDefault(_DesktopAudioRecorder);
15
+ var _DesktopRecorder2 = _interopRequireDefault(_DesktopRecorder);
16
16
 
17
17
  var _MobileRecorder = require('./MobileRecorder');
18
18
 
@@ -24,12 +24,12 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
24
24
  var isUserMediaSupported = !!(window.navigator.getUserMedia || window.navigator.webkitGetUserMedia || window.navigator.mozGetUserMedia || window.navigator.msGetUserMedia);
25
25
  var desktop = !((0, _is_js.tablet)() && (0, _is_js.mobile)());
26
26
 
27
- var Recorder = function Recorder() {
28
- return desktop ? isUserMediaSupported ? _react2.default.createElement(_DesktopAudioRecorder2.default, null) : _react2.default.createElement(
27
+ var Recorder = function Recorder(props) {
28
+ return desktop ? isUserMediaSupported ? _react2.default.createElement(_DesktopRecorder2.default, props) : _react2.default.createElement(
29
29
  'div',
30
30
  null,
31
31
  ' not supported '
32
- ) : _react2.default.createElement(_MobileRecorder2.default, null);
32
+ ) : _react2.default.createElement(_MobileRecorder2.default, props);
33
33
  };
34
34
 
35
35
  exports.default = Recorder;
@@ -18,13 +18,30 @@ var _recorder2 = _interopRequireDefault(_recorder);
18
18
 
19
19
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20
20
 
21
+ var API_URL = 'http://localhost:3004/speechtotext';
22
+
23
+ var sendFile = function sendFile(wav) {
24
+ var xhr = new XMLHttpRequest();
25
+ xhr.onreadystatechange = function () {
26
+ if (xhr.readyState == 4 && xhr.status == 200) {
27
+ console.log('Speech to text: ', xhr.responseText);
28
+ }
29
+ };
30
+ xhr.open('POST', API_URL, false);
31
+ xhr.setRequestHeader('Content-Type', 'audio/wav');
32
+ xhr.send(wav);
33
+ };
34
+
21
35
  var RecorderExample = function RecorderExample() {
22
- return _react2.default.createElement(
23
- 'div',
24
- null,
25
- _react2.default.createElement(_recorder2.default, null),
26
- _react2.default.createElement('audio', { controls: true })
27
- );
36
+ return _react2.default.createElement(_recorder2.default, {
37
+ onVolumeChange: function onVolumeChange(vol) {},
38
+ onError: function onError(err) {
39
+ return console.log('error', err);
40
+ },
41
+ onRecordComplete: function onRecordComplete(wax) {
42
+ return sendFile(wax);
43
+ }
44
+ });
28
45
  };
29
46
 
30
47
  exports.default = RecorderExample;
package/utils/audio.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.audioBufferToWav = exports.convertBlobToaudioBuffer = exports.appendBuffer = exports.convertAudioBufferToWaveform = exports.getWaveform = undefined;
6
+ exports.getWaveform = undefined;
7
7
 
8
8
  var _audioContext = require('./audioContext');
9
9
 
@@ -47,166 +47,51 @@ var getWaveform = exports.getWaveform = function getWaveform(url) {
47
47
  });
48
48
  };
49
49
 
50
- var convertAudioBufferToWaveform = exports.convertAudioBufferToWaveform = function convertAudioBufferToWaveform(audioBuffer) {
50
+ /*
51
+ export const convertAudioBufferToWaveform = (audioBuffer) => {
51
52
  // All this code (except the last line) is stolen/inspired from https://github.com/bbc/waveform-data.js/blob/master/lib/builders/audiodecoder.js
52
- var scale = 512;
53
- var scaleAdjuster = 127;
54
- var dataLength = Math.floor(audioBuffer.length / scale);
55
- var offset = 20;
56
- var dataObject = new DataView(new ArrayBuffer(offset + dataLength * 2));
57
- var leftChannel = void 0,
58
- rightChannel = void 0;
59
- var minValue = Infinity,
60
- max_value = -Infinity,
61
- scale_counter = scale;
62
- var bufferLength = audioBuffer.length;
63
-
64
- dataObject.setInt32(0, 1, true); //version
65
- dataObject.setUint32(4, 1, true); //is 8 bit
66
- dataObject.setInt32(8, audioBuffer.sampleRate, true); //sample rate
67
- dataObject.setInt32(12, scale, true); //scale
68
- dataObject.setInt32(16, dataLength, true); //length
53
+ const scale = 512
54
+ const scaleAdjuster = 127
55
+ const dataLength = Math.floor(audioBuffer.length / scale)
56
+ let offset = 20
57
+ const dataObject = new DataView(new ArrayBuffer(offset + dataLength * 2))
58
+ let leftChannel, rightChannel
59
+ let minValue = Infinity, max_value = -Infinity, scale_counter = scale;
60
+ const bufferLength = audioBuffer.length
61
+
62
+ dataObject.setInt32(0, 1, true); //version
63
+ dataObject.setUint32(4, 1, true); //is 8 bit
64
+ dataObject.setInt32(8, audioBuffer.sampleRate, true); //sample rate
65
+ dataObject.setInt32(12, scale, true); //scale
66
+ dataObject.setInt32(16, dataLength, true); //length
69
67
 
70
68
  leftChannel = audioBuffer.getChannelData(0);
71
69
  rightChannel = audioBuffer.getChannelData(1);
72
70
 
73
- for (var i = 0; i < bufferLength; i++) {
74
- var sample = (leftChannel[i] + rightChannel[i]) / 2 * scaleAdjuster;
71
+ for (let i = 0; i < bufferLength; i++){
72
+ const sample = (leftChannel[i] + rightChannel[i]) / 2 * scaleAdjuster;
75
73
 
76
- if (sample < minValue) {
74
+ if (sample < minValue){
77
75
  minValue = sample;
78
76
  if (minValue < -128) {
79
77
  minValue = -128;
80
78
  }
81
79
  }
82
80
 
83
- if (sample > max_value) {
81
+ if (sample > max_value){
84
82
  max_value = sample;
85
83
  if (max_value > 127) {
86
84
  max_value = 127;
87
85
  }
88
86
  }
89
87
 
90
- if (--scale_counter === 0) {
88
+ if (--scale_counter === 0){
91
89
  dataObject.setInt8(offset++, Math.floor(minValue));
92
90
  dataObject.setInt8(offset++, Math.floor(max_value));
93
- minValue = Infinity;max_value = -Infinity;scale_counter = scale;
91
+ minValue = Infinity; max_value = -Infinity; scale_counter = scale;
94
92
  }
95
93
  }
96
94
 
97
- return _waveformData2.default.create(dataObject.buffer);
98
- };
99
-
100
- var appendBuffer = exports.appendBuffer = function appendBuffer(buffer1, buffer2) {
101
- if (!buffer1) return buffer2;
102
- if (!buffer2) return buffer1;
103
- var numberOfChannels = Math.min(buffer1.numberOfChannels, buffer2.numberOfChannels);
104
- var tmp = audioContext.createBuffer(numberOfChannels, buffer1.length + buffer2.length, buffer1.sampleRate);
105
- for (var i = 0; i < numberOfChannels; i++) {
106
- var channel = tmp.getChannelData(i);
107
- channel.set(buffer1.getChannelData(i), 0);
108
- channel.set(buffer2.getChannelData(i), buffer1.length);
109
- }
110
- return tmp;
111
- };
112
-
113
- var convertBlobToaudioBuffer = exports.convertBlobToaudioBuffer = function convertBlobToaudioBuffer(blob, cb) {
114
- var fileReader = new FileReader();
115
- fileReader.onload = function (_ref) {
116
- var result = _ref.target.result;
117
-
118
- audioContext.decodeAudioData(result, function (buf) {
119
- cb(buf);
120
- });
121
- };
122
- fileReader.readAsArrayBuffer(blob);
123
- };
124
-
125
- var audioBufferToWav = exports.audioBufferToWav = function audioBufferToWav(buffer, opt) {
126
- opt = opt || {};
127
-
128
- var numChannels = buffer.numberOfChannels;
129
- var sampleRate = buffer.sampleRate;
130
- var format = opt.float32 ? 3 : 1;
131
- var bitDepth = format === 3 ? 32 : 16;
132
-
133
- var result = numChannels === 2 ? interleave(buffer.getChannelData(0), buffer.getChannelData(1)) : buffer.getChannelData(0);
134
-
135
- return encodeWAV(result, format, sampleRate, numChannels, bitDepth);
136
- };
137
-
138
- var encodeWAV = function encodeWAV(samples, format, sampleRate, numChannels, bitDepth) {
139
- var bytesPerSample = bitDepth / 8;
140
- var blockAlign = numChannels * bytesPerSample;
141
-
142
- var buffer = new ArrayBuffer(44 + samples.length * bytesPerSample);
143
- var view = new DataView(buffer);
144
-
145
- /* RIFF identifier */
146
- writeString(view, 0, 'RIFF');
147
- /* RIFF chunk length */
148
- view.setUint32(4, 36 + samples.length * bytesPerSample, true);
149
- /* RIFF type */
150
- writeString(view, 8, 'WAVE');
151
- /* format chunk identifier */
152
- writeString(view, 12, 'fmt ');
153
- /* format chunk length */
154
- view.setUint32(16, 16, true);
155
- /* sample format (raw) */
156
- view.setUint16(20, format, true);
157
- /* channel count */
158
- view.setUint16(22, numChannels, true);
159
- /* sample rate */
160
- view.setUint32(24, sampleRate, true);
161
- /* byte rate (sample rate * block align) */
162
- view.setUint32(28, sampleRate * blockAlign, true);
163
- /* block align (channel count * bytes per sample) */
164
- view.setUint16(32, blockAlign, true);
165
- /* bits per sample */
166
- view.setUint16(34, bitDepth, true);
167
- /* data chunk identifier */
168
- writeString(view, 36, 'data');
169
- /* data chunk length */
170
- view.setUint32(40, samples.length * bytesPerSample, true);
171
- if (format === 1) {
172
- // Raw PCM
173
- floatTo16BitPCM(view, 44, samples);
174
- } else {
175
- writeFloat32(view, 44, samples);
176
- }
177
- return buffer;
178
- };
179
-
180
- var interleave = function interleave(inputL, inputR) {
181
- var length = inputL.length + inputR.length;
182
- var result = new Float32Array(length);
183
-
184
- var index = 0;
185
- var inputIndex = 0;
186
-
187
- while (index < length) {
188
- result[index++] = inputL[inputIndex];
189
- result[index++] = inputR[inputIndex];
190
- inputIndex++;
191
- }
192
- return result;
193
- };
194
-
195
- var writeFloat32 = function writeFloat32(output, offset, input) {
196
- for (var i = 0; i < input.length; i++, offset += 4) {
197
- output.setFloat32(offset, input[i], true);
198
- }
199
- };
200
-
201
- var floatTo16BitPCM = function floatTo16BitPCM(output, offset, input) {
202
- for (var i = 0; i < input.length; i++, offset += 2) {
203
- var s = Math.max(-1, Math.min(1, input[i]));
204
- output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
205
- }
206
- };
207
-
208
- var writeString = function writeString(view, offset, string) {
209
- for (var i = 0; i < string.length; i++) {
210
- view.setUint8(offset + i, string.charCodeAt(i));
211
- }
212
- };
95
+ return WaveformData.create(dataObject.buffer)
96
+ }
97
+ */
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var shimMediaDevices = exports.shimMediaDevices = function shimMediaDevices() {
7
+ // Older browsers might not implement mediaDevices at all, so we set an empty object first
8
+ if (window.navigator.mediaDevices === undefined) {
9
+ window.navigator.mediaDevices = {};
10
+ }
11
+
12
+ // Some browsers partially implement mediaDevices. We can't just assign an object
13
+ // with getUserMedia as it would overwrite existing properties.
14
+ // Here, we will just add the getUserMedia property if it's missing.
15
+ if (window.navigator.mediaDevices.getUserMedia === undefined) {
16
+ window.navigator.mediaDevices.getUserMedia = function (constraints) {
17
+
18
+ // First get ahold of the legacy getUserMedia, if present
19
+ var getUserMedia = window.navigator.webkitGetUserMedia || window.navigator.mozGetUserMedia;
20
+
21
+ // Some browsers just don't implement it - return a rejected promise with an error
22
+ // to keep a consistent interface
23
+ if (!getUserMedia) {
24
+ return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
25
+ }
26
+
27
+ // Otherwise, wrap the call to the old navigator.getUserMedia with a Promise
28
+ return new Promise(function (resolve, reject) {
29
+ getUserMedia.call(navigator, constraints, resolve, reject);
30
+ });
31
+ };
32
+ }
33
+ };
@@ -1,84 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
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
-
9
- var _react = require('react');
10
-
11
- var _react2 = _interopRequireDefault(_react);
12
-
13
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
-
15
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
16
-
17
- 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; }
18
-
19
- 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; }
20
-
21
- var loadedScripts = [];
22
-
23
- var getCssEl = function getCssEl(_ref) {
24
- var href = _ref.href;
25
-
26
- var link = document.createElement('link');
27
- link.rel = 'stylesheet';
28
- link.type = 'text/css';
29
- link.href = href;
30
- link.media = 'all';
31
- return link;
32
- };
33
-
34
- var getScriptEl = function getScriptEl(_ref2) {
35
- var src = _ref2.src,
36
- onload = _ref2.onload,
37
- onError = _ref2.onError;
38
-
39
- var script = document.createElement('script');
40
- script.type = 'text/javascript';
41
- script.src = src;
42
- script.async = false;
43
- script.onload = onload;
44
- script.onerror = onError;
45
- return script;
46
- };
47
-
48
- var AsyncLoader = function (_Component) {
49
- _inherits(AsyncLoader, _Component);
50
-
51
- function AsyncLoader() {
52
- _classCallCheck(this, AsyncLoader);
53
-
54
- return _possibleConstructorReturn(this, (AsyncLoader.__proto__ || Object.getPrototypeOf(AsyncLoader)).apply(this, arguments));
55
- }
56
-
57
- _createClass(AsyncLoader, [{
58
- key: 'componentDidMount',
59
- value: function componentDidMount() {
60
- var _props = this.props,
61
- src = _props.src,
62
- href = _props.href,
63
- _props$onLoad = _props.onLoad,
64
- onLoad = _props$onLoad === undefined ? function () {} : _props$onLoad,
65
- _props$onError = _props.onError,
66
- onError = _props$onError === undefined ? function () {} : _props$onError;
67
-
68
- if (src && !loadedScripts.includes(href || src)) {
69
- var el = href ? getCssEl({ href: href }) : getScriptEl({ src: src, onLoad: onLoad, onError: onError });
70
- document.body.appendChild(el);
71
- loadedScripts.push(href || src);
72
- }
73
- }
74
- }, {
75
- key: 'render',
76
- value: function render() {
77
- return _react2.default.createElement('noscript', null);
78
- }
79
- }]);
80
-
81
- return AsyncLoader;
82
- }(_react.Component);
83
-
84
- exports.default = AsyncLoader;
@@ -1,191 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
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
-
9
- var _react = require('react');
10
-
11
- var _react2 = _interopRequireDefault(_react);
12
-
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 _audio = require('../utils/audio');
22
-
23
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
24
-
25
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
26
-
27
- 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; }
28
-
29
- 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; }
30
-
31
- var audioContext = new _audioContext2.default();
32
-
33
- var DesktopAudioRecorder = function (_Component) {
34
- _inherits(DesktopAudioRecorder, _Component);
35
-
36
- function DesktopAudioRecorder(props) {
37
- _classCallCheck(this, DesktopAudioRecorder);
38
-
39
- var _this = _possibleConstructorReturn(this, (DesktopAudioRecorder.__proto__ || Object.getPrototypeOf(DesktopAudioRecorder)).call(this, props));
40
-
41
- _this.state = {
42
- isRecording: false,
43
- recordedData: null,
44
- waveform: null
45
- };
46
- //this.audioRecorder = null
47
- _this.buffers = [];
48
- return _this;
49
- }
50
-
51
- _createClass(DesktopAudioRecorder, [{
52
- key: 'componentDidMount',
53
- value: function componentDidMount() {
54
- var _this2 = this;
55
-
56
- window.navigator.getUserMedia({
57
- "audio": {
58
- "mandatory": {
59
- "googEchoCancellation": "false",
60
- "googAutoGainControl": "false",
61
- "googNoiseSuppression": "false",
62
- "googHighpassFilter": "false"
63
- },
64
- "optional": []
65
- }
66
- }, function (stream) {
67
- return _this2.onMediaSuccess(stream);
68
- }, function (stream) {
69
- return _this2.onMediaError(stream);
70
- });
71
- }
72
- }, {
73
- key: 'render',
74
- value: function render() {
75
- var _this3 = this;
76
-
77
- var _state = this.state,
78
- isRecording = _state.isRecording,
79
- waveform = _state.waveform;
80
-
81
- return _react2.default.createElement(
82
- 'div',
83
- null,
84
- 'Desktop audio recorder',
85
- isRecording ? _react2.default.createElement(
86
- 'button',
87
- { onClick: function onClick() {
88
- return _this3.stopRecording();
89
- } },
90
- ' stop recording '
91
- ) : _react2.default.createElement(
92
- 'button',
93
- { onClick: function onClick() {
94
- return _this3.record();
95
- } },
96
- ' record '
97
- ),
98
- waveform ? _react2.default.createElement(_CustomWave2.default, {
99
- width: 500,
100
- currentTime: 0,
101
- totalTime: 200,
102
- height: 40,
103
- isLoading: false,
104
- waveform: waveform
105
- }) : null
106
- );
107
- }
108
- }, {
109
- key: 'record',
110
- value: function record() {
111
- this.setState({
112
- recordedData: null,
113
- isRecording: true
114
- });
115
- }
116
- }, {
117
- key: 'onMediaSuccess',
118
- value: function onMediaSuccess(stream) {
119
- var _this4 = this;
120
-
121
- var bufferSize = 4096;
122
- var numberOfInputChannels = 2;
123
- var numberOfOutputChannels = 2;
124
-
125
- // creates an audio node from the microphone incoming stream
126
- var mediaStream = audioContext.createMediaStreamSource(stream);
127
- // https://developer.mozilla.org/en-US/docs/Web/API/AudioaudioContext/createScriptProcessor
128
- var recorder = audioContext.createScriptProcessor ? audioContext.createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels) : audioContext.createJavaScriptNode(bufferSize, numberOfInputChannels, numberOfOutputChannels);
129
-
130
- recorder.onaudioprocess = function (e) {
131
- var _state2 = _this4.state,
132
- recordedData = _state2.recordedData,
133
- isRecording = _state2.isRecording;
134
-
135
- if (!isRecording) return;
136
- var audioBuffer = (0, _audio.appendBuffer)(recordedData, e.inputBuffer);
137
- var waveform = (0, _audio.convertAudioBufferToWaveform)(audioBuffer);
138
-
139
- _this4.setState({
140
- recordedData: audioBuffer,
141
- waveform: waveform
142
- });
143
- };
144
-
145
- // we connect the recorder with the input stream
146
- mediaStream.connect(recorder);
147
- recorder.connect(audioContext.destination);
148
- }
149
- }, {
150
- key: 'onMediaError',
151
- value: function onMediaError(e) {
152
- console.error('media error', e);
153
- }
154
-
155
- // This is just for demo purposes: in real life we'll upload the file somewhere
156
-
157
- }, {
158
- key: 'updateAudioDom',
159
- value: function updateAudioDom() {
160
- var recordedData = this.state.recordedData;
161
-
162
- var audioEl = document.querySelector('audio');
163
-
164
- if (audioEl) {
165
- var wav = (0, _audio.audioBufferToWav)(recordedData);
166
- var audioBlob = new Blob([wav], { type: 'audio/wav' });
167
- var reader = new FileReader();
168
- reader.onload = function (e) {
169
- // e.target.result will hold the base64 data.
170
- // Note: It includes the pre-text "data:audio/<format>;base64,<base64 data>"
171
- audioEl.src = e.target.result;
172
- };
173
- reader.readAsDataURL(audioBlob);
174
- }
175
- }
176
- }, {
177
- key: 'stopRecording',
178
- value: function stopRecording() {
179
- this.setState({
180
- isRecording: false
181
- });
182
-
183
- // Update audio element with new file
184
- this.updateAudioDom();
185
- }
186
- }]);
187
-
188
- return DesktopAudioRecorder;
189
- }(_react.Component);
190
-
191
- exports.default = DesktopAudioRecorder;