const FFT = require('fft.js'); import { globalShortcut } from "electron"; const nodeAudio = require('@crimata/nodeaudio'); import { sendMessage } from "@/io"; import { updateTray } from "@/tray"; import { backgroundMitt, ipcEmit } from '@/composables/useEmitter'; let inputDevice: number; let outputDevice: number; let setWriteId: ReturnType; let setStreamsId: ReturnType; let playbackId: string; const streamState = { rec: false, pb: false }; const chunks: Int16Array[] = []; const fft = new FFT(4); function calcFFT(int16Arr: Int16Array) { const out = fft.createComplexArray(); fft.realTransform(out, int16Arr); return out; } backgroundMitt.on("read", (int16Arr: Int16Array) => { if (streamState.rec) { chunks.push(int16Arr); ipcEmit("recording", calcFFT(int16Arr)); /* fft used for animation */ } } ); backgroundMitt.on("write", (int16Arr: Int16Array) => { ipcEmit("playback", { uid: playbackId, fft: calcFFT(int16Arr) }); streamState.pb = true; clearTimeout(setWriteId); setWriteId = setTimeout(() => streamState.pb = false, 1000); } ); function setStreams() { const defaultInput = nodeAudio.core.GetDefaultInputDevice(); const defaultOutput = nodeAudio.core.GetDefaultOutputDevice(); if (inputDevice !== defaultInput) { inputDevice = defaultInput; nodeAudio.core.CloseInputStream(inputDevice); nodeAudio.core.OpenInputStream(inputDevice); } if (outputDevice !== defaultOutput) { outputDevice = defaultOutput; nodeAudio.core.CloseOutputStream(outputDevice); nodeAudio.core.OpenOutputStream(outputDevice); } } function startRecording() { streamState.rec = true; updateTray("recording", streamState.rec); } function stopRecording() { streamState.rec = false; updateTray("recording", streamState.rec); /* Send the data to the platform right away */ sendMessage({ text: false, audio: nodeAudio.utils.mergeChunks(chunks) } as Raw); chunks.length = 0; } function InitAudio() { nodeAudio.core.Initialize(backgroundMitt.emit.bind(backgroundMitt)); setStreamsId = setInterval(setStreams, 2000); // sense device /* Toggle recording switch with global shortcut */ globalShortcut.register('CommandOrControl+R', () => { if (streamState.rec) { stopRecording(); } else { startRecording(); } } ); } /* Will override an existing playback process */ function playback(audio: Int16Array, uid: string) { playbackId = uid; /* uid of message */ // nodeAudio.core.CancelPlayback(); /* terminate any current playback */ nodeAudio.core.WriteToOutputStream(audio.buffer); } function TerminateAudio() { clearInterval(setStreamsId); nodeAudio.core.Terminate(); } export { InitAudio, TerminateAudio, playback, streamState };