PageSourceSearch

https://www.hamienet.com/assets/ConverterPage-BBskLDF8.js

js hamienet.com collected 2026-10-02 04:59:51 UTC 84,541 bytes, 1,368 lines download raw bytes

1const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/MidiEngine-2SYF-_aI.js","assets/vendor-audio-D-wTggbx.js","assets/vendor-react-Bay9Y7Lb.js","assets/vendor-D0P4XgNj.js","assets/vendor-i18n-BC7ZMXWQ.js","assets/vendor-DqKRdbjz.css","assets/vendor-spessasynth-DH8n6o_V.js"])))=>i.map(i=>d[i]);
2import { _ as __vitePreload } from "./vendor-react-three-BCww3P1x.js";
3import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js";
4import { u as useSettings, a as api } from "./index-w5lXls15.js";
5import { g as getActionCost } from "./credit-rules-8PgauDOD.js";
6import { W as Waveform } from "./Waveform-BgnMyg5E.js";
7import { A as AdSlot } from "./AdSlot-BEBlpA_I.js";
8import { C as CreditsExhaustedModal } from "./CreditsExhaustedModal-DRhMaBTs.js";
9import { u as useTranslation } from "./vendor-i18n-BC7ZMXWQ.js";
10import { b3 as FileHeadphone, b2 as Upload, db as Music2, b_ as Pause, bV as Play, cq as Settings2, ck as Layers, bU as Volume2, cg as Activity, dh as SlidersVertical, bq as Coins, cM as RefreshCw, a_ as CircleCheck, d1 as Download, b1 as CircleAlert } from "./vendor-D0P4XgNj.js";
11import "./vendor-framer-B-4FZk1Z.js";
12const ConverterPage = ({ currentUser, onAuthRequested, onPublish }) => {
13  const { t } = useTranslation();
14  const { formatNumber } = useSettings();
15  const [file, setFile] = reactExports.useState(null);
16  const [jobId, setJobId] = reactExports.useState(null);
17  const [status, setStatus] = reactExports.useState("idle");
18  const [errorMsg, setErrorMsg] = reactExports.useState("");
19  const [isCreditsExhaustedModalOpen, setIsCreditsExhaustedModalOpen] = reactExports.useState(false);
20  const [result, setResult] = reactExports.useState(null);
21  const [isPlaying, setIsPlaying] = reactExports.useState(false);
22  const [currentTime, setCurrentTime] = reactExports.useState(0);
23  const [duration, setDuration] = reactExports.useState(0);
24  const fileInputRef = reactExports.useRef(null);
25  const audioRef = reactExports.useRef(null);
26  const pollingInterval = reactExports.useRef(null);
27  const shouldClearFileOnPopRef = reactExports.useRef(false);
28  const [logs, setLogs] = reactExports.useState("");
29  const logContainerRef = reactExports.useRef(null);
30  const [creditCost, setCreditCost] = reactExports.useState(5);
31  const [extraSfCost, setExtraSfCost] = reactExports.useState(2);
32  const [wavSurchargeCost, setWavSurchargeCost] = reactExports.useState(10);
33  const [extraFormatCost, setExtraFormatCost] = reactExports.useState(2);
34  const [progressMsg, setProgressMsg] = reactExports.useState("");
35  const [percent, setPercent] = reactExports.useState(null);
36  const [isBuyingWav, setIsBuyingWav] = reactExports.useState(false);
37  const [soundfonts, setSoundfonts] = reactExports.useState([]);
38  const [tempLifetimeHours, setTempLifetimeHours] = reactExports.useState(12);
39  const [guestUsage, setGuestUsage] = reactExports.useState(null);
40  const [freeCredits, setFreeCredits] = reactExports.useState(25);
41  const [activeOutputIdx, setActiveOutputIdx] = reactExports.useState(0);
42  const [mixingSettings, setMixingSettings] = reactExports.useState({
43    soundfont: "",
44    soundfonts: [],
45    reverb: 0.2,
46    chorus: 0,
47    // Aligned with site standard processing
48    gain: 1,
49    format: "mp3",
50    formats: ["mp3"],
51    exportStems: false,
52    mastering: true
53  });
54  const [midiBuffer, setMidiBuffer] = reactExports.useState(null);
55  const [isMidiPlaying, setIsMidiPlaying] = reactExports.useState(false);
56  const [midiCurrentTime, setMidiCurrentTime] = reactExports.useState(0);
57  const [midiDuration, setMidiDuration] = reactExports.useState(0);
58  const [isMidiLoading, setIsMidiLoading] = reactExports.useState(false);
59  const midiEngineRef = reactExports.useRef(null);
60  const audioCtxRef = reactExports.useRef(null);
61  const midiTimerRef = reactExports.useRef(null);
62  const N = Math.max(1, mixingSettings.soundfonts.length);
63  const soundfontsCost = extraSfCost * (N - 1);
64  const hasWav = mixingSettings.formats.some((f) => f.toLowerCase() === "wav");
65  const wavSurchargeTotal = hasWav ? wavSurchargeCost * N : 0;
66  let extraFormatsCost = 0;
67  const extraFormats = mixingSettings.formats.slice(1);
68  for (const fmt of extraFormats) {
69    if (fmt.toLowerCase() !== "wav") {
70      extraFormatsCost += extraFormatCost;
71    }
72  }
73  const currentCost = creditCost + soundfontsCost + wavSurchargeTotal + extraFormatsCost * N;
74  const stopMidiPlayback = () => {
75    if (midiTimerRef.current) {
76      clearInterval(midiTimerRef.current);
77      midiTimerRef.current = null;
78    }
79    if (midiEngineRef.current) {
80      try {
81        midiEngineRef.current.stop();
82        midiEngineRef.current.destroy();
83      } catch (e) {
84        console.warn(e);
85      }
86      midiEngineRef.current = null;
87    }
88    setIsMidiPlaying(false);
89    setMidiCurrentTime(0);
90  };
91  const toggleMidiPlayback = async () => {
92    if (!midiBuffer) return;
93    if (isMidiPlaying) {
94      if (midiEngineRef.current) {
95        midiEngineRef.current.pause();
96      }
97      setIsMidiPlaying(false);
98      if (midiTimerRef.current) {
99        clearInterval(midiTimerRef.current);
100        midiTimerRef.current = null;
101      }
102    } else {
103      setIsPlaying(false);
104      setIsMidiLoading(true);
105      try {
106        if (!audioCtxRef.current) {
107          audioCtxRef.current = new (window.AudioContext || window.webkitAudioContext)();
108        }
109        if (audioCtxRef.current.state === "suspended") {
110          await audioCtxRef.current.resume();
111        }
112        if (!midiEngineRef.current) {
113          const sfPath = mixingSettings.soundfonts[0] || mixingSettings.soundfont;
114          const sfUrl = `/storage/soundfonts/${sfPath}`;
115          const { MidiEngine } = await __vitePreload(async () => {
116            const { MidiEngine: MidiEngine2 } = await import("./MidiEngine-2SYF-_aI.js");
117            return { MidiEngine: MidiEngine2 };
118          }, true ? __vite__mapDeps([0,1,2,3,4,5,6]) : void 0);
119          midiEngineRef.current = new MidiEngine(audioCtxRef.current, audioCtxRef.current.destination, sfUrl);
120          await midiEngineRef.current.initialize();
121          midiEngineRef.current.loadMidi(midiBuffer);
122        }
123        await midiEngineRef.current.play();
124        setIsMidiPlaying(true);
125        setMidiDuration(midiEngineRef.current.getDuration() || 0);
126        midiTimerRef.current = setInterval(() => {
127          if (midiEngineRef.current) {
128            const cur = midiEngineRef.current.getCurrentTime();
129            setMidiCurrentTime(cur);
130            if (cur >= midiEngineRef.current.getDuration() - 0.2) {
131              stopMidiPlayback();
132            }
133          }
134        }, 200);
135      } catch (err) {
136        console.error("Midi playback failed:", err);
137        alert("Failed to initialize client synth: " + err.message);
138        stopMidiPlayback();
139      } finally {
140        setIsMidiLoading(false);
141      }
142    }
143  };
144  const handleMidiSeek = (time) => {
145    if (midiEngineRef.current) {
146      midiEngineRef.current.seek(time);
147      setMidiCurrentTime(time);
148    }
149  };
150  const handleSoundfontsChange = (newSfs) => {
151    stopMidiPlayback();
152    setMixingSettings((prev) => ({
153      ...prev,
154      soundfonts: newSfs,
155      soundfont: newSfs[0] || ""
156    }));
157  };
158  reactExports.useEffect(() => {
159    if (file) {
160      const reader = new FileReader();
161      reader.onload = (e) => {
162        var _a;
163        if ((_a = e.target) == null ? void 0 : _a.result) {
164          setMidiBuffer(e.target.result);
165        }
166      };
167      reader.readAsArrayBuffer(file);
168    } else {
169      setMidiBuffer(null);
170      stopMidiPlayback();
171    }
172    return () => {
173      stopMidiPlayback();
174    };
175  }, [file]);
176  reactExports.useEffect(() => {
177    const pageTitle = t("converter.title", "MIDI Converter");
178    document.title = `${pageTitle} | HamieNet`;
179    api.getSoundfonts().then((res) => {
180      const meta = res.metadata || {};
181      const filteredSf = (res.files || []).filter((sf) => {
182        const isSf2 = sf.path.toLowerCase().endsWith(".sf2");
183        const baseName = sf.path.replace(/\.h?sf[23]$/i, "");
184        const folderMeta = meta[baseName] || {};
185        const formatMeta = meta[sf.path] || {};
186        const combinedMeta = { ...folderMeta, ...formatMeta };
187        return isSf2 && combinedMeta.visibleConverter !== false;
188      }).map((sf) => {
189        const baseName = sf.path.replace(/\.h?sf[23]$/i, "");
190        const folderMeta = meta[baseName] || {};
191        const formatMeta = meta[sf.path] || {};
192        const combinedMeta = { ...folderMeta, ...formatMeta };
193        return {
194          ...sf,
195          displayName: folderMeta.name || combinedMeta.name || baseName.replace(/_/g, " ")
196        };
197      }).sort((a, b) => (a.displayName || a.path).localeCompare(b.displayName || b.path, void 0, { sensitivity: "base", numeric: true }));
198      setSoundfonts(filteredSf);
199      const defaultSf = res.defaultConverterSf || res.active;
200      if (defaultSf && defaultSf.toLowerCase().endsWith(".sf2")) {
201        setMixingSettings((prev) => ({
202          ...prev,
203          soundfont: prev.soundfont || defaultSf,
204          soundfonts: prev.soundfonts.length > 0 ? prev.soundfonts : [defaultSf]
205        }));
206      } else if (filteredSf.length > 0) {
207        setMixingSettings((prev) => ({
208          ...prev,
209          soundfont: prev.soundfont || filteredSf[0].path,
210          soundfonts: prev.soundfonts.length > 0 ? prev.soundfonts : [filteredSf[0].path]
211        }));
212      }
213    }).catch((e) => console.warn("Failed to fetch soundfonts", e));
214    if (!currentUser) {
215      fetch("/api/convert/guest-usage").then((r) => r.json()).then((data) => {
216        if (data && data.success) {
217          setGuestUsage({
218            limit: data.limit,
219            spent: data.spent,
220            cost: data.cost
221          });
222          setCreditCost(data.cost);
223        }
224      }).catch((e) => console.warn("Failed to fetch guest usage", e));
225    }
226    api.getSystemSetting("credit_config").then((res) => {
227      var _a;
228      const config = res == null ? void 0 : res.value;
229      if (config) {
230        setCreditCost(getActionCost("conversion", config));
231        setExtraSfCost(getActionCost("conversion_extra_sf", config));
232        setWavSurchargeCost(getActionCost("conversion_wav_surcharge", config));
233        setExtraFormatCost(getActionCost("conversion_extra_format", config));
234        const freeTier = (_a = config.allotments) == null ? void 0 : _a.find((a) => a.id === "free");
235        if (freeTier == null ? void 0 : freeTier.base) {
236          setFreeCredits(freeTier.base);
237        }
238      }
239    }).catch((e) => console.warn("Failed to fetch credit config", e));
240    api.getSystemSetting("converter_config").then((res) => {
241      if ((res == null ? void 0 : res.value) && typeof res.value === "object") {
242        const val = res.value.tempFilesLifetimeHours;
243        if (val !== void 0) {
244          setTempLifetimeHours(Number(val));
245        }
246      }
247    }).catch((e) => console.warn("Failed to fetch converter config", e));
248    return () => {
249      document.title = "HamieNet";
250      stopMidiPlayback();
251      if (audioCtxRef.current) {
252        audioCtxRef.current.close().catch(() => {
253        });
254      }
255    };
256  }, [currentUser]);
257  const resetConverter = (clearFile = true) => {
258    var _a;
259    setIsPlaying(false);
260    stopMidiPlayback();
261    if ((_a = window.history.state) == null ? void 0 : _a.converterActive) {
262      shouldClearFileOnPopRef.current = clearFile;
263      window.history.back();
264    } else {
265      setStatus("idle");
266      if (clearFile) {
267        setFile(null);
268      }
269      setJobId(null);
270      setResult(null);
271      setErrorMsg("");
272    }
273  };
274  reactExports.useEffect(() => {
275    const handlePopState = (e) => {
276      if (status !== "idle" && (!e.state || !e.state.converterActive)) {
277        setStatus("idle");
278        if (shouldClearFileOnPopRef.current) {
279          setFile(null);
280        }
281        shouldClearFileOnPopRef.current = false;
282        setJobId(null);
283        setResult(null);
284        setErrorMsg("");
285        setIsPlaying(false);
286        stopMidiPlayback();
287      }
288    };
289    window.addEventListener("popstate", handlePopState);
290    return () => window.removeEventListener("popstate", handlePopState);
291  }, [status]);
292  reactExports.useEffect(() => {
293    if (logContainerRef.current) {
294      logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight;
295    }
296  }, [logs]);
297  const formatTime = (secs) => {
298    if (isNaN(secs) || !isFinite(secs)) return "0:00";
299    const m = Math.floor(secs / 60);
300    const s = Math.floor(secs % 60);
301    return `${m}:${s < 10 ? "0" : ""}${s}`;
302  };
303  const handleFileSelect = (e) => {
304    if (e.target.files && e.target.files[0]) {
305      setFile(e.target.files[0]);
306      setStatus("idle");
307      setResult(null);
308      setJobId(null);
309    }
310  };
311  const handleDrop = (e) => {
312    e.preventDefault();
313    if (e.dataTransfer.files && e.dataTransfer.files[0]) {
314      setFile(e.dataTransfer.files[0]);
315      setStatus("idle");
316      setResult(null);
317      setJobId(null);
318    }
319  };
320  const handleBuyWav = async () => {
321    var _a;
322    if (!result || !jobId) return;
323    const isGuest = !currentUser;
324    const confirmMsg = isGuest ? t("converter.buyWavGuestConfirm", `Downloading the WAV file will cost ${wavSurchargeCost} credits. Continue?`) : t("converter.buyWavConfirm", `Downloading the WAV file will cost ${wavSurchargeCost} credits. Your current balance is ${formatNumber(currentUser.credits || 0)}. Continue?`);
325    if (!confirm(confirmMsg)) {
326      return;
327    }
328    setIsBuyingWav(true);
329    try {
330      const activeOutput = ((_a = result.outputs) == null ? void 0 : _a[activeOutputIdx]) || {
331        soundfont: mixingSettings.soundfont
332      };
333      const sf = activeOutput.soundfont || mixingSettings.soundfont;
334      const res = await fetch("/api/convert/buy-wav", {
335        method: "POST",
336        headers: {
337          "Content-Type": "application/json"
338        },
339        body: JSON.stringify({
340          jobId,
341          soundfont: sf
342        })
343      });
344      const data = await res.json();
345      if (res.ok && data && data.success) {
346        if (currentUser && typeof data.newCredits === "number") {
347          currentUser.credits = data.newCredits;
348        }
349        const newOutput = {
350          format: "wav",
351          path: data.path,
352          soundfont: sf,
353          waveform: []
354        };
355        setResult((prev) => {
356          if (!prev) return null;
357          const nextOutputs = [...prev.outputs || []];
358          if (!nextOutputs.some((out) => out.format.toLowerCase() === "wav" && out.soundfont === sf)) {
359            nextOutputs.push(newOutput);
360          }
361          return {
362            ...prev,
363            outputs: nextOutputs
364          };
365        });
366        const link = document.createElement("a");
367        link.href = data.path;
368        link.download = `${result.title || "audio"}.wav`;
369        document.body.appendChild(link);
370        link.click();
371        document.body.removeChild(link);
372      } else {
373        alert(data.error || "Failed to purchase WAV file.");
374      }
375    } catch (e) {
376      alert(e.message || "An error occurred during purchase.");
377    } finally {
378      setIsBuyingWav(false);
379    }
380  };
381  const handleUpload = async () => {
382    if (!file) return;
383    const isGuest = !currentUser;
384    if (isGuest) {
385      const limit = (guestUsage == null ? void 0 : guestUsage.limit) || 15;
386      const spent = (guestUsage == null ? void 0 : guestUsage.spent) || 0;
387      const available = Math.max(0, limit - spent);
388      if (available < currentCost) {
389        setIsCreditsExhaustedModalOpen(true);
390        return;
391      }
392    }
393    const confirmMsg = isGuest ? t("converter.guestConfirm", `As a guest, this conversion costs ${currentCost} credits. Continue?`) : t("converter.creditConfirm", `This conversion will cost ${currentCost} credits. Your current balance is ${formatNumber(currentUser.credits || 0)}. Continue?`);
394    if (!confirm(confirmMsg)) {
395      return;
396    }
397    stopMidiPlayback();
398    setIsPlaying(false);
399    setStatus("uploading");
400    try {
401      window.history.pushState({ ...window.history.state, converterActive: true }, "");
402    } catch (e) {
403      console.warn("History pushState in ConverterPage blocked:", e);
404    }
405    setErrorMsg("");
406    setPercent(0);
407    setLogs("");
408    const formData = new FormData();
409    formData.append("midiFile", file);
410    formData.append("title", file.name.replace(".mid", ""));
411    formData.append("mixingSettings", JSON.stringify(mixingSettings));
412    try {
413      const res = await fetch("/api/convert", {
414        method: "POST",
415        body: formData
416      });
417      const data = await res.json();
418      if (res.ok && data && data.track) {
419        if (currentUser && typeof data.newCredits === "number") {
420          currentUser.credits = data.newCredits;
421        }
422        setStatus((prev) => {
423          if (prev === "uploading") {
424            setJobId(data.track.id);
425            return "processing";
426          }
427          return prev;
428        });
429      } else {
430        setStatus((prev) => {
431          if (prev === "uploading") {
432            if (res.status === 403 && isGuest) {
433              setErrorMsg(t("converter.guestLimitError", "Daily guest conversion limit reached (5/day). Please sign in for higher limits."));
434            } else {
435              setErrorMsg(data.error || "Upload failed to initialize.");
436            }
437            return "error";
438          }
439          return prev;
440        });
441      }
442    } catch (e) {
443      setStatus((prev) => {
444        if (prev === "uploading") {
445          setErrorMsg(e.message || "An unexpected error occurred.");
446          return "error";
447        }
448        return prev;
449      });
450    }
451  };
452  reactExports.useEffect(() => {
453    if (status === "processing" && jobId) {
454      pollingInterval.current = setInterval(async () => {
455        try {
456          if (jobId.toString().startsWith("temp_")) {
457            const res = await fetch(`/api/convert/status/${jobId}`);
458            if (!res.ok) {
459              throw new Error("Failed to fetch status");
460            }
461            const track = await res.json();
462            if (track) {
463              if (track.logs !== void 0 && track.logs !== null) {
464                setLogs(track.logs);
465              }
466              if (track.status === "completed") {
467                setStatus((prev) => {
468                  if (prev === "processing") {
469                    setResult(track);
470                    setPercent(100);
471                    setIsPlaying(false);
472                    return "completed";
473                  }
474                  return prev;
475                });
476                clearInterval(pollingInterval.current);
477              } else if (track.status === "error" || track.status === "rejected" || track.status === "suspended" || track.status === "paused") {
478                setStatus((prev) => {
479                  if (prev === "processing") {
480                    setErrorMsg("File processing failed on the server.");
481                    return "error";
482                  }
483                  return prev;
484                });
485                clearInterval(pollingInterval.current);
486              } else {
487                setStatus((prev) => {
488                  if (prev === "processing") {
489                    if (track.status !== "pending" && track.status !== "processing") {
490                      setProgressMsg(track.status);
491                    }
492                    if (typeof track.percent === "number") {
493                      setPercent(track.percent);
494                    }
495                  }
496                  return prev;
497                });
498              }
499            }
500          } else {
501            try {
502              const track = await api.getTrack(jobId);
503              if (track) {
504                if (track.status === "completed") {
505                  setStatus((prev) => {
506                    if (prev === "processing") {
507                      setResult(track);
508                      setPercent(100);
509                      setIsPlaying(false);
510                      return "completed";
511                    }
512                    return prev;
513                  });
514                  clearInterval(pollingInterval.current);
515                } else if (track.status === "rejected" || track.status === "suspended" || track.status === "paused") {
516                  setStatus((prev) => {
517                    if (prev === "processing") {
518                      setErrorMsg("File processing failed on the server.");
519                      return "error";
520                    }
521                    return prev;
522                  });
523                  clearInterval(pollingInterval.current);
524                } else {
525                  setStatus((prev) => {
526                    if (prev === "processing") {
527                      if (track.status !== "pending" && track.status !== "processing") {
528                        setProgressMsg(track.status);
529                      }
530                      if (typeof track.percent === "number") {
531                        setPercent(track.percent);
532                      }
533                    }
534                    return prev;
535                  });
536                }
537              }
538            } catch (err) {
539              if (err.message.includes("404") || err.message.includes("Not Found") || err.message.includes("available")) {
540                setStatus((prev) => {
541                  if (prev === "processing") {
542                    setErrorMsg(err.message);
543                    return "error";
544                  }
545                  return prev;
546                });
547                clearInterval(pollingInterval.current);
548              }
549            }
550          }
551        } catch (e) {
552        }
553      }, 2e3);
554    }
555    return () => clearInterval(pollingInterval.current);
556  }, [status, jobId]);
557  reactExports.useEffect(() => {
558    var _a;
559    const activeOutput = ((_a = result == null ? void 0 : result.outputs) == null ? void 0 : _a[activeOutputIdx]) || {
560      path: result == null ? void 0 : result.mp3Path,
561      waveform: result == null ? void 0 : result.waveform,
562      soundfont: mixingSettings.soundfont,
563      format: mixingSettings.format
564    };
565    const activePath = activeOutput.path;
566    if (!audioRef.current || !activePath) return;
567    if (audioRef.current.src !== activePath) {
568      audioRef.current.src = activePath;
569      audioRef.current.load();
570    }
571    if (isPlaying) {
572      audioRef.current.play().catch((e) => {
573        console.error("Playback failed:", e);
574        setIsPlaying(false);
575      });
576    } else {
577      audioRef.current.pause();
578    }
579  }, [isPlaying, result == null ? void 0 : result.outputs, activeOutputIdx, result == null ? void 0 : result.mp3Path, mixingSettings.soundfont, mixingSettings.format]);
580  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 md:p-12 max-w-4xl mx-auto flex flex-col items-center justify-center min-h-[80vh] animate-in fade-in", children: [
581    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center mb-10", children: [
582      /* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "text-4xl font-bold text-zinc-900 dark:text-white mb-2 flex items-center justify-center gap-3 flex-wrap", children: [
583        /* @__PURE__ */ jsxRuntimeExports.jsx(FileHeadphone, { className: "text-indigo-500", size: 40 }),
584        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t("converter.title", "MIDI Converter") }),
585        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-bold uppercase tracking-wider bg-amber-500/10 text-amber-500 border border-amber-500/30", children: "beta" })
586      ] }),
587      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500 dark:text-zinc-400", children: t("converter.desc", "High-quality audio rendering using FluidSynth. Upload your .mid file and select soundfonts to generate premium-quality MP3, Opus, or WAV files in seconds.") }),
588      tempLifetimeHours && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 text-zinc-400 dark:text-zinc-500 text-xs font-semibold animate-in fade-in duration-700", children: t("converter.retentionNotice", "Note: Converted temporary files are automatically deleted after {{hours}} hours.", { hours: tempLifetimeHours }) })
589    ] }),
590    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full max-w-xl bg-white dark:bg-zinc-900 rounded-2xl shadow-xl border border-zinc-200 dark:border-zinc-800 overflow-hidden relative", children: [
591      status === "idle" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [
592        /* @__PURE__ */ jsxRuntimeExports.jsxs(
593          "div",
594          {
595            className: "p-10 flex flex-col items-center justify-center border-2 border-dashed border-zinc-300 dark:border-zinc-700 m-4 mb-2 rounded-xl cursor-pointer hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-colors",
596            onDragOver: (e) => e.preventDefault(),
597            onDrop: handleDrop,
598            onClick: () => {
599              var _a;
600              return (_a = fileInputRef.current) == null ? void 0 : _a.click();
601            },
602            children: [
603              /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "file", ref: fileInputRef, className: "hidden", accept: ".mid,.midi", onChange: handleFileSelect }),
604              file ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center gap-2 animate-in zoom-in-95", children: [
605                /* @__PURE__ */ jsxRuntimeExports.jsx(FileHeadphone, { size: 40, className: "text-indigo-500" }),
606                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-bold text-lg text-zinc-900 dark:text-white", children: file.name }),
607                /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-zinc-500", children: [
608                  (file.size / 1024).toFixed(1),
609                  " KB • ",
610                  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: (e) => {
611                    e.stopPropagation();
612                    setFile(null);
613                  }, className: "text-indigo-500 hover:underline", children: "Change File" })
614                ] })
615              ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
616                /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 48, className: "text-zinc-300 dark:text-zinc-600 mb-4" }),
617                /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-medium text-zinc-700 dark:text-zinc-300", children: t("converter.dragDrop", "Drag & Drop MIDI file") }),
618                /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500 mt-2", children: t("converter.browse", "or click to browse") })
619              ] })
620            ]
621          }
622        ),
623        file && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-6 pb-6 pt-2 animate-in slide-in-from-top-4 duration-500 text-left", children: [
624          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-50 dark:bg-zinc-800/50 rounded-xl border border-zinc-200 dark:border-zinc-800 p-5 mb-5 text-left", children: [
625            /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-sm font-bold text-zinc-900 dark:text-white mb-4 flex items-center gap-2", children: [
626              /* @__PURE__ */ jsxRuntimeExports.jsx(Music2, { size: 16, className: "text-indigo-500" }),
627              " ",
628              t("converter.previewOriginal", "In-Browser Preview (Original MIDI)")
629            ] }),
630            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [
631              /* @__PURE__ */ jsxRuntimeExports.jsx(
632                "button",
633                {
634                  onClick: toggleMidiPlayback,
635                  disabled: isMidiLoading,
636                  className: "w-12 h-12 rounded-full bg-indigo-600 hover:bg-indigo-700 text-white flex items-center justify-center shrink-0 transition-colors disabled:opacity-55",
637                  children: isMidiLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin" }) : isMidiPlaying ? /* @__PURE__ */ jsxRuntimeExports.jsx(Pause, { size: 20, fill: "currentColor" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { size: 20, fill: "currentColor", className: "ml-1" })
638                }
639              ),
640              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex items-center gap-3", children: [
641                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-mono text-zinc-500 dark:text-zinc-400 select-none w-10 text-right", children: formatTime(midiCurrentTime) }),
642                /* @__PURE__ */ jsxRuntimeExports.jsx(
643                  "input",
644                  {
645                    type: "range",
646                    min: 0,
647                    max: midiDuration || 100,
648                    step: 0.1,
649                    value: midiCurrentTime,
650                    onChange: (e) => handleMidiSeek(parseFloat(e.target.value)),
651                    className: "flex-1 h-1.5 bg-zinc-300 dark:bg-zinc-700 rounded-lg appearance-none cursor-pointer accent-indigo-600 focus:outline-none"
652                  }
653                ),
654                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-mono text-zinc-500 dark:text-zinc-400 select-none w-10", children: formatTime(midiDuration) })
655              ] })
656            ] })
657          ] }),
658          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-50 dark:bg-zinc-800/50 rounded-xl border border-zinc-200 dark:border-zinc-800 p-5", children: [
659            /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-sm font-bold text-zinc-900 dark:text-white mb-4 flex items-center gap-2", children: [
660              /* @__PURE__ */ jsxRuntimeExports.jsx(Settings2, { size: 16, className: "text-indigo-500" }),
661              " ",
662              t("converter.mixingDesk", "Mixing Desk")
663            ] }),
664            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [
665              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4 text-left", children: [
666                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
667                  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-[10px] uppercase font-bold text-zinc-400 mb-2.5 block flex items-center justify-between", children: [
668                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t("converter.soundfonts", "SoundFonts (select one or more)") }),
669                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[9px] font-black text-indigo-500 lowercase bg-indigo-50 dark:bg-indigo-950/40 px-1.5 py-0.5 rounded", children: [
670                      "+",
671                      t("converter.sfExtraCost", "{{cost}} credits / additional SF", { cost: extraSfCost })
672                    ] })
673                  ] }),
674                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border border-zinc-200 dark:border-zinc-700 rounded-xl bg-white dark:bg-zinc-900 max-h-40 overflow-y-auto p-3.5 space-y-2.5 custom-scrollbar shadow-inner text-left animate-in fade-in duration-300", children: soundfonts.map((sf) => {
675                    const isChecked = mixingSettings.soundfonts.includes(sf.path);
676                    return /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-3 cursor-pointer group select-none", children: [
677                      /* @__PURE__ */ jsxRuntimeExports.jsx(
678                        "input",
679                        {
680                          type: "checkbox",
681                          checked: isChecked,
682                          onChange: () => {
683                            let nextSfs = [...mixingSettings.soundfonts];
684                            if (isChecked) {
685                              if (nextSfs.length > 1) {
686                                nextSfs = nextSfs.filter((p) => p !== sf.path);
687                              }
688                            } else {
689                              nextSfs.push(sf.path);
690                            }
691                            handleSoundfontsChange(nextSfs);
692                          },
693                          className: "w-4 h-4 rounded text-indigo-600 border-zinc-300 focus:ring-indigo-500"
694                        }
695                      ),
696                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-xs font-semibold transition-colors ${isChecked ? "text-indigo-600 dark:text-indigo-400" : "text-zinc-600 dark:text-zinc-400 group-hover:text-zinc-900 dark:group-hover:text-zinc-200"}`, children: sf.displayName })
697                    ] }, sf.path);
698                  }) })
699                ] }),
700                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
701                  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-[10px] uppercase font-bold text-zinc-400 mb-2.5 block flex items-center justify-between", children: [
702                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t("converter.formats", "Formats (select one or more)") }),
703                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[9px] font-black text-indigo-500 lowercase bg-indigo-50 dark:bg-indigo-950/40 px-1.5 py-0.5 rounded", children: [
704                      "+",
705                      t("converter.fmtExtraCost", "{{cost}} credit / extra format, WAV = {{wavCost}}", { cost: extraFormatCost, wavCost: wavSurchargeCost })
706                    ] })
707                  ] }),
708                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-3 gap-2 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-xl p-2.5 shadow-inner", children: ["mp3", "opus", "wav", "flac", "ogg", "aac"].map((f) => {
709                    const isChecked = mixingSettings.formats.includes(f);
710                    return /* @__PURE__ */ jsxRuntimeExports.jsxs(
711                      "button",
712                      {
713                        type: "button",
714                        onClick: () => {
715                          let nextFmts = [...mixingSettings.formats];
716                          if (isChecked) {
717                            if (nextFmts.length > 1) {
718                              nextFmts = nextFmts.filter((fmt) => fmt !== f);
719                            }
720                          } else {
721                            nextFmts.push(f);
722                          }
723                          setMixingSettings((prev) => ({
724                            ...prev,
725                            formats: nextFmts,
726                            format: nextFmts[0] || "mp3"
727                          }));
728                        },
729                        className: `py-2 text-[10px] font-bold rounded-lg uppercase transition-all flex items-center justify-center gap-1.5 ${isChecked ? "bg-indigo-500 text-white shadow" : "text-zinc-500 hover:bg-zinc-100 dark:hover:bg-zinc-800"}`,
730                        children: [
731                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `w-1.5 h-1.5 rounded-full ${isChecked ? "bg-white" : "bg-transparent"}` }),
732                          f
733                        ]
734                      },
735                      f
736                    );
737                  }) })
738                ] }),
739                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 bg-indigo-500/5 dark:bg-indigo-500/10 p-3 rounded-lg border border-indigo-500/20", children: [
740                  /* @__PURE__ */ jsxRuntimeExports.jsx(
741                    "input",
742                    {
743                      type: "checkbox",
744                      id: "exportStems",
745                      checked: mixingSettings.exportStems,
746                      onChange: (e) => setMixingSettings({ ...mixingSettings, exportStems: e.target.checked }),
747                      className: "w-4 h-4 rounded text-indigo-500 focus:ring-indigo-500"
748                    }
749                  ),
750                  /* @__P
750URE__ */ jsxRuntimeExports.jsxs("label", { htmlFor: "exportStems", className: "flex flex-col cursor-pointer", children: [
751                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-bold text-indigo-600 dark:text-indigo-400 flex items-center gap-1.5", children: [
752                      /* @__PURE__ */ jsxRuntimeExports.jsx(Layers, { size: 12 }),
753                      " ",
754                      t("converter.exportStems", "Export Stems")
755                    ] }),
756                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-500", children: t("converter.exportStemsDesc", "Render each MIDI track as separate file") })
757                  ] })
758                ] })
759              ] }),
760              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
761                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
762                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-1.5", children: [
763                    /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-[10px] uppercase font-bold text-zinc-400 flex items-center gap-1", children: [
764                      /* @__PURE__ */ jsxRuntimeExports.jsx(Volume2, { size: 10 }),
765                      " ",
766                      t("converter.gain", "Gain")
767                    ] }),
768                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] font-mono text-zinc-500", children: [
769                      mixingSettings.gain.toFixed(1),
770                      "x"
771                    ] })
772                  ] }),
773                  /* @__PURE__ */ jsxRuntimeExports.jsx(
774                    "input",
775                    {
776                      type: "range",
777                      min: "0",
778                      max: "2",
779                      step: "0.1",
780                      value: mixingSettings.gain,
781                      onChange: (e) => setMixingSettings({ ...mixingSettings, gain: parseFloat(e.target.value) }),
782                      className: "w-full h-1.5 bg-zinc-200 dark:bg-zinc-700 rounded-lg appearance-none cursor-pointer accent-indigo-500"
783                    }
784                  )
785                ] }),
786                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
787                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-1.5", children: [
788                    /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-[10px] uppercase font-bold text-zinc-400 flex items-center gap-1", children: [
789                      /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { size: 10 }),
790                      " ",
791                      t("converter.reverb", "Reverb")
792                    ] }),
793                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] font-mono text-zinc-500", children: [
794                      Math.round(mixingSettings.reverb * 100),
795                      "%"
796                    ] })
797                  ] }),
798                  /* @__PURE__ */ jsxRuntimeExports.jsx(
799                    "input",
800                    {
801                      type: "range",
802                      min: "0",
803                      max: "1",
804                      step: "0.05",
805                      value: mixingSettings.reverb,
806                      onChange: (e) => setMixingSettings({ ...mixingSettings, reverb: parseFloat(e.target.value) }),
807                      className: "w-full h-1.5 bg-zinc-200 dark:bg-zinc-700 rounded-lg appearance-none cursor-pointer accent-indigo-500"
808                    }
809                  )
810                ] }),
811                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
812                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-1.5", children: [
813                    /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-[10px] uppercase font-bold text-zinc-400 flex items-center gap-1", children: [
814                      /* @__PURE__ */ jsxRuntimeExports.jsx(SlidersVertical, { size: 10 }),
815                      " ",
816                      t("converter.chorus", "Chorus")
817                    ] }),
818                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] font-mono text-zinc-500", children: [
819                      Math.round(mixingSettings.chorus * 100),
820                      "%"
821                    ] })
822                  ] }),
823                  /* @__PURE__ */ jsxRuntimeExports.jsx(
824                    "input",
825                    {
826                      type: "range",
827                      min: "0",
828                      max: "1",
829                      step: "0.05",
830                      value: mixingSettings.chorus,
831                      onChange: (e) => setMixingSettings({ ...mixingSettings, chorus: parseFloat(e.target.value) }),
832                      className: "w-full h-1.5 bg-zinc-200 dark:bg-zinc-700 rounded-lg appearance-none cursor-pointer accent-indigo-500"
833                    }
834                  )
835                ] })
836              ] })
837            ] }),
838            (() => {
839              const cost = currentCost;
840              if (currentUser) {
841                const credits = currentUser.credits || 0;
842                const hasEnoughCredits = credits >= cost;
843                const remaining = Math.max(0, credits - cost);
844                const maxScale = Math.max(credits, cost * 2.5, 20);
845                const remainingPercent = remaining / maxScale * 100;
846                const costPercent = Math.min(credits, cost) / maxScale * 100;
847                return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-8 bg-white dark:bg-zinc-950/30 border border-zinc-200/80 dark:border-zinc-800 rounded-2xl p-5 shadow-lg animate-in fade-in slide-in-from-top-4 duration-500", children: [
848                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-2", children: [
849                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[11px] font-black uppercase tracking-wider text-indigo-500 dark:text-indigo-400 flex items-center gap-1.5", children: [
850                      /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { size: 12, className: "animate-pulse" }),
851                      t("converter.energyFuel", "Your Credit Fuel")
852                    ] }),
853                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-black font-mono text-zinc-800 dark:text-zinc-100 bg-zinc-100 dark:bg-zinc-800 px-2.5 py-0.5 rounded-full border border-zinc-200/50 dark:border-zinc-700/50", children: [
854                      formatNumber(credits),
855                      " ",
856                      t("converter.creditsUnit", "Credits")
857                    ] })
858                  ] }),
859                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full bg-zinc-200 dark:bg-zinc-800/80 h-4 rounded-full overflow-hidden flex relative border border-zinc-300/40 dark:border-zinc-700/40 shadow-inner", children: [
860                    remainingPercent > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
861                      "div",
862                      {
863                        className: "h-full bg-gradient-to-r from-emerald-500 via-teal-500 to-cyan-500 transition-all duration-1000 relative shadow-[0_0_12px_rgba(16,185,129,0.3)]",
864                        style: { width: `${remainingPercent}%` },
865                        children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute inset-0 bg-gradient-to-r from-transparent via-white/20 to-transparent -translate-x-full animate-shimmer", style: { animationDuration: "3s", animationIterationCount: "infinite" } })
866                      }
867                    ),
868                    costPercent > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
869                      "div",
870                      {
871                        className: "h-full bg-amber-500 transition-all duration-1000 relative overflow-hidden border-l border-white/20",
872                        style: {
873                          width: `${costPercent}%`,
874                          backgroundImage: "linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent)",
875                          backgroundSize: "12px 12px",
876                          animation: "shimmer 1.5s infinite linear, pulse 2s infinite"
877                        },
878                        title: `-${cost} Credits for this conversion`,
879                        children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute inset-0 bg-amber-400 opacity-20 animate-pulse" })
880                      }
881                    )
882                  ] }),
883                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mt-2.5 text-[10px] font-bold text-zinc-400 dark:text-zinc-500", children: [
884                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [
885                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-emerald-500 inline-block" }),
886                      t("converter.remainingFuel", "Post-Conversion:"),
887                      " ",
888                      formatNumber(remaining)
889                    ] }),
890                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [
891                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-amber-500 animate-pulse inline-block" }),
892                      t("converter.deductionAmount", "Cost:"),
893                      " -",
894                      cost
895                    ] })
896                  ] }),
897                  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-center mt-3 font-semibold px-3 py-1.5 rounded-xl border bg-zinc-100/50 dark:bg-zinc-800/30", children: hasEnoughCredits ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-emerald-600 dark:text-emerald-400", children: [
898                    "🔋 ",
899                    t("converter.fuelReady", "Energy cells fully charged. Ready!")
900                  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-red-500 dark:text-red-400", children: [
901                    "⚠️ ",
902                    t("converter.fuelLow", "Low fuel. Please acquire credits.")
903                  ] }) })
904                ] });
905              } else {
906                const limit = (guestUsage == null ? void 0 : guestUsage.limit) || 15;
907                const spent = (guestUsage == null ? void 0 : guestUsage.spent) || 0;
908                const available = Math.max(0, limit - spent);
909                const remaining = Math.max(0, available - cost);
910                const remainingPercent = remaining / limit * 100;
911                const costPercent = Math.min(available, cost) / limit * 100;
912                const spentPercent = spent / limit * 100;
913                const maxConversions = Math.floor(limit / cost);
914                const leftConversions = Math.floor(available / cost);
915                return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-8 space-y-4", children: [
916                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-950/30 border border-zinc-200/80 dark:border-zinc-800 rounded-2xl p-5 shadow-lg animate-in fade-in slide-in-from-top-4 duration-500", children: [
917                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-2", children: [
918                      /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[11px] font-black uppercase tracking-wider text-indigo-500 dark:text-indigo-400 flex items-center gap-1.5", children: [
919                        /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { size: 12, className: "animate-pulse" }),
920                        t("converter.guestAllowance", "Guest Daily Credit Allowance")
921                      ] }),
922                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-black font-mono text-zinc-800 dark:text-zinc-100 bg-zinc-100 dark:bg-zinc-800 px-2.5 py-0.5 rounded-full border border-zinc-200/50 dark:border-zinc-700/50", children: t("converter.availableCredits", "Available: {{available}} Credits", { available }) })
923                    ] }),
924                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full bg-zinc-200 dark:bg-zinc-800/80 h-4 rounded-full overflow-hidden flex relative border border-zinc-300/40 dark:border-zinc-700/40 shadow-inner", children: [
925                      remainingPercent > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
926                        "div",
927                        {
928                          className: "h-full bg-gradient-to-r from-emerald-500 to-teal-500 transition-all duration-1000 relative shadow-[0_0_12px_rgba(16,185,129,0.3)]",
929                          style: { width: `${remainingPercent}%` },
930                          children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute inset-0 bg-gradient-to-r from-transparent via-white/20 to-transparent -translate-x-full animate-shimmer", style: { animationDuration: "3s", animationIterationCount: "infinite" } })
931                        }
932                      ),
933                      costPercent > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
934                        "div",
935                        {
936                          className: "h-full bg-amber-500 transition-all duration-1000 relative overflow-hidden border-l border-white/20",
937                          style: {
938                            width: `${costPercent}%`,
939                            backgroundImage: "linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent)",
940                            backgroundSize: "12px 12px",
941                            animation: "shimmer 1.5s infinite linear, pulse 2s infinite"
942                          },
943                          title: `-${cost} Credits for this conversion`,
944                          children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute inset-0 bg-amber-400 opacity-20 animate-pulse" })
945                        }
946                      ),
947                      spentPercent > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
948                        "div",
949                        {
950                          className: "h-full bg-zinc-400 dark:bg-zinc-600 transition-all duration-1000 border-l border-white/10",
951                          style: { width: `${spentPercent}%` },
952                          title: `Spent ${spent} credits today`
953                        }
954                      )
955                    ] }),
956                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col md:flex-row justify-between items-start md:items-center mt-2.5 gap-1 md:gap-0 text-[10px] font-bold text-zinc-400 dark:text-zinc-500", children: [
957                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
958                        /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [
959                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-emerald-500 inline-block" }),
960                          t("converter.postConversionRemaining", "Post-Conversion:"),
961                          " ",
962                          remaining
963                        ] }),
964                        /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [
965                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-amber-500 animate-pulse inline-block" }),
966                          t("converter.deductionAmount", "Cost:"),
967                          " -",
968                          cost
969                        ] }),
970                        spent > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [
971                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-zinc-400 inline-block" }),
972                          t("converter.spentToday", "Spent Today:"),
973                          " ",
974                          spent
975                        ] })
976                      ] }),
977                      /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-indigo-500 dark:text-indigo-400 font-extrabold uppercase tracking-wider bg-indigo-50 dark:bg-indigo-950/40 px-1.5 py-0.5 rounded text-[8px]", children: [
978                        leftConversions,
979                        " / ",
980                        maxConversions,
981                        " ",
982                        t("converter.conversionsRemaining", "left")
983                      ] })
984                    ] })
985                  ] }),
986                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gradient-to-r from-indigo-500/10 via-purple-500/10 to-indigo-500/5 border border-indigo-200/50 dark:border-indigo-800/30 rounded-2xl p-5 shadow-lg text-center relative overflow-hidden group", children: [
987                    /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute top-0 right-0 w-32 h-32 bg-indigo-500/10 rounded-full blur-2xl -mr-10 -mt-10 group-hover:bg-indigo-500/20 transition-all duration-700" }),
988                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] font-black uppercase tracking-wider text-indigo-500 dark:text-indigo-400 block mb-1.5", children: [
989                      "✨ ",
990                      t("converter.premiumPromoTitle", "Unlock Unlimited Access"),
991                      " ✨"
992                    ] }),
993                    /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-zinc-600 dark:text-zinc-300 mb-3.5 leading-relaxed font-medium", children: t("converter.promoDesc", "Guests are limited to {{maxConversions}} free daily conversions. Sign up now to receive {{signupCredits}} FREE Credits instantly, unlock access to HQ Soundfonts, and render WAV or Opus stems!", { maxConversions, signupCredits: freeCredits }) }),
994                    /* @__PURE__ */ jsxRuntimeExports.jsxs(
995                      "button",
996                      {
997                        onClick: onAuthRequested,
998                        className: "py-2 px-5 bg-indigo-600 hover:bg-indigo-700 hover:scale-[1.02] active:scale-[0.98] text-white rounded-xl text-[11px] font-extrabold transition-all shadow-md shadow-indigo-600/20 flex items-center gap-1.5 mx-auto animate-in zoom-in-95",
999                        children: [
1000                          /* @__PURE__ */ jsxRuntimeExports.jsx(Coins, { size: 12 }),
1001                          " ",
1002                          t("converter.promoButton", "Create Free Account & Claim Credits")
1003                        ]
1004                      }
1005                    )
1006                  ] })
1007                ] });
1008              }
1009            })(),
1010            /* @__PURE__ */ jsxRuntimeExports.jsxs(
1011              "button",
1012              {
1013                onClick: handleUpload,
1014                className: "mt-8 w-full py-3.5 bg-indigo-600 hover:bg-indigo-700 text-white rounded-xl font-bold shadow-lg shadow-indigo-500/30 transition-all flex items-center justify-center gap-3 group",
1015                children: [
1016                  /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 20, className: "group-hover:rotate-180 transition-transform duration-500" }),
1017                  t("converter.start", "Initialize Processing Engine")
1018                ]
1019              }
1020            )
1021          ] })
1022        ] })
1023      ] }),
1024      (status === "uploading" || status === "processing") && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-8 flex flex-col items-center justify-center text-center w-full", children: [
1025        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative w-16 h-16 mb-4", children: [
1026          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 border-4 border-indigo-500/20 rounded-full" }),
1027          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 border-4 border-indigo-500 border-t-transparent rounded-full animate-spin" }),
1028          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { className: "text-indigo-500 animate-pulse", size: 24 }) })
1029        ] }),
1030        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-xl font-bold text-zinc-900 dark:text-white mb-1.5", children: status === "uploading" ? t("converter.uploading", "Uploading...") : progressMsg || t("converter.rendering", "Rendering Audio...") }),
1031        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500 text-xs max-w-xs mx-auto mb-4", children: status === "uploading" ? t("converter.status_uploading_desc", "Please wait while we receive your file.") : t("converter.status_rendering_desc", "Cloud workers are synthesizing your MIDI using professional grade SoundFonts.") }),
1032        status === "processing" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full max-w-md flex flex-col gap-4 mt-2", children: [
1033          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full flex flex-col items-center gap-1.5", children: [
1034            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full bg-zinc-100 dark:bg-zinc-800 h-2.5 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1035              "div",
1036              {
1037                className: `h-full bg-indigo-500 transition-all duration-500 ${percent === null ? "animate-progress-indeterminate" : ""}`,
1038                style: percent !== null ? { width: `${percent}%` } : void 0
1039              }
1040            ) }),
1041            percent !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-black text-indigo-500 dark:text-indigo-400", children: [
1042              percent,
1043              "%"
1044            ] })
1045          ] }),
1046          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full bg-zinc-950 border border-zinc-800 rounded-xl p-4 text-left shadow-inner animate-in fade-in slide-in-from-bottom-4 duration-500", children: [
1047            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 border-b border-zinc-900 pb-2 mb-3", children: [
1048              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded-full bg-red-500" }),
1049              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded-full bg-yellow-500" }),
1050              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded-full bg-green-500" }),
1051              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-mono text-zinc-500 font-bold uppercase tracking-wider ml-1", children: "Conversion Engine Log" })
1052            ] }),
1053            /* @__PURE__ */ jsxRuntimeExports.jsxs(
1054              "div",
1055              {
1056                className: "font-mono text-[11px] text-zinc-300 h-40 overflow-y-auto space-y-1 scrollbar-thin scrollbar-thumb-zinc-800 scrollbar-track-transparent pr-1",
1057                ref: logContainerRef,
1058                children: [
1059                  logs.split("\n").filter(Boolean).map((line, idx) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "leading-relaxed whitespace-pre-wrap", children: [
1060                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 select-none mr-2", children: ">" }),
1061                    line
1062                  ] }, idx)),
1063                  !logs && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-500 italic animate-pulse", children: "Initializing pipeline workers..." })
1064                ]
1065              }
1066            )
1067          ] }),
1068          /* @__PURE__ */ jsxRuntimeExports.jsx(AdSlot, { type: "converterBottom", className: "my-2 p-2 border-dashed bg-indigo-500/5 border-indigo-500/10" })
1069        ] })
1070      ] }),
1071      status === "completed" && result && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-8 animate-in zoom-in-95", children: [
1072        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center mb-6", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 h-16 bg-emerald-100 dark:bg-emerald-900/30 rounded-full flex items-center justify-center text-emerald-600 dark:text-emerald-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { size: 32 }) }) }),
1073        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-2xl font-bold text-center text-zinc-900 dark:text-white mb-1", children: t("converter.complete", "Conversion Complete!") }),
1074        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-center text-zinc-500 mb-8", children: t("converter.ready", { title: result.title, defaultValue: `${result.title}.opus is ready.` }) }),
1075        (() => {
1076          var _a;
1077          const activeOutput = ((_a = result.outputs) == null ? void 0 : _a[activeOutputIdx]) || {
1078            path: result.mp3Path,
1079            waveform: result.waveform,
1080            soundfont: mixingSettings.soundfont,
1081            format: mixingSettings.format
1082          };
1083          return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1084            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-100 dark:bg-zinc-800 rounded-xl p-4 mb-6 flex flex-col gap-4", children: [
1085              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [
1086                /* @__PURE__ */ jsxRuntimeExports.jsx(
1087                  "button",
1088                  {
1089                    onClick: () => setIsPlaying(!isPlaying),
1090                    className: "w-12 h-12 rounded-full bg-indigo-600 hover:bg-indigo-700 text-white flex items-center justify-center shrink-0 transition-colors",
1091                    children: isPlaying ? /* @__PURE__ */ jsxRuntimeExports.jsx(Pause, { size: 20, fill: "currentColor" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { size: 20, fill: "currentColor", className: "ml-1" })
1092                  }
1093                ),
1094                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex items-center gap-3", children: [
1095                  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-mono text-zinc-500 dark:text-zinc-400 select-none w-10 text-right", children: formatTime(currentTime) }),
1096                  /* @__PURE__ */ jsxRuntimeExports.jsx(
1097                    "input",
1098                    {
1099                      type: "range",
1100                      min: 0,
1101                      max: duration || 100,
1102                      step: 0.1,
1103                      value: currentTime,
1104                      onChange: (e) => {
1105                        const newTime = parseFloat(e.target.value);
1106                        setCurrentTime(newTime);
1107                        if (audioRef.current) {
1108                          audioRef.current.currentTime = newTime;
1109                        }
1110                      },
1111                      className: "flex-1 h-1.5 bg-zinc-300 dark:bg-zinc-700 rounded-lg appearance-none cursor-pointer accent-indigo-600 focus:outline-none"
1112                    }
1113                  ),
1114                  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-mono text-zinc-500 dark:text-zinc-400 select-none w-10", children: formatTime(duration) })
1115                ] })
1116              ] }),
1117              activeOutput.waveform && activeOutput.waveform.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-12 w-full opacity-70 hover:opacity-100 transition-opacity cursor-pointer px-14", onClick: (e) => {
1118                if (audioRef.current && duration) {
1119                  const rect = e.currentTarget.getBoundingClientRect();
1120                  const clickX = e.clientX - rect.left;
1121                  const newTime = clickX / rect.width * duration;
1122                  audioRef.current.currentTime = newTime;
1123                  setCurrentTime(newTime);
1124                }
1125              }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Waveform, { data: activeOutput.waveform, active: true, progress: duration ? currentTime / duration : 0, className: "h-full pointer-events-none" }) }),
1126              activeOutput.path && /* @__PURE__ */ jsxRuntimeExports.jsx(
1127                "audio",
1128                {
1129                  ref: audioRef,
1130                  src: activeOutput.path,
1131                  onEnded: () => setIsPlaying(false),
1132                  onTimeUpdate: () => {
1133                    if (audioRef.current) {
1134                      setCurrentTime(audioRef.current.currentTime);
1135                      setDuration(audioRef.current.duration);
1136                    }
1137                  },
1138                  onLoadedMetadata: () => {
1139                    if (audioRef.current) {
1140                      setDuration(audioRef.current.duration);
1141                    }
1142                  },
1143                  className: "hidden"
1144                }
1145              )
1146            ] }),
1147            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [
1148              /* @__PURE__ */ jsxRuntimeExports.jsx(
1149                "button",
1150                {
1151                  onClick: resetConverter,
1152                  className: "flex-1 py-3 rounded-lg font-bold text-zinc-600 dark:text-zinc-300 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors",
1153                  children: t("converter.convertAnother", "Convert Another")
1154                }
1155              ),
1156              /* @__PURE__ */ jsxRuntimeExports.jsxs(
1157                "a",
1158                {
1159                  href: activeOutput.path || "#",
1160                  download: true,
1161                  className: "flex-[2] py-3 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg font-bold flex items-center justify-center gap-2 shadow-lg shadow-indigo-500/20 transition-all",
1162                  children: [
1163                    /* @__PURE__ */ jsxRuntimeExports.jsx(Download, { size: 20 }),
1164                    " ",
1165                    t("converter.download", `Download ${activeOutput.format.toUpperCase()}`)
1166                  ]
1167                }
1168              )
1169            ] }),
1170            (!result.outputs || !result.outputs.some((out) => out.format.toLowerCase() === "wav")) && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-4 w-full", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
1171              "button",
1172              {
1173                onClick: handleBuyWav,
1174                disabled: isBuyingWav,
1175                className: "w-full py-2.5 bg-amber-500 hover:bg-amber-600 disabled:opacity-50 text-white rounded-lg font-bold flex items-center justify-center gap-2 shadow transition-all text-sm",
1176                children: [
1177                  isBuyingWav ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-4.5 h-4.5 border-2 border-white border-t-transparent rounded-full animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Coins, { size: 16 }),
1178                  t("converter.buyWav", "Download Lossless WAV (2 Credits)")
1179                ]
1180              }
1181            ) }),
1182            result.outputs && result.outputs.length > 0 && (() => {
1183              const uniqueSoundfonts = Array.from(new Set(result.outputs.map((out) => out.soundfont)));
1184              const uniqueFormats = Array.from(new Set(result.outputs.map((out) => out.format.toLowerCase())));
1185              const isMultiOutput = uniqueSoundfonts.length > 1 || uniqueFormats.length > 1;
1186              return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-8 pt-8 border-t border-zinc-100 dark:border-zinc-800 text-left", children: [
1187                /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-sm font-bold text-zinc-900 dark:text-white mb-4 flex items-center gap-2 uppercase tracking-wider", children: [
1188                  /* @__PURE__ */ jsxRuntimeExports.jsx(Layers, { size: 16, className: "text-indigo-500" }),
1189                  " ",
1190                  t("converter.convertedOutputs", "Converted Outputs")
1191                ] }),
1192                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-x-auto rounded-xl border border-zinc-200 dark:border-zinc-800", children: isMultiOutput ? /* @__PURE__ */ jsxRuntimeExports.jsxs("table", { className: "w-full text-left border-collapse", children: [
1193                  /* @__PURE__ */ jsxRuntimeExports.jsx("thead", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "bg-zinc-50 dark:bg-zinc-900/80 border-b border-zinc-200 dark:border-zinc-800 text-zinc-400 dark:text-zinc-500 text-[10px] font-black uppercase tracking-wider", children: [
1194                    /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "p-3 text-left", children: "SoundFont" }),
1195                    uniqueFormats.map((fmt) => /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "p-3 text-center", children: fmt.toUpperCase() }, fmt))
1196                  ] }) }),
1197                  /* @__PURE__ */ jsxRuntimeExports.jsx("tbody", { className: "divide-y divide-zinc-100 dark:divide-zinc-800/60 bg-white dark:bg-zinc-900", children: uniqueSoundfonts.map((sf) => /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "hover:bg-zinc-50/50 dark:hover:bg-zinc-800/30 transition-colors", children: [
1198                    /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3 font-bold text-zinc-800 dark:text-zinc-200 text-sm", children: sf.replace(".sf2", "").replace(/_/g, " ") }),
1199                    uniqueFormats.map((fmt) => {
1200                      const idx = result.outputs.findIndex((out2) => out2.soundfont === sf && out2.format.toLowerCase() === fmt);
1201                      if (idx === -1) {
1202                        return /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3 text-center text-zinc-400 dark:text-zinc-600", children: "-" }, fmt);
1203                      }
1204                      const out = result.outputs[idx];
1205                      const isCurrent = activeOutputIdx === idx;
1206                      const isCurrentPlaying = isCurrent && isPlaying;
1207                      return /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3 text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center gap-2", children: [
1208                        /* @__PURE__ */ jsxRuntimeExports.jsx(
1209                          "button",
1210                          {
1211                            onClick: () => {
1212                              if (isCurrent) {
1213                                setIsPlaying(!isPlaying);
1214                              } else {
1215                                setActiveOutputIdx(idx);
1216                                setIsPlaying(true);
1217                              }
1218                            },
1219                            className: `w-8 h-8 rounded-full flex items-center justify-center transition-all ${isCurrentPlaying ? "bg-indigo-600 text-white animate-pulse" : "bg-indigo-50 dark:bg-indigo-950/50 text-indigo-500 hover:bg-indigo-100 dark:hover:bg-indigo-950"}`,
1220                            title: isCurrentPlaying ? "Pause" : "Play",
1221                            children: isCurrentPlaying ? /* @__PURE__ */ jsxRuntimeExports.jsx(Pause, { size: 12, fill: "currentColor" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { size: 12, fill: "currentColor", className: "ml-0.5" })
1222                          }
1223                        ),
1224                        /* @__PURE__ */ jsxRuntimeExports.jsx(
1225                          "a",
1226                          {
1227                            href: out.path,
1228                            download: true,
1229                            className: "inline-flex items-center justify-center w-8 h-8 bg-zinc-100 dark:bg-zinc-800 hover:bg-indigo-600 dark:hover:bg-indigo-600 hover:text-white dark:hover:text-white rounded-full text-zinc-600 dark:text-zinc-400 transition-all",
1230                            title: "Download",
1231                            children: /* @__PURE__ */ jsxRuntimeExports.jsx(Download, { size: 12 })
1232                          }
1233                        )
1234                      ] }) }, fmt);
1235                    })
1236                  ] }, sf)) })
1237                ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("table", { className: "w-full text-left border-collapse", children: [
1238                  /* @__PURE__ */ jsxRuntimeExports.jsx("thead", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "bg-zinc-50 dark:bg-zinc-900/80 border-b border-zinc-200 dark:border-zinc-800 text-zinc-400 dark:text-zinc-500 text-[10px] font-black uppercase tracking-wider", children: [
1239                    /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "p-3 w-12 text-center", children: "Play" }),
1240                    /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "p-3", children: "SoundFont" }),
1241                    /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "p-3 w-24", children: "Format" }),
1242                    /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "p-3 w-28 text-right", children: "Action" })
1243                  ] }) }),
1244                  /* @__PURE__ */ jsxRuntimeExports.jsx("tbody", { className: "divide-y divide-zinc-100 dark:divide-zinc-800/60 bg-white dark:bg-zinc-900", children: result.outputs.map((out, idx) => {
1245                    const isCurrent = activeOutputIdx === idx;
1246                    const isCurrentPlaying = isCurrent && isPlaying;
1247                    return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1248                      "tr",
1249                      {
1250                        className: `transition-colors ${isCurrent ? "bg-indigo-500/5 dark:bg-indigo-950/20" : "hover:bg-zinc-50/50 dark:hover:bg-zinc-800/30"}`,
1251                        children: [
1252                          /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3 text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1253                            "button",
1254                            {
1255                              onClick: () => {
1256                                if (isCurrent) {
1257                                  setIsPlaying(!isPlaying);
1258                                } else {
1259                                  setActiveOutputIdx(idx);
1260                                  setIsPlaying(true);
1261                                }
1262                              },
1263                              className: `w-8 h-8 rounded-full flex items-center justify-center transition-all ${isCurrentPlaying ? "bg-indigo-600 text-white animate-pulse" : "bg-indigo-50 dark:bg-indigo-950/50 text-indigo-500 hover:bg-indigo-100 dark:hover:bg-indigo-950"}`,
1264                              children: isCurrentPlaying ? /* @__PURE__ */ jsxRuntimeExports.jsx(Pause, { size: 12, fill: "currentColor" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { size: 12, fill: "currentColor", className: "ml-0.5" })
1265                            }
1266                          ) }),
1267                          /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-zinc-800 dark:text-zinc-200", children: out.soundfont.replace(".sf2", "").replace(/_/g, " ") }) }),
1268                          /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `px-2 py-0.5 rounded text-[10px] font-black uppercase tracking-wider ${out.format.toLowerCase() === "wav" ? "bg-amber-100 dark:bg-amber-950/40 text-amber-600 dark:text-amber-400" : out.format.toLowerCase() === "mp3" ? "bg-emerald-100 dark:bg-emerald-950/40 text-emerald-600 dark:text-amber-400" : "bg-indigo-100 dark:bg-indigo-950/40 text-indigo-600 dark:text-indigo-400"}`, children: out.format }) }),
1269                          /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-3 text-right", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
1270                            "a",
1271                            {
1272                              href: out.path,
1273                              download: true,
1274                              className: "inline-flex items-center gap-1 px-3 py-1.5 bg-zinc-100 dark:bg-zinc-800 hover:bg-indigo-600 dark:hover:bg-indigo-600 hover:text-white dark:hover:text-white rounded-lg text-zinc-600 dark:text-zinc-400 font-bold transition-all text-xs",
1275                              children: [
1276                                /* @__PURE__ */ jsxRuntimeExports.jsx(Download, { size: 12 }),
1277                                " Download"
1278                              ]
1279                            }
1280                          ) })
1281                        ]
1282                      },
1283                      idx
1284                    );
1285                  }) })
1286                ] }) })
1287              ] });
1288            })()
1289          ] });
1290        })(),
1291        !(jobId == null ? void 0 : jobId.toString().startsWith("temp_")) && status === "completed" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-4 text-center text-sm text-green-600 dark:text-green-400 font-medium", children: "Successfully Uploaded!" }),
1292        (jobId == null ? void 0 : jobId.toString().startsWith("temp_")) && status === "completed" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1293          "button",
1294          {
1295            onClick: () => onPublish(file),
1296            className: "w-full py-3 bg-zinc-800 hover:bg-zinc-900 dark:bg-zinc-700 dark:hover:bg-zinc-600 text-white rounded-lg font-bold flex items-center justify-center gap-2 transition-all",
1297            children: "Uploadt MIDI to Site"
1298          }
1299        ) }),
1300        result.instruments && result.instruments.some((i) => i.stemPath) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-10 pt-8 border-t border-zinc-100 dark:border-zinc-800", children: [
1301          /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-sm font-bold text-zinc-900 dark:text-white mb-4 flex items-center gap-2 uppercase tracking-wider", children: [
1302            /* @__PURE__ */ jsxRuntimeExports.jsx(Layers, { size: 16, className: "text-indigo-500" }),
1303            " Generated Stems"
1304          ] }),
1305          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 gap-2 max-h-48 overflow-y-auto pr-2 custom-scrollbar", children: result.instruments.filter((i) => i.stemPath).map((inst, idx) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between bg-zinc-50 dark:bg-zinc-900/50 p-3 rounded-lg border border-zinc-200 dark:border-zinc-800", children: [
1306            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 overflow-hidden", children: [
1307              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-8 h-8 rounded bg-zinc-200 dark:bg-zinc-800 flex items-center justify-center text-[10px] font-bold text-zinc-500 shrink-0", children: [
1308                "#",
1309                inst.trackId
1310              ] }),
1311              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300 truncate", children: inst.name })
1312            ] }),
1313            /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: inst.stemPath, download: true, className: "text-indigo-500 hover:text-indigo-600 p-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Download, { size: 16 }) })
1314          ] }, idx)) })
1315        ] })
1316      ] }),
1317      status === "error" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-10 flex flex-col items-center justify-center text-center", children: [
1318        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 h-16 bg-red-100 dark:bg-red-900/30 rounded-full flex items-center justify-center text-red-500 mb-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { size: 32 }) }),
1319        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-xl font-bold text-zinc-900 dark:text-white mb-2", children: t("converter.error", "Conversion Failed") }),
1320        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500 text-sm mb-6", children: errorMsg || t("converter.error_desc", "Something went wrong during the conversion process. Please try a different file.") }),
1321        /* @__PURE__ */ jsxRuntimeExports.jsx(
1322          "button",
1323          {
1324            onClick: () => resetConverter(false),
1325            className: "px-6 py-2 bg-zinc-200 dark:bg-zinc-800 hover:bg-zinc-300 dark:hover:bg-zinc-700 rounded-lg font-bold text-zinc-900 dark:text-white transition-colors",
1326            children: t("converter.try_again", "Try Again")
1327          }
1328        )
1329      ] })
1330    ] }),
1331    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-12 grid grid-cols-1 md:grid-cols-3 gap-6 text-center max-w-4xl", children: [
1332      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4", children: [
1333        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-zinc-900 dark:text-white mb-1", children: t("converter.features.soundfontsTitle", "High Quality SoundFonts") }),
1334        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500", children: t("converter.features.soundfontsDesc", "We use professional-grade FluidR3 GM soundfonts for realistic instrument reproduction.") })
1335      ] }),
1336      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4", children: [
1337        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-zinc-900 dark:text-white mb-1", children: t("converter.features.fastProcessingTitle", "Fast Processing") }),
1338        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500", children: t("converter.features.fastProcessingDesc", "Cloud-based workers convert your MIDI files in seconds, regardless of complexity.") })
1339      ] }),
1340      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4", children: [
1341        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-zinc-900 dark:text-white mb-1", children: t("converter.features.securePrivateTitle", "Secure & Private") }),
1342        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500", children: t("converter.features.securePrivateDesc", "Files are processed securely and can be deleted immediately after download.") })
1343      ] })
1344    ] }),
1345    /* @__PURE__ */ jsxRuntimeExports.jsx(AdSlot, { type: "converterBottom" }),
1346    /* @__PURE__ */ jsxRuntimeExports.jsx("style", { children: `
1347                @keyframes shimmer {
1348                    100% {
1349                        transform: translateX(100%);
1350                    }
1351                }
1352                .animate-shimmer {
1353                    animation: shimmer 2.5s infinite linear;
1354                }
1355            ` }),
1356    /* @__PURE__ */ jsxRuntimeExports.jsx(
1357      CreditsExhaustedModal,
1358      {
1359        isOpen: isCreditsExhaustedModalOpen,
1360        onClose: () => setIsCreditsExhaustedModalOpen(false),
1361        onSignUp: onAuthRequested
1362      }
1363    )
1364  ] });
1365};
1366export {
1367  ConverterPage as default
1368};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.