diff --git a/TextToSpeech/VirejDasani/README.md b/TextToSpeech/VirejDasani/README.md new file mode 100644 index 000000000..e9f62cb65 --- /dev/null +++ b/TextToSpeech/VirejDasani/README.md @@ -0,0 +1,7 @@ +# [Offline Text To Speech](https://virejdasani.github.io/OfflineTextToSpeech/) + +- Developed by [Virej Dasani](https://virejdasani.github.io/) + +- [Live Website](https://virejdasani.github.io/OfflineTextToSpeech/) + +![](https://raw.githubusercontent.com/virejdasani/OfflineTextToSpeech/main/assets/bannerBG.png) diff --git a/TextToSpeech/VirejDasani/assets/bannerBG.png b/TextToSpeech/VirejDasani/assets/bannerBG.png new file mode 100644 index 000000000..2cda7a318 Binary files /dev/null and b/TextToSpeech/VirejDasani/assets/bannerBG.png differ diff --git a/TextToSpeech/VirejDasani/assets/icon.png b/TextToSpeech/VirejDasani/assets/icon.png new file mode 100644 index 000000000..b24de32d8 Binary files /dev/null and b/TextToSpeech/VirejDasani/assets/icon.png differ diff --git a/TextToSpeech/VirejDasani/assets/icons/pauseIcon.svg b/TextToSpeech/VirejDasani/assets/icons/pauseIcon.svg new file mode 100644 index 000000000..a576109a4 --- /dev/null +++ b/TextToSpeech/VirejDasani/assets/icons/pauseIcon.svg @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/TextToSpeech/VirejDasani/assets/icons/resumeIcon.svg b/TextToSpeech/VirejDasani/assets/icons/resumeIcon.svg new file mode 100644 index 000000000..2d9566c84 --- /dev/null +++ b/TextToSpeech/VirejDasani/assets/icons/resumeIcon.svg @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/TextToSpeech/VirejDasani/assets/icons/speakIcon.svg b/TextToSpeech/VirejDasani/assets/icons/speakIcon.svg new file mode 100644 index 000000000..db7c93ca7 --- /dev/null +++ b/TextToSpeech/VirejDasani/assets/icons/speakIcon.svg @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/TextToSpeech/VirejDasani/assets/icons/stopIcon.svg b/TextToSpeech/VirejDasani/assets/icons/stopIcon.svg new file mode 100644 index 000000000..f27d5877e --- /dev/null +++ b/TextToSpeech/VirejDasani/assets/icons/stopIcon.svg @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/TextToSpeech/VirejDasani/assets/whiteGlossBackground.png b/TextToSpeech/VirejDasani/assets/whiteGlossBackground.png new file mode 100644 index 000000000..46a10c49e Binary files /dev/null and b/TextToSpeech/VirejDasani/assets/whiteGlossBackground.png differ diff --git a/TextToSpeech/VirejDasani/index.html b/TextToSpeech/VirejDasani/index.html new file mode 100644 index 000000000..b32ffd743 --- /dev/null +++ b/TextToSpeech/VirejDasani/index.html @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + Offline Text To Speech + + + +
+ + + + +
+ + +

Offline Text To Speech

+
+ +

Offline Text To + Speech is now available as a browser extension!

+

Download it here

+
+ + + +
+ + + +
+ + +

|

+ + + +

|

+ + + +
+ + + +
+ + + +
+
+ +
+ + + + + \ No newline at end of file diff --git a/TextToSpeech/VirejDasani/index.js b/TextToSpeech/VirejDasani/index.js new file mode 100644 index 000000000..7c48f80a1 --- /dev/null +++ b/TextToSpeech/VirejDasani/index.js @@ -0,0 +1,95 @@ +// This is so that if speech is still playing from previous session, it stops on page load +speechSynthesis.cancel(); + +var isSpeaking = false; + +// Initialize the speech synthesis +var speech = new SpeechSynthesisUtterance(); +speech.rate = 1; +speech.pitch = 1; +speech.volume = 1; +speech.voice = speechSynthesis.getVoices()[0]; + +function speakInputText() { + isSpeaking = true; + + speech.text = document.getElementById("textInput").value; + speechSynthesis.speak(speech); +} + +function pauseSpeech() { + if (isSpeaking) { + isSpeaking = false; + speechSynthesis.pause(); + document.getElementById( + "pauseButton" + ).innerHTML = `Resume`; + } else { + isSpeaking = true; + speechSynthesis.resume(); + document.getElementById( + "pauseButton" + ).innerHTML = `Pause`; + } +} + +function stopSpeech() { + isSpeaking = false; + speechSynthesis.cancel(); +} + +function changeVoice(voice) { + if (voice == "voice1") { + // console.log((speech.voice = speechSynthesis.getVoices()[8])); + speech.voice = speechSynthesis.getVoices()[8]; + } else if (voice == "voice2") { + // console.log((speech.voice = speechSynthesis.getVoices()[0])); + speech.voice = speechSynthesis.getVoices()[0]; + } else if (voice == "voice3") { + // console.log((speech.voice = speechSynthesis.getVoices()[1])); + speech.voice = speechSynthesis.getVoices()[1]; + } else if (voice == "voice4") { + // console.log((speech.voice = speechSynthesis.getVoices()[11])); + speech.voice = speechSynthesis.getVoices()[11]; + } else if (voice == "voice5") { + // console.log((speech.voice = speechSynthesis.getVoices()[12])); + speech.voice = speechSynthesis.getVoices()[12]; + } else if (voice == "voice6") { + // console.log((speech.voice = speechSynthesis.getVoices()[18])); + speech.voice = speechSynthesis.getVoices()[18]; + } else if (voice == "voice7") { + // console.log((speech.voice = speechSynthesis.getVoices()[33])); + speech.voice = speechSynthesis.getVoices()[33]; + } else if (voice == "voice8") { + // console.log((speech.voice = speechSynthesis.getVoices()[37])); + speech.voice = speechSynthesis.getVoices()[37]; + } else if (voice == "voice9") { + // console.log((speech.voice = speechSynthesis.getVoices()[41])); + speech.voice = speechSynthesis.getVoices()[41]; + } + + // for (let i = 0; i < 100; i++) { + // console.log((speech.voice = speechSynthesis.getVoices()[i])); + // } +} + +function changeVoiceSpeed(voiceSpeed) { + // For some reason, speed below 0.5 doesn't work + if (voiceSpeed == "speed2") { + speech.rate = 2; + } else if (voiceSpeed == "speed1.75") { + speech.rate = 1.75; + } else if (voiceSpeed == "speed1.5") { + speech.rate = 1.5; + } else if (voiceSpeed == "speed1.25") { + speech.rate = 1.25; + } else if (voiceSpeed == "speed1") { + speech.rate = 1; + } else if (voiceSpeed == "speed0.75") { + speech.rate = 0.75; + } else if (voiceSpeed == "speed0.5") { + speech.rate = 0.5; + } +} diff --git a/TextToSpeech/VirejDasani/style.css b/TextToSpeech/VirejDasani/style.css new file mode 100644 index 000000000..febf929b7 --- /dev/null +++ b/TextToSpeech/VirejDasani/style.css @@ -0,0 +1,325 @@ +@import url("https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@350;400&display=swap"); + +:root { + --body-font-size: 18px; + --body-font-weight: 300; + --header-font-weight: 500; + + --main-lateral-padding: 17px; + + --footer-color: #bbbbbb; + --link-color: #248ef1; + --link-underline-color: #248ef1e5; + + --small-link-color: #3f3f3f; +} + + +* { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; +} + +body { + padding-left: 0px; + padding-right: 0px; + margin: auto; + background-image: url("./assets/whiteGlossBackground.png"); +} + +.main { + margin: auto; + width: 100%; +} + +.padding { + padding: 12px; +} + +.padding-semi-large { + padding: 14px 0px; +} + +h2 { + font-size: 34px; + font-weight: var(--header-font-weight); + text-align: left; + line-height: 125%; + margin: auto; +} + +p { + font-size: 18px; + line-height: 160%; + margin: auto; + font-weight: var(--body-font-weight); +} + +#indicators { + display: flex; + flex-direction: row; + padding-top: 20px; + align-items: center; +} + +#repo-links { + display: flex; + flex-direction: row; + align-items: center; +} + +.indicator-separator { + padding-left: 7px; + padding-right: 7px; +} + +.indicator { + font-size: 16px; + color: #00000059; + font-weight: 400; +} + +#indicators a { + text-underline-offset: 1px; + transition: 0.2s; +} + +#indicators a:hover { + color: var(--small-link-color); +} + +.icon-link { + width: 16px; + padding-left: 7px; +} + +.icon-link-small { + width: 14px; + padding-left: 7px; +} + +.link { + color: var(--link-color); + text-decoration: none; + padding-bottom: 3px; + + background: linear-gradient(to right, transparent, transparent), linear-gradient(to right, var(--link-underline-color), var(--link-underline-color)); + background-size: 100% 3px, 0 3px; + background-position: 100% 100%, 0 100%; + background-repeat: no-repeat; + transition: background-size 500ms; +} + +.link:hover { + background-size: 0 3px, 100% 3px; +} + +.button-standard { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + + padding: 10px; + padding-left: 11px; + padding-right: 11px; + background-color: rgba(255, 255, 255, 0.4); + + border-color: rgba(0, 0, 0, 0.14); + border-width: 1px; + border-style: solid; + border-radius: 6px; + text-decoration: none; + color: #000000; + + box-sizing: border-box; + box-shadow: 0px 3px 11px rgba(0, 0, 0, 0.07); + font-size: 16px; + font-weight: var(--header-font-weight); + + transition: all 0.15s ease; +} + +.button-standard:visited { + color: inherit; +} + +.button-standard:hover { + transform: scale(1.08); + background-color: rgba(255, 255, 255, 0.7); +} + +#section-1 { + padding-top: 50px; +} + +#app-store-buttons { + display: flex; + flex-direction: row; + justify-content: center; +} + +#app-store-buttons p { + font-size: 24px; + opacity: 0.1; + line-height: 0%; + padding: 15px; +} + +.section-alignment { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +#landing-header { + text-align: center; + padding-top: 7px; +} + +.main { + max-width: 750px; +} + +/* Mobile Only */ +@media only screen and (max-width: 425px) { + body { + background-size: 1200%; + } + + h2 { + font-size: 36px; + } + + p { + font-size: 20px; + } + + #app-store-buttons { + display: contents; + } +} + +/* Mobile Design - Tablet */ +@media only screen and (max-width: 999px) { + body { + background-size: 1200%; + } + + /* Make sure to show the links once we're on a desktop */ + + /* Make buttons stack instead */ +/**/ + + #app-store-buttons p { + padding: 8px; + visibility: hidden; + } +} + +/* Desktop Design */ +@media only screen and (min-width: 1000px) { + body { + background-size: 700%; + } + + /* Make sure to show the links once we're on a desktop */ + + /* Push out the lists for better visibility */ +} + +textarea { + padding: 10px; + border-radius: 10px; + background-color: rgba(255, 255, 255, 0.1); + width: 80%; + font-size: 16px; + margin-top: 8px; +} + +.optionsDiv { + position: relative; + /*Don't really need this just for demo styling*/ + + float: left; + min-width: 200px; + margin-top: 20px; + margin-left: 10px; + margin-right: 10px; +} + +.optionsDiv:after { + content: '<>'; + font: 17px "Consolas", monospace; + color: #333; + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); + right: 11px; + top: 14px; + padding: 0 0 2px; + border-bottom: 1px solid #999; + position: absolute; + pointer-events: none; +} + +.optionsDiv select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + display: block; + width: 100%; + max-width: 320px; + height: 40px; + float: right; + margin: 5px 0px; + padding: 0px 24px; + font-size: 16px; + line-height: 1.75; + color: #333; + background-color: rgba(255, 255, 255, 0.3); + background-image: none; + border: 1px solid #cccccc; + -ms-word-break: normal; + word-break: normal; + border-radius: 6px; +} + +#dropdowns { + margin: 10px; +} + +/* This it the input field when it does not have focus */ +textarea[type=text] { + outline: none; + box-shadow: none; + border: solid 1px rgb(91, 91, 91); +} + +/* This is for the highlighted color when the input field is in focus */ +textarea[type=text]:focus { + outline: none; + box-shadow: none; + border: solid 1px rgb(125, 125, 125); +} + +/* This it the input field when it does not have focus */ +select { + outline: none; + box-shadow: none; + border: solid 1px rgb(91, 91, 91); +} + +/* This is for the highlighted color when the input field is in focus */ +select:focus { + outline: none; + box-shadow: none; + border: solid 1px rgb(125, 125, 125); +} + +::-webkit-scrollbar { + background-color: rgba(255, 255, 255, 0.4); + width: 10px !important; + border-radius: 10px; +} \ No newline at end of file