Skip to content

Commit 50e6310

Browse files
committed
merge code and get analyser data
1 parent 48a1e8a commit 50e6310

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

app/components/realtime-chat/realtime-chat.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export function RealtimeChat({
7171
const turnDetection: TurnDetection = useVAD
7272
? { type: "server_vad" }
7373
: null;
74-
clientRef.current.configure({
74+
await clientRef.current.configure({
7575
instructions: "",
7676
voice,
7777
input_audio_transcription: { model: "whisper-1" },
@@ -100,6 +100,7 @@ export function RealtimeChat({
100100
});
101101
}
102102
}
103+
await clientRef.current.generateResponse();
103104
} catch (error) {
104105
console.error("Set message failed:", error);
105106
}
@@ -267,11 +268,25 @@ export function RealtimeChat({
267268
console.error(error);
268269
});
269270

271+
// TODO demo to get frequency. will pass audioHandlerRef.current to child component draw.
272+
// TODO try using requestAnimationFrame
273+
const interval = setInterval(() => {
274+
if (audioHandlerRef.current) {
275+
const data = audioHandlerRef.current.getByteFrequencyData();
276+
console.log("getByteFrequencyData", data);
277+
}
278+
}, 100);
279+
270280
return () => {
271281
if (isRecording) {
272282
toggleRecording();
273283
}
274-
audioHandlerRef.current?.close().catch(console.error);
284+
audioHandlerRef.current
285+
?.close()
286+
.catch(console.error)
287+
.finally(() => {
288+
clearInterval(interval);
289+
});
275290
disconnect();
276291
};
277292
}, []);

app/lib/audio.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
export class AudioHandler {
22
private context: AudioContext;
3+
private mergeNode: ChannelMergerNode;
4+
private analyserData: Uint8Array;
5+
public analyser: AnalyserNode;
36
private workletNode: AudioWorkletNode | null = null;
47
private stream: MediaStream | null = null;
58
private source: MediaStreamAudioSourceNode | null = null;
@@ -13,6 +16,16 @@ export class AudioHandler {
1316

1417
constructor() {
1518
this.context = new AudioContext({ sampleRate: this.sampleRate });
19+
// using ChannelMergerNode to get merged audio data, and then get analyser data.
20+
this.mergeNode = new ChannelMergerNode(this.context, { numberOfInputs: 2 });
21+
this.analyser = new AnalyserNode(this.context, { fftSize: 256 });
22+
this.analyserData = new Uint8Array(this.analyser.frequencyBinCount);
23+
this.mergeNode.connect(this.analyser);
24+
}
25+
26+
getByteFrequencyData() {
27+
this.analyser.getByteFrequencyData(this.analyserData);
28+
return this.analyserData;
1629
}
1730

1831
async initialize() {
@@ -60,6 +73,7 @@ export class AudioHandler {
6073
};
6174

6275
this.source.connect(this.workletNode);
76+
this.source.connect(this.mergeNode, 0, 0);
6377
this.workletNode.connect(this.context.destination);
6478

6579
this.workletNode.port.postMessage({ command: "START_RECORDING" });
@@ -114,6 +128,7 @@ export class AudioHandler {
114128
const source = this.context.createBufferSource();
115129
source.buffer = audioBuffer;
116130
source.connect(this.context.destination);
131+
source.connect(this.mergeNode, 0, 1);
117132

118133
const chunkDuration = audioBuffer.length / this.sampleRate;
119134

0 commit comments

Comments
 (0)