MCPcopy
hub / github.com/stemdeckapp/stemdeck / mixerScreen

Function mixerScreen

static/mobile/app.js:436–484  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

434}
435
436function mixerScreen() {
437 const c = state.current || { title: "No track selected", sub: "Pick one from your Library", initial: "♪", gradient: DEFAULT_GRADIENT, stemCount: 0 };
438 const sourceTag = c.sub || "—";
439 const stemTag = c.stemCount ? `${c.stemCount} stems` : "";
440 const dur = curDuration();
441 const body = state.mixerView === "stems" ? stemsBody() : analysisBody();
442 const ready = engineReady && engineTrackId === state.current?.id;
443 const preparing = !!state.current && !state.current.loading && !state.current.error && !ready;
444 const canPlay = ready;
445 const curIdx = state.current ? state.tracks.findIndex((t) => t.id === state.current.id) : -1;
446 const hasPrev = curIdx > 0;
447 const hasNext = curIdx >= 0 && curIdx < state.tracks.length - 1;
448
449 return `<div class="screen scrl">
450 <div class="pad">
451 <div class="mx-head">
452 <button class="icon-btn" data-action="tab" data-tab="library">${ICON.chevron}</button>
453 <span class="now-playing">NOW PLAYING</span>
454 <button class="icon-btn">${ICON.dots}</button>
455 </div>
456 <div class="cover-wrap">
457 <div class="cover" style="${artStyle(c)}"><span>${artLabel(c)}</span></div>
458 <div class="track-title">${esc(c.title)}</div>
459 <div class="track-sub">${esc(c.sub)}</div>
460 <div class="tags"><span class="tag">${esc(sourceTag)}</span>${stemTag ? `<span class="tag">${stemTag}</span>` : ""}</div>
461 </div>
462 <div class="wave">
463 <div class="wave-bars" data-seek>${mainWaveform()}<div class="playhead" style="left:${state.progress * 100}%"></div></div>
464 <div class="wave-times"><span class="cur">${fmt(state.progress * dur)}</span><span class="dur">${fmt(dur)}</span></div>
465 </div>
466 <div class="transport">
467 <button class="t-step" data-action="prev" ${hasPrev ? "" : "disabled"}>${ICON.prev}</button>
468 <button class="t-play" data-action="play" data-playing="${state.playing}" ${canPlay ? "" : "disabled style=opacity:.45"}>${state.playing ? ICON.pause(26, "#1a1206") : ICON.play(28, "#1a1206")}</button>
469 <button class="t-step" data-action="next" ${hasNext ? "" : "disabled"}>${ICON.next}</button>
470 </div>
471 <div class="speed-row">
472 <span class="speed-row-label">Speed</span>
473 <input type="range" class="speed-slider" data-speed min="0" max="2" step="0.25" value="${state.speed}">
474 <span class="speed-row-val">${state.speed % 1 === 0 ? state.speed.toFixed(1) : state.speed}x</span>
475 </div>
476 ${preparing ? '<div class="mx-prep">Preparing audio…</div>' : ""}
477 <div class="segmented">
478 <button class="${state.mixerView === "stems" ? "on" : ""}" data-action="mixview" data-view="stems">Stems</button>
479 <button class="${state.mixerView === "analysis" ? "on" : ""}" data-action="mixview" data-view="analysis">Analysis</button>
480 </div>
481 </div>
482 ${body}
483 </div>`;
484}
485
486function libraryBody() {
487 if (state.libState === "loading") {

Callers 1

renderFunction · 0.85

Calls 8

curDurationFunction · 0.85
stemsBodyFunction · 0.85
analysisBodyFunction · 0.85
artStyleFunction · 0.85
artLabelFunction · 0.85
mainWaveformFunction · 0.85
fmtFunction · 0.85
escFunction · 0.70

Tested by

no test coverage detected