import PropTypes from 'prop-types'; import React from 'react'; import classNames from 'classnames'; import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-intl'; import Waveform from '../waveform/waveform.jsx'; import Label from '../forms/label.jsx'; import Input from '../forms/input.jsx'; import BufferedInputHOC from '../forms/buffered-input-hoc.jsx'; import AudioSelector from '../../containers/audio-selector.jsx'; import IconButton from '../icon-button/icon-button.jsx'; import {SOUND_BYTE_LIMIT} from '../../lib/audio/audio-util.js'; import styles from './sound-editor.css'; import playIcon from './icon--play.svg'; import stopIcon from './icon--stop.svg'; import redoIcon from './icon--redo.svg'; import undoIcon from './icon--undo.svg'; import modifyIcon from './icon--modify.svg'; import fasterIcon from './icon--faster.svg'; import slowerIcon from './icon--slower.svg'; import louderIcon from './icon--louder.svg'; import softerIcon from './icon--softer.svg'; import robotIcon from './icon--robot.svg'; import echoIcon from './icon--echo.svg'; import highpassIcon from './icon--highpass.svg'; import lowpassIcon from './icon--lowpass.svg'; import reverseIcon from './icon--reverse.svg'; import fadeOutIcon from './icon--fade-out.svg'; import fadeInIcon from './icon--fade-in.svg'; import muteIcon from './icon--mute.svg'; import deleteIcon from './icon--delete.svg'; import copyIcon from './icon--copy.svg'; import pasteIcon from './icon--paste.svg'; import copyToNewIcon from './icon--copy-to-new.svg'; const BufferedInput = BufferedInputHOC(Input); const messages = defineMessages({ sound: { id: 'gui.soundEditor.sound', description: 'Label for the name of the sound', defaultMessage: 'Sound' }, play: { id: 'gui.soundEditor.play', description: 'Title of the button to start playing the sound', defaultMessage: 'Play' }, stop: { id: 'gui.soundEditor.stop', description: 'Title of the button to stop the sound', defaultMessage: 'Stop' }, copy: { id: 'gui.soundEditor.copy', description: 'Title of the button to copy the sound', defaultMessage: 'Copy' }, paste: { id: 'gui.soundEditor.paste', description: 'Title of the button to paste the sound', defaultMessage: 'Paste' }, copyToNew: { id: 'gui.soundEditor.copyToNew', description: 'Title of the button to copy the selection into a new sound', defaultMessage: 'Copy to New' }, delete: { id: 'gui.soundEditor.delete', description: 'Title of the button to delete the sound', defaultMessage: 'Delete' }, save: { id: 'gui.soundEditor.save', description: 'Title of the button to save trimmed sound', defaultMessage: 'Save' }, undo: { id: 'gui.soundEditor.undo', description: 'Title of the button to undo', defaultMessage: 'Undo' }, redo: { id: 'gui.soundEditor.redo', description: 'Title of the button to redo', defaultMessage: 'Redo' }, faster: { id: 'gui.soundEditor.faster', description: 'Title of the button to apply the faster effect', defaultMessage: 'Faster' }, slower: { id: 'gui.soundEditor.slower', description: 'Title of the button to apply the slower effect', defaultMessage: 'Slower' }, echo: { id: 'gui.soundEditor.echo', description: 'Title of the button to apply the echo effect', defaultMessage: 'Echo' }, robot: { id: 'gui.soundEditor.robot', description: 'Title of the button to apply the robot effect', defaultMessage: 'Robot' }, louder: { id: 'gui.soundEditor.louder', description: 'Title of the button to apply the louder effect', defaultMessage: 'Louder' }, softer: { id: 'gui.soundEditor.softer', description: 'Title of the button to apply thr.softer effect', defaultMessage: 'Softer' }, reverse: { id: 'gui.soundEditor.reverse', description: 'Title of the button to apply the reverse effect', defaultMessage: 'Reverse' }, fadeOut: { id: 'gui.soundEditor.fadeOut', description: 'Title of the button to apply the fade out effect', defaultMessage: 'Fade out' }, fadeIn: { id: 'gui.soundEditor.fadeIn', description: 'Title of the button to apply the fade in effect', defaultMessage: 'Fade in' }, mute: { id: 'gui.soundEditor.mute', description: 'Title of the button to apply the mute effect', defaultMessage: 'Mute' } }); const formatTime = timeSeconds => { const minutes = (Math.floor(timeSeconds / 60)) .toString() .padStart(2, '0'); const seconds = (timeSeconds % 60) .toFixed(2) .padStart(5, '0'); return `${minutes}:${seconds}`; }; const formatDuration = (playheadPercent, trimStartPercent, trimEndPercent, durationSeconds) => { // If no selection, the trim is the entire sound. trimStartPercent = trimStartPercent === null ? 0 : trimStartPercent; trimEndPercent = trimEndPercent === null ? 1 : trimEndPercent; // If the playhead doesn't exist, assume it's at the start of the selection. playheadPercent = playheadPercent === null ? trimStartPercent : playheadPercent; // If selection has zero length, treat it as the entire sound being selected. // This happens when the user first clicks to start making a selection. const trimSize = (trimEndPercent - trimStartPercent) || 1; const trimDuration = trimSize * durationSeconds; const progressInTrim = (playheadPercent - trimStartPercent) / trimSize; const currentTime = progressInTrim * trimDuration; return `${formatTime(currentTime)} / ${formatTime(trimDuration)}`; }; const formatSoundSize = bytes => { if (bytes > 1000 * 1000) { return `${(bytes / 1000 / 1000).toFixed(2)}MB`; } return `${(bytes / 1000).toFixed(2)}KB`; }; const SoundEditor = props => (