From 2b0e454c23be37f336ff97a3c3e8e6f820393ab0 Mon Sep 17 00:00:00 2001 From: Sherman Rofeman Date: Wed, 4 Jan 2023 20:45:49 -0300 Subject: [PATCH 01/11] feat: add random intervals to timeouts. I add a function to generate random timeouts for the execution of the speak function. This adds a more natural speech as was intended by the issue #8. --- script.js | 51 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/script.js b/script.js index 14453c6..2ba519c 100644 --- a/script.js +++ b/script.js @@ -23,7 +23,14 @@ let localVoices; * @type {Array} */ let speakTimeoutsIds = []; - +/** + * An array that contains all the random intervals created whenever there is + * an whitespace in the input text. This is needed for the `setTimeout` + * functions used by the `speak` function. + * + * @type {Array} + */ +let randomIntervals = [0]; /** @type {HTMLTextAreaElement} */ const $inputText = document.querySelector('.js-input-text'); /** @type {HTMLDivElement} */ @@ -67,15 +74,15 @@ function calculatePitchRate() { } /** - * Returns the speak interval in miliseconds based on the value of the + * Returns the speak interval in milliseconds based on the value of the * $intervalSlider element in the page. * * If the $intervalSlider has not been changed, it returns 175 by default, * that is the value set in the HTML page. * - * @returns {number} The speak interval in miliseconds. + * @returns {number} The speak interval in milliseconds. */ -function calculateIntervalInMiliseconds() { +function calculateIntervalInMilliseconds() { return $intervalSlider.value; } @@ -138,7 +145,7 @@ function cancelPreviousSpeakTimeouts() { function writeDialogueText() { const inputText = getInputText(); const inputTextCharacters = inputText.split(''); - const intervalInMiliseconds = calculateIntervalInMiliseconds(); + const intervalInMilliseconds = calculateIntervalInMilliseconds(); $dialogueText.innerHTML = ''; @@ -148,7 +155,7 @@ function writeDialogueText() { ) => { speakTimeoutsIds.push(setTimeout(() => { $dialogueText.innerHTML += inputTextCharacter; - }, intervalInMiliseconds * inputTextCharacterIndex)); + }, intervalInMilliseconds * inputTextCharacterIndex)); }); } @@ -169,6 +176,16 @@ async function loadLocalVoices() { } } +/** + * Returns a random interval in milliseconds that + */ +function createRandomIntervalInMilliseconds() { + const minimumIntervalInMilliseconds = 100; + const maximumIntervalInMilliseconds = 500; + return Math.floor(Math.random() * maximumIntervalInMilliseconds) + + minimumIntervalInMilliseconds; +} + /** * Creates and plays a speak with the input text inserted in the $inputText * element. @@ -178,20 +195,36 @@ async function loadLocalVoices() { async function speak() { await loadLocalVoices(); cancelPreviousSpeakTimeouts(); + randomIntervals = [0]; const inputText = getInputText(); const inputTextCharacters = inputText.split(''); const selectedVoiceDecodedAudioData = localVoices[$voiceSelector.value]; - const intervalInMiliseconds = calculateIntervalInMiliseconds(); + const intervalInMilliseconds = calculateIntervalInMilliseconds(); inputTextCharacters.forEach(( - _inputTextCharacter, + inputTextCharacter, inputTextCharacterIndex ) => { + const randomIntervalsSum = + randomIntervals.reduce((sum, randomInterval) => { + return randomInterval + sum; + }); + console.log(randomIntervalsSum); + let interval; + if (inputTextCharacter === ' ') { + const randomInterval = createRandomIntervalInMilliseconds(); + interval = intervalInMilliseconds * inputTextCharacterIndex + + randomInterval + randomIntervalsSum; + randomIntervals.push(randomInterval); + } else { + interval = intervalInMilliseconds * inputTextCharacterIndex + + randomIntervalsSum; + } speakTimeoutsIds.push(setTimeout(() => { playDecodedAudioData(selectedVoiceDecodedAudioData); - }, intervalInMiliseconds * inputTextCharacterIndex)); + }, interval)); }); } From 92f9141e1df80baa25a10d5e1d33344db41642de Mon Sep 17 00:00:00 2001 From: Sherman Rofeman Date: Wed, 4 Jan 2023 21:12:47 -0300 Subject: [PATCH 02/11] refactor: reorganize code by using functions. --- script.js | 78 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/script.js b/script.js index 2ba519c..dda9efd 100644 --- a/script.js +++ b/script.js @@ -25,12 +25,16 @@ let localVoices; let speakTimeoutsIds = []; /** * An array that contains all the random intervals created whenever there is - * an whitespace in the input text. This is needed for the `setTimeout` - * functions used by the `speak` function. + * an white space in the input text. + * + * This array starts with zero because it will be needed the sum of the values + * that are inside it, and if there is no value, it returns an error when the + * `reduce` function is used. * * @type {Array} */ -let randomIntervals = [0]; +let randomIntervalsInMilliseconds = [0]; + /** @type {HTMLTextAreaElement} */ const $inputText = document.querySelector('.js-input-text'); /** @type {HTMLDivElement} */ @@ -51,7 +55,7 @@ $sayItButton.addEventListener('pointerdown', async () => { /** * Returns the input text that was inserted in the $inputText element. - * It makes a treatment to remove whitespaces that are on the start and end + * It makes a treatment to remove white spaces that are on the start and end * of the text. * * @returns {string} The input text that was inserted in the $inputText @@ -177,13 +181,54 @@ async function loadLocalVoices() { } /** - * Returns a random interval in milliseconds that + * Adds a random interval, in milliseconds, into the + * `randomIntervalsInMilliseconds` array that may be used by the `speak` + * function to create a more natural feeling, being applied whenever there is + * a white space in the input text. + * + * @returns {number} A random interval in milliseconds. */ -function createRandomIntervalInMilliseconds() { +function addRandomIntervalInMilliseconds() { + /** + * The minimum value for the interval, in milliseconds. + * @type {number} + **/ const minimumIntervalInMilliseconds = 100; + /** + * The maximum value for the interval, in milliseconds. + * @type {number} + **/ const maximumIntervalInMilliseconds = 500; - return Math.floor(Math.random() * maximumIntervalInMilliseconds) + + const randomIntervalInMilliseconds = Math.floor(Math.random() * maximumIntervalInMilliseconds) + minimumIntervalInMilliseconds; + + randomIntervalsInMilliseconds.push(randomIntervalInMilliseconds); +} + +/** + * Returns the sum, in milliseconds, of all the values that are inside the + * `randomIntervalsInMilliseconds` array. This value may be used to calculate + * the timeouts of the `speak` function properly when some random interval has + * been added. + * + * @returns {number} The sum, in milliseconds, of all the values that are + * inside the `randomIntervalsInMilliseconds` array. + */ +function calculateRandomIntervalsSum() { + return randomIntervalsInMilliseconds.reduce( + (sum, randomIntervalsInMillisecond) => { + return sum + randomIntervalsInMillisecond + } + ); +} + +/** + * Cancels all the previous random intervals used, by reseting the + * `randomIntervalsInMilliseconds` array to just the element zero, as it was + * at the start. + */ +function cancelRandomIntervals() { + randomIntervalsInMilliseconds = [0]; } /** @@ -195,7 +240,7 @@ function createRandomIntervalInMilliseconds() { async function speak() { await loadLocalVoices(); cancelPreviousSpeakTimeouts(); - randomIntervals = [0]; + cancelRandomIntervals(); const inputText = getInputText(); const inputTextCharacters = inputText.split(''); @@ -207,24 +252,13 @@ async function speak() { inputTextCharacter, inputTextCharacterIndex ) => { - const randomIntervalsSum = - randomIntervals.reduce((sum, randomInterval) => { - return randomInterval + sum; - }); - console.log(randomIntervalsSum); - let interval; if (inputTextCharacter === ' ') { - const randomInterval = createRandomIntervalInMilliseconds(); - interval = intervalInMilliseconds * inputTextCharacterIndex + - randomInterval + randomIntervalsSum; - randomIntervals.push(randomInterval); - } else { - interval = intervalInMilliseconds * inputTextCharacterIndex + - randomIntervalsSum; + addRandomIntervalInMilliseconds(); } + const randomIntervalsSum = calculateRandomIntervalsSum(); speakTimeoutsIds.push(setTimeout(() => { playDecodedAudioData(selectedVoiceDecodedAudioData); - }, interval)); + }, intervalInMilliseconds * inputTextCharacterIndex + randomIntervalsSum)); }); } From 9fe9b30e9ed6b2b31a945d8ca449d36bd95283f9 Mon Sep 17 00:00:00 2001 From: Sherman Rofeman Date: Thu, 5 Jan 2023 10:53:23 -0300 Subject: [PATCH 03/11] refactor: change to number. --- script.js | 47 ++++++++++++----------------------------------- 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/script.js b/script.js index dda9efd..f57cf7f 100644 --- a/script.js +++ b/script.js @@ -1,3 +1,4 @@ +//@ts-check /** * An object containing the decoded audio data of the voices that are * stored locally in the server. @@ -24,16 +25,11 @@ let localVoices; */ let speakTimeoutsIds = []; /** - * An array that contains all the random intervals created whenever there is - * an white space in the input text. - * - * This array starts with zero because it will be needed the sum of the values - * that are inside it, and if there is no value, it returns an error when the - * `reduce` function is used. - * - * @type {Array} + * A number that will keep the sum of all the random intervals added to the + * timeouts of the `speak` function. This is needed to make the timeout time + * work whenever a random interval has been added when a white space is hit. */ -let randomIntervalsInMilliseconds = [0]; +let randomIntervalsInMilliseconds = 0; /** @type {HTMLTextAreaElement} */ const $inputText = document.querySelector('.js-input-text'); @@ -185,8 +181,6 @@ async function loadLocalVoices() { * `randomIntervalsInMilliseconds` array that may be used by the `speak` * function to create a more natural feeling, being applied whenever there is * a white space in the input text. - * - * @returns {number} A random interval in milliseconds. */ function addRandomIntervalInMilliseconds() { /** @@ -199,36 +193,19 @@ function addRandomIntervalInMilliseconds() { * @type {number} **/ const maximumIntervalInMilliseconds = 500; - const randomIntervalInMilliseconds = Math.floor(Math.random() * maximumIntervalInMilliseconds) + + const randomIntervalInMilliseconds = + Math.floor(Math.random() * maximumIntervalInMilliseconds) + minimumIntervalInMilliseconds; - randomIntervalsInMilliseconds.push(randomIntervalInMilliseconds); -} - -/** - * Returns the sum, in milliseconds, of all the values that are inside the - * `randomIntervalsInMilliseconds` array. This value may be used to calculate - * the timeouts of the `speak` function properly when some random interval has - * been added. - * - * @returns {number} The sum, in milliseconds, of all the values that are - * inside the `randomIntervalsInMilliseconds` array. - */ -function calculateRandomIntervalsSum() { - return randomIntervalsInMilliseconds.reduce( - (sum, randomIntervalsInMillisecond) => { - return sum + randomIntervalsInMillisecond - } - ); + randomIntervalsInMilliseconds += randomIntervalInMilliseconds; } /** * Cancels all the previous random intervals used, by reseting the - * `randomIntervalsInMilliseconds` array to just the element zero, as it was - * at the start. + * `randomIntervalsInMilliseconds` to zero, as it was at the start. */ function cancelRandomIntervals() { - randomIntervalsInMilliseconds = [0]; + randomIntervalsInMilliseconds = 0; } /** @@ -255,10 +232,10 @@ async function speak() { if (inputTextCharacter === ' ') { addRandomIntervalInMilliseconds(); } - const randomIntervalsSum = calculateRandomIntervalsSum(); + speakTimeoutsIds.push(setTimeout(() => { playDecodedAudioData(selectedVoiceDecodedAudioData); - }, intervalInMilliseconds * inputTextCharacterIndex + randomIntervalsSum)); + }, intervalInMilliseconds * inputTextCharacterIndex + randomIntervalsInMilliseconds)); }); } From e1a8bf674ffcf55eec36e80f1b2c41c939577ff1 Mon Sep 17 00:00:00 2001 From: Sherman Rofeman Date: Thu, 5 Jan 2023 10:59:15 -0300 Subject: [PATCH 04/11] fix: write to dialogueText now matches the speak timeout. --- script.js | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/script.js b/script.js index f57cf7f..5d9c839 100644 --- a/script.js +++ b/script.js @@ -1,4 +1,5 @@ //@ts-check + /** * An object containing the decoded audio data of the voices that are * stored locally in the server. @@ -45,8 +46,7 @@ const $voiceSelector = document.querySelector('.js-voice-selector'); const $sayItButton = document.querySelector('.js-say-it-button'); $sayItButton.addEventListener('pointerdown', async () => { - await speak(); - writeDialogueText(); + await speakAndWriteToDialogueText(); }); /** @@ -138,27 +138,6 @@ function cancelPreviousSpeakTimeouts() { } } -/** - * Writes the input text inserted at the $inputText element to the - * $dialogueText element. - */ -function writeDialogueText() { - const inputText = getInputText(); - const inputTextCharacters = inputText.split(''); - const intervalInMilliseconds = calculateIntervalInMilliseconds(); - - $dialogueText.innerHTML = ''; - - inputTextCharacters.forEach(( - inputTextCharacter, - inputTextCharacterIndex - ) => { - speakTimeoutsIds.push(setTimeout(() => { - $dialogueText.innerHTML += inputTextCharacter; - }, intervalInMilliseconds * inputTextCharacterIndex)); - }); -} - /** * Loads the local voices. This is needed to fix the error * `The AudioContext was not allowed to start`, loading the local voices only @@ -214,17 +193,18 @@ function cancelRandomIntervals() { * * @async */ -async function speak() { +async function speakAndWriteToDialogueText() { await loadLocalVoices(); cancelPreviousSpeakTimeouts(); cancelRandomIntervals(); const inputText = getInputText(); const inputTextCharacters = inputText.split(''); - const selectedVoiceDecodedAudioData = - localVoices[$voiceSelector.value]; + const localVoiceSelected = localVoices[$voiceSelector.value]; const intervalInMilliseconds = calculateIntervalInMilliseconds(); + $dialogueText.innerHTML = ''; + inputTextCharacters.forEach(( inputTextCharacter, inputTextCharacterIndex @@ -234,7 +214,8 @@ async function speak() { } speakTimeoutsIds.push(setTimeout(() => { - playDecodedAudioData(selectedVoiceDecodedAudioData); + playDecodedAudioData(localVoiceSelected); + $dialogueText.innerHTML += inputTextCharacter; }, intervalInMilliseconds * inputTextCharacterIndex + randomIntervalsInMilliseconds)); }); } From 711cb386c01a38f95ab090a10ec17a7a8aaca0cd Mon Sep 17 00:00:00 2001 From: Sherman Rofeman Date: Thu, 5 Jan 2023 11:30:39 -0300 Subject: [PATCH 05/11] feat: add extra treatment to remove extra white spaces. I added one more treatment to the function. Now, extra white spaces added between the words are removed. This was maded to avoid long random intervals when the white space is found by the function. --- script.js | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/script.js b/script.js index 5d9c839..04fa64b 100644 --- a/script.js +++ b/script.js @@ -9,26 +9,27 @@ * * This variable starts `undefined`, and is only defined when the user * interacts with the page by using the function - * `loadLocalVoicesDecodedAudioData`. This is needed to fix the error `The - * AudioContext was not allowed to start`, loading the local voices only when - * the user interacts with the page. + * `loadLocalVoices`. This is needed to fix the warning `The AudioContext was + * not allowed to start`, by loading the local voices only when the user + * interacts with the page. */ let localVoices; /** - * An array that contains all the ids of the timeouts set by the `speak` - * function. Each timeout is corresponded to the speak of one of the - * characters inserted in the $inputText element. + * An array that contains all the ids of the timeouts set by the + * `speakAndWriteToDialogueText` function. Each timeout is corresponded to the + * speak of one of the characters inserted in the $inputText element. * - * This array needs to exist to the code be able to cancel previous timeouts - * avoiding the audio to overlap each other. + * This array needs to exist to the code be able to cancel previous timeouts, + * avoiding the audio to overlap. * * @type {Array} */ let speakTimeoutsIds = []; /** * A number that will keep the sum of all the random intervals added to the - * timeouts of the `speak` function. This is needed to make the timeout time - * work whenever a random interval has been added when a white space is hit. + * timeouts of the `speakAndWriteToDialogueText` function. This is needed to + * make the timeout time work whenever a random interval has been added when a + * white space is found. */ let randomIntervalsInMilliseconds = 0; @@ -52,13 +53,29 @@ $sayItButton.addEventListener('pointerdown', async () => { /** * Returns the input text that was inserted in the $inputText element. * It makes a treatment to remove white spaces that are on the start and end - * of the text. + * of the text as well extra white spaces that has been added between the + * words. * * @returns {string} The input text that was inserted in the $inputText * element with some treatments. */ function getInputText() { - return $inputText.value.trim(); + const treatedCharacters = []; + let lastCharacter = ''; + $inputText + .value + .trim() + .split('') + .forEach((inputTextCharacter) => { + if ( + (lastCharacter === ' ' && inputTextCharacter !== ' ') || + (lastCharacter !== ' ') + ) { + treatedCharacters.push(inputTextCharacter); + } + lastCharacter = inputTextCharacter; + }); + return treatedCharacters.join(''); } /** @@ -203,6 +220,8 @@ async function speakAndWriteToDialogueText() { const localVoiceSelected = localVoices[$voiceSelector.value]; const intervalInMilliseconds = calculateIntervalInMilliseconds(); + console.log(inputText); + $dialogueText.innerHTML = ''; inputTextCharacters.forEach(( From 928e4d47aafa9eac4abfb15df81501b57acf608e Mon Sep 17 00:00:00 2001 From: Sherman Rofeman Date: Thu, 5 Jan 2023 11:35:47 -0300 Subject: [PATCH 06/11] docs: update some of the JSDocs to match new functions. --- script.js | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/script.js b/script.js index 04fa64b..735d511 100644 --- a/script.js +++ b/script.js @@ -69,7 +69,7 @@ function getInputText() { .forEach((inputTextCharacter) => { if ( (lastCharacter === ' ' && inputTextCharacter !== ' ') || - (lastCharacter !== ' ') + lastCharacter !== ' ' ) { treatedCharacters.push(inputTextCharacter); } @@ -87,7 +87,7 @@ function getInputText() { * @returns {number} The pitch rate. */ function calculatePitchRate() { - return 0.4 * 4 ** $pitchSlider.value + 0.2; + return 0.4 * 4 ** + $pitchSlider.value + 0.2; } /** @@ -100,7 +100,7 @@ function calculatePitchRate() { * @returns {number} The speak interval in milliseconds. */ function calculateIntervalInMilliseconds() { - return $intervalSlider.value; + return + $intervalSlider.value; } /** @@ -156,7 +156,7 @@ function cancelPreviousSpeakTimeouts() { } /** - * Loads the local voices. This is needed to fix the error + * Loads the local voices. This is needed to fix the warning * `The AudioContext was not allowed to start`, loading the local voices only * when the user interact with the page. * @@ -174,24 +174,16 @@ async function loadLocalVoices() { /** * Adds a random interval, in milliseconds, into the - * `randomIntervalsInMilliseconds` array that may be used by the `speak` - * function to create a more natural feeling, being applied whenever there is - * a white space in the input text. + * `randomIntervalsInMilliseconds` number that may be used by the + * `speakAndWriteToDialogueText` function to create a more natural feeling, + * being applied whenever there is a white space in the input text. */ function addRandomIntervalInMilliseconds() { - /** - * The minimum value for the interval, in milliseconds. - * @type {number} - **/ - const minimumIntervalInMilliseconds = 100; - /** - * The maximum value for the interval, in milliseconds. - * @type {number} - **/ - const maximumIntervalInMilliseconds = 500; + const minimumIntervalValueInMilliseconds = 100; + const maximumIntervalValueInMilliseconds = 500; const randomIntervalInMilliseconds = - Math.floor(Math.random() * maximumIntervalInMilliseconds) + - minimumIntervalInMilliseconds; + Math.floor(Math.random() * maximumIntervalValueInMilliseconds) + + minimumIntervalValueInMilliseconds; randomIntervalsInMilliseconds += randomIntervalInMilliseconds; } @@ -206,7 +198,8 @@ function cancelRandomIntervals() { /** * Creates and plays a speak with the input text inserted in the $inputText - * element. + * element. It also, writes the text to the $dialogueText element at the same + * time it is speaking. * * @async */ @@ -220,8 +213,6 @@ async function speakAndWriteToDialogueText() { const localVoiceSelected = localVoices[$voiceSelector.value]; const intervalInMilliseconds = calculateIntervalInMilliseconds(); - console.log(inputText); - $dialogueText.innerHTML = ''; inputTextCharacters.forEach(( @@ -235,7 +226,9 @@ async function speakAndWriteToDialogueText() { speakTimeoutsIds.push(setTimeout(() => { playDecodedAudioData(localVoiceSelected); $dialogueText.innerHTML += inputTextCharacter; - }, intervalInMilliseconds * inputTextCharacterIndex + randomIntervalsInMilliseconds)); + }, intervalInMilliseconds * inputTextCharacterIndex + + randomIntervalsInMilliseconds + )); }); } From e5d81f5eec035ef8a174887b8f679d772d38b455 Mon Sep 17 00:00:00 2001 From: Sherman Rofeman Date: Thu, 5 Jan 2023 11:40:21 -0300 Subject: [PATCH 07/11] refactor: separate white space treatments to its own function. --- script.js | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/script.js b/script.js index 735d511..d316198 100644 --- a/script.js +++ b/script.js @@ -51,31 +51,42 @@ $sayItButton.addEventListener('pointerdown', async () => { }); /** - * Returns the input text that was inserted in the $inputText element. - * It makes a treatment to remove white spaces that are on the start and end - * of the text as well extra white spaces that has been added between the - * words. + * Trims and remove extra white spaces that are between the words of a string. * - * @returns {string} The input text that was inserted in the $inputText - * element with some treatments. + * @param {string} text The text to be treated. + * + * @returns {string} The treated string. */ -function getInputText() { +function trimAndRemoveExtraWhiteSpaces(text) { const treatedCharacters = []; let lastCharacter = ''; - $inputText - .value + text .trim() .split('') - .forEach((inputTextCharacter) => { + .forEach((character) => { if ( - (lastCharacter === ' ' && inputTextCharacter !== ' ') || + (lastCharacter === ' ' && character !== ' ') || lastCharacter !== ' ' ) { - treatedCharacters.push(inputTextCharacter); + treatedCharacters.push(character); } - lastCharacter = inputTextCharacter; + lastCharacter = character; }); return treatedCharacters.join(''); + +} + +/** + * Returns the input text that was inserted in the $inputText element. + * It makes a treatment to remove white spaces that are on the start and end + * of the text as well extra white spaces that has been added between the + * words. + * + * @returns {string} The input text that was inserted in the $inputText + * element with some treatments. + */ +function getInputText() { + return trimAndRemoveExtraWhiteSpaces($inputText.value); } /** From 9978390f2e87ae11ce8689cc05747191dcc3732f Mon Sep 17 00:00:00 2001 From: Sherman Rofeman Date: Thu, 5 Jan 2023 11:54:33 -0300 Subject: [PATCH 08/11] refactor: make random intervals relative to interval chosen. Now, all the random intervals are inversely proportional to the interval chosen. Which means: + if the interval chosen is low, the random interval is high. + if the interval chosen is high, the random interval is low. This makes the voices more natural. --- script.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/script.js b/script.js index d316198..5d36ea2 100644 --- a/script.js +++ b/script.js @@ -157,8 +157,7 @@ function playDecodedAudioData(decodedAudioData) { * and make too much noise. */ function cancelPreviousSpeakTimeouts() { - const hasSpeakTimeoutIds = speakTimeoutsIds.length > 0; - if (hasSpeakTimeoutIds) { + if (speakTimeoutsIds.length > 0) { speakTimeoutsIds.forEach((speakTimeoutId) => { clearTimeout(speakTimeoutId); }); @@ -190,11 +189,13 @@ async function loadLocalVoices() { * being applied whenever there is a white space in the input text. */ function addRandomIntervalInMilliseconds() { + const intervalInMilliseconds = calculateIntervalInMilliseconds(); const minimumIntervalValueInMilliseconds = 100; - const maximumIntervalValueInMilliseconds = 500; + const maximumIntervalValueInMilliseconds = 3e4 / intervalInMilliseconds; const randomIntervalInMilliseconds = Math.floor(Math.random() * maximumIntervalValueInMilliseconds) + minimumIntervalValueInMilliseconds; + console.log(randomIntervalInMilliseconds); randomIntervalsInMilliseconds += randomIntervalInMilliseconds; } @@ -221,7 +222,7 @@ async function speakAndWriteToDialogueText() { const inputText = getInputText(); const inputTextCharacters = inputText.split(''); - const localVoiceSelected = localVoices[$voiceSelector.value]; + const selectedLocalVoice = localVoices[$voiceSelector.value]; const intervalInMilliseconds = calculateIntervalInMilliseconds(); $dialogueText.innerHTML = ''; @@ -235,7 +236,7 @@ async function speakAndWriteToDialogueText() { } speakTimeoutsIds.push(setTimeout(() => { - playDecodedAudioData(localVoiceSelected); + playDecodedAudioData(selectedLocalVoice); $dialogueText.innerHTML += inputTextCharacter; }, intervalInMilliseconds * inputTextCharacterIndex + randomIntervalsInMilliseconds From ec64ed0ec1fbf78dde2c38166eee0dc13fe19f6c Mon Sep 17 00:00:00 2001 From: Sherman Rofeman Date: Thu, 5 Jan 2023 11:58:28 -0300 Subject: [PATCH 09/11] refactor: remove unecessary console.log. --- script.js | 1 - 1 file changed, 1 deletion(-) diff --git a/script.js b/script.js index 5d36ea2..6797397 100644 --- a/script.js +++ b/script.js @@ -195,7 +195,6 @@ function addRandomIntervalInMilliseconds() { const randomIntervalInMilliseconds = Math.floor(Math.random() * maximumIntervalValueInMilliseconds) + minimumIntervalValueInMilliseconds; - console.log(randomIntervalInMilliseconds); randomIntervalsInMilliseconds += randomIntervalInMilliseconds; } From e6a9e4314e51ade3f2dd770da1775bb0c3bb9c73 Mon Sep 17 00:00:00 2001 From: Sherman Rofeman Date: Sat, 7 Jan 2023 17:07:51 -0300 Subject: [PATCH 10/11] fix: make only one audio context available for the code. --- script.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/script.js b/script.js index 6797397..e1187ac 100644 --- a/script.js +++ b/script.js @@ -32,6 +32,18 @@ let speakTimeoutsIds = []; * white space is found. */ let randomIntervalsInMilliseconds = 0; +/** + * A variable that hosts an AudioContext type to be used throughout the code. + * This variable needs to exists because, previously, creating an audio context + * to each function was causing the audios to overlap or mute in Chromium, + * Google Chrome and Brave. By using only one audio context solved that issue. + * + * This variable starts undefined by the same reason the `localVoices` variable + * does: to fix the warning `The AudioContext was not allowed to start`, by + * loading this audio context only when the user interacts with the page. + * @type {AudioContext} + */ +let audioContext; /** @type {HTMLTextAreaElement} */ const $inputText = document.querySelector('.js-input-text'); @@ -129,7 +141,6 @@ async function createDecodedAudioDataFromVoiceFile(fileName) { const voiceFileDirectoryPath = 'assets/voices/' + fileName; const fileResponse = await fetch(voiceFileDirectoryPath); const arrayBuffer = await fileResponse.arrayBuffer(); - const audioContext = new AudioContext(); return audioContext.decodeAudioData(arrayBuffer); } @@ -142,7 +153,6 @@ async function createDecodedAudioDataFromVoiceFile(fileName) { * `createDecodedAudioDataFromVoiceFile`. */ function playDecodedAudioData(decodedAudioData) { - const audioContext = new AudioContext(); const source = audioContext.createBufferSource(); const pitchRate = calculatePitchRate(); @@ -174,6 +184,7 @@ function cancelPreviousSpeakTimeouts() { */ async function loadLocalVoices() { if (!localVoices) { + audioContext = new AudioContext(); localVoices = { quack: await createDecodedAudioDataFromVoiceFile('quack.mp3'), bark: await createDecodedAudioDataFromVoiceFile('bark.wav'), From d3bdba6575b6ad230c540d81799684eee0489da9 Mon Sep 17 00:00:00 2001 From: Sherman Rofeman Date: Sun, 8 Jan 2023 10:22:45 -0300 Subject: [PATCH 11/11] refactor: follow suggestions for refactoring. --- index.html | 10 +++++----- script.js | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/index.html b/index.html index 8fbde79..e690910 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ - + quackspeak: Text-to-quack @@ -14,10 +14,10 @@
diff --git a/script.js b/script.js index e1187ac..c11c21f 100644 --- a/script.js +++ b/script.js @@ -59,7 +59,7 @@ const $voiceSelector = document.querySelector('.js-voice-selector'); const $sayItButton = document.querySelector('.js-say-it-button'); $sayItButton.addEventListener('pointerdown', async () => { - await speakAndWriteToDialogueText(); + await speakAndWriteDialogue(); }); /** @@ -69,7 +69,7 @@ $sayItButton.addEventListener('pointerdown', async () => { * * @returns {string} The treated string. */ -function trimAndRemoveExtraWhiteSpaces(text) { +function removeWhiteSpaces(text) { const treatedCharacters = []; let lastCharacter = ''; text @@ -90,15 +90,15 @@ function trimAndRemoveExtraWhiteSpaces(text) { /** * Returns the input text that was inserted in the $inputText element. - * It makes a treatment to remove white spaces that are on the start and end - * of the text as well extra white spaces that has been added between the - * words. + * + * It removes white spaces from the start and end of the text as well as extra + * white spaces that have been added between the words. * * @returns {string} The input text that was inserted in the $inputText * element with some treatments. */ function getInputText() { - return trimAndRemoveExtraWhiteSpaces($inputText.value); + return removeWhiteSpaces($inputText.value); } /** @@ -225,7 +225,7 @@ function cancelRandomIntervals() { * * @async */ -async function speakAndWriteToDialogueText() { +async function speakAndWriteDialogue() { await loadLocalVoices(); cancelPreviousSpeakTimeouts(); cancelRandomIntervals();