improve round speech synthesis
This commit is contained in:
parent
520939fa66
commit
f953317546
5
ui/@types/lichess/index.d.ts
vendored
5
ui/@types/lichess/index.d.ts
vendored
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(() => {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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') : ''
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue