Skip to content

Commit

Permalink
Merge pull request render-examples#22 from aivy-tokyo/feat/skip_first…
Browse files Browse the repository at this point in the history
…_greeting

「起動時のスキップボタン」の実装
  • Loading branch information
Nobuhiko Futagami committed Aug 25, 2023
2 parents 568b06a + b0c4208 commit ebf3968
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 21 deletions.
47 changes: 32 additions & 15 deletions components/FirstGreeting.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PropsWithChildren, useContext, useState, useCallback } from "react";
import { PropsWithChildren, useContext, useState, useCallback, useEffect } from "react";
import { ViewerContext } from "../features/vrmViewer/viewerContext";
import { speakFirstConversation } from "../features/speakFirstConversation";
import { useAtomValue } from "jotai";
Expand Down Expand Up @@ -29,23 +29,40 @@ export const FirstGreeting: React.FC<PropsWithChildren> = ({ children }) => {
}
}, [firstGreetingDone, textToSpeechApiType, userInfo?.name, viewer.model]);

const handleSkipFirstGreeting = useCallback(() => {
viewer.model?.stopSpeak();
setFirstGreetingDone(true);
}, [viewer.model]);

if (!firstGreetingDone) {
return (
<div
className={`
fixed top-0 flex justify-center items-center h-screen w-full bg-opacity-60
${startButtonClicked ? "bg-transparent" : "bg-black"}
`}
>
{!startButtonClicked && (
<button
className="btn btn-secondary is-rounded is-large is-fullwidth"
onClick={greet}
<>
<div
className={`
fixed top-0 flex justify-center items-center h-screen w-full bg-opacity-60
${startButtonClicked ? "bg-transparent" : "bg-black"}
`}
>
AILLAと英会話を始めましょう!
</button>
)}
</div>
{startButtonClicked ?
(
<button
className="btn btn-secondary is-rounded is-large is-fullwidth"
onClick={() => handleSkipFirstGreeting()}
>
スキップする
</button>
)
:
(
<button
className="btn btn-secondary is-rounded is-large is-fullwidth"
onClick={greet}
>
AILLAと英会話を始めましょう!
</button>
)}
</div>
</>
);
}

Expand Down
19 changes: 13 additions & 6 deletions features/lipSync/lipSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export class LipSync {
public readonly audio: AudioContext;
public readonly analyser: AnalyserNode;
public readonly timeDomainData: Float32Array;

private _bufferSource?: AudioBufferSourceNode;

public constructor(audio: AudioContext) {
this.audio = audio;
Expand Down Expand Up @@ -34,14 +36,19 @@ export class LipSync {
public async playFromArrayBuffer(buffer: ArrayBuffer, onEnded?: () => void) {
const audioBuffer = await this.audio.decodeAudioData(buffer);

const bufferSource = this.audio.createBufferSource();
bufferSource.buffer = audioBuffer;
this._bufferSource = this.audio.createBufferSource();
this._bufferSource.buffer = audioBuffer;

bufferSource.connect(this.audio.destination);
bufferSource.connect(this.analyser);
bufferSource.start();
this._bufferSource.connect(this.audio.destination);
this._bufferSource.connect(this.analyser);
this._bufferSource.start();
if (onEnded) {
bufferSource.addEventListener("ended", onEnded);
this._bufferSource.addEventListener("ended", onEnded);
}
}

public stop() {
if (!this._bufferSource)return;
this._bufferSource.stop();
}
}
1 change: 1 addition & 0 deletions features/speakFirstConversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export const speakFirstConversation = async ({
'ja'
);
}
viewerModel.orderedToSkip = false;
} catch (error) {
console.error("Failed to speak:", error);
}
Expand Down
7 changes: 7 additions & 0 deletions features/vrmViewer/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export class Model {
public vrm?: VRM | null;
public mixer?: THREE.AnimationMixer;
public emoteController?: EmoteController;
public orderedToSkip: boolean = false;

private _lookAtTargetParent: THREE.Object3D;
private _lipSync?: LipSync;
Expand Down Expand Up @@ -71,6 +72,7 @@ export class Model {
* 音声を再生し、リップシンクを行う
*/
public async speak(buffer: ArrayBuffer, screenplay: Pick<Screenplay, "expression">) {
if(this.orderedToSkip) return;
this.emoteController?.playEmotion(screenplay.expression);
await new Promise((resolve) => {
this._lipSync?.playFromArrayBuffer(buffer, () => {
Expand All @@ -79,6 +81,11 @@ export class Model {
});
}

public stopSpeak() {
this._lipSync?.stop();
this.orderedToSkip = true;
}

public update(delta: number): void {
if (this._lipSync) {
const { volume } = this._lipSync.update();
Expand Down

0 comments on commit ebf3968

Please sign in to comment.