🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

885閲覧

画像と音声を同期させたい

risasayo

総合スコア5

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2019/12/23 04:59

前提・実現したいこと

画像とテキストで入力した音声を同期させたい(”あ”の文字を打ったら画像が”あ”の文字になり、VOCALOIDのようなものを作りたい)

発生している問題・エラーメッセージ

画像と音声を出すことはできたが、その二つを同期させるやり方がどのようなコードを使うのかがわからない

###該当のソースコード
HTML5

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>Talking Face "あ"の修正</title> <link rel="stylesheet" href="talking-face2.css"> <script src="./js/face-animation2.js"></script> <script src="./js/text-to-speech.js"></script> </head> <body>

<canvas id="canvas" width="800" height="750"></canvas>

<textarea id="text" rows="4" cols="40"> あいうえお </textarea>
<br> <input type="button" value="目を動かす" onclick="eyeStart();"> <input type="button" value="口を動かす" onclick="mouthStart();"> <input type="text" id="mouthstatus" value="閉" size="4" style="text-align:center;"> <div id="navigation"> <button id="speak-btn">再生</button> <button id="cancel-btn">停止</button> <button id="pause-btn">一時停止</button> <button id="resume-btn">再開</button> </div> </body>

JavaScript
// 発音記号列
var PronNum = -1; //開始前は-1にしておく
var PronSeq = [ { name: "c", time: 2000 },
{ name: "a", time: 10000 },
{ name: "e", time: 4000 },
{ name: "i", time: 4000 },
{ name: "o", time: 4000 },
{ name: "u", time: 4000 },
{ name: "c", time: 4000 } ];

// canvas変数
var cvs;
var ctx;

// 顔データの保存領域
var img_f = new Image();
var img_eL1 = new Image();
var img_eL2 = new Image();
var img_eL3 = new Image();
var img_eR1 = new Image();
var img_eR2 = new Image();
var img_eR3 = new Image();
var img_mc = new Image();
var img_ma1 = new Image();
var img_ma2 = new Image();
var img_ma3 = new Image();
var img_ma4 = new Image();
var img_mi1 = new Image();
var img_mi2 = new Image();
var img_mu1 = new Image();
var img_mu2 = new Image();
var img_me1 = new Image();
var img_me2 = new Image();
var img_mo1 = new Image();
var img_mo2 = new Image();

// 顔データを取り出す連想配列
var imgdata;

// 表示する顔データ
var img_f = new Image(); //顔
var img_eL = new Image(); //左目
var img_eR = new Image(); //右目
var img_m = new Image(); //口

// タイマー変数
var tickTimeID;
var eyeTimeID, mouthTimeID, PronTimeID;
var eyeNum=mouthNum=1;

//ロード時に実行しておく関数
window.onload = function(){
cvs = document.getElementById("canvas");
ctx = cvs.getContext("2d");

img_f.src = "./img/face_t.png"; img_eL1.src = "./img/eye_L1_t.png"; img_eL2.src = "./img/eye_L2_t.png"; img_eL3.src = "./img/eye_L3_t.png"; img_eR1.src = "./img/eye_R1_t.png"; img_eR2.src = "./img/eye_R2_t.png"; img_eR3.src = "./img/eye_R3_t.png"; img_mc.src = "./img/mouth_c_t.png"; img_ma1.src = "./img/mouth_a1_t.png"; img_ma2.src = "./img/mouth_a2_t.png"; img_ma3.src = "./img/mouth_a3_t.png"; img_ma4.src = "./img/mouth_a4_t.png"; img_mi1.src = "./img/mouth_i1_t.png"; img_mi2.src = "./img/mouth_i2_t.png"; img_mu1.src = "./img/mouth_u1_t.png"; img_mu2.src = "./img/mouth_u1_t.png"; img_me1.src = "./img/mouth_e1_t.png"; img_me2.src = "./img/mouth_e2_t.png"; img_mo1.src = "./img/mouth_o1_t.png"; img_mo2.src = "./img/mouth_o2_t.png"; imgdata = { "f": img_f, "eL1": img_eL1, "eL2": img_eL2, "eL3": img_eL3, "eR1": img_eR1, "eR2": img_eR2, "eR3": img_eR3, "mc1": img_mc, "mc2": img_mc, "ma1": img_ma1, "ma2": img_ma2, "ma3": img_ma3, "ma4": img_ma4, "mi1": img_mi1, "mi2": img_mi2, "mu1": img_mu1, "mu2": img_mu2, "me1": img_me1, "me2": img_me2, "mo1": img_mo1, "mo2": img_mo2}; //初期顔を表示 img_f.src = imgdata["f"].src; img_eL.src = imgdata["eL"+1].src; img_eR.src = imgdata["eR"+1].src; img_m.src = imgdata["mc1"].src; img_f.onload = function(){ ctx.drawImage(img_f,0,0,800,750); ctx.drawImage(img_eL,0,0,800,750); ctx.drawImage(img_eR,0,0,800,750); ctx.drawImage(img_m,0,0,800,750); }; // 顔を描き換えるタイマー関数tick()を起動しておく tickTimeID = setInterval("tick()", 50);

} /* onload() */

// 一定時間ごとに顔を描き換える関数
function tick() {
ctx.drawImage(img_f,0,0,800,750);
ctx.drawImage(img_eL,0,0,800,750);
ctx.drawImage(img_eR,0,0,800,750);
ctx.drawImage(img_m,0,0,800,750);
} /* tick() */

// 目の画像を切り替える関数
function eyeMove(){
img_eL.src = imgdata["eL"+eyeNum].src;
img_eR.src = imgdata["eR"+eyeNum].src;
if((++eyeNum)==4) eyeNum=1;
} /* eyeMove() */

// 口の画像を切り替える関数
function mouthMove(){
img_m.src = imgdata["m"+PronSeq[PronNum].name+mouthNum].src;
if((++mouthNum)==5) mouthNum=1;
} /* mouthMove() */

// 発音を切り替える関数
function setPron(){

// 発音をセット if (PronNum==-1) { // 初回のセット PronNum=0; } else { if ((++PronNum)==PronSeq.length) PronNum=0; } // 現在音声出力中の母音を表示 switch(PronSeq[PronNum].name){ case "c": document.getElementById("mouthstatus").value = "閉"; break; case "a": document.getElementById("mouthstatus").value = "ア"; break; case "i": document.getElementById("mouthstatus").value = "イ"; break; case "u": document.getElementById("mouthstatus").value = "ウ"; break; case "e": document.getElementById("mouthstatus").value = "エ"; break; case "o": document.getElementById("mouthstatus").value = "オ"; break; } // 次の母音に切り替える時間をセットする PronTimeID = setTimeout("setPron()", PronSeq[PronNum].time);

} /* setPron() */

// 目の切り替え開始
function eyeStart() {

// 目の画像を切り替えるタイマー関数 eyeTimeID = setInterval("eyeMove()", 800);

} /* eyeStart() */

// 口の切り替えを開始
function mouthStart() {

// 発音をセットする setPron(); // 口の画像を切り替えるタイマー関数 mouthTimeID = setInterval("mouthMove()", 500);

} /* mouthStart() */

JavaScript
window.addEventListener("load",function(){

const text = document.querySelector('#text') const speakBtn = document.querySelector('#speak-btn') const cancelBtn = document.querySelector('#cancel-btn') const pauseBtn = document.querySelector('#pause-btn') const resumeBtn = document.querySelector('#resume-btn') speakBtn.addEventListener('click', function() { const uttr = new SpeechSynthesisUtterance(text.value); uttr.rate = 1; uttr.pitch = 3; uttr.volume =1; speechSynthesis.speak(uttr); uttr.onend = function (event) { stop(); console.log('喋った時間:' + event.elapsedTime + 'ms'); } stat(); }) cancelBtn.addEventListener('click', function() { speechSynthesis.cancel(); stop(); }) pauseBtn.addEventListener('click', function() { speechSynthesis.pause(); pause(); }) resumeBtn.addEventListener('click', function() { speechSynthesis.resume() stat(); })

},true);

試したこと

WEB上でいろいろ試してみたが、うまく動かず詰まってしまった

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2019/12/23 05:05

このままではコードが読みづらいので、質問を編集し、<code>ボタンを押し、出てくる’’’の枠の中にコードを貼り付けてください
guest

回答1

0

ベストアンサー

画像と音声を同期させたい

現状は、setInterval() を2つ使っているため、同期は不可能です。
せめて、setInterval() を1つにして、時間軸を統一してください。

追記)
こちらのご質問回答した内容が、同期の基礎になります。
ご質問だと画像変化/音声の再生・停止が起こるタイミングを同時に制御する「時間軸」を考えます。

画像と音声を出すことはできたが、その二つを同期させるやり方がどのようなコードを使うのかがわからない

コードは、「javascript ゲームエンジン」で見つかるゲームコンテンツ作成用ライブラリの実装方法を参考にしてはどうでしょう。

ゲームループの中で「画像の表示切り替え」や「音声/動画の再生」、「入力」を行います。同一の時間進行を示す「フレーム(時限発火する関数)」で様々な処理を実行するのがゲームエンジンの同期の取リ方です。

javascript製ゲームエンジンは、通常、requestAnimationFrame()を用いて 12FPS 前後で安定するゲームループを実装しますが、短時間で終わる簡単なアニメーション処理は、setInterval() で実装することもあります。

「ゲームエンジン」は以下のことを同期するフレームワークの類と言えます。

  • フレームごとに時間管理

1. 終了までに時間を要する音声/動画は特に重要
2. 処理落ちもあるため、次のフレームは何もしない方法も考える

  • 表示する画像、音声、動画は先読みしてメモリ上にキャッシュ
  • 入力イベントはループ内から入力状態を参照する
  • 画像が複数のときは、ツリー構造で管理する。

投稿2019/12/25 07:37

編集2019/12/25 22:18
AkitoshiManabe

総合スコア5434

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

risasayo

2019/12/26 01:14

回答有難うございます。 早速試してみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問