mime-chat/src/audio.ts
2021-08-26 12:31:18 -05:00

124 lines
2.9 KiB
TypeScript

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<typeof setTimeout>;
let setStreamsId: ReturnType<typeof setTimeout>;
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 };