diff --git a/static/v3/badges.js b/static/v3/badges.js index 609d90b..6ff8e36 100644 --- a/static/v3/badges.js +++ b/static/v3/badges.js @@ -60,6 +60,52 @@ return typeof settings.tuning === 'string' ? settings.tuning : 'Custom'; } + // The SELECTED instrument's live working tuning (host `workingTuning` capability). + // Feature-detected: returns null when the host doesn't expose it, so the card + // quietly falls back to the profile tuning. `offsets` are named via the shared + // displayTuningName resolver; "home" = still in the profile/default tuning. + function workingTuningInfo() { + var wt = window.feedBack && window.feedBack.workingTuning; + var st = wt && typeof wt.get === 'function' ? wt.get() : null; + if (!st) return null; + var offsets = Array.isArray(st.offsets) ? st.offsets : null; + var nameFor = window.displayTuningName + || (window.feedBack && window.feedBack.displayTuningName); + // Resolve BOTH the home tuning and the working tuning through the SAME namer so + // "home?" is a like-for-like comparison — comparing a raw settings string ('Custom' + // / 'E Standard') against a from-offsets name would mislabel a real home tuning. + var homeLabel = (typeof nameFor === 'function') + ? (nameFor(typeof settings.tuning === 'string' ? settings.tuning : null, + Array.isArray(settings.tuning) ? settings.tuning : null) || tuningLabel()) + : tuningLabel(); + var label = (offsets && typeof nameFor === 'function') ? nameFor(null, offsets) : homeLabel; + return { + label: label, + short: label.replace(/ Standard\b/, ' Std').replace(/Custom Tuning/, 'Custom'), + // Home = no explicit working offsets, OR the working tuning names the same as + // the profile's home tuning (both via `nameFor`, so the compare is consistent). + isHome: !offsets || label === homeLabel, + provenance: st.provenance === 'verified' ? 'verified' : 'assumed', + }; + } + + // Honesty glyph: a hollow diamond for an assumed tuning, a filled one for a + // per-string mic-verified tuning (see the workingTuning provenance flag). + function provenanceGlyph(p) { + return p === 'verified' + ? '◆' + : '◇'; + } + + // Tell the host which instrument is now selected, so workingTuning.get() + // surfaces THIS instrument's own remembered tuning. No-op without the capability. + function setWorkingInstrument(inst, sc) { + var wt = window.feedBack && window.feedBack.workingTuning; + if (wt && typeof wt.setCurrentInstrument === 'function') { + try { wt.setCurrentInstrument(inst, sc); } catch (_) { /* noop */ } + } + } + let settings = { instrument: 'guitar', string_count: 6, tuning: 'Standard', reference_pitch: 440 }; async function loadTunings() { @@ -129,13 +175,14 @@ accepted = !(body && body.error); } } catch (e) { /* non-fatal — leave settings unchanged */ } - if (!accepted) return; + if (!accepted) return false; Object.assign(settings, patch); if (sm && sm.emit) sm.emit('instrument:changed', { instrument: settings.instrument, stringCount: settings.string_count, tuning: settings.tuning, }); pushToTuner(); renderTuner(); // reflect new tuning on the tuner card + return true; } // Drive the tuner plugin's instrument + tuning from the selection. @@ -343,14 +390,29 @@ function renderInstrument() { const host = document.getElementById('v3-badge-instrument'); if (!host) return; + const wt = workingTuningInfo(); host.innerHTML = '