Update audio controller (#904)

* Remove redundant assignment of select value

* Update TTS preparation

* Don't hide options

* Improve voice sorting

* Update event handler

* Apply options to all selects targeting audio.textToSpeechVoice

* Update selector

* Use IDs

* Move test text to a hidden text input
This commit is contained in:
toasted-nutbread 2020-10-10 12:11:33 -04:00 committed by GitHub
parent 6799b87cc6
commit 3174f3c657
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 59 deletions

View File

@ -28,18 +28,25 @@ class AudioController {
this._audioSourceContainer = null;
this._audioSourceAddButton = null;
this._audioSourceEntries = [];
this._ttsVoiceTestTextInput = null;
}
async prepare() {
this._audioSystem.prepare();
this._audioSourceContainer = document.querySelector('.audio-source-list');
this._audioSourceAddButton = document.querySelector('.audio-source-add');
this._ttsVoiceTestTextInput = document.querySelector('#text-to-speech-voice-test-text');
this._audioSourceContainer = document.querySelector('#audio-source-list');
this._audioSourceAddButton = document.querySelector('#audio-source-add');
this._audioSourceContainer.textContent = '';
this._audioSourceAddButton.addEventListener('click', this._onAddAudioSource.bind(this), false);
this._prepareTextToSpeech();
if (typeof speechSynthesis !== 'undefined') {
speechSynthesis.addEventListener('voiceschanged', this._updateTextToSpeechVoices.bind(this), false);
}
this._updateTextToSpeechVoices();
document.querySelector('#text-to-speech-voice-test').addEventListener('click', this._onTestTextToSpeech.bind(this), false);
this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this));
@ -59,57 +66,62 @@ class AudioController {
}
}
_prepareTextToSpeech() {
if (typeof speechSynthesis === 'undefined') { return; }
_onTestTextToSpeech() {
try {
const text = this._ttsVoiceTestTextInput.value || '';
const voiceUri = document.querySelector('[data-setting="audio.textToSpeechVoice"]').value;
speechSynthesis.addEventListener('voiceschanged', this._updateTextToSpeechVoices.bind(this), false);
this._updateTextToSpeechVoices();
document.querySelector('#text-to-speech-voice').addEventListener('change', this._onTextToSpeechVoiceChange.bind(this), false);
document.querySelector('#text-to-speech-voice-test').addEventListener('click', this._testTextToSpeech.bind(this), false);
const audio = this._audioSystem.createTextToSpeechAudio(text, voiceUri);
audio.volume = 1.0;
audio.play();
} catch (e) {
// NOP
}
}
_updateTextToSpeechVoices() {
const voices = Array.prototype.map.call(speechSynthesis.getVoices(), (voice, index) => ({voice, index}));
const voices = (
typeof speechSynthesis !== 'undefined' ?
[...speechSynthesis.getVoices()].map((voice, index) => ({
voice,
isJapanese: this._languageTagIsJapanese(voice.lang),
index
})) :
[]
);
voices.sort(this._textToSpeechVoiceCompare.bind(this));
document.querySelector('#text-to-speech-voice-container').hidden = (voices.length === 0);
for (const select of document.querySelectorAll('[data-setting="audio.textToSpeechVoice"]')) {
const fragment = document.createDocumentFragment();
const fragment = document.createDocumentFragment();
let option = document.createElement('option');
option.value = '';
option.textContent = 'None';
fragment.appendChild(option);
for (const {voice} of voices) {
option = document.createElement('option');
option.value = voice.voiceURI;
option.textContent = `${voice.name} (${voice.lang})`;
let option = document.createElement('option');
option.value = '';
option.textContent = 'None';
fragment.appendChild(option);
}
const select = document.querySelector('#text-to-speech-voice');
select.textContent = '';
select.appendChild(fragment);
select.value = select.dataset.value;
for (const {voice} of voices) {
option = document.createElement('option');
option.value = voice.voiceURI;
option.textContent = `${voice.name} (${voice.lang})`;
fragment.appendChild(option);
}
select.textContent = '';
select.appendChild(fragment);
}
}
_textToSpeechVoiceCompare(a, b) {
const aIsJapanese = this._languageTagIsJapanese(a.voice.lang);
const bIsJapanese = this._languageTagIsJapanese(b.voice.lang);
if (aIsJapanese) {
if (!bIsJapanese) { return -1; }
if (a.isJapanese) {
if (!b.isJapanese) { return -1; }
} else {
if (bIsJapanese) { return 1; }
if (b.isJapanese) { return 1; }
}
const aIsDefault = a.voice.default;
const bIsDefault = b.voice.default;
if (aIsDefault) {
if (!bIsDefault) { return -1; }
if (a.voice.default) {
if (!b.voice.default) { return -1; }
} else {
if (bIsDefault) { return 1; }
if (b.voice.default) { return 1; }
}
return a.index - b.index;
@ -123,19 +135,6 @@ class AudioController {
);
}
_testTextToSpeech() {
try {
const text = document.querySelector('#text-to-speech-voice-test').dataset.speechText || '';
const voiceUri = document.querySelector('#text-to-speech-voice').value;
const audio = this._audioSystem.createTextToSpeechAudio(text, voiceUri);
audio.volume = 1.0;
audio.play();
} catch (e) {
// NOP
}
}
_getUnusedAudioSource() {
const audioSourcesAvailable = [
'jpod101',
@ -195,10 +194,6 @@ class AudioController {
this._audioSourceEntries.splice(index, 1);
}
_onTextToSpeechVoiceChange(e) {
e.currentTarget.dataset.value = e.currentTarget.value;
}
async _onAddAudioSource() {
const audioSource = this._getUnusedAudioSource();
const index = this._audioSourceEntries.length;

View File

@ -346,14 +346,15 @@
<input type="number" min="0" max="100" id="audio-playback-volume" class="form-control" data-setting="audio.volume">
</div>
<div class="form-group" id="text-to-speech-voice-container" hidden>
<div class="form-group" id="text-to-speech-voice-container">
<label for="text-to-speech-voice">Text-to-speech voice</label>
<div class="input-group">
<select class="form-control" id="text-to-speech-voice" data-setting="audio.textToSpeechVoice"></select>
<div class="input-group-btn">
<button class="btn btn-default" id="text-to-speech-voice-test" title="Test voice" data-speech-text="よみちゃん"><span class="glyphicon glyphicon-volume-up"></span></button>
<button class="btn btn-default" id="text-to-speech-voice-test" title="Test voice"><span class="glyphicon glyphicon-volume-up"></span></button>
</div>
</div>
<input type="text" value="よみちゃん" id="text-to-speech-voice-test-text" hidden>
</div>
<div class="form-group options-advanced">
@ -363,9 +364,9 @@
<div class="form-group ignore-form-changes">
<label>Audio playback sources</label>
<div class="audio-source-list generic-input-list"></div>
<div class="audio-source-list generic-input-list" id="audio-source-list"></div>
<div class="input-group audio-source-options">
<button class="btn btn-default audio-source-add" title="Add audio playback source"><span class="glyphicon glyphicon-plus"></span></button>
<button class="btn btn-default audio-source-add" title="Add audio playback source" id="audio-source-add"><span class="glyphicon glyphicon-plus"></span></button>
</div>
<template id="audio-source-template"><div class="input-group audio-source">