2022-11-25 23:13:17 -07:00
|
|
|
import { useRouter } from "next/router";
|
2022-12-14 01:54:26 -07:00
|
|
|
import { unmute } from "../external/unmute";
|
2022-12-13 22:10:43 -07:00
|
|
|
import { useCallback, useEffect, useState } from "react";
|
2022-11-26 13:12:40 -07:00
|
|
|
import * as Tone from "tone";
|
2022-11-24 21:22:03 -07:00
|
|
|
|
2022-11-27 14:53:22 -07:00
|
|
|
import AudioPlayer from "../components/AudioPlayer";
|
2022-12-13 23:29:49 -07:00
|
|
|
import FallingBehindWarning from "../components/FallingBehindWarning";
|
2022-11-27 17:59:00 -07:00
|
|
|
import PageHead from "../components/PageHead";
|
2022-12-02 12:54:47 -07:00
|
|
|
import Share from "../components/Share";
|
2022-12-11 19:45:48 -07:00
|
|
|
import Settings from "../components/Settings";
|
2022-11-27 16:38:00 -07:00
|
|
|
import ModelInference from "../components/ModelInference";
|
2022-11-23 23:08:00 -07:00
|
|
|
import Pause from "../components/Pause";
|
2022-11-27 16:38:00 -07:00
|
|
|
import PromptPanel from "../components/PromptPanel";
|
|
|
|
import ThreeCanvas from "../components/ThreeCanvas";
|
2022-11-20 12:56:36 -07:00
|
|
|
|
2022-12-16 09:45:02 -07:00
|
|
|
import { samplePrompts, initialSeeds, initialSeedImageMap } from "../samplePrompts";
|
2022-12-14 02:13:40 -07:00
|
|
|
|
2022-11-27 16:38:00 -07:00
|
|
|
import {
|
|
|
|
AppState,
|
|
|
|
InferenceInput,
|
|
|
|
InferenceResult,
|
|
|
|
PromptInput,
|
|
|
|
} from "../types";
|
2022-11-23 22:46:32 -07:00
|
|
|
|
2022-12-14 02:13:40 -07:00
|
|
|
function getRandomFromArray(arr: any[], n: number) {
|
|
|
|
var result = new Array(n),
|
|
|
|
len = arr.length,
|
|
|
|
taken = new Array(len);
|
|
|
|
if (n > len)
|
|
|
|
throw new RangeError("getRandom: more elements taken than available");
|
|
|
|
while (n--) {
|
|
|
|
var x = Math.floor(Math.random() * len);
|
|
|
|
result[n] = arr[x in taken ? taken[x] : x];
|
|
|
|
taken[x] = --len in taken ? taken[len] : len;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-11-23 23:08:00 -07:00
|
|
|
export default function Home() {
|
2022-11-27 16:38:00 -07:00
|
|
|
// High-level state of the prompts
|
|
|
|
const [appState, setAppState] = useState<AppState>(AppState.UNINITIALIZED);
|
|
|
|
|
|
|
|
// Whether playback is paused
|
|
|
|
const [paused, setPaused] = useState(true);
|
|
|
|
|
|
|
|
// Current interpolation parameters
|
2022-11-27 14:53:22 -07:00
|
|
|
const [alpha, setAlpha] = useState(0.0);
|
2022-12-13 22:10:43 -07:00
|
|
|
const [alphaRollover, setAlphaRollover] = useState(false);
|
2022-11-25 23:13:17 -07:00
|
|
|
const [alphaVelocity, setAlphaVelocity] = useState(0.25);
|
2022-11-23 22:46:32 -07:00
|
|
|
|
2022-12-12 22:43:34 -07:00
|
|
|
// Settings
|
|
|
|
const [denoising, setDenoising] = useState(0.75);
|
2022-12-14 20:53:52 -07:00
|
|
|
const [seedImageId, setSeedImageId] = useState(
|
|
|
|
initialSeeds[Math.floor(Math.random() * initialSeeds.length)]
|
|
|
|
);
|
|
|
|
const [seed, setSeed] = useState(
|
|
|
|
initialSeedImageMap[seedImageId][
|
|
|
|
Math.floor(Math.random() * initialSeedImageMap[seedImageId].length)
|
|
|
|
]
|
|
|
|
);
|
2022-12-12 22:43:34 -07:00
|
|
|
|
2022-11-27 16:38:00 -07:00
|
|
|
// Prompts shown on screen and maintained by the prompt panel
|
|
|
|
const [promptInputs, setPromptInputs] = useState<PromptInput[]>([]);
|
2022-11-25 23:13:17 -07:00
|
|
|
|
2022-11-27 16:38:00 -07:00
|
|
|
// Model execution results
|
2022-12-11 18:14:42 -07:00
|
|
|
const [inferenceResults, setInferenceResults] = useState<InferenceResult[]>(
|
|
|
|
[]
|
|
|
|
);
|
2022-11-23 23:08:00 -07:00
|
|
|
|
2022-11-27 17:46:10 -07:00
|
|
|
// Currently playing result, from the audio player
|
2022-12-11 18:14:42 -07:00
|
|
|
const [nowPlayingResult, setNowPlayingResult] =
|
|
|
|
useState<InferenceResult>(null);
|
2022-11-27 17:46:10 -07:00
|
|
|
|
2022-11-25 23:13:17 -07:00
|
|
|
// Set the initial seed from the URL if available
|
2022-11-27 16:38:00 -07:00
|
|
|
const router = useRouter();
|
2022-11-25 23:13:17 -07:00
|
|
|
useEffect(() => {
|
2022-11-27 16:38:00 -07:00
|
|
|
// Make sure params are ready
|
|
|
|
if (!router.isReady) {
|
|
|
|
return;
|
2022-11-25 23:13:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (router.query.alphaVelocity) {
|
|
|
|
setAlphaVelocity(parseFloat(router.query.alphaVelocity as string));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (router.query.seed) {
|
|
|
|
setSeed(parseInt(router.query.seed as string));
|
|
|
|
}
|
|
|
|
|
2022-11-27 16:38:00 -07:00
|
|
|
// Set prompt inputs here so that they are empty and incorrect information isn't shown
|
|
|
|
// until URL params have a chance to be read.
|
2022-12-14 02:13:40 -07:00
|
|
|
let initPromptInputs = [
|
|
|
|
{ prompt: "" },
|
|
|
|
{ prompt: "" },
|
|
|
|
{ prompt: "" },
|
|
|
|
{ prompt: "" },
|
|
|
|
{ prompt: "" },
|
|
|
|
{ prompt: "" },
|
|
|
|
];
|
|
|
|
|
|
|
|
// Set random initial prompts
|
|
|
|
const samples = getRandomFromArray(samplePrompts, 4);
|
|
|
|
for (let i = 0; i < 4; i++) {
|
|
|
|
initPromptInputs[i].prompt = samples[i];
|
|
|
|
}
|
2022-11-25 23:13:17 -07:00
|
|
|
if (router.query.prompt) {
|
2022-11-27 16:38:00 -07:00
|
|
|
initPromptInputs[3].prompt = router.query.prompt as string;
|
2022-11-25 23:13:17 -07:00
|
|
|
}
|
2022-12-14 02:13:40 -07:00
|
|
|
setPromptInputs(initPromptInputs);
|
2022-12-12 22:43:34 -07:00
|
|
|
|
|
|
|
if (router.query.denoising) {
|
|
|
|
setDenoising(parseFloat(router.query.denoising as string));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (router.query.seedImageId) {
|
|
|
|
setSeedImageId(router.query.seedImageId as string);
|
|
|
|
}
|
2022-11-27 16:38:00 -07:00
|
|
|
}, [router.isReady, router.query]);
|
2022-11-24 01:00:06 -07:00
|
|
|
|
2022-11-24 23:58:33 -07:00
|
|
|
// Set the app state based on the prompt inputs array
|
|
|
|
useEffect(() => {
|
2022-12-13 22:10:43 -07:00
|
|
|
if (!alphaRollover) {
|
2022-11-24 23:58:33 -07:00
|
|
|
return;
|
|
|
|
}
|
2022-12-13 22:10:43 -07:00
|
|
|
setAlphaRollover(false);
|
2022-11-24 23:58:33 -07:00
|
|
|
|
|
|
|
const upNextPrompt = promptInputs[promptInputs.length - 1].prompt;
|
|
|
|
const endPrompt = promptInputs[promptInputs.length - 2].prompt;
|
|
|
|
|
2022-11-27 16:38:00 -07:00
|
|
|
let newAppState = appState;
|
|
|
|
|
|
|
|
if (appState == AppState.SAME_PROMPT) {
|
2022-11-29 15:58:59 -07:00
|
|
|
if (upNextPrompt) {
|
2022-11-27 16:38:00 -07:00
|
|
|
newAppState = AppState.TRANSITION;
|
2022-11-29 15:58:59 -07:00
|
|
|
|
|
|
|
// swap the last two prompts to bring the upNextPrompt into the next inference call
|
|
|
|
setPromptInputs((prevPromptInputs) => {
|
|
|
|
const newPromptInputs = [...prevPromptInputs];
|
|
|
|
newPromptInputs[newPromptInputs.length - 1] = {
|
|
|
|
prompt: endPrompt,
|
|
|
|
};
|
|
|
|
newPromptInputs[newPromptInputs.length - 2] = {
|
|
|
|
prompt: upNextPrompt,
|
|
|
|
};
|
|
|
|
return newPromptInputs;
|
|
|
|
});
|
2022-11-24 23:58:33 -07:00
|
|
|
}
|
|
|
|
setSeed(seed + 1);
|
2022-11-27 16:38:00 -07:00
|
|
|
} else if (appState == AppState.TRANSITION) {
|
2022-11-24 23:58:33 -07:00
|
|
|
setPromptInputs([...promptInputs, { prompt: "" }]);
|
|
|
|
|
|
|
|
if (upNextPrompt) {
|
2022-11-27 16:38:00 -07:00
|
|
|
newAppState = AppState.TRANSITION;
|
2022-11-24 23:58:33 -07:00
|
|
|
} else {
|
2022-11-27 16:38:00 -07:00
|
|
|
newAppState = AppState.SAME_PROMPT;
|
2022-11-24 23:58:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-27 16:38:00 -07:00
|
|
|
if (newAppState != appState) {
|
|
|
|
setAppState(newAppState);
|
|
|
|
}
|
2022-12-13 22:10:43 -07:00
|
|
|
}, [promptInputs, alpha, alphaRollover, appState, seed]);
|
2022-11-24 23:58:33 -07:00
|
|
|
|
|
|
|
// On any app state change, reset alpha
|
|
|
|
useEffect(() => {
|
|
|
|
console.log("App State: ", appState);
|
2022-11-27 16:38:00 -07:00
|
|
|
|
|
|
|
if (appState == AppState.UNINITIALIZED) {
|
|
|
|
setAppState(AppState.SAME_PROMPT);
|
|
|
|
} else {
|
|
|
|
setAlpha(0.25);
|
|
|
|
}
|
2022-11-24 23:58:33 -07:00
|
|
|
}, [appState]);
|
|
|
|
|
2022-11-27 16:38:00 -07:00
|
|
|
// What to do when a new inference result is available
|
2022-12-13 22:10:43 -07:00
|
|
|
const newResultCallback = useCallback(
|
|
|
|
(input: InferenceInput, result: InferenceResult) => {
|
|
|
|
setInferenceResults((prevResults: InferenceResult[]) => {
|
|
|
|
const maxResultCounter = Math.max(...prevResults.map((r) => r.counter));
|
2022-11-24 22:24:37 -07:00
|
|
|
|
2022-12-13 22:10:43 -07:00
|
|
|
const lastResult = prevResults.find(
|
|
|
|
(r) => r.counter == maxResultCounter
|
|
|
|
);
|
2022-11-24 22:24:37 -07:00
|
|
|
|
2022-12-13 22:10:43 -07:00
|
|
|
const newCounter = lastResult ? lastResult.counter + 1 : 0;
|
2022-11-24 22:24:37 -07:00
|
|
|
|
2022-12-13 22:10:43 -07:00
|
|
|
result.counter = newCounter;
|
|
|
|
result.input = input;
|
|
|
|
result.played = false;
|
2022-11-24 22:24:37 -07:00
|
|
|
|
2022-12-13 22:10:43 -07:00
|
|
|
let newAlpha = alpha + alphaVelocity;
|
|
|
|
if (newAlpha > 1 + 1e-3) {
|
|
|
|
newAlpha = newAlpha - 1;
|
|
|
|
setAlphaRollover(true);
|
|
|
|
}
|
|
|
|
setAlpha(newAlpha);
|
2022-11-24 22:24:37 -07:00
|
|
|
|
2022-12-13 22:10:43 -07:00
|
|
|
return [...prevResults, result];
|
|
|
|
});
|
|
|
|
},
|
|
|
|
[alpha, alphaVelocity]
|
|
|
|
);
|
2022-11-24 22:24:37 -07:00
|
|
|
|
2022-12-14 20:53:52 -07:00
|
|
|
// State to handle the timeout for the player to not hog GPU forever. If you are
|
|
|
|
// in SAME_PROMPT for this long, it will pause the player and bring up an alert.
|
|
|
|
const timeoutIncrement = 600.0;
|
|
|
|
const [timeoutPlayerTime, setTimeoutPlayerTime] = useState(timeoutIncrement);
|
|
|
|
|
|
|
|
const nowPlayingCallback = useCallback(
|
|
|
|
(result: InferenceResult, playerTime: number) => {
|
|
|
|
console.log(
|
|
|
|
"Now playing result ",
|
|
|
|
result.counter,
|
|
|
|
", player time is ",
|
|
|
|
playerTime
|
2022-11-30 12:53:40 -07:00
|
|
|
);
|
2022-12-14 20:53:52 -07:00
|
|
|
|
|
|
|
setNowPlayingResult(result);
|
|
|
|
|
|
|
|
// find the first promptInput that matches the result.input.end.prompt and set it's transitionCounter to the result.counter if not already set
|
|
|
|
setPromptInputs((prevPromptInputs) => {
|
|
|
|
const newPromptInputs = [...prevPromptInputs];
|
|
|
|
const promptInputIndex = newPromptInputs.findIndex(
|
|
|
|
(p) => p.prompt == result.input.end.prompt
|
|
|
|
);
|
|
|
|
if (promptInputIndex >= 0) {
|
|
|
|
if (newPromptInputs[promptInputIndex].transitionCounter == null) {
|
|
|
|
newPromptInputs[promptInputIndex].transitionCounter =
|
|
|
|
result.counter;
|
|
|
|
}
|
2022-11-30 12:53:40 -07:00
|
|
|
}
|
2022-12-14 20:53:52 -07:00
|
|
|
return newPromptInputs;
|
2022-12-11 18:14:42 -07:00
|
|
|
});
|
2022-12-14 20:53:52 -07:00
|
|
|
|
|
|
|
// set played state for the result to true
|
|
|
|
setInferenceResults((prevResults: InferenceResult[]) => {
|
|
|
|
return prevResults.map((r) => {
|
|
|
|
if (r.counter == result.counter) {
|
|
|
|
r.played = true;
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// Extend the timeout if we're transitioning
|
|
|
|
if (appState == AppState.TRANSITION) {
|
|
|
|
setTimeoutPlayerTime(playerTime + timeoutIncrement);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we've hit the timeout, pause and increment the timeout
|
|
|
|
if (playerTime > timeoutPlayerTime) {
|
|
|
|
setTimeoutPlayerTime(playerTime + timeoutIncrement);
|
|
|
|
setPaused(true);
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
if (confirm("Are you still riffing?")) {
|
|
|
|
setPaused(false);
|
|
|
|
}
|
|
|
|
}, 100);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[timeoutPlayerTime, appState]
|
|
|
|
);
|
2022-11-24 22:24:37 -07:00
|
|
|
|
2022-12-13 23:29:49 -07:00
|
|
|
// Track from the audio player whether we're behind on having new inference results,
|
|
|
|
// in order to display an alert.
|
|
|
|
const [playerIsBehind, setPlayerIsBehind] = useState(false);
|
|
|
|
const playerIsBehindCallback = (isBehind: boolean) => {
|
|
|
|
setPlayerIsBehind(isBehind);
|
|
|
|
};
|
|
|
|
|
2022-12-12 23:28:14 -07:00
|
|
|
// TODO(hayk): This is not done yet but it's supposed to clear out future state and prompts
|
|
|
|
// and allow the user to immediately start a new prompt.
|
|
|
|
const resetCallback = () => {
|
|
|
|
console.log("RESET");
|
|
|
|
|
|
|
|
setPromptInputs([
|
|
|
|
promptInputs[0],
|
|
|
|
promptInputs[1],
|
|
|
|
promptInputs[2],
|
|
|
|
{ prompt: "" },
|
|
|
|
{ prompt: "" },
|
|
|
|
{ prompt: "" },
|
|
|
|
]);
|
|
|
|
|
|
|
|
if (nowPlayingResult == null) {
|
|
|
|
setInferenceResults([]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// const counter = nowPlayingResult ? nowPlayingResult.counter : -1;
|
|
|
|
// setInferenceResults(inferenceResults.filter((r) => r.counter <= counter));
|
|
|
|
// setNowPlayingResult(null);
|
|
|
|
};
|
|
|
|
|
2022-12-14 01:10:23 -07:00
|
|
|
useEffect(() => {
|
2022-12-14 02:13:40 -07:00
|
|
|
unmute(Tone.context.rawContext, true, false);
|
2022-12-14 01:10:23 -07:00
|
|
|
}, []);
|
|
|
|
|
2022-11-20 12:56:36 -07:00
|
|
|
return (
|
2022-11-20 14:39:15 -07:00
|
|
|
<>
|
2022-11-27 17:59:00 -07:00
|
|
|
<PageHead />
|
2022-11-20 12:56:36 -07:00
|
|
|
|
2022-12-13 12:43:17 -07:00
|
|
|
<div className="absolute w-full h-screen z-10">
|
2022-12-13 22:10:43 -07:00
|
|
|
{/* Note, top bg section is used to maintain color in background on ios notch devices */}
|
|
|
|
<div className="absolute top-0 left-0 right-0 h-1 bg-[#0A2342]" />
|
|
|
|
<div className="absolute top-1 left-0 right-0 h-1/2 bg-gradient-to-b from-[#0A2342]" />
|
|
|
|
</div>
|
2022-12-13 12:43:17 -07:00
|
|
|
|
2022-11-24 12:41:41 -07:00
|
|
|
<div className="bg-[#0A2342] flex flex-row min-h-screen text-white">
|
2022-12-13 12:43:17 -07:00
|
|
|
<div className="absolute w-full md:w-1/3">
|
|
|
|
<div className="absolute top-4 md:top-6 left-0 right-0 flex justify-center">
|
|
|
|
<div
|
2022-12-13 22:10:43 -07:00
|
|
|
className="text-3xl font-bold font-mono text-transparent bg-clip-text bg-gradient-to-t from-white/80 to-white/70 z-20 cursor-pointer"
|
2022-12-13 12:43:17 -07:00
|
|
|
onClick={() => window.open("/about", "_blank")}
|
|
|
|
>
|
|
|
|
[RIFFUSION]
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2022-12-13 23:29:49 -07:00
|
|
|
{playerIsBehind ? <FallingBehindWarning /> : null}
|
|
|
|
|
2022-12-08 15:34:03 -07:00
|
|
|
<div className="brightness-50 md:filter-none w-full z-0 md:w-1/3 min-h-screen">
|
2022-11-25 22:17:29 -07:00
|
|
|
<ThreeCanvas
|
|
|
|
paused={paused}
|
|
|
|
getTime={() => Tone.Transport.seconds}
|
|
|
|
inferenceResults={inferenceResults}
|
|
|
|
/>
|
2022-11-20 14:39:15 -07:00
|
|
|
</div>
|
|
|
|
|
2022-11-27 16:38:00 -07:00
|
|
|
<ModelInference
|
|
|
|
alpha={alpha}
|
2022-12-13 22:10:43 -07:00
|
|
|
alphaRollover={alphaRollover}
|
2022-11-27 16:38:00 -07:00
|
|
|
seed={seed}
|
|
|
|
appState={appState}
|
|
|
|
promptInputs={promptInputs}
|
2022-11-27 17:46:10 -07:00
|
|
|
nowPlayingResult={nowPlayingResult}
|
2022-11-27 16:38:00 -07:00
|
|
|
newResultCallback={newResultCallback}
|
2022-12-12 19:23:03 -07:00
|
|
|
useBaseten={process.env.NEXT_PUBLIC_RIFFUSION_USE_BASETEN == "true"}
|
2022-12-12 22:43:34 -07:00
|
|
|
denoising={denoising}
|
|
|
|
seedImageId={seedImageId}
|
2022-11-27 16:38:00 -07:00
|
|
|
/>
|
2022-12-12 19:23:03 -07:00
|
|
|
|
2022-11-27 17:46:10 -07:00
|
|
|
<AudioPlayer
|
|
|
|
paused={paused}
|
|
|
|
inferenceResults={inferenceResults}
|
|
|
|
nowPlayingCallback={nowPlayingCallback}
|
2022-12-13 23:29:49 -07:00
|
|
|
playerIsBehindCallback={playerIsBehindCallback}
|
2022-12-23 17:38:05 -07:00
|
|
|
useCompressor={true}
|
2022-11-27 17:46:10 -07:00
|
|
|
/>
|
2022-11-27 14:53:22 -07:00
|
|
|
|
2022-11-23 23:08:00 -07:00
|
|
|
<PromptPanel
|
|
|
|
prompts={promptInputs}
|
2022-11-30 12:53:40 -07:00
|
|
|
inferenceResults={inferenceResults}
|
|
|
|
nowPlayingResult={nowPlayingResult}
|
2022-11-30 17:30:52 -07:00
|
|
|
appState={appState}
|
2022-11-24 19:32:39 -07:00
|
|
|
changePrompt={(prompt: string, index: number) => {
|
2022-11-24 16:23:20 -07:00
|
|
|
const newPromptInputs = [...promptInputs];
|
2022-11-24 19:32:39 -07:00
|
|
|
newPromptInputs[index].prompt = prompt;
|
2022-11-24 16:23:20 -07:00
|
|
|
setPromptInputs(newPromptInputs);
|
|
|
|
}}
|
2022-12-14 13:44:10 -07:00
|
|
|
setPaused={setPaused}
|
2022-12-12 23:28:14 -07:00
|
|
|
resetCallback={resetCallback}
|
2022-11-23 23:08:00 -07:00
|
|
|
/>
|
2022-11-20 14:56:58 -07:00
|
|
|
|
2022-12-14 20:53:52 -07:00
|
|
|
<Pause paused={paused} setPaused={setPaused} />
|
2022-11-20 15:02:14 -07:00
|
|
|
|
2022-12-02 14:18:00 -07:00
|
|
|
<Share
|
|
|
|
inferenceResults={inferenceResults}
|
|
|
|
nowPlayingResult={nowPlayingResult}
|
|
|
|
/>
|
2022-12-02 12:54:47 -07:00
|
|
|
|
2022-12-12 19:23:03 -07:00
|
|
|
<Settings
|
|
|
|
promptInputs={promptInputs}
|
|
|
|
inferenceResults={inferenceResults}
|
|
|
|
nowPlayingResult={nowPlayingResult}
|
2022-12-12 22:43:34 -07:00
|
|
|
denoising={denoising}
|
|
|
|
setDenoising={setDenoising}
|
|
|
|
seedImage={seedImageId}
|
|
|
|
setSeedImage={setSeedImageId}
|
2022-12-11 18:14:42 -07:00
|
|
|
/>
|
2022-11-20 14:39:15 -07:00
|
|
|
</div>
|
|
|
|
</>
|
2022-11-20 12:56:36 -07:00
|
|
|
);
|
|
|
|
}
|