diff --git a/app/audio/AudioForm.tsx b/app/audio/AudioForm.tsx
index 0bdf8cd..0dce8be 100644
--- a/app/audio/AudioForm.tsx
+++ b/app/audio/AudioForm.tsx
@@ -9,8 +9,13 @@ import getTempo from "@/utils/getTempo";
import isolateAudio from "@/utils/isolateAudio";
import getAudioFromURL from "@/utils/getAudioFromUrl";
import { useToast } from "@/hooks/use-toast";
+import Loading from "@/components/Loading";
-export default function AudioForm() {
+export default function AudioForm({
+ setFormComplete,
+}: {
+ setFormComplete: (value: boolean) => void;
+}) {
const { audioForm, setAudioForm, setAudioStorage, songName } =
useContext(AudioContext);
const isPart1Complete = audioForm.audio_file || audioForm.audio_link;
@@ -72,7 +77,10 @@ export default function AudioForm() {
// Make API Request
isolateAudio(formData, setAudioStorage).then(() => {
- setIsSubmitting(false);
+ setTimeout(() => {
+ setIsSubmitting(false);
+ setisLoading(false);
+ }, 2000);
});
} catch (error) {
console.error(error);
@@ -151,16 +159,14 @@ export default function AudioForm() {
in={isLoading}
timeout={700}
classNames="fade"
+ onExited={() => setFormComplete(true)}
unmountOnExit
>
-
- Loading...
-
- {/* */}
+
diff --git a/app/audio/AudioPart3.tsx b/app/audio/AudioPart3.tsx
index 1043ac7..a3ba30f 100644
--- a/app/audio/AudioPart3.tsx
+++ b/app/audio/AudioPart3.tsx
@@ -132,7 +132,7 @@ export default function AudioPart3({
Submit
diff --git a/app/audio/MidiEditor.tsx b/app/audio/MidiEditor.tsx
index d2451e0..fe4c6ed 100644
--- a/app/audio/MidiEditor.tsx
+++ b/app/audio/MidiEditor.tsx
@@ -3,10 +3,10 @@
import {
Dispatch,
FormEventHandler,
+ forwardRef,
MouseEventHandler,
SetStateAction,
useContext,
- useEffect,
useRef,
useState,
} from "react";
@@ -24,182 +24,191 @@ import {
import AudioMixer from "@/components/AudioMixer";
import { convertToMidi } from "@/utils/getMidi";
-export default function MidiEditor({
- conversionFlag,
-}: {
+interface Props {
conversionFlag: Dispatch>;
-}) {
- const { audioStorage, setAudioStorage, audioForm } = useContext(AudioContext);
- const [selectedMidi, setSelectedMidi] = useState(0);
- const midiAdjustments = useRef(null);
- const audioControls = useRef(null);
- const [midiOpen, setMidiOpen] = useState(false);
-
- const [midiVolume, setMidiVolume] = useState(50);
- const [midiPan, setMidiPan] = useState(0);
- const midiControls = {
- volume: midiVolume,
- setVolume: setMidiVolume,
- pan: midiPan,
- setPan: setMidiPan,
- };
-
- const [audioVolume, setAudioVolume] = useState(50);
- const [audioPan, setAudioPan] = useState(0);
- const originalAudioControls = {
- volume: audioVolume,
- setVolume: setAudioVolume,
- pan: audioPan,
- setPan: setAudioPan,
- };
-
- const storageArray = Object.entries(
- audioStorage as Record,
- );
- const key = storageArray[selectedMidi][0];
- const isDrums = key === "drums";
- const isLastKey = selectedMidi === storageArray.length - 1;
- const isFirstKey = selectedMidi === 0;
- const stem = (audioStorage as Record)[
- key as keyof AudioStorage
- ];
-
- const handleOpen: MouseEventHandler = (_event) => {
- setTimeout(() => {
- if (!midiAdjustments.current || !audioControls.current) return;
- if (midiAdjustments.current.dataset.state === "open") setMidiOpen(true);
- else setMidiOpen(false);
- }, 50);
- };
-
- const handleRegenerateMidi: FormEventHandler = async (e) => {
- e.preventDefault();
- conversionFlag(true);
-
- setAudioStorage((prev) => {
- if (!prev) return prev;
- const updatedStorage: AudioStorage = { ...prev };
- const name = stem.name;
- updatedStorage[name] = {
- ...updatedStorage[name],
- midiBlob: null,
- };
+}
- return updatedStorage;
- });
+const MidiEditor = forwardRef(
+ ({ conversionFlag }: Props, ref: React.ForwardedRef) => {
+ const { audioStorage, setAudioStorage, audioForm } =
+ useContext(AudioContext);
+ const [selectedMidi, setSelectedMidi] = useState(0);
+ const midiAdjustments = useRef(null);
+ const audioControls = useRef(null);
+ const [midiOpen, setMidiOpen] = useState(false);
+
+ const [midiVolume, setMidiVolume] = useState(50);
+ const [midiPan, setMidiPan] = useState(0);
+ const midiControls = {
+ volume: midiVolume,
+ setVolume: setMidiVolume,
+ pan: midiPan,
+ setPan: setMidiPan,
+ };
- const formData = new FormData(e.currentTarget);
- const adjustments: midiAdjustments = {
- onset_threshold: formData.get("note_segmentation") as string,
- frame_threshold: formData.get("confidence_threshold") as string,
- minimum_note_length: formData.get("minimum_note_length") as string,
+ const [audioVolume, setAudioVolume] = useState(50);
+ const [audioPan, setAudioPan] = useState(0);
+ const originalAudioControls = {
+ volume: audioVolume,
+ setVolume: setAudioVolume,
+ pan: audioPan,
+ setPan: setAudioPan,
};
- const maxFreq = parseInt(formData.get("maximum_frequency") as string);
- if (maxFreq < 18000) {
- adjustments.maximum_frequency = maxFreq.toString();
- }
- const minFreq = parseInt(formData.get("minimum_frequency") as string);
- if (minFreq > 0) {
- adjustments.minimum_frequency = minFreq.toString();
- }
-
- const newMidi = await convertToMidi(
- stem,
- audioForm.tempo as number,
- false,
- adjustments,
+
+ const storageArray = Object.entries(
+ audioStorage as Record,
);
+ const key = storageArray[selectedMidi][0];
+ const isDrums = key === "drums";
+ const isLastKey = selectedMidi === storageArray.length - 1;
+ const isFirstKey = selectedMidi === 0;
+ const stem = (audioStorage as Record)[
+ key as keyof AudioStorage
+ ];
+
+ const handleOpen: MouseEventHandler = (_event) => {
+ setTimeout(() => {
+ if (!midiAdjustments.current || !audioControls.current) return;
+ if (midiAdjustments.current.dataset.state === "open") setMidiOpen(true);
+ else setMidiOpen(false);
+ }, 50);
+ };
+
+ const handleRegenerateMidi: FormEventHandler = async (
+ e,
+ ) => {
+ e.preventDefault();
+ conversionFlag(true);
- setAudioStorage((prev) => {
- if (!prev) return prev;
- const updatedStorage: AudioStorage = { ...prev };
- const name = stem.name;
- updatedStorage[name] = {
- ...updatedStorage[name],
- midiBlob: newMidi,
+ setAudioStorage((prev) => {
+ if (!prev) return prev;
+ const updatedStorage: AudioStorage = { ...prev };
+ const name = stem.name;
+ updatedStorage[name] = {
+ ...updatedStorage[name],
+ midiBlob: null,
+ };
+
+ return updatedStorage;
+ });
+
+ const formData = new FormData(e.currentTarget);
+ const adjustments: midiAdjustments = {
+ onset_threshold: formData.get("note_segmentation") as string,
+ frame_threshold: formData.get("confidence_threshold") as string,
+ minimum_note_length: formData.get("minimum_note_length") as string,
};
+ const maxFreq = parseInt(formData.get("maximum_frequency") as string);
+ if (maxFreq < 18000) {
+ adjustments.maximum_frequency = maxFreq.toString();
+ }
+ const minFreq = parseInt(formData.get("minimum_frequency") as string);
+ if (minFreq > 0) {
+ adjustments.minimum_frequency = minFreq.toString();
+ }
+
+ const newMidi = await convertToMidi(
+ stem,
+ audioForm.tempo as number,
+ false,
+ adjustments,
+ );
+
+ setAudioStorage((prev) => {
+ if (!prev) return prev;
+ const updatedStorage: AudioStorage = { ...prev };
+ const name = stem.name;
+ updatedStorage[name] = {
+ ...updatedStorage[name],
+ midiBlob: newMidi,
+ };
- return updatedStorage;
- });
- conversionFlag(false);
- };
-
- return (
-
- {/* ^ div should have xl:max-w-1200px */}
-
-
-
+
- {!isDrums && (
-
+
+ {!isDrums && (
+
+
+ Midi Adjustments
+
+
+
+
+
+ )}
+
- Midi Adjustments
+ Audio Controls
-
-
+
+
+
- )}
-
-
- Audio Controls
-
-
-
-
-
-
-
- {!midiOpen && (
-
- {!isFirstKey && (
-
setSelectedMidi(selectedMidi - 1)}
- className="button-secondary flex h-min w-full cursor-pointer items-center justify-center gap-2 rounded-3xl border-2 border-border px-6 py-2 text-base font-semibold transition-colors xl:max-w-[300px]"
- >
- Back
-
- )}
- {!isLastKey ? (
-
setSelectedMidi(selectedMidi + 1)}
- className="button-primary flex h-min w-full cursor-pointer items-center justify-center gap-2 rounded-3xl px-6 py-2 text-base font-semibold transition-colors xl:max-w-[300px]"
- >
- Next
-
- ) : (
-
- Export
-
- )}
- )}
-
-
- );
-}
+ {!midiOpen && (
+
+ {!isFirstKey && (
+
setSelectedMidi(selectedMidi - 1)}
+ className="button-secondary flex h-min w-full cursor-pointer items-center justify-center gap-2 rounded-3xl border-2 border-border px-6 py-2 text-base transition-colors xl:max-w-[300px]"
+ >
+ Back
+
+ )}
+ {!isLastKey ? (
+
setSelectedMidi(selectedMidi + 1)}
+ className="button-primary flex h-min w-full cursor-pointer items-center justify-center gap-2 rounded-3xl px-6 py-2 text-base transition-colors xl:max-w-[300px]"
+ >
+ Next
+
+ ) : (
+
+ Export
+
+ )}
+
+ )}
+
+
+ );
+ },
+);
+
+export default MidiEditor;
diff --git a/app/audio/page.tsx b/app/audio/page.tsx
index dbd4bde..bff91dc 100644
--- a/app/audio/page.tsx
+++ b/app/audio/page.tsx
@@ -1,6 +1,7 @@
"use client";
import React, { useContext, useEffect, useRef, useState } from "react";
+import { CSSTransition } from "react-transition-group";
import { AudioContext } from "./AudioProvider";
import AudioForm from "./AudioForm";
import handleMidiConversion from "@/utils/getMidi";
@@ -10,9 +11,11 @@ export default function Page() {
const { audioForm, audioStorage, setAudioStorage, songName } =
useContext(AudioContext);
const [flatScore, setFlatScore] = useState(null);
+ const [formComplete, setFormComplete] = useState(false);
const [isConverting, setIsConverting] = useState(false);
const [isMidiComplete, setIsMidiComplete] = useState(false);
const flatRef = useRef(null);
+ const editorRef = useRef(null);
// Convert to Midi
useEffect(() => {
@@ -66,8 +69,16 @@ export default function Page() {
className="flex w-full max-w-[1200px] flex-col items-center justify-around px-8 sm:px-20 xl:px-0"
id="resize container"
>
- {!audioStorage && }
- {audioStorage && }
+ {!formComplete && }
+
+
+
{/* {isMidiComplete && (
(null);
+ const [info, setInfo] = useState(null);
+ const [index, setIndex] = useState(-1);
+ if (index === -1) {
+ setIndex(Math.floor(Math.random() * infoList.length));
+ }
+
+ const dots = Array.from({ length: dotCount }, (_, index) => (
+
+ .
+
+ ));
+
+ const changeInfo = () => {
+ let randomIndex;
+ do {
+ randomIndex = Math.floor(Math.random() * infoList.length);
+ } while (randomIndex === index);
+
+ setInfo(infoList[randomIndex]);
+ setIndex(randomIndex);
+ setInfoTrigger(true);
+ };
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setInfoTrigger((prev) => !prev);
+ }, 12000);
+
+ return () => clearInterval(interval);
+ }, [infoTrigger]);
+
+ return (
+ <>
+
+ {text}
+ {dots}
+
+
+
+ {info ?? infoList[index]}
+
+
+ >
+ );
+}
diff --git a/components/MidiAdjustments.tsx b/components/MidiAdjustments.tsx
index de6e27f..fdbfe49 100644
--- a/components/MidiAdjustments.tsx
+++ b/components/MidiAdjustments.tsx
@@ -1,6 +1,7 @@
"use client";
import MidiSlider from "@/components/MidiSlider";
import { Button } from "@/components/ui/button";
+import { useScreenSize } from "@/hooks/use-screen-size";
import { FormEvent, useState } from "react";
export default function MidiAdjustments({
@@ -9,6 +10,7 @@ export default function MidiAdjustments({
handleSubmit: (event: FormEvent) => void;
}) {
const [reset, setReset] = useState(false);
+ const screenSize = useScreenSize();
const handleReset = (event: FormEvent) => {
event.preventDefault();
setReset((prev) => !prev);
@@ -70,7 +72,7 @@ export default function MidiAdjustments({
Reset
- Regenerate Midi
+ Regenerate {screenSize != "xs" ? "Midi" : ""}
);
diff --git a/hooks/use-screen-size.ts b/hooks/use-screen-size.ts
new file mode 100644
index 0000000..e3bc046
--- /dev/null
+++ b/hooks/use-screen-size.ts
@@ -0,0 +1,38 @@
+import { useState, useEffect } from "react";
+
+type ScreenSize = "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "";
+
+export const useScreenSize = (): ScreenSize => {
+ const [screenSize, setScreenSize] = useState("");
+
+ useEffect(() => {
+ const handleResize = () => {
+ if (window.innerWidth < 640) {
+ setScreenSize("xs");
+ } else if (window.innerWidth >= 640 && window.innerWidth < 768) {
+ setScreenSize("sm");
+ } else if (window.innerWidth >= 768 && window.innerWidth < 1024) {
+ setScreenSize("md");
+ } else if (window.innerWidth >= 1024 && window.innerWidth < 1280) {
+ setScreenSize("lg");
+ } else if (window.innerWidth >= 1280 && window.innerWidth < 1536) {
+ setScreenSize("xl");
+ } else if (window.innerWidth >= 1536) {
+ setScreenSize("2xl");
+ } else {
+ setScreenSize(""); // Fallback for unexpected cases
+ }
+ };
+
+ // Add the resize event listener
+ window.addEventListener("resize", handleResize);
+
+ // Call the handler once to set the initial screen size
+ handleResize();
+
+ // Clean up the event listener on unmount
+ return () => window.removeEventListener("resize", handleResize);
+ }, []);
+
+ return screenSize;
+};
diff --git a/utils/infoList.ts b/utils/infoList.ts
new file mode 100644
index 0000000..c7ceec3
--- /dev/null
+++ b/utils/infoList.ts
@@ -0,0 +1,8 @@
+export const infoList = [
+ "You can adjust the volume and pan of the midi audio and original audio while it's playing.",
+ "It is recommended when uploading a solo instrument recording to provide a tempo. Otherwise, the tempo will automatically be calculated.",
+ "If the tempo was not able to be detected properly, it will default to 120 BPM.",
+ "Hey, I'm glad that you got the backend set up. Thank you so much for taking the time to check out my project! ^_^",
+ "If there are any unnecessarily high or low notes in the midi, you can adjust the min and max frequencies and regenerate it.",
+ "The backdoor dominant is the five chord in the relative major of the parallel minor.",
+];