Skip to content

Commit 712b179

Browse files
committed
Adding line TTS, TTS speed and volume control, Parisian French nasal vowels
1 parent 5dfa388 commit 712b179

5 files changed

Lines changed: 170 additions & 28 deletions

File tree

wiktionary_pron/css/style.css

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
src: url("../fonts/EBGaramond-Regular.woff2") format("woff2");
1313
}
1414

15+
input[type="range"] {
16+
padding: revert;
17+
}
18+
1519
button:enabled:active {
1620
background: #e5e5e5;
1721
-webkit-box-shadow: inset 0px 0px 5px #c1c1c1;
@@ -22,7 +26,7 @@ button:enabled:active {
2226

2327
.line {
2428
position: relative;
25-
29+
padding-left: 10px;
2630
}
2731

2832
hr {
@@ -145,6 +149,28 @@ body.dark_mode option {
145149
background-image: linear-gradient(to bottom, #1F1B24, #1F1B24);
146150
}
147151

152+
body.dark_mode input[type="range"] {
153+
154+
accent-color: #CE93D8;
155+
}
156+
157+
body.dark_mode button.audio-popup {
158+
color: white;
159+
background-color: #CE93D8;
160+
}
161+
162+
body.dark_mode button.audio-popup-line {
163+
color: white;
164+
background-color: initial;
165+
}
166+
167+
body.dark_mode button.audio-popup-line:hover {
168+
color: white;
169+
background-color: #CE93D8;
170+
}
171+
172+
173+
148174
body.dark_mode button {
149175
background-color: #CE93D8;
150176
color: black;
@@ -243,16 +269,54 @@ body i.fa-moon-o {
243269
transition: opacity 0.5s;
244270
}
245271

272+
.line {
273+
transition: background 0.5s;
274+
margin-left: 11px;
275+
276+
}
277+
278+
.left-column {
279+
flex: 1;
280+
position: relative;
281+
padding-left: 15px;
282+
}
283+
284+
.right-column {
285+
flex: 1;
286+
padding-left: 15px;
287+
position: relative;
288+
}
289+
290+
.line:has(.audio-popup-line:nth-of-type(1):hover) {
291+
background: rgba(211, 225, 241, 0.26);
292+
}
293+
294+
.left-column:has(.audio-popup-line:nth-of-type(1):hover) {
295+
background: rgba(211, 225, 241, 0.26);
296+
}
297+
298+
299+
246300
.audio-popup-line {
247301

248302
position: absolute;
249-
top: 5%;
250-
left: -5%;
303+
304+
left: -3%;
251305
transition: opacity 0.5s;
252-
font-size: 15px;
306+
font-size: 25px;
253307
background-color: #f0f8ff00;
254-
opacity: 0;
255-
visibility: hidden;
308+
309+
310+
margin-left: 0;
311+
padding-left: 0;
312+
text-align: center;
313+
314+
margin: 0;
315+
padding-right: 10px;
316+
padding-left: 10px;
317+
318+
height: 100%;
319+
256320
}
257321

258322
.cell {

wiktionary_pron/index.html

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,14 @@ <h1 style="flex: 1;">Online IPA Converter</h1>
9696
<option disabled selected value> --</option>
9797

9898

99-
</select></div>
99+
</select>
100+
<div>
101+
Speed: <input class="custom-input" type="range" min="0" max="200" step="10" value="100" id="tts_speed">
102+
Volume: <input class="custom-input" type="range" min="0" max="100" step="10" value="100"
103+
id="tts_volume">
104+
105+
</div>
106+
</div>
100107

101108

102109
</form>

wiktionary_pron/scripts/main.js

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,14 @@ async function transcribe(mode) {
5959
const words = line.split(" ").concat(["\n"]);
6060

6161
const container = document.createElement("tr");
62+
container.className = "line";
6263
resultDiv.appendChild(container);
6364

65+
const ttsButton = document.createElement("button");
66+
ttsButton.className = "fa fa-volume-down audio-popup-line";
67+
68+
container.prepend(ttsButton);
69+
6470
async function processWord(word) {
6571
console.log("processing", word);
6672
let { status, value } = await getIpa(word, lang, langStyle, langForm);
@@ -217,10 +223,10 @@ async function transcribe(mode) {
217223
container.style.marginRight = "auto";
218224

219225
const leftColumn = document.createElement("div");
220-
leftColumn.style.flex = "1";
226+
leftColumn.classList.add("left-column");
221227

222228
const rightColumn = document.createElement("div");
223-
rightColumn.style.flex = "1";
229+
rightColumn.classList.add("right-column");
224230

225231
for (let i = 0; i < words.length; i++) {
226232
const wordDiv = document.createElement("div");
@@ -260,8 +266,18 @@ async function transcribe(mode) {
260266
resultDiv.appendChild(resultSpan);
261267

262268
leftColumn.appendChild(wordDiv);
269+
263270
rightColumn.appendChild(resultDiv);
264271
}
272+
const leftTTSButton = document.createElement("button");
273+
leftTTSButton.className = "fa fa-volume-down audio-popup-line";
274+
275+
leftColumn.prepend(leftTTSButton);
276+
277+
const rightTTSButton = document.createElement("button");
278+
rightTTSButton.className = "fa fa-volume-down audio-popup-line";
279+
280+
rightColumn.prepend(rightTTSButton);
265281

266282
container.appendChild(leftColumn);
267283
container.appendChild(rightColumn);
@@ -397,7 +413,7 @@ const languages = {
397413
ttsCode: "es-ES",
398414
},
399415
French: {
400-
styles: ["Default"],
416+
styles: ["Default", "Parisian (experimental)"],
401417
forms: ["Phonemic"],
402418
langCode: "fr",
403419
ttsCode: "fr-FR",
@@ -485,6 +501,12 @@ async function updateOptionsUponLanguageSelection(event) {
485501
if (!(selectedLanguage in loadedLanguages)) {
486502
disableAll();
487503
await loadLanguage(lang.langCode);
504+
if (selectedLanguage === "Latin") {
505+
updateLoadingText("Macrons list", "");
506+
await macronize("");
507+
updateLoadingText("", "");
508+
}
509+
488510
if (selectedLanguage === "German") {
489511
updateLoadingText("German lexicon", "");
490512
globalThis.lexicon = await loadLexicon("German");

wiktionary_pron/scripts/tts.js

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,60 @@ function populateVoiceList() {
2121
}
2222

2323
populateVoiceList();
24+
25+
function getSelectedVoice() {
26+
const voices = EasySpeech.voices();
27+
const selectedVoice = document
28+
.querySelector("#tts")
29+
.selectedOptions[0].getAttribute("data-name");
30+
31+
return voices.find((v) => v.name === selectedVoice);
32+
}
2433
function tts(transcriptionMode) {
2534
console.log("running tts");
2635
const text_els =
2736
transcriptionMode === "line"
2837
? document.querySelectorAll(".input_text")
2938
: document.querySelectorAll("#result span");
3039

40+
const lineButtons = document.querySelectorAll(".audio-popup-line");
41+
42+
const getVolume = () => {
43+
return parseFloat(document.querySelector("#tts_volume").value) / 100;
44+
};
45+
const getSpeed = () => {
46+
return parseFloat(document.querySelector("#tts_speed").value) / 100;
47+
};
48+
49+
lineButtons.forEach((button) => {
50+
button.addEventListener("click", (e) => {
51+
button = e.currentTarget;
52+
let lineText = Array.from(
53+
button.parentElement.querySelectorAll(".input_text"),
54+
)
55+
.map((x) => x.textContent)
56+
.join(" ");
57+
console.log(5555, lineText);
58+
if (!lineText) {
59+
lineText = Array.from(button.parentElement.querySelectorAll(".ipa"))
60+
.map((x) => x.getAttribute("data-word"))
61+
.join(" ");
62+
console.log(5555, lineText);
63+
}
64+
65+
console.log("Speaking:", lineText);
66+
EasySpeech.speak({
67+
text: lineText,
68+
voice: getSelectedVoice(),
69+
pitch: 1,
70+
rate: getSpeed(),
71+
volume: getVolume(),
72+
// there are more events, see the API for supported events
73+
boundary: () => console.debug("boundary reached"),
74+
});
75+
});
76+
});
77+
3178
Array.from(text_els).map(function (el) {
3279
let timer;
3380
const popup = el.previousElementSibling;
@@ -48,22 +95,13 @@ function tts(transcriptionMode) {
4895
return text;
4996
}
5097

51-
function getSelectedVoice() {
52-
const voices = EasySpeech.voices();
53-
const selectedVoice = document
54-
.querySelector("#tts")
55-
.selectedOptions[0].getAttribute("data-name");
56-
57-
return voices.find((v) => v.name === selectedVoice);
58-
}
59-
6098
popup.addEventListener("click", () =>
6199
EasySpeech.speak({
62100
text: getTextContent(el),
63101
voice: getSelectedVoice(),
64102
pitch: 1,
65-
rate: 1,
66-
volume: 1,
103+
rate: getSpeed(),
104+
volume: getVolume(),
67105
// there are more events, see the API for supported events
68106
boundary: () => console.debug("boundary reached"),
69107
}),

wiktionary_pron/scripts/utils.js

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,11 @@ async function wait(ms = 1) {
7777
}
7878

7979
function clearStorage() {
80-
const cache = JSON.parse(localStorage.getItem("get_ipa_no_cache") || "{}");
81-
cache["get_ipa_no_cache"] = "";
82-
localStorage.setItem("get_ipa_no_cache", JSON.stringify(cache));
80+
// const cache = JSON.parse(localStorage.getItem("get_ipa_no_cache") || "{}");
81+
// cache["get_ipa_no_cache"] = "";
82+
// localStorage.setItem("get_ipa_no_cache", JSON.stringify(cache));
83+
localStorage.clear();
84+
localforage.clear();
8385
}
8486

8587
function get_ipa_no_cache(text, args) {
@@ -150,6 +152,7 @@ function get_ipa_no_cache(text, args) {
150152
if (langForm === "Phonemic") {
151153
command = `(window.fr_ipa.show("${cleanText}")[0])`;
152154
}
155+
153156
break;
154157
case "Ukrainian":
155158
if (langForm === "Phonetic") {
@@ -225,6 +228,14 @@ function get_ipa_no_cache(text, args) {
225228
return { value: text, status: "error" };
226229
}
227230

231+
if (langStyle === "Parisian (experimental)") {
232+
ipa = ipa
233+
.replace("ɔ̃̃̃̃̃", "õ")
234+
.replace("ɑ̃", "ɔ̃")
235+
.replace("œ̃", "ɑ̃")
236+
.replace("ɛ̃", "ɑ̃");
237+
}
238+
228239
console.log("final ipa ", ipa);
229240
return { value: ipa, status: "success" };
230241
}
@@ -402,10 +413,10 @@ function disableAll(include_elements = []) {
402413
// Iterate through each form and disable all its elements
403414
forms.forEach((form) => {
404415
Array.from(form.elements)
405-
.concat(include_elements)
406-
.forEach((element) => {
407-
element.disabled = true;
408-
});
416+
.concat(include_elements)
417+
.forEach((element) => {
418+
element.disabled = true;
419+
});
409420
});
410421
}
411422

0 commit comments

Comments
 (0)