Advertisement
caLLowCreation

naivebot audio-helper

Feb 11th, 2020
223
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. const path = window.location.pathname;
  3. const page = path.split("/").pop();
  4.  
  5. function playAudio(path, volume, callback) {
  6.     return new Promise((resolve) => {
  7.         _playSound.play(path, volume, callback).then(() => {
  8.             audio = null;
  9.             resolve({ success: true, resultText: `audio played: ${path}`, path: path });
  10.         }).catch((error) => {
  11.             audio = null;
  12.             resolve({ success: false, resultText: error, path: path });
  13.         });
  14.     });
  15. }
  16.  
  17. const _playSound = {
  18.     clearSound: () => {
  19.         Object.values(_playSound.activeAudio).map(function (a) {
  20.             a.pause();
  21.             a.currentTime = 0;
  22.         })
  23.         _playSound.activeAudio = {};
  24.     },
  25.     activeAudio: {},
  26.     play: (path, volume, callback) => {
  27.         let timeStamp = Date.now();
  28.         _playSound.activeAudio[timeStamp] = new Audio(path);
  29.         _playSound.activeAudio[timeStamp].volume = volume || 0.5;
  30.         _playSound.activeAudio[timeStamp].addEventListener('error', function () {
  31.             _playSound.activeAudio[timeStamp] = null;
  32.             delete _playSound.activeAudio[timeStamp];
  33.         }, false);
  34.         _playSound.activeAudio[timeStamp].addEventListener("ended", function () {
  35.  
  36.             if (callback) {
  37.                 callback();
  38.             }
  39.             _playSound.activeAudio[timeStamp] = null;
  40.             delete _playSound.activeAudio[timeStamp];
  41.         }, false);
  42.  
  43.         return _playSound.activeAudio[timeStamp].play();
  44.     },
  45.     soundQue: {
  46.         list: [],
  47.         active: false,
  48.         add: (path, volume) => {
  49.             _playSound.soundQue.list.push([path, volume]);
  50.             if (!_playSound.soundQue.active) {
  51.                 _playSound.soundQue.play();
  52.             }
  53.         },
  54.         play: (data) => {
  55.             if (_playSound.soundQue.list.length > 0) {
  56.                 let res = _playSound.soundQue.list.shift();
  57.                 _playSound.soundQue.active = true;
  58.                 _playSound.play(res[0], res[1], function () {
  59.                     if (_playSound.soundQue.list.length > 0) {
  60.                         setTimeout(() => _playSound.soundQue.play(), 1000);
  61.                     }
  62.                     else {
  63.                         _playSound.soundQue.active = false;
  64.                     }
  65.                 });
  66.             }
  67.         }
  68.     }
  69. }
  70.  
  71. const speech = {
  72.     utterances: [],
  73.     playing: false
  74. };
  75.  
  76. function speechPlayer() {
  77.  
  78.     if (speech.playing === true) return;
  79.     if (speech.utterances.length === 0) return;
  80.     speech.playing = true;
  81.  
  82.     const msg = speech.utterances.shift();
  83.  
  84.     msg.onstart = (event) => {
  85.         sentActionToServer(true, 'onstart', msg.text, event);
  86.     }
  87.  
  88.     msg.onerror = (event) => {
  89.         sentActionToServer(false, 'onerror', event.utterance.text, event);
  90.         speech.playing = false;
  91.         speechPlayer();
  92.     }
  93.     speechUtteranceChunker(msg, null, (result) => {
  94.         console.log(result);
  95.         if (result.success === true) {
  96.             sentActionToServer(true, 'onend', msg.text, event);
  97.             speech.playing = false;
  98.             speechPlayer();
  99.         } else {
  100.             sentActionToServer(false, 'onend', msg.text, event);;
  101.             speech.playing = false;
  102.             speechPlayer();
  103.         }
  104.     });
  105. }
  106.  
  107. function optionSpeech(index, volume, rate, pitch, text) {
  108.     //speechSynthesis.cancel();
  109.     const msg = new SpeechSynthesisUtterance();
  110.     msg.voice = speechSynthesis.getVoices()[index];
  111.     msg.voiceURI = 'native';
  112.     msg.volume = volume;
  113.     msg.rate = rate;
  114.     msg.pitch = pitch;
  115.     msg.lang = 'en-GB';
  116.     msg.text = text;
  117.  
  118.     speech.utterances.push(msg);
  119.     speechPlayer();
  120. }
  121.  
  122. function sentActionToServer(success, name, msg, event) {
  123.     if (socket) {
  124.         if (socket.emit) {
  125.             socket.emit('speech-synthesis', { success: success, action: name, text: msg, page: page, event: event });
  126.         }
  127.     }
  128. }
  129.  
  130. function resetVoice() {
  131.     speechSynthesis.cancel();
  132. }
  133.  
  134. function stopTTS() {
  135.     resetVoice();
  136. }
  137.  
  138. /**
  139.  * Chunkify
  140.  * Google Chrome Speech Synthesis Chunking Pattern
  141.  * Fixes inconsistencies with speaking long texts in speechUtterance objects
  142.  * Licensed under the MIT License
  143.  * https://gist.github.com/woollsta/2d146f13878a301b36d7#file-chunkify-js
  144.  * Peter Woolley and Brett Zamir
  145.  */
  146. const speechUtteranceChunker = (utt, settings, callback) => {
  147.    
  148.     settings = settings || {};
  149.     let newUtt;
  150.     const txt = (settings && settings.offset !== undefined ? utt.text.substring(settings.offset) : utt.text);
  151.     if (utt.voice && utt.voice.voiceURI === 'native') { // Not part of the spec
  152.         newUtt = utt;
  153.         newUtt.text = txt;
  154.         newUtt.addEventListener('end', (event) => {
  155.             if (speechUtteranceChunker.cancel) {
  156.                 speechUtteranceChunker.cancel = false;
  157.             }
  158.             if (callback !== undefined) {
  159.                 callback({ success: false, event: event });
  160.             }
  161.         });
  162.     }
  163.     else {
  164.         const chunkLength = (settings && settings.chunkLength) || 160;
  165.         const pattRegex = new RegExp('^[\\s\\S]{' + Math.floor(chunkLength / 2) + ',' + chunkLength + '}[.!?,]{1}|^[\\s\\S]{1,' + chunkLength + '}$|^[\\s\\S]{1,' + chunkLength + '} ');
  166.         const chunkArr = txt.match(pattRegex);
  167.  
  168.         if (chunkArr[0] === undefined || chunkArr[0].length <= 2) {
  169.             //call once all text has been spoken...
  170.             if (callback !== undefined) {
  171.                 callback({ success: true });
  172.             }
  173.             return;
  174.         }
  175.         const chunk = chunkArr[0];
  176.         newUtt = new SpeechSynthesisUtterance(chunk);
  177.         let x;
  178.         for (x in utt) {
  179.             if (utt[x] && x !== 'text') {
  180.                 newUtt[x] = utt[x];
  181.             }
  182.         }
  183.         newUtt.addEventListener('end', () => {
  184.             if (speechUtteranceChunker.cancel) {
  185.                 speechUtteranceChunker.cancel = false;
  186.                 return;
  187.             }
  188.             settings.offset = settings.offset || 0;
  189.             settings.offset += chunk.length - 1;
  190.             speechUtteranceChunker(utt, settings, callback);
  191.         });
  192.     }
  193.  
  194.     if (settings.modifier) {
  195.         settings.modifier(newUtt);
  196.     }
  197.     console.log(newUtt); //IMPORTANT!! Do not remove: Logging the object out fixes some onend firing issues.
  198.     //placing the speak invocation inside a callback fixes ordering and onend issues.
  199.     setTimeout(() => {
  200.         speechSynthesis.speak(newUtt);
  201.     }, 0);
  202. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement