c788cb1a0b
This reverts commit 7ee1db049f.
259 lines
11 KiB
HTML
259 lines
11 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||
<title>MOTIF — Test models</title>
|
||
<style>
|
||
:root {
|
||
--color-bg: #0b0b0f;
|
||
--color-surface: rgba(255, 255, 255, 0.06);
|
||
--color-surface-2: rgba(255, 255, 255, 0.09);
|
||
--color-border: rgba(255, 255, 255, 0.12);
|
||
--color-text: rgba(255, 255, 255, 0.9);
|
||
--color-text-muted: rgba(255, 255, 255, 0.7);
|
||
--color-accent-primary: #00ff88;
|
||
--color-accent-secondary: #ff3cf5;
|
||
--radius: 12px;
|
||
--shadow-sm: 0 12px 34px rgba(0,0,0,0.45);
|
||
--glow-primary: 0 0 18px rgba(0, 255, 136, 0.18);
|
||
--spacing-unit: 8px;
|
||
}
|
||
|
||
body {
|
||
background: radial-gradient(1000px 600px at 20% 10%, rgba(255,60,245,0.10), transparent 55%),
|
||
radial-gradient(900px 500px at 80% 20%, rgba(0,255,136,0.09), transparent 50%),
|
||
linear-gradient(180deg, #07070a, #0b0b0f 60%, #060609);
|
||
color: var(--color-text);
|
||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||
margin: 0;
|
||
padding: calc(var(--spacing-unit) * 6) calc(var(--spacing-unit) * 3);
|
||
}
|
||
|
||
.container { max-width: 960px; margin: 0 auto; }
|
||
|
||
h1 {
|
||
color: var(--color-accent-primary);
|
||
text-align: center;
|
||
margin: 0 0 calc(var(--spacing-unit) * 4) 0;
|
||
font-size: 2em;
|
||
font-weight: 700;
|
||
letter-spacing: 0.05em;
|
||
text-shadow: var(--glow-primary);
|
||
}
|
||
|
||
.topbar {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: calc(var(--spacing-unit) * 2);
|
||
margin-bottom: calc(var(--spacing-unit) * 2);
|
||
}
|
||
.topbar h1 { margin: 0; }
|
||
.topbar-actions {
|
||
margin-left: auto;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
.nav-link {
|
||
background: transparent;
|
||
border: 1px solid rgba(255,255,255,0.14);
|
||
color: rgba(255,255,255,0.85);
|
||
padding: 8px 10px;
|
||
border-radius: var(--radius);
|
||
box-shadow: none;
|
||
font-size: 13px;
|
||
text-decoration: none;
|
||
}
|
||
.nav-link:hover { box-shadow: var(--shadow-sm); border-color: rgba(255,255,255,0.22); }
|
||
|
||
.controls { margin: calc(var(--spacing-unit) * 3) 0; text-align: center; }
|
||
input[type="text"] {
|
||
width: min(600px, 100%);
|
||
padding: 12px 14px;
|
||
background: rgba(0,0,0,0.28);
|
||
border: 1px solid rgba(255,255,255,0.12);
|
||
border-radius: 10px;
|
||
color: var(--color-text);
|
||
outline: none;
|
||
}
|
||
button {
|
||
background: var(--color-surface);
|
||
border: 1px solid rgba(255,255,255,0.12);
|
||
color: rgba(255,255,255,0.86);
|
||
padding: 10px 12px;
|
||
border-radius: 10px;
|
||
cursor: pointer;
|
||
}
|
||
button.primary {
|
||
background: linear-gradient(90deg, rgba(0,255,136,0.18), rgba(255,60,245,0.10));
|
||
border-color: rgba(0,255,136,0.28);
|
||
}
|
||
button:disabled { opacity: 0.5; cursor: not-allowed; }
|
||
|
||
#status {
|
||
margin-top: 10px;
|
||
padding: 10px 12px;
|
||
border: 1px solid rgba(255,255,255,0.10);
|
||
border-radius: 12px;
|
||
background: rgba(0,0,0,0.20);
|
||
color: rgba(255,255,255,0.75);
|
||
}
|
||
|
||
.section {
|
||
border: 1px solid rgba(255,255,255,0.12);
|
||
border-radius: 18px;
|
||
background: rgba(0,0,0,0.18);
|
||
padding: 14px;
|
||
box-shadow: 0 26px 90px rgba(0,0,0,0.35);
|
||
margin-top: 16px;
|
||
}
|
||
.section-header { display:flex; align-items: baseline; justify-content: space-between; gap: 10px; }
|
||
.section-title { margin: 0; font-size: 18px; }
|
||
.section-subtitle { margin: 0; color: rgba(255,255,255,0.65); font-size: 13px; }
|
||
.divider { height: 1px; background: rgba(255,255,255,0.08); margin: 12px 0; }
|
||
|
||
.results-section { display: none; }
|
||
.results-section.visible { display: block; }
|
||
.results-table { width: 100%; border-collapse: collapse; }
|
||
.results-table th, .results-table td { padding: 10px; border-bottom: 1px solid rgba(255,255,255,0.08); }
|
||
.results-table tr.selected { background: rgba(0,255,136,0.06); }
|
||
|
||
.player-section { display: none; }
|
||
.player-section.visible { display: block; }
|
||
|
||
.preview-controls, .motif-controls { display:flex; gap: 10px; align-items:center; flex-wrap: wrap; }
|
||
.volume-control { display:flex; align-items:center; gap: 8px; }
|
||
.volume-control label { color: rgba(255,255,255,0.65); font-size: 12px; }
|
||
input[type="range"] { width: 160px; }
|
||
|
||
.model-row { display:flex; align-items:center; gap: 10px; flex-wrap: wrap; }
|
||
.model-row label { color: rgba(255,255,255,0.7); font-size: 12px; }
|
||
select {
|
||
background: rgba(0,0,0,0.28);
|
||
border: 1px solid rgba(255,255,255,0.12);
|
||
color: rgba(255,255,255,0.9);
|
||
padding: 10px 12px;
|
||
border-radius: 10px;
|
||
font-family: inherit;
|
||
}
|
||
|
||
.ios-audio-banner {
|
||
margin-top: 10px;
|
||
border: 1px solid rgba(255,255,255,0.10);
|
||
border-radius: 12px;
|
||
padding: 10px 12px;
|
||
background: rgba(0,0,0,0.18);
|
||
display:none;
|
||
}
|
||
.ios-audio-banner .row { display:flex; align-items:center; justify-content:space-between; gap: 10px; }
|
||
.ios-audio-banner .state { margin-top: 6px; font-size: 12px; color: rgba(255,255,255,0.65); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="topbar">
|
||
<h1>🎵 MOTIF</h1>
|
||
<div class="topbar-actions">
|
||
<a class="nav-link" href="/" aria-label="Back to main app">Home</a>
|
||
</div>
|
||
</div>
|
||
<p style="text-align:center; color: rgba(255,255,255,0.7); margin-top: 0;">Test models: Pre‑8bit → NES/GB → SNES‑ish</p>
|
||
|
||
<div class="controls">
|
||
<input type="text" id="songInput" placeholder="Enter song name..." />
|
||
<button id="searchBtn">Search</button>
|
||
</div>
|
||
|
||
<div id="status">Ready. Enter a song name to search for MIDI files.</div>
|
||
|
||
<div id="resultsSection" class="section results-section">
|
||
<div class="section-header">
|
||
<h3 class="section-title">Search Results</h3>
|
||
<p class="section-subtitle">Pick a MIDI, then compare models.</p>
|
||
</div>
|
||
<div class="divider"></div>
|
||
<table id="resultsTable" class="results-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Title</th>
|
||
<th>Source</th>
|
||
<th>Duration</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="resultsBody"></tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div id="playerSection" class="player-section">
|
||
<div id="selectedInfo" class="section">
|
||
<div style="display:flex; flex-direction:column; gap: 6px;">
|
||
<h4 id="selectedTitle" style="margin:0;">No MIDI selected</h4>
|
||
<p id="selectedMeta" style="margin:0; color: rgba(255,255,255,0.7); font-size: 13px;">Select a MIDI file from search results to enable playback</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section">
|
||
<div class="section-header">
|
||
<h3 class="section-title">Preview</h3>
|
||
<p class="section-subtitle">Soundfont MIDI preview (baseline).</p>
|
||
</div>
|
||
<div class="divider"></div>
|
||
<div class="preview-controls">
|
||
<button id="soundfontPlayBtn" class="primary" disabled>Play Preview</button>
|
||
<button id="soundfontStopBtn" disabled>Stop</button>
|
||
<div class="volume-control">
|
||
<label for="soundfontVolume">Volume</label>
|
||
<input type="range" id="soundfontVolume" min="0" max="1" step="0.01" value="0.8" />
|
||
</div>
|
||
<button id="nextResultBtn" disabled>Try Next Result</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section">
|
||
<div class="section-header">
|
||
<h3 class="section-title">Motif generation</h3>
|
||
<p class="section-subtitle">Same MIDI → different synth models.</p>
|
||
</div>
|
||
<div class="divider"></div>
|
||
|
||
<div class="model-row">
|
||
<label for="modelSelect">Model</label>
|
||
<select id="modelSelect">
|
||
<option value="pre8bit">Pre‑8bit (beep / sparse)</option>
|
||
<option value="nes_gb" selected>NES / Game Boy (chip)</option>
|
||
<option value="snes_ish">SNES‑ish (warm + echo)</option>
|
||
</select>
|
||
<span id="modelHint" style="color: rgba(255,255,255,0.65); font-size: 12px;">Square/triangle/noise vibe, tight envelope.</span>
|
||
</div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<div class="motif-controls">
|
||
<button id="motifBtn" class="primary" disabled>Generate & Play</button>
|
||
<button id="motifStopBtn" disabled>Stop</button>
|
||
<div class="volume-control">
|
||
<label for="motifVolume">Volume</label>
|
||
<input type="range" id="motifVolume" min="0" max="1" step="0.01" value="0.3" />
|
||
</div>
|
||
</div>
|
||
|
||
<div id="iosAudioBanner" class="ios-audio-banner" aria-live="polite">
|
||
<div class="row">
|
||
<div class="copy" style="color: rgba(255,255,255,0.8); font-size: 13px;">
|
||
<strong>iOS Safari:</strong> tap once to enable audio, then press <strong>Generate & Play</strong>.
|
||
</div>
|
||
<button id="enableAudioBtn" type="button">Enable Audio</button>
|
||
</div>
|
||
<div id="iosAudioState" class="state">Audio: …</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script type="module" src="/src/models.ts"></script>
|
||
</body>
|
||
</html>
|
||
|