From 7bbe5f0589473d0f333284731fc6b855b44b6427 Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum <eric.rosenbaum@gmail.com> Date: Tue, 9 Jul 2019 10:42:53 -0400 Subject: [PATCH] Add fade in, fade out and mute effects --- src/components/sound-editor/icon--fade-in.svg | Bin 0 -> 3542 bytes .../sound-editor/icon--fade-out.svg | Bin 0 -> 3499 bytes src/components/sound-editor/icon--mute.svg | Bin 0 -> 1763 bytes src/components/sound-editor/sound-editor.jsx | 39 ++++++++++++++++++ src/containers/sound-editor.jsx | 3 ++ src/lib/audio/audio-effects.js | 19 ++++++++- src/lib/audio/effects/fade-effect.js | 27 ++++++++++++ src/lib/audio/effects/mute-effect.js | 22 ++++++++++ 8 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/components/sound-editor/icon--fade-in.svg create mode 100644 src/components/sound-editor/icon--fade-out.svg create mode 100644 src/components/sound-editor/icon--mute.svg create mode 100644 src/lib/audio/effects/fade-effect.js create mode 100644 src/lib/audio/effects/mute-effect.js 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 0000000000000000000000000000000000000000..6bd9e6974fed57d83e6d40da8e7103450550cb8f GIT binary patch literal 3542 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 YP?j`cVXBJ=)IpOpz-hz=)RnRW0NP|I+W-In literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d6704bc0ee4ae2c7d7c10d9b4585c1426d4e85dc GIT binary patch literal 3499 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 literal 0 HcmV?d00001 diff --git a/src/components/sound-editor/icon--mute.svg b/src/components/sound-editor/icon--mute.svg new file mode 100644 index 0000000000000000000000000000000000000000..1fcbbd55962f47042df81f333bb098d0802a0257 GIT binary patch literal 1763 zcmcDqugJ|&C`&CW&dkrVRWj5wP*O<EOU_Tp%uBab3Jr17wNSFR<FY9(OIIk*Oex8* zRWdRts8CYKNX<;oD1q_HGE>W)@+)kW3=|9$j6g^U*-%3zg^Jvqykc9WjFOT9D}DX) z@^Za$W4-*MbbTWO0|WiyvUI2ttBRb=yliX=4J|D#^}(`Ac3cVy3JNxgy1EMPsd=eI zi6!|(Rtmw{sU^u73Z|xdMhY6{7KRpvnhLrKARCLV^!1CuvWW!+ddc~@3c9*bGfFZ` za#HPr^Gowm^j*`^Qj<%H^?gfAQf>4hG7y_mQj3%AoQqNuOHxx5$}>wcpqA;`=!2zT zs?v%f#)6$!kXVwTkYcOkYiO)zVrpV&Zepops%KzgVQ6Y(Vyxg}XsTysWMOD%W}#!G zXJKw)WN2V&qTp<3s%L3rXke&gq-SbjXl!V1Y@}dlre|zvYGGk)jwWhmVPS3#5=7E( zre|qkXl8C;q+_gSXl8C`U~Fy%G65lKW@2b*Zf;@;5`~&ztY>L#VqtDzZm8g6qGxJs zU~Ft)V5wthre|PjY;0(5rr>O%XJl+{Vr*t%4iYxDFf%eVuuw48GdD9bH8VCeMin(N zvotfav@`^X!i_N2Gc-3dH#alaF*Mb)FfcGNGBHs=5i~Y3H8nLbQ!v&;7+|VrU~FV& zYHp(7W2R?pXk=(&X>6opXryOoX<%q>q2O$$XJ}+%Xb7^*NYB8`$k5o_Qo&5e&`{69 z#LU>(*bu@oGcdBWFgI23G1IZoGcz_f0dbr`93vBRLqj7|1(5NUCWfX)<~rtjmPY1g z5J7VTOEU{Ib5kTiA9FneBNH<NV<RIZQD+N1b5nD3GYb<7BvC^HJtIpKLqkIyGd&AK zP{5fg7#iqV7#mxfnOo?X>KU4uS(q7_DmWV&=vf+BnwpuL=$L?#gfU3e&`{6Fz|h>p z)JVrf&&(X+Y(qmmQv-7|GZRB3K_5dSJqu$)6Jv8rBvEHWV?9Fy10xF)kg0G3jP;C- zO$-gpO+i)}nH!oL8CWP_PpVN0pfqf1qGPFNU}0=#Vh&0rhQ@lPCOU>DdKRX};J^df z0}?USGcqwXH#Ro~nPy~UWMOP#2#Rl0Gf40wInvNn4<_n^<Rc_uXC&Vv2_prRp{bs+ znHksxNP%i-s%Kzs430lgsG6Fa8=G60f}Cq)X<%VsZmwWxpl4udYGwgSxW=HIXkuon zV5w(fZenh1YHX+j3N;f8OG6_Q1s{lCk$fMeq>!0ns|3p8x`s-2Hu@kIB=3WY1Xwv> zlMYsfS-dDI6qgj`XQ$dK<>lw4!g#vSBGynzAuTf}2PO$(>lT&fq}nQ_mZj$9r=&nj zKyWdWn^>F;wgtq{HG*j^&&VuEMN$V=TUwl|04_qUGKx~uY?YKj&W3oPv^W*wey~D) zkYPxCh(CN2i?czVO~)dWo|;#ZsBakWn+RqpDS%9{RVppY(NG34b&WJ(PE&SvGc$H} zLw8(JYH|tKBhL9b`9(?!pz1_Pq0&~#KnYRzAlEz~r+_pexkexAG#e1Z22`)u0RY;q Bqmcjr literal 0 HcmV?d00001 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={<FormattedMessage {...messages.softer} />} onClick={props.onSofter} /> + <IconButton + className={styles.effectButton} + img={muteIcon} + title={<FormattedMessage {...messages.mute} />} + onClick={props.onMute} + /> <IconButton className={styles.effectButton} img={reverseIcon} title={<FormattedMessage {...messages.reverse} />} onClick={props.onReverse} /> + <IconButton + className={styles.effectButton} + img={fadeOutIcon} + title={<FormattedMessage {...messages.fadeOut} />} + onClick={props.onFadeOut} + /> + <IconButton + className={styles.effectButton} + img={fadeInIcon} + title={<FormattedMessage {...messages.fadeIn} />} + onClick={props.onFadeIn} + /> </div> </div> ); @@ -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; -- GitLab