mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-07-26 06:42:32 +00:00
Some checks are pending
ship-ci / ci (push) Waiting to run
The merged-tuning-catalog route moves to lib/routers/tunings.py, verbatim except
@app->@router, CONFIG_DIR->appstate.config_dir, and the two seam substrates it
needed:
- lib/appconfig.py — the pure config.json reader `_load_config` (used by ~11
server sites + future config-reading routers). server.py re-imports it, so
those call sites and any `server._load_config` test reference are unchanged.
- appstate.tuning_providers — the TuningProviderRegistry instance injected by
reference (a stable object mutated in place via register()/unregister()), so
the router reads the same registry plugins populate through plugin_context.
The instance stays defined in server.py, so `server.tuning_providers` still
resolves — zero test retargets.
The tuning constants (DEFAULT_REFERENCE_PITCH, TUNING_PRESET_MIDIS,
freqs_to_midis) already live in lib/tunings.py and are imported directly.
server.py: 6,960 -> 6,917.
Verified: pyflakes clean (bar the pre-existing unused `tuning_name` import);
route table IDENTICAL (143); full pytest 2400 passed (110 tuning/config cases);
eslint 0. Boot smoke: /api/tunings serves referencePitch + tunings + tuningMidis.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
47 lines
1.9 KiB
Python
47 lines
1.9 KiB
Python
"""The merged tuning catalog (/api/tunings).
|
|
|
|
Extracted verbatim from server.py (R3) except @app->@router, CONFIG_DIR->
|
|
appstate.config_dir, _load_config imported from lib/appconfig, and the tuning
|
|
registry read through the appstate seam (appstate.tuning_providers — the same
|
|
instance plugins register into via the plugin_context in server.py).
|
|
"""
|
|
|
|
from fastapi import APIRouter
|
|
|
|
import appstate
|
|
from appconfig import _load_config
|
|
from tunings import DEFAULT_REFERENCE_PITCH, TUNING_PRESET_MIDIS, freqs_to_midis
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/api/tunings")
|
|
def get_tunings():
|
|
cfg = _load_config(appstate.config_dir / "config.json") or {}
|
|
ref = cfg.get("reference_pitch", DEFAULT_REFERENCE_PITCH)
|
|
try:
|
|
ref = float(ref)
|
|
if not (430.0 <= ref <= 450.0):
|
|
ref = DEFAULT_REFERENCE_PITCH
|
|
except (TypeError, ValueError):
|
|
ref = DEFAULT_REFERENCE_PITCH
|
|
merged = appstate.tuning_providers.get_merged(ref)
|
|
# tuningMidis: the same catalog as exact integer MIDI notes (low → high).
|
|
# Built-ins come straight from TUNING_PRESET_MIDIS (no float round-trip);
|
|
# provider-contributed entries are recovered from their frequencies at the
|
|
# served reference pitch. Every consumer today (the v3 badges, plugins)
|
|
# reconstructs midis client-side via log2 — a rounding footgun at non-440
|
|
# references — so serve the integers once, host-side. Additive: the
|
|
# existing referencePitch/tunings shape is unchanged.
|
|
tuning_midis: dict[str, dict[str, list[int]]] = {}
|
|
for key, names in merged.items():
|
|
builtin = TUNING_PRESET_MIDIS.get(key, {})
|
|
resolved: dict[str, list[int]] = {}
|
|
for name, freqs in names.items():
|
|
midis = builtin.get(name) or freqs_to_midis(freqs, ref)
|
|
if midis:
|
|
resolved[name] = list(midis)
|
|
if resolved:
|
|
tuning_midis[key] = resolved
|
|
return {"referencePitch": ref, "tunings": merged, "tuningMidis": tuning_midis}
|