From 5599626405f57cde0cc1bfafb913f2e95e2bd818 Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum Date: Fri, 27 Sep 2019 14:20:34 -0400 Subject: [PATCH] Revert "Revert "Limit louder effect with a max RMS"" This reverts commit 45cb96f2d4705415451f2730b04163e2bf7a8dba. --- src/components/sound-editor/sound-editor.jsx | 2 ++ src/containers/sound-editor.jsx | 12 ++++++++++++ src/lib/audio/effects/volume-effect.js | 10 +++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/components/sound-editor/sound-editor.jsx b/src/components/sound-editor/sound-editor.jsx index 84f56d08b..32a018a56 100644 --- a/src/components/sound-editor/sound-editor.jsx +++ b/src/components/sound-editor/sound-editor.jsx @@ -265,6 +265,7 @@ const SoundEditor = props => ( onClick={props.onSlower} /> } @@ -340,6 +341,7 @@ SoundEditor.propTypes = { onUndo: PropTypes.func.isRequired, playhead: PropTypes.number, setRef: PropTypes.func, + tooLoud: PropTypes.bool.isRequired, trimEnd: PropTypes.number, trimStart: PropTypes.number }; diff --git a/src/containers/sound-editor.jsx b/src/containers/sound-editor.jsx index a2b19719f..94fca9524 100644 --- a/src/containers/sound-editor.jsx +++ b/src/containers/sound-editor.jsx @@ -14,6 +14,8 @@ import log from '../lib/log.js'; const UNDO_STACK_SIZE = 99; +const MAX_RMS = 1.2; + class SoundEditor extends React.Component { constructor (props) { super(props); @@ -265,6 +267,15 @@ class SoundEditor extends React.Component { } }); } + tooLoud () { + const numChunks = this.state.chunkLevels.length; + const startIndex = this.state.trimStart === null ? + 0 : Math.floor(this.state.trimStart * numChunks); + const endIndex = this.state.trimEnd === null ? + numChunks - 1 : Math.ceil(this.state.trimEnd * numChunks); + const trimChunks = this.state.chunkLevels.slice(startIndex, endIndex); + return Math.max(...trimChunks) > MAX_RMS; + } getUndoItem () { return { ...this.copyCurrentBuffer(), @@ -399,6 +410,7 @@ class SoundEditor extends React.Component { name={this.props.name} playhead={this.state.playhead} setRef={this.setRef} + tooLoud={this.tooLoud()} trimEnd={this.state.trimEnd} trimStart={this.state.trimStart} onChangeName={this.handleChangeName} diff --git a/src/lib/audio/effects/volume-effect.js b/src/lib/audio/effects/volume-effect.js index 0cfcd6415..a5d12a987 100644 --- a/src/lib/audio/effects/volume-effect.js +++ b/src/lib/audio/effects/volume-effect.js @@ -14,8 +14,16 @@ class VolumeEffect { this.gain.gain.setValueAtTime(volume, endSeconds); this.gain.gain.exponentialRampToValueAtTime(1.0, endSeconds + this.rampLength); + // Use a waveshaper node to prevent sample values from exceeding -1 or 1. + // Without this, gain can cause samples to exceed this range, then they + // are clipped on save, and the sound is distorted on load. + this.waveShaper = this.audioContext.createWaveShaper(); + this.waveShaper.curve = new Float32Array([-1, 1]); + this.waveShaper.oversample = 'none'; + this.input.connect(this.gain); - this.gain.connect(this.output); + this.gain.connect(this.waveShaper); + this.waveShaper.connect(this.output); } }