Merci Gilles. Tu peux attacher un fichier, ça fonctionne sur la GUILDE.
Le lun. 20 nov. 2023 à 12:48, Yves Gufflet <yves.gufflet@???> a écrit :
>
> Bonjour,
>
> Le fichier joint répond à la demande (j'ai du mal à expédier le fichier
> en html non supporté par la liste, il faut recopier le texte et le
> mettre dans un fichier html)
>
> Il s'agit d'un simple fichier que l'on peut ouvrir avec son navigateur
> et sans besoin d'un serveur web.
>
> Il utilise la fonctionnalité SpeechSynthetizer du navigateur.
>
> Cette fonctionnalité est expérimentale et certaines choses bugs en
> fonction du navigateur : ici le curseur ne suit pas le texte lu et la
> pause et le résume ne marche pas.
>
> Les voix sous chrome sont naturelles. Sous FF elles sont très robotisés.
>
> Yves
>
> <!DOCTYPE html>
> <html lang="fr-FR">
> <head>
> <meta charset="UTF-8" />
> <meta name="viewport" content="width=device-width,
> initial-scale=1.0" />
> <title>Text to Speech</title>
> <style>
>
> html,
> body
> {
> width : 100%;
> height : 100%;
> margin : 0px;
> padding : 0px;
> }
>
> #texttospeak,
> #textbeingspoken
> {
> margin:0px;
> width : 50%;
> height : 50%;
> }
>
> #controllers
> {
> position:absolute;
> top:0px;
> right:0px;
> width : 50%;
> height : 100%;
> display:flex;
> flex-direction:column;
> row-gap:20px;
> align-items : center;
> padding : 20px;
> }
>
> #controllers > *
> {
> display:flex;
> }
>
> .speecharg label
> {
> margin-right:10px;
> font-weight:bold;
> width : 100px;
> text-align:right;
> }
>
> .speecharg input,
> .speecharg select
> {
> width : 200px;
> }
>
> #start
> {
> margin:10px;
> font-weight:bold;
> }
>
> #start.started
> {
> background: red;
> }
>
> #marker
> {
> position:absolute;
> top:0px;
> left:0px;
> z-index:10;
> width:10px;
> height:10px;
> background:black;
> }
>
> </style>
>
> <script>
>
> var texttospeak;
> var textbeingspoken;
> var marker;
> var range;
> var firstBoundary;
> var voices = [];
> var utterance;
>
> function populateVoiceList()
> {
> voices = window.speechSynthesis.getVoices();
> var selectElm = document.querySelector('#voice');
> selectElm.innerHTML = '';
>
> voices.sort ((a, b) => { return a.name > b.name; })
>
> var selected = false;
>
> for (var i=0;i < voices.length;i++)
> {
> var option = document.createElement('option');
> option.innerHTML = voices[i].name + ' (' + voices[i].lang + ')';
> option.setAttribute('value', voices[i].voiceURI);
> option.voice = voices[i];
> if (!selected && (voices[i].lang == "fr-FR"))
> {
> selected = true;
> option.selected = true;
> }
> selectElm.appendChild(option);
> }
> }
>
> function stop()
> {
> speechSynthesis.cancel();
> }
>
> function pauseresume()
> {
> if (speechSynthesis.paused)
> speechSynthesis.resume();
> else
> speechSynthesis.pause();
> }
>
> function start()
> {
> firstBoundary = true;
>
> utterance = new SpeechSynthesisUtterance(texttospeak.value);
>
> textbeingspoken.textContent = texttospeak.value;
>
> utterance.voice = voices[document.getElementById('voice').selectedIndex];
> utterance.volume = document.getElementById('volume').value;
> utterance.pitch = document.getElementById('pitch').value;
> var rate = document.getElementById('rate').value;
> utterance.rate = Math.pow(Math.abs(rate) + 1, rate < 0 ? -1 : 1);
>
> utterance.addEventListener('start', function ()
> {
> marker.classList.remove('animate');
> document.body.classList.add('speaking');
> });
>
> utterance.addEventListener('start', handleSpeechEvent);
> utterance.addEventListener('end', handleSpeechEvent);
> utterance.addEventListener('error', handleSpeechEvent);
> utterance.addEventListener('boundary', handleSpeechEvent);
> utterance.addEventListener('pause', handleSpeechEvent);
> utterance.addEventListener('resume', handleSpeechEvent);
>
> speechSynthesis.speak(utterance);
> }
>
> function handleSpeechEvent(e)
> {
> console.log('Speech Event:', e);
>
> switch (e.type)
> {
> case 'start':
> marker.classList.remove('animate');
> document.body.classList.add('speaking');
> break;
> case 'end':
> case 'endEvent':
> case 'error':
> document.body.classList.remove('speaking');
> marker.classList.remove('moved');
> break;
> case 'boundary':
> {
> if (e.name != 'word')
> break;
>
> var substr = speechtext.slice(e.charIndex);
> var rex = /\S+/g;
> var res = rex.exec(substr);
>
> if (!res) return;
>
> var startOffset = res.index + e.charIndex;
> var endOffset = rex.lastIndex + e.charIndex;
>
> range.setStart(textbeingspoken.firstChild, startOffset);
> range.setEnd(textbeingspoken.firstChild, endOffset);
>
> var rect = range.getBoundingClientRect();
> var delta = 0;
>
> var parentRect = textbeingspoken.getBoundingClientRect();
>
> if (rect.bottom > parentRect.bottom) delta = rect.bottom -
> parentRect.bottom;
> if (rect.top < parentRect.top) delta = rect.top - parentRect.top;
>
> textbeingspoken.scrollTop += delta;
>
> texttospeak.scrollTop = textbeingspoken.scrollTop;
>
> marker.style.top = rect.top - delta - 1;
> marker.style.left = rect.left - 1;
> marker.style.width = rect.width + 1;
> marker.style.height = rect.height + 1;
> marker.classList.add('moved');
>
> if (firstBoundary)
> {
> firstBoundary = false;
> marker.classList.add('animate');
> }
>
> break;
> }
> default:
> break;
> }
> }
>
> window.onload = () =>
> {
> texttospeak = document.getElementById('texttospeak');
> textbeingspoken = document.getElementById('textbeingspoken');
> marker = document.getElementById('marker');
> range = document.createRange();
>
> populateVoiceList();
>
> if (speechSynthesis.onvoiceschanged !== undefined)
> speechSynthesis.onvoiceschanged = populateVoiceList;
> };
>
> </script>
>
> </head>
> <body>
> <textarea id="texttospeak">Pour lire ce texte appuyez sur PLAY.
> Pour mettre en pause et résumer la lecture, cliquez sur PAUSE/RESUME.
> Cette fonctionnalité buggue en fonction des plateformes.
> Pour arrêter la lecture, cliquez sur STOP.
> Vous pouvez modifier les paramètres de lecture en ajustant les paramètres.
> Vous devez arrêter et reprendre la lecture pour qu'ils soient pris en
> compte.</textarea>
> <textarea id="textbeingspoken"></textarea>
> <div id="marker"></div>
> <div id="controllers">
> <div class="speecharg">
> <label for="voice">Voice</label><select id="voice"></select>
> </div>
> <div class="speecharg">
> <label for="pitch">Pitch</label><input id="pitch" type="range"
> value="0.5" min="0" max="1" step="0.05">
> </div>
> <div class="speecharg">
> <label for="rate">Rate</label><input id="rate" type="range"
> value="0" min="-3" max="3" step="0.25">
> </div>
> <div class="speecharg">
> <label for="volue">Volume</label><input id="volume" type="range"
> value="1" min="0" max="1" step="0.05">
> </div>
> <button id="start"type="button"
> onmousedown="start();"><strong>PLAY</strong></button>
> <button type="button" aria-label="Pause/Resume" title="Pause/Resume"
> onmousedown="pauseresume();"><strong>RESUME/PAUSE</strong></button>
> <button type="button" aria-label="Cancel" title="Cancel"
> onmousedown="stop();"><strong>STOP</strong></button>
> <div class="bottom"></div>
> </div>
> </body>
> </html>
>