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 { ReactComponent as PlayIcon } from './icon--play.svg'; import { ReactComponent as StopIcon } from './icon--stop.svg'; import { ReactComponent as RedoIcon } from './icon--redo.svg'; import { ReactComponent as UndoIcon } from './icon--undo.svg'; import { ReactComponent as ModifyIcon } from './icon--modify.svg'; import { ReactComponent as FormatIcon } from './icon--format.svg'; import { ReactComponent as FasterIcon } from './icon--faster.svg'; import { ReactComponent as SlowerIcon } from './icon--slower.svg'; import { ReactComponent as LouderIcon } from './icon--louder.svg'; import { ReactComponent as SofterIcon } from './icon--softer.svg'; import { ReactComponent as RobotIcon } from './icon--robot.svg'; import { ReactComponent as EchoIcon } from './icon--echo.svg'; import { ReactComponent as HighpassIcon } from './icon--highpass.svg'; import { ReactComponent as LowpassIcon } from './icon--lowpass.svg'; import { ReactComponent as ReverseIcon } from './icon--reverse.svg'; import { ReactComponent as FadeOutIcon } from './icon--fade-out.svg'; import { ReactComponent as FadeInIcon } from './icon--fade-in.svg'; import { ReactComponent as MuteIcon } from './icon--mute.svg'; import { ReactComponent as DeleteIcon } from './icon--delete.svg'; import { ReactComponent as CopyIcon } from './icon--copy.svg'; import { ReactComponent as PasteIcon } from './icon--paste.svg'; import { ReactComponent as CopyToNewIcon } from './icon--copy-to-new.svg'; const BufferedInput = BufferedInputHOC(Input); const messages = defineMessages({ modify: { id: 'gui.soundEditor.modify', description: 'Title of the button to modify the sound', defaultMessage: 'Modify' }, lowpass: { id: 'gui.soundEditor.lowpass', defaultMessage: 'Low pass' }, highpass: { id: 'gui.soundEditor.highpass', defaultMessage: 'High pass' }, format: { id: 'gui.soundEditor.format', defaultMessage: 'Format' }, 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) => { trimStartPercent = trimStartPercent === null ? 0 : trimStartPercent; trimEndPercent = trimEndPercent === null ? 1 : trimEndPercent; playheadPercent = playheadPercent === null ? trimStartPercent : playheadPercent; 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 => (
} title={props.intl.formatMessage(messages.copy)} onClick={props.onCopy} /> } title={props.intl.formatMessage(messages.paste)} onClick={props.onPaste} /> } title={props.intl.formatMessage(messages.copyToNew)} onClick={props.onCopyToNew} />
} title={props.intl.formatMessage(messages.delete)} onClick={props.onDelete} />
{props.playhead ? ( ) : ( )}
} title={} onClick={props.onModifySound} /> } title={} onClick={props.onFaster} /> } title={} onClick={props.onSlower} /> } title={} onClick={props.onLouder} /> } title={} onClick={props.onSofter} /> } title={} onClick={props.onMute} /> } title={} onClick={props.onFadeIn} /> } title={} onClick={props.onFadeOut} /> } title={} onClick={props.onReverse} /> } title={} onClick={props.onRobot} /> } title={} onClick={props.onEcho} /> } title={} onClick={props.onLowPass} /> } title={} onClick={props.onHighPass} /> } title={} onClick={props.onFormatSound} />
{formatDuration(props.playhead, props.trimStart, props.trimEnd, props.duration)}
{props.sampleRate} {'Hz '} {`${String(props.dataFormat).toUpperCase()} `} {props.isStereo ? ( ) : ( )} {` (${formatSoundSize(props.size)})`}
{props.size >= SOUND_BYTE_LIMIT && (
)} {(props.dataFormat === "mp3" || props.dataFormat === "ogg" || props.dataFormat === "flac") && (
)} {(props.dataFormat === "ogg") && (
)} {props.isStereo && (
)}
); SoundEditor.propTypes = { isStereo: PropTypes.bool.isRequired, duration: PropTypes.number.isRequired, dataFormat: PropTypes.number.isRequired, size: PropTypes.bool.isRequired, sampleRate: PropTypes.number.isRequired, canPaste: PropTypes.bool.isRequired, canRedo: PropTypes.bool.isRequired, canUndo: PropTypes.bool.isRequired, chunkLevels: PropTypes.arrayOf(PropTypes.number).isRequired, intl: intlShape, name: PropTypes.string.isRequired, onChangeName: PropTypes.func.isRequired, onContainerClick: PropTypes.func.isRequired, onCopy: PropTypes.func.isRequired, onCopyToNew: PropTypes.func.isRequired, onDelete: PropTypes.func, onEcho: PropTypes.func.isRequired, onLowPass: PropTypes.func.isRequired, onHighPass: PropTypes.func.isRequired, onFadeIn: PropTypes.func.isRequired, onFadeOut: PropTypes.func.isRequired, onFaster: PropTypes.func.isRequired, onModifySound: PropTypes.func.isRequired, onFormatSound: PropTypes.func.isRequired, onLouder: PropTypes.func.isRequired, onMute: PropTypes.func.isRequired, onPaste: PropTypes.func.isRequired, onPlay: PropTypes.func.isRequired, onRedo: PropTypes.func.isRequired, onReverse: PropTypes.func.isRequired, onRobot: PropTypes.func.isRequired, onSetTrim: PropTypes.func, onSlower: PropTypes.func.isRequired, onSofter: PropTypes.func.isRequired, onStop: PropTypes.func.isRequired, onUndo: PropTypes.func.isRequired, playhead: PropTypes.number, setRef: PropTypes.func, tooLoud: PropTypes.bool.isRequired, trimEnd: PropTypes.number, trimStart: PropTypes.number }; export default injectIntl(SoundEditor);