Skip to content

Commit

Permalink
Adds visual controls (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcyoung authored Feb 11, 2024
1 parent 7ff2f30 commit 184317f
Show file tree
Hide file tree
Showing 27 changed files with 461 additions and 131 deletions.
1 change: 1 addition & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"typecheck": "tsc --noEmit",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"format": "prettier --check \"**/*.{js,cjs,mjs,ts,tsx,md,json}\"",
Expand Down
2 changes: 2 additions & 0 deletions app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const getAnalyzerComponent = (mode: ApplicationMode) => {
return <AudioAnalyzer mode={mode} />;
case APPLICATION_MODE.WAVE_FORM:
case APPLICATION_MODE.NOISE:
case APPLICATION_MODE.PARTICLE_NOISE:
return null;
default:
return mode satisfies never;
Expand All @@ -26,6 +27,7 @@ const getCanvasComponent = (mode: ApplicationMode) => {
case APPLICATION_MODE.WAVE_FORM:
case APPLICATION_MODE.NOISE:
case APPLICATION_MODE.AUDIO:
case APPLICATION_MODE.PARTICLE_NOISE:
return <Visual3DCanvas mode={mode} />;
default:
return mode satisfies never;
Expand Down
31 changes: 0 additions & 31 deletions app/src/components/analyzers/fftAnalyzerControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,6 @@ export const FFTAnalyzerControls = ({
analyzer: FFTAnalyzer;
}) => {
const { octaveBandMode, energyMeasure } = useFFTAnalyzerContext();
// const { octaveBands, energyMeasure } = useControls({
// Audio: folder({
// octaveBands: {
// value: 2,
// order: 75,
// options: {
// "1/24th octave bands": 1,
// "1/12th octave bands": 2,
// "1/8th octave bands": 3,
// "1/6th octave bands": 4,
// "1/4th octave bands": 5,
// "1/3rd octave bands": 6,
// "Half octave bands": 7,
// "Full octave bands": 8,
// },
// },
// energyMeasure: {
// value: "overall",
// order: 76,
// options: [
// "overall",
// "peak",
// "bass",
// "lowMid",
// "mid",
// "highMid",
// "treble",
// ],
// },
// }),
// });
const freqData = useVisualSourceDataX();
const energyInfo = useEnergyInfo();
const { resizeVisualSourceData } = useAppStateActions();
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/audio/audioSource.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AUDIO_SOURCE } from "@/components/audio/sourceControls/common";
import FileAudioControls from "@/components/audio/sourceControls/file";
import { CurrentTrackPlayer } from "@/components/controls/audio/soundcloud/player";
import { CurrentTrackPlayer } from "@/components/controls/audioSource/soundcloud/player";

export const ControlledAudioSource = ({
audio,
Expand Down
16 changes: 6 additions & 10 deletions app/src/components/canvas/Visual3D.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BackgroundFog, CanvasBackground } from "@/components/canvas/common";
import AudioVisual from "@/components/visualizers/visualizerAudio";
import NoiseVisual from "@/components/visualizers/visualizerNoise";
// import ParticleNoiseVisual from "@/components/visualizers/visualizerParticleNoise";
import ParticleNoiseVisual from "@/components/visualizers/visualizerParticleNoise";
import WaveformVisual from "@/components/visualizers/visualizerWaveform";
import {
CAMERA_CONTROLS_MODE,
Expand All @@ -17,20 +17,16 @@ import { MaybePaletteTracker } from "./paletteTracker";
const VisualizerComponent = ({
mode,
}: {
mode: "WAVE_FORM" | "NOISE" | "AUDIO";
mode: "WAVE_FORM" | "NOISE" | "AUDIO" | "PARTICLE_NOISE";
}) => {
const {
visual,
//palette
} = useVisualContext();
const { visual } = useVisualContext();
switch (mode) {
case APPLICATION_MODE.WAVE_FORM:
return <WaveformVisual visual={visual} />;
case APPLICATION_MODE.NOISE:
// if (visual === "swarm") {
// return <ParticleNoiseVisual />;
// }
return <NoiseVisual visual={visual} />;
case APPLICATION_MODE.PARTICLE_NOISE:
return <ParticleNoiseVisual />;
case APPLICATION_MODE.AUDIO:
return <AudioVisual visual={visual} />;
default:
Expand Down Expand Up @@ -79,7 +75,7 @@ const CameraControls = () => {
const Visual3DCanvas = ({
mode,
}: {
mode: "WAVE_FORM" | "NOISE" | "AUDIO";
mode: "WAVE_FORM" | "NOISE" | "AUDIO" | "PARTICLE_NOISE";
}) => {
return (
<Canvas
Expand Down
6 changes: 3 additions & 3 deletions app/src/components/controls/mode/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import {
getPlatformSupportedAudioSources,
type AudioSource,
} from "@/components/audio/sourceControls/common";
import { FileUploadControls } from "@/components/controls/audio/fileUpload";
import { SoundcloudControls } from "@/components/controls/audio/soundcloud/controls";
import { FileUploadControls } from "@/components/controls/audioSource/fileUpload";
import { SoundcloudControls } from "@/components/controls/audioSource/soundcloud/controls";
import { Label } from "@/components/ui/label";
import {
useAudioSourceContext,
Expand All @@ -27,7 +27,7 @@ export const ValueLabel = ({
...props
}: HTMLProps<HTMLDivElement> & {
label: string;
value: string;
value: string | number;
}) => {
return (
<div
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/controls/mode/noise.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const NoiseGeneratorModeControls = () => {
step={0.01}
onValueChange={(e) => setTimeScale(e[0])}
/>
<ValueLabel label="Iteration Count" value={nIterations.toString()} />
<ValueLabel label="Iteration Count" value={nIterations} />
<Slider
defaultValue={[nIterations]}
value={[nIterations]}
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/controls/mode/waveform.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const WaveformModeControls = () => {
/>
</div>
<div className="flex w-full items-center justify-between">
<Label htmlFor="color-background">Double</Label>
<Label>Double</Label>
<Switch
defaultChecked={waveformFrequenciesHz.length > 1}
onCheckedChange={(e) => {
Expand Down
16 changes: 13 additions & 3 deletions app/src/components/controls/modeSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ import {
isAudioMode,
type ApplicationMode,
} from "@/lib/applicationModes";
import { Activity, Music, Shell, Waves } from "lucide-react";
import {
AudioWaveform,
Drum,
HelpCircle,
Music,
Shell,
Waves,
} from "lucide-react";

import { AudioModeControls } from "./mode/audio";
import { AudioScopeModeControls } from "./mode/audioScope";
Expand All @@ -25,15 +32,18 @@ import { WaveformModeControls } from "./mode/waveform";
const ModeIcon = ({ mode }: { mode: ApplicationMode }) => {
switch (mode) {
case "WAVE_FORM":
return <Activity />;
return <AudioWaveform />;
case "NOISE":
return <Waves />;
case "AUDIO":
return <Music />;
case "AUDIO_SCOPE":
return <Shell />;
case "PARTICLE_NOISE":
return <Drum />;
default:
return mode satisfies never;
return <HelpCircle />;
// return mode satisfies never;
}
};
const ModeSelectEntry = ({ mode }: { mode: ApplicationMode }) => {
Expand Down
100 changes: 100 additions & 0 deletions app/src/components/controls/visual/cube.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Slider } from "@/components/ui/slider";
import { Switch } from "@/components/ui/switch";
import {
useCubeVisualConfigContext,
useCubeVisualConfigContextSetters,
} from "@/context/visualConfig/cube";

import { ValueLabel } from "../mode/common";

const Presets = [
{
name: "default",
nPerSide: 10,
unitSpacingScalar: 0.1,
volume: true,
},
{
name: "custom",
},
] as const;

export const CubeVisualSettingsControls = () => {
const { nPerSide, unitSpacingScalar, volume } = useCubeVisualConfigContext();
const { setNPerSide, setUnitSpacingScalar, setVolume } =
useCubeVisualConfigContextSetters();
const [preset, setPreset] = useState<(typeof Presets)[number]>(
Presets.find(
(p) =>
p.name !== "custom" &&
p.nPerSide === nPerSide &&
p.volume === volume &&
p.unitSpacingScalar === unitSpacingScalar,
) ?? Presets[0],
);

useEffect(() => {
if (preset.name === "custom") {
return;
}
setNPerSide(preset.nPerSide);
setUnitSpacingScalar(preset.unitSpacingScalar);
setVolume(preset.volume);
}, [preset, setNPerSide, setUnitSpacingScalar, setVolume]);

return (
<div className="flex w-full flex-col items-start justify-start gap-4">
<Label>Cube Presets</Label>
<div className="flex w-full items-center justify-start gap-2">
{Presets.map((p) => (
<Button
key={`cube_preset_${p.name}`}
variant="ghost"
aria-selected={p === preset}
className="p-2 aria-selected:bg-primary/20"
onClick={() => setPreset(p)}
>
{p.name}
</Button>
))}
</div>
{preset.name === "custom" && (
<>
<ValueLabel label="N x Per Side" value={nPerSide} />
<Slider
defaultValue={[nPerSide]}
value={[nPerSide]}
min={3}
max={20}
step={1}
onValueChange={(e) => setNPerSide(e[0])}
/>
<ValueLabel
label="Cube Spacing"
value={unitSpacingScalar.toFixed(2)}
/>
<Slider
defaultValue={[unitSpacingScalar]}
value={[unitSpacingScalar]}
min={0}
max={0.5}
step={0.1}
onValueChange={(e) => setUnitSpacingScalar(e[0])}
/>
<div className="flex w-full items-center justify-between">
<Label>Volume</Label>
<Switch
defaultChecked={volume}
onCheckedChange={(e) => {
setVolume(e);
}}
/>
</div>
</>
)}
</div>
);
};
97 changes: 97 additions & 0 deletions app/src/components/controls/visual/diffusedRing.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Slider } from "@/components/ui/slider";
import { Switch } from "@/components/ui/switch";
import {
useRingVisualConfigContext,
useRingVisualConfigContextSetters,
} from "@/context/visualConfig/diffusedRing";

import { ValueLabel } from "../mode/common";

const Presets = [
{
name: "default",
radius: 2,
pointSize: 0.2,
mirrorEffects: false,
},
{
name: "custom",
},
] as const;

export const DiffusedRingVisualSettingsControls = () => {
const { radius, pointSize, mirrorEffects } = useRingVisualConfigContext();
const { setRadius, setPointSize, setMirrorEffects } =
useRingVisualConfigContextSetters();
const [preset, setPreset] = useState<(typeof Presets)[number]>(
Presets.find(
(p) =>
p.name !== "custom" &&
p.pointSize === pointSize &&
p.radius === radius &&
p.mirrorEffects === mirrorEffects,
) ?? Presets[0],
);

useEffect(() => {
if (preset.name === "custom") {
return;
}
setRadius(preset.radius);
setPointSize(preset.pointSize);
setMirrorEffects(preset.mirrorEffects);
}, [preset, setRadius, setPointSize, setMirrorEffects]);

return (
<div className="flex w-full flex-col items-start justify-start gap-4">
<Label>Diffused Ring Presets</Label>
<div className="flex w-full items-center justify-start gap-2">
{Presets.map((p) => (
<Button
key={`sphere_preset_${p.name}`}
variant="ghost"
aria-selected={p === preset}
className="p-2 aria-selected:bg-primary/20"
onClick={() => setPreset(p)}
>
{p.name}
</Button>
))}
</div>
{preset.name === "custom" && (
<>
<ValueLabel label="Radius" value={radius.toFixed(2)} />
<Slider
defaultValue={[radius]}
value={[radius]}
min={0.25}
max={3}
step={0.25}
onValueChange={(e) => setRadius(e[0])}
/>
<ValueLabel label="Point Size" value={pointSize.toFixed(2)} />
<Slider
defaultValue={[pointSize]}
value={[pointSize]}
min={0.01}
max={0.25}
step={0.01}
onValueChange={(e) => setPointSize(e[0])}
/>
<div className="flex w-full items-center justify-between">
<Label>Mirror Effects</Label>
<Switch
defaultChecked={mirrorEffects}
onCheckedChange={(e) => {
setMirrorEffects(e);
}}
/>
</div>
</>
)}
</div>
);
};
Loading

0 comments on commit 184317f

Please sign in to comment.