Skip to content

Commit 4d136c7

Browse files
authored
Merge pull request scratchfoundation#4339 from paulkaplan/prevent-large-sounds
Prevent creating sounds that are too big in the sound editor
2 parents 50a9541 + 6fa6b02 commit 4d136c7

File tree

3 files changed

+34
-17
lines changed

3 files changed

+34
-17
lines changed

src/containers/sound-editor.jsx

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import WavEncoder from 'wav-encoder';
55

66
import {connect} from 'react-redux';
77

8-
import {computeChunkedRMS} from '../lib/audio/audio-util.js';
8+
import {computeChunkedRMS, SOUND_BYTE_LIMIT} from '../lib/audio/audio-util.js';
99
import AudioEffects from '../lib/audio/audio-effects.js';
1010
import SoundEditorComponent from '../components/sound-editor/sound-editor.jsx';
1111
import AudioBufferPlayer from '../lib/audio/audio-buffer-player.js';
@@ -65,32 +65,45 @@ class SoundEditor extends React.Component {
6565
});
6666
}
6767
submitNewSamples (samples, sampleRate, skipUndo) {
68-
if (!skipUndo) {
69-
this.redoStack = [];
70-
if (this.undoStack.length >= UNDO_STACK_SIZE) {
71-
this.undoStack.shift(); // Drop the first element off the array
72-
}
73-
this.undoStack.push(this.copyCurrentBuffer());
74-
}
7568
// Encode the new sound into a wav so that it can be stored
7669
let wavBuffer = null;
7770
try {
7871
wavBuffer = WavEncoder.encode.sync({
7972
sampleRate: sampleRate,
8073
channelData: [samples]
8174
});
75+
76+
if (wavBuffer.byteLength > SOUND_BYTE_LIMIT) {
77+
// Cancel the sound update by setting to null
78+
wavBuffer = null;
79+
log.error(`Refusing to encode sound larger than ${SOUND_BYTE_LIMIT} bytes`);
80+
}
8281
} catch (e) {
8382
// This error state is mostly for the mock sounds used during testing.
8483
// Any incorrect sound buffer trying to get interpretd as a Wav file
8584
// should yield this error.
85+
// This can also happen if the sound is too be allocated in memory.
8686
log.error(`Encountered error while trying to encode sound update: ${e}`);
8787
}
8888

89-
this.resetState(samples, sampleRate);
90-
this.props.vm.updateSoundBuffer(
91-
this.props.soundIndex,
92-
this.audioBufferPlayer.buffer,
93-
wavBuffer ? new Uint8Array(wavBuffer) : new Uint8Array());
89+
// Do not submit sound if it could not be encoded (i.e. if too large)
90+
if (wavBuffer) {
91+
if (!skipUndo) {
92+
this.redoStack = [];
93+
if (this.undoStack.length >= UNDO_STACK_SIZE) {
94+
this.undoStack.shift(); // Drop the first element off the array
95+
}
96+
this.undoStack.push(this.copyCurrentBuffer());
97+
}
98+
this.resetState(samples, sampleRate);
99+
this.props.vm.updateSoundBuffer(
100+
this.props.soundIndex,
101+
this.audioBufferPlayer.buffer,
102+
new Uint8Array(wavBuffer));
103+
104+
return true; // Update succeeded
105+
}
106+
return false; // Update failed
94107
}
95108
handlePlay () {
96109
this.audioBufferPlayer.play(
@@ -147,8 +160,8 @@ class SoundEditor extends React.Component {
147160
effects.process(({renderedBuffer}) => {
148161
const samples = renderedBuffer.getChannelData(0);
149162
const sampleRate = renderedBuffer.sampleRate;
150-
this.submitNewSamples(samples, sampleRate);
151-
this.handlePlay();
163+
const success = this.submitNewSamples(samples, sampleRate);
164+
if (success) this.handlePlay();
152165
});
153166
}
154167
handleUndo () {

src/lib/audio/audio-util.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const SOUND_BYTE_LIMIT = 10 * 1000 * 1000; // 10mb
2+
13
const computeRMS = function (samples, scaling = 0.55) {
24
if (samples.length === 0) return 0;
35
// Calculate RMS, adapted from https://github.com/Tonejs/Tone.js/blob/master/Tone/component/Meter.js#L88
@@ -23,5 +25,6 @@ const computeChunkedRMS = function (samples, chunkSize = 1024) {
2325

2426
export {
2527
computeRMS,
26-
computeChunkedRMS
28+
computeChunkedRMS,
29+
SOUND_BYTE_LIMIT
2730
};

test/__mocks__/audio-buffer-player.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ export default class MockAudioBufferPlayer {
33
this.samples = samples;
44
this.sampleRate = sampleRate;
55
this.buffer = {
6-
getChannelData: jest.fn(() => samples)
6+
getChannelData: jest.fn(() => samples),
7+
sampleRate: sampleRate
78
};
89
this.play = jest.fn((trimStart, trimEnd, onUpdate) => {
910
this.onUpdate = onUpdate;

0 commit comments

Comments
 (0)