82 lines
1.8 KiB
TypeScript
82 lines
1.8 KiB
TypeScript
import { MemoryRouter as Router, Switch, Route } from 'react-router-dom';
|
|
import { IpcRenderer } from 'electron/renderer';
|
|
|
|
import './App.css';
|
|
import { useEffect, useState } from 'react';
|
|
|
|
import { AppState } from '../main/backend';
|
|
import PatternPreview from './PatternPreview';
|
|
import GraphVisualization from './Graph';
|
|
|
|
const ipcRenderer = (window as any).electron.ipcRenderer as IpcRenderer;
|
|
|
|
function tap() {
|
|
ipcRenderer.send("beat-tracking", "tap");
|
|
}
|
|
|
|
const FrontendRoot: React.FC = () => {
|
|
|
|
const [state, setState] = useState<AppState>();
|
|
|
|
const pollMain = async () => {
|
|
const reply = await ipcRenderer.invoke("poll");
|
|
setState(reply);
|
|
}
|
|
|
|
useEffect(() => {
|
|
const interval = setInterval(pollMain, 20);
|
|
return () => clearInterval(interval);
|
|
});
|
|
|
|
return <>
|
|
{
|
|
state
|
|
? <Frontend state={state} />
|
|
: <div> oops </div>
|
|
}
|
|
</>;
|
|
};
|
|
|
|
|
|
const Frontend: React.FC<{ state: AppState }> = ({ state }) => {
|
|
|
|
return <>
|
|
<div>
|
|
<button onClick={tap}>Tap</button>
|
|
</div>
|
|
<div>
|
|
{Object.entries(state.patterns).map(([patternId, output]) => (
|
|
<PatternPreview key={patternId} patternId={patternId} output={output} />
|
|
))}
|
|
</div>
|
|
{
|
|
state.graphData
|
|
? <div>
|
|
<p> Bass Filtered </p>
|
|
<p>
|
|
<GraphVisualization points={state.graphData.bassFiltered} />
|
|
</p>
|
|
<p> Autocorrelation </p>
|
|
<p>
|
|
<GraphVisualization points={state.graphData.autoCorrelated} />
|
|
</p>
|
|
</div>
|
|
: <div> no graph data </div>
|
|
}
|
|
<div>
|
|
{JSON.stringify(state)}
|
|
</div>
|
|
</>;
|
|
}
|
|
|
|
|
|
export default function App() {
|
|
return (
|
|
<Router>
|
|
<Switch>
|
|
<Route path="/" component={FrontendRoot} />
|
|
</Switch>
|
|
</Router>
|
|
);
|
|
}
|