Skip to content

Commit bdb0a8f

Browse files
committed
Remove unnecessary calls to get_duration and get_wave
1 parent da5f3e5 commit bdb0a8f

File tree

3 files changed

+119
-102
lines changed

3 files changed

+119
-102
lines changed

src/bundles/sound/src/__tests__/sound.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ describe(funcs.make_sound, () => {
1111
it('Should not error when duration is zero', () => {
1212
expect(() => funcs.make_sound(() => 0, 0)).not.toThrow();
1313
});
14-
14+
1515
it('Should error gracefully when wave is not a function', () => {
1616
expect(() => funcs.make_sound(true as any, 1))
1717
.toThrow('make_sound expects a wave, got true');

src/bundles/sound/src/functions.ts

Lines changed: 104 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -336,62 +336,65 @@ export function play_in_tab(sound: Sound): Sound {
336336
// If a sound is already playing, terminate execution.
337337
} else if (isPlaying) {
338338
throw new Error(`${play_in_tab.name}: audio system still playing previous sound`);
339-
} else if (get_duration(sound) < 0) {
339+
}
340+
341+
const duration = get_duration(sound);
342+
if (duration < 0) {
340343
throw new Error(`${play_in_tab.name}: duration of sound is negative`);
341-
} else if (get_duration(sound) === 0) {
344+
} else if (duration === 0) {
342345
return sound;
343-
} else {
344-
// Instantiate audio context if it has not been instantiated.
345-
if (!audioplayer) {
346-
init_audioCtx();
347-
}
348-
349-
// Create mono buffer
350-
const channel: number[] = [];
351-
const len = Math.ceil(FS * get_duration(sound));
352-
353-
let temp: number;
354-
let prev_value = 0;
355-
356-
const wave = get_wave(sound);
357-
for (let i = 0; i < len; i += 1) {
358-
temp = wave(i / FS);
359-
// clip amplitude
360-
// channel[i] = temp > 1 ? 1 : temp < -1 ? -1 : temp;
361-
if (temp > 1) {
362-
channel[i] = 1;
363-
} else if (temp < -1) {
364-
channel[i] = -1;
365-
} else {
366-
channel[i] = temp;
367-
}
346+
}
368347

369-
// smoothen out sudden cut-outs
370-
if (channel[i] === 0 && Math.abs(channel[i] - prev_value) > 0.01) {
371-
channel[i] = prev_value * 0.999;
372-
}
348+
// Instantiate audio context if it has not been instantiated.
349+
if (!audioplayer) {
350+
init_audioCtx();
351+
}
373352

374-
prev_value = channel[i];
353+
// Create mono buffer
354+
const channel: number[] = [];
355+
const len = Math.ceil(FS * duration);
356+
357+
let temp: number;
358+
let prev_value = 0;
359+
360+
const wave = get_wave(sound);
361+
for (let i = 0; i < len; i += 1) {
362+
temp = wave(i / FS);
363+
// clip amplitude
364+
// channel[i] = temp > 1 ? 1 : temp < -1 ? -1 : temp;
365+
if (temp > 1) {
366+
channel[i] = 1;
367+
} else if (temp < -1) {
368+
channel[i] = -1;
369+
} else {
370+
channel[i] = temp;
375371
}
376372

377-
// quantize
378-
for (let i = 0; i < channel.length; i += 1) {
379-
channel[i] = Math.floor(channel[i] * 32767.999);
373+
// smoothen out sudden cut-outs
374+
if (channel[i] === 0 && Math.abs(channel[i] - prev_value) > 0.01) {
375+
channel[i] = prev_value * 0.999;
380376
}
381377

382-
const riffwave = new RIFFWAVE([]);
383-
riffwave.header.sampleRate = FS;
384-
riffwave.header.numChannels = 1;
385-
riffwave.header.bitsPerSample = 16;
386-
riffwave.Make(channel);
378+
prev_value = channel[i];
379+
}
387380

388-
const soundToPlay = {
389-
toReplString: () => '<AudioPlayed>',
390-
dataUri: riffwave.dataURI
391-
};
392-
audioPlayed.push(soundToPlay);
393-
return sound;
381+
// quantize
382+
for (let i = 0; i < channel.length; i += 1) {
383+
channel[i] = Math.floor(channel[i] * 32767.999);
394384
}
385+
386+
const riffwave = new RIFFWAVE([]);
387+
riffwave.header.sampleRate = FS;
388+
riffwave.header.numChannels = 1;
389+
riffwave.header.bitsPerSample = 16;
390+
riffwave.Make(channel);
391+
392+
const soundToPlay = {
393+
toReplString: () => '<AudioPlayed>',
394+
dataUri: riffwave.dataURI
395+
};
396+
audioPlayed.push(soundToPlay);
397+
return sound;
395398
}
396399

397400
/**
@@ -406,59 +409,62 @@ export function play(sound: Sound): Sound {
406409
// Type-check sound
407410
if (!is_sound(sound)) {
408411
throw new Error(`${play.name} is expecting sound, but encountered ${sound}`);
409-
} else if (get_duration(sound) < 0) {
412+
}
413+
414+
const duration = get_duration(sound);
415+
if (duration < 0) {
410416
throw new Error(`${play.name}: duration of sound is negative`);
411-
} else if (get_duration(sound) === 0) {
417+
} else if (duration === 0) {
412418
return sound;
413-
} else {
414-
// Instantiate audio context if it has not been instantiated.
415-
if (!audioplayer) {
416-
init_audioCtx();
417-
}
418-
419-
// Create mono buffer
420-
const theBuffer = audioplayer.createBuffer(
421-
1,
422-
Math.ceil(FS * get_duration(sound)),
423-
FS
424-
);
425-
const channel = theBuffer.getChannelData(0);
426-
427-
let temp: number;
428-
let prev_value = 0;
419+
}
429420

430-
const wave = get_wave(sound);
431-
for (let i = 0; i < channel.length; i += 1) {
432-
temp = wave(i / FS);
433-
// clip amplitude
434-
if (temp > 1) {
435-
channel[i] = 1;
436-
} else if (temp < -1) {
437-
channel[i] = -1;
438-
} else {
439-
channel[i] = temp;
440-
}
421+
// Instantiate audio context if it has not been instantiated.
422+
if (!audioplayer) {
423+
init_audioCtx();
424+
}
441425

442-
// smoothen out sudden cut-outs
443-
if (channel[i] === 0 && Math.abs(channel[i] - prev_value) > 0.01) {
444-
channel[i] = prev_value * 0.999;
445-
}
426+
// Create mono buffer
427+
const theBuffer = audioplayer.createBuffer(
428+
1,
429+
Math.ceil(FS * duration),
430+
FS
431+
);
432+
const channel = theBuffer.getChannelData(0);
433+
434+
let temp: number;
435+
let prev_value = 0;
436+
437+
const wave = get_wave(sound);
438+
for (let i = 0; i < channel.length; i += 1) {
439+
temp = wave(i / FS);
440+
// clip amplitude
441+
if (temp > 1) {
442+
channel[i] = 1;
443+
} else if (temp < -1) {
444+
channel[i] = -1;
445+
} else {
446+
channel[i] = temp;
447+
}
446448

447-
prev_value = channel[i];
449+
// smoothen out sudden cut-outs
450+
if (channel[i] === 0 && Math.abs(channel[i] - prev_value) > 0.01) {
451+
channel[i] = prev_value * 0.999;
448452
}
449453

450-
// Connect data to output destination
451-
const source = audioplayer.createBufferSource();
452-
source.buffer = theBuffer;
453-
source.connect(audioplayer.destination);
454-
isPlaying = true;
455-
source.start();
456-
source.onended = () => {
457-
source.disconnect(audioplayer.destination);
458-
isPlaying = false;
459-
};
460-
return sound;
454+
prev_value = channel[i];
461455
}
456+
457+
// Connect data to output destination
458+
const source = audioplayer.createBufferSource();
459+
source.buffer = theBuffer;
460+
source.connect(audioplayer.destination);
461+
isPlaying = true;
462+
source.start();
463+
source.onended = () => {
464+
source.disconnect(audioplayer.destination);
465+
isPlaying = false;
466+
};
467+
return sound;
462468
}
463469

464470
/**
@@ -751,10 +757,13 @@ export function phase_mod(
751757
duration: number,
752758
amount: number
753759
): SoundTransformer {
754-
return (modulator: Sound) => make_sound(
755-
(t) => Math.sin(2 * Math.PI * t * freq + amount * get_wave(modulator)(t)),
756-
duration
757-
);
760+
return modulator => {
761+
const wave = get_wave(modulator);
762+
return make_sound(
763+
t => Math.sin(2 * Math.PI * t * freq + amount * wave(t)),
764+
duration
765+
);
766+
};
758767
}
759768

760769
// Instruments

src/bundles/sound/src/types.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
import type { Pair } from 'js-slang/dist/stdlib/list';
22

3+
/**
4+
* A wave is a function that takes in a number `t` and returns
5+
* a number representing the amplitude at time `t`.\
6+
* The amplitude should fall within the range of [-1, 1].
7+
*/
38
export type Wave = (t: number) => number;
9+
10+
/**
11+
* A Sound is a pair(wave, duration) where duration is the length of the sound in seconds.
12+
* The constructor make_sound and accessors get_wave and get_duration are provided.
13+
*/
414
export type Sound = Pair<Wave, number>;
15+
516
export type SoundProducer = (...t: any) => Sound;
617
export type SoundTransformer = (s: Sound) => Sound;
7-
export type ErrorLogger = (
8-
error: string[] | string,
9-
isSlangError?: boolean
10-
) => void;
11-
export type AudioPlayed = {
18+
19+
export interface AudioPlayed {
1220
toReplString: () => string;
1321
dataUri: string;
1422
};
1523

16-
export type SoundModuleState = {
24+
export interface SoundModuleState {
1725
audioPlayed: AudioPlayed[];
1826
};

0 commit comments

Comments
 (0)