Skip to content

Commit 1560bc1

Browse files
authored
sound and stereo_sound: renaming and fixing (#239)
* renaming play and play_concurrently to play_in_tab and play; fixing stereo_sound play * renaming play and play_concurrently to play_in_tab and play; fixing stereo_sound play * documentation fixes; return values of play functions made more regular * documentation fixes; return values of play functions made more regular * minor fix in play_wave * fixes after sayomaki's review * fixes after sayomaki's review * fixes after sayomaki's review * fixes after sayomaki's review
1 parent a7deb51 commit 1560bc1

File tree

4 files changed

+145
-160
lines changed

4 files changed

+145
-160
lines changed

src/bundles/sound/functions.ts

Lines changed: 67 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
/**
2-
* The sounds library provides functions for constructing and playing sounds.
2+
* The `sound` module provides functions for constructing and playing sounds.
33
*
44
* A wave is a function that takes in a number `t` and returns
55
* a number representing the amplitude at time `t`.
66
* The amplitude should fall within the range of [-1, 1].
77
*
8-
* A Sound is a pair(wave, duration) where duration is the length of the sound in seconds.
8+
* A Sound is a pair(wave, duration) where duration is the length of the Sound in seconds.
99
* The constructor make_sound and accessors get_wave and get_duration are provided.
1010
*
1111
* Sound Discipline:
12-
* For all sounds, the wave function applied to and time `t` beyond its duration returns 0, that is:
12+
* For all Sounds, the wave function applied to and time `t` beyond its duration returns 0, that is:
1313
* `(get_wave(sound))(get_duration(sound) + x) === 0` for any x >= 0.
1414
*
1515
* Two functions which combine Sounds, `consecutively` and `simultaneously` are given.
16-
* Additionally, we provide sound transformation functions `adsr` and `phase_mod`
16+
* Additionally, we provide Sound transformation functions `adsr` and `phase_mod`
1717
* which take in a Sound and return a Sound.
1818
*
1919
* Finally, the provided `play` function takes in a Sound and plays it using your
@@ -127,7 +127,7 @@ const recording_signal_ms = 100;
127127
const pre_recording_signal_pause_ms = 200;
128128

129129
function play_recording_signal() {
130-
play_concurrently(sine_sound(1200, recording_signal_ms / 1000));
130+
play(sine_sound(1200, recording_signal_ms / 1000));
131131
}
132132

133133
// eslint-disable-next-line @typescript-eslint/no-shadow
@@ -175,10 +175,11 @@ export function init_record(): string {
175175
}
176176

177177
/**
178-
* takes a <CODE>buffer</CODE> duration (in seconds) as argument, and
178+
* Records a sound until the returned stop function is called.
179+
* Takes a <CODE>buffer</CODE> duration (in seconds) as argument, and
179180
* returns a nullary stop function <CODE>stop</CODE>. A call
180-
* <CODE>stop()</CODE> returns a sound promise: a nullary function
181-
* that returns a sound. Example: <PRE><CODE>init_record();
181+
* <CODE>stop()</CODE> returns a Sound promise: a nullary function
182+
* that returns a Sound. Example: <PRE><CODE>init_record();
182183
* const stop = record(0.5);
183184
* // record after 0.5 seconds. Then in next query:
184185
* const promise = stop();
@@ -188,7 +189,7 @@ export function init_record(): string {
188189
* @param buffer - pause before recording, in seconds
189190
* @returns nullary <CODE>stop</CODE> function;
190191
* <CODE>stop()</CODE> stops the recording and
191-
* returns a sound promise: a nullary function that returns the recorded sound
192+
* returns a Sound promise: a nullary function that returns the recorded Sound
192193
*/
193194
export function record(buffer: number): () => () => Sound {
194195
check_permission();
@@ -213,15 +214,15 @@ export function record(buffer: number): () => () => Sound {
213214
/**
214215
* Records a sound of given <CODE>duration</CODE> in seconds, after
215216
* a <CODE>buffer</CODE> also in seconds, and
216-
* returns a sound promise: a nullary function
217-
* that returns a sound. Example: <PRE><CODE>init_record();
217+
* returns a Sound promise: a nullary function
218+
* that returns a Sound. Example: <PRE><CODE>init_record();
218219
* const promise = record_for(2, 0.5);
219-
* // In next query, you can play the promised sound, by
220+
* // In next query, you can play the promised Sound, by
220221
* // applying the promise:
221222
* play(promise());</CODE></PRE>
222223
* @param duration duration in seconds
223224
* @param buffer pause before recording, in seconds
224-
* @return <CODE>promise</CODE>: nullary function which returns recorded sound
225+
* @return <CODE>promise</CODE>: nullary function which returns recorded Sound
225226
*/
226227
export function record_for(duration: number, buffer: number): () => Sound {
227228
recorded_sound = undefined;
@@ -270,8 +271,8 @@ export function record_for(duration: number, buffer: number): () => Sound {
270271
* that takes in a non-negative input time and returns an amplitude
271272
* between -1 and 1.
272273
*
273-
* @param wave wave function of the sound
274-
* @param duration duration of the sound
274+
* @param wave wave function of the Sound
275+
* @param duration duration of the Sound
275276
* @return with wave as wave function and duration as duration
276277
* @example const s = make_sound(t => Math_sin(2 * Math_PI * 440 * t), 5);
277278
*/
@@ -319,33 +320,33 @@ export function is_sound(x: any): x is Sound {
319320
/**
320321
* Plays the given Wave using the computer’s sound device, for the duration
321322
* given in seconds.
322-
* The sound is only played if no other sounds are currently being played.
323323
*
324324
* @param wave the wave function to play, starting at 0
325-
* @return the given sound
325+
* @return the resulting Sound
326326
* @example play_wave(t => math_sin(t * 3000), 5);
327327
*/
328-
export function play_wave(wave: Wave, duration: number): AudioPlayed {
328+
export function play_wave(wave: Wave, duration: number): Sound {
329329
return play(make_sound(wave, duration));
330330
}
331331

332332
/**
333333
* Plays the given Sound using the computer’s sound device.
334-
* The sound is only played if no other sounds are currently being played.
334+
* The sound is added to a list of sounds to be played one-at-a-time
335+
* in a Source Academy tab.
335336
*
336-
* @param sound the sound to play
337-
* @return the given sound
338-
* @example play(sine_sound(440, 5));
337+
* @param sound the Sound to play
338+
* @return the given Sound
339+
* @example play_in_tab(sine_sound(440, 5));
339340
*/
340-
export function play(sound: Sound): AudioPlayed {
341+
export function play_in_tab(sound: Sound): Sound {
341342
// Type-check sound
342343
if (!is_sound(sound)) {
343-
throw new Error(`${play.name} is expecting sound, but encountered ${sound}`);
344+
throw new Error(`${play_in_tab.name} is expecting sound, but encountered ${sound}`);
344345
// If a sound is already playing, terminate execution.
345346
} else if (isPlaying) {
346-
throw new Error(`${play.name}: audio system still playing previous sound`);
347+
throw new Error(`${play_in_tab.name}: audio system still playing previous sound`);
347348
} else if (get_duration(sound) < 0) {
348-
throw new Error(`${play.name}: duration of sound is negative`);
349+
throw new Error(`${play_in_tab.name}: duration of sound is negative`);
349350
} else {
350351
// Instantiate audio context if it has not been instantiated.
351352
if (!audioplayer) {
@@ -391,43 +392,31 @@ export function play(sound: Sound): AudioPlayed {
391392
riffwave.header.bitsPerSample = 16;
392393
riffwave.Make(channel);
393394

394-
/*
395-
const audio = new Audio(riffwave.dataURI);
396-
const source2 = audioplayer.createMediaElementSource(audio);
397-
source2.connect(audioplayer.destination);
398-
399-
// Connect data to output destination
400-
isPlaying = true;
401-
audio.play();
402-
audio.onended = () => {
403-
source2.disconnect(audioplayer.destination);
404-
isPlaying = false;
405-
}; */
406-
407395
const soundToPlay = {
408396
toReplString: () => '<AudioPlayed>',
409397
dataUri: riffwave.dataURI,
410398
};
411399
audioPlayed.push(soundToPlay);
412-
return soundToPlay;
400+
return sound;
413401
}
414402
}
415403

416404
/**
417405
* Plays the given Sound using the computer’s sound device
418-
* on top of any sounds that are currently playing.
406+
* on top of any Sounds that are currently playing.
419407
*
420-
* @param sound the sound to play
421-
* @example play_concurrently(sine_sound(440, 5));
408+
* @param sound the Sound to play
409+
* @return the given Sound
410+
* @example play(sine_sound(440, 5));
422411
*/
423-
export function play_concurrently(sound: Sound): void {
412+
export function play(sound: Sound): Sound {
424413
// Type-check sound
425414
if (!is_sound(sound)) {
426415
throw new Error(
427-
`${play_concurrently.name} is expecting sound, but encountered ${sound}`,
416+
`${play.name} is expecting sound, but encountered ${sound}`,
428417
);
429-
} else if (get_duration(sound) <= 0) {
430-
// Do nothing
418+
} else if (get_duration(sound) < 0) {
419+
throw new Error(`${play.name}: duration of sound is negative`);
431420
} else {
432421
// Instantiate audio context if it has not been instantiated.
433422
if (!audioplayer) {
@@ -475,6 +464,7 @@ export function play_concurrently(sound: Sound): void {
475464
source.disconnect(audioplayer.destination);
476465
isPlaying = false;
477466
};
467+
return sound;
478468
}
479469
}
480470

@@ -489,45 +479,45 @@ export function stop(): void {
489479
// Primitive sounds
490480

491481
/**
492-
* Makes a noise sound with given duration
482+
* Makes a noise Sound with given duration
493483
*
494484
* @param duration the duration of the noise sound
495-
* @return resulting noise sound
485+
* @return resulting noise Sound
496486
* @example noise_sound(5);
497487
*/
498488
export function noise_sound(duration: number): Sound {
499489
return make_sound((_t) => Math.random() * 2 - 1, duration);
500490
}
501491

502492
/**
503-
* Makes a silence sound with given duration
493+
* Makes a silence Sound with given duration
504494
*
505-
* @param duration the duration of the silence sound
506-
* @return resulting silence sound
495+
* @param duration the duration of the silence Sound
496+
* @return resulting silence Sound
507497
* @example silence_sound(5);
508498
*/
509499
export function silence_sound(duration: number): Sound {
510500
return make_sound((_t) => 0, duration);
511501
}
512502

513503
/**
514-
* Makes a sine wave sound with given frequency and duration
504+
* Makes a sine wave Sound with given frequency and duration
515505
*
516-
* @param freq the frequency of the sine wave sound
517-
* @param duration the duration of the sine wave sound
518-
* @return resulting sine wave sound
506+
* @param freq the frequency of the sine wave Sound
507+
* @param duration the duration of the sine wave Sound
508+
* @return resulting sine wave Sound
519509
* @example sine_sound(440, 5);
520510
*/
521511
export function sine_sound(freq: number, duration: number): Sound {
522512
return make_sound((t) => Math.sin(2 * Math.PI * t * freq), duration);
523513
}
524514

525515
/**
526-
* Makes a square wave sound with given frequency and duration
516+
* Makes a square wave Sound with given frequency and duration
527517
*
528-
* @param freq the frequency of the square wave sound
529-
* @param duration the duration of the square wave sound
530-
* @return resulting square wave sound
518+
* @param freq the frequency of the square wave Sound
519+
* @param duration the duration of the square wave Sound
520+
* @return resulting square wave Sound
531521
* @example square_sound(440, 5);
532522
*/
533523
export function square_sound(f: number, duration: number): Sound {
@@ -545,11 +535,11 @@ export function square_sound(f: number, duration: number): Sound {
545535
}
546536

547537
/**
548-
* Makes a triangle wave sound with given frequency and duration
538+
* Makes a triangle wave Sound with given frequency and duration
549539
*
550-
* @param freq the frequency of the triangle wave sound
551-
* @param duration the duration of the triangle wave sound
552-
* @return resulting triangle wave sound
540+
* @param freq the frequency of the triangle wave Sound
541+
* @param duration the duration of the triangle wave Sound
542+
* @return resulting triangle wave Sound
553543
* @example triangle_sound(440, 5);
554544
*/
555545
export function triangle_sound(freq: number, duration: number): Sound {
@@ -569,11 +559,11 @@ export function triangle_sound(freq: number, duration: number): Sound {
569559
}
570560

571561
/**
572-
* Makes a sawtooth wave sound with given frequency and duration
562+
* Makes a sawtooth wave Sound with given frequency and duration
573563
*
574-
* @param freq the frequency of the sawtooth wave sound
575-
* @param duration the duration of the sawtooth wave sound
576-
* @return resulting sawtooth wave sound
564+
* @param freq the frequency of the sawtooth wave Sound
565+
* @param duration the duration of the sawtooth wave Sound
566+
* @return resulting sawtooth wave Sound
577567
* @example sawtooth_sound(440, 5);
578568
*/
579569
export function sawtooth_sound(freq: number, duration: number): Sound {
@@ -594,11 +584,11 @@ export function sawtooth_sound(freq: number, duration: number): Sound {
594584

595585
/**
596586
* Makes a new Sound by combining the sounds in a given list
597-
* where the second sound is appended to the end of the first sound,
598-
* the third sound is appended to the end of the second sound, and
599-
* so on. The effect is that the sounds in the list are joined end-to-end
587+
* where the second Sound is appended to the end of the first Sound,
588+
* the third Sound is appended to the end of the second Sound, and
589+
* so on. The effect is that the Sounds in the list are joined end-to-end
600590
*
601-
* @param list_of_sounds given list of sounds
591+
* @param list_of_sounds given list of Sounds
602592
* @return the combined Sound
603593
* @example consecutively(list(sine_sound(200, 2), sine_sound(400, 3)));
604594
*/
@@ -615,10 +605,10 @@ export function consecutively(list_of_sounds: List): Sound {
615605
}
616606

617607
/**
618-
* Makes a new Sound by combining the sounds in a given list
619-
* where all the sounds are overlapped on top of each other.
608+
* Makes a new Sound by combining the Sounds in a given list
609+
* where all the Sounds are overlapped on top of each other.
620610
*
621-
* @param list_of_sounds given list of sounds
611+
* @param list_of_sounds given list of Sounds
622612
* @return the combined Sound
623613
* @example simultaneously(list(sine_sound(200, 2), sine_sound(400, 3)))
624614
*/
@@ -730,15 +720,15 @@ export function stacking_adsr(
730720
}
731721

732722
/**
733-
* Returns a SoundTransformer which uses its argument
723+
* Returns a Sound transformer which uses its argument
734724
* to modulate the phase of a (carrier) sine wave
735725
* of given frequency and duration with a given Sound.
736726
* Modulating with a low frequency Sound results in a vibrato effect.
737727
* Modulating with a Sound with frequencies comparable to
738728
* the sine wave frequency results in more complex wave forms.
739729
*
740730
* @param freq the frequency of the sine wave to be modulated
741-
* @param duration the duration of the output soud
731+
* @param duration the duration of the output Sound
742732
* @param amount the amount of modulation to apply to the carrier sine wave
743733
* @return function which takes in a Sound and returns a Sound
744734
* @example phase_mod(440, 5, 1)(sine_sound(220, 5));

src/bundles/sound/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ export {
2121
phase_mod,
2222
piano,
2323
// Play-related
24+
play_in_tab,
2425
play,
25-
play_concurrently,
2626
play_wave,
2727
record,
2828
record_for,

0 commit comments

Comments
 (0)