improve round speech synthesis

This commit is contained in:
Thibault Duplessis 2019-04-29 18:34:23 +07:00
parent 520939fa66
commit f953317546
6 changed files with 43 additions and 45 deletions

View file

@ -54,7 +54,10 @@ interface Lichess {
render(ctrl: any): any;
}
playMusic(): any;
RoundSpeech(): any;
Speech?: {
say(t: string, cut?: boolean): void;
step(s: { san?: San }, cut?: boolean): void;
};
spinnerHtml: string;
movetimeChart: any;
hasTouchEvents: boolean;

View file

@ -43,7 +43,7 @@ export function ctrl(raw: string[], trans: Trans, redraw: Redraw, close: Close):
},
volume(v: number) {
api.setVolume(v);
api.move('knight c3');
api.move('knight F 7');
},
redraw,
trans,

View file

@ -21,6 +21,7 @@ import { valid as crazyValid } from './crazy/crazyCtrl';
import { ctrl as makeKeyboardMove, KeyboardMove } from './keyboardMove';
import renderUser = require('./view/user');
import cevalSub = require('./cevalSub');
import viewStatus from 'game/view/status';
import * as keyboard from './keyboard';
import { RoundOpts, RoundData, ApiMove, ApiEnd, Redraw, SocketMove, SocketDrop, SocketOpts, MoveMetadata, Position, NvuiPlugin } from './interfaces';
@ -69,7 +70,6 @@ export default class RoundController {
nvui?: NvuiPlugin;
private music?: any;
private speech?: any;
constructor(opts: RoundOpts, redraw: Redraw) {
@ -122,11 +122,17 @@ export default class RoundController {
});
if (this.music && set !== 'music') this.music = undefined;
if (!this.speech && set === 'speech')
if (!window.Speech && set === 'speech')
li.loadScript('compiled/lichess.round.speech.min.js').then(() => {
this.speech = li.RoundSpeech();
const s = viewStatus(this);
if (s == 'playingRightNow') window.Speech!.step(this.stepAt(this.ply), false);
else {
window.Speech!.say(s);
const w = this.data.game.winner;
if (w) window.Speech!.say(this.trans.noarg(w + 'IsVictorious'))
}
});
if (this.speech && set !== 'speech') this.speech = undefined;
if (window.Speech && set !== 'music') window.Speech = undefined;
});
li.pubsub.on('zen', () => {
@ -200,7 +206,7 @@ export default class RoundController {
this.cancelMove();
this.chessground.selectSquare(null);
if (!this.jump(ply)) this.redraw();
if (this.speech) this.speech.jump(round.plyStep(this.data, ply));
if (window.Speech) window.Speech.step(this.stepAt(ply));
};
isPlaying = () => game.isPlayerPlaying(this.data);
@ -211,7 +217,7 @@ export default class RoundController {
this.ply = ply;
this.justDropped = undefined;
this.preDrop = undefined;
const s = round.plyStep(this.data, ply),
const s = this.stepAt(ply),
config: CgConfig = {
fen: s.fen,
lastMove: util.uci2move(s.uci),
@ -446,7 +452,7 @@ export default class RoundController {
this.onChange();
if (this.keyboardMove) this.keyboardMove.update(step);
if (this.music) this.music.jump(o);
if (this.speech) this.speech.jump(step, true);
if (window.Speech) window.Speech.step(step, true);
};
private playPredrop = () => {
@ -671,14 +677,16 @@ export default class RoundController {
setChessground = (cg: CgApi) => {
this.chessground = cg;
if (this.data.pref.keyboardMove) {
this.keyboardMove = makeKeyboardMove(this, round.plyStep(this.data, this.ply), this.redraw);
this.keyboardMove = makeKeyboardMove(this, this.stepAt(this.ply), this.redraw);
li.raf(this.redraw);
}
};
private stepAt = (ply: Ply) => round.plyStep(this.data, ply);
private delayedInit = () => {
const d = this.data;
if (this.isPlaying() && !li.sound.say('ready') && game.nbMoves(d, d.player.color) === 0 && !this.isSimulHost()) {
if (this.isPlaying() && game.nbMoves(d, d.player.color) === 0 && !this.isSimulHost()) {
li.sound.genericNotify();
}
li.requestIdleCallback(() => {

View file

@ -1,8 +1,6 @@
import { Step } from '../interfaces';
const roles: { [letter: string]: string } = { P: 'pawn', R: 'rook', N: 'knight', B: 'bishop', Q: 'queen', K: 'king' };
export function renderSan(san: San) {
function renderSan(san: San) {
let move: string;
if (san.includes('O-O-O')) move = 'long castle';
else if (san.includes('O-O')) move = 'short castle';
@ -22,25 +20,13 @@ export function renderSan(san: San) {
return move;
}
window.lichess.RoundSpeech = function() {
const synth = window.speechSynthesis;
const volumeStorage = window.lichess.storage.make('sound-volume');
function say(text: string, queue: boolean = false) {
// console.log(`%c${text} ${queue}`, 'color: red');
const msg = new SpeechSynthesisUtterance(text);
msg.rate = 1.2;
msg.volume = parseFloat(volumeStorage.get());
if (!queue) synth.cancel();
synth.speak(msg);
}
return {
jump(s: Step, queue: boolean = false) {
if (!s) return;
say(s.san ? renderSan(s.san) : 'Game starts', queue);
}
};
export function say(text: string, cut: boolean = false) {
const msg = new SpeechSynthesisUtterance(text);
msg.rate = 1.2;
if (cut) speechSynthesis.cancel();
window.lichess.sound.say(msg);
}
export function step(s: { san?: San}, cut: boolean = true) {
say(s.san ? renderSan(s.san) : 'Game start', cut);
}

View file

@ -62,7 +62,7 @@ export function renderResult(ctrl: RoundController): VNode | undefined {
result = '½-½';
}
if (result || status.aborted(ctrl.data)) {
const winner = game.getPlayer(ctrl.data, ctrl.data.game.winner);
const winner = ctrl.data.game.winner;
return h('div.result-wrap', [
h('p.result', result || ''),
h('p.status', {
@ -72,7 +72,7 @@ export function renderResult(ctrl: RoundController): VNode | undefined {
})
}, [
viewStatus(ctrl),
winner ? ' • ' + ctrl.trans.noarg(winner.color + 'IsVictorious') : ''
winner ? ' • ' + ctrl.trans.noarg(winner + 'IsVictorious') : ''
])
]);
}

View file

@ -586,24 +586,22 @@
var enabled = function() {
return soundSet !== 'silent';
};
var getVolume = function() {
return parseFloat(api.volumeStorage.get() || api.defaultVolume);
}
Object.keys(names).forEach(function(name) {
api[name] = function(text) {
if (!enabled()) return;
if (!text || !api.say(text)) {
Howler.volume(getVolume());
Howler.volume(api.getVolume());
collection(name).play();
}
}
});
api.say = function(text) {
api.say = function(text, cut) {
if (soundSet != 'speech') return false;
var msg = new SpeechSynthesisUtterance(text);
msg.volume = getVolume();
speechSynthesis.cancel();
var msg = text.text ? text : new SpeechSynthesisUtterance(text);
msg.volume = api.getVolume();
if (cut) speechSynthesis.cancel();
speechSynthesis.speak(msg);
console.log(`%c${msg.text}`, 'color: blue');
return true;
};
api.load = function(name) {
@ -613,6 +611,9 @@
api.volumeStorage.set(v);
Howler.volume(v);
};
api.getVolume = function() {
return api.volumeStorage.get() || api.defaultVolume;
};
var publish = function() {
lichess.pubsub.emit('sound_set')(soundSet);