// ---- GATE 2: Audio Recording ----
async function startRecording() {
if (isRecording) {
// Stop recording
if (mediaRecorder && mediaRecorder.state === 'recording') {
mediaRecorder.stop();
}
isRecording = false;
gate2Btn.classList.remove('recording');
gate2Btn.textContent = '🔄 Repeat Last 30s';
return;
}
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(stream);
audioChunks = [];
mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
audioChunks.push(event.data);
}
};
mediaRecorder.onstop = () => {
audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
// Keep only the last 30 seconds
// For demo, we process immediately
processAudioBuffer();
};
mediaRecorder.start(1000); // Record in 1-second chunks
isRecording = true;
gate2Btn.classList.add('recording');
gate2Btn.textContent = '⏹️ Stop Recording';
} catch (err) {
alert('Could not access microphone. Please allow microphone access.');
console.error(err);
}
}
// ---- GATE 2: Process Audio Buffer ----
function processAudioBuffer() {
if (!audioBlob) {
resultDiv.innerHTML = `
⚠️ No audio recorded. Tap Repeat Last 30s first.
`;
return;
}
// Simulate transcription + translation (since we can't run STT locally)
// In production, you'd send audioBlob to your STT service
const sampleTranscripts = [
"Chef said: deglaze the pan with white wine, then add the stock.",
"Now we julienne the carrots and sauté them in butter.",
"Blanch the green beans for two minutes, then shock them in ice water.",
"Fold the cream into the batter gently.",
"Sear the steak on high heat for two minutes each side."
];
// Pick a random transcript for demo
const transcript = sampleTranscripts[Math.floor(Math.random() * sampleTranscripts.length)];
// Find culinary terms in the transcript and replace with Malay
let translated = transcript;
let foundTerms = [];
glossary.forEach(term => {
const regex = new RegExp(term.en_term, 'gi');
if (transcript.match(regex)) {
foundTerms.push(term);
translated = translated.replace(regex, `${term.en_term} (${term.malay_term})`);
}
});
// Build the result display
let termsHtml = '';
if (foundTerms.length > 0) {
termsHtml = foundTerms.map(t =>
`${t.en_term} → 🇲🇾 ${t.malay_term}
`
).join('');
} else {
termsHtml = 'No culinary terms detected in this snippet.
';
}
resultDiv.innerHTML = `
🎙️ Last 30 Seconds
📝 Original:
“${transcript}”
🇲🇾 Translated:
“${translated}”
🔍 Terms Found:
${termsHtml}
👆 Tap Listen to hear the translation
`;
// Auto-speak the translation in Malay
const malayText = translated.replace(/\([^)]*\)/g, '').trim();
speakText(malayText, 'ms-MY');
// Reset recording state
isRecording = false;
gate2Btn.classList.remove('recording');
gate2Btn.textContent = '🔄 Repeat Last 30s';
audioBlob = null;
}
// ---- GATE 2: Stop Everything ----
function stopAll() {
// Stop recording
if (mediaRecorder && mediaRecorder.state === 'recording') {
mediaRecorder.stop();
}
isRecording = false;
gate2Btn.classList.remove('recording');
gate2Btn.textContent = '🔄 Repeat Last 30s';
// Cancel speech
if (isSpeaking) {
window.speechSynthesis.cancel();
isSpeaking = false;
listenBtn.textContent = '🔊 Listen';
listenBtn.classList.remove('speaking');
}
// Stop STT
if (recognition) {
recognition.stop();
recognition = null;
askBtn.classList.remove('listening');
askBtn.textContent = '🎤 Ask';
}
// Clear result
resultDiv.innerHTML = `
⏹️ Stopped. Tap Repeat Last 30s to try again.
`;
}