Skip to content

Commit

Permalink
add controls
Browse files Browse the repository at this point in the history
  • Loading branch information
Jackie Edwards committed May 25, 2024
1 parent 59279c8 commit a54c920
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 37 deletions.
Binary file modified bun.lockb
Binary file not shown.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
},
"dependencies": {
"@babel/standalone": "^7.24.5",
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/react-fontawesome": "^0.2.2",
"@monaco-editor/react": "^4.6.0",
"@types/babel__standalone": "^7.1.7",
"react": "^18.2.0",
Expand Down
136 changes: 99 additions & 37 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import "./App.css";
import { visualizeJackieSort } from "./business/commands";
import { transformTypescript } from "./ts";
import { useOscillator } from "./business/audio";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import * as Icons from "@fortawesome/free-solid-svg-icons";

function setUpMonaco(monaco: Monaco): void {
monaco.languages.typescript.typescriptDefaults.addExtraLib(editorExtraTypes);
Expand All @@ -37,8 +39,17 @@ export default function App() {
number[]
> | null>(() => visualizeJackieSort(items));

const [commandGeneratorFunction, setCommandGeneratorFunction] = useState(() => visualizeJackieSort);

const [sortPlaying, setSortPlaying] = useState(false);
const [muted, setMuted] = useState(false);
const [sortFinished, setSortFinished] = useState(false);

// Run a step of the sorting algorithm every x ms
useInterval(() => {
if (!commandGenerator) return;
if (!sortPlaying) return;

const command = commandGenerator.next(items);
if (!command.done) {
swaps.fill(false);
Expand Down Expand Up @@ -77,9 +88,9 @@ export default function App() {
setSwaps(swaps.slice());
setItems(items.slice());
if (sorted.every((s) => s)) {
oscillator.current.gain.gain.setValueAtTime(0, 0);
} else {
oscillator.current.gain.gain.setValueAtTime(0.1, 0);
setSortPlaying(false);
setSortFinished(true);
oscillator.current.mute();
}
}
oscillator.current.oscillator.frequency.setValueAtTime(
Expand All @@ -88,42 +99,77 @@ export default function App() {
);
}, 10);

const onTextChange = useCallback(async (text: string) => {
try {
const javascriptCode = transformTypescript(text)!;
console.log(`"${javascriptCode}"`);
if (lastScript === javascriptCode) return;
else {
setItems([...Array(itemCount).keys()].sort(() => Math.random() - 0.5));
setSorted([]);
setSwaps([]);
}
if (javascriptCode) lastScript = javascriptCode;
const newGenerator = (
await import(
/* @vite-ignore */ URL.createObjectURL(
new Blob(
[
`${editorExtraTypes}
const reset = useCallback(() => {
const newItems = [...Array(itemCount).keys()].sort(() => Math.random() - 0.5);
setItems(newItems);
setSortFinished(false);
setSorted(newItems.map(() => false));
setSwaps(newItems.map(() => false));
setCursors([]);
setCommandGenerator(commandGeneratorFunction(newItems));

}, [setItems, itemCount, setSorted, setSwaps, setCursors, commandGeneratorFunction, setCommandGenerator]);

const onTextChange = useCallback(
async (text: string) => {
try {
const javascriptCode = transformTypescript(text)!;
if (lastScript === javascriptCode) return;
else {
setItems(
[...Array(itemCount).keys()].sort(() => Math.random() - 0.5)
);
setSorted(items.map(() => false));
setSwaps(items.map(() => false));
}
if (javascriptCode) lastScript = javascriptCode;
const newGenerator = (
await import(
/* @vite-ignore */ URL.createObjectURL(
new Blob(
[
`${editorExtraTypes}
${javascriptCode}`,
],
{ type: "text/javascript" }
],
{ type: "text/javascript" }
)
)
)
)
).default;
// console.log(newGenerator)
console.log(newGenerator);
if (typeof newGenerator === "function") {
setCommandGenerator(newGenerator(items));
} else {
).default;
if (typeof newGenerator === "function") {
setCommandGeneratorFunction(newGenerator);
setCommandGenerator(newGenerator(items));
} else {
setCommandGenerator(null);
}
} catch (e) {
setCommandGenerator(null);
console.warn(e);
}
} catch (e) {
setCommandGenerator(null);
console.warn(e);
},
[items, itemCount]
);

const toggleVolume = useCallback(() => {
if (muted && sortPlaying) {
oscillator.current.unmute();
} else {
oscillator.current.mute();
}
setMuted(!muted);
}, [muted, setMuted, oscillator, sortPlaying]);
const togglePlaying = useCallback(() => {
if (sortPlaying) {
oscillator.current.mute();
} else if (!muted) {
oscillator.current.unmute();
console.log("Test");
}
}, []);
if (!sortPlaying && sortFinished) {
reset();
}
setSortPlaying(!sortPlaying);
}, [sortPlaying, setSortPlaying, muted, oscillator, sortFinished, reset]);

return (
<div
Expand All @@ -137,20 +183,36 @@ export default function App() {
}
}
>
<button onClick={() => oscillator.current.oscillator.start()}>
Play
</button>
<ResizablePanes uniqueId="uniqueId" vertical resizerSize={5}>
<Pane id="editor" size={1} minSize={0.5}>
<Editor
beforeMount={setUpMonaco}
defaultLanguage="typescript"
theme="vs-dark"
defaultValue={defaultScript}
height="100vh"
height="90vh"
width="100%"
onChange={(text) => onTextChange(text || "")}
/>
<div
style={{
height: "10vh",
}}
>
<button onClick={() => toggleVolume()}>
<FontAwesomeIcon
icon={muted ? Icons.faVolumeMute : Icons.faVolumeUp}
/>
</button>
<button onClick={() => reset()}>
<FontAwesomeIcon icon={Icons.faRefresh} />
</button>
<button onClick={() => togglePlaying()}>
<FontAwesomeIcon
icon={sortPlaying ? Icons.faPause : Icons.faPlay}
/>
</button>
</div>
</Pane>
<Pane id="visualization" size={1}>
<div
Expand Down
16 changes: 16 additions & 0 deletions src/business/audio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ export type UseOscillator = {
ctx: AudioContext;
oscillator: OscillatorNode;
gain: GainNode;

mute: () => void;
unmute: () => void;
};

export function useOscillator(): React.MutableRefObject<UseOscillator> {
const useOscillatorObject = useRef<UseOscillator>(null!);
useEffect(() => {
let hasStarted = false;
const audioCtx = new AudioContext();

const oscillatorNode = new OscillatorNode(audioCtx, {
Expand All @@ -23,6 +27,18 @@ export function useOscillator(): React.MutableRefObject<UseOscillator> {
ctx: audioCtx,
oscillator: oscillatorNode,
gain: gainNode,
unmute: () => {
if (hasStarted) {
gainNode.gain.setValueAtTime(0.1, audioCtx.currentTime);
} else {
gainNode.gain.setValueAtTime(0.1, audioCtx.currentTime);
oscillatorNode.start();
hasStarted = true;
}
},
mute: () => {
gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
},
};

return () => {
Expand Down

0 comments on commit a54c920

Please sign in to comment.