| <!doctype html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> |
| <title>NanoMaestro Realtime - Real-time AI Music</title> |
| <link rel="preconnect" href="https://fonts.googleapis.com"> |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet"> |
| <link rel="stylesheet" href="./styles.css?v=2.2" /> |
| </head> |
| <body> |
| |
| <div id="loadingOverlay" class="loading-overlay"> |
| <div class="loader-card"> |
| <h1 class="loader-title">NanoMaestro Realtime</h1> |
| <p class="loader-subtitle">Real-time Lightweight Music Model</p> |
| |
| <div class="progress-container"> |
| <div class="progress-bar"> |
| <span id="loadProgress"></span> |
| </div> |
| <div class="progress-details"> |
| <span id="loadStatus">Preparing application...</span> |
| <span id="loadPercent">0%</span> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <main class="dashboard-shell"> |
| |
| <header class="app-header"> |
| <div class="brand"> |
| <div> |
| <h2>NanoMaestro Realtime</h2> |
| <p id="appStatus">Ready to perform</p> |
| </div> |
| </div> |
| </header> |
| |
| <div class="dashboard-content"> |
| |
| <aside class="sidebar-spacer info-sidebar"> |
| <div class="info-card"> |
| <h5>About NanoMaestro</h5> |
| <p>This model is a tiny, approximately 50 MB music-generation model with about 13 million parameters, designed to run continuously in real time on almost any consumer CPU.</p> |
| <p>Inference runs entirely on your device through WebAssembly (WASM), allowing NanoMaestro to generate music directly on your device locally.</p> |
| </div> |
| </aside> |
| |
| |
| <div class="main-column"> |
| |
| <section class="visualizer-panel"> |
| <div class="panel-header"> |
| <h3>Performance Visualizer</h3> |
| <div class="hud-stats"> |
| <div class="hud-item"> |
| <span class="hud-label">BPM</span> |
| <span class="hud-value" id="tempo">120</span> |
| </div> |
| <div class="hud-item"> |
| <span class="hud-label">Notes</span> |
| <span class="hud-value" id="eventCount">0</span> |
| </div> |
| <div class="hud-item"> |
| <span class="hud-label">Last Token</span> |
| <span class="hud-value" id="lastToken">-</span> |
| </div> |
| <div class="hud-item queue-hud-item"> |
| <span class="hud-label">Queue</span> |
| <div class="queue-hud-row"> |
| <div class="readout-progress"> |
| <span id="queueFill"></span> |
| </div> |
| <span class="hud-value" id="queueCount">0</span> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="visualizer-container"> |
| <canvas id="noteCanvas"></canvas> |
| </div> |
| </section> |
| |
| |
| <section class="controls-panel-bottom"> |
| |
| <div class="controls-main-row"> |
| |
| <div class="control-group playback-actions"> |
| <button id="startBtn" type="button" class="btn-primary" disabled> |
| <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"><path d="M8 5v14l11-7z"/></svg> |
| Start Performance |
| </button> |
| <button id="stopBtn" type="button" class="btn-secondary" disabled> |
| <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg> |
| Stop |
| </button> |
| <button id="newSongBtn" type="button" class="btn-secondary" disabled> |
| <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/></svg> |
| New Song |
| </button> |
| </div> |
|
|
| |
| <div class="control-group seeding-group"> |
| <div class="toggle-group" id="seedSourceGroup"> |
| <button type="button" class="toggle-btn active" data-value="default">Start from Blank</button> |
| <button type="button" class="toggle-btn" data-value="midi">Start from MIDI</button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="midiSeedControls" style="display: none;" class="midi-seed-controls"> |
| <div class="input-file-group"> |
| <label for="midiFileInput">Select MIDI File</label> |
| <input id="midiFileInput" type="file" accept=".mid,.midi" /> |
| </div> |
| |
| <div id="midiFileInfo" class="midi-file-info" style="display: none; margin-top: 10px;"> |
| <p id="midiFileName" class="midi-info-text" style="font-weight: 500;"></p> |
| <p id="midiFileStats" class="midi-info-text" style="margin-top: 2px;"></p> |
| |
| <div class="timeline-container" style="margin-top: 14px;"> |
| <span class="slider-header" style="font-size: 0.72rem; margin-bottom: 6px; color: var(--color-text-muted);">Visual Song Map & Warm-up Context (256 Tokens)</span> |
| <div id="midiTimeline" class="midi-timeline"></div> |
| </div> |
| |
| <div class="slider-group" style="margin-top: 12px;"> |
| <div class="slider-header"> |
| <label for="midiStartBar">Start Generation from Bar</label> |
| <span id="midiStartBarValue">0</span> |
| </div> |
| <input id="midiStartBar" type="range" min="0" max="0" step="1" value="0" /> |
| </div> |
| <p id="midiStartBarTime" class="midi-info-subtext"></p> |
| </div> |
| </div> |
| </section> |
| </div> |
|
|
| |
| <aside class="sidebar-column"> |
| |
| <details class="advanced-details settings-dropdown"> |
| <summary>Generation & Acoustic Settings</summary> |
| <div class="advanced-content settings-vertical-stack"> |
| |
| <div class="settings-column"> |
| <h5>Generation Engine</h5> |
| <div class="slider-group"> |
| <div class="slider-header"> |
| <label for="temperature">Creativity (Temp)</label> |
| <span id="temperatureValue">0.85</span> |
| </div> |
| <input id="temperature" type="range" min="0.45" max="1.35" step="0.05" value="0.85" /> |
| </div> |
|
|
| <div class="slider-group"> |
| <div class="slider-header"> |
| <label for="topK">Vocabulary Focus (Top K)</label> |
| <span id="topKValue">40</span> |
| </div> |
| <input id="topK" type="range" min="5" max="120" step="1" value="40" /> |
| </div> |
| </div> |
|
|
| |
| <div class="settings-column"> |
| <h5>Acoustic Parameters</h5> |
| <div class="slider-group"> |
| <div class="slider-header"> |
| <label for="masterVolume">Volume</label> |
| <span id="volumeValue">85%</span> |
| </div> |
| <input id="masterVolume" type="range" min="0" max="100" step="1" value="85" /> |
| </div> |
|
|
| <div class="slider-group"> |
| <div class="slider-header"> |
| <label for="reverbWet">Room Size (Reverb)</label> |
| <span id="reverbValue">22%</span> |
| </div> |
| <input id="reverbWet" type="range" min="0" max="100" step="1" value="22" /> |
| </div> |
|
|
| <div class="slider-group"> |
| <div class="slider-header"> |
| <label for="delayWet">Echo (Delay)</label> |
| <span id="delayValue">8%</span> |
| </div> |
| <input id="delayWet" type="range" min="0" max="100" step="1" value="8" /> |
| </div> |
|
|
| <div class="slider-group"> |
| <div class="slider-header"> |
| <label for="synthRelease">Sustain (Release)</label> |
| <span id="releaseValue">1.2s</span> |
| </div> |
| <input id="synthRelease" type="range" min="0.2" max="3.0" step="0.1" value="1.2" /> |
| </div> |
| </div> |
| </div> |
| </details> |
| </aside> |
| </div> |
| </main> |
|
|
| <script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.20.1/dist/ort.min.js"></script> |
| <script src="https://cdn.jsdelivr.net/npm/tone@15.1.22/build/Tone.js"></script> |
| <script type="module" src="./app.js?v=2.2"></script> |
| </body> |
| </html> |
|
|