recording+playback+sending works correctly
This commit is contained in:
+14
-11
@@ -2650,9 +2650,14 @@ ul.tabbar li.active > a {
|
|||||||
border-radius: 1.5rem;
|
border-radius: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.audio canvas.visualiser {
|
.audio canvas {
|
||||||
width: 12rem;
|
width: 14rem;
|
||||||
height: 2.6rem;
|
height: 2.6rem;
|
||||||
|
margin-right: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.audio canvas.playback {
|
||||||
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.audio .duration {
|
.audio .duration {
|
||||||
@@ -2665,8 +2670,8 @@ ul.tabbar li.active > a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.audio-player .material-icons.large {
|
.audio-player .material-icons.large {
|
||||||
font-size: 2.5rem;
|
font-size: 2.4rem;
|
||||||
color: #009688;
|
color: #667575;
|
||||||
}
|
}
|
||||||
|
|
||||||
.audio-player .material-icons.disabled {
|
.audio-player .material-icons.disabled {
|
||||||
@@ -2674,16 +2679,16 @@ ul.tabbar li.active > a {
|
|||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.audio-player .visualiser {
|
.audio-player .playback {
|
||||||
width: 12rem;
|
width: 14rem;
|
||||||
height: 2.6rem;
|
height: 2.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.audio-player canvas.visualiser {
|
.audio-player canvas.playback {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.audio-player div.visualiser {
|
.audio-player div.playback {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -2692,9 +2697,7 @@ ul.tabbar li.active > a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.audio-player .timer {
|
.audio-player .timer {
|
||||||
font-size: small;
|
font-size: smaller;
|
||||||
float: right;
|
|
||||||
padding-right: 7.4rem;
|
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -12,13 +12,10 @@ const CANVAS_UPSCALING = 2.0;
|
|||||||
const LINE_WIDTH = 3 * CANVAS_UPSCALING;
|
const LINE_WIDTH = 3 * CANVAS_UPSCALING;
|
||||||
// Spacing between two visualization bars.
|
// Spacing between two visualization bars.
|
||||||
const SPACING = 2 * CANVAS_UPSCALING;
|
const SPACING = 2 * CANVAS_UPSCALING;
|
||||||
// Color of histogram bars (base color #009688).
|
// Color of histogram bars.
|
||||||
const BAR_COLOR = '#85c7c5';
|
const BAR_COLOR = '#bbb';
|
||||||
const BAR_COLOR_DARK = '#559695';
|
const BAR_COLOR_DARK = '#888';
|
||||||
const THUMB_COLOR = '#246867';
|
const THUMB_COLOR = '#666';
|
||||||
|
|
||||||
// Background color
|
|
||||||
const BKG_COLOR = '#fff';
|
|
||||||
// Minimum number of amplitude bars to draw.
|
// Minimum number of amplitude bars to draw.
|
||||||
const MIN_PREVIEW_LENGTH = 16;
|
const MIN_PREVIEW_LENGTH = 16;
|
||||||
|
|
||||||
@@ -36,6 +33,7 @@ export default class AudioPlayer extends React.PureComponent {
|
|||||||
playing: false,
|
playing: false,
|
||||||
currentTime: '0:00',
|
currentTime: '0:00',
|
||||||
duration: this.props.duration > 0 ? secondsToTime(this.props.duration / 1000) : '-:--',
|
duration: this.props.duration > 0 ? secondsToTime(this.props.duration / 1000) : '-:--',
|
||||||
|
longMin: this.props.duration >= 600000,
|
||||||
preview: preview
|
preview: preview
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -91,10 +89,12 @@ export default class AudioPlayer extends React.PureComponent {
|
|||||||
initAudio() {
|
initAudio() {
|
||||||
this.audioPlayer = new Audio(this.props.src);
|
this.audioPlayer = new Audio(this.props.src);
|
||||||
this.audioPlayer.oncanplay = _ => this.setState({canPlay: true});
|
this.audioPlayer.oncanplay = _ => this.setState({canPlay: true});
|
||||||
this.audioPlayer.ontimeupdate = _ => this.setState({currentTime: secondsToTime(this.audioPlayer.currentTime)});
|
this.audioPlayer.ontimeupdate = _ => this.setState({
|
||||||
|
currentTime: secondsToTime(this.audioPlayer.currentTime, this.state.longMin)
|
||||||
|
});
|
||||||
this.audioPlayer.onended = _ => {
|
this.audioPlayer.onended = _ => {
|
||||||
this.audioPlayer.currentTime = 0;
|
this.audioPlayer.currentTime = 0;
|
||||||
this.setState({playing: false, currentTime: secondsToTime(0)})
|
this.setState({playing: false, currentTime: secondsToTime(0, this.state.longMin)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ export default class AudioPlayer extends React.PureComponent {
|
|||||||
const rect = e.target.getBoundingClientRect();
|
const rect = e.target.getBoundingClientRect();
|
||||||
const offset = (e.clientX - rect.left) / this.effectiveWidth * CANVAS_UPSCALING;
|
const offset = (e.clientX - rect.left) / this.effectiveWidth * CANVAS_UPSCALING;
|
||||||
this.audioPlayer.currentTime = this.props.duration * offset / 1000;
|
this.audioPlayer.currentTime = this.props.duration * offset / 1000;
|
||||||
this.setState({currentTime: secondsToTime(this.audioPlayer.currentTime)});
|
this.setState({currentTime: secondsToTime(this.audioPlayer.currentTime, this.state.longMin)});
|
||||||
if (!this.state.playing && this.state.preview) {
|
if (!this.state.playing && this.state.preview) {
|
||||||
this.visualize();
|
this.visualize();
|
||||||
}
|
}
|
||||||
@@ -232,14 +232,15 @@ export default class AudioPlayer extends React.PureComponent {
|
|||||||
(this.props.short ? '' : ' large') +
|
(this.props.short ? '' : ' large') +
|
||||||
(this.state.canPlay ? '' : ' disabled');
|
(this.state.canPlay ? '' : ' disabled');
|
||||||
const play = (<a href="#" onClick={this.handlePlay} title="Play">
|
const play = (<a href="#" onClick={this.handlePlay} title="Play">
|
||||||
<i className={playClass}>{this.state.playing ? 'pause_circle' : 'play_circle'}</i>
|
<i className={playClass}>{this.state.playing ? 'pause_circle' :
|
||||||
|
(this.state.canPlay ? 'play_circle' : 'not_interested')}</i>
|
||||||
</a>);
|
</a>);
|
||||||
return (<div className="audio-player">{this.props.short ?
|
return (<div className="audio-player">{this.props.short ?
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
{this.state.preview ?
|
{this.state.preview ?
|
||||||
<canvas className="visualiser" ref={this.canvasRef} onClick={this.handleSeek} /> :
|
<canvas className="playback" ref={this.canvasRef} onClick={this.handleSeek} /> :
|
||||||
<div className="visualiser"> - </div>
|
<div className="playback"> - </div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{play}
|
{play}
|
||||||
@@ -249,8 +250,8 @@ export default class AudioPlayer extends React.PureComponent {
|
|||||||
{play}
|
{play}
|
||||||
<div>
|
<div>
|
||||||
{this.state.preview ?
|
{this.state.preview ?
|
||||||
<canvas className="visualiser" ref={this.canvasRef} onClick={this.handleSeek} /> :
|
<canvas className="playback" ref={this.canvasRef} onClick={this.handleSeek} /> :
|
||||||
<div className="visualiser">
|
<div className="playback">
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="preview_unavailable" defaultMessage="unavailable" description="Message shown when media preview is not available" />
|
id="preview_unavailable" defaultMessage="unavailable" description="Message shown when media preview is not available" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,24 +9,26 @@ import { secondsToTime } from '../lib/strformat';
|
|||||||
|
|
||||||
// FFT resolution.
|
// FFT resolution.
|
||||||
const BUFFER_SIZE = 256;
|
const BUFFER_SIZE = 256;
|
||||||
|
// Make canvas bigger than the element size to reduce blurring.
|
||||||
|
const CANVAS_UPSCALING = 2.0;
|
||||||
// Thickness of a visualization bar.
|
// Thickness of a visualization bar.
|
||||||
const LINE_WIDTH = 4;
|
const LINE_WIDTH = 3 * CANVAS_UPSCALING;
|
||||||
// Spacing between two visualization bars.
|
// Spacing between two visualization bars.
|
||||||
const SPACING = 2;
|
const SPACING = 2 * CANVAS_UPSCALING;
|
||||||
// Duration represented by one visualization bar.
|
// Duration represented by one visualization bar.
|
||||||
const MILLIS_PER_BAR = 100;
|
const MILLIS_PER_BAR = 100;
|
||||||
// Color of histogram bars
|
// Color of histogram bars
|
||||||
const BAR_COLOR = '#8fbed6';
|
const BAR_COLOR = '#bbb';
|
||||||
// Scaling for visualization bars.
|
// Vertical scaling for visualization bars.
|
||||||
const BAR_SCALE = 64.0;
|
const BAR_SCALE = 64.0;
|
||||||
// Background color
|
|
||||||
const BKG_COLOR = '#eeeeee';
|
|
||||||
// Minimum duration of a recording in milliseconds.
|
// Minimum duration of a recording in milliseconds.
|
||||||
const MIN_DURATION = 200;
|
const MIN_DURATION = 200;
|
||||||
// Maximum duration of a recording in milliseconds (10 min).
|
// Maximum duration of a recording in milliseconds (10 min).
|
||||||
const MAX_DURATION = 600000;
|
const MAX_DURATION = 600000;
|
||||||
// Number of bars in preview.
|
// Number of bars in preview.
|
||||||
const VISUALIZATION_BARS = 96;
|
const VISUALIZATION_BARS = 96;
|
||||||
|
// Maximum number of samples per bar.
|
||||||
|
const MAX_SAMPLES_PER_BAR = 10;
|
||||||
|
|
||||||
export default class AudioRecorder extends React.PureComponent {
|
export default class AudioRecorder extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -44,6 +46,7 @@ export default class AudioRecorder extends React.PureComponent {
|
|||||||
|
|
||||||
this.visualize = this.visualize.bind(this);
|
this.visualize = this.visualize.bind(this);
|
||||||
this.initMediaRecording = this.initMediaRecording.bind(this);
|
this.initMediaRecording = this.initMediaRecording.bind(this);
|
||||||
|
this.initCanvas = this.initCanvas.bind(this);
|
||||||
this.getRecording = this.getRecording.bind(this);
|
this.getRecording = this.getRecording.bind(this);
|
||||||
this.cleanUp = this.cleanUp.bind(this);
|
this.cleanUp = this.cleanUp.bind(this);
|
||||||
|
|
||||||
@@ -59,11 +62,6 @@ export default class AudioRecorder extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.canvasContext = this.canvasRef.current.getContext('2d');
|
|
||||||
this.canvasContext.lineCap = 'round';
|
|
||||||
// To reduce line blurring.
|
|
||||||
this.canvasContext.translate(0.5, 0.5);
|
|
||||||
|
|
||||||
this.stream = null;
|
this.stream = null;
|
||||||
this.mediaRecorder = null;
|
this.mediaRecorder = null;
|
||||||
this.audioContext = null;
|
this.audioContext = null;
|
||||||
@@ -82,13 +80,16 @@ export default class AudioRecorder extends React.PureComponent {
|
|||||||
|
|
||||||
// Draw amplitude of sound.
|
// Draw amplitude of sound.
|
||||||
visualize() {
|
visualize() {
|
||||||
|
this.initCanvas();
|
||||||
|
|
||||||
const pcmData = new Uint8Array(this.analyser.frequencyBinCount);
|
const pcmData = new Uint8Array(this.analyser.frequencyBinCount);
|
||||||
const width = this.canvasRef.current.width;
|
const width = this.canvasWidth;
|
||||||
const height = this.canvasRef.current.height;
|
const height = this.canvasHeight;
|
||||||
|
// Number of bars.
|
||||||
const viewLength = (width / (LINE_WIDTH + SPACING)) | 0;
|
const viewLength = (width / (LINE_WIDTH + SPACING)) | 0;
|
||||||
|
// Duration of audio which fits onto the screen.
|
||||||
const viewDuration = MILLIS_PER_BAR * viewLength;
|
const viewDuration = MILLIS_PER_BAR * viewLength;
|
||||||
|
|
||||||
this.canvasContext.fillStyle = BKG_COLOR;
|
|
||||||
this.canvasContext.lineWidth = LINE_WIDTH;
|
this.canvasContext.lineWidth = LINE_WIDTH;
|
||||||
this.canvasContext.strokeStyle = BAR_COLOR;
|
this.canvasContext.strokeStyle = BAR_COLOR;
|
||||||
|
|
||||||
@@ -144,7 +145,7 @@ export default class AudioRecorder extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clear canvas.
|
// Clear canvas.
|
||||||
this.canvasContext.fillRect(0, 0, width, height);
|
this.canvasContext.clearRect(0, 0, width, height);
|
||||||
|
|
||||||
// Draw amplitude bars.
|
// Draw amplitude bars.
|
||||||
this.canvasContext.beginPath();
|
this.canvasContext.beginPath();
|
||||||
@@ -202,6 +203,18 @@ export default class AudioRecorder extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initCanvas() {
|
||||||
|
this.canvasRef.current.width = this.canvasRef.current.offsetWidth * CANVAS_UPSCALING;
|
||||||
|
this.canvasRef.current.height = this.canvasRef.current.offsetHeight * CANVAS_UPSCALING;
|
||||||
|
|
||||||
|
this.canvasContext = this.canvasRef.current.getContext('2d');
|
||||||
|
this.canvasContext.lineCap = 'round';
|
||||||
|
// To reduce line blurring.
|
||||||
|
this.canvasContext.translate(0.5, 0.5);
|
||||||
|
this.canvasWidth = this.canvasRef.current.width;
|
||||||
|
this.canvasHeight = this.canvasRef.current.height;
|
||||||
|
}
|
||||||
|
|
||||||
initMediaRecording(stream) {
|
initMediaRecording(stream) {
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
this.mediaRecorder = new MediaRecorder(stream);
|
this.mediaRecorder = new MediaRecorder(stream);
|
||||||
@@ -260,16 +273,21 @@ export default class AudioRecorder extends React.PureComponent {
|
|||||||
const data = audio.getChannelData(0);
|
const data = audio.getChannelData(0);
|
||||||
// Number of amplitude bars in preview.
|
// Number of amplitude bars in preview.
|
||||||
const viewLength = Math.min(data.length, VISUALIZATION_BARS);
|
const viewLength = Math.min(data.length, VISUALIZATION_BARS);
|
||||||
// The number of samples in each bar. Limit the number of samples to something reasonable, no need to process all.
|
// The number of samples in each bar.
|
||||||
const spb = Math.min(100, (data.length / viewLength) | 0);
|
const totalSPB = (data.length / viewLength) | 0;
|
||||||
|
// Distance between samples: we are going to take just a fracton of samples.
|
||||||
|
const samplingRate = Math.max(1, (totalSPB / MAX_SAMPLES_PER_BAR) | 0);
|
||||||
|
|
||||||
let buffer = [];
|
let buffer = [];
|
||||||
let max = -1;
|
let max = -1;
|
||||||
for (let i = 0; i < viewLength; i++) {
|
for (let i = 0; i < viewLength; i++) {
|
||||||
let amplitude = 0;
|
let amplitude = 0;
|
||||||
for (let j = 0; j < spb; j++) {
|
let count = 0;
|
||||||
amplitude += data[spb * i + j] ** 2;
|
for (let j = 0; j < totalSPB; j += samplingRate) {
|
||||||
|
amplitude += data[totalSPB * i + j] ** 2;
|
||||||
|
count ++;
|
||||||
}
|
}
|
||||||
const val = Math.sqrt(amplitude / spb);
|
const val = Math.sqrt(amplitude / count);
|
||||||
buffer.push(val);
|
buffer.push(val);
|
||||||
max = Math.max(max, val);
|
max = Math.max(max, val);
|
||||||
}
|
}
|
||||||
@@ -293,7 +311,7 @@ export default class AudioRecorder extends React.PureComponent {
|
|||||||
<i className="material-icons">delete_outline</i>
|
<i className="material-icons">delete_outline</i>
|
||||||
</a>
|
</a>
|
||||||
{this.state.recording ?
|
{this.state.recording ?
|
||||||
<canvas className="visualiser" ref={this.canvasRef} />
|
<canvas ref={this.canvasRef} />
|
||||||
:
|
:
|
||||||
<AudioPlayer
|
<AudioPlayer
|
||||||
src={this.state.blobUrl}
|
src={this.state.blobUrl}
|
||||||
|
|||||||
+39
-28
@@ -9681,10 +9681,9 @@ __webpack_require__.r(__webpack_exports__);
|
|||||||
const CANVAS_UPSCALING = 2.0;
|
const CANVAS_UPSCALING = 2.0;
|
||||||
const LINE_WIDTH = 3 * CANVAS_UPSCALING;
|
const LINE_WIDTH = 3 * CANVAS_UPSCALING;
|
||||||
const SPACING = 2 * CANVAS_UPSCALING;
|
const SPACING = 2 * CANVAS_UPSCALING;
|
||||||
const BAR_COLOR = '#85c7c5';
|
const BAR_COLOR = '#bbb';
|
||||||
const BAR_COLOR_DARK = '#559695';
|
const BAR_COLOR_DARK = '#888';
|
||||||
const THUMB_COLOR = '#246867';
|
const THUMB_COLOR = '#666';
|
||||||
const BKG_COLOR = '#fff';
|
|
||||||
const MIN_PREVIEW_LENGTH = 16;
|
const MIN_PREVIEW_LENGTH = 16;
|
||||||
class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
|
class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -9700,6 +9699,7 @@ class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComp
|
|||||||
playing: false,
|
playing: false,
|
||||||
currentTime: '0:00',
|
currentTime: '0:00',
|
||||||
duration: this.props.duration > 0 ? (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.props.duration / 1000) : '-:--',
|
duration: this.props.duration > 0 ? (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.props.duration / 1000) : '-:--',
|
||||||
|
longMin: this.props.duration >= 600000,
|
||||||
preview: preview
|
preview: preview
|
||||||
};
|
};
|
||||||
this.initAudio = this.initAudio.bind(this);
|
this.initAudio = this.initAudio.bind(this);
|
||||||
@@ -9760,14 +9760,14 @@ class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComp
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.audioPlayer.ontimeupdate = _ => this.setState({
|
this.audioPlayer.ontimeupdate = _ => this.setState({
|
||||||
currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.audioPlayer.currentTime)
|
currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.audioPlayer.currentTime, this.state.longMin)
|
||||||
});
|
});
|
||||||
|
|
||||||
this.audioPlayer.onended = _ => {
|
this.audioPlayer.onended = _ => {
|
||||||
this.audioPlayer.currentTime = 0;
|
this.audioPlayer.currentTime = 0;
|
||||||
this.setState({
|
this.setState({
|
||||||
playing: false,
|
playing: false,
|
||||||
currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(0)
|
currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(0, this.state.longMin)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -9894,7 +9894,7 @@ class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComp
|
|||||||
const offset = (e.clientX - rect.left) / this.effectiveWidth * CANVAS_UPSCALING;
|
const offset = (e.clientX - rect.left) / this.effectiveWidth * CANVAS_UPSCALING;
|
||||||
this.audioPlayer.currentTime = this.props.duration * offset / 1000;
|
this.audioPlayer.currentTime = this.props.duration * offset / 1000;
|
||||||
this.setState({
|
this.setState({
|
||||||
currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.audioPlayer.currentTime)
|
currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.audioPlayer.currentTime, this.state.longMin)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!this.state.playing && this.state.preview) {
|
if (!this.state.playing && this.state.preview) {
|
||||||
@@ -9911,21 +9911,21 @@ class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComp
|
|||||||
title: "Play"
|
title: "Play"
|
||||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
className: playClass
|
className: playClass
|
||||||
}, this.state.playing ? 'pause_circle' : 'play_circle'));
|
}, this.state.playing ? 'pause_circle' : this.state.canPlay ? 'play_circle' : 'not_interested'));
|
||||||
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||||
className: "audio-player"
|
className: "audio-player"
|
||||||
}, this.props.short ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.state.preview ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("canvas", {
|
}, this.props.short ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.state.preview ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("canvas", {
|
||||||
className: "visualiser",
|
className: "playback",
|
||||||
ref: this.canvasRef,
|
ref: this.canvasRef,
|
||||||
onClick: this.handleSeek
|
onClick: this.handleSeek
|
||||||
}) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
}) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||||
className: "visualiser"
|
className: "playback"
|
||||||
}, " - ")), play) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, play, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.state.preview ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("canvas", {
|
}, " - ")), play) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, play, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.state.preview ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("canvas", {
|
||||||
className: "visualiser",
|
className: "playback",
|
||||||
ref: this.canvasRef,
|
ref: this.canvasRef,
|
||||||
onClick: this.handleSeek
|
onClick: this.handleSeek
|
||||||
}) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
}) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||||
className: "visualiser"
|
className: "playback"
|
||||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
|
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
|
||||||
id: "preview_unavailable",
|
id: "preview_unavailable",
|
||||||
defaultMessage: [{
|
defaultMessage: [{
|
||||||
@@ -9962,15 +9962,16 @@ __webpack_require__.r(__webpack_exports__);
|
|||||||
|
|
||||||
|
|
||||||
const BUFFER_SIZE = 256;
|
const BUFFER_SIZE = 256;
|
||||||
const LINE_WIDTH = 4;
|
const CANVAS_UPSCALING = 2.0;
|
||||||
const SPACING = 2;
|
const LINE_WIDTH = 3 * CANVAS_UPSCALING;
|
||||||
|
const SPACING = 2 * CANVAS_UPSCALING;
|
||||||
const MILLIS_PER_BAR = 100;
|
const MILLIS_PER_BAR = 100;
|
||||||
const BAR_COLOR = '#8fbed6';
|
const BAR_COLOR = '#bbb';
|
||||||
const BAR_SCALE = 64.0;
|
const BAR_SCALE = 64.0;
|
||||||
const BKG_COLOR = '#eeeeee';
|
|
||||||
const MIN_DURATION = 200;
|
const MIN_DURATION = 200;
|
||||||
const MAX_DURATION = 600000;
|
const MAX_DURATION = 600000;
|
||||||
const VISUALIZATION_BARS = 96;
|
const VISUALIZATION_BARS = 96;
|
||||||
|
const MAX_SAMPLES_PER_BAR = 10;
|
||||||
class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
|
class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -9985,6 +9986,7 @@ class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
|
|||||||
};
|
};
|
||||||
this.visualize = this.visualize.bind(this);
|
this.visualize = this.visualize.bind(this);
|
||||||
this.initMediaRecording = this.initMediaRecording.bind(this);
|
this.initMediaRecording = this.initMediaRecording.bind(this);
|
||||||
|
this.initCanvas = this.initCanvas.bind(this);
|
||||||
this.getRecording = this.getRecording.bind(this);
|
this.getRecording = this.getRecording.bind(this);
|
||||||
this.cleanUp = this.cleanUp.bind(this);
|
this.cleanUp = this.cleanUp.bind(this);
|
||||||
this.handleResume = this.handleResume.bind(this);
|
this.handleResume = this.handleResume.bind(this);
|
||||||
@@ -9998,9 +10000,6 @@ class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.canvasContext = this.canvasRef.current.getContext('2d');
|
|
||||||
this.canvasContext.lineCap = 'round';
|
|
||||||
this.canvasContext.translate(0.5, 0.5);
|
|
||||||
this.stream = null;
|
this.stream = null;
|
||||||
this.mediaRecorder = null;
|
this.mediaRecorder = null;
|
||||||
this.audioContext = null;
|
this.audioContext = null;
|
||||||
@@ -10019,12 +10018,12 @@ class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
visualize() {
|
visualize() {
|
||||||
|
this.initCanvas();
|
||||||
const pcmData = new Uint8Array(this.analyser.frequencyBinCount);
|
const pcmData = new Uint8Array(this.analyser.frequencyBinCount);
|
||||||
const width = this.canvasRef.current.width;
|
const width = this.canvasWidth;
|
||||||
const height = this.canvasRef.current.height;
|
const height = this.canvasHeight;
|
||||||
const viewLength = width / (LINE_WIDTH + SPACING) | 0;
|
const viewLength = width / (LINE_WIDTH + SPACING) | 0;
|
||||||
const viewDuration = MILLIS_PER_BAR * viewLength;
|
const viewDuration = MILLIS_PER_BAR * viewLength;
|
||||||
this.canvasContext.fillStyle = BKG_COLOR;
|
|
||||||
this.canvasContext.lineWidth = LINE_WIDTH;
|
this.canvasContext.lineWidth = LINE_WIDTH;
|
||||||
this.canvasContext.strokeStyle = BAR_COLOR;
|
this.canvasContext.strokeStyle = BAR_COLOR;
|
||||||
let prevBarCount = 0;
|
let prevBarCount = 0;
|
||||||
@@ -10076,7 +10075,7 @@ class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.canvasContext.fillRect(0, 0, width, height);
|
this.canvasContext.clearRect(0, 0, width, height);
|
||||||
this.canvasContext.beginPath();
|
this.canvasContext.beginPath();
|
||||||
|
|
||||||
for (let i = 0; i < this.viewBuffer.length; i++) {
|
for (let i = 0; i < this.viewBuffer.length; i++) {
|
||||||
@@ -10142,6 +10141,16 @@ class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initCanvas() {
|
||||||
|
this.canvasRef.current.width = this.canvasRef.current.offsetWidth * CANVAS_UPSCALING;
|
||||||
|
this.canvasRef.current.height = this.canvasRef.current.offsetHeight * CANVAS_UPSCALING;
|
||||||
|
this.canvasContext = this.canvasRef.current.getContext('2d');
|
||||||
|
this.canvasContext.lineCap = 'round';
|
||||||
|
this.canvasContext.translate(0.5, 0.5);
|
||||||
|
this.canvasWidth = this.canvasRef.current.width;
|
||||||
|
this.canvasHeight = this.canvasRef.current.height;
|
||||||
|
}
|
||||||
|
|
||||||
initMediaRecording(stream) {
|
initMediaRecording(stream) {
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
this.mediaRecorder = new MediaRecorder(stream);
|
this.mediaRecorder = new MediaRecorder(stream);
|
||||||
@@ -10198,18 +10207,21 @@ class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
|
|||||||
createPreview(audio) {
|
createPreview(audio) {
|
||||||
const data = audio.getChannelData(0);
|
const data = audio.getChannelData(0);
|
||||||
const viewLength = Math.min(data.length, VISUALIZATION_BARS);
|
const viewLength = Math.min(data.length, VISUALIZATION_BARS);
|
||||||
const spb = Math.min(100, data.length / viewLength | 0);
|
const totalSPB = data.length / viewLength | 0;
|
||||||
|
const samplingRate = Math.max(1, totalSPB / MAX_SAMPLES_PER_BAR | 0);
|
||||||
let buffer = [];
|
let buffer = [];
|
||||||
let max = -1;
|
let max = -1;
|
||||||
|
|
||||||
for (let i = 0; i < viewLength; i++) {
|
for (let i = 0; i < viewLength; i++) {
|
||||||
let amplitude = 0;
|
let amplitude = 0;
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
for (let j = 0; j < spb; j++) {
|
for (let j = 0; j < totalSPB; j += samplingRate) {
|
||||||
amplitude += data[spb * i + j] ** 2;
|
amplitude += data[totalSPB * i + j] ** 2;
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
const val = Math.sqrt(amplitude / spb);
|
const val = Math.sqrt(amplitude / count);
|
||||||
buffer.push(val);
|
buffer.push(val);
|
||||||
max = Math.max(max, val);
|
max = Math.max(max, val);
|
||||||
}
|
}
|
||||||
@@ -10237,7 +10249,6 @@ class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
|
|||||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
className: "material-icons"
|
className: "material-icons"
|
||||||
}, "delete_outline")), this.state.recording ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("canvas", {
|
}, "delete_outline")), this.state.recording ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("canvas", {
|
||||||
className: "visualiser",
|
|
||||||
ref: this.canvasRef
|
ref: this.canvasRef
|
||||||
}) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_audio_player_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], {
|
}) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_audio_player_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], {
|
||||||
src: this.state.blobUrl,
|
src: this.state.blobUrl,
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user