<!-- --------------------- Created By InCoder --------------------- -->
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Text to Speach - InCoder</title>
<link rel="stylesheet" href="main.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
</head>
<body>
<div class="container">
<div class="title">Text to Speech Converter</div>
<div class="text">
<textarea placeholder="Enter Text" id="text" cols="30" rows="5"></textarea>
</div>
<div class="rate">
<span>1</span>
<p>Speed</p>
<input type="range" min="0" max="3" id="rate" value="1">
</div>
<div class="pitch">
<span>1</span>
<p>Voice Pitch</p>
<input type="range" min="0" max="10" id="pitch" value="1">
</div>
<select id="voices">
</select>
<button class="convert">Convert</button>
</div>
<script src="script.js"></script>
</body>
</html>
/* --------------------- Created By InCoder --------------------- */
@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
body {
display: flex;
height: 100vh;
background: #000;
align-items: center;
justify-content: center;
}
.container {
margin: 0 1rem;
padding: 0 1.2rem;
text-align: center;
border-radius: 0.4rem;
width: clamp(20rem, 4vw, 30rem);
background: rgb(255 255 255 / 80%);
}
.container .title {
font-weight: 600;
font-size: 1.4rem;
margin-top: 0.4rem;
margin-bottom: 0.4rem;
}
.container .text textarea {
width: 100%;
padding: 0.4rem;
border-radius: 0.6rem;
border: 2px solid rgb(0 0 0 / 20%);
background: rgb(255 255 255 / 70%);
}
.container .text textarea:focus {
outline: none;
border: 2px solid rgb(39 181 197);
}
.container :is(.rate, .pitch) {
position: relative;
margin-top: 1rem;
}
.container :is(.rate, .pitch) span {
top: 0;
right: 0;
width: 1.3rem;
height: 1.5rem;
position: absolute;
border-radius: 0.1rem;
background: rgb(255 255 255 / 50%);
}
.container :is(.rate, .pitch) p {
font-size: .8rem;
width: fit-content;
}
.container :is(.rate, .pitch) input[type="range"] {
width: 100%;
background-color: rgb(39 181 197);
}
.container :is(.rate, .pitch) input[type="range"] {
width: 100%;
opacity: 0.7;
outline: none;
height: 0.2rem;
appearance: none;
transition: 0.2s;
transition: opacity 0.2s;
background: rgb(0 0 0 / 30%);
}
.container :is(.rate, .pitch) input[type="range"]:hover {
opacity: 1;
}
.container :is(.rate, .pitch) input[type="range"]::slider-thumb {
width: 1rem;
height: 1rem;
cursor: grab;
appearance: none;
border-radius: 50%;
appearance: none;
background: rgb(39 181 197);
}
.container :is(.rate, .pitch) input[type="range"]::range-thumb {
width: 1rem;
height: 1rem;
cursor: grab;
background: rgb(39 181 197);
}
.container .convert {
width: 100%;
cursor: pointer;
padding: 0.2rem 0;
margin-top: .6rem;
font-size: 1.1rem;
margin-bottom: 1rem;
border-radius: 0.6rem;
color: rgb(0 0 0 / 80%);
border: 1px solid transparent;
background: rgb(255 255 255 / 50%);
}
.container button:focus {
outline: 2px solid rgb(0 0 0 / 40%);
}
#voices {
border: 0;
width: 100%;
height: 2.4rem;
margin-top: 0.6rem;
border-radius: 0.4rem;
padding: 0 0 0 0.5rem;
background: rgb(255 255 255 / 50%)
url("data:image/svg+xml,<svg height='10px' width='10px' viewBox='0 0 16 16' fill='%23000000' xmlns='http://www.w3.org/2000/svg'><path d='M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z'/></svg>")
no-repeat;
background-position: calc(100% - 0.75rem) center !important;
appearance: none !important;
appearance: none !important;
appearance: none !important;
padding-right: 2rem !important;
}
#voices:focus {
outline: 2px solid rgb(0 0 0 / 40%);
}
#voices option {
padding: 2rem;
}
// --------------------- Created By InCoder ---------------------
let text = document.querySelector('#text')
rate = document.querySelector('#rate')
pitch = document.querySelector('#pitch')
play = document.querySelector('#play')
stopSpeech = document.querySelector('#stop')
convert = document.querySelector('.convert')
voicesOptions = document.querySelector('#voices')
let voices = []
let synth = speechSynthesis
const getVoices = () => {
voices = synth.getVoices()
voices.forEach(voice => {
let option = document.createElement('option')
option.innerText = `${voice.name}`
option.setAttribute('value', voice.name)
option.setAttribute('data-name', voice.name)
option.setAttribute('data-lang', voice.lang)
voicesOptions.appendChild(option)
})
}
getVoices()
if (synth.onvoiceschanged !== undefined) {
synth.onvoiceschanged = getVoices
}
const convertToSpeach = () => {
if (synth.speaking) {
return
}
if (text.value !== '') {
let speakText = new SpeechSynthesisUtterance(text.value)
speakText.onend = e => {
convert.disabled = false
}
speakText.onerror = e => {
console.log('Something Went Wrong....')
}
let selectedVoice = voicesOptions.value
voices.forEach(voice => {
if (voice.name == selectedVoice) {
speakText.voice = voice
}
})
speakText.rate = rate.value
speakText.pitch = pitch.value
convert.disabled = true
synth.speak(speakText)
}
voicesOptions.addEventListener('change', () => {
synth.cancel()
convertToSpeach()
})
rate.addEventListener('change', () => {
synth.cancel()
convertToSpeach()
document.querySelector('.rate span').innerText = rate.value
})
pitch.addEventListener('change', () => {
synth.cancel()
convertToSpeach()
document.querySelector('.pitch span').innerText = pitch.value
})
}
rate.addEventListener('change', () => {
document.querySelector('.rate span').innerText = rate.value
})
pitch.addEventListener('change', () => {
document.querySelector('.pitch span').innerText = pitch.value
})
convert.addEventListener('click', convertToSpeach)
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.