@lls/lls-audio 0.0.14 → 0.0.17
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 +3 -3
- package/player/Audio.js +24 -6
- package/player/index.js +35 -10
- package/player/styles/styles.js +14 -1
- package/player/styles/timelineClassNames.js +1 -2
- package/recorder/DesktopAudioRecorder.js +26 -0
- package/recorder/DesktopRecorder.js +0 -1
- package/stories/player.js +1 -1
- package/stories/recorder.js +2 -2
- package/utils/audio.js +90 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lls/lls-audio",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"devDependencies": {
|
|
6
6
|
"@kadira/storybook": "^2.21.0",
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"node": ">=0.12.0"
|
|
35
35
|
},
|
|
36
36
|
"repository": {
|
|
37
|
-
"url": "github.com/lelivrescolaire/
|
|
37
|
+
"url": "github.com/lelivrescolaire/sound-poke"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"start": "npm run storybook",
|
|
41
|
-
"storybook": "start-storybook -p 9009
|
|
41
|
+
"storybook": "start-storybook -p 9009",
|
|
42
42
|
"deploy-storybook": "storybook-to-ghpages",
|
|
43
43
|
"build": "rm -rf dist && mkdir dist && babel -d dist src",
|
|
44
44
|
"copy:package": "cp -R package.json dist/",
|
package/player/Audio.js
CHANGED
|
@@ -28,6 +28,8 @@ var Player = function (_Component) {
|
|
|
28
28
|
|
|
29
29
|
var _this = _possibleConstructorReturn(this, (Player.__proto__ || Object.getPrototypeOf(Player)).call(this, props));
|
|
30
30
|
|
|
31
|
+
_this.requestAnimationId = null;
|
|
32
|
+
|
|
31
33
|
_this.play = function () {
|
|
32
34
|
return _this.refs.player.play();
|
|
33
35
|
};
|
|
@@ -65,12 +67,27 @@ var Player = function (_Component) {
|
|
|
65
67
|
return _this.setStateWithCallback({ currentTime: _this.getCurrentTime() });
|
|
66
68
|
};
|
|
67
69
|
|
|
70
|
+
_this.watchAudioUpdate = function () {
|
|
71
|
+
var step = function step(timestamp) {
|
|
72
|
+
if (_this.getCurrentTime() !== _this.state.currentTime) {
|
|
73
|
+
_this.setStateWithCallback({ currentTime: _this.getCurrentTime() });
|
|
74
|
+
}
|
|
75
|
+
_this.requestAnimationId = requestAnimationFrame(step);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
_this.requestAnimationId = requestAnimationFrame(step);
|
|
79
|
+
};
|
|
80
|
+
|
|
68
81
|
_this.onPlay = function () {
|
|
69
|
-
|
|
82
|
+
_this.setStateWithCallback({ play: true }, function () {
|
|
83
|
+
return _this.watchAudioUpdate();
|
|
84
|
+
});
|
|
70
85
|
};
|
|
71
86
|
|
|
72
87
|
_this.onPause = function () {
|
|
73
|
-
|
|
88
|
+
_this.setStateWithCallback({ play: false }, function () {
|
|
89
|
+
return cancelAnimationFrame(_this.requestAnimationId);
|
|
90
|
+
});
|
|
74
91
|
};
|
|
75
92
|
|
|
76
93
|
_this.onEnded = function () {
|
|
@@ -92,7 +109,7 @@ var Player = function (_Component) {
|
|
|
92
109
|
duration: 0
|
|
93
110
|
};
|
|
94
111
|
|
|
95
|
-
(0, _utils.autoBind)(['onEnded', 'onDurationChange', '
|
|
112
|
+
(0, _utils.autoBind)(['onEnded', 'onDurationChange', 'onPlay', 'onPause', 'onAudioUpdate'], _this);
|
|
96
113
|
|
|
97
114
|
// Execute callback onChange props
|
|
98
115
|
_this.setStateWithCallback = function (state) {
|
|
@@ -139,14 +156,13 @@ var Player = function (_Component) {
|
|
|
139
156
|
key: 'componentDidMount',
|
|
140
157
|
value: function componentDidMount() {
|
|
141
158
|
this.props.onChange(this.state);
|
|
142
|
-
|
|
143
159
|
var player = this.refs.player;
|
|
144
160
|
|
|
145
161
|
player.addEventListener('ended', this.onEnded);
|
|
146
162
|
player.addEventListener('durationchange', this.onDurationChange);
|
|
147
|
-
player.addEventListener('timeupdate', this.onAudioUpdate);
|
|
148
163
|
player.addEventListener('play', this.onPlay);
|
|
149
164
|
player.addEventListener('pause', this.onPause);
|
|
165
|
+
player.addEventListener('timeupdate', this.onAudioUpdate);
|
|
150
166
|
}
|
|
151
167
|
}, {
|
|
152
168
|
key: 'componentWillUnmount',
|
|
@@ -155,9 +171,9 @@ var Player = function (_Component) {
|
|
|
155
171
|
|
|
156
172
|
player.removeEventListener('ended', this.onEnded);
|
|
157
173
|
player.removeEventListener('durationchange', this.onDurationChange);
|
|
158
|
-
player.removeEventListener('timeupdate', this.onAudioUpdate);
|
|
159
174
|
player.removeEventListener('play', this.onPlay);
|
|
160
175
|
player.removeEventListener('pause', this.onPause);
|
|
176
|
+
player.removeEventListener('timeupdate', this.onAudioUpdate);
|
|
161
177
|
}
|
|
162
178
|
}, {
|
|
163
179
|
key: 'getCurrentTime',
|
|
@@ -168,6 +184,7 @@ var Player = function (_Component) {
|
|
|
168
184
|
startTime = _state$currentRange.startTime,
|
|
169
185
|
endTime = _state$currentRange.endTime,
|
|
170
186
|
loop = _state.loop;
|
|
187
|
+
|
|
171
188
|
// check if current time is in the middle of current range
|
|
172
189
|
|
|
173
190
|
if (currentTime > endTime || currentTime < startTime) {
|
|
@@ -183,6 +200,7 @@ var Player = function (_Component) {
|
|
|
183
200
|
var duration = this.refs.player.duration;
|
|
184
201
|
|
|
185
202
|
this.setStateWithCallback({
|
|
203
|
+
play: false,
|
|
186
204
|
currentTime: 0,
|
|
187
205
|
duration: duration,
|
|
188
206
|
currentRange: { startTime: 0, endTime: duration }
|
package/player/index.js
CHANGED
|
@@ -84,7 +84,20 @@ var Player = function (_Component) {
|
|
|
84
84
|
return _this.refs.audio.setRange(range);
|
|
85
85
|
};
|
|
86
86
|
|
|
87
|
-
_this.
|
|
87
|
+
_this.toggleVisible = function () {
|
|
88
|
+
var visible = _this.state.visible;
|
|
89
|
+
|
|
90
|
+
_this.setState({
|
|
91
|
+
visible: !visible
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
_this.state = {
|
|
96
|
+
waveform: false,
|
|
97
|
+
loading: true,
|
|
98
|
+
containerWidth: 0,
|
|
99
|
+
visible: true
|
|
100
|
+
};
|
|
88
101
|
_this.setContainerWidth = (0, _utils.debounce)(_this.setContainerWidth.bind(_this), 500);
|
|
89
102
|
_this.onKeyPress = _this.onKeyPress.bind(_this);
|
|
90
103
|
return _this;
|
|
@@ -109,7 +122,7 @@ var Player = function (_Component) {
|
|
|
109
122
|
}, {
|
|
110
123
|
key: 'componentWillReceiveProps',
|
|
111
124
|
value: function componentWillReceiveProps(newProps) {
|
|
112
|
-
if (newProps.
|
|
125
|
+
if (newProps.src !== this.props.src || newProps.visible !== newProps.visible) {
|
|
113
126
|
this.initialize(newProps);
|
|
114
127
|
}
|
|
115
128
|
}
|
|
@@ -138,10 +151,16 @@ var Player = function (_Component) {
|
|
|
138
151
|
value: function initialize(props) {
|
|
139
152
|
var _this3 = this;
|
|
140
153
|
|
|
141
|
-
var
|
|
154
|
+
var src = props.src,
|
|
155
|
+
_props$visible = props.visible,
|
|
156
|
+
visible = _props$visible === undefined ? true : _props$visible;
|
|
142
157
|
|
|
143
|
-
(0, _audio.getWaveform)(
|
|
144
|
-
_this3.setState({
|
|
158
|
+
(0, _audio.getWaveform)(src).then(function (waveform) {
|
|
159
|
+
_this3.setState({
|
|
160
|
+
waveform: waveform,
|
|
161
|
+
loading: false,
|
|
162
|
+
visible: visible
|
|
163
|
+
});
|
|
145
164
|
});
|
|
146
165
|
}
|
|
147
166
|
}, {
|
|
@@ -149,7 +168,9 @@ var Player = function (_Component) {
|
|
|
149
168
|
value: function render() {
|
|
150
169
|
var _this4 = this;
|
|
151
170
|
|
|
152
|
-
var
|
|
171
|
+
var _props = this.props,
|
|
172
|
+
src = _props.src,
|
|
173
|
+
className = _props.className;
|
|
153
174
|
var _state = this.state,
|
|
154
175
|
loading = _state.loading,
|
|
155
176
|
duration = _state.duration,
|
|
@@ -159,7 +180,8 @@ var Player = function (_Component) {
|
|
|
159
180
|
containerWidth = _state.containerWidth,
|
|
160
181
|
speed = _state.speed,
|
|
161
182
|
_state$currentRange = _state.currentRange,
|
|
162
|
-
currentRange = _state$currentRange === undefined ? {} : _state$currentRange
|
|
183
|
+
currentRange = _state$currentRange === undefined ? {} : _state$currentRange,
|
|
184
|
+
visible = _state.visible;
|
|
163
185
|
var _currentRange$startTi = currentRange.startTime,
|
|
164
186
|
startTime = _currentRange$startTi === undefined ? 0 : _currentRange$startTi,
|
|
165
187
|
_currentRange$endTime = currentRange.endTime,
|
|
@@ -167,7 +189,7 @@ var Player = function (_Component) {
|
|
|
167
189
|
|
|
168
190
|
return _react2.default.createElement(
|
|
169
191
|
'div',
|
|
170
|
-
{ className: 'Audio_player ' + (0, _noImportant.css)(styles.player) },
|
|
192
|
+
{ className: 'Audio_player ' + (0, _noImportant.css)(styles.player) + ' ' + className + ' ' + (visible ? '' : (0, _noImportant.css)(styles.hidden)) },
|
|
171
193
|
_react2.default.createElement(
|
|
172
194
|
'div',
|
|
173
195
|
{ className: (0, _noImportant.css)(styles.play_and_stop), onClick: function onClick() {
|
|
@@ -177,7 +199,7 @@ var Player = function (_Component) {
|
|
|
177
199
|
),
|
|
178
200
|
_react2.default.createElement(_Audio2.default, { onChange: function onChange(state) {
|
|
179
201
|
return _this4.setState(_extends({}, state));
|
|
180
|
-
}, ref: 'audio', src:
|
|
202
|
+
}, ref: 'audio', src: src }),
|
|
181
203
|
_react2.default.createElement(
|
|
182
204
|
'div',
|
|
183
205
|
{ className: (0, _noImportant.css)(styles.timeline), ref: 'container' },
|
|
@@ -211,7 +233,10 @@ var Player = function (_Component) {
|
|
|
211
233
|
_react2.default.createElement(_reactInputRange2.default, { classNames: _volumeClassNames2.default, maxValue: 100, minValue: 0, value: this.state.volume, onChange: function onChange(c, v) {
|
|
212
234
|
return _this4.refs.audio.setVolume(v);
|
|
213
235
|
} })
|
|
214
|
-
)
|
|
236
|
+
),
|
|
237
|
+
_react2.default.createElement('div', { className: 'Close ' + (0, _noImportant.css)(styles.close), onClick: function onClick() {
|
|
238
|
+
return _this4.toggleVisible();
|
|
239
|
+
} })
|
|
215
240
|
);
|
|
216
241
|
}
|
|
217
242
|
}]);
|
package/player/styles/styles.js
CHANGED
|
@@ -60,5 +60,18 @@ exports.default = {
|
|
|
60
60
|
':hover': {
|
|
61
61
|
overflow: 'visible'
|
|
62
62
|
}
|
|
63
|
-
})
|
|
63
|
+
}),
|
|
64
|
+
close: {
|
|
65
|
+
cursor: 'pointer',
|
|
66
|
+
position: 'absolute',
|
|
67
|
+
top: 1,
|
|
68
|
+
right: 3,
|
|
69
|
+
':after': {
|
|
70
|
+
content: "'✖'",
|
|
71
|
+
color: '#e5e5e5'
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
hidden: {
|
|
75
|
+
display: 'none'
|
|
76
|
+
}
|
|
64
77
|
};
|
|
@@ -109,6 +109,7 @@ var DesktopAudioRecorder = function (_Component) {
|
|
|
109
109
|
key: 'record',
|
|
110
110
|
value: function record() {
|
|
111
111
|
this.setState({
|
|
112
|
+
recordedData: null,
|
|
112
113
|
isRecording: true
|
|
113
114
|
});
|
|
114
115
|
}
|
|
@@ -150,12 +151,37 @@ var DesktopAudioRecorder = function (_Component) {
|
|
|
150
151
|
value: function onMediaError(e) {
|
|
151
152
|
console.error('media error', e);
|
|
152
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
|
+
}
|
|
153
176
|
}, {
|
|
154
177
|
key: 'stopRecording',
|
|
155
178
|
value: function stopRecording() {
|
|
156
179
|
this.setState({
|
|
157
180
|
isRecording: false
|
|
158
181
|
});
|
|
182
|
+
|
|
183
|
+
// Update audio element with new file
|
|
184
|
+
this.updateAudioDom();
|
|
159
185
|
}
|
|
160
186
|
}]);
|
|
161
187
|
|
|
@@ -118,7 +118,6 @@ var DesktopRecorder = function (_Component) {
|
|
|
118
118
|
var recordedData = this.state.recordedData;
|
|
119
119
|
|
|
120
120
|
var mergedBuffer = (0, _audio.appendBuffer)(recordedData, audioBuffer);
|
|
121
|
-
console.log("mergedBuffer", mergedBuffer);
|
|
122
121
|
this.setState({
|
|
123
122
|
recordedData: mergedBuffer
|
|
124
123
|
});
|
package/stories/player.js
CHANGED
|
@@ -62,7 +62,7 @@ var PlayerExample = function (_Component) {
|
|
|
62
62
|
'http://lls-media-public.s3.amazonaws.com/upload/LeLivreScolaire/p15vcjbl4lvpl9l7g8ov8ammh1.mp3'
|
|
63
63
|
)
|
|
64
64
|
),
|
|
65
|
-
_react2.default.createElement(_player2.default, {
|
|
65
|
+
_react2.default.createElement(_player2.default, { src: this.state.url })
|
|
66
66
|
);
|
|
67
67
|
}
|
|
68
68
|
}]);
|
package/stories/recorder.js
CHANGED
|
@@ -22,8 +22,8 @@ var RecorderExample = function RecorderExample() {
|
|
|
22
22
|
return _react2.default.createElement(
|
|
23
23
|
'div',
|
|
24
24
|
null,
|
|
25
|
-
_react2.default.createElement(
|
|
26
|
-
_react2.default.createElement(
|
|
25
|
+
_react2.default.createElement(_recorder2.default, null),
|
|
26
|
+
_react2.default.createElement('audio', { controls: true })
|
|
27
27
|
);
|
|
28
28
|
};
|
|
29
29
|
|
package/utils/audio.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.convertBlobToaudioBuffer = exports.appendBuffer = exports.convertAudioBufferToWaveform = exports.getWaveform = undefined;
|
|
6
|
+
exports.audioBufferToWav = exports.convertBlobToaudioBuffer = exports.appendBuffer = exports.convertAudioBufferToWaveform = exports.getWaveform = undefined;
|
|
7
7
|
|
|
8
8
|
var _audioContext = require('./audioContext');
|
|
9
9
|
|
|
@@ -120,4 +120,93 @@ var convertBlobToaudioBuffer = exports.convertBlobToaudioBuffer = function conve
|
|
|
120
120
|
});
|
|
121
121
|
};
|
|
122
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
|
+
}
|
|
123
212
|
};
|