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..6bd9e6974
--- /dev/null
+++ b/src/components/sound-editor/icon--fade-in.svg
@@ -0,0 +1,34 @@
+
+
\ 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..d6704bc0e
--- /dev/null
+++ b/src/components/sound-editor/icon--fade-out.svg
@@ -0,0 +1,34 @@
+
+
\ 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..1fcbbd559
--- /dev/null
+++ b/src/components/sound-editor/icon--mute.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/src/components/sound-editor/sound-editor.jsx b/src/components/sound-editor/sound-editor.jsx
index 57fc2149e..cbd731f14 100644
--- a/src/components/sound-editor/sound-editor.jsx
+++ b/src/components/sound-editor/sound-editor.jsx
@@ -26,6 +26,9 @@ 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';
const BufferedInput = BufferedInputHOC(Input);
@@ -99,6 +102,21 @@ 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'
}
});
@@ -237,12 +255,30 @@ const SoundEditor = props => (
title={}
onClick={props.onSofter}
/>
+ }
+ onClick={props.onMute}
+ />
}
onClick={props.onReverse}
/>
+ }
+ onClick={props.onFadeOut}
+ />
+ }
+ onClick={props.onFadeIn}
+ />
);
@@ -257,8 +293,11 @@ SoundEditor.propTypes = {
onChangeName: PropTypes.func.isRequired,
onContainerClick: PropTypes.func.isRequired,
onEcho: PropTypes.func.isRequired,
+ onFadeIn: PropTypes.func.isRequired,
+ onFadeOut: PropTypes.func.isRequired,
onFaster: PropTypes.func.isRequired,
onLouder: PropTypes.func.isRequired,
+ onMute: PropTypes.func.isRequired,
onPlay: PropTypes.func.isRequired,
onRedo: PropTypes.func.isRequired,
onReverse: PropTypes.func.isRequired,
diff --git a/src/containers/sound-editor.jsx b/src/containers/sound-editor.jsx
index 67ba3a1ae..24c0758d3 100644
--- a/src/containers/sound-editor.jsx
+++ b/src/containers/sound-editor.jsx
@@ -227,8 +227,11 @@ class SoundEditor extends React.Component {
onContainerClick={this.handleContainerClick}
onDelete={this.handleDelete}
onEcho={this.effectFactory(effectTypes.ECHO)}
+ onFadeIn={this.effectFactory(effectTypes.FADEIN)}
+ onFadeOut={this.effectFactory(effectTypes.FADEOUT)}
onFaster={this.effectFactory(effectTypes.FASTER)}
onLouder={this.effectFactory(effectTypes.LOUDER)}
+ onMute={this.effectFactory(effectTypes.MUTE)}
onPlay={this.handlePlay}
onRedo={this.handleRedo}
onReverse={this.effectFactory(effectTypes.REVERSE)}
diff --git a/src/lib/audio/audio-effects.js b/src/lib/audio/audio-effects.js
index 5dae9cf13..b6b78f5b0 100644
--- a/src/lib/audio/audio-effects.js
+++ b/src/lib/audio/audio-effects.js
@@ -1,6 +1,8 @@
import EchoEffect from './effects/echo-effect.js';
import RobotEffect from './effects/robot-effect.js';
import VolumeEffect from './effects/volume-effect.js';
+import FadeEffect from './effects/fade-effect.js';
+import MuteEffect from './effects/mute-effect.js';
const effectTypes = {
ROBOT: 'robot',
@@ -9,7 +11,10 @@ const effectTypes = {
SOFTER: 'lower',
FASTER: 'faster',
SLOWER: 'slower',
- ECHO: 'echo'
+ ECHO: 'echo',
+ FADEIN: 'fade in',
+ FADEOUT: 'fade out',
+ MUTE: 'mute'
};
class AudioEffects {
@@ -117,6 +122,18 @@ class AudioEffects {
({input, output} = new RobotEffect(this.audioContext,
this.adjustedTrimStartSeconds, this.adjustedTrimEndSeconds));
break;
+ case effectTypes.FADEIN:
+ ({input, output} = new FadeEffect(this.audioContext, true,
+ this.adjustedTrimStartSeconds, this.adjustedTrimEndSeconds));
+ break;
+ case effectTypes.FADEOUT:
+ ({input, output} = new FadeEffect(this.audioContext, false,
+ this.adjustedTrimStartSeconds, this.adjustedTrimEndSeconds));
+ break;
+ case effectTypes.MUTE:
+ ({input, output} = new MuteEffect(this.audioContext,
+ this.adjustedTrimStartSeconds, this.adjustedTrimEndSeconds));
+ break;
}
if (input && output) {
diff --git a/src/lib/audio/effects/fade-effect.js b/src/lib/audio/effects/fade-effect.js
new file mode 100644
index 000000000..5a13c5c16
--- /dev/null
+++ b/src/lib/audio/effects/fade-effect.js
@@ -0,0 +1,27 @@
+class FadeEffect {
+ constructor (audioContext, fadeIn, startSeconds, endSeconds) {
+ this.audioContext = audioContext;
+
+ this.input = this.audioContext.createGain();
+ this.output = this.audioContext.createGain();
+
+ this.gain = this.audioContext.createGain();
+
+ this.gain.gain.setValueAtTime(1, 0);
+
+ if (fadeIn) {
+ this.gain.gain.setValueAtTime(0, startSeconds);
+ this.gain.gain.linearRampToValueAtTime(1, endSeconds);
+ } else {
+ this.gain.gain.setValueAtTime(1, startSeconds);
+ this.gain.gain.linearRampToValueAtTime(0, endSeconds);
+ }
+
+ this.gain.gain.setValueAtTime(1, endSeconds);
+
+ this.input.connect(this.gain);
+ this.gain.connect(this.output);
+ }
+}
+
+export default FadeEffect;
diff --git a/src/lib/audio/effects/mute-effect.js b/src/lib/audio/effects/mute-effect.js
new file mode 100644
index 000000000..c2a2e68d5
--- /dev/null
+++ b/src/lib/audio/effects/mute-effect.js
@@ -0,0 +1,22 @@
+class MuteEffect {
+ constructor (audioContext, startSeconds, endSeconds) {
+ this.audioContext = audioContext;
+
+ this.input = this.audioContext.createGain();
+ this.output = this.audioContext.createGain();
+
+ this.gain = this.audioContext.createGain();
+
+ // Smoothly ramp the gain down before the start time, and up after the end time.
+ this.rampLength = 0.001;
+ this.gain.gain.setValueAtTime(1.0, Math.max(0, startSeconds - this.rampLength));
+ this.gain.gain.linearRampToValueAtTime(0, startSeconds);
+ this.gain.gain.setValueAtTime(0, endSeconds);
+ this.gain.gain.linearRampToValueAtTime(1.0, endSeconds + this.rampLength);
+
+ this.input.connect(this.gain);
+ this.gain.connect(this.output);
+ }
+}
+
+export default MuteEffect;