Files
feedBack/plugins/tuner
6aed8510d7 Tuner: passive "different tuning" badge cue naming the retune (issue E, stage 2.5/3) (#657)
* Tuner: passive "different tuning" badge cue that names the retune

Building on the coverage check: when you enter a song your current
instrument doesn't cover, the topbar tuner badge gets an amber ring + a
tooltip naming the change (e.g. "retune B->A", or "the reference pitch"
for an A440 vs A432 mismatch). Advisory only -- it never auto-opens the
panel; recomputed on song:ready, cleared on song-load / leaving the
player.

Refactors the coverage check into a structured report
(window._tunerAutoOpen.coverageReport -> { covered, retune:[{from,to}],
reference, cantCover }); the boolean gate now wraps it. The cue is
CSS-free (inline ring + native tooltip, no Tailwind rebuild) and no-ops
when the tuner plugin is absent.

Touches static/v3/badges.js (cue) + plugins/tuner/screen.js (report).
v3-only. Stacked on #656 (issue E stage 2.5/3). The splitscreen-suppress
and no-usable-input guards move to E2 (the playback gate).

Tests: tests/js/tuner_auto_open.test.js (report names the strings,
reference mismatch, badge wiring).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QbexxfTt8q2tAn436MqGWF

* feat(tuner): read/write the live per-instrument working tuning — both-directions retune prompt (working-tuning PR 3) (#660)

The §4 coverage check compared each song against the player's fixed
instrument-profile tuning, so the tuner only ever prompted *away* from a "home"
tuning (E -> Drop C#) and stayed silent coming back (Drop C# -> E), even though
the player had physically retuned.

_playerTuning() now reads the host's live per-instrument working tuning
(window.feedBack.workingTuning, keyed by the selected instrument from
/api/settings) instead of re-deriving from the static settings tuning, so
coverage is measured against what the instrument is ACTUALLY in and prompts both
directions. On clearing an auto-opened tuner, _publishWorkingTuning() writes that
song's tuning as the instrument's live working tuning ('assumed' — PR 4's
explicit "I tuned / Skip" refines the write-point), so the next song is judged
against where the player now is.

Per-instrument (guitar vs bass tracked separately). Feature-detected: falls back
to the static /api/settings tuning when the working-tuning capability is absent,
so the 27 existing coverage tests are unchanged. Builds on PR 1 (host
workingTuning) + PR 2 (instrument->chart routing).

Tests: tests/js/tuner_auto_open.test.js — +2 (both-directions coverage via a live
Drop-D working tuning; publish-on-clear targets the right instrument slot); 29
pass total.

Claude-Session: https://claude.ai/code/session_01QbexxfTt8q2tAn436MqGWF

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* fix(tuner): transactional open + fail-closed auto-open config (tuner-E #655 review) (#681)

Two review fixes for the auto-open opt-in+persist stage:

- enable() wasn't transactional. The panel (with the ×/Skip buttons) is shown
  before `await _tunerAudio.start()`, and `_state.enabled` was only set after it.
  A ×/Skip dismiss during that await hit disable() with wasEnabled=false, then
  enable() completed and flipped enabled on — an enabled-but-hidden zombie. Guard
  the open with an `_openGen` token bumped on every enable()/disable(); after the
  audio-start await, bail if superseded instead of enabling. Closes #675.

- Config wasn't fail-closed. routes.py normalized the opt-in with
  bool(data.get("autoOpenOnTuningChange", False)), so "false"/"0"/junk coerced to
  True. Accept only a real JSON boolean. Closes #676.

Tests: tuner_auto_open.test.js (dismiss-mid-open stays disabled — fails without
the token guard), test_config.py (auto-open default-false + fail-closed on
non-bool). 34 JS + 24 config tests green.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(tuner): coverage stays conservative when the instrument is unknown (tuner-E #656 review) (#682)

_playerTuning() is documented as conservative ("missing data → not covered → still
prompt"), but when /api/settings carried no instrument identity (a fresh profile:
_default_settings() omits instrument/string_count/tuning) it invented guitar/6/440/
standard, so an unconfigured player was treated as 6-string E-standard and coverage
suppressed the auto-open (and badge cue) for matching songs. The post-#660 rewrite
only returned null when the whole fetch failed (!s), not when settings existed but
lacked an instrument.

Now return null unless there's a confident identity — any of instrument/string_count/
tuning in settings, or live working-tuning offsets. A configured standard guitar still
covers a standard song (no regression). Closes #677.

Tests: tuner_auto_open.test.js — empty-settings → not covered (fails without the fix);
configured standard guitar → still covered.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(tuner): badge coverage cue staleness + unknown-as-warning + dedupe (tuner-E #657 review) (#683)

Three review fixes for the passive "different tuning" badge cue stage:

- Stale async cue (#678): _refreshCoverageCue awaited coverageReport then wrote the
  DOM unconditionally, so a slow /api/settings fetch could restore the previous
  song's amber ring after song:loading / leaving the player. Add a monotonic token
  bumped on every refresh and both clear paths; apply the awaited report only if the
  token still matches.

- "Unknown" rendered as "needs retune" (#679): the plugin returns a conservative
  all-false report on a fetch hiccup; the cue painted that as an amber "retune the
  reference pitch" ring. Collapse a no-signal report (not covered, no reference /
  retune / cantCover) to null (no cue) via _meaningfulReport(). A genuine not-covered
  report always carries reference / retune / cantCover, so real cues are preserved.

- Duplicate /api/settings fetch (#680): the auto-open gate and the badge cue both
  call coverageReport() per song:ready. Cache the coverage promise per song (keyed by
  session + tuning + centOffset) so they share one fetch; invalidate on song:loading,
  instrument:changed, and working-tuning-changed so it can't go stale within a song.

Tests: tuner_auto_open.test.js — concurrent reports share one fetch, a new song
refetches (fails without the cache). 34 JS tests green. Codex-reviewed.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Byron Gamatos <xasiklas@gmail.com>
2026-07-01 10:28:04 +02:00
..
2026-06-16 18:47:13 +02:00

FeedBack Tuner Plugin

grafik

A real-time guitar and bass tuner plugin for FeedBack.

This plugin adds a floating "Tuner" button to the FeedBack interface, providing a high-accuracy chromatic tuner with support for multiple presets, custom tunings, and automatic song tuning detection.

Features

  • Real-time Pitch Detection: Uses the YIN algorithm for robust and accurate frequency tracking.
  • Multiple Presets: Includes common guitar and bass tunings (Standard, Drop D, DADGAD, Open G, etc.).
  • Automatic Song Tuning: Detects and selects the correct tuning for the currently playing song in the FeedBack player.
  • Manual & Auto Tracking: Automatically estimates the closest string or allows manual selection for focused tuning.
  • Visual Feedback: Large cents-deviation gauge, frequency display, and color-coded indicators.
  • Custom Tunings: Add your own tunings via note names (e.g., E2, A2) or Hz frequencies in the settings.
  • Audio Device Selection: Choose specific input devices and channels (Mono, Left, Right) for professional interfaces.
  • Themable UI: Styled with Tailwind CSS to match your FeedBack theme.
  • Visualizations: Pick from different visualizations to suit your needs (Currently: Default, Strobe, Analogue Gauge, Mace Fx III, and Toilet Tuner)

Available Visualizations

Name Image
Default grafik
Strobe grafik
Analogue Gauge grafik
Mace-Fx III grafik
Bender PP-Tiny grafik
CHEF MT-3 grafik
Toilet Tuner grafik

Installation

Download a Release

  1. Download one of the Releases
  2. Extract it to your plugins folder
  3. Restart FeedBack

Update Manager

The plugin is listed in the official plugin repository, so it can also be installed directly via the Update Manager

Git

cd /path/to/feedBack/plugins
git clone https://github.com/OmikronApex/slopsmith-plugin-tuner.git tuner
# Restart FeedBack (or restart your docker container)
docker compose restart

How to Use

  1. Click the Tuner button at the bottom-right of the screen (or the "Tuner" button in the player controls).
  2. The tuner will automatically default to the Current Song tuning if you are in the player.
  3. Select other presets or custom tunings from the dropdown menu if needed.
  4. Pluck a string. The tuner will automatically detect the closest string in the selected tuning.
  5. (Optional) Click a specific note button in the tuner window to lock onto that string (useful for very out-of-tune strings).
  6. Adjust your tuning until the needle is centered and the indicator turns green.

Configuration

In-App Settings

Click the ⚙️ icon in the tuner window to access:

  • Audio Input: Select your preferred microphone or audio interface.
  • Channel Selection: Choose between Mono (mixed), Left, or Right channels (ideal for multi-channel audio interfaces).
  • Visualization: Choose between different visualization options.
grafik

Plugin Manager

Access advanced settings via the FeedBack Plugin Manager (Settings -> Plugins -> Tuner):

  • Floating Button: Toggle the visibility of the tuner button on the main interface.
  • Tuning Visibility: Toggle which built-in tunings appear in your menu.
  • Custom Tunings: Define your own tuning presets by entering a name and a list of notes/frequencies.
grafik

Changelog

[1.3.1] - 2026-06-04

  • JUCE bridge audio input: when running inside FeedBack Desktop the tuner taps the engine's raw audio stream (getRawAudioFrame) and runs its own tuning-optimised YIN over it, falling back to the browser microphone pipeline otherwise.
  • Fixed octave-low / sub-harmonic pitch errors (canonical YIN absolute-threshold selection) and added octave-aware nearest-string matching.
  • "Free Tune" is now remembered as your last tuning, so it persists across sessions instead of resetting to a preset each time.
  • Relocated visualization SVG assets to visualization/assets/, served via the dedicated /api/plugins/tuner/viz-assets/ route (supersedes the 1.3.0 note about the root assets/ directory).
  • Removed the legacy Tailwind stylesheet (assets/plugin.css) and its styles manifest entry — supersedes the 1.3.0 stylesheet note below.

[1.3.0] - 2026-06-01

  • Added PP-Tiny visualization: inspired by the Fender PT-100 chromatic tuner panel, with a curved 11-LED arc, 8-segment note display with split centre bar, and always-on BATT. indicator.
  • Added CHEF MT-3 visualization: inspired by the BOSS TU-3, featuring a 90° curved glass gauge arc, 51 tick marks, red 7-segment display, and rubber mode/brightness buttons.
  • Refactored screen.js into focused modules: audio pipeline extracted to utils/audio.js, UI layer extracted to utils/ui.js (shared-state factory pattern). screen.js reduced from ~1060 to ~300 lines.
  • Normalised DEFAULT_TUNINGS keys to instrument keys (guitar-6, bass-4, etc.) — removes the internal group-name lookup table.
  • Added plugin stylesheet (assets/plugin.css) via the FeedBack styles contract, ensuring arbitrary Tailwind classes render correctly for runtime-installed users.
  • Moved SVG assets (Bathroom.svg, Plunger.svg, Toiletbowl.svg) to the root assets/ directory; removed the now-redundant custom asset route from routes.py.
  • Moved Toilet Tuner to the end of the visualization picker list.

[1.2.8] - 2026-05-31

  • Added Toilet Tuner visualization: bathroom scene background with a plunger that slides left/right proportional to cents deviation; dips into the toilet bowl when in tune (±2 cents) and shows a 💩 emoji on the wall calendar.

[1.2.7] - 2026-05-31

  • Added Mace Fx III visualization: dark navy LCD-style panel with a chromatic tick gauge, inward directional arrows, large note/octave readout, a rotating pink strobe semicircle, and a pixelated grid overlay.
  • Improved tuner detection stability: median frequency filtering plus YIN octave correction (rejects both overtone and undertone errors) keeps low strings from jumping octaves as they decay.
  • Added pluck-attack warm-up so the noisy string-attack transient no longer shows a wrong pitch before settling.
  • Added frame-to-frame octave continuity tracking to eliminate residual octave flips.

[1.2.6] - 2026-05-31

  • Added Analogue Gauge visualization: vintage mechanical instrument panel with rotating frequency and note name drums, semicircular needle gauge, and a physical-style in-tune lightbulb.
  • Added AUTO mode indicator lamp: lights when Free Tune is active, dims on manual string lock.
  • Visualizations now receive tuning mode context (free / auto / manual) from the core plugin.

[1.2.5] - 2026-05-30

  • Improved mic error handling: better error messages and inline error banner instead of browser alert.
  • Fixed Real Tone Cable (mono-only USB audio) support when the device is explicitly selected.
  • Fixed error banner persisting across screen navigation after a mic failure.
  • Fixed stale error banner remaining visible after a successful device switch.
  • Fixed silent failure when audio restart fails during device switch.

[1.2.4] - 2026-05-25

  • Improved low-frequency detection by lowering minimum detectable frequency to 20Hz.

[1.2.3] - 2026-05-19

  • Refactored tuner plugin: simplified script loading, modularized audio pipeline, and improved visualization state management.
  • Fixed issue where targeting a specific string was impossible when no audio input was present.

[1.2.2] - 2026-05-18

  • Added missing YIN-worker script.

[1.2.1] - 2026-05-18

  • Added graceful handling for audio device errors by resetting device ID on exceptions.

[1.2.0] - 2026-05-18

  • Introduced Strobe Tuner visualization.
  • Modularized visualization handling and improved state management.
  • Enhanced tuning synchronization logic.

[1.1.0] - 2026-05-10

  • Added 5-string bass tunings.
  • Removed unnecessary scroll limit in settings UI.

[1.0.3] - 2026-05-10

  • Visual polish for the settings page.
  • Added toggle for floating tuner button visibility.

[1.0.2] - 2026-05-10

  • Added microphone and channel selection settings.
  • Integrated tuner button into the player UI.
  • Added dynamic tuning detection within the player.

[1.0.1] - 2026-05-10

  • Fixed floating button reappearing on song end.
  • Improved tuner button injection in player UI.

[1.0.0] - 2026-05-10

  • Initial release.

License

MIT