From 115d6b56a8f83666d7155ed8a44270d6ee9244a9 Mon Sep 17 00:00:00 2001 From: henz Date: Sun, 10 Sep 2023 15:26:27 +0800 Subject: [PATCH 1/9] renaming play and play_concurrently to play_in_tab and play; fixing stereo_sound play --- src/bundles/sound/functions.ts | 14 ++-- src/bundles/sound/index.ts | 2 +- src/bundles/stereo_sound/functions.ts | 97 +++++++++++++-------------- src/bundles/stereo_sound/index.ts | 4 +- 4 files changed, 55 insertions(+), 62 deletions(-) diff --git a/src/bundles/sound/functions.ts b/src/bundles/sound/functions.ts index d8b1d20cb..bd90a89ea 100644 --- a/src/bundles/sound/functions.ts +++ b/src/bundles/sound/functions.ts @@ -127,7 +127,7 @@ const recording_signal_ms = 100; const pre_recording_signal_pause_ms = 200; function play_recording_signal() { - play_concurrently(sine_sound(1200, recording_signal_ms / 1000)); + play(sine_sound(1200, recording_signal_ms / 1000)); } // eslint-disable-next-line @typescript-eslint/no-shadow @@ -337,15 +337,15 @@ export function play_wave(wave: Wave, duration: number): AudioPlayed { * @return the given sound * @example play(sine_sound(440, 5)); */ -export function play(sound: Sound): AudioPlayed { +export function play_in_tab(sound: Sound): AudioPlayed { // Type-check sound if (!is_sound(sound)) { - throw new Error(`${play.name} is expecting sound, but encountered ${sound}`); + throw new Error(`${play_in_tab.name} is expecting sound, but encountered ${sound}`); // If a sound is already playing, terminate execution. } else if (isPlaying) { - throw new Error(`${play.name}: audio system still playing previous sound`); + throw new Error(`${play_in_tab.name}: audio system still playing previous sound`); } else if (get_duration(sound) < 0) { - throw new Error(`${play.name}: duration of sound is negative`); + throw new Error(`${play_in_tab.name}: duration of sound is negative`); } else { // Instantiate audio context if it has not been instantiated. if (!audioplayer) { @@ -420,11 +420,11 @@ export function play(sound: Sound): AudioPlayed { * @param sound the sound to play * @example play_concurrently(sine_sound(440, 5)); */ -export function play_concurrently(sound: Sound): void { +export function play(sound: Sound): void { // Type-check sound if (!is_sound(sound)) { throw new Error( - `${play_concurrently.name} is expecting sound, but encountered ${sound}`, + `${play.name} is expecting sound, but encountered ${sound}`, ); } else if (get_duration(sound) <= 0) { // Do nothing diff --git a/src/bundles/sound/index.ts b/src/bundles/sound/index.ts index 7b128739f..9d0b2c7cb 100644 --- a/src/bundles/sound/index.ts +++ b/src/bundles/sound/index.ts @@ -21,8 +21,8 @@ export { phase_mod, piano, // Play-related + play_in_tab, play, - play_concurrently, play_wave, record, record_for, diff --git a/src/bundles/stereo_sound/functions.ts b/src/bundles/stereo_sound/functions.ts index 64ee4fa0d..fa9ea759d 100644 --- a/src/bundles/stereo_sound/functions.ts +++ b/src/bundles/stereo_sound/functions.ts @@ -114,7 +114,7 @@ function start_recording(mediaRecorder: MediaRecorder) { const recording_signal_duration_ms = 100; function play_recording_signal() { - play_concurrently(sine_sound(1200, recording_signal_duration_ms / 1000)); + play(sine_sound(1200, recording_signal_duration_ms / 1000)); } // eslint-disable-next-line @typescript-eslint/no-shadow @@ -252,7 +252,7 @@ export function record_for(duration: number, buffer: number): () => Sound { * @param right_wave wave function of the right channel of the sound * @param duration duration of the sound * @return resulting stereo sound - * @example const s = make_stereo_sound(t => Math_sin(2 * Math_PI * 440 * t), t => Math_sin(2 * Math_PI * 300 * t), 5); + * @example const s = make_stereo_sound(t => math_sin(2 * math_PI * 440 * t), t => math_sin(2 * math_PI * 300 * t), 5); */ export function make_stereo_sound( left_wave: Wave, @@ -277,7 +277,7 @@ export function make_stereo_sound( * @param wave wave function of the sound * @param duration duration of the sound * @return with wave as wave function and duration as duration - * @example const s = make_sound(t => Math_sin(2 * Math_PI * 440 * t), 5); + * @example const s = make_sound(t => math_sin(2 * math_PI * 440 * t), 5); */ export function make_sound(wave: Wave, duration: number): Sound { return make_stereo_sound(wave, wave, duration); @@ -288,7 +288,7 @@ export function make_sound(wave: Wave, duration: number): Sound { * * @param sound given Sound * @return the wave function of the Sound - * @example get_wave(make_sound(t => Math_sin(2 * Math_PI * 440 * t), 5)); // Returns t => Math_sin(2 * Math_PI * 440 * t) + * @example get_wave(make_sound(t => math_sin(2 * math_PI * 440 * t), 5)); // Returns t => math_sin(2 * math_PI * 440 * t) */ export function get_left_wave(sound: Sound): Wave { return head(head(sound)); @@ -299,7 +299,7 @@ export function get_left_wave(sound: Sound): Wave { * * @param sound given Sound * @return the wave function of the Sound - * @example get_wave(make_sound(t => Math_sin(2 * Math_PI * 440 * t), 5)); // Returns t => Math_sin(2 * Math_PI * 440 * t) + * @example get_wave(make_sound(t => math_sin(2 * math_PI * 440 * t), 5)); // Returns t => math_sin(2 * math_PI * 440 * t) */ export function get_right_wave(sound: Sound): Wave { return tail(head(sound)); @@ -310,7 +310,7 @@ export function get_right_wave(sound: Sound): Wave { * * @param sound given Sound * @return the duration of the Sound - * @example get_duration(make_sound(t => Math_sin(2 * Math_PI * 440 * t), 5)); // Returns 5 + * @example get_duration(make_sound(t => math_sin(2 * math_PI * 440 * t), 5)); // Returns 5 */ export function get_duration(sound: Sound): number { return tail(sound); @@ -366,21 +366,22 @@ export function play_waves( /** * Plays the given Sound using the computer’s sound device. - * The sound is only played if no other sounds are currently being played. + * The sound is added to a list of sounds to be played one-at-a-time + * in a Source Academy tab. * * @param sound the sound to play * @return the given sound - * @example play(sine_sound(440, 5)); + * @example play_in_tab(sine_sound(440, 5)); */ -export function play(sound: Sound): AudioPlayed { +export function play_in_tab(sound: Sound): AudioPlayed { // Type-check sound if (!is_sound(sound)) { - throw new Error(`${play.name} is expecting sound, but encountered ${sound}`); + throw new Error(`${play_in_tab.name} is expecting sound, but encountered ${sound}`); // If a sound is already playing, terminate execution. } else if (isPlaying) { - throw new Error(`${play.name}: audio system still playing previous sound`); + throw new Error(`${play_in_tab.name}: audio system still playing previous sound`); } else if (get_duration(sound) < 0) { - throw new Error(`${play.name}: duration of sound is negative`); + throw new Error(`${play_in_tab.name}: duration of sound is negative`); } else { // Instantiate audio context if it has not been instantiated. if (!audioplayer) { @@ -450,19 +451,6 @@ export function play(sound: Sound): AudioPlayed { riffwave.header.bitsPerSample = 16; riffwave.Make(channel); - /* - const audio = new Audio(riffwave.dataURI); - const source2 = audioplayer.createMediaElementSource(audio); - source2.connect(audioplayer.destination); - - // Connect data to output destination - isPlaying = true; - audio.play(); - audio.onended = () => { - source2.disconnect(audioplayer.destination); - isPlaying = false; - }; */ - const audio = { toReplString: () => '', dataUri: riffwave.dataURI, @@ -478,68 +466,73 @@ export function play(sound: Sound): AudioPlayed { * on top of any sounds that are currently playing. * * @param sound the sound to play - * @example play_concurrently(sine_sound(440, 5)); + * @example play(sine_sound(440, 5)); */ -export function play_concurrently(sound: Sound): void { +export function play(sound: Sound): void { // Type-check sound if (!is_sound(sound)) { - throw new Error( - `${play_concurrently.name} is expecting sound, but encountered ${sound}`, - ); - } else if (get_duration(sound) <= 0) { - // Do nothing + throw new Error(`${play.name} is expecting sound, but encountered ${sound}`); + // If a sound is already playing, terminate execution. + } else if (isPlaying) { + throw new Error(`${play.name}: audio system still playing previous sound`); + } else if (get_duration(sound) < 0) { + throw new Error(`${play.name}: duration of sound is negative`); } else { // Instantiate audio context if it has not been instantiated. if (!audioplayer) { init_audioCtx(); } - const channel: number[] = Array[2 * Math.ceil(FS * get_duration(sound))]; + const channel: number[] = []; + const len = Math.ceil(FS * get_duration(sound)); let Ltemp: number; let Rtemp: number; - let prev_value = 0; + let Lprev_value = 0; + let Rprev_value = 0; const left_wave = get_left_wave(sound); - - for (let i = 0; i < channel.length; i += 2) { + const right_wave = get_right_wave(sound); + for (let i = 0; i < len; i += 1) { Ltemp = left_wave(i / FS); // clip amplitude if (Ltemp > 1) { - channel[i] = 1; + channel[2 * i] = 1; } else if (Ltemp < -1) { - channel[i] = -1; + channel[2 * i] = -1; } else { - channel[i] = Ltemp; + channel[2 * i] = Ltemp; } // smoothen out sudden cut-outs - if (channel[i] === 0 && Math.abs(channel[i] - prev_value) > 0.01) { - channel[i] = prev_value * 0.999; + if ( + channel[2 * i] === 0 + && Math.abs(channel[2 * i] - Lprev_value) > 0.01 + ) { + channel[2 * i] = Lprev_value * 0.999; } - prev_value = channel[i]; - } + Lprev_value = channel[2 * i]; - prev_value = 0; - const right_wave = get_right_wave(sound); - for (let i = 1; i < channel.length; i += 2) { Rtemp = right_wave(i / FS); // clip amplitude if (Rtemp > 1) { - channel[i] = 1; + channel[2 * i + 1] = 1; } else if (Rtemp < -1) { - channel[i] = -1; + channel[2 * i + 1] = -1; } else { - channel[i] = Rtemp; + channel[2 * i + 1] = Rtemp; } // smoothen out sudden cut-outs - if (channel[i] === 0 && Math.abs(channel[i] - prev_value) > 0.01) { - channel[i] = prev_value * 0.999; + if ( + channel[2 * i + 1] === 0 + && Math.abs(channel[2 * i] - Rprev_value) > 0.01 + ) { + channel[2 * i + 1] = Rprev_value * 0.999; } - prev_value = channel[i]; + Rprev_value = channel[2 * i + 1]; } // quantize diff --git a/src/bundles/stereo_sound/index.ts b/src/bundles/stereo_sound/index.ts index abd2dd07b..40f02ec2a 100644 --- a/src/bundles/stereo_sound/index.ts +++ b/src/bundles/stereo_sound/index.ts @@ -10,10 +10,10 @@ export { pan, pan_mod, // Play-related - play, + play_in_tab, play_wave, play_waves, - play_concurrently, + play, stop, // Recording init_record, From 06c796e0c6851ea3c56caa1fcc256bb9921d0aa1 Mon Sep 17 00:00:00 2001 From: henz Date: Sun, 10 Sep 2023 15:31:13 +0800 Subject: [PATCH 2/9] renaming play and play_concurrently to play_in_tab and play; fixing stereo_sound play --- src/bundles/sound/functions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bundles/sound/functions.ts b/src/bundles/sound/functions.ts index bd90a89ea..19ce8b4da 100644 --- a/src/bundles/sound/functions.ts +++ b/src/bundles/sound/functions.ts @@ -426,8 +426,8 @@ export function play(sound: Sound): void { throw new Error( `${play.name} is expecting sound, but encountered ${sound}`, ); - } else if (get_duration(sound) <= 0) { - // Do nothing + } else if (get_duration(sound) < 0) { + throw new Error(`${play.name}: duration of sound is negative`); } else { // Instantiate audio context if it has not been instantiated. if (!audioplayer) { From f2c1e5f49abe33695a622e3ed9acbf2256f5553b Mon Sep 17 00:00:00 2001 From: henz Date: Sun, 10 Sep 2023 16:15:36 +0800 Subject: [PATCH 3/9] documentation fixes; return values of play functions made more regular --- src/bundles/sound/functions.ts | 111 +++++++++++++------------- src/bundles/stereo_sound/functions.ts | 33 ++++---- 2 files changed, 75 insertions(+), 69 deletions(-) diff --git a/src/bundles/sound/functions.ts b/src/bundles/sound/functions.ts index 19ce8b4da..d7d69b403 100644 --- a/src/bundles/sound/functions.ts +++ b/src/bundles/sound/functions.ts @@ -1,19 +1,19 @@ /** - * The sounds library provides functions for constructing and playing sounds. + * The `sound` module provides functions for constructing and playing sounds. * * A wave is a function that takes in a number `t` and returns * a number representing the amplitude at time `t`. * The amplitude should fall within the range of [-1, 1]. * - * A Sound is a pair(wave, duration) where duration is the length of the sound in seconds. + * A Sound is a pair(wave, duration) where duration is the length of the Sound in seconds. * The constructor make_sound and accessors get_wave and get_duration are provided. * * Sound Discipline: - * For all sounds, the wave function applied to and time `t` beyond its duration returns 0, that is: + * For all Sounds, the wave function applied to and time `t` beyond its duration returns 0, that is: * `(get_wave(sound))(get_duration(sound) + x) === 0` for any x >= 0. * * Two functions which combine Sounds, `consecutively` and `simultaneously` are given. - * Additionally, we provide sound transformation functions `adsr` and `phase_mod` + * Additionally, we provide Sound transformation functions `adsr` and `phase_mod` * which take in a Sound and return a Sound. * * Finally, the provided `play` function takes in a Sound and plays it using your @@ -175,10 +175,11 @@ export function init_record(): string { } /** - * takes a buffer duration (in seconds) as argument, and + * Records a sound until the returned stop function is called. + * Takes a buffer duration (in seconds) as argument, and * returns a nullary stop function stop. A call - * stop() returns a sound promise: a nullary function - * that returns a sound. Example:
init_record();
+ * stop() returns a Sound promise: a nullary function
+ * that returns a Sound. Example: 
init_record();
  * const stop = record(0.5);
  * // record after 0.5 seconds. Then in next query:
  * const promise = stop();
@@ -188,7 +189,7 @@ export function init_record(): string {
  * @param buffer - pause before recording, in seconds
  * @returns nullary stop function;
  * stop() stops the recording and
- * returns a sound promise: a nullary function that returns the recorded sound
+ * returns a Sound promise: a nullary function that returns the recorded Sound
  */
 export function record(buffer: number): () => () => Sound {
   check_permission();
@@ -213,15 +214,15 @@ export function record(buffer: number): () => () => Sound {
 /**
  * Records a sound of given duration in seconds, after
  * a buffer also in seconds, and
- * returns a sound promise: a nullary function
- * that returns a sound. Example: 
init_record();
+ * returns a Sound promise: a nullary function
+ * that returns a Sound. Example: 
init_record();
  * const promise = record_for(2, 0.5);
- * // In next query, you can play the promised sound, by
+ * // In next query, you can play the promised Sound, by
  * // applying the promise:
  * play(promise());
* @param duration duration in seconds * @param buffer pause before recording, in seconds - * @return promise: nullary function which returns recorded sound + * @return promise: nullary function which returns recorded Sound */ export function record_for(duration: number, buffer: number): () => Sound { recorded_sound = undefined; @@ -270,8 +271,8 @@ export function record_for(duration: number, buffer: number): () => Sound { * that takes in a non-negative input time and returns an amplitude * between -1 and 1. * - * @param wave wave function of the sound - * @param duration duration of the sound + * @param wave wave function of the Sound + * @param duration duration of the Sound * @return with wave as wave function and duration as duration * @example const s = make_sound(t => Math_sin(2 * Math_PI * 440 * t), 5); */ @@ -319,25 +320,25 @@ export function is_sound(x: any): x is Sound { /** * Plays the given Wave using the computer’s sound device, for the duration * given in seconds. - * The sound is only played if no other sounds are currently being played. + * The Sound is only played if no other sounds are currently being played. * * @param wave the wave function to play, starting at 0 - * @return the given sound + * @return the resulting Sound * @example play_wave(t => math_sin(t * 3000), 5); */ -export function play_wave(wave: Wave, duration: number): AudioPlayed { +export function play_wave(wave: Wave, duration: number): Sound { return play(make_sound(wave, duration)); } /** * Plays the given Sound using the computer’s sound device. - * The sound is only played if no other sounds are currently being played. + * The Sound is only played if no other sounds are currently being played. * - * @param sound the sound to play - * @return the given sound + * @param sound the Sound to play + * @return the given Sound * @example play(sine_sound(440, 5)); */ -export function play_in_tab(sound: Sound): AudioPlayed { +export function play_in_tab(sound: Sound): Sound { // Type-check sound if (!is_sound(sound)) { throw new Error(`${play_in_tab.name} is expecting sound, but encountered ${sound}`); @@ -409,18 +410,19 @@ export function play_in_tab(sound: Sound): AudioPlayed { dataUri: riffwave.dataURI, }; audioPlayed.push(soundToPlay); - return soundToPlay; + return sound; } } /** * Plays the given Sound using the computer’s sound device - * on top of any sounds that are currently playing. + * on top of any Sounds that are currently playing. * - * @param sound the sound to play + * @param sound the Sound to play + * @return the given Sound * @example play_concurrently(sine_sound(440, 5)); */ -export function play(sound: Sound): void { +export function play(sound: Sound): Sound { // Type-check sound if (!is_sound(sound)) { throw new Error( @@ -475,6 +477,7 @@ export function play(sound: Sound): void { source.disconnect(audioplayer.destination); isPlaying = false; }; + return sound; } } @@ -489,10 +492,10 @@ export function stop(): void { // Primitive sounds /** - * Makes a noise sound with given duration + * Makes a noise Sound with given duration * * @param duration the duration of the noise sound - * @return resulting noise sound + * @return resulting noise Sound * @example noise_sound(5); */ export function noise_sound(duration: number): Sound { @@ -500,10 +503,10 @@ export function noise_sound(duration: number): Sound { } /** - * Makes a silence sound with given duration + * Makes a silence Sound with given duration * - * @param duration the duration of the silence sound - * @return resulting silence sound + * @param duration the duration of the silence Sound + * @return resulting silence Sound * @example silence_sound(5); */ export function silence_sound(duration: number): Sound { @@ -511,10 +514,10 @@ export function silence_sound(duration: number): Sound { } /** - * Makes a sine wave sound with given frequency and duration + * Makes a sine wave Sound with given frequency and duration * - * @param freq the frequency of the sine wave sound - * @param duration the duration of the sine wave sound + * @param freq the frequency of the sine wave Sound + * @param duration the duration of the sine wave Sound * @return resulting sine wave sound * @example sine_sound(440, 5); */ @@ -523,11 +526,11 @@ export function sine_sound(freq: number, duration: number): Sound { } /** - * Makes a square wave sound with given frequency and duration + * Makes a square wave Sound with given frequency and duration * - * @param freq the frequency of the square wave sound - * @param duration the duration of the square wave sound - * @return resulting square wave sound + * @param freq the frequency of the square wave Sound + * @param duration the duration of the square wave Sound + * @return resulting square wave Sound * @example square_sound(440, 5); */ export function square_sound(f: number, duration: number): Sound { @@ -545,11 +548,11 @@ export function square_sound(f: number, duration: number): Sound { } /** - * Makes a triangle wave sound with given frequency and duration + * Makes a triangle wave Sound with given frequency and duration * - * @param freq the frequency of the triangle wave sound - * @param duration the duration of the triangle wave sound - * @return resulting triangle wave sound + * @param freq the frequency of the triangle wave Sound + * @param duration the duration of the triangle wave Sound + * @return resulting triangle wave Sound * @example triangle_sound(440, 5); */ export function triangle_sound(freq: number, duration: number): Sound { @@ -569,11 +572,11 @@ export function triangle_sound(freq: number, duration: number): Sound { } /** - * Makes a sawtooth wave sound with given frequency and duration + * Makes a sawtooth wave Sound with given frequency and duration * - * @param freq the frequency of the sawtooth wave sound - * @param duration the duration of the sawtooth wave sound - * @return resulting sawtooth wave sound + * @param freq the frequency of the sawtooth wave Sound + * @param duration the duration of the sawtooth wave Sound + * @return resulting sawtooth wave Sound * @example sawtooth_sound(440, 5); */ export function sawtooth_sound(freq: number, duration: number): Sound { @@ -594,11 +597,11 @@ export function sawtooth_sound(freq: number, duration: number): Sound { /** * Makes a new Sound by combining the sounds in a given list - * where the second sound is appended to the end of the first sound, - * the third sound is appended to the end of the second sound, and - * so on. The effect is that the sounds in the list are joined end-to-end + * where the second Sound is appended to the end of the first Sound, + * the third Sound is appended to the end of the second Sound, and + * so on. The effect is that the Sounds in the list are joined end-to-end * - * @param list_of_sounds given list of sounds + * @param list_of_sounds given list of Sounds * @return the combined Sound * @example consecutively(list(sine_sound(200, 2), sine_sound(400, 3))); */ @@ -615,10 +618,10 @@ export function consecutively(list_of_sounds: List): Sound { } /** - * Makes a new Sound by combining the sounds in a given list - * where all the sounds are overlapped on top of each other. + * Makes a new Sound by combining the Sounds in a given list + * where all the Sounds are overlapped on top of each other. * - * @param list_of_sounds given list of sounds + * @param list_of_sounds given list of Sounds * @return the combined Sound * @example simultaneously(list(sine_sound(200, 2), sine_sound(400, 3))) */ @@ -730,7 +733,7 @@ export function stacking_adsr( } /** - * Returns a SoundTransformer which uses its argument + * Returns a Sound transformer which uses its argument * to modulate the phase of a (carrier) sine wave * of given frequency and duration with a given Sound. * Modulating with a low frequency Sound results in a vibrato effect. @@ -738,7 +741,7 @@ export function stacking_adsr( * the sine wave frequency results in more complex wave forms. * * @param freq the frequency of the sine wave to be modulated - * @param duration the duration of the output soud + * @param duration the duration of the output Sound * @param amount the amount of modulation to apply to the carrier sine wave * @return function which takes in a Sound and returns a Sound * @example phase_mod(440, 5, 1)(sine_sound(220, 5)); diff --git a/src/bundles/stereo_sound/functions.ts b/src/bundles/stereo_sound/functions.ts index fa9ea759d..2cc7349f8 100644 --- a/src/bundles/stereo_sound/functions.ts +++ b/src/bundles/stereo_sound/functions.ts @@ -1,9 +1,10 @@ /** * - * The stereo sounds library build on the sounds library by accommodating stereo sounds. - * Within this library, all sounds are represented in stereo, with two waves, left and right. + * The `stereo_sound` module build on the `sound` module by accommodating stereo sounds. + * Within this module, all Sounds are represented in stereo, with two waves, left and right. * - * A Stereo Sound is a `pair(pair(left_wave, right_wave), duration)` where duration is the length of the sound in seconds. + * A Stereo Sound (just denoted as "Sound" in this document) is + a `pair(pair(left_wave, right_wave), duration)` where duration is the length of the Sound in seconds. * The constructor `make_stereo_sound` and accessors `get_left_wave`, `get_right_wave`, and `get_duration` are provided. * The `make_sound` constructor from sounds is syntatic sugar for `make_stereo_sounds` with equal waves. * @@ -162,20 +163,21 @@ export function init_record(): string { } /** - * takes a buffer duration (in seconds) as argument, and + * Records a sound until the returned stop function is called. + * Takes a buffer duration (in seconds) as argument, and * returns a nullary stop function stop. A call - * stop() returns a sound promise: a nullary function - * that returns a sound. Example:
init_record();
+ * stop() returns a Sound promise: a nullary function
+ * that returns a Sound. Example: 
init_record();
  * const stop = record(0.5);
  * // record after 0.5 seconds. Then in next query:
  * const promise = stop();
- * // In next query, you can play the promised sound, by
+ * // In next query, you can play the promised Sound, by
  * // applying the promise:
  * play(promise());
* @param buffer - pause before recording, in seconds * @returns nullary stop function; * stop() stops the recording and - * returns a sound promise: a nullary function that returns the recorded sound + * returns a sound promise: a nullary function that returns the recorded Sound */ export function record(buffer: number): () => () => Sound { check_permission(); @@ -200,8 +202,8 @@ export function record(buffer: number): () => () => Sound { /** * Records a sound of given duration in seconds, after * a buffer also in seconds, and - * returns a sound promise: a nullary function - * that returns a sound. Example:
init_record();
+ * returns a Sound promise: a nullary function
+ * that returns a Sound. Example: 
init_record();
  * const promise = record_for(2, 0.5);
  * // In next query, you can play the promised sound, by
  * // applying the promise:
@@ -349,7 +351,6 @@ export function play_wave(wave: Wave, duration: number): AudioPlayed {
  * Plays the given two Waves using the computer’s sound device, for the duration
  * given in seconds. The first Wave is for the left channel, the second for the
  * right channel.
- * The sound is only played if no other sounds are currently being played.
  *
  * @param wave1 the wave function to play on the left channel, starting at 0
  * @param wave2 the wave function to play on the right channel, starting at 0
@@ -360,7 +361,7 @@ export function play_waves(
   wave1: Wave,
   wave2: Wave,
   duration: number,
-): AudioPlayed {
+): Sound {
   return play(make_stereo_sound(wave1, wave2, duration));
 }
 
@@ -373,7 +374,7 @@ export function play_waves(
  * @return the given sound
  * @example play_in_tab(sine_sound(440, 5));
  */
-export function play_in_tab(sound: Sound): AudioPlayed {
+export function play_in_tab(sound: Sound): Sound {
   // Type-check sound
   if (!is_sound(sound)) {
     throw new Error(`${play_in_tab.name} is expecting sound, but encountered ${sound}`);
@@ -457,7 +458,7 @@ export function play_in_tab(sound: Sound): AudioPlayed {
     };
 
     audioPlayed.push(audio);
-    return audio;
+    return sound;
   }
 }
 
@@ -466,9 +467,10 @@ export function play_in_tab(sound: Sound): AudioPlayed {
  * on top of any sounds that are currently playing.
  *
  * @param sound the sound to play
+ * @return the given sound
  * @example play(sine_sound(440, 5));
  */
-export function play(sound: Sound): void {
+export function play(sound: Sound): Sound {
   // Type-check sound
   if (!is_sound(sound)) {
     throw new Error(`${play.name} is expecting sound, but encountered ${sound}`);
@@ -556,6 +558,7 @@ export function play(sound: Sound): void {
       source2.disconnect(audioplayer.destination);
       isPlaying = false;
     };
+    return sound;
   }
 }
 

From 5f93923f12c9f4ff438a1c272f59a79a34af3de1 Mon Sep 17 00:00:00 2001
From: henz 
Date: Sun, 10 Sep 2023 16:18:58 +0800
Subject: [PATCH 4/9] documentation fixes; return values of play functions made
 more regular

---
 src/bundles/stereo_sound/functions.ts | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/bundles/stereo_sound/functions.ts b/src/bundles/stereo_sound/functions.ts
index 2cc7349f8..542a65f7c 100644
--- a/src/bundles/stereo_sound/functions.ts
+++ b/src/bundles/stereo_sound/functions.ts
@@ -337,13 +337,13 @@ export function is_sound(x: any): boolean {
 /**
  * Plays the given Wave using the computer’s sound device, for the duration
  * given in seconds.
- * The sound is only played if no other sounds are currently being played.
+ * The Sound is only played if no other Sounds are currently being played.
  *
  * @param wave the wave function to play, starting at 0
- * @return the given sound
+ * @return the given Sound
  * @example play_wave(t => math_sin(t * 3000), 5);
  */
-export function play_wave(wave: Wave, duration: number): AudioPlayed {
+export function play_wave(wave: Wave, duration: number): Sound {
   return play(make_sound(wave, duration));
 }
 

From 7d74800f9a53a3aaf7520b2c295a66c694064f8b Mon Sep 17 00:00:00 2001
From: henz 
Date: Sun, 10 Sep 2023 16:26:54 +0800
Subject: [PATCH 5/9] minor fix in play_wave

---
 src/bundles/sound/functions.ts        | 4 ++--
 src/bundles/stereo_sound/functions.ts | 1 -
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/bundles/sound/functions.ts b/src/bundles/sound/functions.ts
index d7d69b403..673e1d26b 100644
--- a/src/bundles/sound/functions.ts
+++ b/src/bundles/sound/functions.ts
@@ -320,7 +320,6 @@ export function is_sound(x: any): x is Sound {
 /**
  * Plays the given Wave using the computer’s sound device, for the duration
  * given in seconds.
- * The Sound is only played if no other sounds are currently being played.
  *
  * @param wave the wave function to play, starting at 0
  * @return the resulting Sound
@@ -332,7 +331,8 @@ export function play_wave(wave: Wave, duration: number): Sound {
 
 /**
  * Plays the given Sound using the computer’s sound device.
- * The Sound is only played if no other sounds are currently being played.
+ * The sound is added to a list of sounds to be played one-at-a-time
+ * in a Source Academy tab.
  *
  * @param sound the Sound to play
  * @return the given Sound
diff --git a/src/bundles/stereo_sound/functions.ts b/src/bundles/stereo_sound/functions.ts
index 542a65f7c..398e3e2e9 100644
--- a/src/bundles/stereo_sound/functions.ts
+++ b/src/bundles/stereo_sound/functions.ts
@@ -337,7 +337,6 @@ export function is_sound(x: any): boolean {
 /**
  * Plays the given Wave using the computer’s sound device, for the duration
  * given in seconds.
- * The Sound is only played if no other Sounds are currently being played.
  *
  * @param wave the wave function to play, starting at 0
  * @return the given Sound

From 71e0c350307e1d447c61941615bce15c4ba3ab9e Mon Sep 17 00:00:00 2001
From: henz 
Date: Sun, 10 Sep 2023 17:30:00 +0800
Subject: [PATCH 6/9] fixes after sayomaki's review

---
 src/bundles/sound/functions.ts        | 19 +++----------------
 src/bundles/stereo_sound/functions.ts | 16 ++++++++--------
 2 files changed, 11 insertions(+), 24 deletions(-)

diff --git a/src/bundles/sound/functions.ts b/src/bundles/sound/functions.ts
index 673e1d26b..f1d296e73 100644
--- a/src/bundles/sound/functions.ts
+++ b/src/bundles/sound/functions.ts
@@ -336,7 +336,7 @@ export function play_wave(wave: Wave, duration: number): Sound {
  *
  * @param sound the Sound to play
  * @return the given Sound
- * @example play(sine_sound(440, 5));
+ * @example play_in_tab(sine_sound(440, 5));
  */
 export function play_in_tab(sound: Sound): Sound {
   // Type-check sound
@@ -392,19 +392,6 @@ export function play_in_tab(sound: Sound): Sound {
     riffwave.header.bitsPerSample = 16;
     riffwave.Make(channel);
 
-    /*
-    const audio = new Audio(riffwave.dataURI);
-    const source2 = audioplayer.createMediaElementSource(audio);
-    source2.connect(audioplayer.destination);
-
-    // Connect data to output destination
-    isPlaying = true;
-    audio.play();
-    audio.onended = () => {
-      source2.disconnect(audioplayer.destination);
-      isPlaying = false;
-    }; */
-
     const soundToPlay = {
       toReplString: () => '',
       dataUri: riffwave.dataURI,
@@ -420,7 +407,7 @@ export function play_in_tab(sound: Sound): Sound {
  *
  * @param sound the Sound to play
  * @return the given Sound
- * @example play_concurrently(sine_sound(440, 5));
+ * @example play(sine_sound(440, 5));
  */
 export function play(sound: Sound): Sound {
   // Type-check sound
@@ -518,7 +505,7 @@ export function silence_sound(duration: number): Sound {
  *
  * @param freq the frequency of the sine wave Sound
  * @param duration the duration of the sine wave Sound
- * @return resulting sine wave sound
+ * @return resulting sine wave Sound
  * @example sine_sound(440, 5);
  */
 export function sine_sound(freq: number, duration: number): Sound {
diff --git a/src/bundles/stereo_sound/functions.ts b/src/bundles/stereo_sound/functions.ts
index 398e3e2e9..8088a7747 100644
--- a/src/bundles/stereo_sound/functions.ts
+++ b/src/bundles/stereo_sound/functions.ts
@@ -250,10 +250,10 @@ export function record_for(duration: number, buffer: number): () => Sound {
  * that takes in a non-negative input time and returns an amplitude
  * between -1 and 1.
  *
- * @param left_wave wave function of the left channel of the sound
- * @param right_wave wave function of the right channel of the sound
- * @param duration duration of the sound
- * @return resulting stereo sound
+ * @param left_wave wave function of the left channel of the Sound
+ * @param right_wave wave function of the right channel of the Sound
+ * @param duration duration of the Sound
+ * @return resulting stereo Sound
  * @example const s = make_stereo_sound(t => math_sin(2 * math_PI * 440 * t), t => math_sin(2 * math_PI * 300 * t), 5);
  */
 export function make_stereo_sound(
@@ -276,9 +276,9 @@ export function make_stereo_sound(
  * that takes in a non-negative input time and returns an amplitude
  * between -1 and 1.
  *
- * @param wave wave function of the sound
- * @param duration duration of the sound
- * @return with wave as wave function and duration as duration
+ * @param wave wave function of the Sound
+ * @param duration duration of the Sound
+ * @return Sound with the given `wave` function for both channels and `duration` as duration
  * @example const s = make_sound(t => math_sin(2 * math_PI * 440 * t), 5);
  */
 export function make_sound(wave: Wave, duration: number): Sound {
@@ -366,7 +366,7 @@ export function play_waves(
 
 /**
  * Plays the given Sound using the computer’s sound device.
- * The sound is added to a list of sounds to be played one-at-a-time
+ * The sound is added to a list of Sounds to be played one-at-a-time
  * in a Source Academy tab.
  *
  * @param sound the sound to play

From c587896cc04ec7fa8d65163f58c3defaabb63352 Mon Sep 17 00:00:00 2001
From: henz 
Date: Sun, 10 Sep 2023 17:32:46 +0800
Subject: [PATCH 7/9] fixes after sayomaki's review

---
 src/bundles/stereo_sound/functions.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/bundles/stereo_sound/functions.ts b/src/bundles/stereo_sound/functions.ts
index 8088a7747..d382c07b0 100644
--- a/src/bundles/stereo_sound/functions.ts
+++ b/src/bundles/stereo_sound/functions.ts
@@ -465,8 +465,8 @@ export function play_in_tab(sound: Sound): Sound {
  * Plays the given Sound using the computer’s sound device
  * on top of any sounds that are currently playing.
  *
- * @param sound the sound to play
- * @return the given sound
+ * @param sound the Sound to play
+ * @return the given Sound
  * @example play(sine_sound(440, 5));
  */
 export function play(sound: Sound): Sound {

From 728d52b4503f4b3e6b7ec44e14eca96de4473a95 Mon Sep 17 00:00:00 2001
From: henz 
Date: Sun, 10 Sep 2023 17:34:25 +0800
Subject: [PATCH 8/9] fixes after sayomaki's review

---
 src/bundles/stereo_sound/functions.ts | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/bundles/stereo_sound/functions.ts b/src/bundles/stereo_sound/functions.ts
index d382c07b0..7cd090112 100644
--- a/src/bundles/stereo_sound/functions.ts
+++ b/src/bundles/stereo_sound/functions.ts
@@ -366,11 +366,11 @@ export function play_waves(
 
 /**
  * Plays the given Sound using the computer’s sound device.
- * The sound is added to a list of Sounds to be played one-at-a-time
+ * The Sound is added to a list of Sounds to be played one-at-a-time
  * in a Source Academy tab.
  *
- * @param sound the sound to play
- * @return the given sound
+ * @param sound the Sound to play
+ * @return the given Sound
  * @example play_in_tab(sine_sound(440, 5));
  */
 export function play_in_tab(sound: Sound): Sound {
@@ -463,7 +463,7 @@ export function play_in_tab(sound: Sound): Sound {
 
 /**
  * Plays the given Sound using the computer’s sound device
- * on top of any sounds that are currently playing.
+ * on top of any Sounds that are currently playing.
  *
  * @param sound the Sound to play
  * @return the given Sound

From a373de28fe522e7ac947b563527a70ef0b7457d2 Mon Sep 17 00:00:00 2001
From: henz 
Date: Sun, 10 Sep 2023 17:42:15 +0800
Subject: [PATCH 9/9] fixes after sayomaki's review

---
 src/bundles/stereo_sound/functions.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/bundles/stereo_sound/functions.ts b/src/bundles/stereo_sound/functions.ts
index 7cd090112..84ddb23ca 100644
--- a/src/bundles/stereo_sound/functions.ts
+++ b/src/bundles/stereo_sound/functions.ts
@@ -353,7 +353,7 @@ export function play_wave(wave: Wave, duration: number): Sound {
  *
  * @param wave1 the wave function to play on the left channel, starting at 0
  * @param wave2 the wave function to play on the right channel, starting at 0
- * @return the given sound
+ * @return the given Sound
  * @example play_waves(t => math_sin(t * 3000), t => math_sin(t * 6000), 5);
  */
 export function play_waves(