![]()
+
\ No newline at end of file
diff --git a/src/components/sound-editor/icon--copy.svg b/src/components/sound-editor/icon--copy.svg
new file mode 100644
index 000000000..7bac62c1b
--- /dev/null
+++ b/src/components/sound-editor/icon--copy.svg
@@ -0,0 +1,14 @@
+
+
\ No newline at end of file
diff --git a/src/components/sound-editor/icon--delete.svg b/src/components/sound-editor/icon--delete.svg
new file mode 100644
index 000000000..8f662201e
--- /dev/null
+++ b/src/components/sound-editor/icon--delete.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/src/components/sound-editor/icon--fade-in.svg b/src/components/sound-editor/icon--fade-in.svg
new file mode 100644
index 000000000..6c7487584
--- /dev/null
+++ b/src/components/sound-editor/icon--fade-in.svg
@@ -0,0 +1,14 @@
+
+
\ No newline at end of file
diff --git a/src/components/sound-editor/icon--fade-out.svg b/src/components/sound-editor/icon--fade-out.svg
new file mode 100644
index 000000000..96e8d6244
--- /dev/null
+++ b/src/components/sound-editor/icon--fade-out.svg
@@ -0,0 +1,14 @@
+
+
\ No newline at end of file
diff --git a/src/components/sound-editor/icon--lounder.svg b/src/components/sound-editor/icon--lounder.svg
deleted file mode 100644
index a1022b4b8..000000000
--- a/src/components/sound-editor/icon--lounder.svg
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
\ No newline at end of file
diff --git a/src/components/sound-editor/icon--mute.svg b/src/components/sound-editor/icon--mute.svg
new file mode 100644
index 000000000..6cdd71d4d
--- /dev/null
+++ b/src/components/sound-editor/icon--mute.svg
@@ -0,0 +1,9 @@
+
+
diff --git a/src/components/sound-editor/icon--paste.svg b/src/components/sound-editor/icon--paste.svg
new file mode 100644
index 000000000..53ca104c1
--- /dev/null
+++ b/src/components/sound-editor/icon--paste.svg
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/src/components/sound-editor/icon--play.svg b/src/components/sound-editor/icon--play.svg
new file mode 100644
index 000000000..817a2cab9
--- /dev/null
+++ b/src/components/sound-editor/icon--play.svg
@@ -0,0 +1,20 @@
+
+
diff --git a/src/components/sound-editor/icon--stop.svg b/src/components/sound-editor/icon--stop.svg
new file mode 100644
index 000000000..c960e66c3
--- /dev/null
+++ b/src/components/sound-editor/icon--stop.svg
@@ -0,0 +1,21 @@
+
+
diff --git a/src/components/sound-editor/sound-editor.css b/src/components/sound-editor/sound-editor.css
index 279875fc8..7a791e6ab 100644
--- a/src/components/sound-editor/sound-editor.css
+++ b/src/components/sound-editor/sound-editor.css
@@ -63,7 +63,9 @@
background: hsla(300, 53%, 60%, 0.15);
border: 1px solid $ui-black-transparent;
border-radius: 5px;
- padding: 3px;
+
+ margin-top: 20px;
+ margin-bottom: 20px;
}
$border-radius: 0.25rem;
@@ -93,9 +95,9 @@ $border-radius: 0.25rem;
height: 3rem;
width: 3rem;
outline: none;
- background: white;
+ background: $motion-primary;
border-radius: 100%;
- border: 1px solid $ui-black-transparent;
+ border: 4px solid $ui-white-dim;
cursor: pointer;
padding: 0.75rem;
user-select: none;
@@ -118,6 +120,7 @@ $border-radius: 0.25rem;
color: $text-primary;
font-size: 0.625rem;
user-select: none;
+
}
[dir="ltr"] .trim-button {
@@ -130,7 +133,6 @@ $border-radius: 0.25rem;
.trim-button > img {
width: 1.25rem;
- margin-bottom: -0.375rem;
}
.effect-button {
@@ -138,6 +140,7 @@ $border-radius: 0.25rem;
color: $text-primary;
font-size: 0.625rem;
user-select: none;
+ padding: 0.25rem 0;
}
.effect-button + .effect-button {
@@ -150,12 +153,25 @@ $border-radius: 0.25rem;
margin-bottom: -0.375rem;
}
-/* mirror the louder/softer speaker icons when rtl */
-[dir="rtl"] .effect-button:nth-of-type(6) img {
- transform: scaleX(-1);
+.tool-button {
+ flex-basis: 60px;
+ color: $text-primary;
+ font-size: 0.625rem;
+ user-select: none;
+ padding: 0.25rem 0;
}
-[dir="rtl"] .effect-button:nth-of-type(7) img {
+.tool-button + .tool-button {
+ margin: 0;
+}
+
+.tool-button img {
+ width: 4rem;
+ height: 1.5rem;
+ margin-bottom: -0.375rem;
+}
+
+[dir="rtl"] .flip-in-rtl img {
transform: scaleX(-1);
}
@@ -167,6 +183,10 @@ $border-radius: 0.25rem;
margin-right: 1rem;
}
+.button-group {
+ display: flex;
+}
+
.button-group .button {
border-radius: 0;
}
diff --git a/src/components/sound-editor/sound-editor.jsx b/src/components/sound-editor/sound-editor.jsx
index f97338e06..84f56d08b 100644
--- a/src/components/sound-editor/sound-editor.jsx
+++ b/src/components/sound-editor/sound-editor.jsx
@@ -8,24 +8,29 @@ import Label from '../forms/label.jsx';
import Input from '../forms/input.jsx';
import BufferedInputHOC from '../forms/buffered-input-hoc.jsx';
-import AudioTrimmer from '../../containers/audio-trimmer.jsx';
+import AudioSelector from '../../containers/audio-selector.jsx';
import IconButton from '../icon-button/icon-button.jsx';
import styles from './sound-editor.css';
-import playIcon from '../record-modal/icon--play.svg';
-import stopIcon from '../record-modal/icon--stop-playback.svg';
-import trimIcon from './icon--trim.svg';
-import trimConfirmIcon from './icon--trim-confirm.svg';
+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 echoIcon from './icon--echo.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 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);
@@ -45,10 +50,25 @@ const messages = defineMessages({
description: 'Title of the button to stop the sound',
defaultMessage: 'Stop'
},
- trim: {
- id: 'gui.soundEditor.trim',
- description: 'Title of the button to start trimminging the sound',
- defaultMessage: 'Trim'
+ 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',
@@ -99,11 +119,30 @@ const messages = defineMessages({
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 SoundEditor = props => (
-
+
+
+
+
+
+
- ) : (
-
- )}
- onClick={props.onActivateTrim}
+ className={styles.toolButton}
+ disabled={props.trimStart === null}
+ img={deleteIcon}
+ title={props.intl.formatMessage(messages.delete)}
+ onClick={props.onDelete}
/>
@@ -161,12 +216,13 @@ const SoundEditor = props => (
height={160}
width={600}
/>
-
@@ -209,61 +265,81 @@ const SoundEditor = props => (
onClick={props.onSlower}
/>
}
- onClick={props.onEcho}
- />
-
}
- onClick={props.onRobot}
- />
-
}
onClick={props.onLouder}
/>
}
onClick={props.onSofter}
/>
+
}
+ onClick={props.onMute}
+ />
+
}
+ onClick={props.onFadeIn}
+ />
+
}
+ onClick={props.onFadeOut}
+ />
}
onClick={props.onReverse}
/>
+
}
+ onClick={props.onRobot}
+ />
);
SoundEditor.propTypes = {
+ canPaste: PropTypes.bool.isRequired,
canRedo: PropTypes.bool.isRequired,
canUndo: PropTypes.bool.isRequired,
chunkLevels: PropTypes.arrayOf(PropTypes.number).isRequired,
intl: intlShape,
name: PropTypes.string.isRequired,
- onActivateTrim: PropTypes.func,
onChangeName: PropTypes.func.isRequired,
+ onContainerClick: PropTypes.func.isRequired,
+ onCopy: PropTypes.func.isRequired,
+ onCopyToNew: PropTypes.func.isRequired,
+ onDelete: PropTypes.func,
onEcho: PropTypes.func.isRequired,
+ onFadeIn: PropTypes.func.isRequired,
+ onFadeOut: PropTypes.func.isRequired,
onFaster: 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,
- onSetTrimEnd: PropTypes.func,
- onSetTrimStart: PropTypes.func,
+ 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,
trimEnd: PropTypes.number,
trimStart: PropTypes.number
};
diff --git a/src/components/waveform/waveform.jsx b/src/components/waveform/waveform.jsx
index 48a0a4935..3c7b4d26b 100644
--- a/src/components/waveform/waveform.jsx
+++ b/src/components/waveform/waveform.jsx
@@ -19,17 +19,21 @@ class Waveform extends React.PureComponent {
// composite time when animating the playhead
const takeEveryN = Math.ceil(data.length / width);
- const filteredData = takeEveryN === 1 ? data :
+ const filteredData = takeEveryN === 1 ? data.slice(0) :
data.filter((_, i) => i % takeEveryN === 0);
- const cappedData = [0, ...filteredData, 0];
+ // Need at least two points to render waveform.
+ if (filteredData.length === 1) {
+ filteredData.push(filteredData[0]);
+ }
+ const maxIndex = filteredData.length - 1;
const points = [
- ...cappedData.map((v, i) =>
- [width * i / cappedData.length, height * v / 2]
+ ...filteredData.map((v, i) =>
+ [width * (i / maxIndex), height * v / 2]
),
- ...cappedData.reverse().map((v, i) =>
- [width * (cappedData.length - i - 1) / cappedData.length, -height * v / 2]
+ ...filteredData.reverse().map((v, i) =>
+ [width * (1 - (i / maxIndex)), -height * v / 2]
)
];
const pathComponents = points.map(([x, y], i) => {
@@ -40,15 +44,8 @@ class Waveform extends React.PureComponent {
return (