コエポチ | 音声読み上げ&翻訳 ボタンポチポチで音声チャット
入力した文章を機械音声に変換するWebサービス。海外に旅行いくときや、病気で声が出ないとき、無言勢の音声チャット、英会話・英単語の学習に使えます。
定型文/日常会話
カスタム/固有名詞/名前など (改行区切り)
音声の設定::
単語だけで喋ってもいいし、単語をつなげてまとまった文章に翻訳できます
中国語、フランス語、ドイツ語など多言語対応
(人工音声の種類・性能は端末環境依存です)
これだけで1週間ぐらい生活や会話をしてみてほしい
Windows10のGoogleChrome, Android/iPhoneで音声動作確認済 2022/07時点
windows10 GoogleChromeだと「Microsoft Ayumi - Japanese (Japan)」「Google 日本語」「Google US」のような音声候補が表示される。
iPhone Safariの場合は「Kyoko」「Karen」のような仮人名のみ。
Android GoogleChromeの場合は「日本語 日本」「英語 アメリカ語」のような候補名になる。
Yes No 私 は を も に と か で が 、 1 2 3 4 5 6 7 8 9 0
view source
JavaScript
//https://developer.mozilla.org/ja/docs/Web/API/SpeechSynthesis
var url = new URL(location);
var params = new URLSearchParams(location.search.slice(1));
var $DEMO = $('#freeText');
var $text = $('#text');
var $textEn = $('#textEn');
var ch = '';
var Speech = {
voices: null,
synthes: null,
init: function(){
var o = this;
o.loadVoices();
o.synthes = new SpeechSynthesisUtterance();
},
loadVoices: function(){
var o = this;
o.voices = window.speechSynthesis.getVoices();
},
say: function(msgText, voiceName){
var o = this;
o.synthes.voice = null;
if(voiceName){
for (var i = 0; i < o.voices.length; i++){
if (o.voices[i].name == voiceName)
o.synthes.voice = o.voices[i];
}
}
o.sayStop();
o.synthes.text = msgText;
speechSynthesis.speak(o.synthes);
},
sayStop: function(){
speechSynthesis.cancel();
}
}
var View = {
getVoiceButtons : function(voices){
var buttons = document.createElement('div');
buttons.id = 'langs';
for (var i = 0; i < voices.length; i++){
var voice = voices[i];
var button = document.createElement('button');
button.textContent = voice.name;
button.setAttribute('title', voice.lang);
buttons.appendChild(button);
}
return buttons;
}
}
var App = {
el: {
getVoiceBtn : $DEMO[0].querySelector('.getVoiceBtn'),
getTextInput : $DEMO[0].querySelector('#text'),
},
init: function(){
var o = this;
Speech.init();
o.el.getVoiceBtn.addEventListener('click', function(){
o.showVoiceButtons();
this.remove();
}, false);
o.el.getTextInput.addEventListener('keyup', function(){
if(!$('#keyup').prop('checked')){
return;
}
Speech.say(
$('#text').val(),
ch,
);
}, false);
},
showVoiceButtons : function(){
Speech.loadVoices();
var buttons = View.getVoiceButtons(Speech.voices)
buttons.addEventListener('click', function(evt){
var v = $('#text').val();
var btn = $(evt.target);
var voiceName = btn.text();
var lang = btn.attr('title');
console.log(lang);
lang = lang.replace(/-.*/,'');
talk(v,null,voiceName);
//ch = evt.target.textContent,
//Speech.say(
// v,
// evt.target.textContent,
//);
if($('#trans').prop('checked')){
transEn(v, lang, voiceName);
}
}, false);
$DEMO[0].appendChild(buttons);
}
}
App.init();
var voices = window.speechSynthesis.getVoices();
var voiceJa = voices[5];
var voiceEn = voices[5];
setTimeout(function(){
initVoice();
}, 99);
setTimeout(function(){
var v = params.get('text');
if(v){
$text.val(v);
talk(v);
console.log(v);
document.title = v + ' | ' + document.title;
}
$DEMO[0].querySelector('.getVoiceBtn').click();
initVoice();
}, 999);
$(document).on('click', '#talk', function(){
var v = $text.val();
talk(v);
if($('#trans').prop('checked')){
$textEn.val('');
transEn(v);
//var vEn = $textEn.val();
//talk(vEn, 'en');
}
});
$(document).on('click', '#clear', function(){
$text.val('');
$textEn.val('');
});
$(document).on('click', '#full', function(){
$('#text')[0].requestFullscreen();
$('#text').css({fontSize:'10vw'});
});
//var texts = $('#serifText').text().split("\n");
var $serif = $('#serif');
$.get('/csv/serif.txt', function(data){
console.log(data);
var texts = data.split("\n");
texts.forEach(function(v){
if(v.match(/==/)){
setHead(v, $serif);
} else {
setBtn(v, $serif);
}
});
});
$('#customSerif').on('change', function(){
var texts = $(this).val().split("\n");
texts.forEach(function(v){
setBtn(v, $serif);
});
});
var transURL = 'https://script.google.com/macros/s/AKfycbyBRpvqb5PE5w3UBf7PIq2PUF1JNONfjb1WWRaNCg6c9kbdMsVKohiUWV0opjnOQ8Qtmw/exec';
var charTexts = $('#charText').text().split("\n");
var $char = $('#char');
charTexts.forEach(function(v, i){
if(i===12){
$char.append($('<br>'));
}
setBtn(v, $char);
});
function initVoice(){
voices = window.speechSynthesis.getVoices();
console.log(voices);
var isFindvoiceJa = false;
var isFindvoiceEn = false;
voices.forEach(function(v){
if(!isFindvoiceJa){
if(v.lang.match(/ja-JP/)){
console.log(v);
voiceJa = v;
isFindvoiceJa = true;
}
}
if(!isFindvoiceEn){
if(v.name.match(/en-US/)){
console.log(v);
voiceEn = v;
isFindvoiceEn = true;
}
}
});
voices.forEach(function(v){
console.log(v);
if(!isFindvoiceJa){
if(v.name.match(/日本/) || v.name.match(/Japan/) || v.name.match(/Kyoko/)){
voiceJa = v;
isFindvoiceJa = true;
}
}
if(!isFindvoiceEn){
if(v.name.match(/Eng/) || v.name.match(/アメリカ/)){
voiceEn = v;
isFindvoiceEn = true;
}
}
});
console.log(voiceJa);
console.log(voiceEn);
var pJa = document.createElement('p');
pJa.textContent = voiceJa.name + ':' + voiceJa.lang;
$serif[0].appendChild(pJa);
var pEn = document.createElement('p');
pEn.textContent = voiceEn.name + ':' + voiceEn.lang;
$serif[0].appendChild(pEn);
}
function talk(v, lang='ja', voiceName){
if(!v){return;}
if(v.length < 2){
if(v.match(/[\.,。、]/)){
return;
}
}
var utter = new SpeechSynthesisUtterance(v);
if(lang === 'en'){
utter.voice = voiceEn;
} else {
utter.voice = voiceJa;
}
var volume = Number($('#volume').val()) || 1;
utter.volume = volume;
var rate = Number($('#rate').val()) || 1;
if(lang !== 'ja' && rate > 1.5){
rate = 1.5;
}
utter.rate = rate;
var pitch = Number($('#pitch').val()) || 1;
utter.pitch = pitch;
if(voiceName){
for(var i = 0; i < voices.length; i++){
if(voices[i].name == voiceName){
utter.voice = voices[i];
}
}
}
console.log(v + ':' + lang + ':' + utter.voice.name);
window.speechSynthesis.speak(utter);
}
function setHead(v, ele){
v = v.replace(/==/, '');
var head = document.createElement('h4');
head.textContent = v;
head.setAttribute('class', v);
ele[0].appendChild(head);
$(head).on('click', function(){
var ele = $(this);
clickAction(ele);
});
$a = $('<a>', {href:'#'}).text(v);
$a.on('click', function(){
var target = $('#demo').find('.'+v).eq(0);
var top = target.offset().top - 160;
$('html,body').animate({scrollTop:top});
return false;
});
$('#category').append($a);
}
function setBtn(v, ele){
if(!v){return;}
var $button = $('<a>', {href:'?text='+v});
$button.text(v);
if(v.length>6){
$button.addClass('long');
}
$button.on('click', function(){
var ele = $(this);
clickAction(ele);
return false;
});
ele.append($button);
}
function clickAction(ele){
var v = ele.text();
window.speechSynthesis.cancel()
talk(v);
ele.addClass('pushed');
$text.val($text.val() +' '+ v);
if($('#trans').prop('checked')){
transEn(v);
}
}
function transEn(v, lang='en', voiceName){
$.get(transURL, { text: v, source: 'ja',target: lang },
function(data){
var v = data;
talk(v, 'en', voiceName);
$textEn.val($textEn.val() +' '+ v);
var vDic = v.split(' ')[0];
vDic = vDic.replace(/Please/im, '');
var $dic = $('#dictionary');
var href = $dic.attr('href-src') + vDic;
$dic.attr({'href':href, 'title':vDic});
});
}
var $shareBtn = $('<button>',{title:'twitterに共有!'}).text('twitterに共有!');
$serif.before($shareBtn);
$shareBtn.on('click', function(){
var v = $text.val();
if(!v){return;}
var url = location.href +'?text='+ encodeURIComponent(v);
v = encodeURI(v ,url);
share(v);
});
var share = function(message, url='hi0a.com') {
var url = encodeURIComponent(location.href);
window.open('https://twitter.com/intent/tweet?text='+message+'&url='+url);
}
//https://script.google.com
/*
function doGet(e) {
var p = e.parameter;
var translatedText = LanguageApp.translate(p.text, p.source, p.target);
return ContentService.createTextOutput(translatedText);
}
*/
CSS
#code{
display:none;
}
#textarea{
position:fixed;
top:0;
left:0;
width:100%;
background-color:#fff;
font-size:12px;
}
#textarea > *{
display:block;
}
#textarea a{
display:inline-block;
color:#555;
line-height:24px;
}
#textarea a:vlink{
color:#999;
}
textarea{
width:99%;
height:2em;
}
#btns button{
min-width:20vw;
padding:8px 0;
}
textarea#textEn{
height:2em;
background-color:#eee;
color:#444;
}
#textarea nav a{
display:inline-block;
font-size:12px;
line-height:12px;
margin:1px 4px;
padding:8px 0;
color:#888;
}
#textarea nav a:hover{
color:#222;
}
#char a,
#serif a{
display:inline-block;
color:#000;
text-align:center;
text-decoration:none;
width:24.8%;
height:28px;
line-height:28px;
background-color: transparent;
border: none;
cursor: pointer;
outline: none;
padding: 0;
appearance: none;
overflow:hidden;
vertical-align:top;
}
#char a{
width:8%;
}
#serif a:hover,
#char a:hover{
background-color:#eee;
}
#serif a.long{
font-size:0.6rem;
}
#textarea button{
border: 1px solid #888;
background-color: #ddd;
}
button:hover{
background-color: #ccc;
}
button.pushed{
font-weight:bold;
background-color: #eee;
}
#char{
position:fixed;
bottom:0;
left:0;
width:100%;
background-color:#fff;
}
#customSerif{
height:8em;
}
#langs button{
color:#333;
}
#control label,
#control input[type="range"]{
display:block;
width:90%;
}
pre{
display:none;
}
#demo h1{
margin-top:160px;
font-size:18px;
line-height:18px;
}
h4{
font-weight:bold;
padding-top:8px;
padding-left:2em;
}
HTML
ページのソースを表示 : Ctrl+U , DevTools : F12
view-source:https://hi0a.com/demo/-js/js-speech-voice/
ABOUT
hi0a.com 「ひまアプリ」は無料で遊べるミニゲームや便利ツールを公開しています。
プログラミング言語の動作デモやWEBデザイン、ソースコード、フロントエンド等の開発者のための技術を公開しています。
必要な機能の関数をコピペ利用したり勉強に活用できます。
プログラムの動作サンプル結果は画面上部に出力表示されています。
環境:最新のブラウザ GoogleChrome / Windows / Android / iPhone 等の端末で動作確認しています。
画像素材や音素材は半分自作でフリー素材配布サイトも利用しています。LINK参照。
動く便利なものが好きなだけで技術自体に興味はないのでコードは汚いです。
途中放置や実験状態、仕様変更、API廃止等で動かないページもあります。