import { useEffect, useRef, useState, type Dispatch, type SetStateAction, } from "react"; import clsx from "clsx"; import { ConditioningPanel } from "./ConditioningPanel"; import type { AppError } from "../App"; const SERVER_DOWN = "The muscriptor server is temporarily unavailable."; /** * First screen of the two-step flow: pick an audio file, then optionally choose * conditioning instruments, then hit "Transcribe" to hand off to the main view. * Transcription doesn't start until the button is clicked. */ export function WelcomeScreen(props: { selectedFile: File | null; onPickFile: (file: File) => void; /** Loads the bundled demo track + its suggested conditioning. */ onUseExample: () => Promise; condSelected: Set; onCondChange: (next: Set) => void; onTranscribe: () => void; /** True while a file is dragged over the window; swaps the prompt in place. */ dragging: boolean; /** A server-down notice replaces the picker; a file error sits beside it. */ error: AppError | null; setError: Dispatch>; }) { const { selectedFile, onPickFile, onUseExample, condSelected, onCondChange, onTranscribe, dragging, error, setError, } = props; const fileInputRef = useRef(null); const [loadingExample, setLoadingExample] = useState(false); // Probe the server on mount. A failure swaps the file picker for a // server-down notice; success clears a stale server-down notice so the user // can try again once the server recovers. A file error (e.g. an undecodable // upload) is left alone — the server being up doesn't make a bad file good. useEffect(() => { let cancelled = false; const clearServerError = () => setError((prev) => (prev?.kind === "server" ? null : prev)); fetch("/health") .then((r) => { if (cancelled) return; if (r.ok) clearServerError(); else setError({ kind: "server", message: SERVER_DOWN }); }) .catch(() => { if (!cancelled) setError({ kind: "server", message: SERVER_DOWN }); }); return () => { cancelled = true; }; }, [setError]); async function handleExample() { setLoadingExample(true); try { await onUseExample(); } catch (e) { alert("Couldn't load the example file: " + (e as Error).message); } finally { setLoadingExample(false); } } return (

MuScriptor is the best open model for multi-instrument transcription to date. Give it a recording: pop, classical, metal, jazz, whatever, and it transcribes the notes played by every instrument into MIDI, for you to download or explore interactively.

{ const f = e.target.files?.[0]; if (f) onPickFile(f); // Allow re-picking the same file (onChange won't fire otherwise). e.target.value = ""; }} />
{error?.kind === "server" ? (

unavailable

{error.message}

) : selectedFile === null ? (
) : (

{selectedFile.name}

)}
{error?.kind === "file" && (

{error.message}

)} {error?.kind !== "server" && selectedFile !== null && ( <>
)}
); }