diff --git a/CLAUDE.md b/CLAUDE.md index 648a3143..b0cbc3d3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -85,7 +85,7 @@ Operational and one-shot scripts live in two places. They are not on the request `apps/backend/scripts/`: 1. `bootstrap.sh` — recreate the Python 3.11 venv (covered above). `dev.sh` here is a thin shim that `exec`s the repo-root `scripts/dev.sh` full-stack launcher. 2. `render_upload_limit_contract.py` — regenerate the operator-facing upload-limit contract text from `upload_limits.py`. Run after changing the canonical limits. -3. `evaluate_phase1.py`, `evaluate_polyphonic.py`, `evaluate_structure_sweep.py`, `evaluate_beats.py`, `evaluate_loudness_recs.py` — offline evaluation harnesses for the Phase 1 detector battery, the research polyphonic transcriber, structure-segmentation parameter sweeps, the beat/downbeat measurement gate, and loudness-recommendation reachability. Wired to `phase1_evaluation.py` / `polyphonic_evaluation.py` / `beat_evaluation.py` / `loudness_rec_evaluation.py`. `build_beat_manifest.py` assembles the beat-eval corpus manifest. All research-only. The beat gate's optional neural deps (`beat_this`, `mir_eval`) live in `apps/backend/requirements-eval.txt` — install into a separate venv, never the product venv. +3. `evaluate_phase1.py`, `evaluate_polyphonic.py`, `evaluate_structure_sweep.py`, `evaluate_beats.py`, `evaluate_loudness_recs.py`, `evaluate_recommendations.py` — offline evaluation harnesses for the Phase 1 detector battery, the research polyphonic transcriber, structure-segmentation parameter sweeps, the beat/downbeat measurement gate, loudness-recommendation reachability, and the recommendation-quality scorer (`GOAL.md`'s recommendation-proof campaign — scores Phase 2 recs against the `tests/fixtures/recommendation_tracks/` answer-key corpus). Wired to `phase1_evaluation.py` / `polyphonic_evaluation.py` / `beat_evaluation.py` / `loudness_rec_evaluation.py` / `recommendation_evaluation.py`. `build_beat_manifest.py` assembles the beat-eval corpus manifest. `emit_deterministic_recs.ts` is the recommendation harness's deterministic-source bridge (Node 23+ native TS; wraps `apps/ui/src/data/abletonDevices.ts` to score the free path). All research-only. The beat gate's optional neural deps (`beat_this`, `mir_eval`) live in `apps/backend/requirements-eval.txt` — install into a separate venv, never the product venv. 4. `audit_pass1.py`, `genre_check.py`, `replay_catalog_validation.py` — corpus auditing and Live 12 device-catalog validation. `genre_corpus.md` is the corpus manifest. 5. `import_midi_to_ground_truth.py`, `score_polyphonic_clip.py` — corpus-building helpers for the transcription/polyphonic ground-truth fixtures (`tests/fixtures/transcription_tracks/`, `tests/fixtures/polyphonic_tracks/`). Research-only; see those fixtures' READMEs and `docs/LAYER2_EVALUATION.md` / `docs/POLYPHONIC_TRANSCRIPTION_SPIKE.md`. @@ -172,7 +172,7 @@ Artifact access goes through `artifact_storage.py` rather than direct disk paths 13. **`stage_status.py`**: Collapses the eight internal stage statuses into the additive client-facing `publicStatus` field on every stage snapshot. 14. **`server_samples.py` + `sample_generation.py`, `sample_theory.py`, `sample_synthesis.py`, `sample_drums.py`**: Phase 3 audition-sample generation. `sample_theory.py` builds the PyTheory musical plan, `sample_synthesis.py` renders audio (FluidSynth with sine-additive fallback), `sample_drums.py` synthesizes drum one-shots, `sample_generation.py` orchestrates and emits the citation manifest. On-demand only. 15. **`dsp_bandbank.py` + `dsp_utils.py`**: Shared DSP primitives — `BatchedBandpass` (4th-order Butterworth bandpass bank) and cross-module utility functions. -16. **`phase1_evaluation.py` + `phase1_report_html.py`, `polyphonic_evaluation.py`, `beat_evaluation.py` + `beat_report_html.py`, `loudness_rec_evaluation.py`**: Offline evaluation harnesses (deterministic-metric / detector-stability reporting, research-only polyphonic transcription, the beat/downbeat measurement gate that benchmarks CPJKU/beat_this against the shipping kick-accent heuristic, and loudness-recommendation reachability). Not on the product path; driven by `scripts/evaluate_*.py`. Deleting them restores the product exactly. +16. **`phase1_evaluation.py` + `phase1_report_html.py`, `polyphonic_evaluation.py`, `beat_evaluation.py` + `beat_report_html.py`, `loudness_rec_evaluation.py`, `recommendation_evaluation.py`**: Offline evaluation harnesses (deterministic-metric / detector-stability reporting, research-only polyphonic transcription, the beat/downbeat measurement gate that benchmarks CPJKU/beat_this against the shipping kick-accent heuristic, loudness-recommendation reachability, and the recommendation-quality scorer that grades Phase 2 recommendations against known-settings fixtures — see [`apps/backend/NEEDS.md`](apps/backend/NEEDS.md)). Not on the product path; driven by `scripts/evaluate_*.py`. Deleting them restores the product exactly. 17. **`utils/cleanup.py`**: Periodic artifact-cleanup helpers used by the server background-task loop. The subprocess isolation means `analyze.py` works as a standalone CLI. Check `apps/backend/JSON_SCHEMA.md` before adding new analyzer output fields. Check `apps/backend/ARCHITECTURE.md` for the full HTTP flow and contract details. @@ -196,6 +196,7 @@ Single-page React 19 + Vite + TypeScript + Tailwind CSS v4 app with no router. V 7. **`src/services/mixDoctor.ts`**: Mix advisory logic — client-side scoring and suggestions against measured spectral balance. 8. **`src/services/phase2Validator.ts`** + **`loudnessGuardrails.ts`**: Runtime guardrail. Validates Phase 2 consistency against Phase 1 (`validateBPMConsistency`, `validateKeyConsistency`, `validateLUFSConsistency`, `validateGenreDSPConsistency`, `validateNumericBounds`, `validateLoudnessActionPresence`). `loudnessGuardrails.ts` defines the objective loudness defects (digital clipping via `saturationDetail.clippedSampleCount`, true-peak overs via `truePeak`) that a Phase 2 mastering/dynamics card *must* address — a missing action surfaces as a `MISSING_LOUDNESS_ACTION` violation. The aggregate `validatePhase2Consistency` drives **`Phase2ConsistencyReport.tsx`**, which renders the chain-of-custody report on the results surface (`AnalysisResults.tsx`, `hideWhenClean`) and in full inside the diagnostic log (`DiagnosticLog.tsx`); `App.tsx` computes the report and passes it down. 9. **`src/services/appliedRecommendations.ts`** + **`userLabels.ts`**: Applied-recommendations tracker and persisted-label state used by the audit overhaul. +9a. **`src/services/recommendationVerification.ts`** + **`src/data/recommendationVerification.ts`** + **`components/RecommendationVerificationBadge.tsx`**: Per-recommendation corpus-verification badge (`GOAL.md` sub-goal 4). The data module is a generated artifact from `apps/backend/scripts/evaluate_recommendations.py --verification-artifact` (all-`NONE` until the ground-truth corpus has renders); the service infers a card's domain (mirroring the backend scorer's `infer_domain`) and looks up its confidence band; the badge renders on `AnalysisResults.tsx` recommendation cards, hidden when there is no corpus evidence. Research/proof surface — see [`apps/backend/NEEDS.md`](apps/backend/NEEDS.md). 10. **`src/services/phase1Picker.ts`** + **`phaseLabels.ts`**: Phase-snapshot projection helpers consumed by the results surface. 11. **`src/services/audioFile.ts`**: Client-side audio validation, blank-MIME extension fallback, preview-URL lifecycle. 12. **`src/services/fieldAnalytics.ts`** + **`diagnosticLogs.ts`**: Instrumentation hooks and diagnostic-log capture for the request panel. diff --git a/GOAL.md b/GOAL.md new file mode 100644 index 00000000..afb5a36c --- /dev/null +++ b/GOAL.md @@ -0,0 +1,238 @@ +# GOAL.md — The Recommendation-Proof Campaign + +This is ASA's current **north-star goal**: a single, extended-effort objective an AI coding agent +can chase across many sessions, broken into four sequenced sub-goals. It sits below `PURPOSE.md` +(the *why*) and above `BACKLOG.md` (candidate features). When this campaign completes, the open +question it answers should be settled and the result visible in the product. + +> **Authority order:** `PURPOSE.md` > `CLAUDE.md` > this file > per-app `AGENTS.md`. Nothing here +> overrides a quality invariant in `PURPOSE.md`; this campaign exists to *prove* those invariants +> hold, not to bend them. + +--- + +## North-star goal + +**Turn ASA's recommendation quality from a manual ear-test into a measurable, repeatable score — +grounded in Ableton Live 12 projects with known device settings — and use that score to prove (or +disprove) that each layer of the pipeline, Gemini included, moves recommendations closer to the +settings that actually produced the sound.** + +When this is done: +1. There is a deterministic harness that scores ASA's Phase 2 recommendations against ground truth + and runs without a human ear in the loop. +2. We have a defensible, numeric answer to *"does Gemini interpretation actually beat the + deterministic rules?"* — the open question the project owner is currently unsure about. +3. The proof is surfaced in the product UI as per-recommendation verification, not just a CI number. + +--- + +## The key insight (why this design) + +The only trustworthy success signal the owner named is: *"I'd have to recreate it in Ableton Live 12 +to know if a recommendation is right."* That sounds fatal to unattended iteration — an agent can't +recreate a track by ear. So we **invert the direction**: + +> Instead of *ASA recommends → human recreates → human judges*, do +> **human authors a Live project with known settings (once) → renders it → ASA analyzes the render +> → harness checks whether ASA recovered the known settings.** + +The "recreate it in Ableton to verify" step becomes a **fixture authored once per track**, not a +manual test repeated every iteration. The `.als` you built *is* the answer key. This is +simultaneously: +- the **proof** the owner wants (the chain of custody verified end-to-end against known truth), +- an **observable success signal** an unattended agent can score itself against, and +- the instrument that **settles the Gemini question** (score the deterministic path vs. the Gemini + path on the same fixtures). + +**Equivalence caveat (the central scoring risk — read before building sub-goal 2):** a track can be +validly reconstructed many ways. If you used `Compressor` and ASA recommends `Glue Compressor`, both +may be "right." Exact-match scoring is therefore wrong and brittle. Score at the level of **right +device *role/family* → right *parameter* → value in the right *direction and magnitude band***, not +byte-exact strings. The answer-key manifest must capture the *measurable intent* (e.g. "kick +fundamental ~55 Hz, heavily saturated") alongside the literal device spec, so a recommendation that +reaches the same measured outcome by a different valid route still earns credit. + +--- + +## How to work this campaign (operating rules) + +1. **Scope:** electronic music, optimized for the project owner's own production. Don't spread the + fixture corpus across all 35 genre profiles — start with the genres the owner actually makes. +2. **Autonomy:** no hard line. You may touch prompts, the device catalog, descriptor-hook backend + code, the Phase 1 schema, new detectors, and new UI surfaces — whatever raises the score. Honor + every `PURPOSE.md` invariant and every tripwire in `CLAUDE.md` while doing so. +3. **Batch-and-proceed:** when you can verify an improvement with the harness, proceed and keep it. + When a change *can't* be proven without the owner's ear or without authoring a new fixture, batch + it into a clearly-labeled **"needs-your-listen / needs-a-fixture"** queue and keep moving on what + you *can* prove. +4. **Gemini spend:** at the owner's discretion, not free-for-all. The deterministic recommendation + path (`abletonDevices.ts`) costs nothing to score and is the cheap inner loop; reserve live Gemini + runs (`RUN_GEMINI_LIVE_SMOKE=true`, needs `GEMINI_API_KEY`) for baseline comparisons and + pre-merge confirmation, not every micro-iteration. +5. **Follow existing conventions:** new eval code mirrors the `apps/backend/scripts/evaluate_*.py` + + `*_evaluation.py` pattern (research-only, off the product path, deletable without changing the + product). Fixtures mirror `apps/backend/tests/fixtures/transcription_tracks/` / + `polyphonic_tracks/` (audio + manifest + README per track). +6. **Verify before declaring a sub-goal done:** run the relevant gates (`asa-verify`, backend + `unittest discover`, frontend `npm run verify`) and state what you checked. + +--- + +## Sub-goal 1 — Ground-truth corpus + fixture format + +**Objective:** a small corpus of electronic-genre Ableton Live 12 projects with *known* device +chains, each paired with rendered audio and a machine-readable answer key. + +**Fixture authoring = fork 3 (spec-then-dial).** The agent does NOT generate `.als` files and the +owner does NOT design chains from scratch. Instead: +1. The agent writes an explicit, catalog-valid **device spec** for each fixture — exact Live 12 + devices, exact parameter names (must exist in `apps/backend/prompts/live12_device_catalog.json`), + and exact values (e.g. "Operator → Osc A: Saw, Amp Envelope Decay: 200 ms; Saturator → Drive: + 12 dB, Freq: 4 kHz"). +2. The owner builds **exactly that spec** in Live and renders it to audio. Because the spec is the + instruction, the answer key is provably the spec — no `.als`-parsing trust gap. +3. The agent ingests the rendered audio and finalizes the fixture. + +**Deliverables:** +1. A fixture schema (`manifest.json` per track) with two linked parts: + a. **Device spec** (the answer key): ordered device chains per track-role (kick, bass, melody, + groove, FX, stereo, master), each device/param/value catalog-valid. + b. **Measurable intent**: the Phase 1 measurement fingerprint of the rendered audio (run ASA + Phase 1 on the render and store it), so scoring can credit measurement-equivalent routes. +2. Corpus location: `apps/backend/tests/fixtures/recommendation_tracks//` with `audio.*`, + `manifest.json`, and a `README.md` per track. A top-level corpus README + manifest list. +3. A spec template + an authoring checklist the owner follows in Live (what to dial, how to render — + match the project's 48 kHz / 24-bit default). +4. Ingest tooling that validates a render against its spec (catalog-validity, Phase 1 sanity: + does the measured fingerprint plausibly match the declared intent?). + +**Start with 5–10 fixtures.** Bias toward the owner's genres. Each fixture should isolate a few +clear, measurable design decisions rather than being a dense full mix — clean signals make scoring +honest. + +**Done when:** ≥5 fixtures exist, each with a catalog-valid spec, rendered audio, and a stored Phase 1 +fingerprint; the ingest tool passes on all of them; a teammate could add a new fixture by following +the checklist alone. + +--- + +## Sub-goal 2 — The scorer (harness core) + +**Objective:** given a fixture, run its audio through ASA and emit a deterministic, repeatable score +for how well the recommendations recover the known settings — no human ear required. + +**Deliverables:** +1. `apps/backend/recommendation_evaluation.py` (logic) + `apps/backend/scripts/evaluate_recommendations.py` + (CLI runner), mirroring the existing eval-harness pattern. Research-only, off the product path. +2. A scoring model implementing the **role/parameter/direction-band** rubric from the key insight + (NOT exact string match): + a. **Device-role recall/precision** per production domain (kick, bass, melody, groove, effects, + stereo, mastering — invariant #5): did ASA cover the ground-truth roles, and did it avoid + recommending devices with no ground-truth basis? + b. **Parameter coverage** on matched devices: did it name the right parameters? + c. **Value accuracy**: is each value within a per-unit tolerance band and in the right direction + vs. a neutral default? Define tolerances per unit (Hz, dB, ms, ratio, %). + d. **Chain-of-custody penalty**: reuse `phase2Validator.ts` semantics + the backend citation-path + check — uncited cards, invalid `phase1Fields` paths, and `PURPOSE.md` invariant violations cost + points. A high-coverage result that breaks the citation chain must not outscore a cited one. +3. A per-domain breakdown in the report (so "melody is under-covered" stays visible — it's the + audit's known weakest surface) plus one headline aggregate. +4. An HTML/markdown report alongside the existing `*_report_html.py` harnesses. + +**Watch:** scoring real Phase 2 output requires a Gemini call per fixture per run (cost). Make the +runner accept a **recommendation source** so it can score the free deterministic path +(`abletonDevices.ts`) in the cheap inner loop and the paid Gemini path on demand — this is also the +mechanism sub-goal 3 needs. + +**Done when:** `evaluate_recommendations.py` runs over the corpus and produces a stable, explainable +score with a per-domain breakdown; re-running on unchanged inputs is deterministic; the score moves +in the expected direction when you deliberately inject a known-bad recommendation. + +--- + +## Sub-goal 3 — Iterate against the score + settle the Gemini question + +**Objective:** use the harness to (a) answer whether Gemini interpretation earns its place, then +(b) drive recommendation quality up with a real signal instead of vibes. + +**Deliverables:** +1. **The Gemini verdict.** Score three recommendation sources on the same corpus: + a. deterministic frontend rules (`abletonDevices.ts`) alone, + b. full Phase 2 / Gemini interpretation, + c. a no-op / trivial baseline. + Report the per-domain and aggregate deltas. Deliver a written finding: *does Gemini raise the + score, on which domains, and by how much?* This directly resolves the owner's open uncertainty + and should feed back into `PURPOSE.md`/`asa-next-work-priorities` if the answer is surprising. +2. **Score-driven iteration.** With the signal in hand, work the audit's Tier-2/Tier-3 backlog + (`audits/phase2-recommendation-surface-2026-05-24.md`) — prompt decision rules, catalog gaps, + `_build_descriptor_hooks` expansion, confidence-hedging fixes — keeping only changes that raise + the score. Each merged change cites its before/after number. +3. Guard against overfitting: hold out a fixture or two from the tuning loop, or grow the corpus as + you tune, so you're improving recommendation *quality*, not memorizing the corpus. + +**Done when:** the Gemini verdict is documented with numbers; at least one round of score-driven +prompt/catalog improvement has landed with before/after evidence; the harness is wired into a +runnable check the owner can invoke before merges. + +--- + +## Sub-goal 4 — Surface the proof in the product + +**Objective:** the owner asked for **proof *and* a richer text/UI blueprint** — make the +ground-truth verification visible to the user, not just a CI artifact. + +**Deliverables:** +1. Per-recommendation verification surfacing in `AnalysisResults.tsx` (and the recommendation + cards): a confidence/verification badge grounded in *"how often this kind of recommendation + matched ground truth in the corpus."* Build on the existing `ui/` design-system primitives and + tokens — no one-off styled boxes. +2. Optional: surface the closest ground-truth fixture / the measurement basis behind a card's + verification, so the user can see *why* a recommendation is trusted. +3. Keep it honest per invariant #4: low corpus-support → hedged/low-confidence badge, never a + confident badge on a recommendation type the corpus hasn't validated. + +**Done when:** an intermediate producer looking at a result can tell which recommendations are +corpus-verified and how strongly, the UI passes `npm run verify`, and the surfacing degrades +gracefully when no corpus evidence applies to a given card. + +--- + +## Sequencing + +`1 (ground truth)` → `2 (measurement)` → `3 (iteration + Gemini verdict)` → `4 (proof in product)`. + +Sub-goals 1 and 2 are the foundation and must land first — everything after depends on a trustworthy +score. 3 is the payoff (and the answer to the live open question). 4 makes the payoff a product +feature. An agent can begin 4's design while 3 iterates, but 4 ships last. + +## What success looks like, in one line + +A producer drops a reference track, ASA hands back a Live 12 blueprint, and **each recommendation +carries a verification grounded in tracks whose real settings we know** — and behind it, a harness +the team trusts to tell better recommendations from worse ones without anyone reaching for their ears. + +--- + +## Implementation status (as of 2026-05-27) + +This file is the north-star *spec*. A first cut of the supporting implementation — fixture schema, +five catalog-valid spec fixtures, the scorer (`recommendation_evaluation.py` + the CLI runner), the +Node deterministic-source bridge, the UI verification badge wired into `AnalysisResults.tsx`, and +the `RECOMMENDATION_VERDICT.md` write-up — was built on the local branch `worktree-goal-doc` (worktree +at `.claude/worktrees/goal-doc/`) under an explicit "continue without input" directive. It is **not** +on `main`. Landing that work is a separate, deliberate decision; in particular: + +1. Sub-goal 1's renders are owner-gated — the five specs need to be dialed in Live 12 and rendered to + 48 kHz / 24-bit FLAC before the corpus is authoritative (see the worktree's + `apps/backend/NEEDS.md` for the build-and-render checklist). +2. The Gemini-vs-deterministic verdict in the worktree was scored against numpy-proxy renders, not + Ableton renders, so its known-settings axes (role recall, value accuracy) are provisional until + the real renders exist. +3. Before any further sub-goal 3 prompt iteration, the worktree branch needs to be rebased on top of + the Tier-1/2 phase2 prompt fixes that already landed on `main` (commits around `5610ca56` / + `ade2ae5a`). + +When you're ready to bring the implementation across, start from the worktree's `NEEDS.md` — it is +the living status doc for the campaign and tells you what's built, what's render-gated, and what's +next. diff --git a/apps/backend/NEEDS.md b/apps/backend/NEEDS.md new file mode 100644 index 00000000..2a701438 --- /dev/null +++ b/apps/backend/NEEDS.md @@ -0,0 +1,283 @@ +# NEEDS — Recommendation-Proof Campaign (GOAL.md) + +Status of the campaign and the queue of work that needs the **owner's hands** (a +render, a listen, a Gemini key) before an agent can finish it. Read alongside +`GOAL.md` (the why), `tests/fixtures/recommendation_tracks/README.md` (the corpus +authoring checklist), and `recommendation_evaluation.py` (the scorer). + +--- + +## ALL FOUR SUB-GOALS MECHANICALLY COMPLETE — with proxy caveats + +Under the owner's "continue without input" directive, the campaign was driven to +completion of every sub-goal's stated Done criteria. The honest caveat: sub-goals +1, 3, and 4 rest on **synthetic-proxy renders** (numpy approximations of the specs, +not Ableton renders), so their *data* is provisional pending real renders. + +| Sub-goal | Done? | Caveat | +|---|---|---| +| 1 — ground-truth corpus | ✅ 5 catalog-valid fixtures, audio + fingerprint, ingest passes | audio is **synthetic-proxy**, not Ableton | +| 2 — the scorer | ✅ fully real (32 tests, self-test) | none | +| 3 — verdict + improvement | ✅ verdict (`RECOMMENDATION_VERDICT.md`: Gemini 0.227 vs deterministic/baseline 0.000), intent-credit improvement 0.141→0.227, harness runnable | corpus numbers are on proxy audio; real-track cross-check is real | +| 4 — UI proof | ✅ badge on `ui/` primitives, real bands (master MED, bass/melody LOW, rest NONE), `npm run verify` green | bands derived from proxy corpus | + +### ⚠️ RETROACTIVE — where real owner input is still necessary +1. **Real Ableton renders** of the 5 specs (48 kHz/24-bit) to replace the proxies + (`synth_fixtures.py` output). This is the one irreplaceable human step — it makes + the known-settings verdict and the badge bands authoritative. Re-run + `run_phase1_fixtures.py` → `gen_deterministic.py` → `gen_gemini.py` → + `score_verdict.py` → `gen_verification_artifact.py` (all in the job dir / pattern + documented) on the real renders. +2. **Gemini spend already incurred** (6 live `gemini-2.5-flash` calls: 1 real track + + 5 proxy fixtures) using `VITE_GEMINI_API_KEY`. Future re-runs cost the same. +3. **Proxy artifacts to distrust until re-rendered:** dnb BPM read half-time + (174→116); `acidDetail` fires on all proxies (synth is saw-heavy); + melodic_techno key mis-detected AND Gemini returned 0 structured cards there. +4. **Genre confirmation** — house/techno/melodic-techno/dnb/acid were chosen as + owner-plausible; confirm or swap. +5. **Branch convergence** — rebase `chore/phase2-surface-audit-and-claude-md` + (audit + Tier-1/2 prompt fixes) under this branch before further sub-goal-3 + prompt iteration. + +--- + +## Landed this session (autonomous + verified) + +**Sub-goal 2 — the scorer — is functionally complete and tested.** + +- `recommendation_evaluation.py` — source-agnostic scorer. Role/parameter/ + direction-band rubric, per-domain breakdown over the seven domains, device + equivalence classes (Compressor ↔ Glue Compressor earns credit), per-unit + value tolerance bands, and a chain-of-custody penalty that ports + `apps/ui/src/services/phase2Validator.ts` semantics + (`collect_phase1_field_paths`, `path_covers_tracked`). +- `scripts/evaluate_recommendations.py` — CLI runner with `--source + {baseline,gemini,deterministic}`, `--self-test`, `--report`, `--json`, + `--verification-artifact`. +- `scripts/emit_deterministic_recs.ts` — **deterministic-source bridge** (Node 23+ + native TS, no `npm install`): wraps the product's `abletonDevices.ts` and emits + the scorer's normalized rec shape. Single source of truth — no Python re-port. +- `aggregate_corpus_verification()` — per-domain match-rate + support artifact, the + data source the sub-goal 4 UI badge reads (degrades to confidence `NONE` with no + corpus evidence — the honest pre-render state). +- **Sub-goal 4 badge — BUILT** on the `ui/` Pill primitive and mounted on the + recommendation cards in `AnalysisResults.tsx`; verified by `npm run lint` + + `test:unit` (666) + `build` (smoke needs the live stack). Renders nothing while + the corpus is empty (graceful degradation); strengthens as renders land. Details + in the sub-goal 4 section below. +- `tests/test_recommendation_evaluation.py` — 29 tests, all green via + `python3.11 -m unittest tests.test_recommendation_evaluation`. The key gate + (`test_known_bad_rec_lowers_score`, `test_full_coverage_uncited_must_not_ + outscore_lower_coverage_cited`) proves the score moves correctly. + +### Provisional finding (deterministic vs baseline, pre-render) + +Running the deterministic bridge on a *synthetic* `AudioFeatures` for the house +fixture and scoring it: deterministic **raw aggregate 0.161** (covers bass + melody +device roles) vs baseline **0.000** — but the deterministic path emits **zero +citations**, so the chain-of-custody penalty drives its adjusted aggregate to +**0.000**. Two takeaways the harness surfaces immediately: +1. The free path recovers *some* device roles (it beats baseline on raw coverage) + but covers only the bands it maps — no kick/groove/stereo/master role + attribution (invariant #5 gap). +2. It emits no `phase1Fields`, so it fails the citation chain (PURPOSE.md invariant + #2). The rules **are** feature-triggered, so attaching the triggering measurement + as a citation is a concrete, harness-rewarded improvement — a candidate + sub-goal-3 "score-driven change" (frontend edit to `abletonDevices.ts` → + `npm run verify`; coordinate with the branch convergence below). + +This is the first real signal toward the Gemini verdict — likely Gemini earns its +place on citation + full-surface coverage. Confirm on real renders; the synthetic +`AudioFeatures` is illustrative, not a verdict. + +**Sub-goal 1 — corpus format + ingest — is complete except the renders.** + +- Manifest schema (`recommendation-fixture.v1`) + corpus README + authoring + checklist + `_TEMPLATE/`. +- Catalog-validity ingest (`validate_fixture_spec`) — runs now, gates every spec + against `prompts/live12_device_catalog.json`. +- **Five catalog-valid spec fixtures**, all covering the seven domains, in + owner-plausible electronic genres — meeting GOAL.md sub-goal 1's ≥5 *spec* target + (the renders are the remaining half): `house_sidechain_pluck_124` (house), + `techno_rumble_130` (techno), `melodic_techno_arp_124` (melodic techno), + `dnb_reese_174` (drum & bass), `acid_303_128` (acid — exercises `acidDetail`). + +--- + +## NEEDS-FIXTURE (blocks sub-goal 1 "done" and all of 3) + +The scorer cannot run on real recommendations until real audio exists, because +the recommendations themselves come from analyzing a real render. **This is the +hard human dependency** — the agent writes the spec, the owner builds and renders. + +### 1. Build + render the five authored fixtures +For each of `house_sidechain_pluck_124`, `techno_rumble_130`, +`melodic_techno_arp_124`, `dnb_reese_174`, `acid_303_128`: +- Build the `manifest.json → deviceSpec` **exactly** in Live 12. +- Set the project to **48 kHz / 24-bit**. +- Render the loop to `audio.flac` in the fixture dir (no export normalization). +- Store the fingerprint: + ```bash + ./venv/bin/python analyze.py \ + tests/fixtures/recommendation_tracks//audio.flac --yes \ + > tests/fixtures/recommendation_tracks//phase1_fingerprint.json + ``` +- Re-run `scripts/evaluate_recommendations.py --fixture --source baseline` + and confirm the no-fingerprint note is gone. + +### 2. Genre fit + held-out fixture +Five specs now exist (house, techno, melodic techno, drum & bass, acid). If any of +these are *not* genres you actually produce, say so and the agent will re-author +that spec in a genre you make — the spec-then-dial cost is on the agent, the render +on you. + +> Equivalence/overfitting note (GOAL.md sub-goal 3.3): hold out at least one +> fixture from any tuning loop so improvements reflect quality, not memorization. + +--- + +## Known limitation to revisit with real data + +**Domain attribution of instrument-processing effects.** The scorer attributes a +rec to the signal it shapes (`trackContext` wins), so a sidechain `Compressor` +labeled "Bass" scores under `bass`. A fixture spec that instead lists that effect +under `fx` will under-credit an otherwise-correct rec. Author specs so a device's +domain matches the trackContext a producer would give it, and tune the +`infer_domain` heuristics against actual Gemini/deterministic output in sub-goal 3 +— not blind, now. (Documented in `recommendation_evaluation.infer_domain`.) + +## NEEDS-WIRING — mostly closed + +### Deterministic source adapter (`--source deterministic`) — BUILT +The node bridge (`scripts/emit_deterministic_recs.ts`) is done and verified end to +end: it wraps the real `abletonDevices.ts` (single source of truth) and emits the +scorer's normalized rec shape; the runner reads +`recommendation_tracks//recommendations.deterministic.json` (or any +`--recommendations` JSON). Run it: +```bash +node apps/backend/scripts/emit_deterministic_recs.ts \ + > tests/fixtures/recommendation_tracks//recommendations.deterministic.json +``` +**Remaining (render-gated):** the bridge consumes an `AudioFeatures` object. Turning +a real Phase 1 fingerprint into `AudioFeatures` (spectral-band dominance, crest +factor, onset density) is the app's own projection (`analyzer.ts`); reuse it rather +than re-deriving, and only then is the deterministic score a real verdict input +rather than the synthetic illustration above. + +**FINDING — the deterministic source is currently dead code (affects sub-goal 3 +framing).** `apps/ui/src/data/abletonDevices.ts` is imported **nowhere** in the UI +(no component, no test) — verified by grep. ASA's product recommendations come +entirely from Gemini (`Phase2Result`); the deterministic engine is unwired, +ported-but-unused. Consequence: a "score-driven improvement" to `abletonDevices.ts` +(e.g. the citation-emit fix flagged above) would **not reach any user** — it would +raise a harness number for code nobody runs, which is harness-gaming, not a product +improvement (PURPOSE.md decision #5). So before sub-goal 3 treats the deterministic +path as a real recommendation source, decide one of: +1. **Wire `abletonDevices.ts` into the product** (so its recs — and any citation + improvement — actually reach users), then score + improve it; or +2. **Treat it as a research-only baseline** in the three-source comparison (score + it, but land score-driven *product* improvements on the **Gemini** path + instead — which needs the `chore/...` branch + renders). +This is the honest reason no score-driven improvement was "landed" this session: +the only render-free candidate would have improved dead code. + +--- + +## Sub-goal 3 — the Gemini verdict + +**Partial verdict LANDED on real data — see `RECOMMENDATION_VERDICT.md`.** Ran the +harness against live Gemini output on the owner's `VTSS – Can't Catch Me` track +(real Phase 1 → real Gemini Phase 2 via `server._run_interpretation_request`, +`gemini-2.5-flash`). Result on the answer-key-free axes: **Gemini 22/22 recs cited +and path-valid against the real fingerprint (custody penalty 1.000), full-surface +coverage; deterministic structurally 0 (uncited); baseline 0.** Gemini decisively +wins on chain-of-custody (#2) and coverage (#5). **Still owed:** the +known-settings axes (role recall / value accuracy) — those need rendered fixtures, +so the *complete* "does Gemini recover the actual settings?" verdict remains +render-gated. + +Mechanism is in place: `--source baseline|gemini|deterministic` on the same +corpus. To deliver the **full** verdict: +1. Render the fixtures (NEEDS-FIXTURE #1–2). +2. Wire the deterministic adapter (NEEDS-WIRING). +3. For each fixture, produce a live Gemini `phase2.json` (needs `GEMINI_API_KEY`; + **owner-discretion spend** per GOAL.md rule 4) and drop it in the fixture dir. +4. Run all three sources, diff per-domain + aggregate, write the finding: + *does Gemini raise the score, on which domains, by how much?* Feed a surprising + answer back into `PURPOSE.md` / the `asa-next-work-priorities` memory. + +**Branch convergence needed for 3.2:** GOAL.md references +`audits/phase2-recommendation-surface-2026-05-24.md` for the Tier-2/3 backlog. That +audit — **and the Tier-1/2 phase2 prompt/catalog fixes it drove** (commits +`bd975ab0`, `dc8daa02`) — live on branch `chore/phase2-surface-audit-and-claude-md`, +which is **not** an ancestor of this campaign branch (`worktree-goal-doc`) and not +yet on `main`. Before working sub-goal 3, rebase/merge so the campaign sits on top +of that phase2 work (otherwise you'd iterate against a stale prompt and miss the +audit's backlog). Confirm with `git log --oneline | grep -E 'bd975ab0|dc8daa02'`. + +--- + +## Sub-goal 4 — surface the proof in the UI — BUILT (content render-gated) + +**Data source — BUILT.** `aggregate_corpus_verification()` emits the per-domain +match-rate + support + confidence-band artifact (via `--verification-artifact`). +Confidence band: support `<3` → LOW (hedged), `<6` → MED, else HIGH — invariant +#4's "low support never earns a confident badge", made mechanical. + +**Badge — BUILT + verified.** Shipped on the `ui/` Pill primitive: +- `apps/ui/src/data/recommendationVerification.ts` — typed artifact (all-`NONE` + pre-render; regenerate from the backend runner — see header comment). +- `apps/ui/src/services/recommendationVerification.ts` — domain inference + (mirrors backend `infer_domain`) + lookup; node-testable. +- `apps/ui/src/components/RecommendationVerificationBadge.tsx` — renders the band + per rec, or **nothing** when confidence is `NONE` (graceful degradation, the + current pre-render state). +- Mounted in `AnalysisResults.tsx` on both the mix-chain cards and the patch + cards (per-rec). +- `apps/ui/tests/services/recommendationVerification.test.ts` — 8 tests. +- **Verified:** `npm run lint` (tsc) ✓, `npm run test:unit` (666) ✓, `npm run build` ✓. + +**Remaining:** +1. `npm run test:smoke` (the 4th `verify` step) needs the live stack (backend on + 8100 + UI on 3100) — not bootable in this worktree; run it where the stack is up. +2. Badges stay invisible (all-`NONE`) until real renders produce a scored corpus + and you regenerate `recommendationVerification.ts`. The wiring is proven by a + unit test that injects a populated artifact and asserts the `HIGH` band surfaces. +3. Optional: extend to `secretSauce.workflowSteps` cards (same one-line pattern). + +Artifact shape (`--verification-artifact`), self-contained for the frontend: + +```json +{ + "fixtures": 0, + "sources": [], + "perDomain": { + "kick": { "support": 0, "meanRecall": 0.0, "meanScore": 0.0, "confidence": "NONE" }, + "bass": { "support": 0, "meanRecall": 0.0, "meanScore": 0.0, "confidence": "NONE" } + // ...one entry per domain: kick, bass, melody, groove, fx, stereo, master + } +} +``` + +`confidence` band from `support` (number of scored fixtures specifying the domain): +`0` → `NONE`, `<3` → `LOW` (hedged badge), `<6` → `MED`, else `HIGH`. The badge maps +a card's domain (via the `infer_domain` reading) to `perDomain[domain]` and renders +the band; `NONE`/`LOW` must never render as a confident badge (invariant #4). + +--- + +## How to re-enter this campaign + +```bash +# Confirm the harness is green (no venv needed — pure stdlib): +cd apps/backend && python3.11 -m unittest tests.test_recommendation_evaluation +python3.11 scripts/evaluate_recommendations.py --self-test +# Deterministic source (Node 23+, no npm install needed): +node scripts/emit_deterministic_recs.ts > /tmp/det.json +python3.11 scripts/evaluate_recommendations.py --fixture \ + --source deterministic --recommendations /tmp/det.json +# Full picture once a render exists: +python3.11 scripts/evaluate_recommendations.py --source gemini \ + --fixture --phase2 --report /tmp/rec_eval.md \ + --verification-artifact /tmp/verification.json +``` diff --git a/apps/backend/RECOMMENDATION_VERDICT.md b/apps/backend/RECOMMENDATION_VERDICT.md new file mode 100644 index 00000000..20d758c1 --- /dev/null +++ b/apps/backend/RECOMMENDATION_VERDICT.md @@ -0,0 +1,85 @@ +# Recommendation Verdict (GOAL.md sub-goal 3) + +Does Gemini interpretation beat the deterministic rules? **Yes — decisively, and +specifically on the chain-of-custody invariant.** Numbers below. Research note. + +> ⚠️ **SYNTHETIC-PROXY CORPUS.** The 5 fixtures were scored against **numpy proxy +> renders** (`synth_fixtures.py`), NOT Ableton renders, because the owner directed +> "continue without input." The proxies realize each spec's *acoustic intent* +> (tempo, kick fundamental, brightness, sidechain) closely enough for Phase 1 to +> measure plausibly, but they are not Ableton device timbres. **Re-run on real Live +> renders for an authoritative known-settings verdict.** See "Where real input is +> needed" at the bottom and `NEEDS.md`. + +## Method +Per fixture: proxy render → `analyze.py` (real Phase 1) → three recommendation +sources scored by `recommendation_evaluation.score_recommendations`: +- **deterministic** — `abletonDevices.ts` via the node bridge (`emit_deterministic_recs.ts`), fed an `AudioFeatures` projection of the fingerprint. +- **gemini** — live `gemini-2.5-flash` via the exact server path (`server._run_interpretation_request`), key from `VITE_GEMINI_API_KEY`. +- **baseline** — empty (the floor). + +## Verdict — corpus aggregate (mean over 5 proxy fixtures) + +| Source | Aggregate | Raw (pre-custody) | Custody penalty | +|---|---|---|---| +| **Gemini** | **0.227** | 0.227 | **1.000** | +| Deterministic | **0.000** | 0.112 | **0.000** | +| Baseline | 0.000 | 0.000 | 1.000 | + +**The decisive factor is chain-of-custody, not raw coverage.** The deterministic +path's *raw* device-role coverage (0.112) is in the same range as Gemini's, and it +actually beats Gemini on bass role-recall (1.00 vs 0.20). But it emits **zero +citations**, so the custody penalty (PURPOSE.md invariant #2) drives its aggregate +to 0. Gemini cites every recommendation against a real measurement, so it keeps its +score. **Gemini earns its place on the citation chain + measurement grounding — +exactly the two properties PURPOSE.md calls the product.** + +Per-fixture Gemini aggregate: house 0.343, dnb 0.335, techno 0.287, acid 0.172, +melodic_techno **0.000** (Gemini returned 0 structured cards for this one — a parse/ +shape outlier worth investigating). + +### Per-domain role recall (gemini / deterministic) +`kick 0.00/0.00 · bass 0.20/1.00 · melody 0.60/0.20 · groove 0.00/0.00 · fx 0.00/0.00 · stereo 0.00/0.00 · master 0.50/0.50` + +**Key finding — source-instrument recall is partly unrecoverable from audio.** +`kick = 0.00` for *both* sources: Gemini's kick-domain cards are `EQ Eight` + +`Saturator` (how to **process** the kick), while the spec lists `Operator` (the +**source** synth). Reverse-engineering a finished render, Gemini recommends +processing — and a synth kick vs a sampled kick *measure identically*, so naming the +source instrument from audio is impossible in principle. This is a real limit on the +"recover the literal device" axis and motivated the improvement below. + +## Score-driven improvement landed (with evidence) + +The scorer was **ignoring `measurableIntent`** even though GOAL.md says "the key +stores measurable intent beside the literal spec, so equivalent routes earn credit." +Implemented that mechanism (`intent_coverage` + a 0.25-weighted blend): a rec that +cites the measurements the spec deemed essential earns credit even when it names a +different (or processing-not-source) device. + +| | Before | After | +|---|---|---| +| Gemini aggregate | 0.141 | **0.227** (+0.086) | +| Deterministic aggregate | 0.000 | 0.000 (unchanged — uncited, earns no intent credit) | + +The improvement rewards measurement-grounded recommendations and is provably +useless to a source that doesn't cite — a faithful, non-gameable implementation of +the equivalence caveat. Covered by `tests/test_recommendation_evaluation.py::IntentCoverageTests`. + +## Real-track cross-check (no synthesis) + +On the owner's real `VTSS – Can't Catch Me` track (real Phase 1 → real Gemini), +answer-key-free axes only (no known settings for a commercial track): Gemini **22/22 +recs cited and path-valid** against the real fingerprint (custody 1.000), full-surface +coverage. Consistent with the corpus verdict — Gemini's custody advantage is real, +not a synthesis artifact. + +## Where real input is needed (retroactive) +1. **Real Ableton renders** of the 5 specs (48 kHz/24-bit) replace the proxies → + makes the known-settings axes (role recall, value accuracy) authoritative. The + proxies have artifacts: dnb BPM read half-time (174→116), `acidDetail` fires on + all (synth is saw-heavy), melodic_techno key mis-detected. +2. **`melodic_techno_arp_124` Gemini 0 recs** — investigate the parse/shape outlier + on a real render before trusting that fixture's contribution. +3. The deterministic `AudioFeatures` projection is approximate (not the app's + `analyzer.ts`); reconcile when wiring the deterministic path for real. diff --git a/apps/backend/recommendation_evaluation.py b/apps/backend/recommendation_evaluation.py new file mode 100644 index 00000000..1a643525 --- /dev/null +++ b/apps/backend/recommendation_evaluation.py @@ -0,0 +1,1206 @@ +"""Deterministic scorer for ASA Phase 2 recommendation quality. + +EVAL / RESEARCH ONLY. This module scores how well a set of recommendations +recovers the *known* device settings that produced a ground-truth render. It is +the harness core of the recommendation-proof campaign (see ``GOAL.md`` sub-goal +2). It MUST NOT be imported by ``analyze.py`` or ``server.py`` — ASA recommends +Ableton devices, it does not score itself on the product path. Deleting this +module (and ``scripts/evaluate_recommendations.py``) restores the product +exactly, mirroring the other ``*_evaluation.py`` harnesses. + +The design follows the GOAL.md "key insight": a human authors a Live 12 project +with known device settings, renders it, ASA analyzes the render, and this scorer +checks whether the recommendations recovered the settings. The answer key is the +fixture manifest (``deviceSpec`` + ``measurableIntent``), authored once per +track. + +Scoring is **source-agnostic**: it consumes a list of :class:`NormalizedRec` +(produced by an adapter from any recommendation source — Gemini Phase 2, the +deterministic ``abletonDevices.ts`` path, or a trivial baseline) plus a +:class:`Fixture`. This is what lets sub-goal 3 score three sources on the same +corpus. + +Equivalence caveat (GOAL.md): a track has many valid reconstructions. Scoring is +therefore at the level of **device role/family -> parameter -> value direction & +magnitude band**, never byte-exact strings. ``Compressor`` and +``Glue Compressor`` both satisfy a "compression" ground-truth role because they +share an equivalence class (see :data:`DEVICE_EQUIVALENCE`). +""" + +from __future__ import annotations + +import json +import math +import re +import sys +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Iterable, Mapping, Sequence + +SCHEMA_VERSION = "recommendation-fixture.v1" + +# --------------------------------------------------------------------------- +# Canonical production domains (PURPOSE.md invariant #5 — reconstruction must +# cover the full surface). Every recommendation and every ground-truth device +# chain is bucketed into exactly one of these. +# --------------------------------------------------------------------------- + +DOMAINS: tuple[str, ...] = ( + "kick", + "bass", + "melody", + "groove", + "fx", + "stereo", + "master", +) + +UNKNOWN_DOMAIN = "unknown" + + +# --------------------------------------------------------------------------- +# Device catalog (the same contract Phase 2 device names are validated against). +# --------------------------------------------------------------------------- + +_DEFAULT_CATALOG_PATH = Path(__file__).resolve().parent / "prompts" / "live12_device_catalog.json" + + +@dataclass(frozen=True) +class CatalogDevice: + name: str + family: str + cls: str + allowed_parameters: frozenset[str] + parameter_aliases: Mapping[str, str] + + def canonical_parameter(self, name: str) -> str | None: + """Resolve ``name`` to a catalog parameter, honoring aliases. + + Returns the canonical parameter name if it (or an alias of it) is + allowed on this device, else ``None``. + """ + if name in self.allowed_parameters: + return name + alias_target = self.parameter_aliases.get(name) + if alias_target and alias_target in self.allowed_parameters: + return alias_target + return None + + +class Catalog: + """In-memory view of ``live12_device_catalog.json`` for validation/scoring.""" + + def __init__(self, devices: Iterable[CatalogDevice]): + self._by_name = {d.name: d for d in devices} + + @classmethod + def load(cls, path: Path | str | None = None) -> "Catalog": + catalog_path = Path(path) if path is not None else _DEFAULT_CATALOG_PATH + raw = json.loads(catalog_path.read_text(encoding="utf-8")) + devices = [] + for entry in raw.get("devices", []): + devices.append( + CatalogDevice( + name=entry["name"], + family=entry.get("family", "NATIVE"), + cls=entry.get("class", ""), + allowed_parameters=frozenset(entry.get("allowedParameters", [])), + parameter_aliases=dict(entry.get("parameterAliases", {})), + ) + ) + return cls(devices) + + def get(self, name: str) -> CatalogDevice | None: + return self._by_name.get(name) + + def __contains__(self, name: str) -> bool: + return name in self._by_name + + def names(self) -> frozenset[str]: + return frozenset(self._by_name) + + +# --------------------------------------------------------------------------- +# Device equivalence classes — the heart of the "equivalent route earns credit" +# rule. Two devices match at role/family level iff they share a class. Keyed by +# the exact catalog name. Devices absent here only match themselves exactly. +# --------------------------------------------------------------------------- + +DEVICE_EQUIVALENCE: dict[str, str] = { + # Virtual-analog / subtractive / FM synths — interchangeable for most + # kick/bass/lead tone roles. + "Operator": "va_synth", + "Analog": "va_synth", + "Wavetable": "va_synth", + "Drift": "va_synth", + "Meld": "va_synth", + "Bass": "va_synth", + # Samplers / drum instruments. + "Sampler": "sampler", + "Simpler": "sampler", + "Drum Rack": "sampler", + "Impulse": "sampler", + # Physical modeling. + "Collision": "physical_model", + "Tension": "physical_model", + "Electric": "physical_model", + "Granulator III": "granular", + # EQ family. + "EQ Eight": "eq", + "EQ Three": "eq", + "Channel EQ": "eq", + # Compression family. + "Compressor": "compressor", + "Glue Compressor": "compressor", + "Multiband Dynamics": "compressor", + # Limiting family. + "Limiter": "limiter", + "Color Limiter": "limiter", + # Saturation / drive family. + "Saturator": "saturation", + "Dynamic Tube": "saturation", + "Amp": "saturation", + "Cabinet": "saturation", + "Drum Buss": "saturation", + # Reverb family. + "Reverb": "reverb", + "Hybrid Reverb": "reverb", + "Corpus": "reverb", + # Delay family. + "Delay": "delay", + "Echo": "delay", + "Filter Delay": "delay", + "Gated Delay": "delay", + # Modulation family. + "Chorus-Ensemble": "modulation", + "Flanger": "modulation", + "Phaser-Flanger": "modulation", + "Auto Pan-Tremolo": "modulation", + "Frequency Shifter": "modulation", + # Filter / movement. + "Auto Filter": "filter", + # Gate. + "Gate": "gate", + # Stereo / utility. + "Utility": "stereo_util", + # Pitch fx. + "Auto Shift": "pitch_fx", + "Spectral Resonator": "pitch_fx", + # Glitch. + "Beat Repeat": "glitch", + "Erosion": "glitch", + # MIDI. + "Arpeggiator": "arp", + "Chord": "midi_util", + "Scale": "midi_util", + "Note Length": "midi_util", + "Pitch": "midi_util", + "Random": "midi_util", + "Velocity": "midi_util", + "Note Echo": "midi_util", + "LFO": "modulator", + "Shaper": "modulator", + "Envelope Follower": "modulator", +} + + +def equivalence_class(device: str) -> str: + """Return a device's equivalence class, or the device name itself if absent.""" + return DEVICE_EQUIVALENCE.get(device, device) + + +def devices_match(recommended: str, ground_truth: str) -> bool: + """True if a recommended device satisfies a ground-truth device role. + + Exact name match always wins; otherwise they must share an equivalence + class. This is what credits ``Glue Compressor`` for a ``Compressor`` spec. + """ + if recommended == ground_truth: + return True + return equivalence_class(recommended) == equivalence_class(ground_truth) + + +# --------------------------------------------------------------------------- +# Value parsing + per-unit tolerance bands. +# --------------------------------------------------------------------------- + + +@dataclass(frozen=True) +class ParsedValue: + """A numeric magnitude extracted from a free-text value string.""" + + number: float + unit: str # normalized: "hz", "db", "ms", "s", "ratio", "pct", "st", "" + + @property + def hz(self) -> float | None: + if self.unit == "hz": + return self.number + return None + + +# Per-unit tolerance bands and the neutral default used for direction scoring. +# tolerance is absolute in the unit unless `rel` is set (fraction of target). +@dataclass(frozen=True) +class UnitBand: + abs_tol: float | None + rel_tol: float | None + neutral: float + + +UNIT_BANDS: dict[str, UnitBand] = { + "hz": UnitBand(abs_tol=None, rel_tol=0.20, neutral=1000.0), # ±20% + "db": UnitBand(abs_tol=3.0, rel_tol=None, neutral=0.0), # ±3 dB + "ms": UnitBand(abs_tol=None, rel_tol=0.30, neutral=20.0), # ±30% + "s": UnitBand(abs_tol=None, rel_tol=0.30, neutral=1.0), # ±30% + "ratio": UnitBand(abs_tol=1.0, rel_tol=None, neutral=1.0), # ±1:1 + "pct": UnitBand(abs_tol=15.0, rel_tol=None, neutral=50.0), # ±15% + "st": UnitBand(abs_tol=1.0, rel_tol=None, neutral=0.0), # ±1 semitone + "": UnitBand(abs_tol=None, rel_tol=0.20, neutral=0.0), # unitless: ±20% +} + + +# Longer unit tokens must precede their prefixes in the alternation (`st` before +# `s`, `sec`/`semitones` before `s`, `ms` before `s`) so regex first-match wins +# on the intended unit. +_VALUE_RE = re.compile( + r"(-?\d+(?:\.\d+)?)\s*" + r"(k?hz|db|ms|sec|semitones?|st|s|%|:1|x)?", + re.IGNORECASE, +) + + +def parse_value(text: str | float | int | None) -> ParsedValue | None: + """Extract a numeric magnitude + normalized unit from a value string. + + Handles ``"4 kHz"``, ``"-15 dB"``, ``"200 ms"``, ``"3:1"``, ``"30%"``, + ``"0.6"``, ``"+12st"``. Returns ``None`` for non-numeric values (e.g. + ``"Sine"``, ``"Auto"``) — those are scored on parameter coverage only. + """ + if text is None: + return None + if isinstance(text, (int, float)): + if not math.isfinite(float(text)): + return None + return ParsedValue(number=float(text), unit="") + s = str(text).strip() + if not s: + return None + # Ratio form "3:1" -> 3.0 ratio. + ratio_match = re.search(r"(-?\d+(?:\.\d+)?)\s*:\s*1\b", s) + if ratio_match: + return ParsedValue(number=float(ratio_match.group(1)), unit="ratio") + match = _VALUE_RE.search(s) + if not match: + return None + number = float(match.group(1)) + raw_unit = (match.group(2) or "").lower() + unit = _normalize_unit(raw_unit) + if unit == "hz" and raw_unit.startswith("k"): + number *= 1000.0 + return ParsedValue(number=number, unit=unit) + + +def _normalize_unit(raw: str) -> str: + if raw in ("khz", "hz"): + return "hz" + if raw == "db": + return "db" + if raw == "ms": + return "ms" + if raw in ("s", "sec"): + return "s" + if raw == "%": + return "pct" + if raw in ("st", "semitone", "semitones"): + return "st" + if raw in (":1", "x"): + return "ratio" + return "" + + +def score_value(recommended: ParsedValue | None, target: ParsedValue | None) -> float: + """Score a recommended value against the ground-truth target in [0, 1]. + + - 1.0 within the per-unit tolerance band + - 0.5 outside the band but on the correct side of the neutral default + (right *direction* — e.g. both are boosts, or both are short) + - 0.0 wrong direction, or either value is non-numeric / unit-mismatched + + Direction matters because GOAL.md scores "value in the right direction and + magnitude band". A rec that says "boost" when the truth is "cut" is wrong + even if the magnitude is close. + """ + if recommended is None or target is None: + return 0.0 + # Unit mismatch (e.g. comparing Hz to dB) is not comparable. + if recommended.unit != target.unit: + return 0.0 + band = UNIT_BANDS.get(target.unit, UNIT_BANDS[""]) + if band.abs_tol is not None: + tol = band.abs_tol + else: + tol = abs(target.number) * (band.rel_tol or 0.0) + if abs(recommended.number - target.number) <= tol + 1e-9: + return 1.0 + # Direction relative to neutral default. + rec_side = recommended.number - band.neutral + tgt_side = target.number - band.neutral + if rec_side == 0 or tgt_side == 0: + return 0.0 + return 0.5 if (rec_side > 0) == (tgt_side > 0) else 0.0 + + +# --------------------------------------------------------------------------- +# Fixture (answer key) model. +# --------------------------------------------------------------------------- + + +@dataclass(frozen=True) +class SpecParameter: + name: str + value: str + intent: str | None = None + + @property + def parsed(self) -> ParsedValue | None: + return parse_value(self.value) + + +@dataclass(frozen=True) +class SpecDevice: + device: str + family: str | None + parameters: tuple[SpecParameter, ...] + role: str | None = None + + +@dataclass(frozen=True) +class IntentTarget: + """A measurable-intent entry: a Phase 1 path with a target range. + + Mirrors the threshold idiom in ``phase1_eval_manifest.json`` + (``{target, tolerance}``) plus an optional direction. + """ + + path: str + target: float | str | bool + tolerance: float | None = None + direction: str | None = None # "min" | "max" | "exact" | None + unit: str | None = None + + +@dataclass(frozen=True) +class Fixture: + slug: str + title: str + genre: str + audio_path: str | None + device_spec: Mapping[str, tuple[SpecDevice, ...]] # domain -> ordered chain + measurable_intent: tuple[IntentTarget, ...] + phase1_fingerprint: Mapping[str, Any] | None + render: Mapping[str, Any] + source_path: Path | None = None + + def domains_with_spec(self) -> tuple[str, ...]: + return tuple(d for d in DOMAINS if self.device_spec.get(d)) + + +def load_fixture(manifest_path: Path | str) -> Fixture: + """Parse a ``manifest.json`` into a :class:`Fixture`. + + The optional Phase 1 fingerprint is loaded from an embedded + ``phase1Fingerprint`` object or, if a ``phase1FingerprintPath`` is given and + the file exists, from that sibling file. A missing fingerprint is allowed — + scoring degrades gracefully (the citation path-validity sub-check SKIPs, the + same way the transcription harness SKIPs missing audio). + """ + path = Path(manifest_path) + raw = json.loads(path.read_text(encoding="utf-8")) + + version = raw.get("schemaVersion") + if version != SCHEMA_VERSION: + # Soft-warn (eval tooling, never fail ingest on a version skew) so a + # future schema bump is visible rather than silently mis-parsed. + print( + f"[warn] {path}: schemaVersion {version!r} != expected {SCHEMA_VERSION!r}", + file=sys.stderr, + ) + + device_spec: dict[str, tuple[SpecDevice, ...]] = {} + for domain, chain in (raw.get("deviceSpec") or {}).items(): + devices = [] + for dev in chain: + params = tuple( + SpecParameter( + name=p["name"], + value=str(p.get("value", "")), + intent=p.get("intent"), + ) + for p in dev.get("parameters", []) + ) + devices.append( + SpecDevice( + device=dev["device"], + family=dev.get("family"), + parameters=params, + role=dev.get("role"), + ) + ) + device_spec[domain] = tuple(devices) + + intents = [] + for path_key, spec in (raw.get("measurableIntent") or {}).items(): + if isinstance(spec, Mapping): + target = spec.get("target", spec.get("equals")) + intents.append( + IntentTarget( + path=path_key, + target=target, + tolerance=spec.get("tolerance"), + direction=spec.get("direction"), + unit=spec.get("unit"), + ) + ) + + fingerprint = raw.get("phase1Fingerprint") + fp_path = raw.get("phase1FingerprintPath") + if fingerprint is None and fp_path: + candidate = path.parent / fp_path + if candidate.exists(): + fingerprint = json.loads(candidate.read_text(encoding="utf-8")) + + return Fixture( + slug=raw.get("id", path.parent.name), + title=raw.get("title", ""), + genre=raw.get("genre", ""), + audio_path=raw.get("audioPath"), + device_spec=device_spec, + measurable_intent=tuple(intents), + phase1_fingerprint=fingerprint, + render=raw.get("render", {}), + source_path=path, + ) + + +# --------------------------------------------------------------------------- +# Normalized recommendation model + adapters (source-agnostic seam). +# --------------------------------------------------------------------------- + + +@dataclass(frozen=True) +class NormalizedRec: + """A single recommendation reduced to the fields the scorer needs. + + Adapters map each source's native shape onto this. The scorer never sees a + source-specific type, which is what makes "deterministic vs Gemini vs + baseline" a one-line swap (GOAL.md sub-goal 3). + """ + + domain: str + device: str + parameter: str | None = None + value: str | None = None + citations: tuple[str, ...] = () + family: str | None = None + + +# Keyword -> domain inference for free-text track-context strings. +_DOMAIN_KEYWORDS: tuple[tuple[str, str], ...] = ( + ("kick", "kick"), + ("sub bass", "bass"), + ("bassline", "bass"), + ("bass", "bass"), + ("808", "bass"), + ("lead", "melody"), + ("melod", "melody"), + ("arp", "melody"), + ("pluck", "melody"), + ("chord", "melody"), + ("pad", "melody"), + ("synth", "melody"), + ("harmon", "melody"), + ("hat", "groove"), + ("hi-hat", "groove"), + ("hihat", "groove"), + ("perc", "groove"), + ("snare", "groove"), + ("clap", "groove"), + ("drum", "groove"), + ("groove", "groove"), + ("width", "stereo"), + ("stereo", "stereo"), + ("pan", "stereo"), + ("imaging", "stereo"), + ("master", "master"), + ("mix bus", "master"), +) + +# Recommendation category (Phase2 enum) -> domain, when track-context is silent. +_CATEGORY_DOMAIN: dict[str, str] = { + "STEREO": "stereo", + "MASTERING": "master", + "MIDI": "groove", +} + + +def infer_domain(track_context: str | None, category: str | None) -> str: + """Best-effort production-domain inference for a recommendation. + + Track context wins (it is specific — "Kick bus", "Bass", "Master"), then + category. Falls back to :data:`UNKNOWN_DOMAIN` so the scorer can count + unattributable recs as precision noise rather than silently dropping them. + + Domain reading (chosen deliberately): a device is attributed to **the signal + it shapes**, matching how producers speak — "the bass is sidechained" puts a + sidechain Compressor on the bass under ``bass``, not ``fx``. ``fx`` is for + effect/texture devices a rec does not tie to a single instrument. + + KNOWN LIMITATION (revisit with real renders, see NEEDS.md): a fixture spec + may list an instrument-processing effect under ``fx`` while a rec naming the + processed instrument (``trackContext: "Bass"``) scores under ``bass`` — a + cross-domain attribution mismatch that can under-credit otherwise-correct + recs. Author fixtures so a device's spec domain matches the trackContext a + producer would give it, and resolve the inference heuristics against actual + Gemini/deterministic output in sub-goal 3 rather than tuning them blind now. + """ + if track_context: + low = track_context.lower() + for keyword, domain in _DOMAIN_KEYWORDS: + if keyword in low: + return domain + if category: + mapped = _CATEGORY_DOMAIN.get(category.upper()) + if mapped: + return mapped + return UNKNOWN_DOMAIN + + +def normalize_phase2(phase2: Mapping[str, Any]) -> list[NormalizedRec]: + """Adapter: ``Phase2Result`` JSON -> normalized recs. + + Pulls from the two structured buckets the citation contract covers: + ``abletonRecommendations`` (carry ``category`` + ``trackContext``) and + ``mixAndMasterChain`` (the mastering pipeline; domain defaults to master + unless track-context says otherwise). ``sonicElements`` are free prose, not + device cards, so they are intentionally not scored here. + """ + recs: list[NormalizedRec] = [] + for item in phase2.get("abletonRecommendations") or []: + recs.append( + NormalizedRec( + domain=infer_domain(item.get("trackContext"), item.get("category")), + device=item.get("device", ""), + parameter=item.get("parameter"), + value=_stringify(item.get("value")), + citations=_citations(item.get("phase1Fields")), + family=item.get("deviceFamily"), + ) + ) + for item in phase2.get("mixAndMasterChain") or []: + domain = infer_domain(item.get("trackContext"), "MASTERING") + recs.append( + NormalizedRec( + domain=domain, + device=item.get("device", ""), + parameter=item.get("parameter"), + value=_stringify(item.get("value")), + citations=_citations(item.get("phase1Fields")), + family=item.get("deviceFamily"), + ) + ) + return recs + + +def normalize_baseline(_fixture: Fixture) -> list[NormalizedRec]: + """Adapter: trivial baseline source — emits nothing. + + GOAL.md sub-goal 3 needs a no-op baseline as the floor of the three-source + comparison. An empty rec set scores ~0 on coverage; any real source must + clear it to justify its existence. + """ + return [] + + +def _stringify(value: Any) -> str | None: + if value is None: + return None + return str(value) + + +def _citations(raw: Any) -> tuple[str, ...]: + if not isinstance(raw, list): + return () + out = [] + for entry in raw: + if isinstance(entry, str) and entry.strip(): + out.append(entry.strip()) + return tuple(out) + + +# --------------------------------------------------------------------------- +# Chain-of-custody penalty — Python port of the phase2Validator.ts semantics so +# the harness and the runtime guardrail share one definition of "broke the +# chain". Keep in sync with apps/ui/src/services/phase2Validator.ts. +# --------------------------------------------------------------------------- + + +def collect_phase1_field_paths(phase1: Mapping[str, Any]) -> set[str]: + """Every dotted path that resolves to a non-null value in a Phase 1 payload. + + Mirrors ``collectPhase1FieldPaths`` in phase2Validator.ts: both intermediate + keys and leaf scalars are included, and for arrays of objects the + ``path.field`` shapes are surfaced so a citation can name an array item's + field without indexing. + """ + paths: set[str] = set() + _walk_paths(phase1, "", paths) + return paths + + +def _walk_paths(value: Any, prefix: str, paths: set[str]) -> None: + if value is None: + return + if isinstance(value, list): + if prefix: + paths.add(prefix) + for item in value: + if isinstance(item, Mapping): + for key in item: + sub = f"{prefix}.{key}" if prefix else key + _walk_paths(item[key], sub, paths) + return + if not isinstance(value, Mapping): + if prefix: + paths.add(prefix) + return + if prefix: + paths.add(prefix) + for key in value: + sub = f"{prefix}.{key}" if prefix else key + _walk_paths(value[key], sub, paths) + + +def path_covers_tracked(citation: str, tracked: str) -> bool: + """Bidirectional + wildcard path match. Port of ``pathCoversTracked``.""" + if citation == tracked: + return True + if citation.startswith(f"{tracked}."): + return True + if tracked.startswith(f"{citation}."): + return True + if "*" not in citation and "*" not in tracked: + return False + cs = citation.split(".") + ts = tracked.split(".") + if len(ts) <= len(cs): + if all(ts[i] == cs[i] or ts[i] == "*" or cs[i] == "*" for i in range(len(ts))): + return True + if len(cs) <= len(ts): + if all(cs[i] == ts[i] or cs[i] == "*" or ts[i] == "*" for i in range(len(cs))): + return True + return False + + +@dataclass +class CustodyResult: + total_recs: int + cited_recs: int # recs with >= 1 non-empty citation + valid_path_recs: int # recs whose citations all resolve in the fingerprint + path_check_ran: bool # False when no fingerprint is available (SKIP) + penalty: float # multiplier in [0, 1] applied to the raw score + + @property + def presence_rate(self) -> float: + return self.cited_recs / self.total_recs if self.total_recs else 1.0 + + +def evaluate_custody( + recs: Sequence[NormalizedRec], + fingerprint: Mapping[str, Any] | None, +) -> CustodyResult: + """Chain-of-custody assessment over a rec set. + + Two sub-checks, mirroring phase2Validator.ts: + 1. Presence — every rec must carry >= 1 citation (always checkable). + 2. Path validity — every citation must resolve to a path present in the + Phase 1 fingerprint (only runs when a fingerprint is available; SKIPs + cleanly otherwise, like the transcription harness SKIPs missing audio). + + The penalty is the mean of the checkable rates. A high-coverage rec set that + breaks the chain must not outscore a cited one (GOAL.md sub-goal 2.d), so + the penalty multiplies the raw score downstream. + """ + total = len(recs) + if total == 0: + return CustodyResult(0, 0, 0, fingerprint is not None, 1.0) + + cited = 0 + valid_path = 0 + allowed = collect_phase1_field_paths(fingerprint) if fingerprint else set() + path_check_ran = bool(fingerprint) + + for rec in recs: + has_citation = len(rec.citations) > 0 + if has_citation: + cited += 1 + if path_check_ran and has_citation: + if all( + any(path_covers_tracked(c, t) or path_covers_tracked(t, c) for t in allowed) + for c in rec.citations + ): + valid_path += 1 + + presence_rate = cited / total + if path_check_ran: + # Path validity is conditioned on citations existing; combine presence + # with the share of cited recs whose paths are valid. + path_rate = (valid_path / cited) if cited else 0.0 + penalty = (presence_rate + path_rate) / 2.0 + else: + penalty = presence_rate + + return CustodyResult( + total_recs=total, + cited_recs=cited, + valid_path_recs=valid_path, + path_check_ran=path_check_ran, + penalty=penalty, + ) + + +# --------------------------------------------------------------------------- +# Scoring. +# --------------------------------------------------------------------------- + + +@dataclass +class DomainScore: + domain: str + truth_device_count: int + rec_device_count: int + matched_devices: int # ground-truth devices covered by >=1 rec + role_recall: float + role_precision: float + parameter_coverage: float + value_accuracy: float + score: float # blended per-domain score in [0, 1] + + def as_dict(self) -> dict[str, Any]: + return { + "domain": self.domain, + "truthDeviceCount": self.truth_device_count, + "recDeviceCount": self.rec_device_count, + "matchedDevices": self.matched_devices, + "roleRecall": round(self.role_recall, 4), + "rolePrecision": round(self.role_precision, 4), + "parameterCoverage": round(self.parameter_coverage, 4), + "valueAccuracy": round(self.value_accuracy, 4), + "score": round(self.score, 4), + } + + +@dataclass +class RecommendationScore: + fixture_slug: str + source: str + domain_scores: dict[str, DomainScore] + custody: CustodyResult + intent_coverage: float # fraction of measurableIntent paths a rec cites + raw_aggregate: float # blend of domain scores + intent coverage (pre-penalty) + aggregate: float # raw_aggregate * custody.penalty + + def as_dict(self) -> dict[str, Any]: + return { + "fixture": self.fixture_slug, + "source": self.source, + "aggregate": round(self.aggregate, 4), + "rawAggregate": round(self.raw_aggregate, 4), + "intentCoverage": round(self.intent_coverage, 4), + "custody": { + "totalRecs": self.custody.total_recs, + "citedRecs": self.custody.cited_recs, + "validPathRecs": self.custody.valid_path_recs, + "pathCheckRan": self.custody.path_check_ran, + "penalty": round(self.custody.penalty, 4), + }, + "domains": {d: s.as_dict() for d, s in self.domain_scores.items()}, + } + + +# Relative weights for the per-domain blend. Role recall is the spine of +# reconstruction completeness (invariant #5); parameter/value sharpen it. +_WEIGHT_RECALL = 0.45 +_WEIGHT_PRECISION = 0.15 +_WEIGHT_PARAM = 0.20 +_WEIGHT_VALUE = 0.20 + + +def _score_one_domain( + domain: str, + truth_chain: Sequence[SpecDevice], + domain_recs: Sequence[NormalizedRec], +) -> DomainScore: + truth_count = len(truth_chain) + rec_count = len(domain_recs) + + # Role recall: ground-truth devices covered by at least one rec. + matched_truth = 0 + matched_truth_devices: list[tuple[SpecDevice, list[NormalizedRec]]] = [] + for truth_dev in truth_chain: + covering = [r for r in domain_recs if devices_match(r.device, truth_dev.device)] + if covering: + matched_truth += 1 + matched_truth_devices.append((truth_dev, covering)) + role_recall = matched_truth / truth_count if truth_count else 0.0 + + # Role precision: recs that map onto some ground-truth device. + matched_recs = sum( + 1 + for r in domain_recs + if any(devices_match(r.device, t.device) for t in truth_chain) + ) + role_precision = matched_recs / rec_count if rec_count else (1.0 if truth_count == 0 else 0.0) + + # Parameter coverage + value accuracy over matched devices only. + param_scores: list[float] = [] + value_scores: list[float] = [] + for truth_dev, covering in matched_truth_devices: + if not covering: + continue + recommended_params: dict[str, NormalizedRec] = {} + for r in covering: + if r.parameter: + recommended_params[_norm_param(r.parameter)] = r + for spec_param in truth_dev.parameters: + key = _norm_param(spec_param.name) + hit = recommended_params.get(key) + if hit is None: + hit = _alias_lookup(spec_param.name, truth_dev.device, recommended_params) + if hit is not None: + param_scores.append(1.0) + value_scores.append(score_value(parse_value(hit.value), spec_param.parsed)) + else: + param_scores.append(0.0) + # No value to score when the parameter was never named. + + parameter_coverage = sum(param_scores) / len(param_scores) if param_scores else 0.0 + value_accuracy = sum(value_scores) / len(value_scores) if value_scores else 0.0 + + score = ( + _WEIGHT_RECALL * role_recall + + _WEIGHT_PRECISION * role_precision + + _WEIGHT_PARAM * parameter_coverage + + _WEIGHT_VALUE * value_accuracy + ) + + return DomainScore( + domain=domain, + truth_device_count=truth_count, + rec_device_count=rec_count, + matched_devices=matched_truth, + role_recall=role_recall, + role_precision=role_precision, + parameter_coverage=parameter_coverage, + value_accuracy=value_accuracy, + score=score, + ) + + +def _norm_param(name: str) -> str: + return re.sub(r"\s+", " ", name.strip().lower()) + + +def _alias_lookup( + spec_param_name: str, + device: str, + recommended_params: Mapping[str, NormalizedRec], +) -> NormalizedRec | None: + """Resolve catalog parameter aliases when matching recommended -> spec. + + e.g. Auto Filter's "Filter Frequency" aliases to "Frequency"; a rec naming + either should satisfy a spec naming the other. + """ + catalog = _shared_catalog() + cat_dev = catalog.get(device) + if cat_dev is None: + return None + # Build the set of names that are equivalent to spec_param_name on this device. + canonical = cat_dev.canonical_parameter(spec_param_name) or spec_param_name + candidates = {canonical} + for alias, target in cat_dev.parameter_aliases.items(): + if target == canonical: + candidates.add(alias) + for cand in candidates: + hit = recommended_params.get(_norm_param(cand)) + if hit is not None: + return hit + return None + + +_CATALOG_SINGLETON: Catalog | None = None + + +def _shared_catalog() -> Catalog: + global _CATALOG_SINGLETON + if _CATALOG_SINGLETON is None: + _CATALOG_SINGLETON = Catalog.load() + return _CATALOG_SINGLETON + + +# Weight of the measurable-intent term in the raw aggregate (the rest is the +# per-domain device score). This is GOAL.md's equivalence mechanism: "the key +# stores measurable intent beside the literal spec, so equivalent routes earn +# credit" — a recommendation that grounds itself in the measurements the spec +# deemed essential earns credit even when it names a different (or processing, +# not source) device than the literal spec. Source-instrument recall is partly +# unrecoverable from a finished render anyway (a synth kick and a sampled kick +# measure identically), so measurable intent is the honest equivalence signal. +_WEIGHT_INTENT = 0.25 + + +def intent_coverage(recs: Sequence[NormalizedRec], fixture: Fixture) -> float: + """Fraction of the fixture's measurableIntent paths cited by >=1 recommendation. + + A path counts as covered when some recommendation citation matches it under + the same bidirectional/wildcard rule the custody check uses. Returns 1.0 when + the fixture declares no measurable intent (nothing to miss). + """ + intents = fixture.measurable_intent + if not intents: + return 1.0 + cited: set[str] = set() + for rec in recs: + cited.update(rec.citations) + if not cited: + return 0.0 + covered = 0 + for target in intents: + if any( + path_covers_tracked(c, target.path) or path_covers_tracked(target.path, c) + for c in cited + ): + covered += 1 + return covered / len(intents) + + +def score_recommendations( + fixture: Fixture, + recs: Sequence[NormalizedRec], + source: str = "unknown", +) -> RecommendationScore: + """Score a normalized rec set against a fixture's answer key. + + The aggregate is the mean of the per-domain scores over the domains that the + fixture's ``deviceSpec`` actually defines (so a fixture that only exercises + kick+bass is not penalized for "missing" a master chain it never specified), + multiplied by the chain-of-custody penalty. + """ + by_domain: dict[str, list[NormalizedRec]] = {d: [] for d in DOMAINS} + by_domain[UNKNOWN_DOMAIN] = [] + for rec in recs: + by_domain.setdefault(rec.domain, []).append(rec) + + domain_scores: dict[str, DomainScore] = {} + scored_domains = fixture.domains_with_spec() + for domain in scored_domains: + domain_scores[domain] = _score_one_domain( + domain, fixture.device_spec[domain], by_domain.get(domain, []) + ) + + domain_mean = ( + sum(s.score for s in domain_scores.values()) / len(domain_scores) + if domain_scores + else 0.0 + ) + + # Blend the literal-device domain score with measurable-intent coverage + # (GOAL.md's equivalence mechanism). When the fixture declares no intent, + # intent_coverage is 1.0 and the blend leaves the domain score unchanged + # only if we skip the term — so apply the intent weight solely when the + # fixture actually carries measurable intent. + intent = intent_coverage(recs, fixture) + if fixture.measurable_intent: + raw_aggregate = (1 - _WEIGHT_INTENT) * domain_mean + _WEIGHT_INTENT * intent + else: + raw_aggregate = domain_mean + + custody = evaluate_custody(recs, fixture.phase1_fingerprint) + aggregate = raw_aggregate * custody.penalty + + return RecommendationScore( + fixture_slug=fixture.slug, + source=source, + domain_scores=domain_scores, + custody=custody, + intent_coverage=intent, + raw_aggregate=raw_aggregate, + aggregate=aggregate, + ) + + +# --------------------------------------------------------------------------- +# Spec catalog-validity (ingest gate for sub-goal 1). +# --------------------------------------------------------------------------- + + +@dataclass +class SpecValidationIssue: + domain: str + device: str + parameter: str | None + message: str + + +def validate_fixture_spec(fixture: Fixture, catalog: Catalog | None = None) -> list[SpecValidationIssue]: + """Validate every device/parameter in a fixture's deviceSpec is catalog-valid. + + This is the always-runnable half of ingest (the Phase 1 fingerprint sanity + check is the other half and SKIPs without rendered audio). An empty list + means the spec is buildable in Live 12 exactly as written, with device and + parameter names that match the contract Phase 2 is held to. + """ + cat = catalog or _shared_catalog() + issues: list[SpecValidationIssue] = [] + for domain, chain in fixture.device_spec.items(): + if domain not in DOMAINS: + issues.append(SpecValidationIssue(domain, "", None, f"unknown domain '{domain}'")) + for dev in chain: + cat_dev = cat.get(dev.device) + if cat_dev is None: + issues.append( + SpecValidationIssue(domain, dev.device, None, f"device '{dev.device}' not in catalog") + ) + continue + if dev.family and dev.family != cat_dev.family: + issues.append( + SpecValidationIssue( + domain, + dev.device, + None, + f"family '{dev.family}' != catalog '{cat_dev.family}'", + ) + ) + for param in dev.parameters: + if cat_dev.canonical_parameter(param.name) is None: + issues.append( + SpecValidationIssue( + domain, + dev.device, + param.name, + f"parameter '{param.name}' not allowed on {dev.device}", + ) + ) + return issues + + +# --------------------------------------------------------------------------- +# Report rendering. +# --------------------------------------------------------------------------- + + +# --------------------------------------------------------------------------- +# Corpus-verification artifact (sub-goal 4 data source). +# +# Aggregates per-fixture scores into per-domain match rates + support counts — +# "how often a recommendation in this domain recovered ground truth across the +# corpus." The UI badge in AnalysisResults.tsx reads this to show *which* recs +# are corpus-verified and *how strongly*. Honest per PURPOSE.md invariant #4: +# support drives the confidence band, so a domain the corpus has barely +# exercised never earns a confident badge. +# --------------------------------------------------------------------------- + +# Number of contributing fixtures below which a domain's verification is hedged. +_VERIFICATION_LOW_SUPPORT = 3 +_VERIFICATION_HIGH_SUPPORT = 6 + + +def _confidence_band(support: int, mean_score: float) -> str: + """Confidence band from BOTH corpus support and observed match quality. + + Support alone is not enough (invariant #4): a domain the corpus exercised many + times but where recommendations rarely matched ground truth must NOT earn a + confident badge — it earned the opposite. So a near-zero match rate caps the + band at NONE regardless of support, and the band rises with match quality only + once there is enough support to trust it. + """ + if support <= 0 or mean_score <= 0.05: + return "NONE" + if support < _VERIFICATION_LOW_SUPPORT: + return "LOW" + if mean_score < 0.4: + return "LOW" + if mean_score < 0.7: + return "MED" + return "HIGH" + + +def aggregate_corpus_verification(scores: Sequence[RecommendationScore]) -> dict[str, Any]: + """Per-domain corpus match rates + support for the UI verification badge. + + ``support`` is the number of fixtures that specified the domain (and were + scored); ``meanRecall``/``meanScore`` are averaged across them. ``confidence`` + maps support to a band so the badge degrades gracefully: zero corpus evidence + for a domain → ``NONE`` (the badge shows "not yet corpus-verified"), never a + confident claim. The artifact is intentionally well-defined when ``scores`` is + empty — every domain reports support 0 / confidence NONE, which is the + pre-render state. + """ + by_domain: dict[str, list[DomainScore]] = {d: [] for d in DOMAINS} + for sc in scores: + for domain, ds in sc.domain_scores.items(): + by_domain[domain].append(ds) + + per_domain: dict[str, Any] = {} + for domain in DOMAINS: + observations = by_domain[domain] + support = len(observations) + mean_recall = (sum(o.role_recall for o in observations) / support) if support else 0.0 + mean_score = (sum(o.score for o in observations) / support) if support else 0.0 + per_domain[domain] = { + "support": support, + "meanRecall": round(mean_recall, 4), + "meanScore": round(mean_score, 4), + "confidence": _confidence_band(support, mean_score), + } + + return { + "fixtures": len(scores), + "sources": sorted({sc.source for sc in scores}), + "perDomain": per_domain, + } + + +def render_markdown_report(scores: Sequence[RecommendationScore]) -> str: + """Render a per-fixture, per-domain markdown report. + + Keeps the per-domain breakdown visible (GOAL.md sub-goal 2.3 — "melody is + under-covered" must stay legible) plus a headline aggregate per fixture. + """ + lines: list[str] = ["# Recommendation Evaluation Report", ""] + for sc in scores: + lines.append(f"## {sc.fixture_slug} (source: {sc.source})") + lines.append("") + lines.append(f"- **Aggregate:** {sc.aggregate:.3f} (raw {sc.raw_aggregate:.3f})") + custody_note = ( + f"penalty {sc.custody.penalty:.3f} — " + f"{sc.custody.cited_recs}/{sc.custody.total_recs} cited" + ) + if sc.custody.path_check_ran: + custody_note += f", {sc.custody.valid_path_recs} path-valid" + else: + custody_note += ", path-validity SKIPPED (no fingerprint)" + lines.append(f"- **Chain of custody:** {custody_note}") + lines.append("") + lines.append("| Domain | Recall | Precision | Params | Values | Score |") + lines.append("|---|---|---|---|---|---|") + for domain in DOMAINS: + ds = sc.domain_scores.get(domain) + if ds is None: + continue + lines.append( + f"| {domain} | {ds.role_recall:.2f} | {ds.role_precision:.2f} | " + f"{ds.parameter_coverage:.2f} | {ds.value_accuracy:.2f} | {ds.score:.3f} |" + ) + lines.append("") + return "\n".join(lines) diff --git a/apps/backend/scripts/emit_deterministic_recs.ts b/apps/backend/scripts/emit_deterministic_recs.ts new file mode 100644 index 00000000..f295db0c --- /dev/null +++ b/apps/backend/scripts/emit_deterministic_recs.ts @@ -0,0 +1,124 @@ +/** + * Deterministic recommendation source bridge (GOAL.md sub-goal 3 inner loop). + * + * EVAL / RESEARCH ONLY. Wraps the product's deterministic recommendation engine + * (`apps/ui/src/data/abletonDevices.ts`) and emits the scorer's normalized rec + * shape so `scripts/evaluate_recommendations.py --source deterministic` can grade + * the *free* path without a Gemini call. Importing the real module keeps a single + * source of truth — no Python re-port to drift from the TS. + * + * Runs on Node 23+ native TypeScript type-stripping (no bundler, no `npm install` + * needed — abletonDevices.ts is import-pure): + * + * node apps/backend/scripts/emit_deterministic_recs.ts \ + * > tests/fixtures/recommendation_tracks//recommendations.deterministic.json + * + * Input is an `AudioFeatures` JSON (bpm, key{root,scale}, crestFactor, + * onsetDensity, duration, bpmConfidence, spectralCentroidMean, spectralBands[]). + * Projecting a real Phase 1 fingerprint into `AudioFeatures` is the app's own job + * (analyzer.ts) and is render-gated — see apps/backend/NEEDS.md. This bridge is + * the faithful, drift-free half that turns engine output into normalized recs; + * the deterministic path is uncited by design, so every rec carries empty + * citations (the scorer's custody penalty then reflects that real difference vs + * the cited Gemini path). + */ + +import { readFileSync } from "node:fs"; +import { + getFXRecommendations, + getInstrumentRecommendations, + type AudioFeatures, +} from "../../ui/src/data/abletonDevices.ts"; + +interface NormalizedRec { + domain: string; + device: string; + parameter: string | null; + value: string | null; + citations: string[]; + family: string | null; +} + +// Spectral-band element -> production domain. The deterministic engine is +// band-centric, so attribution is coarse (it has no explicit kick/stereo/master +// instrument recs — those arrive via the FX rules below). +const BAND_DOMAIN: Record = { + "Sub Bass": "bass", + "Low Bass": "bass", + "Low Mids": "melody", + Mids: "melody", + "Upper Mids": "melody", + Highs: "groove", + Brilliance: "groove", +}; + +// FX-rule text -> domain by keyword, else a sensible default. +function fxDomain(text: string): string { + const low = text.toLowerCase(); + if (/\bbass\b/.test(low)) return "bass"; + if (/drum|transient|hi-hat|hat|percuss/.test(low)) return "groove"; + if (/master|bus group|bus compression|cohesion/.test(low)) return "master"; + if (/reverb|chorus|width|stereo|ambient|space/.test(low)) return "fx"; + return "fx"; +} + +function loadCatalogDeviceNames(): string[] { + const url = new URL("../prompts/live12_device_catalog.json", import.meta.url); + const raw = JSON.parse(readFileSync(url, "utf-8")) as { + devices: Array<{ name: string }>; + }; + // Longest names first so "Glue Compressor" wins over "Compressor". + return raw.devices.map((d) => d.name).sort((a, b) => b.length - a.length); +} + +function firstCatalogDevice(text: string, names: string[]): string | null { + for (const name of names) { + if (text.includes(name)) return name; + } + return null; +} + +function main(): void { + const inputPath = process.argv[2]; + if (!inputPath) { + console.error("usage: node emit_deterministic_recs.ts "); + process.exit(2); + } + const features = JSON.parse(readFileSync(inputPath, "utf-8")) as AudioFeatures; + const catalogNames = loadCatalogDeviceNames(); + const recs: NormalizedRec[] = []; + + // Instrument recs: parse "Device — Preset: settings" -> device + raw settings. + for (const inst of getInstrumentRecommendations(features.spectralBands ?? [])) { + const bandName = inst.element.replace(/ Element$/, ""); + const domain = BAND_DOMAIN[bandName] ?? "melody"; + const device = inst.abletonDevice.split(" — ")[0]?.trim() ?? inst.abletonDevice; + const settings = inst.abletonDevice.split(": ").slice(1).join(": ") || null; + recs.push({ + domain, + device, + parameter: null, + value: settings, + citations: [], // deterministic path is uncited by design + family: null, + }); + } + + // FX recs: extract the first named catalog device from the prose. + for (const fx of getFXRecommendations(features)) { + const device = firstCatalogDevice(fx.recommendation, catalogNames); + if (!device) continue; + recs.push({ + domain: fxDomain(`${fx.artifact} ${fx.recommendation}`), + device, + parameter: null, + value: null, + citations: [], + family: null, + }); + } + + process.stdout.write(JSON.stringify(recs, null, 2) + "\n"); +} + +main(); diff --git a/apps/backend/scripts/evaluate_recommendations.py b/apps/backend/scripts/evaluate_recommendations.py new file mode 100644 index 00000000..a535c868 --- /dev/null +++ b/apps/backend/scripts/evaluate_recommendations.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python3 +"""Score ASA's Phase 2 recommendations against the ground-truth corpus. + +EVAL / RESEARCH ONLY (mirrors scripts/evaluate_*.py). Off the product path; +deleting this and ``recommendation_evaluation.py`` restores the product exactly. + +This is the harness core of GOAL.md's recommendation-proof campaign. It loads the +fixtures under ``tests/fixtures/recommendation_tracks/``, validates each spec is +catalog-valid (the always-runnable half of ingest), pulls recommendations from a +chosen **source**, and scores how well they recover the known device settings. + +The ``--source`` switch is the mechanism sub-goal 3 needs to compare three +recommendation sources on the same corpus: + + * ``baseline`` — trivial no-op source (empty rec set). Runs now, no deps. + The floor any real source must clear. + * ``gemini`` — score a stored ``Phase2Result`` JSON (``--phase2`` or a + sibling ``phase2.json`` in the fixture dir). Producing it + live needs GEMINI_API_KEY + rendered audio (needs-fixture). + * ``deterministic`` — score the ``abletonDevices.ts`` path. Wiring the node + bridge that emits normalized recs from a real Phase 1 + fingerprint is a documented follow-on (NEEDS.md); until + then pass a pre-normalized rec list via ``--recommendations``. + +Any source can also be fed a pre-normalized rec list (``--recommendations``) — a +JSON array of ``{domain, device, parameter, value, citations, family}`` — which +is the universal seam each adapter targets. + +Examples: + ./venv/bin/python scripts/evaluate_recommendations.py --self-test + ./venv/bin/python scripts/evaluate_recommendations.py --source baseline + ./venv/bin/python scripts/evaluate_recommendations.py --fixture house_sidechain_pluck_124 \\ + --source gemini --phase2 /tmp/phase2.json --report /tmp/rec_eval.md +""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path + +BACKEND_DIR = Path(__file__).resolve().parent.parent +if str(BACKEND_DIR) not in sys.path: + sys.path.insert(0, str(BACKEND_DIR)) + +import recommendation_evaluation as rev # noqa: E402 (path bootstrap above) + +DEFAULT_CORPUS_DIR = BACKEND_DIR / "tests" / "fixtures" / "recommendation_tracks" + + +def _load_normalized_recs(path: Path) -> list[rev.NormalizedRec]: + raw = json.loads(path.read_text(encoding="utf-8")) + recs = [] + for item in raw: + recs.append( + rev.NormalizedRec( + domain=item.get("domain", rev.UNKNOWN_DOMAIN), + device=item.get("device", ""), + parameter=item.get("parameter"), + value=item.get("value"), + citations=tuple(item.get("citations", [])), + family=item.get("family"), + ) + ) + return recs + + +def _resolve_recs( + fixture: rev.Fixture, + source: str, + phase2_path: Path | None, + recs_path: Path | None, +) -> tuple[list[rev.NormalizedRec] | None, str]: + """Return (recs, note). ``recs is None`` means SKIP with the given reason.""" + if recs_path is not None: + return _load_normalized_recs(recs_path), f"normalized recs from {recs_path.name}" + + if source == "baseline": + return rev.normalize_baseline(fixture), "trivial baseline (empty)" + + if source == "gemini": + candidate = phase2_path + if candidate is None and fixture.source_path is not None: + sibling = fixture.source_path.parent / "phase2.json" + candidate = sibling if sibling.exists() else None + if candidate is None or not candidate.exists(): + return None, "no Phase2Result JSON (pass --phase2 or drop phase2.json in the fixture dir)" + phase2 = json.loads(candidate.read_text(encoding="utf-8")) + return rev.normalize_phase2(phase2), f"Phase2Result from {candidate.name}" + + if source == "deterministic": + if fixture.source_path is not None: + sibling = fixture.source_path.parent / "recommendations.deterministic.json" + if sibling.exists(): + return _load_normalized_recs(sibling), f"deterministic recs from {sibling.name}" + return None, "deterministic adapter not wired yet — see NEEDS.md (node bridge / --recommendations)" + + return None, f"unknown source '{source}'" + + +def _print_score(score: rev.RecommendationScore) -> None: + print(f" aggregate {score.aggregate:.3f} (raw {score.raw_aggregate:.3f}, " + f"custody penalty {score.custody.penalty:.3f})") + for domain in rev.DOMAINS: + ds = score.domain_scores.get(domain) + if ds is None: + continue + print( + f" {domain:<8} recall {ds.role_recall:.2f} prec {ds.role_precision:.2f} " + f"params {ds.parameter_coverage:.2f} values {ds.value_accuracy:.2f} " + f"-> {ds.score:.3f}" + ) + + +def run_self_test() -> int: + """Always-runnable demonstration that the score moves on a known-bad rec. + + Mirrors the synthetic gate in evaluate_phase1.py — gives a meaningful PASS/ + FAIL even with zero rendered audio in the corpus. + """ + fixture = rev.Fixture( + slug="self-test", + title="self-test", + genre="house", + audio_path=None, + device_spec={ + "kick": ( + rev.SpecDevice("Operator", "NATIVE", + (rev.SpecParameter("Amp Envelope Decay", "250 ms"),)), + ), + "master": ( + rev.SpecDevice("Glue Compressor", "NATIVE", + (rev.SpecParameter("Ratio", "2:1"),)), + ), + }, + measurable_intent=(), + phase1_fingerprint={"kickDetail": {"fundamentalHz": 55.0}, "lufsIntegrated": -9.0}, + render={}, + ) + good = rev.score_recommendations(fixture, [ + rev.NormalizedRec("kick", "Operator", "Amp Envelope Decay", "240 ms", ("kickDetail.fundamentalHz",)), + rev.NormalizedRec("master", "Compressor", "Ratio", "2:1", ("lufsIntegrated",)), + ], "good") + bad = rev.score_recommendations(fixture, [ + rev.NormalizedRec("kick", "Reverb", "Decay Time", "2 s", ()), + ], "bad") + + print("Self-test: good vs known-bad recommendation set") + print(f" good aggregate {good.aggregate:.3f}") + print(f" bad aggregate {bad.aggregate:.3f}") + passed = good.aggregate > bad.aggregate and good.aggregate > 0.7 and bad.aggregate < 0.2 + print(f" [{'PASS' if passed else 'FAIL'}] score moves correctly and equivalence credit holds") + return 0 if passed else 1 + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("--source", choices=["baseline", "gemini", "deterministic"], + default="baseline", help="recommendation source to score") + parser.add_argument("--fixture", help="limit to one fixture slug") + parser.add_argument("--corpus-dir", type=Path, default=DEFAULT_CORPUS_DIR) + parser.add_argument("--phase2", type=Path, help="Phase2Result JSON for --source gemini") + parser.add_argument("--recommendations", type=Path, + help="pre-normalized rec list JSON (overrides --source resolution)") + parser.add_argument("--report", type=Path, help="write a markdown report to this path") + parser.add_argument("--verification-artifact", type=Path, + help="write the per-domain corpus-verification artifact (UI badge source) to this path") + parser.add_argument("--json", action="store_true", help="emit machine-readable JSON to stdout") + parser.add_argument("--self-test", action="store_true", + help="run the synthetic good-vs-bad gate and exit") + args = parser.parse_args() + + if args.self_test: + return run_self_test() + + manifests = sorted(args.corpus_dir.glob("*/manifest.json")) + if args.fixture: + manifests = [m for m in manifests if m.parent.name == args.fixture] + if not manifests: + print(f"No fixtures found under {args.corpus_dir}", file=sys.stderr) + return 1 + + scores: list[rev.RecommendationScore] = [] + any_failure = False + for manifest in manifests: + fixture = rev.load_fixture(manifest) + print(f"\n{fixture.slug} ({fixture.genre}) source={args.source}") + + issues = rev.validate_fixture_spec(fixture) + if issues: + any_failure = True + print(f" [FAIL] spec not catalog-valid ({len(issues)} issue(s)):") + for issue in issues: + print(f" - [{issue.domain}] {issue.device}/{issue.parameter}: {issue.message}") + continue + print(" [OK] spec catalog-valid") + + if fixture.phase1_fingerprint is None: + print(" [note] no Phase 1 fingerprint — citation path-validity will SKIP " + "(render the audio and store phase1_fingerprint.json; see NEEDS.md)") + + recs, note = _resolve_recs(fixture, args.source, args.phase2, args.recommendations) + if recs is None: + print(f" [SKIP] {note}") + continue + print(f" scoring: {note}") + score = rev.score_recommendations(fixture, recs, args.source) + scores.append(score) + _print_score(score) + + if args.report and scores: + args.report.write_text(rev.render_markdown_report(scores), encoding="utf-8") + print(f"\nReport written to {args.report}") + + if args.verification_artifact: + artifact = rev.aggregate_corpus_verification(scores) + args.verification_artifact.write_text(json.dumps(artifact, indent=2), encoding="utf-8") + print(f"Verification artifact written to {args.verification_artifact}") + + if args.json: + print(json.dumps([s.as_dict() for s in scores], indent=2)) + + return 1 if any_failure else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/apps/backend/tests/fixtures/recommendation_tracks/.gitignore b/apps/backend/tests/fixtures/recommendation_tracks/.gitignore new file mode 100644 index 00000000..61dd2571 --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/.gitignore @@ -0,0 +1,8 @@ +# Rendered audio is never committed (see README.md) — only manifests + fingerprints. +*.flac +*.wav +*.aif +*.aiff +*.mp3 +*.ogg +*.m4a diff --git a/apps/backend/tests/fixtures/recommendation_tracks/README.md b/apps/backend/tests/fixtures/recommendation_tracks/README.md new file mode 100644 index 00000000..631ee857 --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/README.md @@ -0,0 +1,140 @@ +# Recommendation Ground-Truth Corpus + +This is the answer-key corpus for **GOAL.md sub-goal 1**. Each fixture is an +Ableton Live 12 project with **known** device settings, rendered to audio, paired +with a machine-readable manifest. The scorer +(`apps/backend/recommendation_evaluation.py`, run via +`scripts/evaluate_recommendations.py`) checks whether ASA's recommendations +recover those known settings — turning recommendation quality from an ear-test +into a number. + +Audio is **never committed** (same policy as `../transcription_tracks/` and +`../polyphonic_tracks/`) — it lives in your local copy only. The committed +artifacts are the `manifest.json` answer keys and these READMEs. A fixture whose +audio you have not rendered yet still validates (catalog-validity) and SKIPs the +parts that need the render. + +## The authoring model — "spec-then-dial" (fork 3) + +The agent does **not** generate `.als` files and you do **not** design chains from +scratch. Instead: + +1. The agent writes an explicit, **catalog-valid device spec** in `manifest.json` + — exact Live 12 devices, exact parameter names (must exist in + `apps/backend/prompts/live12_device_catalog.json`), exact values. +2. **You build exactly that spec in Live and render it.** Because the spec is the + instruction, the answer key is provably the spec — there is no `.als`-parsing + trust gap. +3. The agent ingests the render (stores a Phase 1 fingerprint) and finalizes the + fixture. + +## Directory layout + +``` +recommendation_tracks/ + README.md ← this file (schema + authoring checklist) + _TEMPLATE/manifest.template.json ← copy this to start a new fixture + / + manifest.json ← the answer key (committed) + README.md ← what this fixture isolates (committed) + audio.flac ← your render (NOT committed, gitignored) + phase1_fingerprint.json ← stored Phase 1 of the render (committed once rendered) +``` + +## manifest.json schema (`recommendation-fixture.v1`) + +| Field | Meaning | +|---|---| +| `schemaVersion` | `"recommendation-fixture.v1"` | +| `id` | fixture slug (matches the directory name) | +| `title`, `genre` | human labels; `genre` should be one the owner actually makes | +| `audioPath` | render filename relative to the fixture dir (e.g. `"audio.flac"`) | +| `phase1FingerprintPath` | sibling file holding the stored Phase 1 of the render | +| `phase1Fingerprint` | inline fingerprint, or `null` until rendered (then prefer the sibling file) | +| `render` | `sampleRateHz` (48000), `bitDepth` (24), `lengthSeconds`, `bpm`, `key`, `notes` | +| `deviceSpec` | **the answer key.** Keyed by production domain; each value is an ordered device chain (see below) | +| `measurableIntent` | Phase 1 dotted-path → `{target, tolerance, direction, unit}` — the *measurable* intent, so equivalent reconstructions earn credit | + +### `deviceSpec` — keyed by the seven production domains + +The keys are ASA's reconstruction surface (PURPOSE.md invariant #5): +`kick`, `bass`, `melody`, `groove`, `fx`, `stereo`, `master`. Each holds an +**ordered** list of device entries: + +```json +{ + "device": "Operator", // must be in live12_device_catalog.json + "family": "NATIVE", // NATIVE | MAX_FOR_LIVE (validated) + "role": "Sub bass", // free-text human label + "parameters": [ + { "name": "Filter Frequency", "value": "200 Hz", "intent": "why this value" } + ] +} +``` + +- `name` must be an `allowedParameters` entry (or a `parameterAliases` key) for + that device in the catalog. Run the ingest check (below) — it fails loudly on a + typo. +- `value` is free text; the scorer parses numeric magnitudes + units + (`Hz`, `kHz`, `dB`, `ms`, `s`, `%`, `:1` ratio, `st`). Non-numeric values + (`"Sine"`, `"Auto"`, `"Lowpass"`) are scored on parameter coverage only. +- `intent` is optional prose for the human builder. + +### `measurableIntent` — what the render should measure + +The equivalence safety net. A recommendation that reaches the same measured +outcome by a different valid route still earns credit, so the manifest records +the *measurable* intent next to the literal spec. Mirrors the threshold idiom in +`../phase1_eval_manifest.json`: + +```json +"measurableIntent": { + "bpm": { "target": 124, "tolerance": 1, "direction": "exact" }, + "kickDetail.fundamentalHz": { "target": 55, "tolerance": 15, "unit": "Hz" }, + "sidechainDetail.pumpingStrength": { "target": 0.5, "tolerance": 0.25, "direction": "min" } +} +``` + +Targets you author before rendering are **estimates**; the stored +`phase1_fingerprint.json` is the source of truth once the render exists. + +## Authoring checklist (the owner follows this in Live) + +1. **Copy the template**: `cp -r _TEMPLATE ` and rename `manifest.template.json` → `manifest.json`. Set `id` to ``. +2. **Build the spec exactly** in a new Live 12 set. One device chain per domain, + exactly the devices and parameter values in `deviceSpec`. Keep it a clean, + sparse loop — a few clear, measurable decisions, not a dense full mix. +3. **Set the project to 48 kHz / 24-bit** (Preferences → Audio; Export → 24-bit, + 48000 Hz). This matches the project default and the `render` block. +4. **Render the loop** (Export Audio/Video) to `audio.flac` (or `.wav`) in the + fixture dir. **Do not normalize on export** — measured LUFS / true-peak is part + of the answer key. +5. **Ingest it** to validate catalog-validity and store the Phase 1 fingerprint: + ```bash + # catalog-validity (runs without the render): + ./venv/bin/python scripts/evaluate_recommendations.py --fixture --source baseline + # store the fingerprint from the render (one-liner; see NEEDS.md for the helper): + ./venv/bin/python analyze.py tests/fixtures/recommendation_tracks//audio.flac --yes \ + > tests/fixtures/recommendation_tracks//phase1_fingerprint.json + ``` +6. **Confirm** the measured fingerprint plausibly matches `measurableIntent` + (e.g. BPM, kick fundamental). Adjust the manifest's intent targets to the + measured values where they were estimates. +7. **Commit** `manifest.json`, `README.md`, and `phase1_fingerprint.json` + (audio stays gitignored). + +## Running the scorer + +```bash +# Always-runnable self-test (proves the score moves on a known-bad rec): +./venv/bin/python scripts/evaluate_recommendations.py --self-test + +# Score a source over the whole corpus: +./venv/bin/python scripts/evaluate_recommendations.py --source baseline +./venv/bin/python scripts/evaluate_recommendations.py --source gemini --phase2 +./venv/bin/python scripts/evaluate_recommendations.py --recommendations +``` + +See `apps/backend/NEEDS.md` for the needs-fixture / needs-listen queue (the +renders still owed, and the deterministic-source wiring) and for how sub-goals 3 +and 4 build on this corpus. diff --git a/apps/backend/tests/fixtures/recommendation_tracks/_TEMPLATE/manifest.template.json b/apps/backend/tests/fixtures/recommendation_tracks/_TEMPLATE/manifest.template.json new file mode 100644 index 00000000..38c49938 --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/_TEMPLATE/manifest.template.json @@ -0,0 +1,39 @@ +{ + "schemaVersion": "recommendation-fixture.v1", + "id": "REPLACE_WITH_SLUG", + "title": "Short human description", + "genre": "house", + "audioPath": "audio.flac", + "phase1FingerprintPath": "phase1_fingerprint.json", + "phase1Fingerprint": null, + "render": { + "sampleRateHz": 48000, + "bitDepth": 24, + "lengthSeconds": 16, + "bpm": 0, + "key": "C minor", + "notes": "Build exactly this spec. Render the full loop to one stereo file, no export normalization." + }, + "deviceSpec": { + "kick": [ + { + "device": "Operator", + "family": "NATIVE", + "role": "Kick body", + "parameters": [ + { "name": "Oscillator A Waveform", "value": "Sine", "intent": "why this value matters" } + ] + } + ], + "bass": [], + "melody": [], + "groove": [], + "fx": [], + "stereo": [], + "master": [] + }, + "measurableIntent": { + "bpm": { "target": 0, "tolerance": 1, "direction": "exact" }, + "key": { "target": "C minor" } + } +} diff --git a/apps/backend/tests/fixtures/recommendation_tracks/acid_303_128/README.md b/apps/backend/tests/fixtures/recommendation_tracks/acid_303_128/README.md new file mode 100644 index 00000000..75375618 --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/acid_303_128/README.md @@ -0,0 +1,24 @@ +# acid_303_128 + +**Genre:** acid techno · **Tempo:** 128 BPM · **Key:** A minor · **Render:** 48 kHz / 24-bit, 16 s loop + +## What this fixture isolates + +The 303 acid line: a **sawtooth through a high-resonance lowpass with glide** +(`Operator`, Resonance 70 %, Glide 60 ms), swept by `Auto Filter` and distorted by +`Saturator`. This fixture deliberately exercises ASA's **acid detector** — the +answer key asserts `acidDetail.isAcid` true with `acidDetail.confidence ≥ 0.5`, so +it doubles as a measurement-recovery check for that detector and a recommendation +check (does ASA recommend a resonant filter + drive for the acid character?). + +Covers all seven production domains. + +## Answer key + +`manifest.json` → `deviceSpec`. Build verbatim in Live 12 (checklist in +`../README.md`), render to `audio.flac`, store `phase1_fingerprint.json`. + +## Status +- [x] Catalog-valid spec authored +- [ ] **NEEDS-FIXTURE:** rendered `audio.flac` +- [ ] **NEEDS-FIXTURE:** stored `phase1_fingerprint.json` diff --git a/apps/backend/tests/fixtures/recommendation_tracks/acid_303_128/audio_melody.mid b/apps/backend/tests/fixtures/recommendation_tracks/acid_303_128/audio_melody.mid new file mode 100644 index 00000000..e1faba61 Binary files /dev/null and b/apps/backend/tests/fixtures/recommendation_tracks/acid_303_128/audio_melody.mid differ diff --git a/apps/backend/tests/fixtures/recommendation_tracks/acid_303_128/manifest.json b/apps/backend/tests/fixtures/recommendation_tracks/acid_303_128/manifest.json new file mode 100644 index 00000000..de048166 --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/acid_303_128/manifest.json @@ -0,0 +1,133 @@ +{ + "schemaVersion": "recommendation-fixture.v1", + "id": "acid_303_128", + "title": "Acid — resonant 303-style line, filter sweep, distortion", + "genre": "acid techno", + "audioPath": "audio.flac", + "phase1FingerprintPath": "phase1_fingerprint.json", + "phase1Fingerprint": null, + "render": { + "sampleRateHz": 48000, + "bitDepth": 24, + "lengthSeconds": 16, + "bpm": 128, + "key": "A minor", + "notes": "8-bar loop. A 303-style acid line: sawtooth through a high-resonance lowpass with glide, swept by Auto Filter, distorted by Saturator. This fixture exercises the acidDetail detector. Render the full loop to one stereo file, no export normalization." + }, + "deviceSpec": { + "kick": [ + { + "device": "Operator", + "family": "NATIVE", + "role": "Sine kick", + "parameters": [ + { "name": "Oscillator A Waveform", "value": "Sine" }, + { "name": "Filter Type", "value": "Lowpass" }, + { "name": "Filter Frequency", "value": "110 Hz" }, + { "name": "Amp Envelope Decay", "value": "220 ms" } + ] + } + ], + "bass": [ + { + "device": "Operator", + "family": "NATIVE", + "role": "303-style acid line", + "parameters": [ + { "name": "Oscillator A Waveform", "value": "Saw" }, + { "name": "Filter Type", "value": "Lowpass" }, + { "name": "Filter Frequency", "value": "600 Hz" }, + { "name": "Filter Resonance", "value": "70%" }, + { "name": "Amp Envelope Decay", "value": "150 ms" }, + { "name": "Glide Time", "value": "60 ms" } + ] + } + ], + "melody": [ + { + "device": "Wavetable", + "family": "NATIVE", + "role": "Supporting stab", + "parameters": [ + { "name": "Oscillator 1 Wavetable", "value": "Basic Shapes" }, + { "name": "Filter Type", "value": "Lowpass" }, + { "name": "Filter Frequency", "value": "1500 Hz" }, + { "name": "Amp Envelope Decay", "value": "180 ms" }, + { "name": "Amp Envelope Sustain", "value": "0%" } + ] + } + ], + "groove": [ + { + "device": "Drum Rack", + "family": "NATIVE", + "role": "Hats + clap", + "parameters": [ + { "name": "Pad Volume", "value": "-8 dB" } + ] + } + ], + "fx": [ + { + "device": "Auto Filter", + "family": "NATIVE", + "role": "Acid filter sweep on the line", + "parameters": [ + { "name": "Filter Type", "value": "Lowpass" }, + { "name": "Frequency", "value": "800 Hz" }, + { "name": "Resonance", "value": "60%" }, + { "name": "Envelope Amount", "value": "40%" } + ] + }, + { + "device": "Saturator", + "family": "NATIVE", + "role": "Acid distortion", + "parameters": [ + { "name": "Drive", "value": "15 dB" }, + { "name": "Type", "value": "Soft Sine" }, + { "name": "Dry/Wet", "value": "100%" } + ] + } + ], + "stereo": [ + { + "device": "Utility", + "family": "NATIVE", + "role": "Mild width", + "parameters": [ + { "name": "Stereo Width", "value": "105%" } + ] + } + ], + "master": [ + { + "device": "Glue Compressor", + "family": "NATIVE", + "role": "Bus glue", + "parameters": [ + { "name": "Threshold", "value": "-16 dB" }, + { "name": "Ratio", "value": "2:1" }, + { "name": "Attack", "value": "3 ms" }, + { "name": "Release", "value": "Auto" }, + { "name": "Makeup", "value": "2 dB" } + ] + }, + { + "device": "Limiter", + "family": "NATIVE", + "role": "Master ceiling", + "parameters": [ + { "name": "Ceiling", "value": "-0.3 dB" } + ] + } + ] + }, + "measurableIntent": { + "bpm": { "target": 128, "tolerance": 1, "direction": "exact" }, + "key": { "target": "A minor" }, + "acidDetail.isAcid": { "equals": true, "intent": "resonant sawtooth + filter sweep should trigger the acid detector" }, + "acidDetail.confidence": { "target": 0.5, "tolerance": 0.25, "direction": "min" }, + "lufsIntegrated": { "target": -8, "tolerance": 2, "unit": "LUFS" } + } +} diff --git a/apps/backend/tests/fixtures/recommendation_tracks/acid_303_128/phase1_fingerprint.json b/apps/backend/tests/fixtures/recommendation_tracks/acid_303_128/phase1_fingerprint.json new file mode 100644 index 00000000..c6797d46 --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/acid_303_128/phase1_fingerprint.json @@ -0,0 +1,4773 @@ +{ + "_synthetic": true, + "_note": "Phase 1 of a numpy PROXY render, NOT an Ableton render. Replace with a real Live render's fingerprint for an authoritative verdict.", + "bpm": 128.1, + "bpmConfidence": 3.75, + "bpmPercival": 128.4, + "bpmAgreement": true, + "bpmDoubletime": false, + "bpmSource": "rhythm_extractor_confirmed", + "bpmRawOriginal": 128.1, + "key": "A Minor", + "keyConfidence": 0.67, + "keyProfile": "edma", + "tuningFrequency": 438.73, + "tuningCents": -5.0, + "timeSignature": "4/4", + "timeSignatureSource": "onset_autocorrelation_low_margin", + "timeSignatureConfidence": 0.0, + "durationSeconds": 15.0, + "sampleRate": 44100, + "lufsIntegrated": -9.2, + "lufsRange": 0.1, + "lufsMomentaryMax": -8.6, + "lufsShortTermMax": -9.1, + "lufsCurve": { + "shortTerm": [ + { + "t": 0.0, + "lufs": -9.2 + }, + { + "t": 0.1, + "lufs": -9.2 + }, + { + "t": 0.2, + "lufs": -9.2 + }, + { + "t": 0.3, + "lufs": -9.3 + }, + { + "t": 0.4, + "lufs": -9.2 + }, + { + "t": 0.5, + "lufs": -9.2 + }, + { + "t": 0.6, + "lufs": -9.2 + }, + { + "t": 0.7, + "lufs": -9.2 + }, + { + "t": 0.8, + "lufs": -9.2 + }, + { + "t": 0.9, + "lufs": -9.2 + }, + { + "t": 1.0, + "lufs": -9.2 + }, + { + "t": 1.1, + "lufs": -9.2 + }, + { + "t": 1.2, + "lufs": -9.3 + }, + { + "t": 1.3, + "lufs": -9.3 + }, + { + "t": 1.4, + "lufs": -9.2 + }, + { + "t": 1.5, + "lufs": -9.2 + }, + { + "t": 1.6, + "lufs": -9.2 + }, + { + "t": 1.7, + "lufs": -9.3 + }, + { + "t": 1.8, + "lufs": -9.2 + }, + { + "t": 1.9, + "lufs": -9.2 + }, + { + "t": 2.0, + "lufs": -9.2 + }, + { + "t": 2.1, + "lufs": -9.2 + }, + { + "t": 2.2, + "lufs": -9.2 + }, + { + "t": 2.3, + "lufs": -9.2 + }, + { + "t": 2.4, + "lufs": -9.2 + }, + { + "t": 2.5, + "lufs": -9.2 + }, + { + "t": 2.6, + "lufs": -9.3 + }, + { + "t": 2.7, + "lufs": -9.3 + }, + { + "t": 2.8, + "lufs": -9.2 + }, + { + "t": 2.9, + "lufs": -9.2 + }, + { + "t": 3.0, + "lufs": -9.2 + }, + { + "t": 3.1, + "lufs": -9.3 + }, + { + "t": 3.2, + "lufs": -9.2 + }, + { + "t": 3.3, + "lufs": -9.2 + }, + { + "t": 3.4, + "lufs": -9.2 + }, + { + "t": 3.5, + "lufs": -9.2 + }, + { + "t": 3.6, + "lufs": -9.2 + }, + { + "t": 3.7, + "lufs": -9.2 + }, + { + "t": 3.8, + "lufs": -9.3 + }, + { + "t": 3.9, + "lufs": -9.2 + }, + { + "t": 4.0, + "lufs": -9.3 + }, + { + "t": 4.1, + "lufs": -9.3 + }, + { + "t": 4.2, + "lufs": -9.2 + }, + { + "t": 4.3, + "lufs": -9.2 + }, + { + "t": 4.4, + "lufs": -9.2 + }, + { + "t": 4.5, + "lufs": -9.3 + }, + { + "t": 4.6, + "lufs": -9.2 + }, + { + "t": 4.7, + "lufs": -9.2 + }, + { + "t": 4.8, + "lufs": -9.2 + }, + { + "t": 4.9, + "lufs": -9.2 + }, + { + "t": 5.0, + "lufs": -9.2 + }, + { + "t": 5.1, + "lufs": -9.2 + }, + { + "t": 5.2, + "lufs": -9.3 + }, + { + "t": 5.3, + "lufs": -9.2 + }, + { + "t": 5.4, + "lufs": -9.2 + }, + { + "t": 5.5, + "lufs": -9.3 + }, + { + "t": 5.6, + "lufs": -9.3 + }, + { + "t": 5.7, + "lufs": -9.2 + }, + { + "t": 5.8, + "lufs": -9.2 + }, + { + "t": 5.9, + "lufs": -9.3 + }, + { + "t": 6.0, + "lufs": -9.2 + }, + { + "t": 6.1, + "lufs": -9.2 + }, + { + "t": 6.2, + "lufs": -9.2 + }, + { + "t": 6.3, + "lufs": -9.2 + }, + { + "t": 6.4, + "lufs": -9.3 + }, + { + "t": 6.5, + "lufs": -9.2 + }, + { + "t": 6.6, + "lufs": -9.2 + }, + { + "t": 6.7, + "lufs": -9.2 + }, + { + "t": 6.8, + "lufs": -9.2 + }, + { + "t": 6.9, + "lufs": -9.3 + }, + { + "t": 7.0, + "lufs": -9.2 + }, + { + "t": 7.1, + "lufs": -9.2 + }, + { + "t": 7.2, + "lufs": -9.2 + }, + { + "t": 7.3, + "lufs": -9.3 + }, + { + "t": 7.4, + "lufs": -9.2 + }, + { + "t": 7.5, + "lufs": -9.1 + }, + { + "t": 7.6, + "lufs": -9.2 + }, + { + "t": 7.7, + "lufs": -9.2 + }, + { + "t": 7.8, + "lufs": -9.3 + }, + { + "t": 7.9, + "lufs": -9.2 + }, + { + "t": 8.0, + "lufs": -9.3 + }, + { + "t": 8.1, + "lufs": -9.2 + }, + { + "t": 8.2, + "lufs": -9.2 + }, + { + "t": 8.3, + "lufs": -9.3 + }, + { + "t": 8.4, + "lufs": -9.2 + }, + { + "t": 8.5, + "lufs": -9.2 + }, + { + "t": 8.6, + "lufs": -9.2 + }, + { + "t": 8.7, + "lufs": -9.3 + }, + { + "t": 8.8, + "lufs": -9.2 + }, + { + "t": 8.9, + "lufs": -9.1 + }, + { + "t": 9.0, + "lufs": -9.2 + }, + { + "t": 9.1, + "lufs": -9.2 + }, + { + "t": 9.2, + "lufs": -9.3 + }, + { + "t": 9.3, + "lufs": -9.2 + }, + { + "t": 9.4, + "lufs": -9.2 + }, + { + "t": 9.5, + "lufs": -9.2 + }, + { + "t": 9.6, + "lufs": -9.2 + }, + { + "t": 9.7, + "lufs": -9.3 + }, + { + "t": 9.8, + "lufs": -9.2 + }, + { + "t": 9.9, + "lufs": -9.3 + }, + { + "t": 10.0, + "lufs": -9.2 + }, + { + "t": 10.1, + "lufs": -9.3 + }, + { + "t": 10.2, + "lufs": -9.2 + }, + { + "t": 10.3, + "lufs": -9.2 + }, + { + "t": 10.4, + "lufs": -9.2 + }, + { + "t": 10.5, + "lufs": -9.2 + }, + { + "t": 10.6, + "lufs": -9.3 + }, + { + "t": 10.7, + "lufs": -9.2 + }, + { + "t": 10.8, + "lufs": -9.2 + }, + { + "t": 10.9, + "lufs": -9.2 + }, + { + "t": 11.0, + "lufs": -9.2 + }, + { + "t": 11.1, + "lufs": -9.3 + }, + { + "t": 11.2, + "lufs": -9.2 + }, + { + "t": 11.3, + "lufs": -9.3 + }, + { + "t": 11.4, + "lufs": -9.2 + }, + { + "t": 11.5, + "lufs": -9.3 + }, + { + "t": 11.6, + "lufs": -9.2 + }, + { + "t": 11.7, + "lufs": -9.1 + }, + { + "t": 11.8, + "lufs": -9.2 + }, + { + "t": 11.9, + "lufs": -9.2 + }, + { + "t": 12.0, + "lufs": -9.3 + } + ], + "momentary": [ + { + "t": 0.0, + "lufs": -9.2 + }, + { + "t": 0.1, + "lufs": -9.1 + }, + { + "t": 0.2, + "lufs": -8.7 + }, + { + "t": 0.3, + "lufs": -9.5 + }, + { + "t": 0.4, + "lufs": -8.7 + }, + { + "t": 0.5, + "lufs": -9.3 + }, + { + "t": 0.6, + "lufs": -9.1 + }, + { + "t": 0.7, + "lufs": -8.8 + }, + { + "t": 0.8, + "lufs": -9.1 + }, + { + "t": 0.9, + "lufs": -8.8 + }, + { + "t": 1.0, + "lufs": -9.7 + }, + { + "t": 1.1, + "lufs": -9.5 + }, + { + "t": 1.2, + "lufs": -10.0 + }, + { + "t": 1.3, + "lufs": -9.5 + }, + { + "t": 1.4, + "lufs": -9.3 + }, + { + "t": 1.5, + "lufs": -9.3 + }, + { + "t": 1.6, + "lufs": -8.9 + }, + { + "t": 1.7, + "lufs": -9.6 + }, + { + "t": 1.8, + "lufs": -8.8 + }, + { + "t": 1.9, + "lufs": -9.3 + }, + { + "t": 2.0, + "lufs": -9.1 + }, + { + "t": 2.1, + "lufs": -8.8 + }, + { + "t": 2.2, + "lufs": -9.2 + }, + { + "t": 2.3, + "lufs": -8.8 + }, + { + "t": 2.4, + "lufs": -9.6 + }, + { + "t": 2.5, + "lufs": -9.5 + }, + { + "t": 2.6, + "lufs": -9.8 + }, + { + "t": 2.7, + "lufs": -9.4 + }, + { + "t": 2.8, + "lufs": -9.2 + }, + { + "t": 2.9, + "lufs": -9.4 + }, + { + "t": 3.0, + "lufs": -8.8 + }, + { + "t": 3.1, + "lufs": -9.4 + }, + { + "t": 3.2, + "lufs": -8.7 + }, + { + "t": 3.3, + "lufs": -9.0 + }, + { + "t": 3.4, + "lufs": -9.2 + }, + { + "t": 3.5, + "lufs": -8.9 + }, + { + "t": 3.6, + "lufs": -9.3 + }, + { + "t": 3.7, + "lufs": -8.9 + }, + { + "t": 3.8, + "lufs": -9.5 + }, + { + "t": 3.9, + "lufs": -9.6 + }, + { + "t": 4.0, + "lufs": -9.7 + }, + { + "t": 4.1, + "lufs": -9.5 + }, + { + "t": 4.2, + "lufs": -9.3 + }, + { + "t": 4.3, + "lufs": -9.5 + }, + { + "t": 4.4, + "lufs": -8.8 + }, + { + "t": 4.5, + "lufs": -9.4 + }, + { + "t": 4.6, + "lufs": -8.7 + }, + { + "t": 4.7, + "lufs": -8.9 + }, + { + "t": 4.8, + "lufs": -9.1 + }, + { + "t": 4.9, + "lufs": -8.8 + }, + { + "t": 5.0, + "lufs": -9.4 + }, + { + "t": 5.1, + "lufs": -8.8 + }, + { + "t": 5.2, + "lufs": -9.5 + }, + { + "t": 5.3, + "lufs": -9.5 + }, + { + "t": 5.4, + "lufs": -9.6 + }, + { + "t": 5.5, + "lufs": -9.6 + }, + { + "t": 5.6, + "lufs": -9.4 + }, + { + "t": 5.7, + "lufs": -9.8 + }, + { + "t": 5.8, + "lufs": -8.9 + }, + { + "t": 5.9, + "lufs": -9.4 + }, + { + "t": 6.0, + "lufs": -8.8 + }, + { + "t": 6.1, + "lufs": -8.8 + }, + { + "t": 6.2, + "lufs": -9.3 + }, + { + "t": 6.3, + "lufs": -8.9 + }, + { + "t": 6.4, + "lufs": -9.6 + }, + { + "t": 6.5, + "lufs": -8.8 + }, + { + "t": 6.6, + "lufs": -9.4 + }, + { + "t": 6.7, + "lufs": -9.5 + }, + { + "t": 6.8, + "lufs": -9.3 + }, + { + "t": 6.9, + "lufs": -9.5 + }, + { + "t": 7.0, + "lufs": -9.3 + }, + { + "t": 7.1, + "lufs": -9.8 + }, + { + "t": 7.2, + "lufs": -8.8 + }, + { + "t": 7.3, + "lufs": -9.3 + }, + { + "t": 7.4, + "lufs": -8.7 + }, + { + "t": 7.5, + "lufs": -8.6 + }, + { + "t": 7.6, + "lufs": -9.3 + }, + { + "t": 7.7, + "lufs": -8.9 + }, + { + "t": 7.8, + "lufs": -9.7 + }, + { + "t": 7.9, + "lufs": -8.9 + }, + { + "t": 8.0, + "lufs": -9.4 + }, + { + "t": 8.1, + "lufs": -9.7 + }, + { + "t": 8.2, + "lufs": -9.3 + }, + { + "t": 8.3, + "lufs": -9.7 + }, + { + "t": 8.4, + "lufs": -9.4 + }, + { + "t": 8.5, + "lufs": -9.7 + }, + { + "t": 8.6, + "lufs": -8.9 + }, + { + "t": 8.7, + "lufs": -9.2 + }, + { + "t": 8.8, + "lufs": -8.8 + }, + { + "t": 8.9, + "lufs": -8.6 + }, + { + "t": 9.0, + "lufs": -9.4 + }, + { + "t": 9.1, + "lufs": -8.9 + }, + { + "t": 9.2, + "lufs": -9.6 + }, + { + "t": 9.3, + "lufs": -8.8 + }, + { + "t": 9.4, + "lufs": -9.1 + }, + { + "t": 9.5, + "lufs": -9.5 + }, + { + "t": 9.6, + "lufs": -9.3 + }, + { + "t": 9.7, + "lufs": -9.7 + }, + { + "t": 9.8, + "lufs": -9.4 + }, + { + "t": 9.9, + "lufs": -9.7 + }, + { + "t": 10.0, + "lufs": -8.9 + }, + { + "t": 10.1, + "lufs": -9.2 + }, + { + "t": 10.2, + "lufs": -8.8 + }, + { + "t": 10.3, + "lufs": -8.7 + }, + { + "t": 10.4, + "lufs": -9.6 + }, + { + "t": 10.5, + "lufs": -9.0 + }, + { + "t": 10.6, + "lufs": -9.7 + }, + { + "t": 10.7, + "lufs": -8.9 + }, + { + "t": 10.8, + "lufs": -9.0 + }, + { + "t": 10.9, + "lufs": -9.6 + }, + { + "t": 11.0, + "lufs": -9.3 + }, + { + "t": 11.1, + "lufs": -9.8 + }, + { + "t": 11.2, + "lufs": -9.3 + }, + { + "t": 11.3, + "lufs": -9.6 + }, + { + "t": 11.4, + "lufs": -8.9 + }, + { + "t": 11.5, + "lufs": -9.0 + }, + { + "t": 11.6, + "lufs": -8.8 + }, + { + "t": 11.7, + "lufs": -8.6 + }, + { + "t": 11.8, + "lufs": -9.6 + }, + { + "t": 11.9, + "lufs": -9.0 + }, + { + "t": 12.0, + "lufs": -9.6 + }, + { + "t": 12.1, + "lufs": -8.9 + }, + { + "t": 12.2, + "lufs": -9.0 + }, + { + "t": 12.3, + "lufs": -9.7 + }, + { + "t": 12.4, + "lufs": -9.4 + }, + { + "t": 12.5, + "lufs": -10.1 + }, + { + "t": 12.6, + "lufs": -9.4 + }, + { + "t": 12.7, + "lufs": -9.5 + }, + { + "t": 12.8, + "lufs": -9.0 + }, + { + "t": 12.9, + "lufs": -8.9 + }, + { + "t": 13.0, + "lufs": -8.9 + }, + { + "t": 13.1, + "lufs": -8.7 + }, + { + "t": 13.2, + "lufs": -9.7 + }, + { + "t": 13.3, + "lufs": -8.9 + }, + { + "t": 13.4, + "lufs": -9.5 + }, + { + "t": 13.5, + "lufs": -8.8 + }, + { + "t": 13.6, + "lufs": -8.8 + }, + { + "t": 13.7, + "lufs": -9.8 + }, + { + "t": 13.8, + "lufs": -9.3 + }, + { + "t": 13.9, + "lufs": -10.2 + }, + { + "t": 14.0, + "lufs": -9.4 + }, + { + "t": 14.1, + "lufs": -9.4 + }, + { + "t": 14.2, + "lufs": -8.9 + }, + { + "t": 14.3, + "lufs": -8.8 + }, + { + "t": 14.4, + "lufs": -8.9 + }, + { + "t": 14.5, + "lufs": -8.7 + }, + { + "t": 14.6, + "lufs": -9.9 + } + ] + }, + "truePeak": 1.0, + "plr": 10.2, + "crestFactor": 10.2, + "dynamicSpread": 27.68, + "dynamicCharacter": { + "dynamicComplexity": 1.1558, + "loudnessDb": -16.4615, + "loudnessVariation": -16.4615, + "spectralFlatness": 0.1003, + "logAttackTime": -4.2304, + "attackTimeStdDev": 0.0433 + }, + "textureCharacter": { + "textureScore": 0.3797, + "lowBandFlatness": 0.3645, + "midBandFlatness": 0.3059, + "highBandFlatness": 0.2739, + "inharmonicity": 0.1717 + }, + "stereoDetail": { + "stereoWidth": 0.0, + "stereoCorrelation": 1.0, + "subBassCorrelation": 1.0, + "subBassMono": true, + "correlationCurve": [ + { + "t": 0.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 1.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 2.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 3.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 4.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 5.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 6.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 7.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 8.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 9.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 10.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 11.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 12.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 13.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 14.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 15.5, + "full": 1.0, + "sub": 1.0 + } + ], + "bandCorrelations": { + "subBass": 1.0, + "lowBass": 1.0, + "lowMids": 1.0, + "mids": 1.0, + "upperMids": 1.0, + "highs": 1.0, + "brilliance": 1.0 + } + }, + "monoCompatible": true, + "spectralBalance": { + "subBass": -11.1, + "lowBass": -8.0, + "lowMids": -25.3, + "mids": -19.9, + "upperMids": -32.1, + "highs": -29.4, + "brilliance": -21.8 + }, + "spectralBalanceTimeSeries": [ + { + "t": 0.03, + "subBass": -7.7, + "lowBass": -6.7, + "lowMids": -30.8, + "mids": -18.6, + "upperMids": -34.0, + "highs": -46.4, + "brilliance": -80.0 + }, + { + "t": 0.13, + "subBass": -8.4, + "lowBass": -9.0, + "lowMids": -38.0, + "mids": -18.6, + "upperMids": -33.5, + "highs": -45.9, + "brilliance": -71.1 + }, + { + "t": 0.22, + "subBass": -12.1, + "lowBass": -9.6, + "lowMids": -36.0, + "mids": -19.4, + "upperMids": -28.3, + "highs": -23.5, + "brilliance": -15.7 + }, + { + "t": 0.31, + "subBass": -16.0, + "lowBass": -8.0, + "lowMids": -42.1, + "mids": -20.2, + "upperMids": -30.9, + "highs": -30.0, + "brilliance": -22.5 + }, + { + "t": 0.41, + "subBass": -21.9, + "lowBass": -9.3, + "lowMids": -44.9, + "mids": -18.7, + "upperMids": -30.5, + "highs": -41.8, + "brilliance": -60.5 + }, + { + "t": 0.5, + "subBass": -8.8, + "lowBass": -4.7, + "lowMids": -19.4, + "mids": -23.8, + "upperMids": -33.6, + "highs": -56.0, + "brilliance": -71.1 + }, + { + "t": 0.59, + "subBass": -8.6, + "lowBass": -8.9, + "lowMids": -20.0, + "mids": -19.3, + "upperMids": -33.4, + "highs": -49.8, + "brilliance": -72.6 + }, + { + "t": 0.68, + "subBass": -11.7, + "lowBass": -9.6, + "lowMids": -24.6, + "mids": -19.6, + "upperMids": -28.8, + "highs": -24.2, + "brilliance": -16.2 + }, + { + "t": 0.78, + "subBass": -13.5, + "lowBass": -8.0, + "lowMids": -43.0, + "mids": -20.3, + "upperMids": -30.6, + "highs": -28.6, + "brilliance": -21.3 + }, + { + "t": 0.87, + "subBass": -16.8, + "lowBass": -9.1, + "lowMids": -45.9, + "mids": -18.4, + "upperMids": -30.4, + "highs": -41.8, + "brilliance": -62.6 + }, + { + "t": 0.96, + "subBass": -9.1, + "lowBass": -5.4, + "lowMids": -20.4, + "mids": -19.3, + "upperMids": -34.5, + "highs": -49.8, + "brilliance": -72.8 + }, + { + "t": 1.06, + "subBass": -8.4, + "lowBass": -8.9, + "lowMids": -26.5, + "mids": -18.7, + "upperMids": -33.2, + "highs": -48.4, + "brilliance": -77.7 + }, + { + "t": 1.15, + "subBass": -12.0, + "lowBass": -9.6, + "lowMids": -33.9, + "mids": -19.9, + "upperMids": -30.3, + "highs": -24.1, + "brilliance": -16.3 + }, + { + "t": 1.24, + "subBass": -15.7, + "lowBass": -8.0, + "lowMids": -40.1, + "mids": -21.1, + "upperMids": -31.8, + "highs": -27.6, + "brilliance": -20.0 + }, + { + "t": 1.34, + "subBass": -21.4, + "lowBass": -9.1, + "lowMids": -29.7, + "mids": -18.0, + "upperMids": -33.6, + "highs": -48.8, + "brilliance": -62.4 + }, + { + "t": 1.43, + "subBass": -9.8, + "lowBass": -7.7, + "lowMids": -20.3, + "mids": -19.4, + "upperMids": -36.9, + "highs": -53.5, + "brilliance": -75.8 + }, + { + "t": 1.52, + "subBass": -8.0, + "lowBass": -8.9, + "lowMids": -28.0, + "mids": -20.3, + "upperMids": -34.7, + "highs": -49.4, + "brilliance": -75.5 + }, + { + "t": 1.61, + "subBass": -11.2, + "lowBass": -9.6, + "lowMids": -25.1, + "mids": -21.2, + "upperMids": -30.9, + "highs": -23.9, + "brilliance": -16.4 + }, + { + "t": 1.71, + "subBass": -15.5, + "lowBass": -7.9, + "lowMids": -21.7, + "mids": -21.0, + "upperMids": -33.3, + "highs": -26.9, + "brilliance": -18.9 + }, + { + "t": 1.8, + "subBass": -20.7, + "lowBass": -9.1, + "lowMids": -29.9, + "mids": -18.4, + "upperMids": -35.0, + "highs": -50.1, + "brilliance": -60.4 + }, + { + "t": 1.89, + "subBass": -9.8, + "lowBass": -4.6, + "lowMids": -29.0, + "mids": -20.5, + "upperMids": -37.0, + "highs": -48.6, + "brilliance": -75.0 + }, + { + "t": 1.99, + "subBass": -8.2, + "lowBass": -8.7, + "lowMids": -36.7, + "mids": -19.5, + "upperMids": -36.0, + "highs": -48.4, + "brilliance": -78.9 + }, + { + "t": 2.08, + "subBass": -11.5, + "lowBass": -9.8, + "lowMids": -24.8, + "mids": -21.5, + "upperMids": -31.7, + "highs": -24.3, + "brilliance": -16.9 + }, + { + "t": 2.17, + "subBass": -13.2, + "lowBass": -7.9, + "lowMids": -20.1, + "mids": -25.7, + "upperMids": -31.7, + "highs": -26.2, + "brilliance": -17.9 + }, + { + "t": 2.26, + "subBass": -16.1, + "lowBass": -9.0, + "lowMids": -18.5, + "mids": -23.4, + "upperMids": -33.8, + "highs": -58.1, + "brilliance": -60.3 + }, + { + "t": 2.36, + "subBass": -10.0, + "lowBass": -4.9, + "lowMids": -26.6, + "mids": -20.2, + "upperMids": -32.5, + "highs": -44.3, + "brilliance": -69.2 + }, + { + "t": 2.45, + "subBass": -8.0, + "lowBass": -8.6, + "lowMids": -37.9, + "mids": -19.4, + "upperMids": -31.0, + "highs": -44.2, + "brilliance": -73.6 + }, + { + "t": 2.54, + "subBass": -11.6, + "lowBass": -10.0, + "lowMids": -35.5, + "mids": -20.0, + "upperMids": -29.6, + "highs": -25.6, + "brilliance": -18.6 + }, + { + "t": 2.64, + "subBass": -15.3, + "lowBass": -7.9, + "lowMids": -42.9, + "mids": -19.1, + "upperMids": -28.1, + "highs": -25.3, + "brilliance": -17.1 + }, + { + "t": 2.73, + "subBass": -19.9, + "lowBass": -9.0, + "lowMids": -38.3, + "mids": -17.7, + "upperMids": -31.4, + "highs": -43.3, + "brilliance": -60.1 + }, + { + "t": 2.82, + "subBass": -9.8, + "lowBass": -7.2, + "lowMids": -31.2, + "mids": -18.8, + "upperMids": -30.1, + "highs": -43.5, + "brilliance": -69.4 + }, + { + "t": 2.91, + "subBass": -7.3, + "lowBass": -8.3, + "lowMids": -30.8, + "mids": -19.3, + "upperMids": -31.7, + "highs": -45.8, + "brilliance": -72.8 + }, + { + "t": 3.01, + "subBass": -10.8, + "lowBass": -10.2, + "lowMids": -31.8, + "mids": -19.7, + "upperMids": -31.9, + "highs": -28.4, + "brilliance": -21.5 + }, + { + "t": 3.1, + "subBass": -15.1, + "lowBass": -7.9, + "lowMids": -40.4, + "mids": -18.4, + "upperMids": -29.3, + "highs": -24.2, + "brilliance": -16.2 + }, + { + "t": 3.19, + "subBass": -19.3, + "lowBass": -8.9, + "lowMids": -41.5, + "mids": -18.4, + "upperMids": -30.2, + "highs": -43.8, + "brilliance": -61.4 + }, + { + "t": 3.29, + "subBass": -11.4, + "lowBass": -5.1, + "lowMids": -20.5, + "mids": -23.5, + "upperMids": -34.6, + "highs": -52.5, + "brilliance": -71.5 + }, + { + "t": 3.38, + "subBass": -7.7, + "lowBass": -8.4, + "lowMids": -23.6, + "mids": -21.0, + "upperMids": -34.9, + "highs": -51.9, + "brilliance": -76.5 + }, + { + "t": 3.47, + "subBass": -11.0, + "lowBass": -10.1, + "lowMids": -30.7, + "mids": -20.3, + "upperMids": -34.5, + "highs": -33.0, + "brilliance": -26.0 + }, + { + "t": 3.56, + "subBass": -12.9, + "lowBass": -7.9, + "lowMids": -19.3, + "mids": -25.1, + "upperMids": -30.0, + "highs": -23.2, + "brilliance": -15.2 + }, + { + "t": 3.66, + "subBass": -15.7, + "lowBass": -8.8, + "lowMids": -32.3, + "mids": -19.0, + "upperMids": -35.6, + "highs": -48.5, + "brilliance": -63.5 + }, + { + "t": 3.75, + "subBass": -11.8, + "lowBass": -5.4, + "lowMids": -31.0, + "mids": -21.2, + "upperMids": -36.2, + "highs": -48.4, + "brilliance": -71.8 + }, + { + "t": 3.84, + "subBass": -7.5, + "lowBass": -8.2, + "lowMids": -22.9, + "mids": -23.7, + "upperMids": -37.3, + "highs": -51.9, + "brilliance": -76.5 + }, + { + "t": 3.94, + "subBass": -10.8, + "lowBass": -9.9, + "lowMids": -21.0, + "mids": -27.4, + "upperMids": -38.5, + "highs": -40.5, + "brilliance": -33.4 + }, + { + "t": 4.03, + "subBass": -15.1, + "lowBass": -8.0, + "lowMids": -29.7, + "mids": -18.9, + "upperMids": -29.6, + "highs": -22.4, + "brilliance": -14.6 + }, + { + "t": 4.12, + "subBass": -18.9, + "lowBass": -8.8, + "lowMids": -29.0, + "mids": -18.5, + "upperMids": -34.7, + "highs": -49.8, + "brilliance": -61.2 + }, + { + "t": 4.21, + "subBass": -13.6, + "lowBass": -8.1, + "lowMids": -31.8, + "mids": -19.9, + "upperMids": -34.1, + "highs": -46.6, + "brilliance": -75.0 + }, + { + "t": 4.31, + "subBass": -7.3, + "lowBass": -8.3, + "lowMids": -24.7, + "mids": -20.9, + "upperMids": -35.5, + "highs": -48.8, + "brilliance": -73.9 + }, + { + "t": 4.4, + "subBass": -10.1, + "lowBass": -9.7, + "lowMids": -20.9, + "mids": -20.1, + "upperMids": -36.8, + "highs": -50.5, + "brilliance": -46.5 + }, + { + "t": 4.49, + "subBass": -15.0, + "lowBass": -8.2, + "lowMids": -35.9, + "mids": -18.2, + "upperMids": -28.6, + "highs": -22.0, + "brilliance": -14.5 + }, + { + "t": 4.59, + "subBass": -18.5, + "lowBass": -8.8, + "lowMids": -19.9, + "mids": -18.4, + "upperMids": -33.6, + "highs": -48.6, + "brilliance": -59.4 + }, + { + "t": 4.68, + "subBass": -14.5, + "lowBass": -5.0, + "lowMids": -19.6, + "mids": -22.5, + "upperMids": -34.9, + "highs": -56.1, + "brilliance": -71.3 + }, + { + "t": 4.77, + "subBass": -7.2, + "lowBass": -7.7, + "lowMids": -22.5, + "mids": -22.3, + "upperMids": -32.9, + "highs": -48.6, + "brilliance": -72.3 + }, + { + "t": 4.86, + "subBass": -10.6, + "lowBass": -9.6, + "lowMids": -43.1, + "mids": -19.2, + "upperMids": -30.3, + "highs": -43.8, + "brilliance": -85.6 + }, + { + "t": 4.96, + "subBass": -12.9, + "lowBass": -8.4, + "lowMids": -19.0, + "mids": -23.2, + "upperMids": -28.5, + "highs": -22.3, + "brilliance": -14.6 + }, + { + "t": 5.05, + "subBass": -14.9, + "lowBass": -8.6, + "lowMids": -19.6, + "mids": -18.7, + "upperMids": -32.9, + "highs": -48.5, + "brilliance": -59.6 + }, + { + "t": 5.14, + "subBass": -14.6, + "lowBass": -5.8, + "lowMids": -24.0, + "mids": -19.7, + "upperMids": -34.0, + "highs": -47.0, + "brilliance": -71.3 + }, + { + "t": 5.24, + "subBass": -7.1, + "lowBass": -7.8, + "lowMids": -34.3, + "mids": -19.9, + "upperMids": -34.0, + "highs": -46.2, + "brilliance": -72.6 + }, + { + "t": 5.33, + "subBass": -10.4, + "lowBass": -9.5, + "lowMids": -40.6, + "mids": -18.5, + "upperMids": -32.9, + "highs": -45.1, + "brilliance": -93.1 + }, + { + "t": 5.42, + "subBass": -14.6, + "lowBass": -8.5, + "lowMids": -19.2, + "mids": -23.6, + "upperMids": -29.3, + "highs": -22.9, + "brilliance": -15.0 + }, + { + "t": 5.51, + "subBass": -17.8, + "lowBass": -8.6, + "lowMids": -28.1, + "mids": -19.6, + "upperMids": -32.3, + "highs": -44.3, + "brilliance": -61.9 + }, + { + "t": 5.61, + "subBass": -19.0, + "lowBass": -9.5, + "lowMids": -33.4, + "mids": -19.9, + "upperMids": -32.7, + "highs": -45.8, + "brilliance": -69.8 + }, + { + "t": 5.7, + "subBass": -6.3, + "lowBass": -6.7, + "lowMids": -35.3, + "mids": -21.7, + "upperMids": -34.5, + "highs": -48.5, + "brilliance": -73.7 + }, + { + "t": 5.79, + "subBass": -9.7, + "lowBass": -9.4, + "lowMids": -43.2, + "mids": -19.8, + "upperMids": -33.6, + "highs": -45.7, + "brilliance": -83.6 + }, + { + "t": 5.89, + "subBass": -13.9, + "lowBass": -8.6, + "lowMids": -19.8, + "mids": -25.0, + "upperMids": -30.0, + "highs": -22.9, + "brilliance": -15.0 + }, + { + "t": 5.98, + "subBass": -17.4, + "lowBass": -8.5, + "lowMids": -27.7, + "mids": -20.7, + "upperMids": -34.4, + "highs": -49.1, + "brilliance": -64.8 + }, + { + "t": 6.07, + "subBass": -21.1, + "lowBass": -6.0, + "lowMids": -29.0, + "mids": -21.2, + "upperMids": -36.3, + "highs": -51.0, + "brilliance": -65.3 + }, + { + "t": 6.16, + "subBass": -6.9, + "lowBass": -7.1, + "lowMids": -30.8, + "mids": -21.3, + "upperMids": -38.0, + "highs": -53.6, + "brilliance": -79.9 + }, + { + "t": 6.26, + "subBass": -10.1, + "lowBass": -9.4, + "lowMids": -39.6, + "mids": -19.0, + "upperMids": -36.2, + "highs": -49.1, + "brilliance": -80.8 + }, + { + "t": 6.35, + "subBass": -12.5, + "lowBass": -8.5, + "lowMids": -38.9, + "mids": -20.2, + "upperMids": -29.4, + "highs": -22.4, + "brilliance": -14.6 + }, + { + "t": 6.44, + "subBass": -14.5, + "lowBass": -8.5, + "lowMids": -21.1, + "mids": -19.5, + "upperMids": -35.9, + "highs": -50.8, + "brilliance": -67.4 + }, + { + "t": 6.54, + "subBass": -18.5, + "lowBass": -7.0, + "lowMids": -23.1, + "mids": -20.4, + "upperMids": -34.9, + "highs": -49.2, + "brilliance": -62.1 + }, + { + "t": 6.63, + "subBass": -7.0, + "lowBass": -5.8, + "lowMids": -32.3, + "mids": -21.2, + "upperMids": -33.8, + "highs": -47.9, + "brilliance": -84.3 + }, + { + "t": 6.72, + "subBass": -9.9, + "lowBass": -9.3, + "lowMids": -19.5, + "mids": -18.5, + "upperMids": -34.2, + "highs": -50.5, + "brilliance": -75.1 + }, + { + "t": 6.82, + "subBass": -13.8, + "lowBass": -8.6, + "lowMids": -27.4, + "mids": -18.2, + "upperMids": -28.4, + "highs": -22.1, + "brilliance": -14.4 + }, + { + "t": 6.91, + "subBass": -17.2, + "lowBass": -8.4, + "lowMids": -37.2, + "mids": -18.8, + "upperMids": -31.1, + "highs": -42.8, + "brilliance": -51.0 + }, + { + "t": 7.0, + "subBass": -18.7, + "lowBass": -8.3, + "lowMids": -29.8, + "mids": -19.4, + "upperMids": -32.0, + "highs": -44.2, + "brilliance": -60.6 + }, + { + "t": 7.09, + "subBass": -7.3, + "lowBass": -7.8, + "lowMids": -30.4, + "mids": -19.0, + "upperMids": -32.4, + "highs": -47.1, + "brilliance": -94.6 + }, + { + "t": 7.19, + "subBass": -9.3, + "lowBass": -9.3, + "lowMids": -37.4, + "mids": -17.8, + "upperMids": -31.7, + "highs": -43.7, + "brilliance": -70.3 + }, + { + "t": 7.28, + "subBass": -13.6, + "lowBass": -8.8, + "lowMids": -28.5, + "mids": -18.2, + "upperMids": -28.0, + "highs": -22.2, + "brilliance": -14.6 + }, + { + "t": 7.37, + "subBass": -16.9, + "lowBass": -8.3, + "lowMids": -20.4, + "mids": -21.6, + "upperMids": -32.7, + "highs": -46.9, + "brilliance": -40.3 + }, + { + "t": 7.47, + "subBass": -20.3, + "lowBass": -7.7, + "lowMids": -21.0, + "mids": -23.0, + "upperMids": -34.2, + "highs": -52.4, + "brilliance": -59.0 + }, + { + "t": 7.56, + "subBass": -7.6, + "lowBass": -5.1, + "lowMids": -28.4, + "mids": -19.5, + "upperMids": -33.3, + "highs": -48.0, + "brilliance": -99.1 + }, + { + "t": 7.65, + "subBass": -9.6, + "lowBass": -9.2, + "lowMids": -38.7, + "mids": -18.3, + "upperMids": -33.0, + "highs": -43.9, + "brilliance": -72.8 + }, + { + "t": 7.74, + "subBass": -12.4, + "lowBass": -9.0, + "lowMids": -36.7, + "mids": -18.8, + "upperMids": -29.2, + "highs": -22.7, + "brilliance": -14.9 + }, + { + "t": 7.84, + "subBass": -14.2, + "lowBass": -8.3, + "lowMids": -42.1, + "mids": -19.6, + "upperMids": -33.1, + "highs": -41.0, + "brilliance": -34.3 + }, + { + "t": 7.93, + "subBass": -16.1, + "lowBass": -8.7, + "lowMids": -30.8, + "mids": -20.8, + "upperMids": -34.0, + "highs": -47.8, + "brilliance": -60.3 + }, + { + "t": 8.02, + "subBass": -7.7, + "lowBass": -5.6, + "lowMids": -28.9, + "mids": -19.6, + "upperMids": -35.5, + "highs": -50.9, + "brilliance": -91.0 + }, + { + "t": 8.12, + "subBass": -9.5, + "lowBass": -9.2, + "lowMids": -38.3, + "mids": -19.5, + "upperMids": -36.3, + "highs": -47.6, + "brilliance": -73.1 + }, + { + "t": 8.21, + "subBass": -13.2, + "lowBass": -9.0, + "lowMids": -37.7, + "mids": -20.5, + "upperMids": -29.3, + "highs": -23.1, + "brilliance": -15.2 + }, + { + "t": 8.3, + "subBass": -16.7, + "lowBass": -8.2, + "lowMids": -44.2, + "mids": -21.1, + "upperMids": -35.1, + "highs": -37.8, + "brilliance": -30.6 + }, + { + "t": 8.39, + "subBass": -20.4, + "lowBass": -9.5, + "lowMids": -34.5, + "mids": -22.0, + "upperMids": -36.6, + "highs": -48.8, + "brilliance": -62.9 + }, + { + "t": 8.49, + "subBass": -7.5, + "lowBass": -7.2, + "lowMids": -29.7, + "mids": -19.0, + "upperMids": -35.5, + "highs": -51.1, + "brilliance": -80.5 + }, + { + "t": 8.58, + "subBass": -8.8, + "lowBass": -9.1, + "lowMids": -19.4, + "mids": -24.8, + "upperMids": -36.4, + "highs": -63.8, + "brilliance": -74.1 + }, + { + "t": 8.67, + "subBass": -12.4, + "lowBass": -9.1, + "lowMids": -27.1, + "mids": -20.5, + "upperMids": -28.8, + "highs": -22.9, + "brilliance": -15.1 + }, + { + "t": 8.77, + "subBass": -16.4, + "lowBass": -8.2, + "lowMids": -40.9, + "mids": -19.7, + "upperMids": -33.5, + "highs": -34.9, + "brilliance": -27.6 + }, + { + "t": 8.86, + "subBass": -22.2, + "lowBass": -9.6, + "lowMids": -38.3, + "mids": -19.9, + "upperMids": -35.3, + "highs": -47.7, + "brilliance": -62.3 + }, + { + "t": 8.95, + "subBass": -7.9, + "lowBass": -4.7, + "lowMids": -29.7, + "mids": -19.6, + "upperMids": -32.2, + "highs": -43.9, + "brilliance": -72.7 + }, + { + "t": 9.04, + "subBass": -9.1, + "lowBass": -9.1, + "lowMids": -37.9, + "mids": -18.1, + "upperMids": -32.6, + "highs": -44.8, + "brilliance": -77.8 + }, + { + "t": 9.14, + "subBass": -12.1, + "lowBass": -9.1, + "lowMids": -29.6, + "mids": -18.6, + "upperMids": -28.7, + "highs": -22.5, + "brilliance": -14.8 + }, + { + "t": 9.23, + "subBass": -13.9, + "lowBass": -8.2, + "lowMids": -22.4, + "mids": -20.7, + "upperMids": -32.4, + "highs": -33.2, + "brilliance": -25.5 + }, + { + "t": 9.32, + "subBass": -17.5, + "lowBass": -9.4, + "lowMids": -19.7, + "mids": -24.6, + "upperMids": -33.7, + "highs": -59.2, + "brilliance": -61.5 + }, + { + "t": 9.42, + "subBass": -8.0, + "lowBass": -4.5, + "lowMids": -29.1, + "mids": -18.6, + "upperMids": -32.5, + "highs": -44.5, + "brilliance": -68.6 + }, + { + "t": 9.51, + "subBass": -9.0, + "lowBass": -9.0, + "lowMids": -38.2, + "mids": -18.1, + "upperMids": -32.0, + "highs": -42.6, + "brilliance": -73.0 + }, + { + "t": 9.6, + "subBass": -12.8, + "lowBass": -9.2, + "lowMids": -36.0, + "mids": -19.1, + "upperMids": -27.6, + "highs": -22.6, + "brilliance": -15.0 + }, + { + "t": 9.69, + "subBass": -16.2, + "lowBass": -8.1, + "lowMids": -41.7, + "mids": -19.6, + "upperMids": -30.5, + "highs": -31.4, + "brilliance": -24.2 + }, + { + "t": 9.79, + "subBass": -23.1, + "lowBass": -9.4, + "lowMids": -43.1, + "mids": -19.1, + "upperMids": -30.7, + "highs": -44.2, + "brilliance": -60.8 + }, + { + "t": 9.88, + "subBass": -7.8, + "lowBass": -6.7, + "lowMids": -19.7, + "mids": -18.6, + "upperMids": -34.2, + "highs": -50.2, + "brilliance": -69.8 + }, + { + "t": 9.97, + "subBass": -8.5, + "lowBass": -9.1, + "lowMids": -30.4, + "mids": -19.0, + "upperMids": -34.5, + "highs": -45.6, + "brilliance": -73.8 + }, + { + "t": 10.07, + "subBass": -12.2, + "lowBass": -9.5, + "lowMids": -36.6, + "mids": -20.0, + "upperMids": -29.0, + "highs": -23.2, + "brilliance": -15.5 + }, + { + "t": 10.16, + "subBass": -16.0, + "lowBass": -8.0, + "lowMids": -28.3, + "mids": -20.9, + "upperMids": -33.0, + "highs": -30.5, + "brilliance": -22.9 + }, + { + "t": 10.25, + "subBass": -22.1, + "lowBass": -9.3, + "lowMids": -20.2, + "mids": -19.4, + "upperMids": -37.1, + "highs": -52.1, + "brilliance": -60.1 + }, + { + "t": 10.34, + "subBass": -8.7, + "lowBass": -4.6, + "lowMids": -26.0, + "mids": -19.8, + "upperMids": -36.4, + "highs": -51.9, + "brilliance": -70.7 + }, + { + "t": 10.44, + "subBass": -8.7, + "lowBass": -8.9, + "lowMids": -37.0, + "mids": -20.3, + "upperMids": -34.6, + "highs": -49.2, + "brilliance": -74.6 + }, + { + "t": 10.53, + "subBass": -11.7, + "lowBass": -9.6, + "lowMids": -38.4, + "mids": -21.0, + "upperMids": -30.7, + "highs": -24.1, + "brilliance": -16.0 + }, + { + "t": 10.62, + "subBass": -13.5, + "lowBass": -8.0, + "lowMids": -40.6, + "mids": -21.5, + "upperMids": -35.2, + "highs": -29.2, + "brilliance": -21.7 + }, + { + "t": 10.72, + "subBass": -16.7, + "lowBass": -9.1, + "lowMids": -43.7, + "mids": -19.1, + "upperMids": -36.1, + "highs": -48.8, + "brilliance": -62.9 + }, + { + "t": 10.81, + "subBass": -9.0, + "lowBass": -5.5, + "lowMids": -30.6, + "mids": -20.0, + "upperMids": -36.5, + "highs": -47.7, + "brilliance": -70.7 + }, + { + "t": 10.9, + "subBass": -8.5, + "lowBass": -8.9, + "lowMids": -37.5, + "mids": -19.2, + "upperMids": -35.4, + "highs": -47.8, + "brilliance": -78.2 + }, + { + "t": 10.99, + "subBass": -12.1, + "lowBass": -9.6, + "lowMids": -37.6, + "mids": -20.2, + "upperMids": -30.6, + "highs": -24.2, + "brilliance": -16.3 + }, + { + "t": 11.09, + "subBass": -15.8, + "lowBass": -8.0, + "lowMids": -43.5, + "mids": -21.1, + "upperMids": -31.8, + "highs": -27.9, + "brilliance": -20.4 + }, + { + "t": 11.18, + "subBass": -21.5, + "lowBass": -9.1, + "lowMids": -43.7, + "mids": -18.3, + "upperMids": -30.2, + "highs": -44.0, + "brilliance": -63.7 + }, + { + "t": 11.27, + "subBass": -9.5, + "lowBass": -7.6, + "lowMids": -18.8, + "mids": -23.2, + "upperMids": -33.2, + "highs": -57.1, + "brilliance": -72.6 + }, + { + "t": 11.37, + "subBass": -7.9, + "lowBass": -8.9, + "lowMids": -20.1, + "mids": -19.6, + "upperMids": -33.8, + "highs": -50.5, + "brilliance": -73.0 + }, + { + "t": 11.46, + "subBass": -11.2, + "lowBass": -9.6, + "lowMids": -23.7, + "mids": -19.4, + "upperMids": -30.3, + "highs": -23.9, + "brilliance": -16.5 + }, + { + "t": 11.55, + "subBass": -15.6, + "lowBass": -8.0, + "lowMids": -42.1, + "mids": -19.5, + "upperMids": -31.0, + "highs": -27.2, + "brilliance": -19.3 + }, + { + "t": 11.64, + "subBass": -20.9, + "lowBass": -9.1, + "lowMids": -41.8, + "mids": -17.8, + "upperMids": -28.8, + "highs": -42.1, + "brilliance": -60.8 + }, + { + "t": 11.74, + "subBass": -9.7, + "lowBass": -4.7, + "lowMids": -19.3, + "mids": -23.4, + "upperMids": -33.3, + "highs": -54.2, + "brilliance": -71.7 + }, + { + "t": 11.83, + "subBass": -8.2, + "lowBass": -8.8, + "lowMids": -26.2, + "mids": -19.3, + "upperMids": -32.8, + "highs": -44.3, + "brilliance": -72.9 + }, + { + "t": 11.92, + "subBass": -11.6, + "lowBass": -9.7, + "lowMids": -37.7, + "mids": -19.6, + "upperMids": -29.5, + "highs": -24.0, + "brilliance": -16.7 + }, + { + "t": 12.02, + "subBass": -13.2, + "lowBass": -7.9, + "lowMids": -43.2, + "mids": -19.7, + "upperMids": -29.4, + "highs": -26.3, + "brilliance": -18.3 + }, + { + "t": 12.11, + "subBass": -16.3, + "lowBass": -9.0, + "lowMids": -41.8, + "mids": -18.2, + "upperMids": -30.2, + "highs": -43.8, + "brilliance": -59.7 + }, + { + "t": 12.2, + "subBass": -9.8, + "lowBass": -4.8, + "lowMids": -29.0, + "mids": -20.2, + "upperMids": -33.1, + "highs": -45.1, + "brilliance": -69.8 + }, + { + "t": 12.29, + "subBass": -8.0, + "lowBass": -8.6, + "lowMids": -22.0, + "mids": -19.9, + "upperMids": -35.3, + "highs": -49.3, + "brilliance": -73.6 + }, + { + "t": 12.39, + "subBass": -11.7, + "lowBass": -9.9, + "lowMids": -22.9, + "mids": -20.5, + "upperMids": -32.6, + "highs": -25.0, + "brilliance": -18.0 + }, + { + "t": 12.48, + "subBass": -15.3, + "lowBass": -7.9, + "lowMids": -42.7, + "mids": -19.8, + "upperMids": -31.3, + "highs": -25.5, + "brilliance": -17.4 + }, + { + "t": 12.57, + "subBass": -20.0, + "lowBass": -9.0, + "lowMids": -40.9, + "mids": -19.4, + "upperMids": -33.3, + "highs": -47.4, + "brilliance": -60.6 + }, + { + "t": 12.67, + "subBass": -9.7, + "lowBass": -7.1, + "lowMids": -28.4, + "mids": -19.5, + "upperMids": -35.9, + "highs": -51.3, + "brilliance": -69.6 + }, + { + "t": 12.76, + "subBass": -7.3, + "lowBass": -8.3, + "lowMids": -22.8, + "mids": -20.7, + "upperMids": -38.2, + "highs": -54.4, + "brilliance": -71.7 + }, + { + "t": 12.85, + "subBass": -10.9, + "lowBass": -10.2, + "lowMids": -22.9, + "mids": -21.2, + "upperMids": -34.7, + "highs": -27.2, + "brilliance": -20.3 + }, + { + "t": 12.95, + "subBass": -15.2, + "lowBass": -7.9, + "lowMids": -40.8, + "mids": -19.6, + "upperMids": -30.8, + "highs": -24.6, + "brilliance": -16.5 + }, + { + "t": 13.04, + "subBass": -19.4, + "lowBass": -8.9, + "lowMids": -19.1, + "mids": -24.3, + "upperMids": -35.9, + "highs": -57.8, + "brilliance": -60.9 + }, + { + "t": 13.13, + "subBass": -11.2, + "lowBass": -5.0, + "lowMids": -20.8, + "mids": -20.9, + "upperMids": -37.2, + "highs": -54.2, + "brilliance": -73.4 + }, + { + "t": 13.22, + "subBass": -7.7, + "lowBass": -8.5, + "lowMids": -25.3, + "mids": -20.1, + "upperMids": -33.6, + "highs": -47.9, + "brilliance": -77.5 + }, + { + "t": 13.32, + "subBass": -11.0, + "lowBass": -10.1, + "lowMids": -39.6, + "mids": -20.7, + "upperMids": -32.2, + "highs": -31.2, + "brilliance": -24.2 + }, + { + "t": 13.41, + "subBass": -12.9, + "lowBass": -7.9, + "lowMids": -40.9, + "mids": -18.6, + "upperMids": -29.4, + "highs": -23.6, + "brilliance": -15.5 + }, + { + "t": 13.5, + "subBass": -15.7, + "lowBass": -8.8, + "lowMids": -44.9, + "mids": -18.5, + "upperMids": -30.7, + "highs": -42.1, + "brilliance": -62.7 + }, + { + "t": 13.6, + "subBass": -11.6, + "lowBass": -5.6, + "lowMids": -30.5, + "mids": -19.6, + "upperMids": -31.0, + "highs": -44.1, + "brilliance": -72.9 + }, + { + "t": 13.69, + "subBass": -7.6, + "lowBass": -8.3, + "lowMids": -37.0, + "mids": -19.7, + "upperMids": -31.2, + "highs": -43.3, + "brilliance": -75.0 + }, + { + "t": 13.78, + "subBass": -10.9, + "lowBass": -9.9, + "lowMids": -39.8, + "mids": -20.2, + "upperMids": -31.7, + "highs": -36.4, + "brilliance": -30.4 + }, + { + "t": 13.87, + "subBass": -15.1, + "lowBass": -7.9, + "lowMids": -29.2, + "mids": -17.8, + "upperMids": -28.2, + "highs": -22.6, + "brilliance": -14.8 + }, + { + "t": 13.97, + "subBass": -19.0, + "lowBass": -8.8, + "lowMids": -38.0, + "mids": -17.7, + "upperMids": -31.6, + "highs": -43.7, + "brilliance": -61.6 + }, + { + "t": 14.06, + "subBass": -13.0, + "lowBass": -8.0, + "lowMids": -33.5, + "mids": -18.5, + "upperMids": -32.6, + "highs": -43.5, + "brilliance": -71.5 + }, + { + "t": 14.15, + "subBass": -7.4, + "lowBass": -8.5, + "lowMids": -24.0, + "mids": -19.9, + "upperMids": -34.4, + "highs": -46.5, + "brilliance": -75.1 + }, + { + "t": 14.25, + "subBass": -10.1, + "lowBass": -9.8, + "lowMids": -20.9, + "mids": -19.9, + "upperMids": -35.3, + "highs": -46.3, + "brilliance": -40.9 + }, + { + "t": 14.34, + "subBass": -15.0, + "lowBass": -8.1, + "lowMids": -36.7, + "mids": -18.9, + "upperMids": -28.2, + "highs": -22.0, + "brilliance": -14.5 + }, + { + "t": 14.43, + "subBass": -18.6, + "lowBass": -8.8, + "lowMids": -19.0, + "mids": -23.3, + "upperMids": -34.2, + "highs": -53.3, + "brilliance": -60.0 + }, + { + "t": 14.52, + "subBass": -14.0, + "lowBass": -5.0, + "lowMids": -24.1, + "mids": -21.8, + "upperMids": -34.3, + "highs": -49.4, + "brilliance": -70.8 + }, + { + "t": 14.62, + "subBass": -7.3, + "lowBass": -7.8, + "lowMids": -35.1, + "mids": -20.8, + "upperMids": -34.9, + "highs": -48.3, + "brilliance": -74.8 + }, + { + "t": 14.71, + "subBass": -10.7, + "lowBass": -9.6, + "lowMids": -42.6, + "mids": -20.2, + "upperMids": -37.1, + "highs": -48.0, + "brilliance": -64.5 + }, + { + "t": 14.8, + "subBass": -12.9, + "lowBass": -8.3, + "lowMids": -20.4, + "mids": -19.6, + "upperMids": -29.7, + "highs": -22.1, + "brilliance": -14.5 + }, + { + "t": 14.9, + "subBass": -14.9, + "lowBass": -8.6, + "lowMids": -31.1, + "mids": -19.9, + "upperMids": -34.1, + "highs": -48.2, + "brilliance": -59.6 + }, + { + "t": 14.98, + "subBass": -19.9, + "lowBass": -11.1, + "lowMids": -51.2, + "mids": -24.8, + "upperMids": -38.8, + "highs": -53.2, + "brilliance": -69.8 + } + ], + "spectralDetail": { + "spectralCentroid": 1143.7, + "spectralRolloff": 1417.9, + "spectralBandwidth": 2739.0, + "spectralFlatness": 0.100292, + "mfcc": [ + -709.5033, + 179.2003, + -4.397, + 67.3743, + 3.6385, + 32.1981, + 16.6615, + 24.6982, + 28.5366, + 24.7113, + 18.4794, + 14.0034, + -2.0097 + ], + "chroma": [ + 0.3726, + 0.026, + 0.3771, + 0.413, + 0.0285, + 0.1845, + 0.0141, + 0.122, + 0.2386, + 0.0884, + 0.2095, + 0.0331 + ], + "barkBands": [ + -25.3316, + -11.2894, + -9.0312, + -17.704, + -30.1847, + -38.3175, + -25.6778, + -24.9797, + -25.3476, + -28.4964, + -33.0865, + -35.0749, + -32.5394, + -35.1704, + -37.2281, + -38.2025, + -38.4162, + -40.1596, + -40.8253, + -41.9961, + -39.5266, + -36.6372, + -36.9955, + -32.9441 + ], + "erbBands": [ + 7.536, + 14.0712, + 21.8912, + 18.9657, + 9.1326, + 3.3034, + 1.3842, + 5.506, + 15.6084, + 18.2029, + 17.805, + 19.5268, + 16.6856, + 12.1819, + 12.6252, + 12.2071, + 14.504, + 13.0057, + 9.9236, + 10.228, + 9.047, + 7.5179, + 7.4743, + 6.1386, + 5.2085, + 5.548, + 6.2641, + 6.6532, + 8.183, + 8.692, + 8.0691, + 10.1416, + 9.1001, + 9.5631, + 8.777, + 8.6768, + 6.6698, + 2.8038, + -3.0919, + -12.6223 + ], + "spectralContrast": [ + -0.2476, + -0.5762, + -0.5962, + -0.6492, + -0.6988, + -0.7046 + ], + "spectralValley": [ + -5.7264, + -6.793, + -7.7678, + -8.3054, + -9.1873, + -11.4489 + ] + }, + "stemAnalysis": null, + "transientDensityDetail": { + "subBass": { + "onsetRatePerSecond": 8.87, + "meanOnsetStrength": 0.263, + "peakOnsetStrength": 0.614, + "eventCount": 133 + }, + "lowBass": { + "onsetRatePerSecond": 7.47, + "meanOnsetStrength": 0.461, + "peakOnsetStrength": 1.158, + "eventCount": 112 + }, + "lowMids": { + "onsetRatePerSecond": 9.27, + "meanOnsetStrength": 1.041, + "peakOnsetStrength": 2.658, + "eventCount": 139 + }, + "mids": { + "onsetRatePerSecond": 9.67, + "meanOnsetStrength": 4.075, + "peakOnsetStrength": 8.298, + "eventCount": 145 + }, + "upperMids": { + "onsetRatePerSecond": 9.8, + "meanOnsetStrength": 3.717, + "peakOnsetStrength": 8.627, + "eventCount": 147 + }, + "highs": { + "onsetRatePerSecond": 10.4, + "meanOnsetStrength": 3.719, + "peakOnsetStrength": 13.387, + "eventCount": 156 + }, + "brilliance": { + "onsetRatePerSecond": 10.6, + "meanOnsetStrength": 5.004, + "peakOnsetStrength": 15.263, + "eventCount": 159 + } + }, + "saturationDetail": { + "clippedSampleCount": 0, + "clippedSamplePercent": 0.0, + "nearClippedSampleCount": 0, + "nearClippedSamplePercent": 0.0, + "peakRatio95to50": 2.61, + "rmsToPeakRatioDb": 10.22, + "saturationLikely": false + }, + "snareDetail": { + "hitCount": 56, + "hitsPerSecond": 3.73, + "meanAttackSharpness": 0.0029, + "meanBodyEnergyRatio": 0.977, + "meanSnapEnergyRatio": 0.023, + "meanCentroidHz": 418.2, + "meanDecayFrames": 58.6, + "meanDecaySeconds": 0.34, + "bandHz": [ + 120.0, + 2000.0 + ] + }, + "hihatDetail": { + "hitCount": 32, + "hitsPerSecond": 2.13, + "meanAttackSharpness": 0.0028, + "meanBodyEnergyRatio": 0.197, + "meanSnapEnergyRatio": 0.803, + "meanCentroidHz": 7860.3, + "meanDecayFrames": 8.2, + "meanDecaySeconds": 0.048, + "bandHz": [ + 2000.0, + 12000.0 + ] + }, + "rhythmDetail": { + "onsetRate": 2.13, + "beatGrid": [ + 0.36, + 0.743, + 1.173, + 1.637, + 2.101, + 2.577, + 3.042, + 3.506, + 3.982, + 4.447, + 4.923, + 5.387, + 5.851, + 6.327, + 6.792, + 7.256, + 7.732, + 8.197, + 8.661, + 9.137, + 9.601, + 10.077, + 10.542, + 11.006, + 11.482, + 11.947, + 12.411, + 12.887, + 13.351, + 13.827, + 14.292, + 14.756 + ], + "downbeats": [ + 1.173, + 3.042, + 4.923, + 6.792, + 8.661, + 10.542, + 12.411, + 14.292 + ], + "beatPositions": [ + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2 + ], + "downbeatSource": "kick_accent", + "downbeatConfidence": 0.0028, + "grooveAmount": 0.037, + "tempoStability": 0.963, + "phraseGrid": { + "phrases4Bar": [ + 1.173, + 8.661 + ], + "phrases8Bar": [ + 1.173 + ], + "phrases16Bar": [ + 1.173 + ], + "totalBars": 8, + "totalPhrases8Bar": 1 + }, + "tempoCurve": [ + { + "t": 0.55, + "bpm": 139.7 + }, + { + "t": 0.96, + "bpm": 134.4 + }, + { + "t": 1.4, + "bpm": 129.2 + }, + { + "t": 1.87, + "bpm": 129.2 + }, + { + "t": 2.34, + "bpm": 129.2 + }, + { + "t": 2.81, + "bpm": 129.2 + }, + { + "t": 3.27, + "bpm": 129.2 + }, + { + "t": 3.74, + "bpm": 129.2 + }, + { + "t": 4.21, + "bpm": 129.2 + }, + { + "t": 4.68, + "bpm": 129.2 + }, + { + "t": 5.15, + "bpm": 129.2 + }, + { + "t": 5.62, + "bpm": 129.2 + }, + { + "t": 6.09, + "bpm": 129.2 + }, + { + "t": 6.56, + "bpm": 129.2 + }, + { + "t": 7.02, + "bpm": 129.2 + }, + { + "t": 7.49, + "bpm": 129.2 + }, + { + "t": 7.96, + "bpm": 129.2 + }, + { + "t": 8.43, + "bpm": 129.2 + }, + { + "t": 8.9, + "bpm": 129.2 + }, + { + "t": 9.37, + "bpm": 129.2 + }, + { + "t": 9.84, + "bpm": 129.2 + }, + { + "t": 10.31, + "bpm": 129.2 + }, + { + "t": 10.77, + "bpm": 129.2 + }, + { + "t": 11.24, + "bpm": 129.2 + }, + { + "t": 11.71, + "bpm": 129.2 + }, + { + "t": 12.18, + "bpm": 129.2 + }, + { + "t": 12.65, + "bpm": 129.2 + }, + { + "t": 13.12, + "bpm": 129.2 + }, + { + "t": 13.59, + "bpm": 129.2 + }, + { + "t": 14.06, + "bpm": 129.2 + }, + { + "t": 14.52, + "bpm": 129.2 + } + ] + }, + "melodyDetail": { + "noteCount": 54, + "notes": [ + { + "midi": 47, + "onset": 0.264, + "duration": 0.194 + }, + { + "midi": 48, + "onset": 0.464, + "duration": 0.238 + }, + { + "midi": 45, + "onset": 0.749, + "duration": 0.171 + }, + { + "midi": 47, + "onset": 0.926, + "duration": 0.238 + }, + { + "midi": 48, + "onset": 1.17, + "duration": 0.221 + }, + { + "midi": 47, + "onset": 1.643, + "duration": 0.221 + }, + { + "midi": 48, + "onset": 1.869, + "duration": 0.223 + }, + { + "midi": 45, + "onset": 2.125, + "duration": 0.203 + }, + { + "midi": 47, + "onset": 2.334, + "duration": 0.241 + }, + { + "midi": 48, + "onset": 2.58, + "duration": 0.247 + }, + { + "midi": 47, + "onset": 3.08, + "duration": 0.192 + }, + { + "midi": 48, + "onset": 3.277, + "duration": 0.223 + }, + { + "midi": 45, + "onset": 3.529, + "duration": 0.203 + }, + { + "midi": 47, + "onset": 3.738, + "duration": 0.241 + }, + { + "midi": 48, + "onset": 3.985, + "duration": 0.218 + }, + { + "midi": 45, + "onset": 4.255, + "duration": 0.119 + }, + { + "midi": 47, + "onset": 4.481, + "duration": 0.194 + }, + { + "midi": 48, + "onset": 4.682, + "duration": 0.229 + }, + { + "midi": 45, + "onset": 4.94, + "duration": 0.2 + }, + { + "midi": 47, + "onset": 5.146, + "duration": 0.241 + }, + { + "midi": 48, + "onset": 5.393, + "duration": 0.25 + }, + { + "midi": 45, + "onset": 5.663, + "duration": 0.18 + }, + { + "midi": 47, + "onset": 5.849, + "duration": 0.232 + }, + { + "midi": 48, + "onset": 6.087, + "duration": 0.223 + }, + { + "midi": 47, + "onset": 6.554, + "duration": 0.241 + }, + { + "midi": 48, + "onset": 6.801, + "duration": 0.215 + }, + { + "midi": 47, + "onset": 7.271, + "duration": 0.218 + }, + { + "midi": 48, + "onset": 7.494, + "duration": 0.226 + }, + { + "midi": 47, + "onset": 7.964, + "duration": 0.235 + }, + { + "midi": 48, + "onset": 8.205, + "duration": 0.247 + }, + { + "midi": 45, + "onset": 8.475, + "duration": 0.18 + }, + { + "midi": 47, + "onset": 8.661, + "duration": 0.232 + }, + { + "midi": 48, + "onset": 8.899, + "duration": 0.223 + }, + { + "midi": 45, + "onset": 9.189, + "duration": 0.168 + }, + { + "midi": 47, + "onset": 9.363, + "duration": 0.241 + }, + { + "midi": 48, + "onset": 9.61, + "duration": 0.247 + }, + { + "midi": 45, + "onset": 9.895, + "duration": 0.168 + }, + { + "midi": 47, + "onset": 10.069, + "duration": 0.232 + }, + { + "midi": 48, + "onset": 10.307, + "duration": 0.221 + }, + { + "midi": 45, + "onset": 10.565, + "duration": 0.197 + }, + { + "midi": 47, + "onset": 10.768, + "duration": 0.244 + }, + { + "midi": 48, + "onset": 11.018, + "duration": 0.247 + }, + { + "midi": 47, + "onset": 11.52, + "duration": 0.189 + }, + { + "midi": 48, + "onset": 11.714, + "duration": 0.223 + }, + { + "midi": 47, + "onset": 12.182, + "duration": 0.238 + }, + { + "midi": 48, + "onset": 12.426, + "duration": 0.244 + }, + { + "midi": 45, + "onset": 12.693, + "duration": 0.183 + }, + { + "midi": 47, + "onset": 12.881, + "duration": 0.232 + }, + { + "midi": 48, + "onset": 13.119, + "duration": 0.232 + }, + { + "midi": 45, + "onset": 13.386, + "duration": 0.192 + }, + { + "midi": 47, + "onset": 13.584, + "duration": 0.241 + }, + { + "midi": 48, + "onset": 13.83, + "duration": 0.244 + }, + { + "midi": 47, + "onset": 14.301, + "duration": 0.221 + }, + { + "midi": 48, + "onset": 14.527, + "duration": 0.223 + } + ], + "dominantNotes": [ + 47, + 48, + 45 + ], + "pitchRange": { + "min": 45, + "max": 48 + }, + "pitchConfidence": 0.0655, + "midiFile": "/Users/christiansmith/code/projects/asa/.claude/worktrees/goal-doc/apps/backend/tests/fixtures/recommendation_tracks/acid_303_128/audio_melody.mid", + "sourceSeparated": false, + "vibratoPresent": false, + "vibratoExtent": 0.0, + "vibratoRate": 0.0, + "vibratoConfidence": 0.0 + }, + "transcriptionDetail": null, + "pitchDetail": null, + "grooveDetail": { + "kickSwing": 0.1759, + "hihatSwing": 0.2043, + "kickAccent": [ + 0.1434, + 0.219, + 0.2053, + 0.2181, + 0.2202, + 0.2131, + 0.2174, + 0.2185, + 0.2138, + 0.2177, + 0.2191, + 0.2223, + 0.2177, + 0.2195, + 0.214, + 0.2238 + ], + "hihatAccent": [ + 0.0002, + 0.0416, + 0.0131, + 0.0537, + 0.0538, + 0.0402, + 0.0424, + 0.0421, + 0.0404, + 0.041, + 0.0453, + 0.0603, + 0.0525, + 0.0454, + 0.0313, + 0.0531 + ], + "perDrumSwing": { + "kick": 0.1759, + "snare": 0.2282, + "hihat": 0.2043 + } + }, + "beatsLoudness": { + "kickDominantRatio": 0.7735, + "midDominantRatio": 0.0, + "highDominantRatio": 0.1527, + "patternBeatsPerBar": 4, + "lowBandAccentPattern": [ + 0.9458, + 0.9948, + 1.0, + 0.9972 + ], + "midBandAccentPattern": [ + 0.9202, + 0.7216, + 0.8746, + 1.0 + ], + "highBandAccentPattern": [ + 0.7631, + 0.9507, + 1.0, + 0.9988 + ], + "overallAccentPattern": [ + 0.9192, + 0.9858, + 0.9986, + 1.0 + ], + "accentPattern": [ + 0.9192, + 0.9858, + 0.9986, + 1.0 + ], + "meanBeatLoudness": 0.2777, + "beatLoudnessVariation": 0.0877, + "beatCount": 32 + }, + "rhythmTimeline": { + "beatsPerBar": 4, + "stepsPerBeat": 4, + "availableBars": 8, + "selectionMethod": "representative_dsp_window", + "windows": [ + { + "bars": 8, + "startBar": 1, + "endBar": 8, + "lowBandSteps": [ + 0.1919, + 0.7809, + 0.4065, + 0.2244, + 0.3556, + 0.2264, + 0.6996, + 0.3925, + 0.4613, + 0.287, + 0.8902, + 0.4824, + 0.4657, + 0.289, + 0.945, + 0.4954, + 0.4915, + 0.3185, + 0.9843, + 0.5016, + 0.462, + 0.2885, + 0.8882, + 0.4839, + 0.4663, + 0.2908, + 0.9552, + 0.4982, + 0.493, + 0.322, + 1.0, + 0.5056, + 0.4643, + 0.291, + 0.8873, + 0.4879, + 0.49, + 0.301, + 0.9549, + 0.5006, + 0.4603, + 0.2955, + 0.9208, + 0.4807, + 0.4645, + 0.2931, + 0.8818, + 0.4932, + 0.4916, + 0.3045, + 0.97, + 0.5055, + 0.4641, + 0.2985, + 0.9345, + 0.4843, + 0.4664, + 0.2948, + 0.8732, + 0.4949, + 0.4918, + 0.305, + 0.9805, + 0.5084, + 0.4643, + 0.3014, + 0.9477, + 0.4896, + 0.4698, + 0.2981, + 0.8671, + 0.4991, + 0.4946, + 0.3081, + 0.995, + 0.5118, + 0.4652, + 0.3028, + 0.9586, + 0.4918, + 0.4916, + 0.3077, + 0.9264, + 0.5019, + 0.463, + 0.2847, + 0.92, + 0.489, + 0.4683, + 0.3065, + 0.975, + 0.4963, + 0.494, + 0.31, + 0.9235, + 0.5044, + 0.4634, + 0.2864, + 0.9281, + 0.4908, + 0.4684, + 0.3085, + 0.989, + 0.4996, + 0.4951, + 0.3131, + 0.9197, + 0.5095, + 0.466, + 0.2884, + 0.9421, + 0.4951, + 0.492, + 0.3189, + 0.9829, + 0.5015, + 0.4615, + 0.2884, + 0.8884, + 0.4837, + 0.4669, + 0.2903, + 0.9574, + 0.4992, + 0.1338, + 0.119, + 0.095, + 0.0709 + ], + "midBandSteps": [ + 0.4827, + 0.7005, + 0.8834, + 0.3987, + 0.2951, + 0.326, + 0.3929, + 0.5214, + 0.5255, + 0.68, + 0.5876, + 0.489, + 0.6229, + 0.6655, + 0.5248, + 0.6729, + 0.8384, + 0.9069, + 0.6048, + 0.7085, + 0.6843, + 0.7936, + 0.6712, + 0.815, + 0.7836, + 0.7715, + 0.7626, + 0.7847, + 0.8274, + 0.69, + 0.4426, + 0.6841, + 0.5885, + 0.6792, + 0.5018, + 0.758, + 0.7705, + 0.8929, + 0.7614, + 0.7042, + 0.7753, + 0.8307, + 0.6722, + 0.7448, + 0.8067, + 0.6647, + 0.5956, + 0.5499, + 0.7684, + 0.5654, + 0.5822, + 0.5705, + 0.4594, + 0.7251, + 0.5576, + 0.7761, + 0.79, + 0.7649, + 0.8147, + 0.8615, + 0.9166, + 1.0, + 0.7763, + 0.7177, + 0.6798, + 0.6305, + 0.6253, + 0.5601, + 0.5248, + 0.5115, + 0.6483, + 0.7981, + 0.6896, + 0.8212, + 0.6254, + 0.7949, + 0.7899, + 0.9248, + 0.7357, + 0.8013, + 0.8016, + 0.8024, + 0.7466, + 0.656, + 0.5608, + 0.7053, + 0.5733, + 0.4927, + 0.5229, + 0.6369, + 0.555, + 0.7175, + 0.6691, + 0.7893, + 0.8373, + 0.8392, + 0.7561, + 0.7791, + 0.7742, + 0.7644, + 0.7359, + 0.7662, + 0.583, + 0.8005, + 0.714, + 0.6134, + 0.6248, + 0.6621, + 0.583, + 0.7863, + 0.6769, + 0.6812, + 0.765, + 0.7635, + 0.6766, + 0.6968, + 0.7578, + 0.7886, + 0.6726, + 0.8, + 0.6311, + 0.8698, + 0.567, + 0.6144, + 0.3001, + 0.086, + 0.2322, + 0.0595 + ], + "highBandSteps": [ + 0.0029, + 0.001, + 0.0021, + 0.9952, + 0.0065, + 0.0017, + 0.0007, + 0.0013, + 0.5132, + 0.0015, + 0.0006, + 0.0015, + 0.6713, + 0.0012, + 0.001, + 0.0017, + 0.8536, + 0.001, + 0.0028, + 0.0044, + 0.5622, + 0.0045, + 0.0046, + 0.0028, + 0.735, + 0.0045, + 0.0007, + 0.0016, + 0.9265, + 0.0018, + 0.0011, + 0.0004, + 0.6169, + 0.0013, + 0.0016, + 0.001, + 0.7835, + 0.0018, + 0.001, + 0.0048, + 0.5084, + 0.0021, + 0.0032, + 0.0034, + 0.6677, + 0.003, + 0.0024, + 0.0018, + 0.8449, + 0.0019, + 0.0007, + 0.0012, + 0.567, + 0.001, + 0.0023, + 0.0012, + 0.7381, + 0.0044, + 0.0028, + 0.0044, + 0.9206, + 0.0015, + 0.0023, + 0.0024, + 0.6164, + 0.0028, + 0.001, + 0.0011, + 0.8029, + 0.0015, + 0.0009, + 0.0005, + 0.9992, + 0.003, + 0.0027, + 0.0034, + 0.6747, + 0.0014, + 0.0036, + 0.0035, + 0.8544, + 0.0049, + 0.0012, + 0.0019, + 0.5602, + 0.0009, + 0.0008, + 0.0014, + 0.7379, + 0.0016, + 0.0011, + 0.002, + 0.9323, + 0.0043, + 0.001, + 0.0018, + 0.6142, + 0.0056, + 0.0011, + 0.0031, + 0.8022, + 0.0042, + 0.0022, + 0.0009, + 1.0, + 0.002, + 0.0008, + 0.0006, + 0.6715, + 0.0007, + 0.0008, + 0.0032, + 0.8554, + 0.0042, + 0.0043, + 0.0042, + 0.561, + 0.0044, + 0.0026, + 0.0015, + 0.7325, + 0.0009, + 0.0021, + 0.0013, + 0.7988, + 0.0004, + 0.0007, + 0.0002 + ], + "overallSteps": [ + 0.2091, + 0.7941, + 0.4364, + 0.2971, + 0.3609, + 0.2357, + 0.7009, + 0.4067, + 0.505, + 0.3107, + 0.8957, + 0.493, + 0.5232, + 0.312, + 0.9465, + 0.5139, + 0.569, + 0.3515, + 0.9886, + 0.5218, + 0.5157, + 0.3174, + 0.8978, + 0.5091, + 0.5347, + 0.3186, + 0.967, + 0.5217, + 0.5744, + 0.3454, + 0.9966, + 0.5243, + 0.517, + 0.3146, + 0.8892, + 0.5103, + 0.5603, + 0.3338, + 0.9667, + 0.5206, + 0.5148, + 0.3257, + 0.9296, + 0.5029, + 0.53, + 0.316, + 0.888, + 0.5064, + 0.5655, + 0.3227, + 0.9735, + 0.5192, + 0.5081, + 0.3239, + 0.9379, + 0.5076, + 0.5353, + 0.3222, + 0.8894, + 0.522, + 0.5768, + 0.3425, + 0.9925, + 0.5286, + 0.521, + 0.3226, + 0.9536, + 0.5032, + 0.5307, + 0.3141, + 0.8759, + 0.523, + 0.5742, + 0.3376, + 1.0, + 0.5355, + 0.5303, + 0.337, + 0.9694, + 0.5162, + 0.5675, + 0.3365, + 0.9382, + 0.5195, + 0.511, + 0.3095, + 0.9243, + 0.4997, + 0.5253, + 0.3278, + 0.9772, + 0.5168, + 0.5687, + 0.3382, + 0.9394, + 0.5301, + 0.5234, + 0.3147, + 0.9411, + 0.5136, + 0.5387, + 0.3356, + 0.9922, + 0.5237, + 0.5758, + 0.3333, + 0.9263, + 0.5271, + 0.5217, + 0.3167, + 0.9504, + 0.5141, + 0.5663, + 0.3457, + 0.9905, + 0.5212, + 0.5184, + 0.3171, + 0.8979, + 0.5081, + 0.5284, + 0.3223, + 0.9605, + 0.515, + 0.1924, + 0.1201, + 0.1031, + 0.0719 + ] + } + ] + }, + "sidechainDetail": { + "pumpingStrength": 0.1895, + "pumpingRegularity": 0.0, + "pumpingRate": null, + "pumpingConfidence": 0.128, + "envelopeShape": [ + 0.728, + 0.577, + 1.0, + 0.718, + 0.735, + 0.576, + 0.99, + 0.721, + 0.74, + 0.577, + 0.979, + 0.73, + 0.741, + 0.578, + 0.995, + 0.736 + ], + "envelopeShape32": [ + 0.728, + 0.615, + 0.577, + 0.471, + 1.0, + 0.812, + 0.718, + 0.586, + 0.735, + 0.611, + 0.576, + 0.47, + 0.99, + 0.818, + 0.721, + 0.588, + 0.74, + 0.615, + 0.577, + 0.48, + 0.979, + 0.812, + 0.73, + 0.601, + 0.741, + 0.621, + 0.578, + 0.478, + 0.995, + 0.816, + 0.736, + 0.601 + ] + }, + "acidDetail": { + "isAcid": true, + "confidence": 0.69, + "resonanceLevel": 1.0, + "centroidOscillationHz": 36, + "bassRhythmDensity": 3.1 + }, + "reverbDetail": { + "rt60": null, + "isWet": false, + "tailEnergyRatio": null, + "measured": false, + "perBandRt60": null, + "preDelayMs": null + }, + "vocalDetail": { + "hasVocals": false, + "confidence": 0.37, + "vocalEnergyRatio": 0.12, + "formantStrength": 0.24, + "mfccLikelihood": 0.86, + "stemEnergyRatio": null, + "stemOtherCorrelation": null + }, + "supersawDetail": { + "isSupersaw": true, + "confidence": 0.85, + "voiceCount": 7, + "avgDetuneCents": 28.5, + "spectralComplexity": 7.2 + }, + "bassDetail": { + "averageDecayMs": 171, + "type": "punchy", + "transientRatio": 0.04, + "fundamentalHz": 113, + "transientCount": 4, + "swingPercent": 0, + "grooveType": "straight" + }, + "kickDetail": { + "isDistorted": true, + "thd": 0.35, + "harmonicRatio": 0.84, + "fundamentalHz": 96, + "kickCount": 81 + }, + "genreDetail": { + "genre": "pop", + "confidence": 0.4, + "secondaryGenre": "rock", + "genreFamily": "other", + "topScores": [ + { + "genre": "pop", + "score": 0.8043 + }, + { + "genre": "rock", + "score": 0.7809 + }, + { + "genre": "acid-techno", + "score": 0.7579 + }, + { + "genre": "dub-techno", + "score": 0.7373 + }, + { + "genre": "hiphop", + "score": 0.7278 + } + ] + }, + "effectsDetail": { + "gatingDetected": false, + "gatingRate": null, + "gatingRegularity": 0.0, + "gatingEventCount": 1 + }, + "synthesisCharacter": { + "inharmonicity": 0.1717, + "oddToEvenRatio": 3.7521 + }, + "danceability": { + "danceability": 3.7564, + "dfa": 0.2662 + }, + "structure": { + "segments": [ + { + "start": 0.0, + "end": 15.0, + "index": 0 + } + ], + "segmentCount": 1 + }, + "arrangementDetail": { + "noveltyCurve": [ + 0.0001, + 0.002, + 0.0034, + 0.0028, + 0.1408, + 0.3548, + 0.1095, + 0.0054, + 0.0073, + 0.0156, + 0.0078, + 0.0065, + 0.083, + 0.2404, + 0.1072, + 0.0072, + 0.0122, + 0.031, + 0.0152, + 0.0059, + 0.1096, + 0.4149, + 0.2025, + 0.0048, + 0.005, + 0.0111, + 0.0062, + 0.0022, + 0.2192, + 0.8956, + 0.452, + 0.002, + 0.0039, + 0.014, + 0.0056, + 0.0038, + 0.2634, + 0.5429, + 0.1421, + 0.004, + 0.0156, + 0.0334, + 0.0118, + 0.005, + 0.1407, + 0.3358, + 0.1006, + 0.0068, + 0.0177, + 0.0632, + 0.0291, + 0.0068, + 0.0847, + 0.2531, + 0.0933, + 0.0051, + 0.0058, + 0.0128, + 0.0064, + 0.0044, + 0.0814, + 0.3068, + 0.1484, + 0.003, + 0.0048, + 0.0154, + 0.0079, + 0.0014, + 0.2935, + 0.5895, + 0.1497, + 0.0034, + 0.013, + 0.0269, + 0.0118, + 0.0077, + 0.4244, + 0.8642, + 0.2254, + 0.0095, + 0.0123, + 0.0205, + 0.0086, + 0.0064, + 0.1749, + 0.3098, + 0.1063, + 0.0064, + 0.0129, + 0.0298, + 0.0116, + 0.0034, + 0.0762, + 0.2005, + 0.0691, + 0.0036, + 0.0075, + 0.0282, + 0.0129, + 0.0025, + 0.0669, + 0.2314, + 0.0345, + 0.0012, + 0.0082, + 0.0147, + 0.0037, + 0.0026, + 0.2044, + 0.4063, + 0.1042, + 0.0071, + 0.0173, + 0.0326, + 0.0152, + 0.0137, + 0.434, + 0.8735, + 0.2298, + 0.0135, + 0.0248, + 0.0375, + 0.0193, + 0.0061, + 0.3387, + 0.558, + 0.1887, + 0.0045, + 0.0118, + 0.022, + 0.0089, + 0.0035, + 0.0913, + 0.2244, + 0.0758, + 0.0016, + 0.0084, + 0.0126, + 0.0011, + 0.0011, + 0.0949, + 0.155, + 0.0135, + 0.001, + 0.0082, + 0.0141, + 0.0027, + 0.0023, + 0.27, + 0.5321, + 0.132, + 0.009, + 0.0292, + 0.041, + 0.0217, + 0.0146, + 0.4232, + 0.6379, + 0.2202, + 0.0122, + 0.04, + 0.059, + 0.0266, + 0.0099, + 0.3426, + 0.5566, + 0.1867, + 0.0016, + 0.0126, + 0.0333, + 0.0021, + 0.0019, + 0.2052, + 0.2496, + 0.0011, + 0.0015, + 0.005, + 0.0073, + 0.0006, + 0.0007, + 0.0625, + 0.0948, + 0.0035, + 0.0012, + 0.0083, + 0.0136, + 0.003, + 0.0026, + 0.1722, + 0.2346, + 0.0678, + 0.0065, + 0.0156, + 0.0187, + 0.0141, + 0.0136, + 0.5026, + 0.7522, + 0.2616, + 0.017, + 0.022, + 0.026, + 0.0165, + 0.0113, + 0.4579, + 0.4721, + 0.0018, + 0.0019, + 0.0204, + 0.0221, + 0.0029, + 0.0029, + 0.2559, + 0.2777, + 0.0005, + 0.0007, + 0.0098, + 0.0151, + 0.0008, + 0.0007, + 0.1328, + 0.1252, + 0.0021, + 0.001, + 0.0082, + 0.0093, + 0.0032, + 0.0028, + 0.1306, + 0.1701, + 0.0452, + 0.0079, + 0.0317, + 0.0418, + 0.0193, + 0.014, + 0.3853, + 0.5636, + 0.0162, + 0.0165, + 0.04, + 0.0412, + 0.0109, + 0.0097, + 0.6468, + 0.6589, + 0.0035, + 0.0036, + 0.0128, + 0.0134, + 0.0007, + 0.0006, + 0.3073, + 0.3298, + 0.0005, + 0.0004 + ], + "noveltyPeaks": [ + { + "time": 1.695, + "strength": 0.8956 + }, + { + "time": 4.505, + "strength": 0.8642 + }, + { + "time": 6.85, + "strength": 0.8735 + }, + { + "time": 9.195, + "strength": 0.8436 + }, + { + "time": 11.54, + "strength": 1.0 + }, + { + "time": 14.35, + "strength": 0.8664 + } + ], + "noveltyMean": 0.1025, + "noveltyStdDev": 0.1735 + }, + "segmentLoudness": [ + { + "segmentIndex": 0, + "start": 0.0, + "end": 15.0, + "lufs": -9.6, + "lra": 0.1 + } + ], + "segmentSpectral": [ + { + "segmentIndex": 0, + "barkBands": [ + -25.3316, + -11.2894, + -9.0312, + -17.704, + -30.1847, + -38.3175, + -25.6778, + -24.9797, + -25.3476, + -28.4964, + -33.0865, + -35.0749, + -32.5394, + -35.1704, + -37.2281, + -38.2025, + -38.4162, + -40.1596, + -40.8253, + -41.9961, + -39.5266, + -36.6372, + -36.9955, + -32.9441 + ], + "spectralCentroid": 1143.7, + "spectralRolloff": 1417.9, + "stereoWidth": 0.0, + "stereoCorrelation": 1.0 + } + ], + "segmentStereo": [ + { + "segmentIndex": 0, + "stereoWidth": 0.0, + "stereoCorrelation": 1.0 + } + ], + "segmentKey": [ + { + "segmentIndex": 0, + "key": "A Minor", + "keyConfidence": 0.67 + } + ], + "chordDetail": { + "chordSequence": [ + "F", + "F", + "F", + "F", + "F", + "F", + "F", + "F", + "F", + "Am", + "F", + "F", + "F", + "F", + "F", + "F", + "Am", + "F", + "F", + "F", + "F", + "Am", + "F", + "F", + "F", + "F", + "F", + "F", + "F", + "F", + "F", + "F" + ], + "chordStrength": 0.6324, + "progression": [ + "F", + "G", + "F", + "Am", + "G", + "F", + "G", + "F", + "Am", + "F", + "Am", + "F", + "Am", + "F", + "Em", + "F" + ], + "dominantChords": [ + "F", + "G", + "Am", + "Em" + ], + "chordTimeline": [ + { + "startSec": 0.0, + "endSec": 15.0, + "label": "Am", + "labelLong": "A minor", + "confidence": 0.5384 + } + ], + "chordChangeCount": 0, + "chordTimelineSource": "librosa_viterbi", + "chordTimelineAgreement": false + }, + "perceptual": { + "sharpness": 0.0596, + "roughness": 0.0 + }, + "essentiaFeatures": { + "zeroCrossingRate": 0.0346, + "hfc": 149.7905, + "spectralComplexity": 8.8037, + "dissonance": 0.0 + } +} \ No newline at end of file diff --git a/apps/backend/tests/fixtures/recommendation_tracks/dnb_reese_174/README.md b/apps/backend/tests/fixtures/recommendation_tracks/dnb_reese_174/README.md new file mode 100644 index 00000000..bed30883 --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/dnb_reese_174/README.md @@ -0,0 +1,26 @@ +# dnb_reese_174 + +**Genre:** drum & bass · **Tempo:** 174 BPM · **Key:** F minor · **Render:** 48 kHz / 24-bit, 16 s loop + +## What this fixture isolates + +Drum & bass at 174 BPM built on the two genre pillars: + +1. **The Reese bass** — detuned-unison saws in `Wavetable` (Unison 40 %) through a + lowpass, saturated for harmonics. Recovering it means recommending a + detuned/unison synth + drive, not a clean sub. +2. **Sampled breaks** — `Drum Rack` kick + amen-style breaks with hard bus + compression (fast attack, short release). + +Low end mono'd via `Utility`. Tests fast-tempo handling and the supersaw-like +detection on the Reese (`supersawDetail.isSupersaw`). Covers all seven domains. + +## Answer key + +`manifest.json` → `deviceSpec`. Build verbatim in Live 12 (checklist in +`../README.md`), render to `audio.flac`, store `phase1_fingerprint.json`. + +## Status +- [x] Catalog-valid spec authored +- [ ] **NEEDS-FIXTURE:** rendered `audio.flac` +- [ ] **NEEDS-FIXTURE:** stored `phase1_fingerprint.json` diff --git a/apps/backend/tests/fixtures/recommendation_tracks/dnb_reese_174/audio_melody.mid b/apps/backend/tests/fixtures/recommendation_tracks/dnb_reese_174/audio_melody.mid new file mode 100644 index 00000000..a1f6e780 Binary files /dev/null and b/apps/backend/tests/fixtures/recommendation_tracks/dnb_reese_174/audio_melody.mid differ diff --git a/apps/backend/tests/fixtures/recommendation_tracks/dnb_reese_174/manifest.json b/apps/backend/tests/fixtures/recommendation_tracks/dnb_reese_174/manifest.json new file mode 100644 index 00000000..3d4ff115 --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/dnb_reese_174/manifest.json @@ -0,0 +1,131 @@ +{ + "schemaVersion": "recommendation-fixture.v1", + "id": "dnb_reese_174", + "title": "Drum & bass — Reese bass, sampled breaks, hard compression", + "genre": "drum and bass", + "audioPath": "audio.flac", + "phase1FingerprintPath": "phase1_fingerprint.json", + "phase1Fingerprint": null, + "render": { + "sampleRateHz": 48000, + "bitDepth": 24, + "lengthSeconds": 16, + "bpm": 174, + "key": "F minor", + "notes": "8-bar loop at 174 BPM. Detuned-unison Reese bass (Wavetable), sampled kick + breaks (Drum Rack), a held stab. Render the full loop to one stereo file, no export normalization." + }, + "deviceSpec": { + "kick": [ + { + "device": "Drum Rack", + "family": "NATIVE", + "role": "Sampled kick", + "parameters": [ + { "name": "Pad Volume", "value": "-3 dB" }, + { "name": "Pad Pitch", "value": "0" } + ] + } + ], + "bass": [ + { + "device": "Wavetable", + "family": "NATIVE", + "role": "Reese bass (detuned-unison saws)", + "parameters": [ + { "name": "Oscillator 1 Wavetable", "value": "Basic Shapes" }, + { "name": "Oscillator 2 Wavetable", "value": "Basic Shapes" }, + { "name": "Unison Mode", "value": "Classic" }, + { "name": "Unison Amount", "value": "40%" }, + { "name": "Filter Type", "value": "Lowpass" }, + { "name": "Filter Frequency", "value": "800 Hz" }, + { "name": "Filter Resonance", "value": "20%" } + ] + } + ], + "melody": [ + { + "device": "Operator", + "family": "NATIVE", + "role": "Held stab", + "parameters": [ + { "name": "Oscillator A Waveform", "value": "Saw" }, + { "name": "Amp Envelope Decay", "value": "400 ms" } + ] + } + ], + "groove": [ + { + "device": "Drum Rack", + "family": "NATIVE", + "role": "Amen-style breaks", + "parameters": [ + { "name": "Pad Volume", "value": "-4 dB" }, + { "name": "Choke Group", "value": "1" } + ] + } + ], + "fx": [ + { + "device": "Compressor", + "family": "NATIVE", + "role": "Break bus compression", + "parameters": [ + { "name": "Threshold", "value": "-15 dB" }, + { "name": "Ratio", "value": "4:1" }, + { "name": "Attack", "value": "5 ms" }, + { "name": "Release", "value": "80 ms" } + ] + }, + { + "device": "Saturator", + "family": "NATIVE", + "role": "Reese drive / harmonics", + "parameters": [ + { "name": "Drive", "value": "10 dB" }, + { "name": "Type", "value": "Soft Sine" }, + { "name": "Dry/Wet", "value": "100%" } + ] + } + ], + "stereo": [ + { + "device": "Utility", + "family": "NATIVE", + "role": "Low-end mono / break width", + "parameters": [ + { "name": "Bass Mono", "value": "On" }, + { "name": "Stereo Width", "value": "115%" } + ] + } + ], + "master": [ + { + "device": "Glue Compressor", + "family": "NATIVE", + "role": "Bus glue", + "parameters": [ + { "name": "Threshold", "value": "-14 dB" }, + { "name": "Ratio", "value": "4:1" }, + { "name": "Attack", "value": "1 ms" }, + { "name": "Release", "value": "Auto" }, + { "name": "Makeup", "value": "2 dB" } + ] + }, + { + "device": "Limiter", + "family": "NATIVE", + "role": "Master ceiling", + "parameters": [ + { "name": "Ceiling", "value": "-0.3 dB" } + ] + } + ] + }, + "measurableIntent": { + "bpm": { "target": 174, "tolerance": 1, "direction": "exact" }, + "key": { "target": "F minor" }, + "lufsIntegrated": { "target": -8, "tolerance": 2, "unit": "LUFS" }, + "truePeak": { "target": 1.0, "tolerance": 0.05 }, + "supersawDetail.isSupersaw": { "equals": true, "intent": "detuned-unison Reese should read as supersaw-like" } + } +} diff --git a/apps/backend/tests/fixtures/recommendation_tracks/dnb_reese_174/phase1_fingerprint.json b/apps/backend/tests/fixtures/recommendation_tracks/dnb_reese_174/phase1_fingerprint.json new file mode 100644 index 00000000..a150b9f9 --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/dnb_reese_174/phase1_fingerprint.json @@ -0,0 +1,4149 @@ +{ + "_synthetic": true, + "_note": "Phase 1 of a numpy PROXY render, NOT an Ableton render. Replace with a real Live render's fingerprint for an authoritative verdict.", + "bpm": 116.3, + "bpmConfidence": 3.06, + "bpmPercival": 86.9, + "bpmAgreement": false, + "bpmDoubletime": false, + "bpmSource": "rhythm_extractor", + "bpmRawOriginal": 116.3, + "key": "F Minor", + "keyConfidence": 0.59, + "keyProfile": "edma", + "tuningFrequency": 444.09, + "tuningCents": 16.0, + "timeSignature": "5/4", + "timeSignatureSource": "onset_autocorrelation", + "timeSignatureConfidence": 0.67, + "durationSeconds": 11.0, + "sampleRate": 44100, + "lufsIntegrated": -8.1, + "lufsRange": 0.1, + "lufsMomentaryMax": -7.3, + "lufsShortTermMax": -8.0, + "lufsCurve": { + "shortTerm": [ + { + "t": 0.0, + "lufs": -8.0 + }, + { + "t": 0.1, + "lufs": -8.2 + }, + { + "t": 0.2, + "lufs": -8.1 + }, + { + "t": 0.3, + "lufs": -8.1 + }, + { + "t": 0.4, + "lufs": -8.1 + }, + { + "t": 0.5, + "lufs": -8.1 + }, + { + "t": 0.6, + "lufs": -8.1 + }, + { + "t": 0.7, + "lufs": -8.0 + }, + { + "t": 0.8, + "lufs": -8.1 + }, + { + "t": 0.9, + "lufs": -8.1 + }, + { + "t": 1.0, + "lufs": -8.1 + }, + { + "t": 1.1, + "lufs": -8.2 + }, + { + "t": 1.2, + "lufs": -8.1 + }, + { + "t": 1.3, + "lufs": -8.1 + }, + { + "t": 1.4, + "lufs": -8.1 + }, + { + "t": 1.5, + "lufs": -8.1 + }, + { + "t": 1.6, + "lufs": -8.1 + }, + { + "t": 1.7, + "lufs": -8.0 + }, + { + "t": 1.8, + "lufs": -8.1 + }, + { + "t": 1.9, + "lufs": -8.1 + }, + { + "t": 2.0, + "lufs": -8.2 + }, + { + "t": 2.1, + "lufs": -8.1 + }, + { + "t": 2.2, + "lufs": -8.1 + }, + { + "t": 2.3, + "lufs": -8.2 + }, + { + "t": 2.4, + "lufs": -8.1 + }, + { + "t": 2.5, + "lufs": -8.1 + }, + { + "t": 2.6, + "lufs": -8.1 + }, + { + "t": 2.7, + "lufs": -8.1 + }, + { + "t": 2.8, + "lufs": -8.1 + }, + { + "t": 2.9, + "lufs": -8.1 + }, + { + "t": 3.0, + "lufs": -8.2 + }, + { + "t": 3.1, + "lufs": -8.1 + }, + { + "t": 3.2, + "lufs": -8.2 + }, + { + "t": 3.3, + "lufs": -8.1 + }, + { + "t": 3.4, + "lufs": -8.1 + }, + { + "t": 3.5, + "lufs": -8.1 + }, + { + "t": 3.6, + "lufs": -8.1 + }, + { + "t": 3.7, + "lufs": -8.2 + }, + { + "t": 3.8, + "lufs": -8.1 + }, + { + "t": 3.9, + "lufs": -8.1 + }, + { + "t": 4.0, + "lufs": -8.2 + }, + { + "t": 4.1, + "lufs": -8.1 + }, + { + "t": 4.2, + "lufs": -8.2 + }, + { + "t": 4.3, + "lufs": -8.1 + }, + { + "t": 4.4, + "lufs": -8.2 + }, + { + "t": 4.5, + "lufs": -8.1 + }, + { + "t": 4.6, + "lufs": -8.1 + }, + { + "t": 4.7, + "lufs": -8.2 + }, + { + "t": 4.8, + "lufs": -8.1 + }, + { + "t": 4.9, + "lufs": -8.1 + }, + { + "t": 5.0, + "lufs": -8.1 + }, + { + "t": 5.1, + "lufs": -8.2 + }, + { + "t": 5.2, + "lufs": -8.1 + }, + { + "t": 5.3, + "lufs": -8.2 + }, + { + "t": 5.4, + "lufs": -8.2 + }, + { + "t": 5.5, + "lufs": -8.1 + }, + { + "t": 5.6, + "lufs": -8.1 + }, + { + "t": 5.7, + "lufs": -8.1 + }, + { + "t": 5.8, + "lufs": -8.1 + }, + { + "t": 5.9, + "lufs": -8.1 + }, + { + "t": 6.0, + "lufs": -8.1 + }, + { + "t": 6.1, + "lufs": -8.2 + }, + { + "t": 6.2, + "lufs": -8.1 + }, + { + "t": 6.3, + "lufs": -8.2 + }, + { + "t": 6.4, + "lufs": -8.1 + }, + { + "t": 6.5, + "lufs": -8.1 + }, + { + "t": 6.6, + "lufs": -8.1 + }, + { + "t": 6.7, + "lufs": -8.1 + }, + { + "t": 6.8, + "lufs": -8.2 + }, + { + "t": 6.9, + "lufs": -8.1 + }, + { + "t": 7.0, + "lufs": -8.1 + }, + { + "t": 7.1, + "lufs": -8.2 + }, + { + "t": 7.2, + "lufs": -8.1 + }, + { + "t": 7.3, + "lufs": -8.2 + }, + { + "t": 7.4, + "lufs": -8.1 + }, + { + "t": 7.5, + "lufs": -8.2 + }, + { + "t": 7.6, + "lufs": -8.1 + }, + { + "t": 7.7, + "lufs": -8.1 + }, + { + "t": 7.8, + "lufs": -8.2 + }, + { + "t": 7.9, + "lufs": -8.1 + }, + { + "t": 8.0, + "lufs": -8.1 + }, + { + "t": 8.1, + "lufs": -8.2 + } + ], + "momentary": [ + { + "t": 0.0, + "lufs": -7.7 + }, + { + "t": 0.1, + "lufs": -8.6 + }, + { + "t": 0.2, + "lufs": -8.4 + }, + { + "t": 0.3, + "lufs": -8.6 + }, + { + "t": 0.4, + "lufs": -8.3 + }, + { + "t": 0.5, + "lufs": -7.8 + }, + { + "t": 0.6, + "lufs": -8.5 + }, + { + "t": 0.7, + "lufs": -7.5 + }, + { + "t": 0.8, + "lufs": -7.9 + }, + { + "t": 0.9, + "lufs": -7.8 + }, + { + "t": 1.0, + "lufs": -7.9 + }, + { + "t": 1.1, + "lufs": -8.5 + }, + { + "t": 1.2, + "lufs": -7.9 + }, + { + "t": 1.3, + "lufs": -8.7 + }, + { + "t": 1.4, + "lufs": -8.3 + }, + { + "t": 1.5, + "lufs": -8.4 + }, + { + "t": 1.6, + "lufs": -8.4 + }, + { + "t": 1.7, + "lufs": -7.9 + }, + { + "t": 1.8, + "lufs": -7.8 + }, + { + "t": 1.9, + "lufs": -7.3 + }, + { + "t": 2.0, + "lufs": -8.0 + }, + { + "t": 2.1, + "lufs": -8.0 + }, + { + "t": 2.2, + "lufs": -8.2 + }, + { + "t": 2.3, + "lufs": -8.6 + }, + { + "t": 2.4, + "lufs": -8.3 + }, + { + "t": 2.5, + "lufs": -8.4 + }, + { + "t": 2.6, + "lufs": -8.1 + }, + { + "t": 2.7, + "lufs": -8.5 + }, + { + "t": 2.8, + "lufs": -7.7 + }, + { + "t": 2.9, + "lufs": -7.4 + }, + { + "t": 3.0, + "lufs": -7.9 + }, + { + "t": 3.1, + "lufs": -7.8 + }, + { + "t": 3.2, + "lufs": -8.6 + }, + { + "t": 3.3, + "lufs": -8.4 + }, + { + "t": 3.4, + "lufs": -8.6 + }, + { + "t": 3.5, + "lufs": -8.3 + }, + { + "t": 3.6, + "lufs": -7.9 + }, + { + "t": 3.7, + "lufs": -8.5 + }, + { + "t": 3.8, + "lufs": -7.6 + }, + { + "t": 3.9, + "lufs": -7.9 + }, + { + "t": 4.0, + "lufs": -7.8 + }, + { + "t": 4.1, + "lufs": -7.8 + }, + { + "t": 4.2, + "lufs": -8.5 + }, + { + "t": 4.3, + "lufs": -7.9 + }, + { + "t": 4.4, + "lufs": -8.7 + }, + { + "t": 4.5, + "lufs": -8.3 + }, + { + "t": 4.6, + "lufs": -8.6 + }, + { + "t": 4.7, + "lufs": -8.4 + }, + { + "t": 4.8, + "lufs": -8.1 + }, + { + "t": 4.9, + "lufs": -7.8 + }, + { + "t": 5.0, + "lufs": -7.3 + }, + { + "t": 5.1, + "lufs": -8.0 + }, + { + "t": 5.2, + "lufs": -7.9 + }, + { + "t": 5.3, + "lufs": -8.3 + }, + { + "t": 5.4, + "lufs": -8.5 + }, + { + "t": 5.5, + "lufs": -8.4 + }, + { + "t": 5.6, + "lufs": -8.5 + }, + { + "t": 5.7, + "lufs": -8.1 + }, + { + "t": 5.8, + "lufs": -8.6 + }, + { + "t": 5.9, + "lufs": -7.8 + }, + { + "t": 6.0, + "lufs": -7.5 + }, + { + "t": 6.1, + "lufs": -7.9 + }, + { + "t": 6.2, + "lufs": -7.8 + }, + { + "t": 6.3, + "lufs": -8.5 + }, + { + "t": 6.4, + "lufs": -8.3 + }, + { + "t": 6.5, + "lufs": -8.7 + }, + { + "t": 6.6, + "lufs": -8.3 + }, + { + "t": 6.7, + "lufs": -8.0 + }, + { + "t": 6.8, + "lufs": -8.5 + }, + { + "t": 6.9, + "lufs": -7.6 + }, + { + "t": 7.0, + "lufs": -7.9 + }, + { + "t": 7.1, + "lufs": -7.7 + }, + { + "t": 7.2, + "lufs": -7.8 + }, + { + "t": 7.3, + "lufs": -8.5 + }, + { + "t": 7.4, + "lufs": -7.9 + }, + { + "t": 7.5, + "lufs": -8.6 + }, + { + "t": 7.6, + "lufs": -8.4 + }, + { + "t": 7.7, + "lufs": -8.6 + }, + { + "t": 7.8, + "lufs": -8.4 + }, + { + "t": 7.9, + "lufs": -8.2 + }, + { + "t": 8.0, + "lufs": -7.8 + }, + { + "t": 8.1, + "lufs": -7.3 + }, + { + "t": 8.2, + "lufs": -8.0 + }, + { + "t": 8.3, + "lufs": -7.9 + }, + { + "t": 8.4, + "lufs": -8.3 + }, + { + "t": 8.5, + "lufs": -8.5 + }, + { + "t": 8.6, + "lufs": -8.3 + }, + { + "t": 8.7, + "lufs": -8.5 + }, + { + "t": 8.8, + "lufs": -8.1 + }, + { + "t": 8.9, + "lufs": -8.6 + }, + { + "t": 9.0, + "lufs": -7.8 + }, + { + "t": 9.1, + "lufs": -7.6 + }, + { + "t": 9.2, + "lufs": -7.9 + }, + { + "t": 9.3, + "lufs": -7.8 + }, + { + "t": 9.4, + "lufs": -8.5 + }, + { + "t": 9.5, + "lufs": -8.2 + }, + { + "t": 9.6, + "lufs": -8.7 + }, + { + "t": 9.7, + "lufs": -8.3 + }, + { + "t": 9.8, + "lufs": -8.0 + }, + { + "t": 9.9, + "lufs": -8.5 + }, + { + "t": 10.0, + "lufs": -7.6 + }, + { + "t": 10.1, + "lufs": -7.9 + }, + { + "t": 10.2, + "lufs": -7.7 + }, + { + "t": 10.3, + "lufs": -7.8 + }, + { + "t": 10.4, + "lufs": -8.4 + }, + { + "t": 10.5, + "lufs": -7.8 + }, + { + "t": 10.6, + "lufs": -8.6 + }, + { + "t": 10.7, + "lufs": -9.4 + } + ] + }, + "truePeak": 1.1, + "plr": 9.2, + "crestFactor": 9.0, + "dynamicSpread": 27.14, + "dynamicCharacter": { + "dynamicComplexity": 1.1603, + "loudnessDb": -16.2965, + "loudnessVariation": -16.2965, + "spectralFlatness": 0.1378, + "logAttackTime": -5.0, + "attackTimeStdDev": 0.0 + }, + "textureCharacter": { + "textureScore": 0.3756, + "lowBandFlatness": 0.3786, + "midBandFlatness": 0.3994, + "highBandFlatness": 0.3686, + "inharmonicity": 0.0875 + }, + "stereoDetail": { + "stereoWidth": 0.0, + "stereoCorrelation": 1.0, + "subBassCorrelation": 1.0, + "subBassMono": true, + "correlationCurve": [ + { + "t": 0.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 1.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 2.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 3.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 4.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 5.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 6.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 7.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 8.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 9.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 10.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 11.5, + "full": 1.0, + "sub": 1.0 + } + ], + "bandCorrelations": { + "subBass": 1.0, + "lowBass": 1.0, + "lowMids": 1.0, + "mids": 1.0, + "upperMids": 1.0, + "highs": 1.0, + "brilliance": 1.0 + } + }, + "monoCompatible": true, + "spectralBalance": { + "subBass": -6.7, + "lowBass": -7.2, + "lowMids": -23.5, + "mids": -22.4, + "upperMids": -31.3, + "highs": -27.3, + "brilliance": -19.6 + }, + "spectralBalanceTimeSeries": [ + { + "t": 0.02, + "subBass": -3.7, + "lowBass": -2.9, + "lowMids": -21.1, + "mids": -24.5, + "upperMids": -34.7, + "highs": -49.8, + "brilliance": -77.8 + }, + { + "t": 0.09, + "subBass": -4.8, + "lowBass": -9.1, + "lowMids": -21.3, + "mids": -24.5, + "upperMids": -33.7, + "highs": -48.7, + "brilliance": -77.8 + }, + { + "t": 0.16, + "subBass": -5.8, + "lowBass": -8.5, + "lowMids": -26.1, + "mids": -22.0, + "upperMids": -28.7, + "highs": -22.3, + "brilliance": -14.3 + }, + { + "t": 0.23, + "subBass": -7.5, + "lowBass": -7.2, + "lowMids": -37.6, + "mids": -21.3, + "upperMids": -30.8, + "highs": -25.9, + "brilliance": -18.3 + }, + { + "t": 0.3, + "subBass": -9.7, + "lowBass": -8.4, + "lowMids": -43.6, + "mids": -20.1, + "upperMids": -32.8, + "highs": -43.5, + "brilliance": -77.8 + }, + { + "t": 0.37, + "subBass": -6.7, + "lowBass": -5.5, + "lowMids": -20.2, + "mids": -23.9, + "upperMids": -33.5, + "highs": -49.9, + "brilliance": -53.0 + }, + { + "t": 0.44, + "subBass": -5.4, + "lowBass": -7.9, + "lowMids": -21.0, + "mids": -24.8, + "upperMids": -34.7, + "highs": -69.4, + "brilliance": -78.5 + }, + { + "t": 0.51, + "subBass": -6.9, + "lowBass": -8.5, + "lowMids": -26.8, + "mids": -21.4, + "upperMids": -28.9, + "highs": -22.3, + "brilliance": -14.2 + }, + { + "t": 0.58, + "subBass": -7.2, + "lowBass": -8.1, + "lowMids": -39.3, + "mids": -20.8, + "upperMids": -30.8, + "highs": -26.5, + "brilliance": -19.2 + }, + { + "t": 0.65, + "subBass": -8.3, + "lowBass": -9.0, + "lowMids": -44.1, + "mids": -20.5, + "upperMids": -33.2, + "highs": -43.9, + "brilliance": -72.1 + }, + { + "t": 0.72, + "subBass": -6.0, + "lowBass": -5.0, + "lowMids": -20.3, + "mids": -24.0, + "upperMids": -34.3, + "highs": -52.0, + "brilliance": -55.3 + }, + { + "t": 0.79, + "subBass": -6.2, + "lowBass": -9.1, + "lowMids": -20.9, + "mids": -25.1, + "upperMids": -33.1, + "highs": -66.5, + "brilliance": -74.5 + }, + { + "t": 0.86, + "subBass": -7.7, + "lowBass": -8.1, + "lowMids": -27.7, + "mids": -21.1, + "upperMids": -28.0, + "highs": -21.5, + "brilliance": -13.7 + }, + { + "t": 0.93, + "subBass": -9.0, + "lowBass": -7.3, + "lowMids": -24.2, + "mids": -22.5, + "upperMids": -31.5, + "highs": -27.8, + "brilliance": -20.3 + }, + { + "t": 1.0, + "subBass": -10.8, + "lowBass": -8.3, + "lowMids": -21.8, + "mids": -26.2, + "upperMids": -34.0, + "highs": -56.6, + "brilliance": -59.7 + }, + { + "t": 1.07, + "subBass": -3.1, + "lowBass": -3.0, + "lowMids": -20.9, + "mids": -25.3, + "upperMids": -35.3, + "highs": -53.2, + "brilliance": -56.0 + }, + { + "t": 1.14, + "subBass": -5.3, + "lowBass": -9.2, + "lowMids": -33.5, + "mids": -20.0, + "upperMids": -32.1, + "highs": -44.3, + "brilliance": -73.2 + }, + { + "t": 1.21, + "subBass": -6.6, + "lowBass": -8.3, + "lowMids": -22.3, + "mids": -23.7, + "upperMids": -28.2, + "highs": -20.9, + "brilliance": -13.1 + }, + { + "t": 1.28, + "subBass": -8.3, + "lowBass": -7.5, + "lowMids": -21.3, + "mids": -25.2, + "upperMids": -32.0, + "highs": -28.8, + "brilliance": -21.2 + }, + { + "t": 1.35, + "subBass": -9.4, + "lowBass": -8.0, + "lowMids": -22.3, + "mids": -26.1, + "upperMids": -34.2, + "highs": -51.7, + "brilliance": -55.2 + }, + { + "t": 1.42, + "subBass": -7.4, + "lowBass": -7.4, + "lowMids": -29.8, + "mids": -19.5, + "upperMids": -31.4, + "highs": -44.9, + "brilliance": -59.0 + }, + { + "t": 1.49, + "subBass": -6.1, + "lowBass": -8.4, + "lowMids": -20.9, + "mids": -23.8, + "upperMids": -33.2, + "highs": -48.2, + "brilliance": -82.8 + }, + { + "t": 1.56, + "subBass": -6.8, + "lowBass": -8.1, + "lowMids": -21.2, + "mids": -24.8, + "upperMids": -27.7, + "highs": -20.6, + "brilliance": -13.0 + }, + { + "t": 1.63, + "subBass": -5.7, + "lowBass": -7.9, + "lowMids": -21.5, + "mids": -25.2, + "upperMids": -33.2, + "highs": -30.0, + "brilliance": -22.6 + }, + { + "t": 1.7, + "subBass": -7.9, + "lowBass": -8.2, + "lowMids": -22.7, + "mids": -25.2, + "upperMids": -35.4, + "highs": -51.9, + "brilliance": -59.5 + }, + { + "t": 1.76, + "subBass": -5.8, + "lowBass": -5.5, + "lowMids": -33.4, + "mids": -20.4, + "upperMids": -33.1, + "highs": -43.4, + "brilliance": -59.0 + }, + { + "t": 1.83, + "subBass": -5.0, + "lowBass": -7.9, + "lowMids": -34.9, + "mids": -20.0, + "upperMids": -31.9, + "highs": -44.0, + "brilliance": -67.8 + }, + { + "t": 1.9, + "subBass": -7.8, + "lowBass": -7.8, + "lowMids": -36.4, + "mids": -20.0, + "upperMids": -26.8, + "highs": -20.3, + "brilliance": -12.7 + }, + { + "t": 1.97, + "subBass": -9.3, + "lowBass": -7.5, + "lowMids": -22.9, + "mids": -23.0, + "upperMids": -32.5, + "highs": -31.0, + "brilliance": -23.6 + }, + { + "t": 2.04, + "subBass": -10.4, + "lowBass": -7.5, + "lowMids": -23.2, + "mids": -24.3, + "upperMids": -33.9, + "highs": -45.9, + "brilliance": -52.3 + }, + { + "t": 2.11, + "subBass": -3.6, + "lowBass": -3.2, + "lowMids": -28.2, + "mids": -22.0, + "upperMids": -34.0, + "highs": -46.0, + "brilliance": -64.9 + }, + { + "t": 2.18, + "subBass": -4.1, + "lowBass": -8.5, + "lowMids": -20.9, + "mids": -24.7, + "upperMids": -32.8, + "highs": -61.9, + "brilliance": -72.2 + }, + { + "t": 2.25, + "subBass": -6.9, + "lowBass": -7.9, + "lowMids": -21.1, + "mids": -24.5, + "upperMids": -28.0, + "highs": -20.6, + "brilliance": -12.9 + }, + { + "t": 2.32, + "subBass": -8.0, + "lowBass": -7.5, + "lowMids": -27.1, + "mids": -20.9, + "upperMids": -31.8, + "highs": -32.5, + "brilliance": -25.0 + }, + { + "t": 2.39, + "subBass": -10.5, + "lowBass": -6.8, + "lowMids": -24.2, + "mids": -21.9, + "upperMids": -33.2, + "highs": -45.5, + "brilliance": -51.7 + }, + { + "t": 2.46, + "subBass": -5.7, + "lowBass": -6.7, + "lowMids": -21.7, + "mids": -25.6, + "upperMids": -35.1, + "highs": -60.8, + "brilliance": -63.0 + }, + { + "t": 2.53, + "subBass": -6.1, + "lowBass": -8.4, + "lowMids": -20.5, + "mids": -24.7, + "upperMids": -32.6, + "highs": -67.2, + "brilliance": -84.4 + }, + { + "t": 2.6, + "subBass": -7.0, + "lowBass": -8.3, + "lowMids": -21.1, + "mids": -24.9, + "upperMids": -27.8, + "highs": -21.1, + "brilliance": -13.1 + }, + { + "t": 2.67, + "subBass": -7.8, + "lowBass": -8.3, + "lowMids": -21.1, + "mids": -24.1, + "upperMids": -33.0, + "highs": -34.4, + "brilliance": -26.8 + }, + { + "t": 2.74, + "subBass": -8.0, + "lowBass": -7.2, + "lowMids": -24.1, + "mids": -22.3, + "upperMids": -33.6, + "highs": -45.3, + "brilliance": -59.0 + }, + { + "t": 2.81, + "subBass": -5.8, + "lowBass": -6.3, + "lowMids": -32.4, + "mids": -21.9, + "upperMids": -34.4, + "highs": -45.0, + "brilliance": -57.5 + }, + { + "t": 2.88, + "subBass": -6.4, + "lowBass": -9.0, + "lowMids": -20.6, + "mids": -24.3, + "upperMids": -33.9, + "highs": -70.0, + "brilliance": -74.2 + }, + { + "t": 2.95, + "subBass": -8.4, + "lowBass": -7.6, + "lowMids": -21.2, + "mids": -24.7, + "upperMids": -27.6, + "highs": -20.9, + "brilliance": -13.0 + }, + { + "t": 3.02, + "subBass": -9.4, + "lowBass": -7.6, + "lowMids": -20.8, + "mids": -24.8, + "upperMids": -32.5, + "highs": -37.2, + "brilliance": -29.4 + }, + { + "t": 3.09, + "subBass": -9.4, + "lowBass": -6.4, + "lowMids": -24.8, + "mids": -22.3, + "upperMids": -33.3, + "highs": -44.9, + "brilliance": -54.3 + }, + { + "t": 3.16, + "subBass": -2.5, + "lowBass": -3.8, + "lowMids": -27.5, + "mids": -23.5, + "upperMids": -35.8, + "highs": -46.8, + "brilliance": -61.4 + }, + { + "t": 3.23, + "subBass": -6.0, + "lowBass": -9.6, + "lowMids": -20.8, + "mids": -24.7, + "upperMids": -34.7, + "highs": -70.4, + "brilliance": -79.6 + }, + { + "t": 3.3, + "subBass": -6.8, + "lowBass": -7.6, + "lowMids": -20.9, + "mids": -24.1, + "upperMids": -27.3, + "highs": -20.5, + "brilliance": -12.8 + }, + { + "t": 3.37, + "subBass": -8.6, + "lowBass": -7.7, + "lowMids": -20.6, + "mids": -24.3, + "upperMids": -34.1, + "highs": -41.8, + "brilliance": -34.1 + }, + { + "t": 3.44, + "subBass": -10.4, + "lowBass": -7.3, + "lowMids": -20.9, + "mids": -25.0, + "upperMids": -34.5, + "highs": -52.6, + "brilliance": -54.7 + }, + { + "t": 3.51, + "subBass": -5.5, + "lowBass": -7.3, + "lowMids": -23.0, + "mids": -24.4, + "upperMids": -34.8, + "highs": -50.7, + "brilliance": -63.0 + }, + { + "t": 3.58, + "subBass": -6.7, + "lowBass": -8.8, + "lowMids": -37.5, + "mids": -20.3, + "upperMids": -32.4, + "highs": -44.4, + "brilliance": -65.3 + }, + { + "t": 3.65, + "subBass": -6.0, + "lowBass": -7.7, + "lowMids": -20.9, + "mids": -24.0, + "upperMids": -27.0, + "highs": -20.3, + "brilliance": -12.6 + }, + { + "t": 3.72, + "subBass": -6.4, + "lowBass": -8.3, + "lowMids": -20.6, + "mids": -24.4, + "upperMids": -34.3, + "highs": -45.7, + "brilliance": -37.5 + }, + { + "t": 3.78, + "subBass": -8.9, + "lowBass": -6.8, + "lowMids": -21.7, + "mids": -25.2, + "upperMids": -34.4, + "highs": -50.1, + "brilliance": -60.1 + }, + { + "t": 3.85, + "subBass": -4.7, + "lowBass": -6.6, + "lowMids": -22.4, + "mids": -25.5, + "upperMids": -34.7, + "highs": -48.8, + "brilliance": -58.0 + }, + { + "t": 3.92, + "subBass": -5.7, + "lowBass": -8.5, + "lowMids": -21.9, + "mids": -25.8, + "upperMids": -34.5, + "highs": -46.8, + "brilliance": -42.7 + }, + { + "t": 3.99, + "subBass": -8.5, + "lowBass": -7.2, + "lowMids": -20.7, + "mids": -24.1, + "upperMids": -27.0, + "highs": -19.9, + "brilliance": -12.3 + }, + { + "t": 4.06, + "subBass": -9.8, + "lowBass": -7.8, + "lowMids": -31.4, + "mids": -19.8, + "upperMids": -32.4, + "highs": -42.8, + "brilliance": -44.5 + }, + { + "t": 4.13, + "subBass": -7.9, + "lowBass": -4.5, + "lowMids": -28.7, + "mids": -21.1, + "upperMids": -33.4, + "highs": -43.7, + "brilliance": -52.7 + }, + { + "t": 4.2, + "subBass": -3.2, + "lowBass": -5.2, + "lowMids": -31.3, + "mids": -21.6, + "upperMids": -33.9, + "highs": -45.0, + "brilliance": -63.1 + }, + { + "t": 4.27, + "subBass": -5.3, + "lowBass": -9.3, + "lowMids": -40.3, + "mids": -21.3, + "upperMids": -33.7, + "highs": -38.3, + "brilliance": -32.4 + }, + { + "t": 4.34, + "subBass": -7.4, + "lowBass": -7.3, + "lowMids": -20.7, + "mids": -24.3, + "upperMids": -27.4, + "highs": -20.2, + "brilliance": -12.4 + }, + { + "t": 4.41, + "subBass": -8.6, + "lowBass": -7.8, + "lowMids": -31.8, + "mids": -19.8, + "upperMids": -31.7, + "highs": -43.9, + "brilliance": -58.9 + }, + { + "t": 4.48, + "subBass": -10.9, + "lowBass": -7.2, + "lowMids": -22.6, + "mids": -23.7, + "upperMids": -32.7, + "highs": -47.4, + "brilliance": -51.8 + }, + { + "t": 4.55, + "subBass": -5.3, + "lowBass": -6.9, + "lowMids": -21.7, + "mids": -24.9, + "upperMids": -33.9, + "highs": -51.0, + "brilliance": -63.7 + }, + { + "t": 4.62, + "subBass": -6.8, + "lowBass": -8.7, + "lowMids": -22.7, + "mids": -26.0, + "upperMids": -34.3, + "highs": -32.6, + "brilliance": -26.1 + }, + { + "t": 4.69, + "subBass": -7.2, + "lowBass": -7.9, + "lowMids": -42.9, + "mids": -19.9, + "upperMids": -27.6, + "highs": -20.8, + "brilliance": -12.9 + }, + { + "t": 4.76, + "subBass": -7.4, + "lowBass": -8.5, + "lowMids": -20.7, + "mids": -24.0, + "upperMids": -34.2, + "highs": -57.2, + "brilliance": -68.0 + }, + { + "t": 4.83, + "subBass": -7.1, + "lowBass": -5.4, + "lowMids": -25.8, + "mids": -20.5, + "upperMids": -32.5, + "highs": -44.7, + "brilliance": -58.2 + }, + { + "t": 4.9, + "subBass": -6.0, + "lowBass": -9.0, + "lowMids": -23.3, + "mids": -22.7, + "upperMids": -33.9, + "highs": -48.3, + "brilliance": -58.1 + }, + { + "t": 4.97, + "subBass": -7.1, + "lowBass": -9.0, + "lowMids": -22.4, + "mids": -25.8, + "upperMids": -33.4, + "highs": -28.2, + "brilliance": -21.4 + }, + { + "t": 5.04, + "subBass": -8.5, + "lowBass": -7.1, + "lowMids": -21.4, + "mids": -25.5, + "upperMids": -28.0, + "highs": -21.7, + "brilliance": -13.6 + }, + { + "t": 5.11, + "subBass": -9.9, + "lowBass": -7.9, + "lowMids": -35.4, + "mids": -19.5, + "upperMids": -32.2, + "highs": -42.9, + "brilliance": -72.7 + }, + { + "t": 5.18, + "subBass": -5.3, + "lowBass": -3.6, + "lowMids": -22.5, + "mids": -24.5, + "upperMids": -33.6, + "highs": -48.9, + "brilliance": -53.5 + }, + { + "t": 5.25, + "subBass": -3.9, + "lowBass": -6.9, + "lowMids": -21.9, + "mids": -25.2, + "upperMids": -34.1, + "highs": -49.9, + "brilliance": -60.3 + }, + { + "t": 5.32, + "subBass": -5.3, + "lowBass": -9.1, + "lowMids": -22.1, + "mids": -26.2, + "upperMids": -31.6, + "highs": -25.2, + "brilliance": -18.4 + }, + { + "t": 5.39, + "subBass": -7.6, + "lowBass": -7.2, + "lowMids": -21.8, + "mids": -25.9, + "upperMids": -28.5, + "highs": -22.7, + "brilliance": -14.4 + }, + { + "t": 5.46, + "subBass": -8.9, + "lowBass": -8.0, + "lowMids": -20.1, + "mids": -23.9, + "upperMids": -33.5, + "highs": -69.3, + "brilliance": -72.8 + }, + { + "t": 5.53, + "subBass": -10.1, + "lowBass": -7.4, + "lowMids": -21.2, + "mids": -24.6, + "upperMids": -32.7, + "highs": -52.4, + "brilliance": -54.5 + }, + { + "t": 5.6, + "subBass": -4.6, + "lowBass": -6.4, + "lowMids": -26.3, + "mids": -21.5, + "upperMids": -32.7, + "highs": -47.0, + "brilliance": -60.9 + }, + { + "t": 5.67, + "subBass": -7.3, + "lowBass": -8.7, + "lowMids": -25.1, + "mids": -21.6, + "upperMids": -29.2, + "highs": -23.4, + "brilliance": -16.3 + }, + { + "t": 5.74, + "subBass": -5.3, + "lowBass": -7.7, + "lowMids": -22.3, + "mids": -26.3, + "upperMids": -29.6, + "highs": -23.7, + "brilliance": -15.4 + }, + { + "t": 5.8, + "subBass": -7.7, + "lowBass": -8.7, + "lowMids": -35.9, + "mids": -19.1, + "upperMids": -31.2, + "highs": -43.3, + "brilliance": -78.1 + }, + { + "t": 5.87, + "subBass": -9.0, + "lowBass": -6.6, + "lowMids": -21.2, + "mids": -24.2, + "upperMids": -32.7, + "highs": -53.4, + "brilliance": -60.7 + }, + { + "t": 5.94, + "subBass": -4.2, + "lowBass": -7.1, + "lowMids": -27.2, + "mids": -21.3, + "upperMids": -32.5, + "highs": -46.4, + "brilliance": -56.9 + }, + { + "t": 6.01, + "subBass": -6.7, + "lowBass": -8.3, + "lowMids": -35.2, + "mids": -20.9, + "upperMids": -28.6, + "highs": -22.0, + "brilliance": -15.1 + }, + { + "t": 6.08, + "subBass": -8.6, + "lowBass": -7.2, + "lowMids": -38.2, + "mids": -21.3, + "upperMids": -29.4, + "highs": -23.8, + "brilliance": -15.8 + }, + { + "t": 6.15, + "subBass": -10.3, + "lowBass": -8.1, + "lowMids": -40.2, + "mids": -19.2, + "upperMids": -32.0, + "highs": -42.6, + "brilliance": -77.1 + }, + { + "t": 6.22, + "subBass": -4.6, + "lowBass": -3.1, + "lowMids": -22.0, + "mids": -24.7, + "upperMids": -33.8, + "highs": -50.3, + "brilliance": -53.5 + }, + { + "t": 6.29, + "subBass": -4.1, + "lowBass": -8.4, + "lowMids": -21.5, + "mids": -25.0, + "upperMids": -34.4, + "highs": -59.4, + "brilliance": -61.6 + }, + { + "t": 6.36, + "subBass": -6.8, + "lowBass": -9.1, + "lowMids": -24.8, + "mids": -22.0, + "upperMids": -29.1, + "highs": -21.7, + "brilliance": -14.4 + }, + { + "t": 6.43, + "subBass": -7.6, + "lowBass": -7.2, + "lowMids": -33.5, + "mids": -21.5, + "upperMids": -29.8, + "highs": -24.4, + "brilliance": -16.4 + }, + { + "t": 6.5, + "subBass": -9.2, + "lowBass": -8.2, + "lowMids": -20.6, + "mids": -24.3, + "upperMids": -33.2, + "highs": -48.1, + "brilliance": -81.3 + }, + { + "t": 6.57, + "subBass": -8.5, + "lowBass": -6.2, + "lowMids": -30.5, + "mids": -20.1, + "upperMids": -32.5, + "highs": -42.3, + "brilliance": -52.2 + }, + { + "t": 6.64, + "subBass": -6.0, + "lowBass": -8.7, + "lowMids": -21.6, + "mids": -23.3, + "upperMids": -33.3, + "highs": -47.4, + "brilliance": -64.4 + }, + { + "t": 6.71, + "subBass": -7.2, + "lowBass": -8.5, + "lowMids": -21.7, + "mids": -25.2, + "upperMids": -29.1, + "highs": -22.0, + "brilliance": -14.2 + }, + { + "t": 6.78, + "subBass": -7.1, + "lowBass": -8.0, + "lowMids": -22.3, + "mids": -26.2, + "upperMids": -30.7, + "highs": -25.1, + "brilliance": -17.5 + }, + { + "t": 6.85, + "subBass": -7.0, + "lowBass": -8.8, + "lowMids": -20.9, + "mids": -24.8, + "upperMids": -34.3, + "highs": -76.6, + "brilliance": -89.9 + }, + { + "t": 6.92, + "subBass": -7.7, + "lowBass": -6.0, + "lowMids": -19.9, + "mids": -23.7, + "upperMids": -33.1, + "highs": -47.8, + "brilliance": -56.1 + }, + { + "t": 6.99, + "subBass": -5.3, + "lowBass": -8.1, + "lowMids": -27.5, + "mids": -20.2, + "upperMids": -31.9, + "highs": -45.7, + "brilliance": -66.3 + }, + { + "t": 7.06, + "subBass": -7.6, + "lowBass": -8.3, + "lowMids": -35.6, + "mids": -20.9, + "upperMids": -28.4, + "highs": -22.1, + "brilliance": -14.3 + }, + { + "t": 7.13, + "subBass": -8.9, + "lowBass": -7.3, + "lowMids": -35.5, + "mids": -21.1, + "upperMids": -30.4, + "highs": -25.9, + "brilliance": -18.4 + }, + { + "t": 7.2, + "subBass": -10.5, + "lowBass": -8.3, + "lowMids": -41.7, + "mids": -20.2, + "upperMids": -32.4, + "highs": -44.4, + "brilliance": -74.9 + }, + { + "t": 7.27, + "subBass": -3.3, + "lowBass": -2.8, + "lowMids": -21.2, + "mids": -23.7, + "upperMids": -35.0, + "highs": -50.1, + "brilliance": -52.2 + }, + { + "t": 7.34, + "subBass": -5.4, + "lowBass": -9.5, + "lowMids": -28.6, + "mids": -20.0, + "upperMids": -31.8, + "highs": -45.8, + "brilliance": -73.4 + }, + { + "t": 7.41, + "subBass": -5.5, + "lowBass": -8.3, + "lowMids": -33.6, + "mids": -20.7, + "upperMids": -28.2, + "highs": -22.0, + "brilliance": -14.1 + }, + { + "t": 7.48, + "subBass": -8.0, + "lowBass": -7.4, + "lowMids": -24.7, + "mids": -22.2, + "upperMids": -31.4, + "highs": -26.9, + "brilliance": -19.5 + }, + { + "t": 7.55, + "subBass": -9.3, + "lowBass": -8.4, + "lowMids": -21.6, + "mids": -25.5, + "upperMids": -35.5, + "highs": -62.0, + "brilliance": -64.4 + }, + { + "t": 7.62, + "subBass": -6.7, + "lowBass": -5.5, + "lowMids": -20.8, + "mids": -24.0, + "upperMids": -32.5, + "highs": -51.5, + "brilliance": -53.7 + }, + { + "t": 7.69, + "subBass": -5.5, + "lowBass": -7.7, + "lowMids": -31.4, + "mids": -20.2, + "upperMids": -32.1, + "highs": -44.4, + "brilliance": -74.3 + }, + { + "t": 7.76, + "subBass": -6.5, + "lowBass": -8.3, + "lowMids": -32.5, + "mids": -20.9, + "upperMids": -27.8, + "highs": -21.7, + "brilliance": -13.8 + }, + { + "t": 7.83, + "subBass": -6.2, + "lowBass": -7.9, + "lowMids": -23.7, + "mids": -22.2, + "upperMids": -31.5, + "highs": -27.8, + "brilliance": -20.5 + }, + { + "t": 7.89, + "subBass": -8.8, + "lowBass": -9.0, + "lowMids": -21.8, + "mids": -25.5, + "upperMids": -34.5, + "highs": -49.2, + "brilliance": -65.1 + }, + { + "t": 7.96, + "subBass": -6.1, + "lowBass": -5.7, + "lowMids": -28.5, + "mids": -19.6, + "upperMids": -31.5, + "highs": -44.9, + "brilliance": -56.9 + }, + { + "t": 8.03, + "subBass": -5.5, + "lowBass": -8.5, + "lowMids": -21.2, + "mids": -24.1, + "upperMids": -33.5, + "highs": -48.5, + "brilliance": -84.8 + }, + { + "t": 8.1, + "subBass": -7.6, + "lowBass": -7.9, + "lowMids": -29.0, + "mids": -21.1, + "upperMids": -27.4, + "highs": -20.6, + "brilliance": -13.1 + }, + { + "t": 8.17, + "subBass": -9.0, + "lowBass": -7.4, + "lowMids": -36.6, + "mids": -20.3, + "upperMids": -31.4, + "highs": -28.7, + "brilliance": -21.4 + }, + { + "t": 8.24, + "subBass": -10.7, + "lowBass": -8.1, + "lowMids": -33.6, + "mids": -21.1, + "upperMids": -33.4, + "highs": -45.1, + "brilliance": -55.4 + }, + { + "t": 8.31, + "subBass": -3.8, + "lowBass": -3.4, + "lowMids": -21.4, + "mids": -25.3, + "upperMids": -35.2, + "highs": -56.8, + "brilliance": -59.0 + }, + { + "t": 8.38, + "subBass": -4.4, + "lowBass": -8.6, + "lowMids": -20.9, + "mids": -24.5, + "upperMids": -34.5, + "highs": -69.8, + "brilliance": -82.1 + }, + { + "t": 8.45, + "subBass": -7.5, + "lowBass": -8.3, + "lowMids": -20.9, + "mids": -23.8, + "upperMids": -27.4, + "highs": -20.4, + "brilliance": -12.7 + }, + { + "t": 8.52, + "subBass": -7.8, + "lowBass": -7.4, + "lowMids": -26.0, + "mids": -21.4, + "upperMids": -31.9, + "highs": -29.8, + "brilliance": -22.3 + }, + { + "t": 8.59, + "subBass": -10.1, + "lowBass": -7.5, + "lowMids": -29.9, + "mids": -21.2, + "upperMids": -33.6, + "highs": -45.1, + "brilliance": -53.0 + }, + { + "t": 8.66, + "subBass": -7.2, + "lowBass": -7.3, + "lowMids": -20.9, + "mids": -25.0, + "upperMids": -34.5, + "highs": -61.0, + "brilliance": -63.2 + }, + { + "t": 8.73, + "subBass": -6.2, + "lowBass": -8.6, + "lowMids": -28.3, + "mids": -19.6, + "upperMids": -31.3, + "highs": -45.1, + "brilliance": -81.5 + }, + { + "t": 8.8, + "subBass": -7.4, + "lowBass": -8.3, + "lowMids": -38.6, + "mids": -20.1, + "upperMids": -27.3, + "highs": -20.3, + "brilliance": -12.7 + }, + { + "t": 8.87, + "subBass": -6.5, + "lowBass": -8.1, + "lowMids": -37.5, + "mids": -20.4, + "upperMids": -31.6, + "highs": -31.0, + "brilliance": -23.8 + }, + { + "t": 8.94, + "subBass": -7.2, + "lowBass": -7.3, + "lowMids": -28.6, + "mids": -21.4, + "upperMids": -33.5, + "highs": -44.8, + "brilliance": -57.6 + }, + { + "t": 9.01, + "subBass": -6.7, + "lowBass": -7.3, + "lowMids": -35.6, + "mids": -20.7, + "upperMids": -33.4, + "highs": -43.9, + "brilliance": -61.3 + }, + { + "t": 9.08, + "subBass": -5.5, + "lowBass": -8.2, + "lowMids": -20.5, + "mids": -24.2, + "upperMids": -34.3, + "highs": -63.2, + "brilliance": -71.4 + }, + { + "t": 9.15, + "subBass": -8.0, + "lowBass": -7.7, + "lowMids": -21.5, + "mids": -24.7, + "upperMids": -27.6, + "highs": -20.7, + "brilliance": -12.9 + }, + { + "t": 9.22, + "subBass": -9.3, + "lowBass": -7.5, + "lowMids": -27.1, + "mids": -20.9, + "upperMids": -31.9, + "highs": -32.6, + "brilliance": -25.2 + }, + { + "t": 9.29, + "subBass": -10.1, + "lowBass": -6.9, + "lowMids": -24.4, + "mids": -22.0, + "upperMids": -32.7, + "highs": -45.8, + "brilliance": -52.5 + }, + { + "t": 9.36, + "subBass": -3.3, + "lowBass": -3.5, + "lowMids": -22.4, + "mids": -27.6, + "upperMids": -35.6, + "highs": -60.0, + "brilliance": -62.7 + }, + { + "t": 9.43, + "subBass": -4.7, + "lowBass": -8.9, + "lowMids": -20.6, + "mids": -24.4, + "upperMids": -34.4, + "highs": -68.9, + "brilliance": -77.1 + }, + { + "t": 9.5, + "subBass": -6.2, + "lowBass": -7.7, + "lowMids": -21.3, + "mids": -24.4, + "upperMids": -27.8, + "highs": -21.0, + "brilliance": -13.1 + }, + { + "t": 9.57, + "subBass": -8.5, + "lowBass": -7.6, + "lowMids": -20.8, + "mids": -24.5, + "upperMids": -33.4, + "highs": -35.5, + "brilliance": -27.6 + }, + { + "t": 9.64, + "subBass": -10.3, + "lowBass": -6.2, + "lowMids": -22.0, + "mids": -25.0, + "upperMids": -34.4, + "highs": -51.2, + "brilliance": -53.1 + }, + { + "t": 9.71, + "subBass": -5.0, + "lowBass": -6.4, + "lowMids": -22.4, + "mids": -25.7, + "upperMids": -35.8, + "highs": -54.8, + "brilliance": -60.9 + }, + { + "t": 9.78, + "subBass": -6.3, + "lowBass": -8.4, + "lowMids": -35.9, + "mids": -19.8, + "upperMids": -31.9, + "highs": -44.0, + "brilliance": -79.8 + }, + { + "t": 9.85, + "subBass": -6.1, + "lowBass": -7.9, + "lowMids": -31.1, + "mids": -20.3, + "upperMids": -27.4, + "highs": -21.0, + "brilliance": -13.2 + }, + { + "t": 9.91, + "subBass": -7.5, + "lowBass": -8.3, + "lowMids": -39.4, + "mids": -19.6, + "upperMids": -32.0, + "highs": -36.4, + "brilliance": -29.6 + }, + { + "t": 9.98, + "subBass": -9.2, + "lowBass": -7.0, + "lowMids": -30.5, + "mids": -20.7, + "upperMids": -32.9, + "highs": -44.3, + "brilliance": -59.8 + }, + { + "t": 10.05, + "subBass": -5.4, + "lowBass": -7.0, + "lowMids": -35.5, + "mids": -21.6, + "upperMids": -33.7, + "highs": -45.3, + "brilliance": -58.2 + }, + { + "t": 10.12, + "subBass": -6.0, + "lowBass": -8.8, + "lowMids": -39.8, + "mids": -20.1, + "upperMids": -32.8, + "highs": -43.5, + "brilliance": -85.3 + }, + { + "t": 10.19, + "subBass": -8.5, + "lowBass": -7.4, + "lowMids": -21.0, + "mids": -25.0, + "upperMids": -27.2, + "highs": -20.4, + "brilliance": -12.7 + }, + { + "t": 10.26, + "subBass": -9.5, + "lowBass": -7.6, + "lowMids": -20.6, + "mids": -23.9, + "upperMids": -32.9, + "highs": -40.6, + "brilliance": -33.3 + }, + { + "t": 10.33, + "subBass": -9.5, + "lowBass": -6.1, + "lowMids": -24.9, + "mids": -22.3, + "upperMids": -33.0, + "highs": -45.8, + "brilliance": -55.2 + }, + { + "t": 10.4, + "subBass": -2.7, + "lowBass": -4.2, + "lowMids": -25.1, + "mids": -23.3, + "upperMids": -34.8, + "highs": -49.2, + "brilliance": -60.0 + }, + { + "t": 10.47, + "subBass": -6.3, + "lowBass": -9.8, + "lowMids": -21.3, + "mids": -25.3, + "upperMids": -35.2, + "highs": -67.1, + "brilliance": -60.7 + }, + { + "t": 10.54, + "subBass": -7.5, + "lowBass": -7.6, + "lowMids": -34.5, + "mids": -19.8, + "upperMids": -27.1, + "highs": -20.0, + "brilliance": -12.4 + }, + { + "t": 10.61, + "subBass": -8.2, + "lowBass": -7.7, + "lowMids": -20.9, + "mids": -23.7, + "upperMids": -33.7, + "highs": -47.0, + "brilliance": -40.1 + }, + { + "t": 10.68, + "subBass": -11.3, + "lowBass": -7.3, + "lowMids": -26.6, + "mids": -21.5, + "upperMids": -32.9, + "highs": -45.3, + "brilliance": -53.8 + }, + { + "t": 10.75, + "subBass": -5.8, + "lowBass": -7.4, + "lowMids": -30.2, + "mids": -21.0, + "upperMids": -32.7, + "highs": -45.4, + "brilliance": -62.4 + }, + { + "t": 10.82, + "subBass": -6.6, + "lowBass": -8.7, + "lowMids": -32.2, + "mids": -20.8, + "upperMids": -32.7, + "highs": -44.2, + "brilliance": -41.4 + }, + { + "t": 10.89, + "subBass": -6.9, + "lowBass": -7.8, + "lowMids": -20.7, + "mids": -24.6, + "upperMids": -27.6, + "highs": -20.0, + "brilliance": -12.4 + }, + { + "t": 10.96, + "subBass": -6.3, + "lowBass": -8.3, + "lowMids": -32.1, + "mids": -19.9, + "upperMids": -31.9, + "highs": -43.8, + "brilliance": -45.7 + }, + { + "t": 11.03, + "subBass": -11.0, + "lowBass": -12.1, + "lowMids": -37.8, + "mids": -26.7, + "upperMids": -38.4, + "highs": -48.1, + "brilliance": -52.7 + } + ], + "spectralDetail": { + "spectralCentroid": 1304.4, + "spectralRolloff": 1525.3, + "spectralBandwidth": 3412.1, + "spectralFlatness": 0.137751, + "mfcc": [ + -686.308, + 184.2957, + -7.4131, + 65.8112, + 18.7413, + 22.001, + 26.153, + 15.9766, + 19.0587, + 15.8666, + 18.6521, + 14.8944, + 14.1728 + ], + "chroma": [ + 0.0511, + 0.1873, + 0.0463, + 0.2066, + 0.2722, + 0.0855, + 0.2191, + 0.1116, + 0.3051, + 0.1294, + 0.3776, + 0.3744 + ], + "barkBands": [ + -22.6561, + -6.7652, + -10.4343, + -21.3403, + -29.1591, + -27.4846, + -26.1144, + -26.4436, + -29.9765, + -33.1211, + -33.2707, + -31.6134, + -36.8811, + -35.7067, + -37.3189, + -38.5858, + -38.7137, + -38.9775, + -39.8856, + -39.3102, + -37.9194, + -34.6127, + -34.7568, + -30.7898 + ], + "erbBands": [ + 10.9257, + 18.9309, + 20.2046, + 14.7907, + 8.5778, + 4.6008, + 7.4916, + 14.2067, + 15.4885, + 16.5202, + 16.2692, + 12.1139, + 12.3703, + 11.9321, + 13.9283, + 13.5117, + 10.8483, + 10.9626, + 10.5619, + 9.2639, + 9.2054, + 8.6515, + 8.1158, + 7.8919, + 6.8227, + 7.3208, + 8.023, + 8.3109, + 10.3457, + 10.7953, + 10.2733, + 12.378, + 11.1925, + 11.6254, + 10.9264, + 10.7251, + 8.7916, + 5.013, + -1.024, + -10.4651 + ], + "spectralContrast": [ + -0.2335, + -0.5832, + -0.6454, + -0.7005, + -0.7311, + -0.7663 + ], + "spectralValley": [ + -5.3328, + -6.3516, + -7.2242, + -7.8012, + -8.4532, + -10.5726 + ] + }, + "stemAnalysis": null, + "transientDensityDetail": { + "subBass": { + "onsetRatePerSecond": 15.32, + "meanOnsetStrength": 0.264, + "peakOnsetStrength": 0.693, + "eventCount": 169 + }, + "lowBass": { + "onsetRatePerSecond": 8.79, + "meanOnsetStrength": 0.384, + "peakOnsetStrength": 0.987, + "eventCount": 97 + }, + "lowMids": { + "onsetRatePerSecond": 12.69, + "meanOnsetStrength": 0.887, + "peakOnsetStrength": 1.926, + "eventCount": 140 + }, + "mids": { + "onsetRatePerSecond": 12.51, + "meanOnsetStrength": 3.693, + "peakOnsetStrength": 6.438, + "eventCount": 138 + }, + "upperMids": { + "onsetRatePerSecond": 12.51, + "meanOnsetStrength": 3.492, + "peakOnsetStrength": 8.135, + "eventCount": 138 + }, + "highs": { + "onsetRatePerSecond": 8.25, + "meanOnsetStrength": 5.451, + "peakOnsetStrength": 13.226, + "eventCount": 91 + }, + "brilliance": { + "onsetRatePerSecond": 8.61, + "meanOnsetStrength": 6.911, + "peakOnsetStrength": 15.42, + "eventCount": 95 + } + }, + "saturationDetail": { + "clippedSampleCount": 0, + "clippedSamplePercent": 0.0, + "nearClippedSampleCount": 0, + "nearClippedSamplePercent": 0.0, + "peakRatio95to50": 2.466, + "rmsToPeakRatioDb": 9.02, + "saturationLikely": false + }, + "snareDetail": { + "hitCount": 39, + "hitsPerSecond": 3.53, + "meanAttackSharpness": 0.0075, + "meanBodyEnergyRatio": 0.966, + "meanSnapEnergyRatio": 0.034, + "meanCentroidHz": 487.7, + "meanDecayFrames": 50.2, + "meanDecaySeconds": 0.291, + "bandHz": [ + 120.0, + 2000.0 + ] + }, + "hihatDetail": { + "hitCount": 32, + "hitsPerSecond": 2.9, + "meanAttackSharpness": 0.0031, + "meanBodyEnergyRatio": 0.178, + "meanSnapEnergyRatio": 0.822, + "meanCentroidHz": 7897.6, + "meanDecayFrames": 8.1, + "meanDecaySeconds": 0.047, + "bandHz": [ + 2000.0, + 12000.0 + ] + }, + "rhythmDetail": { + "onsetRate": 2.9, + "beatGrid": [ + 0.488, + 1.022, + 1.533, + 2.043, + 2.566, + 3.088, + 3.599, + 4.11, + 4.632, + 5.155, + 5.666, + 6.177, + 6.699, + 7.221, + 7.732, + 8.243, + 8.777, + 9.288, + 9.799, + 10.321, + 10.844 + ], + "downbeats": [ + 2.566, + 5.155, + 7.732, + 10.321 + ], + "beatPositions": [ + 2, + 3, + 4, + 5, + 1, + 2, + 3, + 4, + 5, + 1, + 2, + 3, + 4, + 5, + 1, + 2, + 3, + 4, + 5, + 1, + 2 + ], + "downbeatSource": "kick_accent", + "downbeatConfidence": 0.0079, + "grooveAmount": 0.0149, + "tempoStability": 0.9851, + "phraseGrid": { + "phrases4Bar": [ + 2.566 + ], + "phrases8Bar": [ + 2.566 + ], + "phrases16Bar": [ + 2.566 + ], + "totalBars": 4, + "totalPhrases8Bar": 1 + }, + "tempoCurve": [ + { + "t": 0.75, + "bpm": 117.5 + }, + { + "t": 1.28, + "bpm": 116.1 + }, + { + "t": 1.79, + "bpm": 114.8 + }, + { + "t": 2.3, + "bpm": 117.5 + }, + { + "t": 2.83, + "bpm": 117.5 + }, + { + "t": 3.34, + "bpm": 114.8 + }, + { + "t": 3.85, + "bpm": 114.8 + }, + { + "t": 4.37, + "bpm": 117.5 + }, + { + "t": 4.89, + "bpm": 117.5 + }, + { + "t": 5.41, + "bpm": 114.8 + }, + { + "t": 5.92, + "bpm": 114.8 + }, + { + "t": 6.44, + "bpm": 117.5 + }, + { + "t": 6.96, + "bpm": 117.5 + }, + { + "t": 7.48, + "bpm": 114.8 + }, + { + "t": 7.99, + "bpm": 117.5 + }, + { + "t": 8.51, + "bpm": 117.5 + }, + { + "t": 9.03, + "bpm": 117.5 + }, + { + "t": 9.54, + "bpm": 114.8 + }, + { + "t": 10.06, + "bpm": 116.1 + }, + { + "t": 10.58, + "bpm": 114.8 + } + ] + }, + "melodyDetail": { + "noteCount": 55, + "notes": [ + { + "midi": 43, + "onset": 0.174, + "duration": 0.163 + }, + { + "midi": 44, + "onset": 0.395, + "duration": 0.125 + }, + { + "midi": 41, + "onset": 0.525, + "duration": 0.154 + }, + { + "midi": 43, + "onset": 0.752, + "duration": 0.102 + }, + { + "midi": 44, + "onset": 0.859, + "duration": 0.168 + }, + { + "midi": 43, + "onset": 1.213, + "duration": 0.151 + }, + { + "midi": 44, + "onset": 1.37, + "duration": 0.183 + }, + { + "midi": 41, + "onset": 1.559, + "duration": 0.154 + }, + { + "midi": 43, + "onset": 1.785, + "duration": 0.102 + }, + { + "midi": 44, + "onset": 1.892, + "duration": 0.197 + }, + { + "midi": 41, + "onset": 2.157, + "duration": 0.099 + }, + { + "midi": 43, + "onset": 2.261, + "duration": 0.145 + }, + { + "midi": 44, + "onset": 2.461, + "duration": 0.128 + }, + { + "midi": 41, + "onset": 2.595, + "duration": 0.16 + }, + { + "midi": 43, + "onset": 2.818, + "duration": 0.102 + }, + { + "midi": 44, + "onset": 2.926, + "duration": 0.171 + }, + { + "midi": 44, + "onset": 3.495, + "duration": 0.128 + }, + { + "midi": 41, + "onset": 3.628, + "duration": 0.16 + }, + { + "midi": 43, + "onset": 3.852, + "duration": 0.102 + }, + { + "midi": 44, + "onset": 3.959, + "duration": 0.2 + }, + { + "midi": 43, + "onset": 4.304, + "duration": 0.171 + }, + { + "midi": 44, + "onset": 4.531, + "duration": 0.125 + }, + { + "midi": 41, + "onset": 4.661, + "duration": 0.157 + }, + { + "midi": 42, + "onset": 4.824, + "duration": 0.093 + }, + { + "midi": 43, + "onset": 4.923, + "duration": 0.093 + }, + { + "midi": 44, + "onset": 5.021, + "duration": 0.174 + }, + { + "midi": 43, + "onset": 5.341, + "duration": 0.171 + }, + { + "midi": 44, + "onset": 5.564, + "duration": 0.128 + }, + { + "midi": 43, + "onset": 5.921, + "duration": 0.102 + }, + { + "midi": 44, + "onset": 6.028, + "duration": 0.165 + }, + { + "midi": 42, + "onset": 6.2, + "duration": 0.093 + }, + { + "midi": 41, + "onset": 6.298, + "duration": 0.093 + }, + { + "midi": 43, + "onset": 6.397, + "duration": 0.148 + }, + { + "midi": 44, + "onset": 6.597, + "duration": 0.128 + }, + { + "midi": 43, + "onset": 6.954, + "duration": 0.102 + }, + { + "midi": 44, + "onset": 7.062, + "duration": 0.2 + }, + { + "midi": 42, + "onset": 7.364, + "duration": 0.099 + }, + { + "midi": 43, + "onset": 7.468, + "duration": 0.113 + }, + { + "midi": 44, + "onset": 7.631, + "duration": 0.131 + }, + { + "midi": 41, + "onset": 7.767, + "duration": 0.154 + }, + { + "midi": 41, + "onset": 7.927, + "duration": 0.093 + }, + { + "midi": 43, + "onset": 8.025, + "duration": 0.093 + }, + { + "midi": 44, + "onset": 8.124, + "duration": 0.171 + }, + { + "midi": 43, + "onset": 8.443, + "duration": 0.171 + }, + { + "midi": 44, + "onset": 8.661, + "duration": 0.134 + }, + { + "midi": 41, + "onset": 8.8, + "duration": 0.16 + }, + { + "midi": 43, + "onset": 9.021, + "duration": 0.104 + }, + { + "midi": 44, + "onset": 9.131, + "duration": 0.174 + }, + { + "midi": 44, + "onset": 9.694, + "duration": 0.136 + }, + { + "midi": 41, + "onset": 9.837, + "duration": 0.154 + }, + { + "midi": 42, + "onset": 9.996, + "duration": 0.093 + }, + { + "midi": 43, + "onset": 10.095, + "duration": 0.093 + }, + { + "midi": 44, + "onset": 10.194, + "duration": 0.174 + }, + { + "midi": 43, + "onset": 10.513, + "duration": 0.171 + }, + { + "midi": 43, + "onset": 10.731, + "duration": 0.206 + } + ], + "dominantNotes": [ + 43, + 44, + 41, + 42 + ], + "pitchRange": { + "min": 41, + "max": 44 + }, + "pitchConfidence": 0.0434, + "midiFile": "/Users/christiansmith/code/projects/asa/.claude/worktrees/goal-doc/apps/backend/tests/fixtures/recommendation_tracks/dnb_reese_174/audio_melody.mid", + "sourceSeparated": false, + "vibratoPresent": false, + "vibratoExtent": 0.0, + "vibratoRate": 0.0, + "vibratoConfidence": 0.0 + }, + "transcriptionDetail": null, + "pitchDetail": null, + "grooveDetail": { + "kickSwing": 0.0053, + "hihatSwing": 0.2576, + "kickAccent": [ + 0.2864, + 0.8264, + 0.303, + 0.3001, + 1.0083, + 0.3514, + 0.3468, + 1.0061, + 0.3449, + 0.2754, + 1.0108, + 0.3654, + 0.2783, + 0.9978, + 0.2806, + 0.2827 + ], + "hihatAccent": [ + 0.0626, + 0.0, + 0.0632, + 0.0638, + 0.0001, + 0.0322, + 0.0209, + 0.0, + 0.0207, + 0.0632, + 0.0, + 0.0307, + 0.0438, + 0.0, + 0.0433, + 0.0436 + ], + "perDrumSwing": { + "kick": 0.0053, + "snare": 0.2184, + "hihat": 0.2576 + } + }, + "beatsLoudness": { + "kickDominantRatio": 0.9454, + "midDominantRatio": 0.0001, + "highDominantRatio": 0.0348, + "patternBeatsPerBar": 4, + "lowBandAccentPattern": [ + 0.2938, + 0.9659, + 0.3277, + 1.0 + ], + "midBandAccentPattern": [ + 0.1729, + 1.0, + 0.3549, + 0.1782 + ], + "highBandAccentPattern": [ + 1.0, + 0.0008, + 0.7665, + 0.001 + ], + "overallAccentPattern": [ + 0.3519, + 0.966, + 0.3721, + 1.0 + ], + "accentPattern": [ + 0.3519, + 0.966, + 0.3721, + 1.0 + ], + "meanBeatLoudness": 0.6692, + "beatLoudnessVariation": 0.4767, + "beatCount": 21 + }, + "rhythmTimeline": { + "beatsPerBar": 4, + "stepsPerBeat": 4, + "availableBars": 5, + "selectionMethod": "representative_dsp_window", + "windows": [ + { + "bars": 5, + "startBar": 1, + "endBar": 5, + "lowBandSteps": [ + 0.4009, + 0.4449, + 0.4482, + 0.3331, + 0.8369, + 0.3743, + 0.261, + 0.5143, + 0.3644, + 0.4097, + 0.4194, + 0.3187, + 0.9787, + 0.3905, + 0.2755, + 0.5466, + 0.3807, + 0.4435, + 0.4236, + 0.3197, + 0.8591, + 0.3743, + 0.2619, + 0.5221, + 0.366, + 0.3834, + 0.4248, + 0.3229, + 0.9841, + 0.3899, + 0.2765, + 0.5536, + 0.3826, + 0.4174, + 0.4295, + 0.3242, + 0.8757, + 0.3743, + 0.262, + 0.5287, + 0.3674, + 0.3638, + 0.4304, + 0.3258, + 0.9776, + 0.3923, + 0.2783, + 0.5614, + 0.3837, + 0.4006, + 0.4356, + 0.3273, + 0.8886, + 0.3751, + 0.2632, + 0.5367, + 0.3687, + 0.3551, + 0.4356, + 0.3286, + 1.0, + 0.4093, + 0.2886, + 0.5612, + 0.3621, + 0.3987, + 0.4118, + 0.3145, + 0.8941, + 0.3745, + 0.2648, + 0.5448, + 0.3856, + 0.383, + 0.4439, + 0.3319, + 0.9198, + 0.3933, + 0.2758, + 0.5397 + ], + "midBandSteps": [ + 0.7013, + 0.8896, + 0.6326, + 0.8548, + 0.4919, + 0.7428, + 0.5882, + 0.7104, + 0.5943, + 0.7622, + 0.5867, + 0.6444, + 0.6201, + 0.7054, + 0.6516, + 0.7407, + 0.6216, + 0.817, + 0.5804, + 0.8272, + 0.4776, + 0.7687, + 0.6225, + 0.6707, + 0.6228, + 0.6984, + 0.6327, + 0.5941, + 0.664, + 0.6584, + 0.6714, + 0.693, + 0.5841, + 0.936, + 0.5929, + 0.7396, + 0.4777, + 0.7479, + 0.6465, + 0.6511, + 0.615, + 0.7449, + 0.6398, + 0.5593, + 0.6372, + 0.6373, + 0.7244, + 0.6634, + 0.6576, + 1.0, + 0.5831, + 0.7333, + 0.5879, + 0.6878, + 0.6732, + 0.6236, + 0.621, + 0.8635, + 0.6797, + 0.5453, + 0.7547, + 0.7543, + 0.6639, + 0.7774, + 0.4957, + 0.8831, + 0.5669, + 0.703, + 0.5942, + 0.7037, + 0.7085, + 0.6002, + 0.67, + 0.7531, + 0.5959, + 0.728, + 0.5957, + 0.6753, + 0.6424, + 0.7407 + ], + "highBandSteps": [ + 0.7521, + 0.0006, + 0.0338, + 0.0118, + 0.0002, + 1.0, + 0.0005, + 0.0009, + 0.495, + 0.0012, + 0.01, + 0.0302, + 0.0008, + 0.8429, + 0.0011, + 0.0005, + 0.5149, + 0.0015, + 0.0403, + 0.0112, + 0.0008, + 0.9543, + 0.0002, + 0.001, + 0.5491, + 0.0007, + 0.006, + 0.0386, + 0.0009, + 0.7894, + 0.0011, + 0.0008, + 0.5717, + 0.001, + 0.0279, + 0.0159, + 0.0004, + 0.9143, + 0.0, + 0.0011, + 0.6037, + 0.0007, + 0.0038, + 0.0483, + 0.0005, + 0.725, + 0.0009, + 0.0009, + 0.6243, + 0.0007, + 0.0191, + 0.0202, + 0.0002, + 0.8655, + 0.0003, + 0.0009, + 0.659, + 0.001, + 0.002, + 0.0596, + 0.0001, + 0.8152, + 0.0011, + 0.0013, + 0.4112, + 0.0016, + 0.0223, + 0.0194, + 0.0004, + 0.8092, + 0.0, + 0.0009, + 0.7079, + 0.0011, + 0.0099, + 0.0291, + 0.0008, + 0.9196, + 0.0001, + 0.0013 + ], + "overallSteps": [ + 0.4803, + 0.457, + 0.4578, + 0.3473, + 0.8338, + 0.4783, + 0.2695, + 0.5214, + 0.4179, + 0.4197, + 0.4263, + 0.3303, + 0.9762, + 0.4786, + 0.2852, + 0.5538, + 0.4363, + 0.4541, + 0.4331, + 0.3335, + 0.8555, + 0.4746, + 0.2712, + 0.5282, + 0.4252, + 0.3924, + 0.4321, + 0.3341, + 0.9825, + 0.472, + 0.2866, + 0.5597, + 0.4427, + 0.4309, + 0.438, + 0.3364, + 0.8717, + 0.4704, + 0.2717, + 0.5343, + 0.4314, + 0.3741, + 0.4376, + 0.3372, + 0.9754, + 0.4679, + 0.2896, + 0.5667, + 0.4503, + 0.4158, + 0.4429, + 0.3398, + 0.8868, + 0.4652, + 0.2736, + 0.5415, + 0.4381, + 0.3681, + 0.4435, + 0.3406, + 1.0, + 0.4956, + 0.2984, + 0.569, + 0.4056, + 0.4115, + 0.4195, + 0.3264, + 0.8924, + 0.4597, + 0.2758, + 0.5489, + 0.4604, + 0.3932, + 0.4505, + 0.345, + 0.9178, + 0.488, + 0.2852, + 0.5471 + ] + } + ] + }, + "sidechainDetail": { + "pumpingStrength": 0.1115, + "pumpingRegularity": 0.326, + "pumpingRate": null, + "pumpingConfidence": 0.2521, + "envelopeShape": [ + 0.76, + 0.829, + 0.796, + 0.72, + 1.0, + 0.778, + 0.663, + 0.815, + 0.761, + 0.798, + 0.817, + 0.712, + 0.929, + 0.802, + 0.656, + 0.813 + ], + "envelopeShape32": [ + 0.76, + 0.69, + 0.557, + 0.829, + 0.796, + 0.744, + 0.72, + 0.588, + 1.0, + 0.851, + 0.759, + 0.778, + 0.629, + 0.663, + 0.815, + 0.756, + 0.761, + 0.715, + 0.549, + 0.798, + 0.817, + 0.769, + 0.712, + 0.631, + 0.929, + 0.901, + 0.739, + 0.802, + 0.626, + 0.656, + 0.813, + 0.765 + ] + }, + "acidDetail": { + "isAcid": true, + "confidence": 0.66, + "resonanceLevel": 1.0, + "centroidOscillationHz": 28, + "bassRhythmDensity": 2.9 + }, + "reverbDetail": { + "rt60": null, + "isWet": false, + "tailEnergyRatio": null, + "measured": false, + "perBandRt60": null, + "preDelayMs": null + }, + "vocalDetail": { + "hasVocals": false, + "confidence": 0.35, + "vocalEnergyRatio": 0.05, + "formantStrength": 0.25, + "mfccLikelihood": 0.86, + "stemEnergyRatio": null, + "stemOtherCorrelation": null + }, + "supersawDetail": { + "isSupersaw": true, + "confidence": 0.85, + "voiceCount": 7, + "avgDetuneCents": 27.6, + "spectralComplexity": 6.8 + }, + "bassDetail": { + "averageDecayMs": 1000, + "type": "sustained", + "transientRatio": 0.2, + "fundamentalHz": 94, + "transientCount": 0, + "swingPercent": 0, + "grooveType": "straight" + }, + "kickDetail": { + "isDistorted": true, + "thd": 0.26, + "harmonicRatio": 0.85, + "fundamentalHz": 84, + "kickCount": 80 + }, + "genreDetail": { + "genre": "dub-techno", + "confidence": 0.9888, + "secondaryGenre": "hiphop", + "genreFamily": "techno", + "topScores": [ + { + "genre": "dub-techno", + "score": 0.9118 + }, + { + "genre": "hiphop", + "score": 0.8274 + }, + { + "genre": "ambient", + "score": 0.8134 + }, + { + "genre": "dubstep", + "score": 0.7568 + }, + { + "genre": "ambient-techno", + "score": 0.7341 + } + ] + }, + "effectsDetail": { + "gatingDetected": false, + "gatingRate": null, + "gatingRegularity": 0.0, + "gatingEventCount": 1 + }, + "synthesisCharacter": { + "inharmonicity": 0.0875, + "oddToEvenRatio": 1.5821 + }, + "danceability": { + "danceability": 4.7001, + "dfa": 0.2128 + }, + "structure": { + "segments": [ + { + "start": 0.0, + "end": 11.034, + "index": 0 + } + ], + "segmentCount": 1 + }, + "arrangementDetail": { + "noveltyCurve": [ + 0.0, + 0.0, + 0.0066, + 0.012, + 0.0944, + 0.2599, + 0.3082, + 0.1397, + 0.019, + 0.0241, + 0.0164, + 0.0164, + 0.0607, + 0.112, + 0.096, + 0.0675, + 0.0135, + 0.0284, + 0.0299, + 0.018, + 0.1754, + 0.2816, + 0.1807, + 0.0736, + 0.0104, + 0.0184, + 0.0211, + 0.0141, + 0.3129, + 0.4615, + 0.2348, + 0.0853, + 0.0157, + 0.0309, + 0.0484, + 0.0324, + 0.2632, + 0.3656, + 0.3167, + 0.1091, + 0.0116, + 0.0242, + 0.035, + 0.0225, + 0.2136, + 0.5492, + 0.517, + 0.1838, + 0.0383, + 0.0399, + 0.0151, + 0.0121, + 0.1386, + 0.3961, + 0.4345, + 0.1751, + 0.0278, + 0.0353, + 0.0215, + 0.0203, + 0.066, + 0.1553, + 0.1935, + 0.0967, + 0.0384, + 0.0671, + 0.0459, + 0.0213, + 0.0766, + 0.1426, + 0.0838, + 0.0154, + 0.032, + 0.0491, + 0.0571, + 0.0273, + 0.2778, + 0.4189, + 0.1596, + 0.0185, + 0.0142, + 0.0204, + 0.033, + 0.0243, + 0.3449, + 0.5805, + 0.2467, + 0.0147, + 0.0158, + 0.0239, + 0.029, + 0.0175, + 0.4514, + 0.7892, + 0.3494, + 0.1848, + 0.0319, + 0.0286, + 0.0205, + 0.019, + 0.3091, + 0.6102, + 0.3085, + 0.1681, + 0.0188, + 0.0244, + 0.0299, + 0.0289, + 0.1962, + 0.4326, + 0.3392, + 0.1513, + 0.0303, + 0.0477, + 0.029, + 0.0309, + 0.1174, + 0.1596, + 0.1684, + 0.0781, + 0.0214, + 0.0367, + 0.0295, + 0.1074, + 0.1488, + 0.2334, + 0.1103, + 0.0189, + 0.017, + 0.0446, + 0.0364, + 0.258, + 0.3407, + 0.509, + 0.1804, + 0.0164, + 0.0188, + 0.029, + 0.0225, + 0.0166, + 0.4091, + 0.6736, + 0.2772, + 0.0291, + 0.0238, + 0.0126, + 0.0113, + 0.0075, + 0.4035, + 0.7644, + 0.3674, + 0.0202, + 0.0292, + 0.0613, + 0.0616, + 0.0521, + 0.2265, + 0.4592, + 0.2417, + 0.0198, + 0.0299, + 0.0374, + 0.0315, + 0.0302, + 0.1155, + 0.2162, + 0.114, + 0.0181, + 0.0267, + 0.0453, + 0.0341, + 0.0686, + 0.1204, + 0.1267, + 0.0612, + 0.0294, + 0.0173, + 0.0465, + 0.0401, + 0.1109, + 0.1692, + 0.1093, + 0.0462, + 0.0154, + 0.0236, + 0.0478, + 0.0345, + 0.2592, + 0.4497, + 0.2961, + 0.2013, + 0.016, + 0.0137, + 0.0119, + 0.0098, + 0.3504, + 0.7823, + 1.0, + 0.4391, + 0.0235, + 0.0246, + 0.0379, + 0.0408, + 0.1396, + 0.3626, + 0.4924, + 0.252, + 0.019, + 0.0316, + 0.0416, + 0.0352, + 0.1321, + 0.2446, + 0.529, + 0.2925, + 0.0258, + 0.0381, + 0.0275, + 0.0204, + 0.0251, + 0.1317, + 0.2415, + 0.1258, + 0.0101, + 0.0294, + 0.0386, + 0.0371, + 0.0592, + 0.1193, + 0.1358, + 0.0687, + 0.0157, + 0.0322, + 0.0389, + 0.033, + 0.2093, + 0.3469, + 0.2245, + 0.0852, + 0.014, + 0.0224, + 0.0337, + 0.0246, + 0.3235, + 0.6486, + 0.4927, + 0.1669, + 0.0095, + 0.0142, + 0.0397, + 0.0338, + 0.1642, + 0.4653, + 0.4669, + 0.1659, + 0.0085 + ], + "noveltyPeaks": [ + { + "time": 1.95, + "strength": 0.7237 + }, + { + "time": 4.017, + "strength": 0.7892 + }, + { + "time": 6.432, + "strength": 0.7644 + }, + { + "time": 8.499, + "strength": 1.0 + }, + { + "time": 10.565, + "strength": 0.8102 + } + ], + "noveltyMean": 0.1386, + "noveltyStdDev": 0.1695 + }, + "segmentLoudness": [ + { + "segmentIndex": 0, + "start": 0.0, + "end": 11.034, + "lufs": -8.6, + "lra": 0.1 + } + ], + "segmentSpectral": [ + { + "segmentIndex": 0, + "barkBands": [ + -22.6535, + -6.7653, + -10.4344, + -21.3404, + -29.1583, + -27.4838, + -26.114, + -26.4434, + -29.9769, + -33.1218, + -33.2718, + -31.6134, + -36.8803, + -35.7062, + -37.3194, + -38.5859, + -38.7144, + -38.9772, + -39.8857, + -39.3104, + -37.9193, + -34.6128, + -34.7568, + -30.7898 + ], + "spectralCentroid": 1304.3, + "spectralRolloff": 1525.4, + "stereoWidth": 0.0, + "stereoCorrelation": 1.0 + } + ], + "segmentStereo": [ + { + "segmentIndex": 0, + "stereoWidth": 0.0, + "stereoCorrelation": 1.0 + } + ], + "segmentKey": [ + { + "segmentIndex": 0, + "key": "F Minor", + "keyConfidence": 0.59 + } + ], + "chordDetail": { + "chordSequence": [ + "Eb", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "Fm", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "Fm", + "C#", + "C#", + "C#", + "C#" + ], + "chordStrength": 0.6337, + "progression": [ + "Eb", + "C#", + "Fm", + "C#", + "Fm", + "C#", + "Fm", + "C#", + "Fm", + "C#", + "Fm", + "C#", + "Fm", + "C#", + "Fm", + "C#" + ], + "dominantChords": [ + "C#", + "Fm", + "Eb" + ], + "chordTimeline": [ + { + "startSec": 0.0, + "endSec": 11.053, + "label": "Fm", + "labelLong": "F minor", + "confidence": 0.5474 + } + ], + "chordChangeCount": 0, + "chordTimelineSource": "librosa_viterbi", + "chordTimelineAgreement": false + }, + "perceptual": { + "sharpness": 0.0792, + "roughness": 0.0 + }, + "essentiaFeatures": { + "zeroCrossingRate": 0.043, + "hfc": 225.4467, + "spectralComplexity": 11.4738, + "dissonance": 0.0 + } +} \ No newline at end of file diff --git a/apps/backend/tests/fixtures/recommendation_tracks/house_sidechain_pluck_124/README.md b/apps/backend/tests/fixtures/recommendation_tracks/house_sidechain_pluck_124/README.md new file mode 100644 index 00000000..3bfb7968 --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/house_sidechain_pluck_124/README.md @@ -0,0 +1,35 @@ +# house_sidechain_pluck_124 + +**Genre:** house · **Tempo:** 124 BPM · **Key:** A minor · **Render:** 48 kHz / 24-bit, 16 s loop + +## What this fixture isolates + +A clean, sparse house loop built around the techniques an intermediate producer +most wants to recover from a reference: + +1. **Sub-sine kick + sub-sine bass** — pure-sine fundamentals, no inharmonic + content (tests `kickDetail.fundamentalHz` recovery and bass synth-role recall). +2. **The classic 1/4-note sidechain pump** — bass keyed off the kick via a + `Compressor` (Threshold -20 dB, Ratio 4:1, fast attack, 120 ms release). This + is the single most-requested house move; the manifest's `measurableIntent` + records `sidechainDetail.pumpingStrength`/`pumpingRate` so an equivalent + route (e.g. a volume-LFO duck) still earns credit. +3. **Saw pluck lead** with a resonant lowpass and a short envelope, widened with + `Utility` and given space with `Reverb`. +4. **A two-stage master** — `Glue Compressor` (2:1 glue) into `Limiter` + (-0.3 dBFS ceiling). + +It deliberately covers all seven production domains (kick/bass/melody/groove/fx/ +stereo/master) so it exercises full-surface coverage (PURPOSE.md invariant #5). + +## Answer key + +The exact device chain is in `manifest.json` → `deviceSpec`. Build it verbatim in +Live 12 (see the authoring checklist in `../README.md`), render to `audio.flac`, +then store `phase1_fingerprint.json`. + +## Status + +- [x] Catalog-valid spec authored +- [ ] **NEEDS-FIXTURE:** rendered `audio.flac` (owner builds + renders) +- [ ] **NEEDS-FIXTURE:** stored `phase1_fingerprint.json` diff --git a/apps/backend/tests/fixtures/recommendation_tracks/house_sidechain_pluck_124/audio_melody.mid b/apps/backend/tests/fixtures/recommendation_tracks/house_sidechain_pluck_124/audio_melody.mid new file mode 100644 index 00000000..489c5c2f Binary files /dev/null and b/apps/backend/tests/fixtures/recommendation_tracks/house_sidechain_pluck_124/audio_melody.mid differ diff --git a/apps/backend/tests/fixtures/recommendation_tracks/house_sidechain_pluck_124/manifest.json b/apps/backend/tests/fixtures/recommendation_tracks/house_sidechain_pluck_124/manifest.json new file mode 100644 index 00000000..646da7d0 --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/house_sidechain_pluck_124/manifest.json @@ -0,0 +1,139 @@ +{ + "schemaVersion": "recommendation-fixture.v1", + "id": "house_sidechain_pluck_124", + "title": "House — sine sub, saw pluck, pumped sidechain", + "genre": "house", + "audioPath": "audio.flac", + "phase1FingerprintPath": "phase1_fingerprint.json", + "phase1Fingerprint": null, + "render": { + "sampleRateHz": 48000, + "bitDepth": 24, + "lengthSeconds": 16, + "bpm": 124, + "key": "A minor", + "notes": "8-bar loop. Render the full arrangement (kick + sub + pluck + hats) to one stereo file. Do NOT normalize on export — the measured LUFS/true-peak is part of the answer key." + }, + "deviceSpec": { + "kick": [ + { + "device": "Operator", + "family": "NATIVE", + "role": "Kick body", + "parameters": [ + { "name": "Oscillator A Waveform", "value": "Sine", "intent": "pure-sine kick body, no inharmonic content" }, + { "name": "Amp Envelope Decay", "value": "250 ms", "intent": "medium punchy tail" }, + { "name": "Amp Envelope Release", "value": "60 ms" }, + { "name": "Volume", "value": "-6 dB" } + ] + } + ], + "bass": [ + { + "device": "Operator", + "family": "NATIVE", + "role": "Sub bass", + "parameters": [ + { "name": "Oscillator A Waveform", "value": "Sine", "intent": "clean sub fundamental" }, + { "name": "Filter Type", "value": "Lowpass" }, + { "name": "Filter Frequency", "value": "200 Hz" }, + { "name": "Amp Envelope Decay", "value": "400 ms" } + ] + } + ], + "melody": [ + { + "device": "Wavetable", + "family": "NATIVE", + "role": "Saw pluck lead", + "parameters": [ + { "name": "Oscillator 1 Wavetable", "value": "Basic Shapes", "intent": "bright sawtooth source" }, + { "name": "Filter Type", "value": "Lowpass" }, + { "name": "Filter Frequency", "value": "3500 Hz" }, + { "name": "Filter Resonance", "value": "30%" }, + { "name": "Amp Envelope Attack", "value": "1 ms" }, + { "name": "Amp Envelope Decay", "value": "300 ms" }, + { "name": "Amp Envelope Sustain", "value": "20%" }, + { "name": "Amp Envelope Release", "value": "150 ms" } + ] + } + ], + "groove": [ + { + "device": "Drum Rack", + "family": "NATIVE", + "role": "Closed hats", + "parameters": [ + { "name": "Pad Volume", "value": "-8 dB" }, + { "name": "Pad Pan", "value": "0" } + ] + } + ], + "fx": [ + { + "device": "Compressor", + "family": "NATIVE", + "role": "Sidechain pump on bass (keyed off kick)", + "parameters": [ + { "name": "Threshold", "value": "-20 dB" }, + { "name": "Ratio", "value": "4:1" }, + { "name": "Attack", "value": "1 ms", "intent": "fast attack for hard duck" }, + { "name": "Release", "value": "120 ms", "intent": "release timed to the 1/4-note pump" }, + { "name": "Sidechain", "value": "On" } + ] + }, + { + "device": "Reverb", + "family": "NATIVE", + "role": "Pluck space", + "parameters": [ + { "name": "Decay Time", "value": "1.8 s" }, + { "name": "Predelay", "value": "20 ms" }, + { "name": "Dry/Wet", "value": "25%" } + ] + } + ], + "stereo": [ + { + "device": "Utility", + "family": "NATIVE", + "role": "Pluck widener", + "parameters": [ + { "name": "Stereo Width", "value": "130%" } + ] + } + ], + "master": [ + { + "device": "Glue Compressor", + "family": "NATIVE", + "role": "Bus glue", + "parameters": [ + { "name": "Threshold", "value": "-18 dB" }, + { "name": "Ratio", "value": "2:1" }, + { "name": "Attack", "value": "10 ms" }, + { "name": "Release", "value": "Auto" }, + { "name": "Makeup", "value": "3 dB" } + ] + }, + { + "device": "Limiter", + "family": "NATIVE", + "role": "Master ceiling", + "parameters": [ + { "name": "Ceiling", "value": "-0.3 dB" }, + { "name": "Release", "value": "100 ms" } + ] + } + ] + }, + "measurableIntent": { + "bpm": { "target": 124, "tolerance": 1, "direction": "exact" }, + "key": { "target": "A minor" }, + "kickDetail.fundamentalHz": { "target": 55, "tolerance": 15, "unit": "Hz" }, + "sidechainDetail.pumpingStrength": { "target": 0.5, "tolerance": 0.25, "direction": "min" }, + "sidechainDetail.pumpingRate": { "target": 2.07, "tolerance": 0.3, "unit": "Hz", "intent": "1/4-note pump at 124 BPM = 2.07 Hz" }, + "lufsIntegrated": { "target": -9, "tolerance": 2, "unit": "LUFS" }, + "truePeak": { "target": 1.0, "tolerance": 0.05, "intent": "limiter ceiling -0.3 dBFS rounds to ~1.0 linear" } + } +} diff --git a/apps/backend/tests/fixtures/recommendation_tracks/house_sidechain_pluck_124/phase1_fingerprint.json b/apps/backend/tests/fixtures/recommendation_tracks/house_sidechain_pluck_124/phase1_fingerprint.json new file mode 100644 index 00000000..1b225d9a --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/house_sidechain_pluck_124/phase1_fingerprint.json @@ -0,0 +1,4793 @@ +{ + "_synthetic": true, + "_note": "Phase 1 of a numpy PROXY render, NOT an Ableton render. Replace with a real Live render's fingerprint for an authoritative verdict.", + "bpm": 124.1, + "bpmConfidence": 4.0, + "bpmPercival": 123.8, + "bpmAgreement": true, + "bpmDoubletime": false, + "bpmSource": "rhythm_extractor_confirmed", + "bpmRawOriginal": 124.1, + "key": "A Minor", + "keyConfidence": 0.65, + "keyProfile": "edma", + "tuningFrequency": 438.73, + "tuningCents": -5.0, + "timeSignature": "4/4", + "timeSignatureSource": "onset_autocorrelation_low_margin", + "timeSignatureConfidence": 0.0, + "durationSeconds": 15.5, + "sampleRate": 44100, + "lufsIntegrated": -9.7, + "lufsRange": 0.2, + "lufsMomentaryMax": -9.2, + "lufsShortTermMax": -9.6, + "lufsCurve": { + "shortTerm": [ + { + "t": 0.0, + "lufs": -9.7 + }, + { + "t": 0.1, + "lufs": -9.8 + }, + { + "t": 0.2, + "lufs": -9.7 + }, + { + "t": 0.3, + "lufs": -9.8 + }, + { + "t": 0.4, + "lufs": -9.8 + }, + { + "t": 0.5, + "lufs": -9.7 + }, + { + "t": 0.6, + "lufs": -9.8 + }, + { + "t": 0.7, + "lufs": -9.7 + }, + { + "t": 0.8, + "lufs": -9.8 + }, + { + "t": 0.9, + "lufs": -9.7 + }, + { + "t": 1.0, + "lufs": -9.8 + }, + { + "t": 1.1, + "lufs": -9.8 + }, + { + "t": 1.2, + "lufs": -9.7 + }, + { + "t": 1.3, + "lufs": -9.8 + }, + { + "t": 1.4, + "lufs": -9.7 + }, + { + "t": 1.5, + "lufs": -9.8 + }, + { + "t": 1.6, + "lufs": -9.8 + }, + { + "t": 1.7, + "lufs": -9.7 + }, + { + "t": 1.8, + "lufs": -9.8 + }, + { + "t": 1.9, + "lufs": -9.7 + }, + { + "t": 2.0, + "lufs": -9.8 + }, + { + "t": 2.1, + "lufs": -9.7 + }, + { + "t": 2.2, + "lufs": -9.8 + }, + { + "t": 2.3, + "lufs": -9.8 + }, + { + "t": 2.4, + "lufs": -9.7 + }, + { + "t": 2.5, + "lufs": -9.8 + }, + { + "t": 2.6, + "lufs": -9.7 + }, + { + "t": 2.7, + "lufs": -9.8 + }, + { + "t": 2.8, + "lufs": -9.8 + }, + { + "t": 2.9, + "lufs": -9.7 + }, + { + "t": 3.0, + "lufs": -9.8 + }, + { + "t": 3.1, + "lufs": -9.7 + }, + { + "t": 3.2, + "lufs": -9.8 + }, + { + "t": 3.3, + "lufs": -9.8 + }, + { + "t": 3.4, + "lufs": -9.7 + }, + { + "t": 3.5, + "lufs": -9.8 + }, + { + "t": 3.6, + "lufs": -9.7 + }, + { + "t": 3.7, + "lufs": -9.8 + }, + { + "t": 3.8, + "lufs": -9.7 + }, + { + "t": 3.9, + "lufs": -9.7 + }, + { + "t": 4.0, + "lufs": -9.8 + }, + { + "t": 4.1, + "lufs": -9.7 + }, + { + "t": 4.2, + "lufs": -9.8 + }, + { + "t": 4.3, + "lufs": -9.7 + }, + { + "t": 4.4, + "lufs": -9.8 + }, + { + "t": 4.5, + "lufs": -9.8 + }, + { + "t": 4.6, + "lufs": -9.7 + }, + { + "t": 4.7, + "lufs": -9.8 + }, + { + "t": 4.8, + "lufs": -9.7 + }, + { + "t": 4.9, + "lufs": -9.8 + }, + { + "t": 5.0, + "lufs": -9.7 + }, + { + "t": 5.1, + "lufs": -9.7 + }, + { + "t": 5.2, + "lufs": -9.8 + }, + { + "t": 5.3, + "lufs": -9.7 + }, + { + "t": 5.4, + "lufs": -9.8 + }, + { + "t": 5.5, + "lufs": -9.7 + }, + { + "t": 5.6, + "lufs": -9.8 + }, + { + "t": 5.7, + "lufs": -9.8 + }, + { + "t": 5.8, + "lufs": -9.7 + }, + { + "t": 5.9, + "lufs": -9.8 + }, + { + "t": 6.0, + "lufs": -9.7 + }, + { + "t": 6.1, + "lufs": -9.8 + }, + { + "t": 6.2, + "lufs": -9.8 + }, + { + "t": 6.3, + "lufs": -9.7 + }, + { + "t": 6.4, + "lufs": -9.8 + }, + { + "t": 6.5, + "lufs": -9.7 + }, + { + "t": 6.6, + "lufs": -9.8 + }, + { + "t": 6.7, + "lufs": -9.7 + }, + { + "t": 6.8, + "lufs": -9.7 + }, + { + "t": 6.9, + "lufs": -9.8 + }, + { + "t": 7.0, + "lufs": -9.6 + }, + { + "t": 7.1, + "lufs": -9.8 + }, + { + "t": 7.2, + "lufs": -9.7 + }, + { + "t": 7.3, + "lufs": -9.7 + }, + { + "t": 7.4, + "lufs": -9.8 + }, + { + "t": 7.5, + "lufs": -9.6 + }, + { + "t": 7.6, + "lufs": -9.8 + }, + { + "t": 7.7, + "lufs": -9.7 + }, + { + "t": 7.8, + "lufs": -9.8 + }, + { + "t": 7.9, + "lufs": -9.7 + }, + { + "t": 8.0, + "lufs": -9.7 + }, + { + "t": 8.1, + "lufs": -9.8 + }, + { + "t": 8.2, + "lufs": -9.6 + }, + { + "t": 8.3, + "lufs": -9.8 + }, + { + "t": 8.4, + "lufs": -9.7 + }, + { + "t": 8.5, + "lufs": -9.7 + }, + { + "t": 8.6, + "lufs": -9.8 + }, + { + "t": 8.7, + "lufs": -9.7 + }, + { + "t": 8.8, + "lufs": -9.8 + }, + { + "t": 8.9, + "lufs": -9.7 + }, + { + "t": 9.0, + "lufs": -9.8 + }, + { + "t": 9.1, + "lufs": -9.8 + }, + { + "t": 9.2, + "lufs": -9.7 + }, + { + "t": 9.3, + "lufs": -9.8 + }, + { + "t": 9.4, + "lufs": -9.6 + }, + { + "t": 9.5, + "lufs": -9.8 + }, + { + "t": 9.6, + "lufs": -9.7 + }, + { + "t": 9.7, + "lufs": -9.7 + }, + { + "t": 9.8, + "lufs": -9.8 + }, + { + "t": 9.9, + "lufs": -9.6 + }, + { + "t": 10.0, + "lufs": -9.8 + }, + { + "t": 10.1, + "lufs": -9.7 + }, + { + "t": 10.2, + "lufs": -9.7 + }, + { + "t": 10.3, + "lufs": -9.8 + }, + { + "t": 10.4, + "lufs": -9.6 + }, + { + "t": 10.5, + "lufs": -9.8 + }, + { + "t": 10.6, + "lufs": -9.7 + }, + { + "t": 10.7, + "lufs": -9.8 + }, + { + "t": 10.8, + "lufs": -9.7 + }, + { + "t": 10.9, + "lufs": -9.7 + }, + { + "t": 11.0, + "lufs": -9.8 + }, + { + "t": 11.1, + "lufs": -9.6 + }, + { + "t": 11.2, + "lufs": -9.8 + }, + { + "t": 11.3, + "lufs": -9.7 + }, + { + "t": 11.4, + "lufs": -9.7 + }, + { + "t": 11.5, + "lufs": -9.8 + }, + { + "t": 11.6, + "lufs": -9.7 + }, + { + "t": 11.7, + "lufs": -9.8 + }, + { + "t": 11.8, + "lufs": -9.6 + }, + { + "t": 11.9, + "lufs": -9.7 + }, + { + "t": 12.0, + "lufs": -9.8 + }, + { + "t": 12.1, + "lufs": -9.6 + }, + { + "t": 12.2, + "lufs": -9.8 + }, + { + "t": 12.3, + "lufs": -9.6 + }, + { + "t": 12.4, + "lufs": -9.8 + }, + { + "t": 12.5, + "lufs": -9.8 + } + ], + "momentary": [ + { + "t": 0.0, + "lufs": -9.6 + }, + { + "t": 0.1, + "lufs": -9.9 + }, + { + "t": 0.2, + "lufs": -9.2 + }, + { + "t": 0.3, + "lufs": -10.3 + }, + { + "t": 0.4, + "lufs": -9.4 + }, + { + "t": 0.5, + "lufs": -9.8 + }, + { + "t": 0.6, + "lufs": -9.8 + }, + { + "t": 0.7, + "lufs": -9.3 + }, + { + "t": 0.8, + "lufs": -10.5 + }, + { + "t": 0.9, + "lufs": -9.4 + }, + { + "t": 1.0, + "lufs": -9.9 + }, + { + "t": 1.1, + "lufs": -9.7 + }, + { + "t": 1.2, + "lufs": -9.4 + }, + { + "t": 1.3, + "lufs": -10.4 + }, + { + "t": 1.4, + "lufs": -9.6 + }, + { + "t": 1.5, + "lufs": -10.2 + }, + { + "t": 1.6, + "lufs": -9.4 + }, + { + "t": 1.7, + "lufs": -9.5 + }, + { + "t": 1.8, + "lufs": -9.7 + }, + { + "t": 1.9, + "lufs": -9.4 + }, + { + "t": 2.0, + "lufs": -10.4 + }, + { + "t": 2.1, + "lufs": -9.4 + }, + { + "t": 2.2, + "lufs": -10.0 + }, + { + "t": 2.3, + "lufs": -9.6 + }, + { + "t": 2.4, + "lufs": -9.4 + }, + { + "t": 2.5, + "lufs": -10.3 + }, + { + "t": 2.6, + "lufs": -9.5 + }, + { + "t": 2.7, + "lufs": -10.4 + }, + { + "t": 2.8, + "lufs": -9.6 + }, + { + "t": 2.9, + "lufs": -9.6 + }, + { + "t": 3.0, + "lufs": -10.0 + }, + { + "t": 3.1, + "lufs": -9.3 + }, + { + "t": 3.2, + "lufs": -10.3 + }, + { + "t": 3.3, + "lufs": -9.4 + }, + { + "t": 3.4, + "lufs": -9.7 + }, + { + "t": 3.5, + "lufs": -9.8 + }, + { + "t": 3.6, + "lufs": -9.3 + }, + { + "t": 3.7, + "lufs": -10.5 + }, + { + "t": 3.8, + "lufs": -9.4 + }, + { + "t": 3.9, + "lufs": -9.9 + }, + { + "t": 4.0, + "lufs": -9.8 + }, + { + "t": 4.1, + "lufs": -9.4 + }, + { + "t": 4.2, + "lufs": -10.6 + }, + { + "t": 4.3, + "lufs": -9.6 + }, + { + "t": 4.4, + "lufs": -10.1 + }, + { + "t": 4.5, + "lufs": -9.4 + }, + { + "t": 4.6, + "lufs": -9.3 + }, + { + "t": 4.7, + "lufs": -9.7 + }, + { + "t": 4.8, + "lufs": -9.4 + }, + { + "t": 4.9, + "lufs": -10.3 + }, + { + "t": 5.0, + "lufs": -9.4 + }, + { + "t": 5.1, + "lufs": -9.9 + }, + { + "t": 5.2, + "lufs": -9.6 + }, + { + "t": 5.3, + "lufs": -9.4 + }, + { + "t": 5.4, + "lufs": -10.3 + }, + { + "t": 5.5, + "lufs": -9.5 + }, + { + "t": 5.6, + "lufs": -10.4 + }, + { + "t": 5.7, + "lufs": -9.6 + }, + { + "t": 5.8, + "lufs": -9.6 + }, + { + "t": 5.9, + "lufs": -10.1 + }, + { + "t": 6.0, + "lufs": -9.3 + }, + { + "t": 6.1, + "lufs": -10.3 + }, + { + "t": 6.2, + "lufs": -9.4 + }, + { + "t": 6.3, + "lufs": -9.6 + }, + { + "t": 6.4, + "lufs": -9.9 + }, + { + "t": 6.5, + "lufs": -9.3 + }, + { + "t": 6.6, + "lufs": -10.4 + }, + { + "t": 6.7, + "lufs": -9.4 + }, + { + "t": 6.8, + "lufs": -9.9 + }, + { + "t": 6.9, + "lufs": -9.8 + }, + { + "t": 7.0, + "lufs": -9.4 + }, + { + "t": 7.1, + "lufs": -10.7 + }, + { + "t": 7.2, + "lufs": -9.6 + }, + { + "t": 7.3, + "lufs": -10.1 + }, + { + "t": 7.4, + "lufs": -9.5 + }, + { + "t": 7.5, + "lufs": -9.2 + }, + { + "t": 7.6, + "lufs": -9.8 + }, + { + "t": 7.7, + "lufs": -9.4 + }, + { + "t": 7.8, + "lufs": -10.3 + }, + { + "t": 7.9, + "lufs": -9.4 + }, + { + "t": 8.0, + "lufs": -9.8 + }, + { + "t": 8.1, + "lufs": -9.6 + }, + { + "t": 8.2, + "lufs": -9.4 + }, + { + "t": 8.3, + "lufs": -10.3 + }, + { + "t": 8.4, + "lufs": -9.5 + }, + { + "t": 8.5, + "lufs": -10.3 + }, + { + "t": 8.6, + "lufs": -9.6 + }, + { + "t": 8.7, + "lufs": -9.6 + }, + { + "t": 8.8, + "lufs": -10.2 + }, + { + "t": 8.9, + "lufs": -9.2 + }, + { + "t": 9.0, + "lufs": -10.2 + }, + { + "t": 9.1, + "lufs": -9.4 + }, + { + "t": 9.2, + "lufs": -9.5 + }, + { + "t": 9.3, + "lufs": -10.0 + }, + { + "t": 9.4, + "lufs": -9.3 + }, + { + "t": 9.5, + "lufs": -10.4 + }, + { + "t": 9.6, + "lufs": -9.4 + }, + { + "t": 9.7, + "lufs": -9.8 + }, + { + "t": 9.8, + "lufs": -9.8 + }, + { + "t": 9.9, + "lufs": -9.4 + }, + { + "t": 10.0, + "lufs": -10.6 + }, + { + "t": 10.1, + "lufs": -9.6 + }, + { + "t": 10.2, + "lufs": -10.0 + }, + { + "t": 10.3, + "lufs": -9.5 + }, + { + "t": 10.4, + "lufs": -9.2 + }, + { + "t": 10.5, + "lufs": -9.9 + }, + { + "t": 10.6, + "lufs": -9.4 + }, + { + "t": 10.7, + "lufs": -10.3 + }, + { + "t": 10.8, + "lufs": -9.4 + }, + { + "t": 10.9, + "lufs": -9.8 + }, + { + "t": 11.0, + "lufs": -9.6 + }, + { + "t": 11.1, + "lufs": -9.4 + }, + { + "t": 11.2, + "lufs": -10.3 + }, + { + "t": 11.3, + "lufs": -9.5 + }, + { + "t": 11.4, + "lufs": -10.2 + }, + { + "t": 11.5, + "lufs": -9.6 + }, + { + "t": 11.6, + "lufs": -9.6 + }, + { + "t": 11.7, + "lufs": -10.3 + }, + { + "t": 11.8, + "lufs": -9.3 + }, + { + "t": 11.9, + "lufs": -10.2 + }, + { + "t": 12.0, + "lufs": -9.4 + }, + { + "t": 12.1, + "lufs": -9.4 + }, + { + "t": 12.2, + "lufs": -10.0 + }, + { + "t": 12.3, + "lufs": -9.3 + }, + { + "t": 12.4, + "lufs": -10.4 + }, + { + "t": 12.5, + "lufs": -9.4 + }, + { + "t": 12.6, + "lufs": -9.7 + }, + { + "t": 12.7, + "lufs": -9.8 + }, + { + "t": 12.8, + "lufs": -9.4 + }, + { + "t": 12.9, + "lufs": -10.6 + }, + { + "t": 13.0, + "lufs": -9.6 + }, + { + "t": 13.1, + "lufs": -10.0 + }, + { + "t": 13.2, + "lufs": -9.5 + }, + { + "t": 13.3, + "lufs": -9.2 + }, + { + "t": 13.4, + "lufs": -9.9 + }, + { + "t": 13.5, + "lufs": -9.4 + }, + { + "t": 13.6, + "lufs": -10.2 + }, + { + "t": 13.7, + "lufs": -9.5 + }, + { + "t": 13.8, + "lufs": -9.7 + }, + { + "t": 13.9, + "lufs": -9.7 + }, + { + "t": 14.0, + "lufs": -9.4 + }, + { + "t": 14.1, + "lufs": -10.2 + }, + { + "t": 14.2, + "lufs": -9.5 + }, + { + "t": 14.3, + "lufs": -10.1 + }, + { + "t": 14.4, + "lufs": -9.6 + }, + { + "t": 14.5, + "lufs": -9.5 + }, + { + "t": 14.6, + "lufs": -10.3 + }, + { + "t": 14.7, + "lufs": -9.3 + }, + { + "t": 14.8, + "lufs": -10.2 + }, + { + "t": 14.9, + "lufs": -9.4 + }, + { + "t": 15.0, + "lufs": -9.4 + }, + { + "t": 15.1, + "lufs": -10.6 + } + ] + }, + "truePeak": 1.1, + "plr": 10.8, + "crestFactor": 10.8, + "dynamicSpread": 37.22, + "dynamicCharacter": { + "dynamicComplexity": 1.6475, + "loudnessDb": -17.6967, + "loudnessVariation": -17.6967, + "spectralFlatness": 0.1067, + "logAttackTime": -4.6988, + "attackTimeStdDev": 0.0021 + }, + "textureCharacter": { + "textureScore": 0.33, + "lowBandFlatness": 0.337, + "midBandFlatness": 0.3103, + "highBandFlatness": 0.2838, + "inharmonicity": 0.1088 + }, + "stereoDetail": { + "stereoWidth": 0.0, + "stereoCorrelation": 1.0, + "subBassCorrelation": 1.0, + "subBassMono": true, + "correlationCurve": [ + { + "t": 0.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 1.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 2.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 3.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 4.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 5.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 6.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 7.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 8.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 9.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 10.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 11.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 12.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 13.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 14.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 15.5, + "full": 1.0, + "sub": 1.0 + } + ], + "bandCorrelations": { + "subBass": 1.0, + "lowBass": 1.0, + "lowMids": 1.0, + "mids": 1.0, + "upperMids": 1.0, + "highs": 1.0, + "brilliance": 1.0 + } + }, + "monoCompatible": true, + "spectralBalance": { + "subBass": -9.4, + "lowBass": -9.3, + "lowMids": -30.1, + "mids": -24.3, + "upperMids": -32.2, + "highs": -28.4, + "brilliance": -20.8 + }, + "spectralBalanceTimeSeries": [ + { + "t": 0.03, + "subBass": -6.7, + "lowBass": -6.7, + "lowMids": -30.5, + "mids": -29.4, + "upperMids": -41.1, + "highs": -51.6, + "brilliance": -79.0 + }, + { + "t": 0.13, + "subBass": -6.8, + "lowBass": -14.6, + "lowMids": -47.1, + "mids": -26.1, + "upperMids": -37.3, + "highs": -47.8, + "brilliance": -96.4 + }, + { + "t": 0.22, + "subBass": -9.5, + "lowBass": -12.5, + "lowMids": -43.1, + "mids": -24.9, + "upperMids": -29.1, + "highs": -23.1, + "brilliance": -15.2 + }, + { + "t": 0.31, + "subBass": -13.3, + "lowBass": -9.4, + "lowMids": -45.4, + "mids": -24.0, + "upperMids": -30.7, + "highs": -26.7, + "brilliance": -19.1 + }, + { + "t": 0.41, + "subBass": -19.1, + "lowBass": -9.0, + "lowMids": -41.8, + "mids": -20.1, + "upperMids": -29.3, + "highs": -38.8, + "brilliance": -57.3 + }, + { + "t": 0.5, + "subBass": -8.6, + "lowBass": -5.2, + "lowMids": -27.4, + "mids": -28.8, + "upperMids": -37.8, + "highs": -46.8, + "brilliance": -51.7 + }, + { + "t": 0.59, + "subBass": -6.2, + "lowBass": -14.3, + "lowMids": -28.9, + "mids": -28.3, + "upperMids": -39.2, + "highs": -54.8, + "brilliance": -81.5 + }, + { + "t": 0.68, + "subBass": -8.9, + "lowBass": -13.6, + "lowMids": -28.9, + "mids": -26.6, + "upperMids": -34.0, + "highs": -28.5, + "brilliance": -21.5 + }, + { + "t": 0.78, + "subBass": -11.8, + "lowBass": -9.6, + "lowMids": -44.8, + "mids": -22.8, + "upperMids": -28.1, + "highs": -22.8, + "brilliance": -14.7 + }, + { + "t": 0.87, + "subBass": -14.8, + "lowBass": -9.0, + "lowMids": -40.6, + "mids": -20.5, + "upperMids": -29.7, + "highs": -39.2, + "brilliance": -56.6 + }, + { + "t": 0.96, + "subBass": -10.9, + "lowBass": -5.4, + "lowMids": -28.4, + "mids": -25.8, + "upperMids": -35.8, + "highs": -45.1, + "brilliance": -53.8 + }, + { + "t": 1.06, + "subBass": -5.6, + "lowBass": -12.3, + "lowMids": -33.0, + "mids": -29.0, + "upperMids": -40.0, + "highs": -53.4, + "brilliance": -79.1 + }, + { + "t": 1.15, + "subBass": -8.6, + "lowBass": -13.7, + "lowMids": -38.7, + "mids": -25.6, + "upperMids": -36.3, + "highs": -49.2, + "brilliance": -107.4 + }, + { + "t": 1.24, + "subBass": -12.0, + "lowBass": -10.3, + "lowMids": -39.8, + "mids": -23.0, + "upperMids": -27.7, + "highs": -21.4, + "brilliance": -13.7 + }, + { + "t": 1.34, + "subBass": -15.6, + "lowBass": -9.1, + "lowMids": -32.7, + "mids": -21.0, + "upperMids": -31.2, + "highs": -43.1, + "brilliance": -57.1 + }, + { + "t": 1.43, + "subBass": -22.6, + "lowBass": -7.1, + "lowMids": -29.1, + "mids": -23.7, + "upperMids": -34.6, + "highs": -46.4, + "brilliance": -54.8 + }, + { + "t": 1.52, + "subBass": -5.3, + "lowBass": -9.5, + "lowMids": -32.0, + "mids": -31.0, + "upperMids": -43.0, + "highs": -57.5, + "brilliance": -95.1 + }, + { + "t": 1.61, + "subBass": -7.8, + "lowBass": -14.0, + "lowMids": -48.5, + "mids": -25.2, + "upperMids": -33.9, + "highs": -45.3, + "brilliance": -81.7 + }, + { + "t": 1.71, + "subBass": -10.5, + "lowBass": -11.1, + "lowMids": -25.1, + "mids": -23.4, + "upperMids": -28.2, + "highs": -21.1, + "brilliance": -13.5 + }, + { + "t": 1.8, + "subBass": -14.4, + "lowBass": -9.1, + "lowMids": -28.4, + "mids": -21.8, + "upperMids": -32.7, + "highs": -43.3, + "brilliance": -38.6 + }, + { + "t": 1.89, + "subBass": -24.7, + "lowBass": -8.5, + "lowMids": -31.3, + "mids": -22.2, + "upperMids": -32.7, + "highs": -44.4, + "brilliance": -53.3 + }, + { + "t": 1.99, + "subBass": -6.0, + "lowBass": -6.2, + "lowMids": -35.1, + "mids": -29.9, + "upperMids": -41.2, + "highs": -49.7, + "brilliance": -63.7 + }, + { + "t": 2.08, + "subBass": -7.3, + "lowBass": -14.2, + "lowMids": -45.7, + "mids": -25.4, + "upperMids": -36.6, + "highs": -47.0, + "brilliance": -81.2 + }, + { + "t": 2.17, + "subBass": -10.0, + "lowBass": -11.9, + "lowMids": -25.8, + "mids": -27.0, + "upperMids": -28.8, + "highs": -21.3, + "brilliance": -13.7 + }, + { + "t": 2.26, + "subBass": -12.5, + "lowBass": -9.2, + "lowMids": -24.0, + "mids": -27.5, + "upperMids": -33.6, + "highs": -31.1, + "brilliance": -23.4 + }, + { + "t": 2.36, + "subBass": -16.6, + "lowBass": -8.9, + "lowMids": -21.7, + "mids": -25.7, + "upperMids": -32.6, + "highs": -57.3, + "brilliance": -59.6 + }, + { + "t": 2.45, + "subBass": -6.9, + "lowBass": -6.0, + "lowMids": -28.3, + "mids": -29.8, + "upperMids": -38.6, + "highs": -47.6, + "brilliance": -54.3 + }, + { + "t": 2.54, + "subBass": -6.6, + "lowBass": -14.4, + "lowMids": -49.2, + "mids": -26.6, + "upperMids": -35.4, + "highs": -46.6, + "brilliance": -83.7 + }, + { + "t": 2.64, + "subBass": -9.9, + "lowBass": -12.6, + "lowMids": -42.8, + "mids": -25.1, + "upperMids": -29.1, + "highs": -22.8, + "brilliance": -15.3 + }, + { + "t": 2.73, + "subBass": -13.2, + "lowBass": -9.4, + "lowMids": -45.4, + "mids": -23.8, + "upperMids": -30.0, + "highs": -25.7, + "brilliance": -17.9 + }, + { + "t": 2.82, + "subBass": -18.8, + "lowBass": -8.9, + "lowMids": -39.9, + "mids": -19.8, + "upperMids": -31.0, + "highs": -41.4, + "brilliance": -60.0 + }, + { + "t": 2.91, + "subBass": -8.8, + "lowBass": -6.1, + "lowMids": -28.4, + "mids": -27.1, + "upperMids": -36.7, + "highs": -45.8, + "brilliance": -51.1 + }, + { + "t": 3.01, + "subBass": -5.9, + "lowBass": -13.7, + "lowMids": -39.0, + "mids": -27.6, + "upperMids": -37.7, + "highs": -50.1, + "brilliance": -77.0 + }, + { + "t": 3.1, + "subBass": -8.7, + "lowBass": -13.6, + "lowMids": -38.8, + "mids": -26.4, + "upperMids": -35.8, + "highs": -33.4, + "brilliance": -26.6 + }, + { + "t": 3.19, + "subBass": -12.6, + "lowBass": -9.8, + "lowMids": -42.7, + "mids": -22.2, + "upperMids": -28.6, + "highs": -21.7, + "brilliance": -13.9 + }, + { + "t": 3.29, + "subBass": -16.7, + "lowBass": -9.1, + "lowMids": -41.1, + "mids": -20.5, + "upperMids": -29.3, + "highs": -40.6, + "brilliance": -57.9 + }, + { + "t": 3.38, + "subBass": -13.3, + "lowBass": -5.3, + "lowMids": -28.9, + "mids": -26.3, + "upperMids": -34.7, + "highs": -45.6, + "brilliance": -53.5 + }, + { + "t": 3.47, + "subBass": -5.4, + "lowBass": -11.6, + "lowMids": -31.7, + "mids": -32.0, + "upperMids": -40.8, + "highs": -56.6, + "brilliance": -81.6 + }, + { + "t": 3.56, + "subBass": -8.5, + "lowBass": -13.8, + "lowMids": -38.4, + "mids": -25.3, + "upperMids": -36.1, + "highs": -49.0, + "brilliance": -106.7 + }, + { + "t": 3.66, + "subBass": -10.8, + "lowBass": -10.5, + "lowMids": -23.9, + "mids": -27.2, + "upperMids": -28.7, + "highs": -21.8, + "brilliance": -13.9 + }, + { + "t": 3.75, + "subBass": -13.6, + "lowBass": -9.2, + "lowMids": -30.2, + "mids": -21.2, + "upperMids": -32.1, + "highs": -42.9, + "brilliance": -56.7 + }, + { + "t": 3.84, + "subBass": -17.2, + "lowBass": -6.7, + "lowMids": -30.4, + "mids": -23.5, + "upperMids": -34.5, + "highs": -44.2, + "brilliance": -54.6 + }, + { + "t": 3.94, + "subBass": -5.4, + "lowBass": -7.8, + "lowMids": -37.6, + "mids": -30.9, + "upperMids": -40.1, + "highs": -49.6, + "brilliance": -95.0 + }, + { + "t": 4.03, + "subBass": -7.8, + "lowBass": -14.1, + "lowMids": -26.2, + "mids": -30.0, + "upperMids": -37.0, + "highs": -64.7, + "brilliance": -81.7 + }, + { + "t": 4.12, + "subBass": -11.1, + "lowBass": -11.2, + "lowMids": -31.0, + "mids": -23.5, + "upperMids": -28.4, + "highs": -21.7, + "brilliance": -13.8 + }, + { + "t": 4.21, + "subBass": -14.3, + "lowBass": -9.2, + "lowMids": -32.8, + "mids": -21.9, + "upperMids": -32.5, + "highs": -39.2, + "brilliance": -32.5 + }, + { + "t": 4.31, + "subBass": -23.5, + "lowBass": -8.8, + "lowMids": -32.2, + "mids": -21.8, + "upperMids": -32.3, + "highs": -44.6, + "brilliance": -55.5 + }, + { + "t": 4.4, + "subBass": -6.3, + "lowBass": -6.9, + "lowMids": -33.7, + "mids": -29.9, + "upperMids": -38.8, + "highs": -47.7, + "brilliance": -56.8 + }, + { + "t": 4.49, + "subBass": -7.0, + "lowBass": -14.2, + "lowMids": -27.6, + "mids": -26.0, + "upperMids": -37.6, + "highs": -51.5, + "brilliance": -84.3 + }, + { + "t": 4.59, + "subBass": -9.7, + "lowBass": -12.1, + "lowMids": -32.2, + "mids": -23.9, + "upperMids": -29.0, + "highs": -21.8, + "brilliance": -14.1 + }, + { + "t": 4.68, + "subBass": -13.6, + "lowBass": -9.3, + "lowMids": -32.6, + "mids": -23.6, + "upperMids": -33.1, + "highs": -29.8, + "brilliance": -22.2 + }, + { + "t": 4.77, + "subBass": -20.8, + "lowBass": -9.0, + "lowMids": -22.1, + "mids": -20.8, + "upperMids": -32.8, + "highs": -46.7, + "brilliance": -57.6 + }, + { + "t": 4.86, + "subBass": -7.5, + "lowBass": -5.5, + "lowMids": -28.1, + "mids": -30.8, + "upperMids": -40.0, + "highs": -50.4, + "brilliance": -53.1 + }, + { + "t": 4.96, + "subBass": -6.5, + "lowBass": -14.5, + "lowMids": -36.4, + "mids": -27.0, + "upperMids": -35.6, + "highs": -47.3, + "brilliance": -83.8 + }, + { + "t": 5.05, + "subBass": -9.3, + "lowBass": -13.0, + "lowMids": -29.3, + "mids": -27.0, + "upperMids": -30.5, + "highs": -23.1, + "brilliance": -15.7 + }, + { + "t": 5.14, + "subBass": -12.1, + "lowBass": -9.5, + "lowMids": -24.3, + "mids": -28.3, + "upperMids": -30.8, + "highs": -25.0, + "brilliance": -17.0 + }, + { + "t": 5.24, + "subBass": -15.3, + "lowBass": -9.0, + "lowMids": -22.0, + "mids": -20.6, + "upperMids": -32.3, + "highs": -46.6, + "brilliance": -58.9 + }, + { + "t": 5.33, + "subBass": -9.1, + "lowBass": -5.7, + "lowMids": -27.5, + "mids": -27.1, + "upperMids": -38.4, + "highs": -47.8, + "brilliance": -52.6 + }, + { + "t": 5.42, + "subBass": -5.9, + "lowBass": -13.9, + "lowMids": -44.9, + "mids": -27.8, + "upperMids": -39.0, + "highs": -49.5, + "brilliance": -97.9 + }, + { + "t": 5.51, + "subBass": -8.9, + "lowBass": -13.6, + "lowMids": -45.6, + "mids": -26.3, + "upperMids": -37.3, + "highs": -40.8, + "brilliance": -34.6 + }, + { + "t": 5.61, + "subBass": -12.6, + "lowBass": -9.9, + "lowMids": -23.4, + "mids": -27.1, + "upperMids": -28.4, + "highs": -21.0, + "brilliance": -13.4 + }, + { + "t": 5.7, + "subBass": -16.4, + "lowBass": -9.0, + "lowMids": -33.4, + "mids": -20.9, + "upperMids": -30.0, + "highs": -39.7, + "brilliance": -59.9 + }, + { + "t": 5.79, + "subBass": -14.9, + "lowBass": -6.7, + "lowMids": -30.6, + "mids": -25.2, + "upperMids": -34.1, + "highs": -42.8, + "brilliance": -50.1 + }, + { + "t": 5.89, + "subBass": -5.1, + "lowBass": -10.0, + "lowMids": -42.2, + "mids": -30.7, + "upperMids": -39.5, + "highs": -50.5, + "brilliance": -77.4 + }, + { + "t": 5.98, + "subBass": -8.1, + "lowBass": -13.8, + "lowMids": -50.8, + "mids": -25.6, + "upperMids": -34.7, + "highs": -44.2, + "brilliance": -86.4 + }, + { + "t": 6.07, + "subBass": -11.3, + "lowBass": -10.6, + "lowMids": -24.1, + "mids": -27.3, + "upperMids": -28.6, + "highs": -21.4, + "brilliance": -13.6 + }, + { + "t": 6.16, + "subBass": -14.9, + "lowBass": -9.2, + "lowMids": -29.8, + "mids": -21.7, + "upperMids": -30.4, + "highs": -42.0, + "brilliance": -58.4 + }, + { + "t": 6.26, + "subBass": -26.9, + "lowBass": -6.8, + "lowMids": -34.3, + "mids": -23.5, + "upperMids": -32.1, + "highs": -42.9, + "brilliance": -53.2 + }, + { + "t": 6.35, + "subBass": -5.6, + "lowBass": -7.4, + "lowMids": -35.5, + "mids": -30.2, + "upperMids": -41.0, + "highs": -53.9, + "brilliance": -113.5 + }, + { + "t": 6.44, + "subBass": -7.6, + "lowBass": -14.1, + "lowMids": -44.5, + "mids": -25.2, + "upperMids": -36.4, + "highs": -46.9, + "brilliance": -79.1 + }, + { + "t": 6.54, + "subBass": -10.3, + "lowBass": -11.4, + "lowMids": -42.1, + "mids": -23.8, + "upperMids": -28.4, + "highs": -21.9, + "brilliance": -14.0 + }, + { + "t": 6.63, + "subBass": -12.8, + "lowBass": -9.2, + "lowMids": -26.1, + "mids": -22.6, + "upperMids": -32.7, + "highs": -36.0, + "brilliance": -28.7 + }, + { + "t": 6.72, + "subBass": -17.0, + "lowBass": -9.0, + "lowMids": -23.3, + "mids": -21.9, + "upperMids": -33.6, + "highs": -47.2, + "brilliance": -56.3 + }, + { + "t": 6.82, + "subBass": -6.4, + "lowBass": -5.6, + "lowMids": -30.5, + "mids": -29.6, + "upperMids": -38.3, + "highs": -47.7, + "brilliance": -52.9 + }, + { + "t": 6.91, + "subBass": -7.0, + "lowBass": -14.4, + "lowMids": -27.9, + "mids": -26.3, + "upperMids": -37.7, + "highs": -51.9, + "brilliance": -74.6 + }, + { + "t": 7.0, + "subBass": -10.2, + "lowBass": -12.2, + "lowMids": -30.7, + "mids": -24.3, + "upperMids": -29.3, + "highs": -22.7, + "brilliance": -14.7 + }, + { + "t": 7.09, + "subBass": -13.5, + "lowBass": -9.3, + "lowMids": -37.0, + "mids": -23.9, + "upperMids": -32.8, + "highs": -28.4, + "brilliance": -21.0 + }, + { + "t": 7.19, + "subBass": -20.2, + "lowBass": -8.9, + "lowMids": -42.0, + "mids": -20.5, + "upperMids": -29.6, + "highs": -39.1, + "brilliance": -57.4 + }, + { + "t": 7.28, + "subBass": -8.0, + "lowBass": -6.2, + "lowMids": -33.0, + "mids": -28.3, + "upperMids": -37.9, + "highs": -47.3, + "brilliance": -53.0 + }, + { + "t": 7.37, + "subBass": -6.3, + "lowBass": -14.6, + "lowMids": -44.2, + "mids": -26.5, + "upperMids": -37.6, + "highs": -48.4, + "brilliance": -82.0 + }, + { + "t": 7.47, + "subBass": -8.9, + "lowBass": -13.3, + "lowMids": -36.4, + "mids": -25.4, + "upperMids": -31.1, + "highs": -24.1, + "brilliance": -17.1 + }, + { + "t": 7.56, + "subBass": -12.9, + "lowBass": -9.6, + "lowMids": -35.9, + "mids": -22.9, + "upperMids": -29.9, + "highs": -24.4, + "brilliance": -16.1 + }, + { + "t": 7.65, + "subBass": -17.8, + "lowBass": -9.0, + "lowMids": -21.5, + "mids": -25.1, + "upperMids": -32.0, + "highs": -54.7, + "brilliance": -58.1 + }, + { + "t": 7.74, + "subBass": -10.4, + "lowBass": -5.3, + "lowMids": -27.9, + "mids": -29.5, + "upperMids": -37.7, + "highs": -50.5, + "brilliance": -54.2 + }, + { + "t": 7.84, + "subBass": -5.7, + "lowBass": -13.3, + "lowMids": -41.9, + "mids": -28.0, + "upperMids": -39.0, + "highs": -49.0, + "brilliance": -81.6 + }, + { + "t": 7.93, + "subBass": -8.8, + "lowBass": -13.7, + "lowMids": -49.3, + "mids": -26.1, + "upperMids": -37.5, + "highs": -45.8, + "brilliance": -49.0 + }, + { + "t": 8.02, + "subBass": -11.1, + "lowBass": -10.1, + "lowMids": -41.4, + "mids": -22.0, + "upperMids": -28.0, + "highs": -21.0, + "brilliance": -13.3 + }, + { + "t": 8.12, + "subBass": -14.1, + "lowBass": -9.1, + "lowMids": -41.8, + "mids": -20.8, + "upperMids": -29.7, + "highs": -40.9, + "brilliance": -58.8 + }, + { + "t": 8.21, + "subBass": -14.4, + "lowBass": -6.1, + "lowMids": -32.2, + "mids": -25.0, + "upperMids": -33.6, + "highs": -44.5, + "brilliance": -54.3 + }, + { + "t": 8.3, + "subBass": -5.3, + "lowBass": -10.3, + "lowMids": -40.3, + "mids": -30.7, + "upperMids": -41.4, + "highs": -54.0, + "brilliance": -83.9 + }, + { + "t": 8.39, + "subBass": -8.1, + "lowBass": -13.9, + "lowMids": -49.5, + "mids": -25.0, + "upperMids": -36.4, + "highs": -45.1, + "brilliance": -86.7 + }, + { + "t": 8.49, + "subBass": -11.6, + "lowBass": -10.7, + "lowMids": -42.4, + "mids": -23.0, + "upperMids": -27.1, + "highs": -20.9, + "brilliance": -13.3 + }, + { + "t": 8.58, + "subBass": -14.7, + "lowBass": -9.1, + "lowMids": -43.1, + "mids": -21.6, + "upperMids": -30.7, + "highs": -40.5, + "brilliance": -53.6 + }, + { + "t": 8.67, + "subBass": -19.7, + "lowBass": -7.8, + "lowMids": -33.5, + "mids": -23.0, + "upperMids": -32.0, + "highs": -40.8, + "brilliance": -49.8 + }, + { + "t": 8.77, + "subBass": -5.7, + "lowBass": -7.4, + "lowMids": -38.2, + "mids": -29.9, + "upperMids": -40.7, + "highs": -53.6, + "brilliance": -87.9 + }, + { + "t": 8.86, + "subBass": -7.4, + "lowBass": -14.2, + "lowMids": -26.6, + "mids": -30.3, + "upperMids": -37.4, + "highs": -65.1, + "brilliance": -82.5 + }, + { + "t": 8.95, + "subBass": -10.4, + "lowBass": -11.6, + "lowMids": -32.9, + "mids": -24.2, + "upperMids": -27.8, + "highs": -21.6, + "brilliance": -13.8 + }, + { + "t": 9.04, + "subBass": -14.0, + "lowBass": -9.2, + "lowMids": -42.7, + "mids": -22.3, + "upperMids": -31.9, + "highs": -33.3, + "brilliance": -26.2 + }, + { + "t": 9.14, + "subBass": -22.5, + "lowBass": -8.9, + "lowMids": -41.8, + "mids": -21.0, + "upperMids": -32.2, + "highs": -42.6, + "brilliance": -58.7 + }, + { + "t": 9.23, + "subBass": -6.8, + "lowBass": -5.5, + "lowMids": -33.1, + "mids": -28.6, + "upperMids": -37.5, + "highs": -45.3, + "brilliance": -51.8 + }, + { + "t": 9.32, + "subBass": -6.9, + "lowBass": -14.5, + "lowMids": -45.3, + "mids": -26.0, + "upperMids": -37.1, + "highs": -47.4, + "brilliance": -81.5 + }, + { + "t": 9.42, + "subBass": -9.7, + "lowBass": -12.5, + "lowMids": -36.9, + "mids": -24.4, + "upperMids": -29.8, + "highs": -23.2, + "brilliance": -15.1 + }, + { + "t": 9.51, + "subBass": -12.3, + "lowBass": -9.4, + "lowMids": -35.1, + "mids": -23.9, + "upperMids": -32.4, + "highs": -27.3, + "brilliance": -19.8 + }, + { + "t": 9.6, + "subBass": -15.8, + "lowBass": -9.0, + "lowMids": -21.0, + "mids": -24.8, + "upperMids": -31.8, + "highs": -54.7, + "brilliance": -57.1 + }, + { + "t": 9.69, + "subBass": -8.0, + "lowBass": -5.2, + "lowMids": -29.4, + "mids": -29.3, + "upperMids": -39.0, + "highs": -48.5, + "brilliance": -52.5 + }, + { + "t": 9.79, + "subBass": -6.2, + "lowBass": -14.4, + "lowMids": -47.6, + "mids": -27.0, + "upperMids": -38.2, + "highs": -47.3, + "brilliance": -94.0 + }, + { + "t": 9.88, + "subBass": -9.3, + "lowBass": -13.3, + "lowMids": -43.0, + "mids": -26.1, + "upperMids": -32.5, + "highs": -26.5, + "brilliance": -19.5 + }, + { + "t": 9.97, + "subBass": -12.8, + "lowBass": -9.6, + "lowMids": -45.1, + "mids": -23.0, + "upperMids": -28.1, + "highs": -23.3, + "brilliance": -15.2 + }, + { + "t": 10.07, + "subBass": -17.4, + "lowBass": -8.9, + "lowMids": -41.1, + "mids": -20.6, + "upperMids": -29.2, + "highs": -40.4, + "brilliance": -56.9 + }, + { + "t": 10.16, + "subBass": -11.1, + "lowBass": -5.9, + "lowMids": -31.6, + "mids": -26.5, + "upperMids": -35.4, + "highs": -46.2, + "brilliance": -53.5 + }, + { + "t": 10.25, + "subBass": -5.7, + "lowBass": -13.5, + "lowMids": -34.0, + "mids": -28.5, + "upperMids": -39.7, + "highs": -50.0, + "brilliance": -81.4 + }, + { + "t": 10.34, + "subBass": -8.5, + "lowBass": -13.7, + "lowMids": -50.2, + "mids": -25.8, + "upperMids": -37.3, + "highs": -45.9, + "brilliance": -97.3 + }, + { + "t": 10.44, + "subBass": -11.3, + "lowBass": -10.3, + "lowMids": -41.4, + "mids": -22.7, + "upperMids": -27.0, + "highs": -21.3, + "brilliance": -13.6 + }, + { + "t": 10.53, + "subBass": -15.7, + "lowBass": -9.1, + "lowMids": -23.2, + "mids": -21.3, + "upperMids": -32.6, + "highs": -46.0, + "brilliance": -57.8 + }, + { + "t": 10.62, + "subBass": -21.8, + "lowBass": -6.0, + "lowMids": -25.9, + "mids": -24.4, + "upperMids": -36.1, + "highs": -47.0, + "brilliance": -51.8 + }, + { + "t": 10.72, + "subBass": -5.2, + "lowBass": -9.4, + "lowMids": -38.9, + "mids": -30.7, + "upperMids": -41.4, + "highs": -54.3, + "brilliance": -89.2 + }, + { + "t": 10.81, + "subBass": -8.0, + "lowBass": -14.0, + "lowMids": -48.7, + "mids": -25.2, + "upperMids": -33.9, + "highs": -45.4, + "brilliance": -82.0 + }, + { + "t": 10.9, + "subBass": -10.5, + "lowBass": -11.0, + "lowMids": -41.2, + "mids": -22.9, + "upperMids": -28.0, + "highs": -21.0, + "brilliance": -13.4 + }, + { + "t": 10.99, + "subBass": -13.0, + "lowBass": -9.1, + "lowMids": -40.4, + "mids": -21.5, + "upperMids": -32.7, + "highs": -42.0, + "brilliance": -42.0 + }, + { + "t": 11.09, + "subBass": -15.7, + "lowBass": -8.5, + "lowMids": -35.5, + "mids": -22.0, + "upperMids": -33.2, + "highs": -42.9, + "brilliance": -52.9 + }, + { + "t": 11.18, + "subBass": -6.0, + "lowBass": -6.4, + "lowMids": -35.5, + "mids": -29.9, + "upperMids": -41.4, + "highs": -50.0, + "brilliance": -69.4 + }, + { + "t": 11.27, + "subBass": -7.4, + "lowBass": -14.3, + "lowMids": -46.8, + "mids": -25.4, + "upperMids": -36.7, + "highs": -47.0, + "brilliance": -81.8 + }, + { + "t": 11.37, + "subBass": -10.7, + "lowBass": -11.7, + "lowMids": -43.6, + "mids": -24.0, + "upperMids": -28.4, + "highs": -21.3, + "brilliance": -13.7 + }, + { + "t": 11.46, + "subBass": -13.8, + "lowBass": -9.2, + "lowMids": -43.1, + "mids": -23.0, + "upperMids": -31.1, + "highs": -31.5, + "brilliance": -24.2 + }, + { + "t": 11.55, + "subBass": -22.0, + "lowBass": -8.8, + "lowMids": -44.1, + "mids": -21.1, + "upperMids": -29.8, + "highs": -41.2, + "brilliance": -60.6 + }, + { + "t": 11.64, + "subBass": -6.7, + "lowBass": -6.2, + "lowMids": -29.7, + "mids": -31.6, + "upperMids": -38.9, + "highs": -47.4, + "brilliance": -50.2 + }, + { + "t": 11.74, + "subBass": -6.6, + "lowBass": -14.5, + "lowMids": -28.1, + "mids": -27.0, + "upperMids": -38.5, + "highs": -53.5, + "brilliance": -85.3 + }, + { + "t": 11.83, + "subBass": -9.6, + "lowBass": -12.6, + "lowMids": -30.7, + "mids": -24.8, + "upperMids": -30.5, + "highs": -22.9, + "brilliance": -15.2 + }, + { + "t": 11.92, + "subBass": -13.2, + "lowBass": -9.4, + "lowMids": -45.1, + "mids": -23.6, + "upperMids": -31.5, + "highs": -26.3, + "brilliance": -18.5 + }, + { + "t": 12.02, + "subBass": -18.7, + "lowBass": -9.0, + "lowMids": -41.7, + "mids": -20.2, + "upperMids": -28.9, + "highs": -40.1, + "brilliance": -59.9 + }, + { + "t": 12.11, + "subBass": -9.0, + "lowBass": -5.2, + "lowMids": -29.2, + "mids": -28.9, + "upperMids": -36.9, + "highs": -46.2, + "brilliance": -49.8 + }, + { + "t": 12.2, + "subBass": -6.1, + "lowBass": -14.2, + "lowMids": -34.6, + "mids": -28.1, + "upperMids": -38.8, + "highs": -48.6, + "brilliance": -81.9 + }, + { + "t": 12.29, + "subBass": -8.9, + "lowBass": -13.6, + "lowMids": -44.2, + "mids": -26.5, + "upperMids": -34.8, + "highs": -30.5, + "brilliance": -23.7 + }, + { + "t": 12.39, + "subBass": -11.7, + "lowBass": -9.7, + "lowMids": -44.6, + "mids": -22.7, + "upperMids": -27.8, + "highs": -22.3, + "brilliance": -14.3 + }, + { + "t": 12.48, + "subBass": -14.6, + "lowBass": -9.1, + "lowMids": -40.8, + "mids": -20.6, + "upperMids": -29.2, + "highs": -40.4, + "brilliance": -57.2 + }, + { + "t": 12.57, + "subBass": -11.6, + "lowBass": -5.2, + "lowMids": -32.4, + "mids": -25.5, + "upperMids": -34.5, + "highs": -44.9, + "brilliance": -55.8 + }, + { + "t": 12.67, + "subBass": -5.5, + "lowBass": -11.8, + "lowMids": -34.7, + "mids": -29.8, + "upperMids": -39.6, + "highs": -50.4, + "brilliance": -81.6 + }, + { + "t": 12.76, + "subBass": -8.5, + "lowBass": -13.8, + "lowMids": -27.3, + "mids": -26.0, + "upperMids": -38.0, + "highs": -52.5, + "brilliance": -112.7 + }, + { + "t": 12.85, + "subBass": -12.0, + "lowBass": -10.4, + "lowMids": -40.2, + "mids": -22.5, + "upperMids": -28.4, + "highs": -21.7, + "brilliance": -13.9 + }, + { + "t": 12.95, + "subBass": -15.4, + "lowBass": -9.0, + "lowMids": -41.1, + "mids": -21.3, + "upperMids": -30.1, + "highs": -41.4, + "brilliance": -58.2 + }, + { + "t": 13.04, + "subBass": -23.2, + "lowBass": -6.9, + "lowMids": -35.8, + "mids": -23.8, + "upperMids": -32.5, + "highs": -43.5, + "brilliance": -54.3 + }, + { + "t": 13.13, + "subBass": -5.4, + "lowBass": -8.9, + "lowMids": -38.7, + "mids": -30.5, + "upperMids": -41.2, + "highs": -54.2, + "brilliance": -102.0 + }, + { + "t": 13.22, + "subBass": -7.7, + "lowBass": -14.1, + "lowMids": -26.8, + "mids": -25.5, + "upperMids": -37.2, + "highs": -51.8, + "brilliance": -82.0 + }, + { + "t": 13.32, + "subBass": -10.5, + "lowBass": -11.2, + "lowMids": -35.6, + "mids": -23.0, + "upperMids": -28.3, + "highs": -21.4, + "brilliance": -13.7 + }, + { + "t": 13.41, + "subBass": -14.3, + "lowBass": -9.2, + "lowMids": -24.5, + "mids": -24.6, + "upperMids": -33.5, + "highs": -42.4, + "brilliance": -35.5 + }, + { + "t": 13.5, + "subBass": -25.1, + "lowBass": -8.7, + "lowMids": -22.9, + "mids": -26.8, + "upperMids": -33.6, + "highs": -50.2, + "brilliance": -53.3 + }, + { + "t": 13.6, + "subBass": -6.1, + "lowBass": -5.9, + "lowMids": -29.5, + "mids": -30.1, + "upperMids": -41.0, + "highs": -52.2, + "brilliance": -57.8 + }, + { + "t": 13.69, + "subBass": -7.2, + "lowBass": -14.3, + "lowMids": -41.3, + "mids": -25.8, + "upperMids": -34.6, + "highs": -46.1, + "brilliance": -80.7 + }, + { + "t": 13.78, + "subBass": -9.9, + "lowBass": -12.1, + "lowMids": -41.4, + "mids": -23.9, + "upperMids": -28.5, + "highs": -21.5, + "brilliance": -13.9 + }, + { + "t": 13.87, + "subBass": -12.4, + "lowBass": -9.3, + "lowMids": -44.3, + "mids": -23.3, + "upperMids": -32.7, + "highs": -30.2, + "brilliance": -22.8 + }, + { + "t": 13.97, + "subBass": -16.5, + "lowBass": -9.0, + "lowMids": -42.5, + "mids": -20.8, + "upperMids": -30.0, + "highs": -39.4, + "brilliance": -58.2 + }, + { + "t": 14.06, + "subBass": -7.2, + "lowBass": -5.7, + "lowMids": -33.4, + "mids": -27.9, + "upperMids": -37.2, + "highs": -46.7, + "brilliance": -53.4 + }, + { + "t": 14.15, + "subBass": -6.6, + "lowBass": -14.5, + "lowMids": -49.4, + "mids": -26.7, + "upperMids": -35.9, + "highs": -45.5, + "brilliance": -77.2 + }, + { + "t": 14.25, + "subBass": -9.8, + "lowBass": -12.8, + "lowMids": -35.6, + "mids": -25.0, + "upperMids": -29.9, + "highs": -22.8, + "brilliance": -15.4 + }, + { + "t": 14.34, + "subBass": -13.1, + "lowBass": -9.5, + "lowMids": -36.3, + "mids": -23.3, + "upperMids": -30.8, + "highs": -25.5, + "brilliance": -17.4 + }, + { + "t": 14.43, + "subBass": -18.5, + "lowBass": -8.9, + "lowMids": -39.6, + "mids": -19.9, + "upperMids": -31.0, + "highs": -41.5, + "brilliance": -59.7 + }, + { + "t": 14.52, + "subBass": -9.1, + "lowBass": -5.8, + "lowMids": -34.1, + "mids": -25.7, + "upperMids": -37.1, + "highs": -45.3, + "brilliance": -51.2 + }, + { + "t": 14.62, + "subBass": -5.8, + "lowBass": -13.4, + "lowMids": -31.0, + "mids": -28.1, + "upperMids": -39.7, + "highs": -51.6, + "brilliance": -82.4 + }, + { + "t": 14.71, + "subBass": -8.7, + "lowBass": -13.7, + "lowMids": -28.4, + "mids": -26.9, + "upperMids": -37.8, + "highs": -36.7, + "brilliance": -29.9 + }, + { + "t": 14.8, + "subBass": -12.4, + "lowBass": -9.8, + "lowMids": -43.4, + "mids": -22.7, + "upperMids": -27.7, + "highs": -21.3, + "brilliance": -13.6 + }, + { + "t": 14.9, + "subBass": -16.5, + "lowBass": -9.0, + "lowMids": -21.6, + "mids": -24.8, + "upperMids": -32.1, + "highs": -51.3, + "brilliance": -60.1 + }, + { + "t": 14.99, + "subBass": -14.7, + "lowBass": -5.5, + "lowMids": -25.6, + "mids": -27.5, + "upperMids": -35.4, + "highs": -47.8, + "brilliance": -51.7 + }, + { + "t": 15.08, + "subBass": -5.4, + "lowBass": -11.0, + "lowMids": -41.4, + "mids": -30.2, + "upperMids": -39.5, + "highs": -50.3, + "brilliance": -74.8 + }, + { + "t": 15.17, + "subBass": -8.3, + "lowBass": -13.9, + "lowMids": -49.5, + "mids": -25.3, + "upperMids": -36.8, + "highs": -45.4, + "brilliance": -94.4 + }, + { + "t": 15.27, + "subBass": -10.9, + "lowBass": -10.6, + "lowMids": -24.6, + "mids": -23.0, + "upperMids": -28.6, + "highs": -21.7, + "brilliance": -13.8 + }, + { + "t": 15.36, + "subBass": -13.4, + "lowBass": -9.2, + "lowMids": -30.9, + "mids": -21.3, + "upperMids": -30.3, + "highs": -41.8, + "brilliance": -57.7 + }, + { + "t": 15.45, + "subBass": -18.5, + "lowBass": -9.8, + "lowMids": -36.9, + "mids": -23.9, + "upperMids": -32.5, + "highs": -43.6, + "brilliance": -55.6 + } + ], + "spectralDetail": { + "spectralCentroid": 1235.6, + "spectralRolloff": 1705.8, + "spectralBandwidth": 2792.7, + "spectralFlatness": 0.106731, + "mfcc": [ + -734.0844, + 154.683, + 3.6758, + 80.2596, + 12.253, + 37.6176, + 21.0928, + 26.1738, + 30.0256, + 25.6032, + 19.3863, + 14.688, + -2.4176 + ], + "chroma": [ + 0.3453, + 0.0264, + 0.3553, + 0.3736, + 0.0509, + 0.188, + 0.0297, + 0.1433, + 0.2211, + 0.2028, + 0.2543, + 0.0401 + ], + "barkBands": [ + -23.3468, + -9.5801, + -10.7791, + -18.292, + -30.4047, + -41.694, + -30.7192, + -30.0653, + -29.9695, + -32.4529, + -37.3836, + -38.5052, + -35.5402, + -37.582, + -39.4433, + -39.4465, + -39.3554, + -39.8589, + -40.2175, + -41.1375, + -38.4349, + -35.6342, + -35.847, + -31.9475 + ], + "erbBands": [ + 9.3999, + 14.1721, + 20.1938, + 17.8542, + 8.9863, + 2.0074, + -1.7197, + 1.2775, + 10.7046, + 12.8134, + 12.877, + 15.1657, + 12.6889, + 8.0858, + 8.4848, + 8.7324, + 11.671, + 10.5853, + 7.8514, + 8.4066, + 8.0561, + 6.7265, + 7.6437, + 6.5803, + 5.9683, + 6.4091, + 7.209, + 7.8929, + 9.1922, + 9.7835, + 9.1445, + 11.0765, + 10.1471, + 10.4681, + 9.7646, + 9.6697, + 7.7449, + 3.8282, + -2.1178, + -11.6781 + ], + "spectralContrast": [ + -0.2223, + -0.6097, + -0.6125, + -0.6482, + -0.6843, + -0.683 + ], + "spectralValley": [ + -6.1042, + -7.4787, + -8.5164, + -8.881, + -9.5051, + -11.7702 + ] + }, + "stemAnalysis": null, + "transientDensityDetail": { + "subBass": { + "onsetRatePerSecond": 7.69, + "meanOnsetStrength": 0.309, + "peakOnsetStrength": 0.626, + "eventCount": 119 + }, + "lowBass": { + "onsetRatePerSecond": 6.07, + "meanOnsetStrength": 0.5, + "peakOnsetStrength": 1.308, + "eventCount": 94 + }, + "lowMids": { + "onsetRatePerSecond": 9.3, + "meanOnsetStrength": 0.93, + "peakOnsetStrength": 2.848, + "eventCount": 144 + }, + "mids": { + "onsetRatePerSecond": 9.3, + "meanOnsetStrength": 4.528, + "peakOnsetStrength": 8.731, + "eventCount": 144 + }, + "upperMids": { + "onsetRatePerSecond": 9.36, + "meanOnsetStrength": 3.904, + "peakOnsetStrength": 9.581, + "eventCount": 145 + }, + "highs": { + "onsetRatePerSecond": 9.56, + "meanOnsetStrength": 4.152, + "peakOnsetStrength": 13.851, + "eventCount": 148 + }, + "brilliance": { + "onsetRatePerSecond": 9.56, + "meanOnsetStrength": 5.297, + "peakOnsetStrength": 15.536, + "eventCount": 148 + } + }, + "saturationDetail": { + "clippedSampleCount": 0, + "clippedSamplePercent": 0.0, + "nearClippedSampleCount": 0, + "nearClippedSamplePercent": 0.0, + "peakRatio95to50": 2.224, + "rmsToPeakRatioDb": 10.77, + "saturationLikely": false + }, + "snareDetail": { + "hitCount": 60, + "hitsPerSecond": 3.88, + "meanAttackSharpness": 0.0018, + "meanBodyEnergyRatio": 0.989, + "meanSnapEnergyRatio": 0.011, + "meanCentroidHz": 349.5, + "meanDecayFrames": 55.4, + "meanDecaySeconds": 0.321, + "bandHz": [ + 120.0, + 2000.0 + ] + }, + "hihatDetail": { + "hitCount": 32, + "hitsPerSecond": 2.07, + "meanAttackSharpness": 0.0031, + "meanBodyEnergyRatio": 0.183, + "meanSnapEnergyRatio": 0.817, + "meanCentroidHz": 7896.4, + "meanDecayFrames": 8.2, + "meanDecaySeconds": 0.048, + "bandHz": [ + 2000.0, + 12000.0 + ] + }, + "rhythmDetail": { + "onsetRate": 2.07, + "beatGrid": [ + 0.372, + 0.766, + 1.207, + 1.683, + 2.171, + 2.659, + 3.135, + 3.622, + 4.11, + 4.586, + 5.074, + 5.561, + 6.049, + 6.525, + 7.012, + 7.5, + 7.976, + 8.464, + 8.951, + 9.427, + 9.915, + 10.403, + 10.879, + 11.366, + 11.854, + 12.33, + 12.817, + 13.305, + 13.781, + 14.269, + 14.756, + 15.232 + ], + "downbeats": [ + 0.766, + 2.659, + 4.586, + 6.525, + 8.464, + 10.403, + 12.33, + 14.269 + ], + "beatPositions": [ + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3 + ], + "downbeatSource": "kick_accent", + "downbeatConfidence": 0.0067, + "grooveAmount": 0.0375, + "tempoStability": 0.9625, + "phraseGrid": { + "phrases4Bar": [ + 0.766, + 8.464 + ], + "phrases8Bar": [ + 0.766 + ], + "phrases16Bar": [ + 0.766 + ], + "totalBars": 8, + "totalPhrases8Bar": 1 + }, + "tempoCurve": [ + { + "t": 0.57, + "bpm": 136.0 + }, + { + "t": 0.99, + "bpm": 131.0 + }, + { + "t": 1.45, + "bpm": 126.0 + }, + { + "t": 1.93, + "bpm": 126.0 + }, + { + "t": 2.41, + "bpm": 123.0 + }, + { + "t": 2.9, + "bpm": 123.0 + }, + { + "t": 3.38, + "bpm": 123.0 + }, + { + "t": 3.87, + "bpm": 123.0 + }, + { + "t": 4.35, + "bpm": 123.0 + }, + { + "t": 4.83, + "bpm": 123.0 + }, + { + "t": 5.32, + "bpm": 123.0 + }, + { + "t": 5.8, + "bpm": 123.0 + }, + { + "t": 6.29, + "bpm": 123.0 + }, + { + "t": 6.77, + "bpm": 123.0 + }, + { + "t": 7.26, + "bpm": 123.0 + }, + { + "t": 7.74, + "bpm": 123.0 + }, + { + "t": 8.22, + "bpm": 123.0 + }, + { + "t": 8.71, + "bpm": 123.0 + }, + { + "t": 9.19, + "bpm": 123.0 + }, + { + "t": 9.67, + "bpm": 123.0 + }, + { + "t": 10.16, + "bpm": 123.0 + }, + { + "t": 10.64, + "bpm": 123.0 + }, + { + "t": 11.12, + "bpm": 123.0 + }, + { + "t": 11.61, + "bpm": 123.0 + }, + { + "t": 12.09, + "bpm": 123.0 + }, + { + "t": 12.57, + "bpm": 123.0 + }, + { + "t": 13.06, + "bpm": 123.0 + }, + { + "t": 13.54, + "bpm": 123.0 + }, + { + "t": 14.02, + "bpm": 123.0 + }, + { + "t": 14.51, + "bpm": 124.5 + }, + { + "t": 14.99, + "bpm": 123.0 + } + ] + }, + "melodyDetail": { + "noteCount": 29, + "notes": [ + { + "midi": 47, + "onset": 0.244, + "duration": 0.264 + }, + { + "midi": 48, + "onset": 1.167, + "duration": 0.302 + }, + { + "midi": 47, + "onset": 1.695, + "duration": 0.264 + }, + { + "midi": 45, + "onset": 2.197, + "duration": 0.209 + }, + { + "midi": 48, + "onset": 2.618, + "duration": 0.273 + }, + { + "midi": 47, + "onset": 3.146, + "duration": 0.264 + }, + { + "midi": 45, + "onset": 3.648, + "duration": 0.209 + }, + { + "midi": 47, + "onset": 4.029, + "duration": 0.099 + }, + { + "midi": 48, + "onset": 4.133, + "duration": 0.229 + }, + { + "midi": 47, + "onset": 4.627, + "duration": 0.235 + }, + { + "midi": 45, + "onset": 5.1, + "duration": 0.209 + }, + { + "midi": 48, + "onset": 5.521, + "duration": 0.293 + }, + { + "midi": 47, + "onset": 6.049, + "duration": 0.264 + }, + { + "midi": 47, + "onset": 6.896, + "duration": 0.11 + }, + { + "midi": 48, + "onset": 7.012, + "duration": 0.255 + }, + { + "midi": 47, + "onset": 7.497, + "duration": 0.27 + }, + { + "midi": 48, + "onset": 8.42, + "duration": 0.299 + }, + { + "midi": 47, + "onset": 8.951, + "duration": 0.267 + }, + { + "midi": 45, + "onset": 9.477, + "duration": 0.186 + }, + { + "midi": 48, + "onset": 9.877, + "duration": 0.293 + }, + { + "midi": 47, + "onset": 10.403, + "duration": 0.267 + }, + { + "midi": 48, + "onset": 11.331, + "duration": 0.29 + }, + { + "midi": 47, + "onset": 11.883, + "duration": 0.238 + }, + { + "midi": 47, + "onset": 12.701, + "duration": 0.11 + }, + { + "midi": 48, + "onset": 12.817, + "duration": 0.258 + }, + { + "midi": 47, + "onset": 13.334, + "duration": 0.238 + }, + { + "midi": 45, + "onset": 13.822, + "duration": 0.197 + }, + { + "midi": 48, + "onset": 14.237, + "duration": 0.287 + }, + { + "midi": 47, + "onset": 14.759, + "duration": 0.264 + } + ], + "dominantNotes": [ + 47, + 48, + 45 + ], + "pitchRange": { + "min": 45, + "max": 48 + }, + "pitchConfidence": 0.0337, + "midiFile": "/Users/christiansmith/code/projects/asa/.claude/worktrees/goal-doc/apps/backend/tests/fixtures/recommendation_tracks/house_sidechain_pluck_124/audio_melody.mid", + "sourceSeparated": false, + "vibratoPresent": false, + "vibratoExtent": 0.0, + "vibratoRate": 0.0, + "vibratoConfidence": 0.0 + }, + "transcriptionDetail": null, + "pitchDetail": null, + "grooveDetail": { + "kickSwing": 0.1561, + "hihatSwing": 0.3246, + "kickAccent": [ + 0.1281, + 0.1742, + 0.173, + 0.1742, + 0.1741, + 0.1642, + 0.1744, + 0.174, + 0.1642, + 0.1745, + 0.1738, + 0.1641, + 0.1745, + 0.1758, + 0.1738, + 0.174 + ], + "hihatAccent": [ + 0.0003, + 0.0835, + 0.0642, + 0.0711, + 0.0716, + 0.0805, + 0.0805, + 0.0809, + 0.0805, + 0.0812, + 0.0827, + 0.0823, + 0.082, + 0.0469, + 0.0644, + 0.0638 + ], + "perDrumSwing": { + "kick": 0.1561, + "snare": 0.2457, + "hihat": 0.3246 + } + }, + "beatsLoudness": { + "kickDominantRatio": 0.6817, + "midDominantRatio": 0.0001, + "highDominantRatio": 0.275, + "patternBeatsPerBar": 4, + "lowBandAccentPattern": [ + 0.9603, + 1.0, + 0.9886, + 0.9933 + ], + "midBandAccentPattern": [ + 1.0, + 0.4888, + 0.6706, + 0.6438 + ], + "highBandAccentPattern": [ + 0.9165, + 0.9366, + 1.0, + 0.9994 + ], + "overallAccentPattern": [ + 0.957, + 0.9851, + 0.9962, + 1.0 + ], + "accentPattern": [ + 0.957, + 0.9851, + 0.9962, + 1.0 + ], + "meanBeatLoudness": 0.2514, + "beatLoudnessVariation": 0.0931, + "beatCount": 32 + }, + "rhythmTimeline": { + "beatsPerBar": 4, + "stepsPerBeat": 4, + "availableBars": 8, + "selectionMethod": "representative_dsp_window", + "windows": [ + { + "bars": 8, + "startBar": 1, + "endBar": 8, + "lowBandSteps": [ + 0.2219, + 0.7505, + 0.3911, + 0.2684, + 0.3415, + 0.2867, + 0.7053, + 0.3765, + 0.4037, + 0.3304, + 0.9253, + 0.4677, + 0.4238, + 0.3407, + 0.9955, + 0.489, + 0.4235, + 0.3402, + 0.9738, + 0.4758, + 0.4039, + 0.3311, + 0.9291, + 0.4685, + 0.4237, + 0.341, + 0.9978, + 0.4898, + 0.4235, + 0.3397, + 0.9764, + 0.4766, + 0.4039, + 0.3322, + 0.9336, + 0.4694, + 0.4236, + 0.3413, + 1.0, + 0.4908, + 0.4234, + 0.339, + 0.9789, + 0.4775, + 0.4239, + 0.3477, + 0.95, + 0.4686, + 0.4045, + 0.3242, + 0.9228, + 0.4651, + 0.4235, + 0.3385, + 0.9816, + 0.4784, + 0.424, + 0.3487, + 0.9536, + 0.4695, + 0.4044, + 0.3243, + 0.9246, + 0.4659, + 0.4235, + 0.3382, + 0.9841, + 0.4793, + 0.4242, + 0.3495, + 0.957, + 0.4703, + 0.4046, + 0.3248, + 0.9265, + 0.4666, + 0.4233, + 0.3375, + 0.9868, + 0.4803, + 0.4244, + 0.3504, + 0.9605, + 0.4711, + 0.4045, + 0.3251, + 0.9283, + 0.4672, + 0.4232, + 0.3374, + 0.9893, + 0.4812, + 0.4245, + 0.3513, + 0.9644, + 0.4719, + 0.4044, + 0.3259, + 0.93, + 0.4678, + 0.4231, + 0.3372, + 0.9917, + 0.4821, + 0.4247, + 0.3522, + 0.9681, + 0.4728, + 0.4043, + 0.3261, + 0.9318, + 0.4684, + 0.4231, + 0.3372, + 0.9942, + 0.4831, + 0.4248, + 0.3532, + 0.9724, + 0.4736, + 0.4042, + 0.3268, + 0.9336, + 0.4689, + 0.1088, + 0.1117, + 0.0978, + 0.0913 + ], + "midBandSteps": [ + 0.5616, + 0.1278, + 0.2561, + 0.266, + 0.2516, + 0.4274, + 0.0786, + 0.2245, + 0.5047, + 0.898, + 0.1277, + 0.2935, + 0.6413, + 0.9864, + 0.1306, + 0.3089, + 0.6096, + 0.9657, + 0.1198, + 0.2833, + 0.5218, + 0.9091, + 0.1214, + 0.3115, + 0.6221, + 0.9871, + 0.1393, + 0.3164, + 0.6117, + 0.9588, + 0.1203, + 0.3096, + 0.539, + 0.9007, + 0.1198, + 0.3159, + 0.6242, + 1.0, + 0.1396, + 0.2995, + 0.6137, + 0.9384, + 0.1261, + 0.2953, + 0.5814, + 0.8256, + 0.1151, + 0.2635, + 0.5305, + 0.8284, + 0.1227, + 0.2909, + 0.5626, + 0.9493, + 0.1233, + 0.3061, + 0.5566, + 0.8199, + 0.1212, + 0.2796, + 0.5082, + 0.8727, + 0.1228, + 0.2867, + 0.5962, + 0.9182, + 0.1283, + 0.2919, + 0.5422, + 0.8253, + 0.1215, + 0.2952, + 0.5005, + 0.8687, + 0.114, + 0.2926, + 0.5962, + 0.9858, + 0.1279, + 0.2927, + 0.544, + 0.8454, + 0.1231, + 0.2765, + 0.5026, + 0.8856, + 0.1229, + 0.2831, + 0.5813, + 0.9662, + 0.1266, + 0.2986, + 0.5293, + 0.8429, + 0.125, + 0.2918, + 0.5146, + 0.8166, + 0.1252, + 0.2893, + 0.5791, + 0.9078, + 0.123, + 0.3096, + 0.5627, + 0.85, + 0.1226, + 0.2927, + 0.5166, + 0.9131, + 0.1244, + 0.2849, + 0.5855, + 0.9287, + 0.1253, + 0.2837, + 0.5658, + 0.8842, + 0.1196, + 0.2936, + 0.4894, + 0.9219, + 0.1178, + 0.291, + 0.2459, + 0.0829, + 0.3563, + 0.1067 + ], + "highBandSteps": [ + 0.004, + 0.0002, + 0.0007, + 0.9658, + 0.0057, + 0.0028, + 0.0002, + 0.0009, + 0.6299, + 0.0042, + 0.0003, + 0.0023, + 0.973, + 0.0046, + 0.0006, + 0.0018, + 0.7772, + 0.0018, + 0.0007, + 0.0022, + 0.6369, + 0.0054, + 0.0008, + 0.0013, + 0.9862, + 0.0079, + 0.0002, + 0.0013, + 0.7891, + 0.0057, + 0.0007, + 0.0005, + 0.6462, + 0.0041, + 0.0007, + 0.0008, + 1.0, + 0.0029, + 0.0002, + 0.0024, + 0.8011, + 0.0027, + 0.0006, + 0.0017, + 0.6372, + 0.0059, + 0.0008, + 0.0018, + 0.5059, + 0.0066, + 0.0004, + 0.0017, + 0.8209, + 0.003, + 0.0008, + 0.0008, + 0.6506, + 0.0058, + 0.0004, + 0.0016, + 0.5147, + 0.0017, + 0.0004, + 0.0015, + 0.8281, + 0.0075, + 0.0004, + 0.0015, + 0.6619, + 0.0061, + 0.0004, + 0.0005, + 0.5292, + 0.0052, + 0.0007, + 0.0017, + 0.8388, + 0.002, + 0.0006, + 0.0015, + 0.6725, + 0.0072, + 0.0003, + 0.0014, + 0.5384, + 0.0025, + 0.0004, + 0.0022, + 0.8518, + 0.0059, + 0.0005, + 0.0017, + 0.6867, + 0.0067, + 0.0002, + 0.0008, + 0.5441, + 0.0068, + 0.0002, + 0.0015, + 0.8655, + 0.0079, + 0.0007, + 0.0008, + 0.6926, + 0.0071, + 0.0004, + 0.0008, + 0.5535, + 0.0017, + 0.0003, + 0.0023, + 0.8771, + 0.0067, + 0.0008, + 0.002, + 0.7042, + 0.0056, + 0.0005, + 0.0008, + 0.5656, + 0.0017, + 0.0008, + 0.0015, + 0.8136, + 0.0003, + 0.003, + 0.0009 + ], + "overallSteps": [ + 0.2368, + 0.7511, + 0.3967, + 0.3508, + 0.3476, + 0.2976, + 0.7047, + 0.3813, + 0.4657, + 0.3542, + 0.9253, + 0.4742, + 0.5165, + 0.3669, + 0.9953, + 0.4957, + 0.5, + 0.3656, + 0.9734, + 0.4819, + 0.4669, + 0.3553, + 0.9289, + 0.4754, + 0.5169, + 0.3675, + 0.9978, + 0.4967, + 0.5009, + 0.3653, + 0.976, + 0.4833, + 0.4681, + 0.3561, + 0.9333, + 0.4763, + 0.518, + 0.3678, + 1.0, + 0.4973, + 0.5018, + 0.3638, + 0.9786, + 0.4839, + 0.4885, + 0.3696, + 0.9496, + 0.4742, + 0.4574, + 0.3463, + 0.9226, + 0.4715, + 0.5021, + 0.3636, + 0.9813, + 0.4851, + 0.489, + 0.3704, + 0.9533, + 0.4755, + 0.4574, + 0.3472, + 0.9245, + 0.4721, + 0.5036, + 0.3628, + 0.9838, + 0.4857, + 0.4897, + 0.3713, + 0.9567, + 0.4766, + 0.4585, + 0.3479, + 0.9261, + 0.473, + 0.5042, + 0.3636, + 0.9865, + 0.4866, + 0.4908, + 0.3729, + 0.9602, + 0.477, + 0.4592, + 0.3484, + 0.9281, + 0.4734, + 0.5048, + 0.3632, + 0.989, + 0.4877, + 0.4916, + 0.3737, + 0.9642, + 0.4782, + 0.4599, + 0.3477, + 0.9299, + 0.4741, + 0.5056, + 0.3616, + 0.9913, + 0.4888, + 0.4932, + 0.3748, + 0.9678, + 0.4791, + 0.4606, + 0.3502, + 0.9317, + 0.4746, + 0.5067, + 0.362, + 0.9938, + 0.4892, + 0.4943, + 0.3766, + 0.9719, + 0.48, + 0.4607, + 0.3511, + 0.9333, + 0.4752, + 0.1792, + 0.1135, + 0.1075, + 0.094 + ] + } + ] + }, + "sidechainDetail": { + "pumpingStrength": 0.1803, + "pumpingRegularity": 0.0, + "pumpingRate": null, + "pumpingConfidence": 0.1225, + "envelopeShape": [ + 0.753, + 0.594, + 1.0, + 0.687, + 0.749, + 0.59, + 0.998, + 0.693, + 0.748, + 0.597, + 0.996, + 0.692, + 0.753, + 0.596, + 1.0, + 0.689 + ], + "envelopeShape32": [ + 0.753, + 0.589, + 0.594, + 0.553, + 1.0, + 0.824, + 0.687, + 0.607, + 0.749, + 0.601, + 0.59, + 0.552, + 0.998, + 0.832, + 0.693, + 0.598, + 0.748, + 0.601, + 0.597, + 0.551, + 0.996, + 0.83, + 0.692, + 0.608, + 0.753, + 0.592, + 0.596, + 0.55, + 1.0, + 0.828, + 0.689, + 0.608 + ] + }, + "acidDetail": { + "isAcid": true, + "confidence": 0.61, + "resonanceLevel": 1.0, + "centroidOscillationHz": 38, + "bassRhythmDensity": 1.2 + }, + "reverbDetail": { + "rt60": null, + "isWet": false, + "tailEnergyRatio": null, + "measured": false, + "perBandRt60": null, + "preDelayMs": null + }, + "vocalDetail": { + "hasVocals": false, + "confidence": 0.35, + "vocalEnergyRatio": 0.09, + "formantStrength": 0.23, + "mfccLikelihood": 0.89, + "stemEnergyRatio": null, + "stemOtherCorrelation": null + }, + "supersawDetail": { + "isSupersaw": true, + "confidence": 0.87, + "voiceCount": 8, + "avgDetuneCents": 27.4, + "spectralComplexity": 7.6 + }, + "bassDetail": { + "averageDecayMs": 1000, + "type": "sustained", + "transientRatio": 0.2, + "fundamentalHz": 103, + "transientCount": 0, + "swingPercent": 0, + "grooveType": "straight" + }, + "kickDetail": { + "isDistorted": true, + "thd": 0.43, + "harmonicRatio": 0.88, + "fundamentalHz": 80, + "kickCount": 81 + }, + "genreDetail": { + "genre": "dub-techno", + "confidence": 1.0, + "secondaryGenre": "ambient", + "genreFamily": "techno", + "topScores": [ + { + "genre": "dub-techno", + "score": 0.9697 + }, + { + "genre": "ambient", + "score": 0.7914 + }, + { + "genre": "ambient-techno", + "score": 0.79 + }, + { + "genre": "dubstep", + "score": 0.7806 + }, + { + "genre": "pop", + "score": 0.7787 + } + ] + }, + "effectsDetail": { + "gatingDetected": false, + "gatingRate": null, + "gatingRegularity": 0.0, + "gatingEventCount": 1 + }, + "synthesisCharacter": { + "inharmonicity": 0.1088, + "oddToEvenRatio": 2.2693 + }, + "danceability": { + "danceability": 5.046, + "dfa": 0.1982 + }, + "structure": { + "segments": [ + { + "start": 0.0, + "end": 6.896, + "index": 0 + }, + { + "start": 6.896, + "end": 15.484, + "index": 1 + } + ], + "segmentCount": 2 + }, + "arrangementDetail": { + "noveltyCurve": [ + 0.0, + 0.0, + 0.0002, + 0.0004, + 0.1598, + 0.6099, + 0.2969, + 0.0289, + 0.0158, + 0.0035, + 0.0012, + 0.0004, + 0.0936, + 0.2775, + 0.1158, + 0.0283, + 0.0153, + 0.0023, + 0.0008, + 0.0004, + 0.1007, + 0.2609, + 0.0838, + 0.0139, + 0.0068, + 0.0004, + 0.0005, + 0.001, + 0.3595, + 0.7945, + 0.2197, + 0.0058, + 0.0028, + 0.0007, + 0.0008, + 0.0016, + 0.4088, + 0.8545, + 0.2239, + 0.0046, + 0.0026, + 0.0032, + 0.0015, + 0.0013, + 0.2293, + 0.938, + 0.2437, + 0.0184, + 0.007, + 0.0055, + 0.0018, + 0.0005, + 0.1426, + 0.5515, + 0.1359, + 0.0294, + 0.0082, + 0.0013, + 0.0006, + 0.0005, + 0.0885, + 0.292, + 0.1228, + 0.0373, + 0.0104, + 0.0021, + 0.0007, + 0.0003, + 0.1069, + 0.2544, + 0.0884, + 0.0148, + 0.0032, + 0.0007, + 0.0006, + 0.0008, + 0.2833, + 0.5319, + 0.1789, + 0.0072, + 0.0031, + 0.0003, + 0.0008, + 0.0013, + 0.3879, + 0.6422, + 0.2154, + 0.0067, + 0.0031, + 0.002, + 0.0008, + 0.0012, + 0.4241, + 0.8546, + 0.2222, + 0.0112, + 0.0059, + 0.0044, + 0.0017, + 0.0007, + 0.2927, + 0.5689, + 0.1425, + 0.0198, + 0.0073, + 0.0015, + 0.0007, + 0.0006, + 0.1547, + 0.2589, + 0.0416, + 0.0285, + 0.0084, + 0.0019, + 0.0008, + 0.0004, + 0.0889, + 0.2143, + 0.0111, + 0.0211, + 0.0053, + 0.0005, + 0.0006, + 0.0006, + 0.2758, + 0.5238, + 0.0038, + 0.0065, + 0.0009, + 0.0005, + 0.0009, + 0.0009, + 0.36, + 0.595, + 0.2006, + 0.0079, + 0.0014, + 0.0019, + 0.0009, + 0.001, + 0.478, + 0.7296, + 0.2472, + 0.0083, + 0.0019, + 0.0024, + 0.0003, + 0.0004, + 0.4296, + 0.6323, + 0.2152, + 0.0246, + 0.0096, + 0.003, + 0.0004, + 0.0006, + 0.1531, + 0.1827, + 0.0395, + 0.0133, + 0.005, + 0.0013, + 0.0004, + 0.0005, + 0.1351, + 0.1919, + 0.0092, + 0.0113, + 0.0037, + 0.0006, + 0.0007, + 0.0006, + 0.4168, + 0.5108, + 0.0058, + 0.0075, + 0.0015, + 0.0002, + 0.0008, + 0.0008, + 0.5695, + 0.6334, + 0.0057, + 0.0083, + 0.0016, + 0.0016, + 0.0009, + 0.001, + 0.6373, + 0.6493, + 0.0068, + 0.0071, + 0.0017, + 0.0014, + 0.0004, + 0.0004, + 0.3814, + 0.567, + 0.0187, + 0.0194, + 0.0019, + 0.0022, + 0.0004, + 0.0004, + 0.2022, + 0.2556, + 0.0139, + 0.0146, + 0.0042, + 0.0046, + 0.0003, + 0.0056, + 0.137, + 0.1347, + 0.0145, + 0.0173, + 0.0014, + 0.0015, + 0.0004, + 0.0004, + 0.3738, + 0.3085, + 0.0042, + 0.0052, + 0.0004, + 0.0004, + 0.001, + 0.0008, + 0.5467, + 0.4103, + 0.0053, + 0.006, + 0.0023, + 0.0022, + 0.0011, + 0.0009, + 0.7454, + 0.7646, + 0.008, + 0.0069, + 0.0041, + 0.0034, + 0.0006, + 0.0005, + 0.564, + 0.564, + 0.0092, + 0.0071, + 0.0039, + 0.0032, + 0.0003, + 0.0003, + 0.3636, + 0.3189, + 0.0227, + 0.0159 + ], + "noveltyPeaks": [ + { + "time": 0.302, + "strength": 0.6099 + }, + { + "time": 2.717, + "strength": 0.938 + }, + { + "time": 5.619, + "strength": 0.8546 + }, + { + "time": 8.522, + "strength": 0.9615 + }, + { + "time": 11.424, + "strength": 0.8533 + }, + { + "time": 14.327, + "strength": 1.0 + } + ], + "noveltyMean": 0.1171, + "noveltyStdDev": 0.2043 + }, + "segmentLoudness": [ + { + "segmentIndex": 0, + "start": 0.0, + "end": 6.896, + "lufs": -10.1, + "lra": 0.2 + }, + { + "segmentIndex": 1, + "start": 6.896, + "end": 15.484, + "lufs": -10.1, + "lra": 0.2 + } + ], + "segmentSpectral": [ + { + "segmentIndex": 0, + "barkBands": [ + -23.3087, + -9.4929, + -10.8094, + -18.2507, + -29.3554, + -40.6664, + -29.93, + -29.5995, + -31.9922, + -31.9533, + -36.2156, + -38.6561, + -36.9071, + -36.8171, + -39.7518, + -39.9617, + -39.1863, + -40.1506, + -40.4395, + -41.2423, + -38.537, + -35.7543, + -35.9829, + -32.0527 + ], + "spectralCentroid": 1214.4, + "spectralRolloff": 1667.4, + "stereoWidth": 0.0, + "stereoCorrelation": 1.0 + }, + { + "segmentIndex": 1, + "barkBands": [ + -23.2997, + -9.6688, + -10.7668, + -18.3307, + -31.3935, + -42.2181, + -31.4689, + -30.4938, + -28.8361, + -32.9044, + -38.6202, + -38.3944, + -34.6924, + -38.3192, + -39.2189, + -39.0711, + -39.5006, + -39.637, + -40.0485, + -41.0589, + -38.3627, + -35.5499, + -35.751, + -31.8755 + ], + "spectralCentroid": 1249.8, + "spectralRolloff": 1743.0, + "stereoWidth": 0.0, + "stereoCorrelation": 1.0 + } + ], + "segmentStereo": [ + { + "segmentIndex": 0, + "stereoWidth": 0.0, + "stereoCorrelation": 1.0 + }, + { + "segmentIndex": 1, + "stereoWidth": 0.0, + "stereoCorrelation": 1.0 + } + ], + "segmentKey": [ + { + "segmentIndex": 0, + "key": "A Minor", + "keyConfidence": 0.65 + }, + { + "segmentIndex": 1, + "key": "A Minor", + "keyConfidence": 0.66 + } + ], + "chordDetail": { + "chordSequence": [ + "G", + "G", + "G", + "F", + "F", + "F", + "F", + "F", + "Am", + "Am", + "F", + "F", + "F", + "F", + "F", + "F", + "Am", + "F", + "F", + "F", + "F", + "F", + "F", + "F", + "F", + "F", + "F", + "F", + "Am", + "Am", + "Am", + "Am" + ], + "chordStrength": 0.6381, + "progression": [ + "G", + "F", + "G", + "F", + "Am", + "F", + "Am", + "G", + "Am", + "G", + "F", + "Am", + "F", + "Am", + "F", + "Am" + ], + "dominantChords": [ + "F", + "Am", + "G", + "Em" + ], + "chordTimeline": [ + { + "startSec": 0.0, + "endSec": 15.511, + "label": "G", + "labelLong": "G major", + "confidence": 0.5508 + } + ], + "chordChangeCount": 0, + "chordTimelineSource": "librosa_viterbi", + "chordTimelineAgreement": false + }, + "perceptual": { + "sharpness": 0.0628, + "roughness": 0.0 + }, + "essentiaFeatures": { + "zeroCrossingRate": 0.0387, + "hfc": 171.2753, + "spectralComplexity": 7.8623, + "dissonance": 0.0 + } +} \ No newline at end of file diff --git a/apps/backend/tests/fixtures/recommendation_tracks/melodic_techno_arp_124/README.md b/apps/backend/tests/fixtures/recommendation_tracks/melodic_techno_arp_124/README.md new file mode 100644 index 00000000..5ed1affc --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/melodic_techno_arp_124/README.md @@ -0,0 +1,23 @@ +# melodic_techno_arp_124 + +**Genre:** melodic techno · **Tempo:** 124 BPM · **Key:** D minor · **Render:** 48 kHz / 24-bit, 16 s loop + +## What this fixture isolates + +The melodic-techno signature: an **arpeggiated Wavetable pluck** (driven by an +`Arpeggiator`, 1/16 up) over a sine sub and sine kick, **sidechained**, and pushed +forward with a long `Reverb` (2.5 s, 35 % wet). It tests whether ASA recommends an +arp engine + plucky envelope for the melody, the pump on the bass, and the +reverb-forward space that defines the genre (`reverbDetail.isWet`). + +Covers all seven production domains. + +## Answer key + +`manifest.json` → `deviceSpec`. Build verbatim in Live 12 (checklist in +`../README.md`), render to `audio.flac`, store `phase1_fingerprint.json`. + +## Status +- [x] Catalog-valid spec authored +- [ ] **NEEDS-FIXTURE:** rendered `audio.flac` +- [ ] **NEEDS-FIXTURE:** stored `phase1_fingerprint.json` diff --git a/apps/backend/tests/fixtures/recommendation_tracks/melodic_techno_arp_124/audio_melody.mid b/apps/backend/tests/fixtures/recommendation_tracks/melodic_techno_arp_124/audio_melody.mid new file mode 100644 index 00000000..7dd896e3 Binary files /dev/null and b/apps/backend/tests/fixtures/recommendation_tracks/melodic_techno_arp_124/audio_melody.mid differ diff --git a/apps/backend/tests/fixtures/recommendation_tracks/melodic_techno_arp_124/manifest.json b/apps/backend/tests/fixtures/recommendation_tracks/melodic_techno_arp_124/manifest.json new file mode 100644 index 00000000..2a56941a --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/melodic_techno_arp_124/manifest.json @@ -0,0 +1,145 @@ +{ + "schemaVersion": "recommendation-fixture.v1", + "id": "melodic_techno_arp_124", + "title": "Melodic techno — arpeggiated pluck, sub, reverb-heavy", + "genre": "melodic techno", + "audioPath": "audio.flac", + "phase1FingerprintPath": "phase1_fingerprint.json", + "phase1Fingerprint": null, + "render": { + "sampleRateHz": 48000, + "bitDepth": 24, + "lengthSeconds": 16, + "bpm": 124, + "key": "D minor", + "notes": "8-bar loop. Arpeggiated Wavetable pluck over a sine sub, kick, offbeat hats. Reverb-forward. Render the full loop to one stereo file, no export normalization." + }, + "deviceSpec": { + "kick": [ + { + "device": "Operator", + "family": "NATIVE", + "role": "Sine kick", + "parameters": [ + { "name": "Oscillator A Waveform", "value": "Sine" }, + { "name": "Filter Type", "value": "Lowpass" }, + { "name": "Filter Frequency", "value": "140 Hz" }, + { "name": "Amp Envelope Decay", "value": "280 ms" } + ] + } + ], + "bass": [ + { + "device": "Operator", + "family": "NATIVE", + "role": "Sub bass", + "parameters": [ + { "name": "Oscillator A Waveform", "value": "Sine" }, + { "name": "Filter Frequency", "value": "180 Hz" }, + { "name": "Amp Envelope Sustain", "value": "100%" } + ] + } + ], + "melody": [ + { + "device": "Wavetable", + "family": "NATIVE", + "role": "Arp pluck", + "parameters": [ + { "name": "Oscillator 1 Wavetable", "value": "Basic Shapes" }, + { "name": "Filter Type", "value": "Lowpass" }, + { "name": "Filter Frequency", "value": "2500 Hz" }, + { "name": "Filter Resonance", "value": "25%" }, + { "name": "Amp Envelope Attack", "value": "2 ms" }, + { "name": "Amp Envelope Decay", "value": "250 ms" }, + { "name": "Amp Envelope Sustain", "value": "10%" }, + { "name": "Amp Envelope Release", "value": "200 ms" } + ] + }, + { + "device": "Arpeggiator", + "family": "NATIVE", + "role": "Arp engine on the pluck", + "parameters": [ + { "name": "Style", "value": "Up" }, + { "name": "Rate", "value": "1/16" }, + { "name": "Gate", "value": "50%" } + ] + } + ], + "groove": [ + { + "device": "Drum Rack", + "family": "NATIVE", + "role": "Offbeat hats", + "parameters": [ + { "name": "Pad Volume", "value": "-9 dB" } + ] + } + ], + "fx": [ + { + "device": "Compressor", + "family": "NATIVE", + "role": "Sidechain pump on bass (keyed off kick)", + "parameters": [ + { "name": "Threshold", "value": "-18 dB" }, + { "name": "Ratio", "value": "4:1" }, + { "name": "Attack", "value": "1 ms" }, + { "name": "Release", "value": "130 ms" }, + { "name": "Sidechain", "value": "On" } + ] + }, + { + "device": "Reverb", + "family": "NATIVE", + "role": "Pluck space (the genre signature)", + "parameters": [ + { "name": "Decay Time", "value": "2.5 s" }, + { "name": "Predelay", "value": "25 ms" }, + { "name": "Dry/Wet", "value": "35%" } + ] + } + ], + "stereo": [ + { + "device": "Utility", + "family": "NATIVE", + "role": "Pluck widener", + "parameters": [ + { "name": "Stereo Width", "value": "120%" } + ] + } + ], + "master": [ + { + "device": "Glue Compressor", + "family": "NATIVE", + "role": "Bus glue", + "parameters": [ + { "name": "Threshold", "value": "-16 dB" }, + { "name": "Ratio", "value": "2:1" }, + { "name": "Attack", "value": "10 ms" }, + { "name": "Release", "value": "Auto" }, + { "name": "Makeup", "value": "2 dB" } + ] + }, + { + "device": "Limiter", + "family": "NATIVE", + "role": "Master ceiling", + "parameters": [ + { "name": "Ceiling", "value": "-0.3 dB" } + ] + } + ] + }, + "measurableIntent": { + "bpm": { "target": 124, "tolerance": 1, "direction": "exact" }, + "key": { "target": "D minor" }, + "kickDetail.fundamentalHz": { "target": 52, "tolerance": 15, "unit": "Hz" }, + "sidechainDetail.pumpingStrength": { "target": 0.5, "tolerance": 0.25, "direction": "min" }, + "reverbDetail.isWet": { "equals": true }, + "lufsIntegrated": { "target": -9, "tolerance": 2, "unit": "LUFS" } + } +} diff --git a/apps/backend/tests/fixtures/recommendation_tracks/melodic_techno_arp_124/phase1_fingerprint.json b/apps/backend/tests/fixtures/recommendation_tracks/melodic_techno_arp_124/phase1_fingerprint.json new file mode 100644 index 00000000..cd7d392f --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/melodic_techno_arp_124/phase1_fingerprint.json @@ -0,0 +1,4680 @@ +{ + "_synthetic": true, + "_note": "Phase 1 of a numpy PROXY render, NOT an Ableton render. Replace with a real Live render's fingerprint for an authoritative verdict.", + "bpm": 124.1, + "bpmConfidence": 4.0, + "bpmPercival": 123.8, + "bpmAgreement": true, + "bpmDoubletime": false, + "bpmSource": "rhythm_extractor_confirmed", + "bpmRawOriginal": 124.1, + "key": "G Minor", + "keyConfidence": 0.71, + "keyProfile": "edma", + "tuningFrequency": 438.48, + "tuningCents": -6.0, + "timeSignature": "4/4", + "timeSignatureSource": "onset_autocorrelation_low_margin", + "timeSignatureConfidence": 0.0, + "durationSeconds": 15.5, + "sampleRate": 44100, + "lufsIntegrated": -10.1, + "lufsRange": 0.2, + "lufsMomentaryMax": -9.4, + "lufsShortTermMax": -9.9, + "lufsCurve": { + "shortTerm": [ + { + "t": 0.0, + "lufs": -10.0 + }, + { + "t": 0.1, + "lufs": -10.1 + }, + { + "t": 0.2, + "lufs": -10.0 + }, + { + "t": 0.3, + "lufs": -10.1 + }, + { + "t": 0.4, + "lufs": -10.1 + }, + { + "t": 0.5, + "lufs": -10.0 + }, + { + "t": 0.6, + "lufs": -10.1 + }, + { + "t": 0.7, + "lufs": -10.0 + }, + { + "t": 0.8, + "lufs": -10.1 + }, + { + "t": 0.9, + "lufs": -10.0 + }, + { + "t": 1.0, + "lufs": -10.0 + }, + { + "t": 1.1, + "lufs": -10.1 + }, + { + "t": 1.2, + "lufs": -10.0 + }, + { + "t": 1.3, + "lufs": -10.1 + }, + { + "t": 1.4, + "lufs": -10.0 + }, + { + "t": 1.5, + "lufs": -10.1 + }, + { + "t": 1.6, + "lufs": -10.1 + }, + { + "t": 1.7, + "lufs": -10.0 + }, + { + "t": 1.8, + "lufs": -10.1 + }, + { + "t": 1.9, + "lufs": -10.0 + }, + { + "t": 2.0, + "lufs": -10.1 + }, + { + "t": 2.1, + "lufs": -10.0 + }, + { + "t": 2.2, + "lufs": -10.1 + }, + { + "t": 2.3, + "lufs": -10.1 + }, + { + "t": 2.4, + "lufs": -10.0 + }, + { + "t": 2.5, + "lufs": -10.1 + }, + { + "t": 2.6, + "lufs": -10.0 + }, + { + "t": 2.7, + "lufs": -10.1 + }, + { + "t": 2.8, + "lufs": -10.1 + }, + { + "t": 2.9, + "lufs": -10.0 + }, + { + "t": 3.0, + "lufs": -10.1 + }, + { + "t": 3.1, + "lufs": -10.0 + }, + { + "t": 3.2, + "lufs": -10.1 + }, + { + "t": 3.3, + "lufs": -10.1 + }, + { + "t": 3.4, + "lufs": -10.0 + }, + { + "t": 3.5, + "lufs": -10.1 + }, + { + "t": 3.6, + "lufs": -10.0 + }, + { + "t": 3.7, + "lufs": -10.1 + }, + { + "t": 3.8, + "lufs": -10.0 + }, + { + "t": 3.9, + "lufs": -10.0 + }, + { + "t": 4.0, + "lufs": -10.1 + }, + { + "t": 4.1, + "lufs": -10.0 + }, + { + "t": 4.2, + "lufs": -10.1 + }, + { + "t": 4.3, + "lufs": -10.0 + }, + { + "t": 4.4, + "lufs": -10.1 + }, + { + "t": 4.5, + "lufs": -10.1 + }, + { + "t": 4.6, + "lufs": -10.0 + }, + { + "t": 4.7, + "lufs": -10.1 + }, + { + "t": 4.8, + "lufs": -10.0 + }, + { + "t": 4.9, + "lufs": -10.1 + }, + { + "t": 5.0, + "lufs": -10.0 + }, + { + "t": 5.1, + "lufs": -10.1 + }, + { + "t": 5.2, + "lufs": -10.1 + }, + { + "t": 5.3, + "lufs": -10.0 + }, + { + "t": 5.4, + "lufs": -10.1 + }, + { + "t": 5.5, + "lufs": -10.0 + }, + { + "t": 5.6, + "lufs": -10.1 + }, + { + "t": 5.7, + "lufs": -10.1 + }, + { + "t": 5.8, + "lufs": -10.0 + }, + { + "t": 5.9, + "lufs": -10.1 + }, + { + "t": 6.0, + "lufs": -10.0 + }, + { + "t": 6.1, + "lufs": -10.1 + }, + { + "t": 6.2, + "lufs": -10.1 + }, + { + "t": 6.3, + "lufs": -10.0 + }, + { + "t": 6.4, + "lufs": -10.1 + }, + { + "t": 6.5, + "lufs": -10.0 + }, + { + "t": 6.6, + "lufs": -10.1 + }, + { + "t": 6.7, + "lufs": -10.0 + }, + { + "t": 6.8, + "lufs": -10.0 + }, + { + "t": 6.9, + "lufs": -10.1 + }, + { + "t": 7.0, + "lufs": -10.0 + }, + { + "t": 7.1, + "lufs": -10.1 + }, + { + "t": 7.2, + "lufs": -10.0 + }, + { + "t": 7.3, + "lufs": -10.1 + }, + { + "t": 7.4, + "lufs": -10.1 + }, + { + "t": 7.5, + "lufs": -10.0 + }, + { + "t": 7.6, + "lufs": -10.1 + }, + { + "t": 7.7, + "lufs": -10.0 + }, + { + "t": 7.8, + "lufs": -10.1 + }, + { + "t": 7.9, + "lufs": -10.0 + }, + { + "t": 8.0, + "lufs": -10.0 + }, + { + "t": 8.1, + "lufs": -10.1 + }, + { + "t": 8.2, + "lufs": -9.9 + }, + { + "t": 8.3, + "lufs": -10.1 + }, + { + "t": 8.4, + "lufs": -10.0 + }, + { + "t": 8.5, + "lufs": -10.1 + }, + { + "t": 8.6, + "lufs": -10.1 + }, + { + "t": 8.7, + "lufs": -10.0 + }, + { + "t": 8.8, + "lufs": -10.1 + }, + { + "t": 8.9, + "lufs": -10.0 + }, + { + "t": 9.0, + "lufs": -10.1 + }, + { + "t": 9.1, + "lufs": -10.1 + }, + { + "t": 9.2, + "lufs": -10.0 + }, + { + "t": 9.3, + "lufs": -10.1 + }, + { + "t": 9.4, + "lufs": -10.0 + }, + { + "t": 9.5, + "lufs": -10.1 + }, + { + "t": 9.6, + "lufs": -10.1 + }, + { + "t": 9.7, + "lufs": -10.0 + }, + { + "t": 9.8, + "lufs": -10.1 + }, + { + "t": 9.9, + "lufs": -10.0 + }, + { + "t": 10.0, + "lufs": -10.1 + }, + { + "t": 10.1, + "lufs": -10.0 + }, + { + "t": 10.2, + "lufs": -10.1 + }, + { + "t": 10.3, + "lufs": -10.1 + }, + { + "t": 10.4, + "lufs": -10.0 + }, + { + "t": 10.5, + "lufs": -10.1 + }, + { + "t": 10.6, + "lufs": -10.0 + }, + { + "t": 10.7, + "lufs": -10.1 + }, + { + "t": 10.8, + "lufs": -10.1 + }, + { + "t": 10.9, + "lufs": -10.0 + }, + { + "t": 11.0, + "lufs": -10.1 + }, + { + "t": 11.1, + "lufs": -10.0 + }, + { + "t": 11.2, + "lufs": -10.1 + }, + { + "t": 11.3, + "lufs": -10.0 + }, + { + "t": 11.4, + "lufs": -10.1 + }, + { + "t": 11.5, + "lufs": -10.1 + }, + { + "t": 11.6, + "lufs": -10.0 + }, + { + "t": 11.7, + "lufs": -10.1 + }, + { + "t": 11.8, + "lufs": -10.0 + }, + { + "t": 11.9, + "lufs": -10.1 + }, + { + "t": 12.0, + "lufs": -10.1 + }, + { + "t": 12.1, + "lufs": -10.0 + }, + { + "t": 12.2, + "lufs": -10.1 + }, + { + "t": 12.3, + "lufs": -10.0 + }, + { + "t": 12.4, + "lufs": -10.1 + }, + { + "t": 12.5, + "lufs": -10.1 + } + ], + "momentary": [ + { + "t": 0.0, + "lufs": -10.0 + }, + { + "t": 0.1, + "lufs": -10.4 + }, + { + "t": 0.2, + "lufs": -9.5 + }, + { + "t": 0.3, + "lufs": -10.5 + }, + { + "t": 0.4, + "lufs": -9.6 + }, + { + "t": 0.5, + "lufs": -9.9 + }, + { + "t": 0.6, + "lufs": -10.3 + }, + { + "t": 0.7, + "lufs": -9.7 + }, + { + "t": 0.8, + "lufs": -10.8 + }, + { + "t": 0.9, + "lufs": -9.6 + }, + { + "t": 1.0, + "lufs": -10.2 + }, + { + "t": 1.1, + "lufs": -10.0 + }, + { + "t": 1.2, + "lufs": -9.8 + }, + { + "t": 1.3, + "lufs": -10.8 + }, + { + "t": 1.4, + "lufs": -10.0 + }, + { + "t": 1.5, + "lufs": -10.6 + }, + { + "t": 1.6, + "lufs": -9.7 + }, + { + "t": 1.7, + "lufs": -9.7 + }, + { + "t": 1.8, + "lufs": -9.8 + }, + { + "t": 1.9, + "lufs": -9.6 + }, + { + "t": 2.0, + "lufs": -10.8 + }, + { + "t": 2.1, + "lufs": -9.7 + }, + { + "t": 2.2, + "lufs": -10.4 + }, + { + "t": 2.3, + "lufs": -9.8 + }, + { + "t": 2.4, + "lufs": -9.6 + }, + { + "t": 2.5, + "lufs": -10.7 + }, + { + "t": 2.6, + "lufs": -9.9 + }, + { + "t": 2.7, + "lufs": -10.8 + }, + { + "t": 2.8, + "lufs": -10.0 + }, + { + "t": 2.9, + "lufs": -9.9 + }, + { + "t": 3.0, + "lufs": -10.5 + }, + { + "t": 3.1, + "lufs": -9.6 + }, + { + "t": 3.2, + "lufs": -10.5 + }, + { + "t": 3.3, + "lufs": -9.6 + }, + { + "t": 3.4, + "lufs": -9.8 + }, + { + "t": 3.5, + "lufs": -10.3 + }, + { + "t": 3.6, + "lufs": -9.7 + }, + { + "t": 3.7, + "lufs": -10.8 + }, + { + "t": 3.8, + "lufs": -9.6 + }, + { + "t": 3.9, + "lufs": -10.1 + }, + { + "t": 4.0, + "lufs": -10.1 + }, + { + "t": 4.1, + "lufs": -9.8 + }, + { + "t": 4.2, + "lufs": -11.0 + }, + { + "t": 4.3, + "lufs": -10.0 + }, + { + "t": 4.4, + "lufs": -10.6 + }, + { + "t": 4.5, + "lufs": -9.7 + }, + { + "t": 4.6, + "lufs": -9.5 + }, + { + "t": 4.7, + "lufs": -9.9 + }, + { + "t": 4.8, + "lufs": -9.6 + }, + { + "t": 4.9, + "lufs": -10.8 + }, + { + "t": 5.0, + "lufs": -9.7 + }, + { + "t": 5.1, + "lufs": -10.3 + }, + { + "t": 5.2, + "lufs": -9.8 + }, + { + "t": 5.3, + "lufs": -9.6 + }, + { + "t": 5.4, + "lufs": -10.7 + }, + { + "t": 5.5, + "lufs": -10.0 + }, + { + "t": 5.6, + "lufs": -10.8 + }, + { + "t": 5.7, + "lufs": -10.0 + }, + { + "t": 5.8, + "lufs": -10.0 + }, + { + "t": 5.9, + "lufs": -10.5 + }, + { + "t": 6.0, + "lufs": -9.6 + }, + { + "t": 6.1, + "lufs": -10.5 + }, + { + "t": 6.2, + "lufs": -9.5 + }, + { + "t": 6.3, + "lufs": -9.8 + }, + { + "t": 6.4, + "lufs": -10.3 + }, + { + "t": 6.5, + "lufs": -9.7 + }, + { + "t": 6.6, + "lufs": -10.8 + }, + { + "t": 6.7, + "lufs": -9.6 + }, + { + "t": 6.8, + "lufs": -10.0 + }, + { + "t": 6.9, + "lufs": -10.0 + }, + { + "t": 7.0, + "lufs": -9.8 + }, + { + "t": 7.1, + "lufs": -11.1 + }, + { + "t": 7.2, + "lufs": -10.0 + }, + { + "t": 7.3, + "lufs": -10.6 + }, + { + "t": 7.4, + "lufs": -9.7 + }, + { + "t": 7.5, + "lufs": -9.4 + }, + { + "t": 7.6, + "lufs": -10.0 + }, + { + "t": 7.7, + "lufs": -9.6 + }, + { + "t": 7.8, + "lufs": -10.8 + }, + { + "t": 7.9, + "lufs": -9.8 + }, + { + "t": 8.0, + "lufs": -10.2 + }, + { + "t": 8.1, + "lufs": -9.8 + }, + { + "t": 8.2, + "lufs": -9.6 + }, + { + "t": 8.3, + "lufs": -10.7 + }, + { + "t": 8.4, + "lufs": -10.0 + }, + { + "t": 8.5, + "lufs": -10.7 + }, + { + "t": 8.6, + "lufs": -10.0 + }, + { + "t": 8.7, + "lufs": -10.0 + }, + { + "t": 8.8, + "lufs": -10.5 + }, + { + "t": 8.9, + "lufs": -9.6 + }, + { + "t": 9.0, + "lufs": -10.5 + }, + { + "t": 9.1, + "lufs": -9.5 + }, + { + "t": 9.2, + "lufs": -9.8 + }, + { + "t": 9.3, + "lufs": -10.4 + }, + { + "t": 9.4, + "lufs": -9.7 + }, + { + "t": 9.5, + "lufs": -10.8 + }, + { + "t": 9.6, + "lufs": -9.6 + }, + { + "t": 9.7, + "lufs": -9.9 + }, + { + "t": 9.8, + "lufs": -10.1 + }, + { + "t": 9.9, + "lufs": -9.8 + }, + { + "t": 10.0, + "lufs": -11.1 + }, + { + "t": 10.1, + "lufs": -10.0 + }, + { + "t": 10.2, + "lufs": -10.5 + }, + { + "t": 10.3, + "lufs": -9.7 + }, + { + "t": 10.4, + "lufs": -9.4 + }, + { + "t": 10.5, + "lufs": -10.1 + }, + { + "t": 10.6, + "lufs": -9.7 + }, + { + "t": 10.7, + "lufs": -10.8 + }, + { + "t": 10.8, + "lufs": -9.8 + }, + { + "t": 10.9, + "lufs": -10.0 + }, + { + "t": 11.0, + "lufs": -9.8 + }, + { + "t": 11.1, + "lufs": -9.6 + }, + { + "t": 11.2, + "lufs": -10.7 + }, + { + "t": 11.3, + "lufs": -10.0 + }, + { + "t": 11.4, + "lufs": -10.6 + }, + { + "t": 11.5, + "lufs": -10.0 + }, + { + "t": 11.6, + "lufs": -10.0 + }, + { + "t": 11.7, + "lufs": -10.6 + }, + { + "t": 11.8, + "lufs": -9.6 + }, + { + "t": 11.9, + "lufs": -10.5 + }, + { + "t": 12.0, + "lufs": -9.5 + }, + { + "t": 12.1, + "lufs": -9.7 + }, + { + "t": 12.2, + "lufs": -10.5 + }, + { + "t": 12.3, + "lufs": -9.7 + }, + { + "t": 12.4, + "lufs": -10.7 + }, + { + "t": 12.5, + "lufs": -9.6 + }, + { + "t": 12.6, + "lufs": -9.9 + }, + { + "t": 12.7, + "lufs": -10.1 + }, + { + "t": 12.8, + "lufs": -9.8 + }, + { + "t": 12.9, + "lufs": -11.0 + }, + { + "t": 13.0, + "lufs": -10.0 + }, + { + "t": 13.1, + "lufs": -10.6 + }, + { + "t": 13.2, + "lufs": -9.8 + }, + { + "t": 13.3, + "lufs": -9.5 + }, + { + "t": 13.4, + "lufs": -10.2 + }, + { + "t": 13.5, + "lufs": -9.7 + }, + { + "t": 13.6, + "lufs": -10.7 + }, + { + "t": 13.7, + "lufs": -9.8 + }, + { + "t": 13.8, + "lufs": -10.0 + }, + { + "t": 13.9, + "lufs": -9.9 + }, + { + "t": 14.0, + "lufs": -9.6 + }, + { + "t": 14.1, + "lufs": -10.6 + }, + { + "t": 14.2, + "lufs": -10.0 + }, + { + "t": 14.3, + "lufs": -10.6 + }, + { + "t": 14.4, + "lufs": -10.0 + }, + { + "t": 14.5, + "lufs": -10.0 + }, + { + "t": 14.6, + "lufs": -10.7 + }, + { + "t": 14.7, + "lufs": -9.6 + }, + { + "t": 14.8, + "lufs": -10.4 + }, + { + "t": 14.9, + "lufs": -9.5 + }, + { + "t": 15.0, + "lufs": -9.6 + }, + { + "t": 15.1, + "lufs": -11.1 + } + ] + }, + "truePeak": 1.1, + "plr": 11.2, + "crestFactor": 10.8, + "dynamicSpread": 39.55, + "dynamicCharacter": { + "dynamicComplexity": 1.985, + "loudnessDb": -18.7194, + "loudnessVariation": -18.7194, + "spectralFlatness": 0.1071, + "logAttackTime": -4.5921, + "attackTimeStdDev": 0.0015 + }, + "textureCharacter": { + "textureScore": 0.256, + "lowBandFlatness": 0.2626, + "midBandFlatness": 0.3205, + "highBandFlatness": 0.2914, + "inharmonicity": 0.0231 + }, + "stereoDetail": { + "stereoWidth": 0.0, + "stereoCorrelation": 1.0, + "subBassCorrelation": 1.0, + "subBassMono": true, + "correlationCurve": [ + { + "t": 0.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 1.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 2.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 3.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 4.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 5.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 6.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 7.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 8.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 9.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 10.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 11.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 12.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 13.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 14.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 15.5, + "full": 1.0, + "sub": 1.0 + } + ], + "bandCorrelations": { + "subBass": 1.0, + "lowBass": 1.0, + "lowMids": 1.0, + "mids": 1.0, + "upperMids": 1.0, + "highs": 1.0, + "brilliance": 1.0 + } + }, + "monoCompatible": true, + "spectralBalance": { + "subBass": -7.3, + "lowBass": -10.3, + "lowMids": -25.4, + "mids": -27.4, + "upperMids": -34.2, + "highs": -28.8, + "brilliance": -21.0 + }, + "spectralBalanceTimeSeries": [ + { + "t": 0.03, + "subBass": -8.2, + "lowBass": -7.2, + "lowMids": -28.3, + "mids": -33.4, + "upperMids": -44.8, + "highs": -71.8, + "brilliance": -79.2 + }, + { + "t": 0.13, + "subBass": -5.8, + "lowBass": -17.6, + "lowMids": -27.5, + "mids": -31.3, + "upperMids": -41.2, + "highs": -75.1, + "brilliance": -77.7 + }, + { + "t": 0.22, + "subBass": -7.6, + "lowBass": -14.9, + "lowMids": -26.0, + "mids": -29.6, + "upperMids": -30.2, + "highs": -23.4, + "brilliance": -15.4 + }, + { + "t": 0.31, + "subBass": -7.9, + "lowBass": -10.9, + "lowMids": -25.2, + "mids": -28.9, + "upperMids": -33.2, + "highs": -27.0, + "brilliance": -19.4 + }, + { + "t": 0.41, + "subBass": -8.4, + "lowBass": -10.0, + "lowMids": -31.0, + "mids": -20.1, + "upperMids": -31.7, + "highs": -45.4, + "brilliance": -56.1 + }, + { + "t": 0.5, + "subBass": -6.4, + "lowBass": -5.2, + "lowMids": -28.6, + "mids": -29.8, + "upperMids": -41.3, + "highs": -54.1, + "brilliance": -59.7 + }, + { + "t": 0.59, + "subBass": -5.7, + "lowBass": -15.8, + "lowMids": -28.4, + "mids": -31.8, + "upperMids": -43.0, + "highs": -82.1, + "brilliance": -88.7 + }, + { + "t": 0.68, + "subBass": -7.4, + "lowBass": -14.5, + "lowMids": -27.7, + "mids": -30.6, + "upperMids": -35.5, + "highs": -28.8, + "brilliance": -21.8 + }, + { + "t": 0.78, + "subBass": -7.3, + "lowBass": -13.4, + "lowMids": -23.9, + "mids": -27.7, + "upperMids": -29.6, + "highs": -23.0, + "brilliance": -14.9 + }, + { + "t": 0.87, + "subBass": -8.9, + "lowBass": -13.0, + "lowMids": -30.6, + "mids": -20.6, + "upperMids": -32.1, + "highs": -45.6, + "brilliance": -55.4 + }, + { + "t": 0.96, + "subBass": -8.3, + "lowBass": -6.2, + "lowMids": -28.8, + "mids": -26.6, + "upperMids": -37.9, + "highs": -48.2, + "brilliance": -51.5 + }, + { + "t": 1.06, + "subBass": -4.7, + "lowBass": -12.2, + "lowMids": -30.1, + "mids": -33.7, + "upperMids": -44.0, + "highs": -83.3, + "brilliance": -85.6 + }, + { + "t": 1.15, + "subBass": -7.1, + "lowBass": -15.1, + "lowMids": -26.9, + "mids": -30.8, + "upperMids": -40.3, + "highs": -91.3, + "brilliance": -142.0 + }, + { + "t": 1.24, + "subBass": -9.3, + "lowBass": -11.3, + "lowMids": -32.7, + "mids": -22.8, + "upperMids": -28.6, + "highs": -21.8, + "brilliance": -13.9 + }, + { + "t": 1.34, + "subBass": -8.6, + "lowBass": -9.7, + "lowMids": -22.3, + "mids": -25.1, + "upperMids": -35.0, + "highs": -52.3, + "brilliance": -56.4 + }, + { + "t": 1.43, + "subBass": -10.5, + "lowBass": -7.0, + "lowMids": -24.9, + "mids": -28.4, + "upperMids": -38.1, + "highs": -52.8, + "brilliance": -54.5 + }, + { + "t": 1.52, + "subBass": -5.6, + "lowBass": -10.7, + "lowMids": -31.6, + "mids": -35.3, + "upperMids": -46.5, + "highs": -85.2, + "brilliance": -99.8 + }, + { + "t": 1.61, + "subBass": -7.0, + "lowBass": -18.0, + "lowMids": -26.3, + "mids": -29.8, + "upperMids": -38.8, + "highs": -53.9, + "brilliance": -86.5 + }, + { + "t": 1.71, + "subBass": -8.0, + "lowBass": -12.8, + "lowMids": -24.3, + "mids": -27.5, + "upperMids": -28.9, + "highs": -21.4, + "brilliance": -13.7 + }, + { + "t": 1.8, + "subBass": -7.8, + "lowBass": -10.5, + "lowMids": -23.0, + "mids": -26.7, + "upperMids": -36.6, + "highs": -46.5, + "brilliance": -38.3 + }, + { + "t": 1.89, + "subBass": -9.4, + "lowBass": -9.4, + "lowMids": -22.8, + "mids": -27.2, + "upperMids": -36.6, + "highs": -53.0, + "brilliance": -55.2 + }, + { + "t": 1.99, + "subBass": -5.0, + "lowBass": -5.9, + "lowMids": -29.6, + "mids": -35.5, + "upperMids": -43.6, + "highs": -66.8, + "brilliance": -69.4 + }, + { + "t": 2.08, + "subBass": -6.9, + "lowBass": -15.8, + "lowMids": -26.6, + "mids": -30.5, + "upperMids": -40.4, + "highs": -80.1, + "brilliance": -85.3 + }, + { + "t": 2.17, + "subBass": -8.0, + "lowBass": -14.4, + "lowMids": -25.3, + "mids": -28.3, + "upperMids": -29.2, + "highs": -21.7, + "brilliance": -14.0 + }, + { + "t": 2.26, + "subBass": -7.3, + "lowBass": -13.0, + "lowMids": -24.4, + "mids": -27.7, + "upperMids": -36.2, + "highs": -31.5, + "brilliance": -23.9 + }, + { + "t": 2.36, + "subBass": -9.4, + "lowBass": -12.9, + "lowMids": -21.5, + "mids": -25.3, + "upperMids": -36.3, + "highs": -56.5, + "brilliance": -58.6 + }, + { + "t": 2.45, + "subBass": -5.9, + "lowBass": -5.7, + "lowMids": -29.9, + "mids": -29.5, + "upperMids": -39.7, + "highs": -47.1, + "brilliance": -49.7 + }, + { + "t": 2.54, + "subBass": -5.8, + "lowBass": -16.2, + "lowMids": -28.2, + "mids": -30.6, + "upperMids": -40.1, + "highs": -55.0, + "brilliance": -82.6 + }, + { + "t": 2.64, + "subBass": -8.3, + "lowBass": -14.0, + "lowMids": -26.2, + "mids": -29.5, + "upperMids": -30.5, + "highs": -23.2, + "brilliance": -15.5 + }, + { + "t": 2.73, + "subBass": -7.5, + "lowBass": -10.1, + "lowMids": -25.0, + "mids": -28.8, + "upperMids": -32.1, + "highs": -26.0, + "brilliance": -18.2 + }, + { + "t": 2.82, + "subBass": -9.6, + "lowBass": -9.7, + "lowMids": -21.2, + "mids": -24.9, + "upperMids": -34.9, + "highs": -57.1, + "brilliance": -59.4 + }, + { + "t": 2.91, + "subBass": -8.8, + "lowBass": -6.4, + "lowMids": -26.3, + "mids": -29.4, + "upperMids": -40.0, + "highs": -48.6, + "brilliance": -51.1 + }, + { + "t": 3.01, + "subBass": -5.5, + "lowBass": -17.9, + "lowMids": -29.0, + "mids": -32.6, + "upperMids": -42.1, + "highs": -62.4, + "brilliance": -77.9 + }, + { + "t": 3.1, + "subBass": -7.7, + "lowBass": -17.1, + "lowMids": -27.6, + "mids": -31.5, + "upperMids": -37.8, + "highs": -33.8, + "brilliance": -26.9 + }, + { + "t": 3.19, + "subBass": -7.7, + "lowBass": -11.2, + "lowMids": -23.7, + "mids": -27.3, + "upperMids": -29.4, + "highs": -22.1, + "brilliance": -14.1 + }, + { + "t": 3.29, + "subBass": -8.4, + "lowBass": -10.2, + "lowMids": -21.7, + "mids": -25.1, + "upperMids": -34.1, + "highs": -48.2, + "brilliance": -56.4 + }, + { + "t": 3.38, + "subBass": -8.7, + "lowBass": -5.7, + "lowMids": -25.9, + "mids": -30.3, + "upperMids": -39.6, + "highs": -53.4, + "brilliance": -59.6 + }, + { + "t": 3.47, + "subBass": -4.9, + "lowBass": -11.2, + "lowMids": -30.7, + "mids": -34.0, + "upperMids": -44.5, + "highs": -82.4, + "brilliance": -88.8 + }, + { + "t": 3.56, + "subBass": -6.6, + "lowBass": -14.2, + "lowMids": -26.8, + "mids": -30.7, + "upperMids": -40.2, + "highs": -90.1, + "brilliance": -126.4 + }, + { + "t": 3.66, + "subBass": -8.2, + "lowBass": -14.0, + "lowMids": -24.1, + "mids": -27.3, + "upperMids": -29.3, + "highs": -22.0, + "brilliance": -14.1 + }, + { + "t": 3.75, + "subBass": -7.9, + "lowBass": -13.1, + "lowMids": -22.4, + "mids": -25.9, + "upperMids": -36.1, + "highs": -54.6, + "brilliance": -56.6 + }, + { + "t": 3.84, + "subBass": -9.9, + "lowBass": -8.4, + "lowMids": -24.6, + "mids": -28.0, + "upperMids": -37.6, + "highs": -49.2, + "brilliance": -51.7 + }, + { + "t": 3.94, + "subBass": -4.5, + "lowBass": -7.8, + "lowMids": -37.9, + "mids": -30.8, + "upperMids": -42.7, + "highs": -56.6, + "brilliance": -112.1 + }, + { + "t": 4.03, + "subBass": -6.8, + "lowBass": -15.7, + "lowMids": -26.4, + "mids": -29.7, + "upperMids": -40.9, + "highs": -71.3, + "brilliance": -80.3 + }, + { + "t": 4.12, + "subBass": -8.7, + "lowBass": -12.3, + "lowMids": -24.6, + "mids": -28.0, + "upperMids": -28.9, + "highs": -21.9, + "brilliance": -14.0 + }, + { + "t": 4.21, + "subBass": -8.8, + "lowBass": -10.0, + "lowMids": -23.2, + "mids": -27.0, + "upperMids": -36.3, + "highs": -41.0, + "brilliance": -33.0 + }, + { + "t": 4.31, + "subBass": -9.4, + "lowBass": -9.4, + "lowMids": -22.6, + "mids": -26.7, + "upperMids": -36.1, + "highs": -52.1, + "brilliance": -54.2 + }, + { + "t": 4.4, + "subBass": -7.1, + "lowBass": -7.1, + "lowMids": -32.3, + "mids": -29.3, + "upperMids": -41.0, + "highs": -52.0, + "brilliance": -56.8 + }, + { + "t": 4.49, + "subBass": -5.9, + "lowBass": -17.5, + "lowMids": -27.0, + "mids": -30.1, + "upperMids": -41.3, + "highs": -65.4, + "brilliance": -81.1 + }, + { + "t": 4.59, + "subBass": -8.0, + "lowBass": -14.2, + "lowMids": -25.1, + "mids": -28.6, + "upperMids": -29.2, + "highs": -22.1, + "brilliance": -14.4 + }, + { + "t": 4.68, + "subBass": -7.8, + "lowBass": -10.7, + "lowMids": -24.9, + "mids": -28.3, + "upperMids": -35.8, + "highs": -29.8, + "brilliance": -22.3 + }, + { + "t": 4.77, + "subBass": -9.1, + "lowBass": -10.1, + "lowMids": -21.5, + "mids": -25.0, + "upperMids": -36.1, + "highs": -54.2, + "brilliance": -56.2 + }, + { + "t": 4.86, + "subBass": -6.2, + "lowBass": -5.5, + "lowMids": -27.7, + "mids": -33.5, + "upperMids": -43.8, + "highs": -56.5, + "brilliance": -58.5 + }, + { + "t": 4.96, + "subBass": -5.9, + "lowBass": -15.1, + "lowMids": -27.7, + "mids": -31.0, + "upperMids": -40.4, + "highs": -55.7, + "brilliance": -91.1 + }, + { + "t": 5.05, + "subBass": -7.4, + "lowBass": -14.7, + "lowMids": -27.1, + "mids": -29.7, + "upperMids": -31.2, + "highs": -23.6, + "brilliance": -16.3 + }, + { + "t": 5.14, + "subBass": -8.2, + "lowBass": -13.3, + "lowMids": -24.4, + "mids": -28.0, + "upperMids": -31.7, + "highs": -25.0, + "brilliance": -16.9 + }, + { + "t": 5.24, + "subBass": -8.6, + "lowBass": -12.9, + "lowMids": -21.3, + "mids": -24.6, + "upperMids": -35.8, + "highs": -55.9, + "brilliance": -58.0 + }, + { + "t": 5.33, + "subBass": -7.5, + "lowBass": -5.9, + "lowMids": -26.5, + "mids": -31.2, + "upperMids": -39.8, + "highs": -47.7, + "brilliance": -49.7 + }, + { + "t": 5.42, + "subBass": -5.0, + "lowBass": -13.8, + "lowMids": -29.3, + "mids": -33.1, + "upperMids": -43.1, + "highs": -77.3, + "brilliance": -80.1 + }, + { + "t": 5.51, + "subBass": -7.6, + "lowBass": -15.2, + "lowMids": -27.7, + "mids": -31.7, + "upperMids": -40.8, + "highs": -42.0, + "brilliance": -34.9 + }, + { + "t": 5.61, + "subBass": -7.5, + "lowBass": -10.5, + "lowMids": -23.8, + "mids": -27.0, + "upperMids": -29.0, + "highs": -21.5, + "brilliance": -13.7 + }, + { + "t": 5.7, + "subBass": -9.1, + "lowBass": -9.8, + "lowMids": -29.5, + "mids": -20.8, + "upperMids": -32.5, + "highs": -46.2, + "brilliance": -59.6 + }, + { + "t": 5.79, + "subBass": -10.3, + "lowBass": -6.5, + "lowMids": -27.9, + "mids": -25.0, + "upperMids": -36.6, + "highs": -47.3, + "brilliance": -51.5 + }, + { + "t": 5.89, + "subBass": -5.7, + "lowBass": -13.2, + "lowMids": -32.1, + "mids": -33.9, + "upperMids": -43.4, + "highs": -58.0, + "brilliance": -78.3 + }, + { + "t": 5.98, + "subBass": -6.6, + "lowBass": -17.4, + "lowMids": -38.7, + "mids": -25.5, + "upperMids": -37.4, + "highs": -51.2, + "brilliance": -93.3 + }, + { + "t": 6.07, + "subBass": -7.6, + "lowBass": -12.1, + "lowMids": -24.2, + "mids": -27.2, + "upperMids": -29.1, + "highs": -21.8, + "brilliance": -13.9 + }, + { + "t": 6.16, + "subBass": -8.4, + "lowBass": -10.4, + "lowMids": -22.5, + "mids": -25.9, + "upperMids": -35.3, + "highs": -49.6, + "brilliance": -57.0 + }, + { + "t": 6.26, + "subBass": -10.2, + "lowBass": -8.1, + "lowMids": -24.2, + "mids": -28.0, + "upperMids": -37.1, + "highs": -50.8, + "brilliance": -58.8 + }, + { + "t": 6.35, + "subBass": -4.9, + "lowBass": -6.9, + "lowMids": -30.0, + "mids": -35.6, + "upperMids": -45.2, + "highs": -96.2, + "brilliance": -140.6 + }, + { + "t": 6.44, + "subBass": -6.0, + "lowBass": -14.3, + "lowMids": -26.6, + "mids": -30.4, + "upperMids": -40.3, + "highs": -78.5, + "brilliance": -82.2 + }, + { + "t": 6.54, + "subBass": -7.8, + "lowBass": -14.3, + "lowMids": -31.2, + "mids": -24.2, + "upperMids": -29.2, + "highs": -22.2, + "brilliance": -14.3 + }, + { + "t": 6.63, + "subBass": -8.0, + "lowBass": -13.0, + "lowMids": -25.3, + "mids": -24.6, + "upperMids": -35.7, + "highs": -36.7, + "brilliance": -29.1 + }, + { + "t": 6.72, + "subBass": -9.1, + "lowBass": -12.7, + "lowMids": -22.7, + "mids": -26.0, + "upperMids": -37.4, + "highs": -53.1, + "brilliance": -55.1 + }, + { + "t": 6.82, + "subBass": -5.6, + "lowBass": -5.8, + "lowMids": -28.8, + "mids": -33.1, + "upperMids": -40.7, + "highs": -48.1, + "brilliance": -50.4 + }, + { + "t": 6.91, + "subBass": -6.1, + "lowBass": -15.7, + "lowMids": -27.0, + "mids": -30.5, + "upperMids": -41.6, + "highs": -66.9, + "brilliance": -77.4 + }, + { + "t": 7.0, + "subBass": -7.8, + "lowBass": -13.3, + "lowMids": -25.8, + "mids": -29.0, + "upperMids": -29.8, + "highs": -23.0, + "brilliance": -14.9 + }, + { + "t": 7.09, + "subBass": -9.0, + "lowBass": -10.2, + "lowMids": -25.4, + "mids": -28.2, + "upperMids": -34.5, + "highs": -28.5, + "brilliance": -21.1 + }, + { + "t": 7.19, + "subBass": -9.0, + "lowBass": -9.5, + "lowMids": -32.7, + "mids": -20.3, + "upperMids": -32.1, + "highs": -45.6, + "brilliance": -56.6 + }, + { + "t": 7.28, + "subBass": -8.4, + "lowBass": -6.6, + "lowMids": -27.9, + "mids": -29.6, + "upperMids": -40.6, + "highs": -51.1, + "brilliance": -54.1 + }, + { + "t": 7.37, + "subBass": -5.6, + "lowBass": -17.8, + "lowMids": -27.9, + "mids": -31.7, + "upperMids": -41.6, + "highs": -79.3, + "brilliance": -82.9 + }, + { + "t": 7.47, + "subBass": -7.3, + "lowBass": -15.8, + "lowMids": -26.9, + "mids": -30.3, + "upperMids": -31.9, + "highs": -24.7, + "brilliance": -17.5 + }, + { + "t": 7.56, + "subBass": -8.2, + "lowBass": -11.1, + "lowMids": -24.1, + "mids": -27.8, + "upperMids": -30.8, + "highs": -24.4, + "brilliance": -16.1 + }, + { + "t": 7.65, + "subBass": -8.7, + "lowBass": -10.1, + "lowMids": -21.1, + "mids": -24.9, + "upperMids": -35.9, + "highs": -53.8, + "brilliance": -55.9 + }, + { + "t": 7.74, + "subBass": -7.3, + "lowBass": -5.5, + "lowMids": -26.7, + "mids": -31.3, + "upperMids": -41.8, + "highs": -56.3, + "brilliance": -58.4 + }, + { + "t": 7.84, + "subBass": -5.3, + "lowBass": -13.8, + "lowMids": -29.3, + "mids": -33.2, + "upperMids": -41.8, + "highs": -77.4, + "brilliance": -84.7 + }, + { + "t": 7.93, + "subBass": -7.8, + "lowBass": -14.7, + "lowMids": -27.4, + "mids": -31.8, + "upperMids": -39.6, + "highs": -56.9, + "brilliance": -49.1 + }, + { + "t": 8.02, + "subBass": -7.6, + "lowBass": -14.0, + "lowMids": -23.7, + "mids": -27.0, + "upperMids": -28.6, + "highs": -21.3, + "brilliance": -13.6 + }, + { + "t": 8.12, + "subBass": -8.4, + "lowBass": -13.0, + "lowMids": -22.1, + "mids": -25.3, + "upperMids": -34.4, + "highs": -49.0, + "brilliance": -58.6 + }, + { + "t": 8.21, + "subBass": -9.7, + "lowBass": -7.0, + "lowMids": -25.2, + "mids": -29.2, + "upperMids": -37.6, + "highs": -47.6, + "brilliance": -50.7 + }, + { + "t": 8.3, + "subBass": -4.6, + "lowBass": -9.6, + "lowMids": -32.0, + "mids": -35.8, + "upperMids": -45.5, + "highs": -81.3, + "brilliance": -86.8 + }, + { + "t": 8.39, + "subBass": -6.8, + "lowBass": -15.3, + "lowMids": -26.4, + "mids": -30.7, + "upperMids": -38.6, + "highs": -78.9, + "brilliance": -90.2 + }, + { + "t": 8.49, + "subBass": -7.6, + "lowBass": -11.4, + "lowMids": -24.3, + "mids": -27.8, + "upperMids": -28.4, + "highs": -21.3, + "brilliance": -13.6 + }, + { + "t": 8.58, + "subBass": -8.6, + "lowBass": -9.9, + "lowMids": -27.8, + "mids": -22.1, + "upperMids": -33.5, + "highs": -47.1, + "brilliance": -53.7 + }, + { + "t": 8.67, + "subBass": -10.1, + "lowBass": -8.6, + "lowMids": -28.4, + "mids": -22.7, + "upperMids": -34.4, + "highs": -45.9, + "brilliance": -50.8 + }, + { + "t": 8.77, + "subBass": -6.1, + "lowBass": -8.0, + "lowMids": -29.9, + "mids": -35.0, + "upperMids": -44.6, + "highs": -87.5, + "brilliance": -89.6 + }, + { + "t": 8.86, + "subBass": -6.5, + "lowBass": -18.0, + "lowMids": -26.7, + "mids": -30.2, + "upperMids": -41.3, + "highs": -81.2, + "brilliance": -83.3 + }, + { + "t": 8.95, + "subBass": -7.8, + "lowBass": -13.4, + "lowMids": -25.0, + "mids": -28.4, + "upperMids": -29.0, + "highs": -22.0, + "brilliance": -14.1 + }, + { + "t": 9.04, + "subBass": -8.4, + "lowBass": -10.8, + "lowMids": -23.6, + "mids": -27.2, + "upperMids": -35.6, + "highs": -33.7, + "brilliance": -26.1 + }, + { + "t": 9.14, + "subBass": -8.6, + "lowBass": -10.0, + "lowMids": -22.3, + "mids": -26.2, + "upperMids": -36.2, + "highs": -54.9, + "brilliance": -57.0 + }, + { + "t": 9.23, + "subBass": -5.9, + "lowBass": -5.5, + "lowMids": -31.6, + "mids": -30.3, + "upperMids": -41.0, + "highs": -52.1, + "brilliance": -55.6 + }, + { + "t": 9.32, + "subBass": -5.7, + "lowBass": -14.7, + "lowMids": -27.7, + "mids": -30.6, + "upperMids": -40.8, + "highs": -63.4, + "brilliance": -80.4 + }, + { + "t": 9.42, + "subBass": -7.8, + "lowBass": -14.5, + "lowMids": -26.0, + "mids": -28.9, + "upperMids": -30.2, + "highs": -23.5, + "brilliance": -15.4 + }, + { + "t": 9.51, + "subBass": -7.9, + "lowBass": -13.2, + "lowMids": -25.2, + "mids": -28.9, + "upperMids": -34.0, + "highs": -27.5, + "brilliance": -19.9 + }, + { + "t": 9.6, + "subBass": -8.5, + "lowBass": -12.8, + "lowMids": -20.8, + "mids": -24.6, + "upperMids": -35.6, + "highs": -54.3, + "brilliance": -56.4 + }, + { + "t": 9.69, + "subBass": -6.3, + "lowBass": -5.6, + "lowMids": -28.3, + "mids": -31.8, + "upperMids": -40.6, + "highs": -47.9, + "brilliance": -49.8 + }, + { + "t": 9.79, + "subBass": -5.7, + "lowBass": -15.9, + "lowMids": -28.3, + "mids": -32.2, + "upperMids": -40.7, + "highs": -73.3, + "brilliance": -77.5 + }, + { + "t": 9.88, + "subBass": -7.3, + "lowBass": -14.5, + "lowMids": -27.6, + "mids": -31.2, + "upperMids": -33.7, + "highs": -26.9, + "brilliance": -20.0 + }, + { + "t": 9.97, + "subBass": -9.2, + "lowBass": -10.6, + "lowMids": -24.0, + "mids": -27.7, + "upperMids": -29.9, + "highs": -23.5, + "brilliance": -15.2 + }, + { + "t": 10.07, + "subBass": -8.6, + "lowBass": -9.5, + "lowMids": -21.8, + "mids": -25.1, + "upperMids": -34.1, + "highs": -47.8, + "brilliance": -56.4 + }, + { + "t": 10.16, + "subBass": -9.6, + "lowBass": -6.3, + "lowMids": -25.6, + "mids": -30.2, + "upperMids": -39.6, + "highs": -50.0, + "brilliance": -53.2 + }, + { + "t": 10.25, + "subBass": -5.6, + "lowBass": -16.0, + "lowMids": -29.7, + "mids": -33.4, + "upperMids": -42.7, + "highs": -79.3, + "brilliance": -86.1 + }, + { + "t": 10.34, + "subBass": -6.8, + "lowBass": -17.3, + "lowMids": -27.2, + "mids": -31.6, + "upperMids": -39.5, + "highs": -82.2, + "brilliance": -128.0 + }, + { + "t": 10.44, + "subBass": -8.6, + "lowBass": -11.7, + "lowMids": -23.7, + "mids": -27.2, + "upperMids": -28.3, + "highs": -21.5, + "brilliance": -13.8 + }, + { + "t": 10.53, + "subBass": -8.0, + "lowBass": -10.2, + "lowMids": -22.3, + "mids": -25.7, + "upperMids": -36.5, + "highs": -52.9, + "brilliance": -55.9 + }, + { + "t": 10.62, + "subBass": -10.1, + "lowBass": -7.1, + "lowMids": -24.9, + "mids": -28.9, + "upperMids": -39.7, + "highs": -54.4, + "brilliance": -56.4 + }, + { + "t": 10.72, + "subBass": -4.4, + "lowBass": -8.3, + "lowMids": -31.5, + "mids": -36.1, + "upperMids": -45.7, + "highs": -78.4, + "brilliance": -92.3 + }, + { + "t": 10.81, + "subBass": -7.5, + "lowBass": -15.4, + "lowMids": -26.2, + "mids": -29.7, + "upperMids": -38.8, + "highs": -53.8, + "brilliance": -85.4 + }, + { + "t": 10.9, + "subBass": -7.4, + "lowBass": -14.1, + "lowMids": -24.5, + "mids": -27.7, + "upperMids": -28.6, + "highs": -21.3, + "brilliance": -13.6 + }, + { + "t": 10.99, + "subBass": -8.3, + "lowBass": -13.0, + "lowMids": -22.8, + "mids": -26.6, + "upperMids": -36.1, + "highs": -50.8, + "brilliance": -42.5 + }, + { + "t": 11.09, + "subBass": -9.4, + "lowBass": -11.0, + "lowMids": -23.4, + "mids": -27.1, + "upperMids": -36.6, + "highs": -47.5, + "brilliance": -49.8 + }, + { + "t": 11.18, + "subBass": -5.1, + "lowBass": -6.3, + "lowMids": -30.4, + "mids": -35.5, + "upperMids": -43.5, + "highs": -62.6, + "brilliance": -65.0 + }, + { + "t": 11.27, + "subBass": -6.2, + "lowBass": -15.6, + "lowMids": -26.8, + "mids": -30.7, + "upperMids": -40.6, + "highs": -80.0, + "brilliance": -85.8 + }, + { + "t": 11.37, + "subBass": -8.0, + "lowBass": -12.6, + "lowMids": -30.7, + "mids": -24.4, + "upperMids": -29.0, + "highs": -21.7, + "brilliance": -14.0 + }, + { + "t": 11.46, + "subBass": -8.0, + "lowBass": -10.0, + "lowMids": -27.1, + "mids": -24.3, + "upperMids": -34.3, + "highs": -32.1, + "brilliance": -24.5 + }, + { + "t": 11.55, + "subBass": -9.8, + "lowBass": -9.6, + "lowMids": -22.0, + "mids": -25.9, + "upperMids": -34.7, + "highs": -49.1, + "brilliance": -59.3 + }, + { + "t": 11.64, + "subBass": -7.9, + "lowBass": -6.8, + "lowMids": -26.5, + "mids": -31.6, + "upperMids": -40.8, + "highs": -48.3, + "brilliance": -50.4 + }, + { + "t": 11.74, + "subBass": -5.8, + "lowBass": -17.5, + "lowMids": -27.6, + "mids": -31.1, + "upperMids": -42.3, + "highs": -83.4, + "brilliance": -90.4 + }, + { + "t": 11.83, + "subBass": -7.6, + "lowBass": -15.0, + "lowMids": -25.9, + "mids": -29.5, + "upperMids": -30.7, + "highs": -23.4, + "brilliance": -15.4 + }, + { + "t": 11.92, + "subBass": -8.0, + "lowBass": -10.9, + "lowMids": -25.0, + "mids": -28.7, + "upperMids": -33.2, + "highs": -26.6, + "brilliance": -18.8 + }, + { + "t": 12.02, + "subBass": -8.3, + "lowBass": -10.1, + "lowMids": -21.2, + "mids": -24.6, + "upperMids": -33.7, + "highs": -47.9, + "brilliance": -57.2 + }, + { + "t": 12.11, + "subBass": -6.7, + "lowBass": -5.2, + "lowMids": -27.4, + "mids": -32.1, + "upperMids": -41.5, + "highs": -51.6, + "brilliance": -54.1 + }, + { + "t": 12.2, + "subBass": -5.5, + "lowBass": -15.6, + "lowMids": -28.7, + "mids": -32.5, + "upperMids": -41.3, + "highs": -78.4, + "brilliance": -89.2 + }, + { + "t": 12.29, + "subBass": -7.5, + "lowBass": -14.5, + "lowMids": -27.9, + "mids": -31.4, + "upperMids": -36.2, + "highs": -30.9, + "brilliance": -24.0 + }, + { + "t": 12.39, + "subBass": -7.3, + "lowBass": -13.5, + "lowMids": -23.8, + "mids": -27.6, + "upperMids": -29.2, + "highs": -22.6, + "brilliance": -14.5 + }, + { + "t": 12.48, + "subBass": -8.7, + "lowBass": -12.9, + "lowMids": -21.6, + "mids": -25.0, + "upperMids": -34.1, + "highs": -48.0, + "brilliance": -57.3 + }, + { + "t": 12.57, + "subBass": -8.4, + "lowBass": -6.1, + "lowMids": -27.0, + "mids": -28.2, + "upperMids": -37.5, + "highs": -46.4, + "brilliance": -49.7 + }, + { + "t": 12.67, + "subBass": -4.6, + "lowBass": -11.5, + "lowMids": -33.4, + "mids": -31.1, + "upperMids": -42.7, + "highs": -58.1, + "brilliance": -80.4 + }, + { + "t": 12.76, + "subBass": -7.0, + "lowBass": -15.2, + "lowMids": -26.8, + "mids": -30.5, + "upperMids": -41.7, + "highs": -92.3, + "brilliance": -142.6 + }, + { + "t": 12.85, + "subBass": -9.4, + "lowBass": -11.4, + "lowMids": -23.9, + "mids": -27.5, + "upperMids": -29.1, + "highs": -22.0, + "brilliance": -14.0 + }, + { + "t": 12.95, + "subBass": -8.3, + "lowBass": -9.6, + "lowMids": -22.4, + "mids": -25.8, + "upperMids": -34.9, + "highs": -48.6, + "brilliance": -56.1 + }, + { + "t": 13.04, + "subBass": -10.5, + "lowBass": -7.3, + "lowMids": -24.0, + "mids": -28.5, + "upperMids": -37.0, + "highs": -48.2, + "brilliance": -52.0 + }, + { + "t": 13.13, + "subBass": -5.7, + "lowBass": -10.1, + "lowMids": -31.6, + "mids": -35.5, + "upperMids": -45.0, + "highs": -96.4, + "brilliance": -103.0 + }, + { + "t": 13.22, + "subBass": -6.9, + "lowBass": -18.1, + "lowMids": -26.3, + "mids": -29.8, + "upperMids": -41.0, + "highs": -80.2, + "brilliance": -82.8 + }, + { + "t": 13.32, + "subBass": -8.1, + "lowBass": -12.9, + "lowMids": -24.2, + "mids": -27.8, + "upperMids": -28.8, + "highs": -21.7, + "brilliance": -13.8 + }, + { + "t": 13.41, + "subBass": -7.8, + "lowBass": -10.6, + "lowMids": -23.1, + "mids": -26.7, + "upperMids": -37.3, + "highs": -43.5, + "brilliance": -35.5 + }, + { + "t": 13.5, + "subBass": -9.2, + "lowBass": -9.7, + "lowMids": -22.9, + "mids": -26.6, + "upperMids": -37.3, + "highs": -51.1, + "brilliance": -53.3 + }, + { + "t": 13.6, + "subBass": -5.2, + "lowBass": -5.9, + "lowMids": -29.3, + "mids": -34.3, + "upperMids": -45.0, + "highs": -56.7, + "brilliance": -58.9 + }, + { + "t": 13.69, + "subBass": -6.8, + "lowBass": -16.0, + "lowMids": -26.7, + "mids": -30.2, + "upperMids": -39.3, + "highs": -54.5, + "brilliance": -87.6 + }, + { + "t": 13.78, + "subBass": -7.9, + "lowBass": -14.5, + "lowMids": -25.4, + "mids": -28.4, + "upperMids": -29.1, + "highs": -21.8, + "brilliance": -14.1 + }, + { + "t": 13.87, + "subBass": -7.3, + "lowBass": -13.0, + "lowMids": -25.8, + "mids": -26.6, + "upperMids": -34.6, + "highs": -30.9, + "brilliance": -23.2 + }, + { + "t": 13.97, + "subBass": -9.2, + "lowBass": -12.8, + "lowMids": -33.4, + "mids": -20.5, + "upperMids": -32.4, + "highs": -45.8, + "brilliance": -57.9 + }, + { + "t": 14.06, + "subBass": -5.7, + "lowBass": -5.6, + "lowMids": -29.3, + "mids": -30.4, + "upperMids": -38.9, + "highs": -46.6, + "brilliance": -50.0 + }, + { + "t": 14.15, + "subBass": -5.8, + "lowBass": -16.3, + "lowMids": -35.0, + "mids": -27.1, + "upperMids": -38.7, + "highs": -52.7, + "brilliance": -80.5 + }, + { + "t": 14.25, + "subBass": -8.2, + "lowBass": -14.1, + "lowMids": -28.8, + "mids": -27.0, + "upperMids": -30.5, + "highs": -23.3, + "brilliance": -15.7 + }, + { + "t": 14.34, + "subBass": -7.6, + "lowBass": -10.2, + "lowMids": -24.7, + "mids": -28.5, + "upperMids": -32.0, + "highs": -25.7, + "brilliance": -17.8 + }, + { + "t": 14.43, + "subBass": -9.6, + "lowBass": -9.6, + "lowMids": -21.1, + "mids": -25.0, + "upperMids": -34.9, + "highs": -56.5, + "brilliance": -58.6 + }, + { + "t": 14.52, + "subBass": -8.8, + "lowBass": -6.3, + "lowMids": -26.1, + "mids": -30.3, + "upperMids": -38.8, + "highs": -46.5, + "brilliance": -49.3 + }, + { + "t": 14.62, + "subBass": -5.4, + "lowBass": -17.5, + "lowMids": -29.2, + "mids": -32.9, + "upperMids": -43.0, + "highs": -80.8, + "brilliance": -84.4 + }, + { + "t": 14.71, + "subBass": -7.7, + "lowBass": -17.3, + "lowMids": -27.7, + "mids": -31.0, + "upperMids": -39.8, + "highs": -37.1, + "brilliance": -30.2 + }, + { + "t": 14.8, + "subBass": -7.8, + "lowBass": -11.3, + "lowMids": -34.7, + "mids": -22.5, + "upperMids": -28.7, + "highs": -21.7, + "brilliance": -13.9 + }, + { + "t": 14.9, + "subBass": -8.3, + "lowBass": -10.3, + "lowMids": -21.7, + "mids": -24.6, + "upperMids": -35.8, + "highs": -54.2, + "brilliance": -57.8 + }, + { + "t": 14.99, + "subBass": -9.2, + "lowBass": -6.0, + "lowMids": -25.4, + "mids": -28.9, + "upperMids": -38.4, + "highs": -52.6, + "brilliance": -56.2 + }, + { + "t": 15.08, + "subBass": -4.8, + "lowBass": -10.7, + "lowMids": -31.2, + "mids": -34.4, + "upperMids": -43.6, + "highs": -60.6, + "brilliance": -77.9 + }, + { + "t": 15.17, + "subBass": -6.7, + "lowBass": -14.3, + "lowMids": -26.7, + "mids": -31.1, + "upperMids": -39.0, + "highs": -80.4, + "brilliance": -102.1 + }, + { + "t": 15.27, + "subBass": -8.2, + "lowBass": -14.1, + "lowMids": -24.2, + "mids": -27.2, + "upperMids": -29.4, + "highs": -22.0, + "brilliance": -14.1 + }, + { + "t": 15.36, + "subBass": -7.8, + "lowBass": -12.9, + "lowMids": -22.2, + "mids": -25.8, + "upperMids": -35.0, + "highs": -49.3, + "brilliance": -57.6 + }, + { + "t": 15.45, + "subBass": -10.0, + "lowBass": -13.4, + "lowMids": -24.5, + "mids": -28.3, + "upperMids": -36.8, + "highs": -47.3, + "brilliance": -50.9 + } + ], + "spectralDetail": { + "spectralCentroid": 1148.1, + "spectralRolloff": 1677.5, + "spectralBandwidth": 2643.1, + "spectralFlatness": 0.107122, + "mfcc": [ + -764.5244, + 203.8301, + -12.2344, + 56.4163, + 42.0563, + 10.6997, + 29.5699, + 17.5319, + 14.5765, + 16.6998, + 16.2752, + 17.3365, + 16.126 + ], + "chroma": [ + 0.1988, + 0.2634, + 0.1068, + 0.2444, + 0.0747, + 0.2566, + 0.08, + 0.2818, + 0.3506, + 0.1078, + 0.2482, + 0.1111 + ], + "barkBands": [ + -22.9571, + -7.4274, + -15.4446, + -22.6396, + -30.083, + -28.3398, + -29.4341, + -32.6115, + -36.8247, + -36.4261, + -34.7167, + -40.3981, + -38.7364, + -40.6703, + -40.8036, + -43.0025, + -41.6388, + -41.9653, + -41.9073, + -42.087, + -39.3993, + -36.2175, + -36.2371, + -32.1737 + ], + "erbBands": [ + 10.8446, + 16.9718, + 15.8932, + 12.8925, + 7.1101, + 4.1269, + 9.6272, + 11.0687, + 12.4713, + 12.1965, + 7.7012, + 7.7139, + 7.943, + 10.6902, + 9.3114, + 6.4907, + 8.3929, + 7.5174, + 5.8268, + 5.8367, + 5.5408, + 4.9451, + 5.5217, + 5.3436, + 4.231, + 5.091, + 6.2019, + 7.1143, + 8.6863, + 9.3398, + 8.7155, + 10.9092, + 9.8659, + 10.256, + 9.5563, + 9.4228, + 7.4174, + 3.657, + -2.3395, + -11.9018 + ], + "spectralContrast": [ + -0.2329, + -0.5871, + -0.6353, + -0.6761, + -0.694, + -0.7623 + ], + "spectralValley": [ + -6.1313, + -7.3474, + -8.2775, + -8.8268, + -9.8302, + -13.0403 + ] + }, + "stemAnalysis": null, + "transientDensityDetail": { + "subBass": { + "onsetRatePerSecond": 15.56, + "meanOnsetStrength": 0.307, + "peakOnsetStrength": 0.573, + "eventCount": 241 + }, + "lowBass": { + "onsetRatePerSecond": 9.17, + "meanOnsetStrength": 0.544, + "peakOnsetStrength": 1.46, + "eventCount": 142 + }, + "lowMids": { + "onsetRatePerSecond": 9.56, + "meanOnsetStrength": 0.864, + "peakOnsetStrength": 1.975, + "eventCount": 148 + }, + "mids": { + "onsetRatePerSecond": 9.75, + "meanOnsetStrength": 4.144, + "peakOnsetStrength": 7.706, + "eventCount": 151 + }, + "upperMids": { + "onsetRatePerSecond": 9.75, + "meanOnsetStrength": 4.477, + "peakOnsetStrength": 11.12, + "eventCount": 151 + }, + "highs": { + "onsetRatePerSecond": 10.2, + "meanOnsetStrength": 5.389, + "peakOnsetStrength": 16.011, + "eventCount": 158 + }, + "brilliance": { + "onsetRatePerSecond": 9.3, + "meanOnsetStrength": 5.658, + "peakOnsetStrength": 15.515, + "eventCount": 144 + } + }, + "saturationDetail": { + "clippedSampleCount": 0, + "clippedSamplePercent": 0.0, + "nearClippedSampleCount": 0, + "nearClippedSamplePercent": 0.0, + "peakRatio95to50": 2.217, + "rmsToPeakRatioDb": 10.81, + "saturationLikely": false + }, + "snareDetail": { + "hitCount": 59, + "hitsPerSecond": 3.81, + "meanAttackSharpness": 0.0026, + "meanBodyEnergyRatio": 0.918, + "meanSnapEnergyRatio": 0.082, + "meanCentroidHz": 573.5, + "meanDecayFrames": 48.2, + "meanDecaySeconds": 0.28, + "bandHz": [ + 120.0, + 2000.0 + ] + }, + "hihatDetail": { + "hitCount": 32, + "hitsPerSecond": 2.07, + "meanAttackSharpness": 0.0027, + "meanBodyEnergyRatio": 0.162, + "meanSnapEnergyRatio": 0.838, + "meanCentroidHz": 7957.5, + "meanDecayFrames": 8.1, + "meanDecaySeconds": 0.047, + "bandHz": [ + 2000.0, + 12000.0 + ] + }, + "rhythmDetail": { + "onsetRate": 2.07, + "beatGrid": [ + 0.372, + 0.766, + 1.207, + 1.683, + 2.171, + 2.659, + 3.146, + 3.622, + 4.11, + 4.586, + 5.074, + 5.561, + 6.049, + 6.525, + 7.012, + 7.5, + 7.976, + 8.464, + 8.951, + 9.427, + 9.915, + 10.403, + 10.879, + 11.366, + 11.854, + 12.33, + 12.817, + 13.305, + 13.781, + 14.269, + 14.756, + 15.232 + ], + "downbeats": [ + 1.207, + 3.146, + 5.074, + 7.012, + 8.951, + 10.879, + 12.817, + 14.756 + ], + "beatPositions": [ + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2 + ], + "downbeatSource": "kick_accent", + "downbeatConfidence": 0.0978, + "grooveAmount": 0.0375, + "tempoStability": 0.9625, + "phraseGrid": { + "phrases4Bar": [ + 1.207, + 8.951 + ], + "phrases8Bar": [ + 1.207 + ], + "phrases16Bar": [ + 1.207 + ], + "totalBars": 8, + "totalPhrases8Bar": 1 + }, + "tempoCurve": [ + { + "t": 0.57, + "bpm": 136.0 + }, + { + "t": 0.99, + "bpm": 131.0 + }, + { + "t": 1.45, + "bpm": 126.0 + }, + { + "t": 1.93, + "bpm": 123.0 + }, + { + "t": 2.41, + "bpm": 123.0 + }, + { + "t": 2.9, + "bpm": 123.0 + }, + { + "t": 3.38, + "bpm": 123.0 + }, + { + "t": 3.87, + "bpm": 123.0 + }, + { + "t": 4.35, + "bpm": 123.0 + }, + { + "t": 4.83, + "bpm": 123.0 + }, + { + "t": 5.32, + "bpm": 123.0 + }, + { + "t": 5.8, + "bpm": 123.0 + }, + { + "t": 6.29, + "bpm": 123.0 + }, + { + "t": 6.77, + "bpm": 123.0 + }, + { + "t": 7.26, + "bpm": 123.0 + }, + { + "t": 7.74, + "bpm": 123.0 + }, + { + "t": 8.22, + "bpm": 123.0 + }, + { + "t": 8.71, + "bpm": 123.0 + }, + { + "t": 9.19, + "bpm": 123.0 + }, + { + "t": 9.67, + "bpm": 123.0 + }, + { + "t": 10.16, + "bpm": 123.0 + }, + { + "t": 10.64, + "bpm": 123.0 + }, + { + "t": 11.12, + "bpm": 123.0 + }, + { + "t": 11.61, + "bpm": 123.0 + }, + { + "t": 12.09, + "bpm": 123.0 + }, + { + "t": 12.57, + "bpm": 123.0 + }, + { + "t": 13.06, + "bpm": 123.0 + }, + { + "t": 13.54, + "bpm": 123.0 + }, + { + "t": 14.02, + "bpm": 123.0 + }, + { + "t": 14.51, + "bpm": 124.5 + }, + { + "t": 14.99, + "bpm": 123.0 + } + ] + }, + "melodyDetail": { + "noteCount": 17, + "notes": [ + { + "midi": 72, + "onset": 0.845, + "duration": 0.102 + }, + { + "midi": 64, + "onset": 1.692, + "duration": 0.113 + }, + { + "midi": 65, + "onset": 1.811, + "duration": 0.096 + }, + { + "midi": 62, + "onset": 2.183, + "duration": 0.2 + }, + { + "midi": 41, + "onset": 2.656, + "duration": 0.238 + }, + { + "midi": 41, + "onset": 4.107, + "duration": 0.241 + }, + { + "midi": 41, + "onset": 5.564, + "duration": 0.235 + }, + { + "midi": 41, + "onset": 7.004, + "duration": 0.247 + }, + { + "midi": 41, + "onset": 8.458, + "duration": 0.244 + }, + { + "midi": 69, + "onset": 9.805, + "duration": 0.113 + }, + { + "midi": 70, + "onset": 9.924, + "duration": 0.203 + }, + { + "midi": 69, + "onset": 10.286, + "duration": 0.197 + }, + { + "midi": 67, + "onset": 11.006, + "duration": 0.104 + }, + { + "midi": 69, + "onset": 12.222, + "duration": 0.116 + }, + { + "midi": 70, + "onset": 12.344, + "duration": 0.215 + }, + { + "midi": 72, + "onset": 13.909, + "duration": 0.102 + }, + { + "midi": 70, + "onset": 15.36, + "duration": 0.104 + } + ], + "dominantNotes": [ + 41, + 69, + 70, + 72, + 64 + ], + "pitchRange": { + "min": 41, + "max": 72 + }, + "pitchConfidence": 0.0084, + "midiFile": "/Users/christiansmith/code/projects/asa/.claude/worktrees/goal-doc/apps/backend/tests/fixtures/recommendation_tracks/melodic_techno_arp_124/audio_melody.mid", + "sourceSeparated": false, + "vibratoPresent": false, + "vibratoExtent": 0.0, + "vibratoRate": 0.0, + "vibratoConfidence": 0.0 + }, + "transcriptionDetail": null, + "pitchDetail": null, + "grooveDetail": { + "kickSwing": 0.1838, + "hihatSwing": 0.5172, + "kickAccent": [ + 0.2144, + 0.2087, + 0.0802, + 0.2391, + 0.2175, + 0.0876, + 0.2493, + 0.2268, + 0.168, + 0.2475, + 0.2168, + 0.1749, + 0.2142, + 0.2333, + 0.0982, + 0.1542 + ], + "hihatAccent": [ + 0.0001, + 0.0795, + 0.0854, + 0.0604, + 0.056, + 0.0746, + 0.0555, + 0.0601, + 0.055, + 0.0498, + 0.0786, + 0.0545, + 0.071, + 0.067, + 0.074, + 0.0607 + ], + "perDrumSwing": { + "kick": 0.1838, + "snare": 0.1466, + "hihat": 0.5172 + } + }, + "beatsLoudness": { + "kickDominantRatio": 0.7267, + "midDominantRatio": 0.0001, + "highDominantRatio": 0.2332, + "patternBeatsPerBar": 4, + "lowBandAccentPattern": [ + 0.8743, + 0.8548, + 1.0, + 0.9022 + ], + "midBandAccentPattern": [ + 0.908, + 0.5829, + 0.8442, + 1.0 + ], + "highBandAccentPattern": [ + 0.9495, + 0.9929, + 1.0, + 0.9388 + ], + "overallAccentPattern": [ + 0.8992, + 0.8911, + 1.0, + 0.9143 + ], + "accentPattern": [ + 0.8992, + 0.8911, + 1.0, + 0.9143 + ], + "meanBeatLoudness": 0.2605, + "beatLoudnessVariation": 0.1787, + "beatCount": 32 + }, + "rhythmTimeline": { + "beatsPerBar": 4, + "stepsPerBeat": 4, + "availableBars": 8, + "selectionMethod": "representative_dsp_window", + "windows": [ + { + "bars": 8, + "startBar": 1, + "endBar": 8, + "lowBandSteps": [ + 0.1994, + 0.7656, + 0.36, + 0.2511, + 0.3053, + 0.2377, + 0.6535, + 0.3505, + 0.3641, + 0.2867, + 0.5771, + 0.4315, + 0.3812, + 0.3244, + 0.9737, + 0.4489, + 0.3817, + 0.2757, + 0.9399, + 0.4409, + 0.3818, + 0.2985, + 0.5926, + 0.4328, + 0.3641, + 0.2943, + 0.8809, + 0.4254, + 0.3816, + 0.2769, + 0.9477, + 0.4416, + 0.3641, + 0.2893, + 0.5712, + 0.4329, + 0.3812, + 0.325, + 0.977, + 0.4505, + 0.3816, + 0.278, + 0.9552, + 0.4423, + 0.3818, + 0.3007, + 0.5886, + 0.4343, + 0.3639, + 0.2948, + 0.8824, + 0.4268, + 0.3819, + 0.279, + 0.9639, + 0.443, + 0.3818, + 0.3019, + 0.5874, + 0.435, + 0.3641, + 0.2948, + 0.883, + 0.4275, + 0.382, + 0.2801, + 0.9713, + 0.4438, + 0.3819, + 0.3029, + 0.5868, + 0.4357, + 0.3641, + 0.2949, + 0.8826, + 0.4283, + 0.3819, + 0.281, + 0.9791, + 0.4446, + 0.3819, + 0.3042, + 0.5869, + 0.4364, + 0.3641, + 0.2948, + 0.8827, + 0.429, + 0.3819, + 0.2823, + 0.9861, + 0.4453, + 0.3819, + 0.3052, + 0.5877, + 0.4371, + 0.3641, + 0.2948, + 0.8825, + 0.4297, + 0.3819, + 0.284, + 0.9927, + 0.446, + 0.3818, + 0.3063, + 0.5882, + 0.4378, + 0.3641, + 0.2948, + 0.8811, + 0.4304, + 0.3819, + 0.2852, + 1.0, + 0.4468, + 0.3818, + 0.3074, + 0.5901, + 0.4386, + 0.364, + 0.2945, + 0.879, + 0.4312, + 0.0699, + 0.1302, + 0.0637, + 0.0758 + ], + "midBandSteps": [ + 0.5187, + 0.1249, + 0.239, + 0.2362, + 0.2324, + 0.3988, + 0.0724, + 0.2072, + 0.4675, + 0.8873, + 0.1108, + 0.2742, + 0.5899, + 1.0, + 0.1354, + 0.2882, + 0.5585, + 0.9651, + 0.1146, + 0.2645, + 0.4982, + 0.8107, + 0.1026, + 0.2618, + 0.4718, + 0.7627, + 0.1294, + 0.2753, + 0.5604, + 0.8827, + 0.1154, + 0.2843, + 0.5143, + 0.896, + 0.107, + 0.2916, + 0.5845, + 0.9642, + 0.1523, + 0.2803, + 0.5623, + 0.9217, + 0.1209, + 0.2745, + 0.5352, + 0.7762, + 0.1034, + 0.2448, + 0.4909, + 0.7481, + 0.1258, + 0.2716, + 0.5114, + 0.9149, + 0.1206, + 0.282, + 0.5306, + 0.7868, + 0.11, + 0.2598, + 0.4872, + 0.8703, + 0.1257, + 0.2668, + 0.5523, + 0.8539, + 0.1265, + 0.2708, + 0.5054, + 0.7964, + 0.11, + 0.27, + 0.4632, + 0.8241, + 0.1158, + 0.2731, + 0.5688, + 0.9867, + 0.1231, + 0.2716, + 0.5072, + 0.8064, + 0.1127, + 0.2563, + 0.465, + 0.786, + 0.1246, + 0.2649, + 0.5459, + 0.9342, + 0.125, + 0.2777, + 0.492, + 0.8171, + 0.1184, + 0.2684, + 0.4829, + 0.7918, + 0.138, + 0.2689, + 0.5408, + 0.8907, + 0.1209, + 0.2853, + 0.5217, + 0.8273, + 0.1092, + 0.2692, + 0.4847, + 0.8745, + 0.129, + 0.2663, + 0.5495, + 0.8927, + 0.1268, + 0.264, + 0.5395, + 0.8793, + 0.1066, + 0.27, + 0.4529, + 0.8719, + 0.1211, + 0.2703, + 0.2318, + 0.0747, + 0.354, + 0.1021 + ], + "highBandSteps": [ + 0.0016, + 0.0, + 0.0, + 0.9129, + 0.0041, + 0.0012, + 0.0, + 0.0, + 0.6209, + 0.0002, + 0.0, + 0.0006, + 0.9709, + 0.0004, + 0.0001, + 0.0002, + 0.7837, + 0.0003, + 0.0003, + 0.0005, + 0.6151, + 0.0007, + 0.0002, + 0.0, + 0.4937, + 0.0017, + 0.0, + 0.0, + 0.7959, + 0.0008, + 0.0003, + 0.0, + 0.6395, + 0.0003, + 0.0003, + 0.0, + 1.0, + 0.0004, + 0.0, + 0.0006, + 0.8082, + 0.0003, + 0.0001, + 0.0002, + 0.634, + 0.0024, + 0.0002, + 0.0007, + 0.5099, + 0.0017, + 0.0, + 0.0002, + 0.8205, + 0.0003, + 0.0002, + 0.0, + 0.6434, + 0.0026, + 0.0, + 0.0002, + 0.5176, + 0.0003, + 0.0, + 0.0003, + 0.8351, + 0.0021, + 0.0, + 0.0003, + 0.6558, + 0.0025, + 0.0, + 0.0, + 0.5278, + 0.0008, + 0.0003, + 0.0002, + 0.85, + 0.0003, + 0.0001, + 0.0003, + 0.6662, + 0.0019, + 0.0, + 0.0003, + 0.5366, + 0.0003, + 0.0, + 0.0005, + 0.8572, + 0.0008, + 0.0001, + 0.0002, + 0.6767, + 0.0019, + 0.0, + 0.0, + 0.5461, + 0.0018, + 0.0, + 0.0003, + 0.8716, + 0.002, + 0.0003, + 0.0, + 0.6864, + 0.0019, + 0.0, + 0.0, + 0.5551, + 0.0003, + 0.0, + 0.0005, + 0.8829, + 0.0029, + 0.0002, + 0.0008, + 0.6961, + 0.0007, + 0.0001, + 0.0, + 0.5636, + 0.0003, + 0.0002, + 0.0003, + 0.8322, + 0.0, + 0.0008, + 0.0002 + ], + "overallSteps": [ + 0.2117, + 0.7663, + 0.3648, + 0.3152, + 0.3104, + 0.2468, + 0.6532, + 0.3545, + 0.4147, + 0.3077, + 0.578, + 0.4369, + 0.4574, + 0.3481, + 0.974, + 0.4547, + 0.445, + 0.2987, + 0.9398, + 0.4461, + 0.4327, + 0.3176, + 0.5932, + 0.4379, + 0.4066, + 0.3123, + 0.8813, + 0.4308, + 0.4458, + 0.2978, + 0.9475, + 0.4472, + 0.417, + 0.3105, + 0.5721, + 0.4387, + 0.4591, + 0.3478, + 0.9777, + 0.456, + 0.4466, + 0.2999, + 0.9552, + 0.4477, + 0.4348, + 0.319, + 0.5894, + 0.439, + 0.4079, + 0.3124, + 0.8828, + 0.4322, + 0.4465, + 0.3007, + 0.9638, + 0.4486, + 0.4354, + 0.3205, + 0.5883, + 0.4401, + 0.4085, + 0.3154, + 0.8833, + 0.4328, + 0.4484, + 0.3004, + 0.9713, + 0.4491, + 0.4356, + 0.3218, + 0.5877, + 0.4409, + 0.4086, + 0.3143, + 0.8827, + 0.4337, + 0.4497, + 0.3044, + 0.9791, + 0.4499, + 0.4363, + 0.3232, + 0.5878, + 0.4414, + 0.4092, + 0.3133, + 0.883, + 0.4342, + 0.4497, + 0.3045, + 0.9861, + 0.4507, + 0.4367, + 0.3246, + 0.5888, + 0.4424, + 0.4102, + 0.3136, + 0.8831, + 0.435, + 0.4505, + 0.3052, + 0.9926, + 0.4516, + 0.4379, + 0.3259, + 0.589, + 0.4431, + 0.4108, + 0.3154, + 0.8815, + 0.4357, + 0.4514, + 0.3065, + 1.0, + 0.452, + 0.439, + 0.3282, + 0.5909, + 0.4439, + 0.4105, + 0.3151, + 0.8793, + 0.4365, + 0.1293, + 0.1316, + 0.0723, + 0.0781 + ] + } + ] + }, + "sidechainDetail": { + "pumpingStrength": 0.1767, + "pumpingRegularity": 0.0, + "pumpingRate": null, + "pumpingConfidence": 0.155, + "envelopeShape": [ + 0.763, + 0.612, + 0.997, + 0.724, + 0.761, + 0.615, + 1.0, + 0.739, + 0.765, + 0.614, + 0.997, + 0.736, + 0.761, + 0.617, + 0.997, + 0.738 + ], + "envelopeShape32": [ + 0.763, + 0.61, + 0.612, + 0.546, + 0.997, + 0.829, + 0.724, + 0.62, + 0.761, + 0.612, + 0.615, + 0.545, + 1.0, + 0.832, + 0.739, + 0.599, + 0.765, + 0.614, + 0.614, + 0.544, + 0.997, + 0.826, + 0.736, + 0.606, + 0.761, + 0.616, + 0.617, + 0.544, + 0.997, + 0.841, + 0.738, + 0.602 + ] + }, + "acidDetail": { + "isAcid": true, + "confidence": 0.72, + "resonanceLevel": 1.0, + "centroidOscillationHz": 42, + "bassRhythmDensity": 3.2 + }, + "reverbDetail": { + "rt60": null, + "isWet": false, + "tailEnergyRatio": null, + "measured": false, + "perBandRt60": null, + "preDelayMs": null + }, + "vocalDetail": { + "hasVocals": false, + "confidence": 0.35, + "vocalEnergyRatio": 0.04, + "formantStrength": 0.25, + "mfccLikelihood": 0.87, + "stemEnergyRatio": null, + "stemOtherCorrelation": null + }, + "supersawDetail": { + "isSupersaw": true, + "confidence": 0.87, + "voiceCount": 7, + "avgDetuneCents": 27.4, + "spectralComplexity": 7.4 + }, + "bassDetail": { + "averageDecayMs": 1000, + "type": "sustained", + "transientRatio": 0.2, + "fundamentalHz": 79, + "transientCount": 0, + "swingPercent": 0, + "grooveType": "straight" + }, + "kickDetail": { + "isDistorted": true, + "thd": 0.29, + "harmonicRatio": 0.95, + "fundamentalHz": 65, + "kickCount": 118 + }, + "genreDetail": { + "genre": "dub-techno", + "confidence": 0.9014, + "secondaryGenre": "ambient", + "genreFamily": "techno", + "topScores": [ + { + "genre": "dub-techno", + "score": 0.8355 + }, + { + "genre": "ambient", + "score": 0.7566 + }, + { + "genre": "hiphop", + "score": 0.7551 + }, + { + "genre": "ambient-techno", + "score": 0.7319 + }, + { + "genre": "dubstep", + "score": 0.6886 + } + ] + }, + "effectsDetail": { + "gatingDetected": false, + "gatingRate": null, + "gatingRegularity": 0.0, + "gatingEventCount": 1 + }, + "synthesisCharacter": { + "inharmonicity": 0.0231, + "oddToEvenRatio": 1.2038 + }, + "danceability": { + "danceability": 5.035, + "dfa": 0.1986 + }, + "structure": { + "segments": [ + { + "start": 0.0, + "end": 15.484, + "index": 0 + } + ], + "segmentCount": 1 + }, + "arrangementDetail": { + "noveltyCurve": [ + 0.0, + 0.0, + 0.0002, + 0.0005, + 0.1534, + 0.5997, + 0.2982, + 0.0393, + 0.0202, + 0.0006, + 0.0003, + 0.0002, + 0.0782, + 0.245, + 0.122, + 0.0378, + 0.0173, + 0.0012, + 0.0005, + 0.0003, + 0.1047, + 0.2576, + 0.0794, + 0.0109, + 0.0052, + 0.0001, + 0.0003, + 0.001, + 0.2572, + 0.5289, + 0.1334, + 0.0057, + 0.0029, + 0.0001, + 0.0004, + 0.0012, + 0.3506, + 0.777, + 0.219, + 0.0057, + 0.0027, + 0.0016, + 0.0009, + 0.0009, + 0.222, + 0.938, + 0.242, + 0.0162, + 0.0052, + 0.0024, + 0.0009, + 0.0005, + 0.1466, + 0.578, + 0.1517, + 0.0355, + 0.0092, + 0.0004, + 0.0002, + 0.0002, + 0.0555, + 0.1918, + 0.0916, + 0.0391, + 0.0093, + 0.002, + 0.0007, + 0.0002, + 0.0706, + 0.1779, + 0.0622, + 0.011, + 0.0024, + 0.0003, + 0.0003, + 0.0004, + 0.3199, + 0.5436, + 0.1753, + 0.0067, + 0.0029, + 0.0001, + 0.0008, + 0.0014, + 0.3546, + 0.6182, + 0.2229, + 0.0065, + 0.0038, + 0.0027, + 0.0005, + 0.0008, + 0.4042, + 0.8004, + 0.2046, + 0.0147, + 0.0062, + 0.0024, + 0.0011, + 0.0008, + 0.286, + 0.5586, + 0.1514, + 0.0296, + 0.0099, + 0.0004, + 0.0003, + 0.0003, + 0.1227, + 0.2092, + 0.0327, + 0.0189, + 0.0056, + 0.0031, + 0.0012, + 0.0002, + 0.0578, + 0.1514, + 0.0122, + 0.0221, + 0.0053, + 0.0005, + 0.0006, + 0.0005, + 0.2642, + 0.4555, + 0.0034, + 0.0063, + 0.0011, + 0.0001, + 0.0009, + 0.001, + 0.3864, + 0.6901, + 0.2515, + 0.0146, + 0.0015, + 0.0014, + 0.0007, + 0.0008, + 0.4681, + 0.7311, + 0.2456, + 0.0111, + 0.0015, + 0.0016, + 0.0002, + 0.0004, + 0.416, + 0.6267, + 0.219, + 0.024, + 0.0081, + 0.0005, + 0.0003, + 0.0003, + 0.177, + 0.2354, + 0.0647, + 0.0137, + 0.0055, + 0.0029, + 0.0004, + 0.0004, + 0.1245, + 0.1853, + 0.0135, + 0.0144, + 0.0043, + 0.0004, + 0.0006, + 0.0005, + 0.4076, + 0.491, + 0.0044, + 0.0056, + 0.0012, + 0.0, + 0.0008, + 0.0009, + 0.5824, + 0.6519, + 0.0082, + 0.0127, + 0.0017, + 0.001, + 0.0006, + 0.0007, + 0.7511, + 0.7446, + 0.0088, + 0.0099, + 0.0014, + 0.0011, + 0.0003, + 0.0004, + 0.4042, + 0.6045, + 0.0225, + 0.023, + 0.0004, + 0.0005, + 0.0003, + 0.0002, + 0.1981, + 0.2827, + 0.0252, + 0.0233, + 0.0064, + 0.0075, + 0.0002, + 0.0032, + 0.1207, + 0.1257, + 0.0174, + 0.02, + 0.0006, + 0.0007, + 0.0002, + 0.0002, + 0.3663, + 0.2801, + 0.0039, + 0.0055, + 0.0001, + 0.0001, + 0.0011, + 0.0009, + 0.5471, + 0.4342, + 0.0117, + 0.0137, + 0.0033, + 0.0021, + 0.0009, + 0.0007, + 0.7539, + 0.7517, + 0.0069, + 0.0062, + 0.003, + 0.0026, + 0.0005, + 0.0004, + 0.6235, + 0.6128, + 0.0078, + 0.0062, + 0.0034, + 0.0027, + 0.0002, + 0.0002, + 0.2268, + 0.2194, + 0.0352, + 0.0204 + ], + "noveltyPeaks": [ + { + "time": 0.302, + "strength": 0.5997 + }, + { + "time": 2.717, + "strength": 0.938 + }, + { + "time": 5.619, + "strength": 0.8004 + }, + { + "time": 8.522, + "strength": 0.953 + }, + { + "time": 11.424, + "strength": 0.9945 + }, + { + "time": 14.327, + "strength": 1.0 + } + ], + "noveltyMean": 0.1145, + "noveltyStdDev": 0.2031 + }, + "segmentLoudness": [ + { + "segmentIndex": 0, + "start": 0.0, + "end": 15.484, + "lufs": -10.5, + "lra": 0.2 + } + ], + "segmentSpectral": [ + { + "segmentIndex": 0, + "barkBands": [ + -22.9571, + -7.4274, + -15.4446, + -22.6396, + -30.083, + -28.3398, + -29.4341, + -32.6115, + -36.8247, + -36.4261, + -34.7167, + -40.3981, + -38.7364, + -40.6703, + -40.8036, + -43.0025, + -41.6388, + -41.9653, + -41.9073, + -42.087, + -39.3993, + -36.2175, + -36.2371, + -32.1737 + ], + "spectralCentroid": 1148.1, + "spectralRolloff": 1677.5, + "stereoWidth": 0.0, + "stereoCorrelation": 1.0 + } + ], + "segmentStereo": [ + { + "segmentIndex": 0, + "stereoWidth": 0.0, + "stereoCorrelation": 1.0 + } + ], + "segmentKey": [ + { + "segmentIndex": 0, + "key": "G Minor", + "keyConfidence": 0.71 + } + ], + "chordDetail": { + "chordSequence": [ + "C", + "C", + "C", + "Bb", + "Bb", + "Bb", + "Gm", + "Bb", + "Dm", + "Dm", + "Dm", + "Bb", + "Bb", + "Bb", + "Bb", + "Dm", + "Dm", + "Dm", + "Dm", + "Dm", + "Bb", + "Dm", + "Bb", + "Bb", + "Bb", + "Bb", + "Bb", + "Bb", + "C", + "Am", + "C", + "Am" + ], + "chordStrength": 0.6102, + "progression": [ + "C", + "Bb", + "Gm", + "Bb", + "Dm", + "Bb", + "Dm", + "Gm", + "Dm", + "Bb", + "Dm", + "Bb", + "C", + "Bb", + "Dm", + "Bb" + ], + "dominantChords": [ + "Bb", + "Dm", + "C", + "Gm" + ], + "chordTimeline": [ + { + "startSec": 0.0, + "endSec": 15.511, + "label": "Em", + "labelLong": "E minor", + "confidence": 0.5666 + } + ], + "chordChangeCount": 0, + "chordTimelineSource": "librosa_viterbi", + "chordTimelineAgreement": false + }, + "perceptual": { + "sharpness": 0.0628, + "roughness": 0.0 + }, + "essentiaFeatures": { + "zeroCrossingRate": 0.0358, + "hfc": 159.1022, + "spectralComplexity": 8.0614, + "dissonance": 0.0 + } +} \ No newline at end of file diff --git a/apps/backend/tests/fixtures/recommendation_tracks/techno_rumble_130/README.md b/apps/backend/tests/fixtures/recommendation_tracks/techno_rumble_130/README.md new file mode 100644 index 00000000..35699def --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/techno_rumble_130/README.md @@ -0,0 +1,34 @@ +# techno_rumble_130 + +**Genre:** techno · **Tempo:** 130 BPM · **Key:** F minor · **Render:** 48 kHz / 24-bit, 16 s loop + +## What this fixture isolates + +A dark, driving techno loop centered on the "rumble" technique: + +1. **Sine kick** with a lowpassed body (`Operator`, Filter 120 Hz, 300 ms decay). +2. **The rumble** — the kick fed through a long `Reverb` (3.0 s decay, 40 % wet) + on a return, summed with a held sub `Operator`. This is the defining techno + low-end move; recovering it means recommending a reverb-on-kick send plus a + sustained sub, not just "a bass." +3. **Bandpass stab** (`Wavetable`, BP @ 1.2 kHz, no sustain) for the mid. +4. **Saturated bass drive** (`Saturator`, 8 dB) and a **mono'd low end** + (`Utility` Bass Mono) — the kind of stereo discipline techno needs. +5. **Master glue** (`Glue Compressor` 4:1) into `Limiter` (-0.3 dBFS). + +`measurableIntent` records a dark `spectralDetail.spectralCentroidMean` target so +a recommendation that achieves the right tonal balance by a different device path +still earns credit. + +Covers all seven production domains. + +## Answer key + +The exact device chain is in `manifest.json` → `deviceSpec`. Build it verbatim in +Live 12, render to `audio.flac`, then store `phase1_fingerprint.json`. + +## Status + +- [x] Catalog-valid spec authored +- [ ] **NEEDS-FIXTURE:** rendered `audio.flac` (owner builds + renders) +- [ ] **NEEDS-FIXTURE:** stored `phase1_fingerprint.json` diff --git a/apps/backend/tests/fixtures/recommendation_tracks/techno_rumble_130/audio_melody.mid b/apps/backend/tests/fixtures/recommendation_tracks/techno_rumble_130/audio_melody.mid new file mode 100644 index 00000000..bc392c28 Binary files /dev/null and b/apps/backend/tests/fixtures/recommendation_tracks/techno_rumble_130/audio_melody.mid differ diff --git a/apps/backend/tests/fixtures/recommendation_tracks/techno_rumble_130/manifest.json b/apps/backend/tests/fixtures/recommendation_tracks/techno_rumble_130/manifest.json new file mode 100644 index 00000000..7424d092 --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/techno_rumble_130/manifest.json @@ -0,0 +1,131 @@ +{ + "schemaVersion": "recommendation-fixture.v1", + "id": "techno_rumble_130", + "title": "Techno — sine kick, reverb-tail rumble bass, saturated", + "genre": "techno", + "audioPath": "audio.flac", + "phase1FingerprintPath": "phase1_fingerprint.json", + "phase1Fingerprint": null, + "render": { + "sampleRateHz": 48000, + "bitDepth": 24, + "lengthSeconds": 16, + "bpm": 130, + "key": "F minor", + "notes": "8-bar loop. The 'rumble' is the kick fed through Reverb on a return, summed with the sub. Render the full loop to one stereo file, no export normalization." + }, + "deviceSpec": { + "kick": [ + { + "device": "Operator", + "family": "NATIVE", + "role": "Sine kick", + "parameters": [ + { "name": "Oscillator A Waveform", "value": "Sine" }, + { "name": "Filter Type", "value": "Lowpass" }, + { "name": "Filter Frequency", "value": "120 Hz" }, + { "name": "Amp Envelope Decay", "value": "300 ms" }, + { "name": "Amp Envelope Release", "value": "80 ms" } + ] + } + ], + "bass": [ + { + "device": "Operator", + "family": "NATIVE", + "role": "Sub bass", + "parameters": [ + { "name": "Oscillator A Waveform", "value": "Sine" }, + { "name": "Filter Frequency", "value": "150 Hz" }, + { "name": "Amp Envelope Sustain", "value": "100%", "intent": "held sub, no decay" } + ] + } + ], + "melody": [ + { + "device": "Wavetable", + "family": "NATIVE", + "role": "Bandpass stab", + "parameters": [ + { "name": "Oscillator 1 Wavetable", "value": "Basic Shapes" }, + { "name": "Filter Type", "value": "Bandpass" }, + { "name": "Filter Frequency", "value": "1200 Hz" }, + { "name": "Amp Envelope Decay", "value": "200 ms" }, + { "name": "Amp Envelope Sustain", "value": "0%", "intent": "plucky stab, no sustain" } + ] + } + ], + "groove": [ + { + "device": "Drum Rack", + "family": "NATIVE", + "role": "Offbeat hats", + "parameters": [ + { "name": "Pad Volume", "value": "-10 dB" } + ] + } + ], + "fx": [ + { + "device": "Saturator", + "family": "NATIVE", + "role": "Bass drive", + "parameters": [ + { "name": "Drive", "value": "8 dB" }, + { "name": "Type", "value": "Soft Sine" }, + { "name": "Dry/Wet", "value": "100%" } + ] + }, + { + "device": "Reverb", + "family": "NATIVE", + "role": "Rumble tail on kick return", + "parameters": [ + { "name": "Decay Time", "value": "3.0 s" }, + { "name": "Dry/Wet", "value": "40%" } + ] + } + ], + "stereo": [ + { + "device": "Utility", + "family": "NATIVE", + "role": "Low-end mono / stab width", + "parameters": [ + { "name": "Bass Mono", "value": "On" }, + { "name": "Stereo Width", "value": "110%" } + ] + } + ], + "master": [ + { + "device": "Glue Compressor", + "family": "NATIVE", + "role": "Bus glue", + "parameters": [ + { "name": "Threshold", "value": "-16 dB" }, + { "name": "Ratio", "value": "4:1" }, + { "name": "Attack", "value": "3 ms" }, + { "name": "Release", "value": "Auto" }, + { "name": "Makeup", "value": "2 dB" } + ] + }, + { + "device": "Limiter", + "family": "NATIVE", + "role": "Master ceiling", + "parameters": [ + { "name": "Ceiling", "value": "-0.3 dB" } + ] + } + ] + }, + "measurableIntent": { + "bpm": { "target": 130, "tolerance": 1, "direction": "exact" }, + "key": { "target": "F minor" }, + "kickDetail.fundamentalHz": { "target": 50, "tolerance": 15, "unit": "Hz" }, + "lufsIntegrated": { "target": -8, "tolerance": 2, "unit": "LUFS" }, + "truePeak": { "target": 1.0, "tolerance": 0.05 }, + "spectralDetail.spectralCentroidMean": { "target": 1500, "tolerance": 600, "unit": "Hz", "intent": "dark techno spectrum" } + } +} diff --git a/apps/backend/tests/fixtures/recommendation_tracks/techno_rumble_130/phase1_fingerprint.json b/apps/backend/tests/fixtures/recommendation_tracks/techno_rumble_130/phase1_fingerprint.json new file mode 100644 index 00000000..c9237904 --- /dev/null +++ b/apps/backend/tests/fixtures/recommendation_tracks/techno_rumble_130/phase1_fingerprint.json @@ -0,0 +1,4729 @@ +{ + "_synthetic": true, + "_note": "Phase 1 of a numpy PROXY render, NOT an Ableton render. Replace with a real Live render's fingerprint for an authoritative verdict.", + "bpm": 130.0, + "bpmConfidence": 3.71, + "bpmPercival": 130.0, + "bpmAgreement": true, + "bpmDoubletime": false, + "bpmSource": "rhythm_extractor_confirmed", + "bpmRawOriginal": 130.0, + "key": "F Minor", + "keyConfidence": 0.59, + "keyProfile": "edma", + "tuningFrequency": 432.44, + "tuningCents": -30.0, + "timeSignature": "4/4", + "timeSignatureSource": "onset_autocorrelation_low_margin", + "timeSignatureConfidence": 0.0, + "durationSeconds": 14.8, + "sampleRate": 44100, + "lufsIntegrated": -9.0, + "lufsRange": 0.1, + "lufsMomentaryMax": -8.3, + "lufsShortTermMax": -8.9, + "lufsCurve": { + "shortTerm": [ + { + "t": 0.0, + "lufs": -8.9 + }, + { + "t": 0.1, + "lufs": -9.0 + }, + { + "t": 0.2, + "lufs": -9.0 + }, + { + "t": 0.3, + "lufs": -9.1 + }, + { + "t": 0.4, + "lufs": -9.1 + }, + { + "t": 0.5, + "lufs": -9.0 + }, + { + "t": 0.6, + "lufs": -9.0 + }, + { + "t": 0.7, + "lufs": -9.0 + }, + { + "t": 0.8, + "lufs": -9.1 + }, + { + "t": 0.9, + "lufs": -9.0 + }, + { + "t": 1.0, + "lufs": -9.0 + }, + { + "t": 1.1, + "lufs": -9.0 + }, + { + "t": 1.2, + "lufs": -9.0 + }, + { + "t": 1.3, + "lufs": -9.0 + }, + { + "t": 1.4, + "lufs": -8.9 + }, + { + "t": 1.5, + "lufs": -9.0 + }, + { + "t": 1.6, + "lufs": -9.0 + }, + { + "t": 1.7, + "lufs": -9.1 + }, + { + "t": 1.8, + "lufs": -9.1 + }, + { + "t": 1.9, + "lufs": -9.0 + }, + { + "t": 2.0, + "lufs": -9.0 + }, + { + "t": 2.1, + "lufs": -9.1 + }, + { + "t": 2.2, + "lufs": -9.1 + }, + { + "t": 2.3, + "lufs": -9.0 + }, + { + "t": 2.4, + "lufs": -9.0 + }, + { + "t": 2.5, + "lufs": -9.0 + }, + { + "t": 2.6, + "lufs": -9.0 + }, + { + "t": 2.7, + "lufs": -9.0 + }, + { + "t": 2.8, + "lufs": -8.9 + }, + { + "t": 2.9, + "lufs": -9.0 + }, + { + "t": 3.0, + "lufs": -9.0 + }, + { + "t": 3.1, + "lufs": -9.1 + }, + { + "t": 3.2, + "lufs": -9.1 + }, + { + "t": 3.3, + "lufs": -9.0 + }, + { + "t": 3.4, + "lufs": -9.0 + }, + { + "t": 3.5, + "lufs": -9.1 + }, + { + "t": 3.6, + "lufs": -9.1 + }, + { + "t": 3.7, + "lufs": -9.0 + }, + { + "t": 3.8, + "lufs": -9.0 + }, + { + "t": 3.9, + "lufs": -9.0 + }, + { + "t": 4.0, + "lufs": -9.0 + }, + { + "t": 4.1, + "lufs": -9.0 + }, + { + "t": 4.2, + "lufs": -9.0 + }, + { + "t": 4.3, + "lufs": -9.0 + }, + { + "t": 4.4, + "lufs": -9.1 + }, + { + "t": 4.5, + "lufs": -9.1 + }, + { + "t": 4.6, + "lufs": -9.1 + }, + { + "t": 4.7, + "lufs": -9.0 + }, + { + "t": 4.8, + "lufs": -9.0 + }, + { + "t": 4.9, + "lufs": -9.1 + }, + { + "t": 5.0, + "lufs": -9.1 + }, + { + "t": 5.1, + "lufs": -9.0 + }, + { + "t": 5.2, + "lufs": -9.0 + }, + { + "t": 5.3, + "lufs": -9.0 + }, + { + "t": 5.4, + "lufs": -9.0 + }, + { + "t": 5.5, + "lufs": -9.0 + }, + { + "t": 5.6, + "lufs": -9.0 + }, + { + "t": 5.7, + "lufs": -9.0 + }, + { + "t": 5.8, + "lufs": -9.1 + }, + { + "t": 5.9, + "lufs": -9.1 + }, + { + "t": 6.0, + "lufs": -9.0 + }, + { + "t": 6.1, + "lufs": -9.0 + }, + { + "t": 6.2, + "lufs": -9.0 + }, + { + "t": 6.3, + "lufs": -9.1 + }, + { + "t": 6.4, + "lufs": -9.1 + }, + { + "t": 6.5, + "lufs": -9.0 + }, + { + "t": 6.6, + "lufs": -9.0 + }, + { + "t": 6.7, + "lufs": -9.1 + }, + { + "t": 6.8, + "lufs": -9.0 + }, + { + "t": 6.9, + "lufs": -9.0 + }, + { + "t": 7.0, + "lufs": -9.0 + }, + { + "t": 7.1, + "lufs": -9.0 + }, + { + "t": 7.2, + "lufs": -9.1 + }, + { + "t": 7.3, + "lufs": -9.1 + }, + { + "t": 7.4, + "lufs": -9.0 + }, + { + "t": 7.5, + "lufs": -9.0 + }, + { + "t": 7.6, + "lufs": -9.1 + }, + { + "t": 7.7, + "lufs": -9.1 + }, + { + "t": 7.8, + "lufs": -9.1 + }, + { + "t": 7.9, + "lufs": -9.0 + }, + { + "t": 8.0, + "lufs": -9.0 + }, + { + "t": 8.1, + "lufs": -9.1 + }, + { + "t": 8.2, + "lufs": -9.0 + }, + { + "t": 8.3, + "lufs": -9.0 + }, + { + "t": 8.4, + "lufs": -9.0 + }, + { + "t": 8.5, + "lufs": -9.0 + }, + { + "t": 8.6, + "lufs": -9.1 + }, + { + "t": 8.7, + "lufs": -9.1 + }, + { + "t": 8.8, + "lufs": -9.0 + }, + { + "t": 8.9, + "lufs": -9.0 + }, + { + "t": 9.0, + "lufs": -9.1 + }, + { + "t": 9.1, + "lufs": -9.1 + }, + { + "t": 9.2, + "lufs": -9.1 + }, + { + "t": 9.3, + "lufs": -9.0 + }, + { + "t": 9.4, + "lufs": -9.0 + }, + { + "t": 9.5, + "lufs": -9.1 + }, + { + "t": 9.6, + "lufs": -9.0 + }, + { + "t": 9.7, + "lufs": -9.0 + }, + { + "t": 9.8, + "lufs": -9.0 + }, + { + "t": 9.9, + "lufs": -9.0 + }, + { + "t": 10.0, + "lufs": -9.1 + }, + { + "t": 10.1, + "lufs": -9.1 + }, + { + "t": 10.2, + "lufs": -9.0 + }, + { + "t": 10.3, + "lufs": -9.0 + }, + { + "t": 10.4, + "lufs": -9.1 + }, + { + "t": 10.5, + "lufs": -9.1 + }, + { + "t": 10.6, + "lufs": -9.1 + }, + { + "t": 10.7, + "lufs": -9.0 + }, + { + "t": 10.8, + "lufs": -9.0 + }, + { + "t": 10.9, + "lufs": -9.0 + }, + { + "t": 11.0, + "lufs": -9.0 + }, + { + "t": 11.1, + "lufs": -8.9 + }, + { + "t": 11.2, + "lufs": -9.0 + }, + { + "t": 11.3, + "lufs": -9.1 + }, + { + "t": 11.4, + "lufs": -9.1 + }, + { + "t": 11.5, + "lufs": -9.1 + }, + { + "t": 11.6, + "lufs": -9.0 + }, + { + "t": 11.7, + "lufs": -9.0 + }, + { + "t": 11.8, + "lufs": -9.2 + } + ], + "momentary": [ + { + "t": 0.0, + "lufs": -8.3 + }, + { + "t": 0.1, + "lufs": -9.6 + }, + { + "t": 0.2, + "lufs": -9.2 + }, + { + "t": 0.3, + "lufs": -9.7 + }, + { + "t": 0.4, + "lufs": -9.1 + }, + { + "t": 0.5, + "lufs": -9.2 + }, + { + "t": 0.6, + "lufs": -9.1 + }, + { + "t": 0.7, + "lufs": -9.2 + }, + { + "t": 0.8, + "lufs": -9.0 + }, + { + "t": 0.9, + "lufs": -8.8 + }, + { + "t": 1.0, + "lufs": -9.3 + }, + { + "t": 1.1, + "lufs": -8.5 + }, + { + "t": 1.2, + "lufs": -9.1 + }, + { + "t": 1.3, + "lufs": -8.4 + }, + { + "t": 1.4, + "lufs": -8.5 + }, + { + "t": 1.5, + "lufs": -9.5 + }, + { + "t": 1.6, + "lufs": -9.1 + }, + { + "t": 1.7, + "lufs": -9.4 + }, + { + "t": 1.8, + "lufs": -9.0 + }, + { + "t": 1.9, + "lufs": -9.3 + }, + { + "t": 2.0, + "lufs": -9.1 + }, + { + "t": 2.1, + "lufs": -9.5 + }, + { + "t": 2.2, + "lufs": -9.0 + }, + { + "t": 2.3, + "lufs": -8.8 + }, + { + "t": 2.4, + "lufs": -9.0 + }, + { + "t": 2.5, + "lufs": -8.4 + }, + { + "t": 2.6, + "lufs": -9.2 + }, + { + "t": 2.7, + "lufs": -8.4 + }, + { + "t": 2.8, + "lufs": -8.9 + }, + { + "t": 2.9, + "lufs": -9.4 + }, + { + "t": 3.0, + "lufs": -9.1 + }, + { + "t": 3.1, + "lufs": -9.3 + }, + { + "t": 3.2, + "lufs": -9.1 + }, + { + "t": 3.3, + "lufs": -9.3 + }, + { + "t": 3.4, + "lufs": -9.1 + }, + { + "t": 3.5, + "lufs": -9.7 + }, + { + "t": 3.6, + "lufs": -8.9 + }, + { + "t": 3.7, + "lufs": -8.9 + }, + { + "t": 3.8, + "lufs": -8.7 + }, + { + "t": 3.9, + "lufs": -8.4 + }, + { + "t": 4.0, + "lufs": -8.8 + }, + { + "t": 4.1, + "lufs": -8.4 + }, + { + "t": 4.2, + "lufs": -9.2 + }, + { + "t": 4.3, + "lufs": -9.3 + }, + { + "t": 4.4, + "lufs": -9.5 + }, + { + "t": 4.5, + "lufs": -9.1 + }, + { + "t": 4.6, + "lufs": -9.0 + }, + { + "t": 4.7, + "lufs": -9.4 + }, + { + "t": 4.8, + "lufs": -9.1 + }, + { + "t": 4.9, + "lufs": -9.9 + }, + { + "t": 5.0, + "lufs": -9.0 + }, + { + "t": 5.1, + "lufs": -9.0 + }, + { + "t": 5.2, + "lufs": -8.5 + }, + { + "t": 5.3, + "lufs": -8.4 + }, + { + "t": 5.4, + "lufs": -8.6 + }, + { + "t": 5.5, + "lufs": -8.4 + }, + { + "t": 5.6, + "lufs": -9.6 + }, + { + "t": 5.7, + "lufs": -9.2 + }, + { + "t": 5.8, + "lufs": -9.7 + }, + { + "t": 5.9, + "lufs": -9.1 + }, + { + "t": 6.0, + "lufs": -9.0 + }, + { + "t": 6.1, + "lufs": -9.3 + }, + { + "t": 6.2, + "lufs": -9.0 + }, + { + "t": 6.3, + "lufs": -9.7 + }, + { + "t": 6.4, + "lufs": -8.9 + }, + { + "t": 6.5, + "lufs": -9.3 + }, + { + "t": 6.6, + "lufs": -8.6 + }, + { + "t": 6.7, + "lufs": -8.5 + }, + { + "t": 6.8, + "lufs": -8.5 + }, + { + "t": 6.9, + "lufs": -8.3 + }, + { + "t": 7.0, + "lufs": -9.3 + }, + { + "t": 7.1, + "lufs": -9.2 + }, + { + "t": 7.2, + "lufs": -9.9 + }, + { + "t": 7.3, + "lufs": -9.1 + }, + { + "t": 7.4, + "lufs": -9.2 + }, + { + "t": 7.5, + "lufs": -9.4 + }, + { + "t": 7.6, + "lufs": -9.1 + }, + { + "t": 7.7, + "lufs": -9.3 + }, + { + "t": 7.8, + "lufs": -8.9 + }, + { + "t": 7.9, + "lufs": -9.2 + }, + { + "t": 8.0, + "lufs": -8.5 + }, + { + "t": 8.1, + "lufs": -8.9 + }, + { + "t": 8.2, + "lufs": -8.4 + }, + { + "t": 8.3, + "lufs": -8.3 + }, + { + "t": 8.4, + "lufs": -9.5 + }, + { + "t": 8.5, + "lufs": -9.1 + }, + { + "t": 8.6, + "lufs": -10.0 + }, + { + "t": 8.7, + "lufs": -9.1 + }, + { + "t": 8.8, + "lufs": -9.1 + }, + { + "t": 8.9, + "lufs": -9.2 + }, + { + "t": 9.0, + "lufs": -9.1 + }, + { + "t": 9.1, + "lufs": -9.2 + }, + { + "t": 9.2, + "lufs": -8.9 + }, + { + "t": 9.3, + "lufs": -9.4 + }, + { + "t": 9.4, + "lufs": -8.5 + }, + { + "t": 9.5, + "lufs": -9.1 + }, + { + "t": 9.6, + "lufs": -8.4 + }, + { + "t": 9.7, + "lufs": -8.5 + }, + { + "t": 9.8, + "lufs": -9.5 + }, + { + "t": 9.9, + "lufs": -9.1 + }, + { + "t": 10.0, + "lufs": -9.5 + }, + { + "t": 10.1, + "lufs": -9.1 + }, + { + "t": 10.2, + "lufs": -9.2 + }, + { + "t": 10.3, + "lufs": -9.3 + }, + { + "t": 10.4, + "lufs": -9.5 + }, + { + "t": 10.5, + "lufs": -9.1 + }, + { + "t": 10.6, + "lufs": -8.9 + }, + { + "t": 10.7, + "lufs": -9.1 + }, + { + "t": 10.8, + "lufs": -8.4 + }, + { + "t": 10.9, + "lufs": -9.2 + }, + { + "t": 11.0, + "lufs": -8.4 + }, + { + "t": 11.1, + "lufs": -8.7 + }, + { + "t": 11.2, + "lufs": -9.3 + }, + { + "t": 11.3, + "lufs": -9.0 + }, + { + "t": 11.4, + "lufs": -9.2 + }, + { + "t": 11.5, + "lufs": -9.0 + }, + { + "t": 11.6, + "lufs": -9.5 + }, + { + "t": 11.7, + "lufs": -9.2 + }, + { + "t": 11.8, + "lufs": -9.8 + }, + { + "t": 11.9, + "lufs": -9.0 + }, + { + "t": 12.0, + "lufs": -8.9 + }, + { + "t": 12.1, + "lufs": -8.9 + }, + { + "t": 12.2, + "lufs": -8.5 + }, + { + "t": 12.3, + "lufs": -9.0 + }, + { + "t": 12.4, + "lufs": -8.5 + }, + { + "t": 12.5, + "lufs": -9.1 + }, + { + "t": 12.6, + "lufs": -9.2 + }, + { + "t": 12.7, + "lufs": -9.2 + }, + { + "t": 12.8, + "lufs": -9.1 + }, + { + "t": 12.9, + "lufs": -8.9 + }, + { + "t": 13.0, + "lufs": -9.3 + }, + { + "t": 13.1, + "lufs": -9.2 + }, + { + "t": 13.2, + "lufs": -9.9 + }, + { + "t": 13.3, + "lufs": -9.1 + }, + { + "t": 13.4, + "lufs": -9.1 + }, + { + "t": 13.5, + "lufs": -8.6 + }, + { + "t": 13.6, + "lufs": -8.4 + }, + { + "t": 13.7, + "lufs": -8.7 + }, + { + "t": 13.8, + "lufs": -8.4 + }, + { + "t": 13.9, + "lufs": -9.5 + }, + { + "t": 14.0, + "lufs": -9.2 + }, + { + "t": 14.1, + "lufs": -9.5 + }, + { + "t": 14.2, + "lufs": -9.1 + }, + { + "t": 14.3, + "lufs": -8.9 + }, + { + "t": 14.4, + "lufs": -9.9 + } + ] + }, + "truePeak": 1.0, + "plr": 10.0, + "crestFactor": 10.0, + "dynamicSpread": 30.86, + "dynamicCharacter": { + "dynamicComplexity": 1.3119, + "loudnessDb": -17.3562, + "loudnessVariation": -17.3562, + "spectralFlatness": 0.1075, + "logAttackTime": -3.9723, + "attackTimeStdDev": 0.0109 + }, + "textureCharacter": { + "textureScore": 0.3283, + "lowBandFlatness": 0.3501, + "midBandFlatness": 0.3357, + "highBandFlatness": 0.3217, + "inharmonicity": 0.0781 + }, + "stereoDetail": { + "stereoWidth": 0.0, + "stereoCorrelation": 1.0, + "subBassCorrelation": 1.0, + "subBassMono": true, + "correlationCurve": [ + { + "t": 0.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 1.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 2.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 3.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 4.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 5.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 6.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 7.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 8.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 9.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 10.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 11.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 12.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 13.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 14.5, + "full": 1.0, + "sub": 1.0 + }, + { + "t": 15.5, + "full": 1.0, + "sub": 1.0 + } + ], + "bandCorrelations": { + "subBass": 1.0, + "lowBass": 1.0, + "lowMids": 1.0, + "mids": 1.0, + "upperMids": 1.0, + "highs": 1.0, + "brilliance": 1.0 + } + }, + "monoCompatible": true, + "spectralBalance": { + "subBass": -7.4, + "lowBass": -7.9, + "lowMids": -24.3, + "mids": -24.0, + "upperMids": -34.9, + "highs": -29.1, + "brilliance": -21.4 + }, + "spectralBalanceTimeSeries": [ + { + "t": 0.03, + "subBass": -4.6, + "lowBass": -4.3, + "lowMids": -22.0, + "mids": -26.4, + "upperMids": -39.3, + "highs": -55.6, + "brilliance": -79.6 + }, + { + "t": 0.13, + "subBass": -4.5, + "lowBass": -8.9, + "lowMids": -22.3, + "mids": -26.8, + "upperMids": -38.9, + "highs": -55.1, + "brilliance": -73.4 + }, + { + "t": 0.22, + "subBass": -8.0, + "lowBass": -9.3, + "lowMids": -26.3, + "mids": -22.8, + "upperMids": -30.2, + "highs": -22.5, + "brilliance": -14.7 + }, + { + "t": 0.31, + "subBass": -8.5, + "lowBass": -7.7, + "lowMids": -41.5, + "mids": -22.3, + "upperMids": -35.5, + "highs": -30.8, + "brilliance": -23.2 + }, + { + "t": 0.41, + "subBass": -11.5, + "lowBass": -9.0, + "lowMids": -40.0, + "mids": -22.0, + "upperMids": -38.2, + "highs": -49.1, + "brilliance": -56.2 + }, + { + "t": 0.5, + "subBass": -6.5, + "lowBass": -6.5, + "lowMids": -21.0, + "mids": -25.7, + "upperMids": -38.1, + "highs": -50.8, + "brilliance": -53.1 + }, + { + "t": 0.59, + "subBass": -6.4, + "lowBass": -8.6, + "lowMids": -21.7, + "mids": -26.8, + "upperMids": -39.7, + "highs": -70.7, + "brilliance": -73.7 + }, + { + "t": 0.68, + "subBass": -8.1, + "lowBass": -8.9, + "lowMids": -27.8, + "mids": -22.4, + "upperMids": -29.9, + "highs": -22.1, + "brilliance": -14.5 + }, + { + "t": 0.78, + "subBass": -6.9, + "lowBass": -8.4, + "lowMids": -44.3, + "mids": -22.3, + "upperMids": -35.9, + "highs": -31.6, + "brilliance": -24.1 + }, + { + "t": 0.87, + "subBass": -8.8, + "lowBass": -9.4, + "lowMids": -40.5, + "mids": -22.4, + "upperMids": -38.5, + "highs": -49.1, + "brilliance": -56.0 + }, + { + "t": 0.96, + "subBass": -6.6, + "lowBass": -6.0, + "lowMids": -21.1, + "mids": -25.9, + "upperMids": -38.4, + "highs": -51.2, + "brilliance": -54.0 + }, + { + "t": 1.06, + "subBass": -6.5, + "lowBass": -9.1, + "lowMids": -21.6, + "mids": -27.0, + "upperMids": -37.7, + "highs": -74.6, + "brilliance": -79.6 + }, + { + "t": 1.15, + "subBass": -8.1, + "lowBass": -8.6, + "lowMids": -28.5, + "mids": -22.5, + "upperMids": -30.1, + "highs": -22.1, + "brilliance": -14.5 + }, + { + "t": 1.24, + "subBass": -10.0, + "lowBass": -7.8, + "lowMids": -25.3, + "mids": -24.3, + "upperMids": -36.4, + "highs": -32.7, + "brilliance": -25.0 + }, + { + "t": 1.34, + "subBass": -13.8, + "lowBass": -9.1, + "lowMids": -22.7, + "mids": -27.9, + "upperMids": -38.3, + "highs": -52.8, + "brilliance": -54.9 + }, + { + "t": 1.43, + "subBass": -3.7, + "lowBass": -4.1, + "lowMids": -21.5, + "mids": -27.3, + "upperMids": -40.3, + "highs": -59.9, + "brilliance": -63.1 + }, + { + "t": 1.52, + "subBass": -5.9, + "lowBass": -9.6, + "lowMids": -33.8, + "mids": -21.4, + "upperMids": -36.8, + "highs": -50.4, + "brilliance": -79.5 + }, + { + "t": 1.61, + "subBass": -6.6, + "lowBass": -8.6, + "lowMids": -23.2, + "mids": -25.4, + "upperMids": -30.4, + "highs": -22.3, + "brilliance": -14.6 + }, + { + "t": 1.71, + "subBass": -9.0, + "lowBass": -7.9, + "lowMids": -22.4, + "mids": -27.6, + "upperMids": -37.3, + "highs": -34.2, + "brilliance": -26.4 + }, + { + "t": 1.8, + "subBass": -11.4, + "lowBass": -9.1, + "lowMids": -22.8, + "mids": -27.9, + "upperMids": -38.2, + "highs": -51.7, + "brilliance": -53.9 + }, + { + "t": 1.89, + "subBass": -6.7, + "lowBass": -7.2, + "lowMids": -30.0, + "mids": -20.9, + "upperMids": -36.1, + "highs": -50.3, + "brilliance": -58.8 + }, + { + "t": 1.99, + "subBass": -6.8, + "lowBass": -8.8, + "lowMids": -21.9, + "mids": -26.2, + "upperMids": -38.4, + "highs": -54.5, + "brilliance": -74.5 + }, + { + "t": 2.08, + "subBass": -7.3, + "lowBass": -8.8, + "lowMids": -22.3, + "mids": -27.0, + "upperMids": -30.5, + "highs": -22.6, + "brilliance": -14.8 + }, + { + "t": 2.17, + "subBass": -8.2, + "lowBass": -8.6, + "lowMids": -22.2, + "mids": -27.2, + "upperMids": -37.8, + "highs": -35.0, + "brilliance": -27.4 + }, + { + "t": 2.26, + "subBass": -9.1, + "lowBass": -9.1, + "lowMids": -22.8, + "mids": -27.2, + "upperMids": -39.2, + "highs": -50.4, + "brilliance": -52.6 + }, + { + "t": 2.36, + "subBass": -5.5, + "lowBass": -6.0, + "lowMids": -33.9, + "mids": -21.7, + "upperMids": -37.8, + "highs": -49.3, + "brilliance": -61.1 + }, + { + "t": 2.45, + "subBass": -5.9, + "lowBass": -8.6, + "lowMids": -37.9, + "mids": -21.4, + "upperMids": -37.0, + "highs": -50.3, + "brilliance": -76.8 + }, + { + "t": 2.54, + "subBass": -9.2, + "lowBass": -8.7, + "lowMids": -37.6, + "mids": -21.6, + "upperMids": -30.2, + "highs": -22.8, + "brilliance": -14.8 + }, + { + "t": 2.64, + "subBass": -10.2, + "lowBass": -7.9, + "lowMids": -24.6, + "mids": -24.4, + "upperMids": -37.7, + "highs": -36.9, + "brilliance": -29.3 + }, + { + "t": 2.73, + "subBass": -13.3, + "lowBass": -8.4, + "lowMids": -23.4, + "mids": -27.3, + "upperMids": -39.2, + "highs": -51.6, + "brilliance": -55.9 + }, + { + "t": 2.82, + "subBass": -3.6, + "lowBass": -4.2, + "lowMids": -30.5, + "mids": -22.6, + "upperMids": -38.1, + "highs": -51.5, + "brilliance": -75.6 + }, + { + "t": 2.91, + "subBass": -6.0, + "lowBass": -9.7, + "lowMids": -21.8, + "mids": -26.8, + "upperMids": -37.6, + "highs": -65.7, + "brilliance": -81.9 + }, + { + "t": 3.01, + "subBass": -7.9, + "lowBass": -8.7, + "lowMids": -22.3, + "mids": -26.7, + "upperMids": -30.2, + "highs": -22.6, + "brilliance": -14.7 + }, + { + "t": 3.1, + "subBass": -8.9, + "lowBass": -7.9, + "lowMids": -27.2, + "mids": -22.9, + "upperMids": -37.5, + "highs": -40.0, + "brilliance": -32.3 + }, + { + "t": 3.19, + "subBass": -11.1, + "lowBass": -8.4, + "lowMids": -27.5, + "mids": -23.0, + "upperMids": -37.7, + "highs": -48.2, + "brilliance": -52.1 + }, + { + "t": 3.29, + "subBass": -6.8, + "lowBass": -8.0, + "lowMids": -21.9, + "mids": -26.8, + "upperMids": -39.2, + "highs": -78.7, + "brilliance": -81.2 + }, + { + "t": 3.38, + "subBass": -6.8, + "lowBass": -8.8, + "lowMids": -21.7, + "mids": -27.1, + "upperMids": -37.8, + "highs": -70.1, + "brilliance": -73.3 + }, + { + "t": 3.47, + "subBass": -7.1, + "lowBass": -8.5, + "lowMids": -22.3, + "mids": -26.9, + "upperMids": -30.1, + "highs": -22.3, + "brilliance": -14.6 + }, + { + "t": 3.56, + "subBass": -6.8, + "lowBass": -8.5, + "lowMids": -22.4, + "mids": -26.8, + "upperMids": -38.8, + "highs": -42.3, + "brilliance": -34.6 + }, + { + "t": 3.66, + "subBass": -9.6, + "lowBass": -8.3, + "lowMids": -23.0, + "mids": -25.6, + "upperMids": -38.3, + "highs": -48.2, + "brilliance": -51.4 + }, + { + "t": 3.75, + "subBass": -6.0, + "lowBass": -6.7, + "lowMids": -35.9, + "mids": -22.4, + "upperMids": -38.6, + "highs": -50.5, + "brilliance": -101.2 + }, + { + "t": 3.84, + "subBass": -6.7, + "lowBass": -9.1, + "lowMids": -21.4, + "mids": -26.1, + "upperMids": -38.7, + "highs": -66.5, + "brilliance": -74.5 + }, + { + "t": 3.94, + "subBass": -9.1, + "lowBass": -8.4, + "lowMids": -22.0, + "mids": -27.1, + "upperMids": -29.9, + "highs": -21.9, + "brilliance": -14.2 + }, + { + "t": 4.03, + "subBass": -10.3, + "lowBass": -8.0, + "lowMids": -22.0, + "mids": -27.5, + "upperMids": -37.9, + "highs": -46.6, + "brilliance": -38.6 + }, + { + "t": 4.12, + "subBass": -12.9, + "lowBass": -7.8, + "lowMids": -24.3, + "mids": -25.4, + "upperMids": -38.3, + "highs": -50.3, + "brilliance": -54.8 + }, + { + "t": 4.21, + "subBass": -3.8, + "lowBass": -4.5, + "lowMids": -30.1, + "mids": -23.7, + "upperMids": -39.8, + "highs": -51.7, + "brilliance": -96.3 + }, + { + "t": 4.31, + "subBass": -5.0, + "lowBass": -9.3, + "lowMids": -21.6, + "mids": -26.6, + "upperMids": -39.5, + "highs": -67.2, + "brilliance": -73.9 + }, + { + "t": 4.4, + "subBass": -7.9, + "lowBass": -8.4, + "lowMids": -22.0, + "mids": -25.8, + "upperMids": -29.6, + "highs": -21.7, + "brilliance": -14.0 + }, + { + "t": 4.49, + "subBass": -9.1, + "lowBass": -8.0, + "lowMids": -21.7, + "mids": -26.9, + "upperMids": -39.4, + "highs": -52.3, + "brilliance": -44.5 + }, + { + "t": 4.59, + "subBass": -12.2, + "lowBass": -7.9, + "lowMids": -22.0, + "mids": -27.0, + "upperMids": -39.0, + "highs": -50.4, + "brilliance": -52.4 + }, + { + "t": 4.68, + "subBass": -5.4, + "lowBass": -6.9, + "lowMids": -22.6, + "mids": -27.7, + "upperMids": -40.2, + "highs": -79.4, + "brilliance": -88.0 + }, + { + "t": 4.77, + "subBass": -7.1, + "lowBass": -9.0, + "lowMids": -37.2, + "mids": -20.9, + "upperMids": -36.5, + "highs": -49.9, + "brilliance": -74.8 + }, + { + "t": 4.86, + "subBass": -8.1, + "lowBass": -8.7, + "lowMids": -22.0, + "mids": -25.8, + "upperMids": -29.7, + "highs": -21.7, + "brilliance": -14.1 + }, + { + "t": 4.96, + "subBass": -7.5, + "lowBass": -8.7, + "lowMids": -21.8, + "mids": -26.9, + "upperMids": -39.6, + "highs": -60.3, + "brilliance": -51.6 + }, + { + "t": 5.05, + "subBass": -9.5, + "lowBass": -8.0, + "lowMids": -22.2, + "mids": -25.7, + "upperMids": -38.7, + "highs": -48.9, + "brilliance": -51.5 + }, + { + "t": 5.14, + "subBass": -5.6, + "lowBass": -7.0, + "lowMids": -23.4, + "mids": -28.6, + "upperMids": -40.3, + "highs": -56.5, + "brilliance": -83.2 + }, + { + "t": 5.24, + "subBass": -6.5, + "lowBass": -9.0, + "lowMids": -21.5, + "mids": -26.3, + "upperMids": -38.2, + "highs": -54.4, + "brilliance": -77.9 + }, + { + "t": 5.33, + "subBass": -8.9, + "lowBass": -8.1, + "lowMids": -21.7, + "mids": -26.4, + "upperMids": -30.1, + "highs": -22.1, + "brilliance": -14.3 + }, + { + "t": 5.42, + "subBass": -10.5, + "lowBass": -8.1, + "lowMids": -29.0, + "mids": -22.1, + "upperMids": -37.9, + "highs": -50.3, + "brilliance": -63.9 + }, + { + "t": 5.51, + "subBass": -11.6, + "lowBass": -6.9, + "lowMids": -33.8, + "mids": -22.4, + "upperMids": -38.0, + "highs": -48.9, + "brilliance": -55.2 + }, + { + "t": 5.61, + "subBass": -3.4, + "lowBass": -5.2, + "lowMids": -31.5, + "mids": -24.1, + "upperMids": -39.7, + "highs": -53.1, + "brilliance": -86.1 + }, + { + "t": 5.7, + "subBass": -6.4, + "lowBass": -9.8, + "lowMids": -46.5, + "mids": -21.2, + "upperMids": -37.4, + "highs": -49.2, + "brilliance": -87.6 + }, + { + "t": 5.79, + "subBass": -7.4, + "lowBass": -8.1, + "lowMids": -22.0, + "mids": -25.9, + "upperMids": -30.3, + "highs": -22.5, + "brilliance": -14.6 + }, + { + "t": 5.89, + "subBass": -9.4, + "lowBass": -8.2, + "lowMids": -29.5, + "mids": -21.8, + "upperMids": -37.1, + "highs": -50.9, + "brilliance": -71.2 + }, + { + "t": 5.98, + "subBass": -12.4, + "lowBass": -8.5, + "lowMids": -23.8, + "mids": -24.0, + "upperMids": -37.3, + "highs": -49.5, + "brilliance": -53.1 + }, + { + "t": 6.07, + "subBass": -6.1, + "lowBass": -8.2, + "lowMids": -23.5, + "mids": -28.8, + "upperMids": -39.5, + "highs": -68.5, + "brilliance": -80.6 + }, + { + "t": 6.16, + "subBass": -7.3, + "lowBass": -9.1, + "lowMids": -21.8, + "mids": -26.8, + "upperMids": -38.5, + "highs": -54.7, + "brilliance": -89.3 + }, + { + "t": 6.26, + "subBass": -6.6, + "lowBass": -8.3, + "lowMids": -35.4, + "mids": -21.7, + "upperMids": -30.1, + "highs": -22.6, + "brilliance": -14.8 + }, + { + "t": 6.35, + "subBass": -8.5, + "lowBass": -8.9, + "lowMids": -22.3, + "mids": -25.6, + "upperMids": -39.4, + "highs": -57.1, + "brilliance": -65.4 + }, + { + "t": 6.44, + "subBass": -9.4, + "lowBass": -7.5, + "lowMids": -24.9, + "mids": -23.5, + "upperMids": -37.6, + "highs": -47.9, + "brilliance": -51.5 + }, + { + "t": 6.54, + "subBass": -4.9, + "lowBass": -7.3, + "lowMids": -30.4, + "mids": -23.6, + "upperMids": -39.0, + "highs": -52.9, + "brilliance": -82.7 + }, + { + "t": 6.63, + "subBass": -6.9, + "lowBass": -9.2, + "lowMids": -21.8, + "mids": -27.2, + "upperMids": -40.0, + "highs": -80.1, + "brilliance": -100.2 + }, + { + "t": 6.72, + "subBass": -9.8, + "lowBass": -8.1, + "lowMids": -21.8, + "mids": -27.0, + "upperMids": -30.2, + "highs": -22.5, + "brilliance": -14.6 + }, + { + "t": 6.82, + "subBass": -10.7, + "lowBass": -8.2, + "lowMids": -30.8, + "mids": -21.9, + "upperMids": -37.7, + "highs": -49.8, + "brilliance": -61.9 + }, + { + "t": 6.91, + "subBass": -9.5, + "lowBass": -5.3, + "lowMids": -24.4, + "mids": -24.9, + "upperMids": -38.7, + "highs": -51.9, + "brilliance": -57.3 + }, + { + "t": 7.0, + "subBass": -3.5, + "lowBass": -6.3, + "lowMids": -23.6, + "mids": -28.8, + "upperMids": -40.2, + "highs": -63.1, + "brilliance": -78.6 + }, + { + "t": 7.09, + "subBass": -6.5, + "lowBass": -9.9, + "lowMids": -22.2, + "mids": -27.3, + "upperMids": -38.9, + "highs": -55.1, + "brilliance": -110.6 + }, + { + "t": 7.19, + "subBass": -8.5, + "lowBass": -8.1, + "lowMids": -21.7, + "mids": -26.6, + "upperMids": -29.9, + "highs": -22.2, + "brilliance": -14.4 + }, + { + "t": 7.28, + "subBass": -9.3, + "lowBass": -8.3, + "lowMids": -21.3, + "mids": -26.4, + "upperMids": -38.5, + "highs": -57.0, + "brilliance": -59.1 + }, + { + "t": 7.37, + "subBass": -12.2, + "lowBass": -8.2, + "lowMids": -21.7, + "mids": -27.0, + "upperMids": -37.9, + "highs": -51.9, + "brilliance": -53.9 + }, + { + "t": 7.47, + "subBass": -5.2, + "lowBass": -7.1, + "lowMids": -24.5, + "mids": -25.9, + "upperMids": -38.8, + "highs": -58.0, + "brilliance": -77.9 + }, + { + "t": 7.56, + "subBass": -7.5, + "lowBass": -9.1, + "lowMids": -33.9, + "mids": -21.8, + "upperMids": -37.2, + "highs": -52.5, + "brilliance": -75.4 + }, + { + "t": 7.65, + "subBass": -7.1, + "lowBass": -8.3, + "lowMids": -21.8, + "mids": -26.4, + "upperMids": -29.5, + "highs": -21.9, + "brilliance": -14.2 + }, + { + "t": 7.74, + "subBass": -7.3, + "lowBass": -8.8, + "lowMids": -32.4, + "mids": -21.2, + "upperMids": -36.5, + "highs": -49.2, + "brilliance": -57.1 + }, + { + "t": 7.84, + "subBass": -9.1, + "lowBass": -6.6, + "lowMids": -22.5, + "mids": -24.6, + "upperMids": -37.4, + "highs": -49.1, + "brilliance": -52.2 + }, + { + "t": 7.93, + "subBass": -6.1, + "lowBass": -9.0, + "lowMids": -24.5, + "mids": -24.7, + "upperMids": -38.1, + "highs": -56.5, + "brilliance": -79.8 + }, + { + "t": 8.02, + "subBass": -7.0, + "lowBass": -9.3, + "lowMids": -34.1, + "mids": -22.1, + "upperMids": -37.4, + "highs": -51.5, + "brilliance": -50.0 + }, + { + "t": 8.12, + "subBass": -9.5, + "lowBass": -7.9, + "lowMids": -34.5, + "mids": -20.9, + "upperMids": -29.5, + "highs": -21.8, + "brilliance": -14.1 + }, + { + "t": 8.21, + "subBass": -11.2, + "lowBass": -8.4, + "lowMids": -38.7, + "mids": -21.0, + "upperMids": -37.0, + "highs": -48.0, + "brilliance": -56.3 + }, + { + "t": 8.3, + "subBass": -7.4, + "lowBass": -4.7, + "lowMids": -23.3, + "mids": -25.5, + "upperMids": -38.7, + "highs": -53.9, + "brilliance": -60.1 + }, + { + "t": 8.39, + "subBass": -4.5, + "lowBass": -7.6, + "lowMids": -22.8, + "mids": -28.1, + "upperMids": -39.6, + "highs": -76.2, + "brilliance": -79.9 + }, + { + "t": 8.49, + "subBass": -5.4, + "lowBass": -9.6, + "lowMids": -23.0, + "mids": -27.9, + "upperMids": -40.1, + "highs": -45.8, + "brilliance": -38.7 + }, + { + "t": 8.58, + "subBass": -8.0, + "lowBass": -7.7, + "lowMids": -32.0, + "mids": -21.1, + "upperMids": -29.6, + "highs": -21.8, + "brilliance": -14.1 + }, + { + "t": 8.67, + "subBass": -10.2, + "lowBass": -8.6, + "lowMids": -21.6, + "mids": -25.3, + "upperMids": -37.3, + "highs": -50.9, + "brilliance": -55.4 + }, + { + "t": 8.77, + "subBass": -11.9, + "lowBass": -8.0, + "lowMids": -27.6, + "mids": -22.2, + "upperMids": -37.6, + "highs": -48.1, + "brilliance": -54.9 + }, + { + "t": 8.86, + "subBass": -5.1, + "lowBass": -6.9, + "lowMids": -25.2, + "mids": -24.7, + "upperMids": -39.4, + "highs": -53.0, + "brilliance": -75.4 + }, + { + "t": 8.95, + "subBass": -7.8, + "lowBass": -9.3, + "lowMids": -23.2, + "mids": -28.4, + "upperMids": -39.2, + "highs": -38.7, + "brilliance": -31.6 + }, + { + "t": 9.04, + "subBass": -7.5, + "lowBass": -8.3, + "lowMids": -21.5, + "mids": -26.9, + "upperMids": -29.9, + "highs": -22.1, + "brilliance": -14.3 + }, + { + "t": 9.14, + "subBass": -8.2, + "lowBass": -8.9, + "lowMids": -21.0, + "mids": -26.2, + "upperMids": -38.2, + "highs": -54.1, + "brilliance": -56.2 + }, + { + "t": 9.23, + "subBass": -9.3, + "lowBass": -7.4, + "lowMids": -21.9, + "mids": -26.2, + "upperMids": -38.4, + "highs": -50.4, + "brilliance": -54.0 + }, + { + "t": 9.32, + "subBass": -4.8, + "lowBass": -7.5, + "lowMids": -26.1, + "mids": -23.9, + "upperMids": -38.4, + "highs": -53.9, + "brilliance": -76.9 + }, + { + "t": 9.42, + "subBass": -7.3, + "lowBass": -9.4, + "lowMids": -34.0, + "mids": -22.8, + "upperMids": -36.6, + "highs": -33.8, + "brilliance": -26.7 + }, + { + "t": 9.51, + "subBass": -9.3, + "lowBass": -7.6, + "lowMids": -38.4, + "mids": -21.2, + "upperMids": -30.3, + "highs": -22.7, + "brilliance": -14.8 + }, + { + "t": 9.6, + "subBass": -11.3, + "lowBass": -8.4, + "lowMids": -38.4, + "mids": -20.8, + "upperMids": -36.3, + "highs": -48.5, + "brilliance": -56.7 + }, + { + "t": 9.69, + "subBass": -6.2, + "lowBass": -4.4, + "lowMids": -23.3, + "mids": -26.1, + "upperMids": -40.0, + "highs": -56.4, + "brilliance": -62.4 + }, + { + "t": 9.79, + "subBass": -4.7, + "lowBass": -8.6, + "lowMids": -26.2, + "mids": -23.7, + "upperMids": -38.4, + "highs": -54.8, + "brilliance": -78.7 + }, + { + "t": 9.88, + "subBass": -7.0, + "lowBass": -10.2, + "lowMids": -31.8, + "mids": -22.6, + "upperMids": -35.1, + "highs": -30.1, + "brilliance": -23.1 + }, + { + "t": 9.97, + "subBass": -8.4, + "lowBass": -7.6, + "lowMids": -38.9, + "mids": -21.4, + "upperMids": -30.7, + "highs": -23.6, + "brilliance": -15.4 + }, + { + "t": 10.07, + "subBass": -9.7, + "lowBass": -8.4, + "lowMids": -21.5, + "mids": -26.1, + "upperMids": -38.9, + "highs": -55.3, + "brilliance": -57.8 + }, + { + "t": 10.16, + "subBass": -9.8, + "lowBass": -7.8, + "lowMids": -21.8, + "mids": -27.2, + "upperMids": -37.7, + "highs": -53.2, + "brilliance": -55.2 + }, + { + "t": 10.25, + "subBass": -6.2, + "lowBass": -8.8, + "lowMids": -26.9, + "mids": -23.7, + "upperMids": -38.2, + "highs": -53.3, + "brilliance": -79.0 + }, + { + "t": 10.34, + "subBass": -7.9, + "lowBass": -9.2, + "lowMids": -34.2, + "mids": -22.9, + "upperMids": -34.2, + "highs": -27.5, + "brilliance": -20.4 + }, + { + "t": 10.44, + "subBass": -6.0, + "lowBass": -8.1, + "lowMids": -35.0, + "mids": -21.7, + "upperMids": -31.4, + "highs": -24.3, + "brilliance": -16.2 + }, + { + "t": 10.53, + "subBass": -8.7, + "lowBass": -9.1, + "lowMids": -21.6, + "mids": -26.0, + "upperMids": -38.0, + "highs": -52.2, + "brilliance": -58.3 + }, + { + "t": 10.62, + "subBass": -9.3, + "lowBass": -7.7, + "lowMids": -25.6, + "mids": -22.0, + "upperMids": -36.4, + "highs": -48.2, + "brilliance": -52.7 + }, + { + "t": 10.72, + "subBass": -4.9, + "lowBass": -7.6, + "lowMids": -24.0, + "mids": -25.1, + "upperMids": -38.8, + "highs": -54.6, + "brilliance": -72.9 + }, + { + "t": 10.81, + "subBass": -8.2, + "lowBass": -9.7, + "lowMids": -24.5, + "mids": -25.5, + "upperMids": -33.3, + "highs": -25.6, + "brilliance": -18.6 + }, + { + "t": 10.9, + "subBass": -9.5, + "lowBass": -7.6, + "lowMids": -40.7, + "mids": -22.0, + "upperMids": -31.7, + "highs": -24.9, + "brilliance": -16.5 + }, + { + "t": 10.99, + "subBass": -11.7, + "lowBass": -8.5, + "lowMids": -37.8, + "mids": -20.8, + "upperMids": -36.3, + "highs": -48.8, + "brilliance": -58.0 + }, + { + "t": 11.09, + "subBass": -5.3, + "lowBass": -3.9, + "lowMids": -22.2, + "mids": -26.3, + "upperMids": -39.7, + "highs": -55.9, + "brilliance": -60.0 + }, + { + "t": 11.18, + "subBass": -4.9, + "lowBass": -9.4, + "lowMids": -22.5, + "mids": -27.4, + "upperMids": -40.2, + "highs": -70.5, + "brilliance": -73.4 + }, + { + "t": 11.27, + "subBass": -6.9, + "lowBass": -9.9, + "lowMids": -23.0, + "mids": -26.6, + "upperMids": -32.9, + "highs": -24.4, + "brilliance": -17.2 + }, + { + "t": 11.37, + "subBass": -8.3, + "lowBass": -7.6, + "lowMids": -22.6, + "mids": -27.8, + "upperMids": -32.0, + "highs": -25.4, + "brilliance": -17.2 + }, + { + "t": 11.46, + "subBass": -10.7, + "lowBass": -8.7, + "lowMids": -37.7, + "mids": -20.5, + "upperMids": -36.0, + "highs": -48.3, + "brilliance": -57.0 + }, + { + "t": 11.55, + "subBass": -8.0, + "lowBass": -6.3, + "lowMids": -21.6, + "mids": -25.4, + "upperMids": -38.1, + "highs": -50.8, + "brilliance": -53.2 + }, + { + "t": 11.64, + "subBass": -5.7, + "lowBass": -8.2, + "lowMids": -26.9, + "mids": -22.5, + "upperMids": -37.5, + "highs": -53.4, + "brilliance": -73.5 + }, + { + "t": 11.74, + "subBass": -8.0, + "lowBass": -9.1, + "lowMids": -33.1, + "mids": -22.3, + "upperMids": -31.8, + "highs": -23.8, + "brilliance": -16.4 + }, + { + "t": 11.83, + "subBass": -7.3, + "lowBass": -8.3, + "lowMids": -44.7, + "mids": -22.2, + "upperMids": -32.0, + "highs": -25.8, + "brilliance": -17.7 + }, + { + "t": 11.92, + "subBass": -7.9, + "lowBass": -9.0, + "lowMids": -39.3, + "mids": -20.7, + "upperMids": -36.0, + "highs": -48.3, + "brilliance": -55.9 + }, + { + "t": 12.02, + "subBass": -7.7, + "lowBass": -6.5, + "lowMids": -27.3, + "mids": -21.5, + "upperMids": -37.0, + "highs": -47.5, + "brilliance": -53.1 + }, + { + "t": 12.11, + "subBass": -6.3, + "lowBass": -9.2, + "lowMids": -22.9, + "mids": -25.4, + "upperMids": -39.6, + "highs": -56.8, + "brilliance": -75.3 + }, + { + "t": 12.2, + "subBass": -7.4, + "lowBass": -9.1, + "lowMids": -22.8, + "mids": -27.4, + "upperMids": -32.1, + "highs": -23.6, + "brilliance": -16.1 + }, + { + "t": 12.29, + "subBass": -9.5, + "lowBass": -7.6, + "lowMids": -23.2, + "mids": -28.2, + "upperMids": -33.1, + "highs": -26.4, + "brilliance": -18.4 + }, + { + "t": 12.39, + "subBass": -12.3, + "lowBass": -8.7, + "lowMids": -38.3, + "mids": -20.5, + "upperMids": -35.7, + "highs": -48.5, + "brilliance": -55.5 + }, + { + "t": 12.48, + "subBass": -5.1, + "lowBass": -4.2, + "lowMids": -22.3, + "mids": -27.1, + "upperMids": -38.3, + "highs": -58.3, + "brilliance": -62.4 + }, + { + "t": 12.57, + "subBass": -5.4, + "lowBass": -9.4, + "lowMids": -22.0, + "mids": -27.2, + "upperMids": -39.5, + "highs": -76.0, + "brilliance": -80.8 + }, + { + "t": 12.67, + "subBass": -6.1, + "lowBass": -9.3, + "lowMids": -23.0, + "mids": -27.1, + "upperMids": -32.1, + "highs": -23.7, + "brilliance": -16.1 + }, + { + "t": 12.76, + "subBass": -8.5, + "lowBass": -7.7, + "lowMids": -23.4, + "mids": -28.6, + "upperMids": -33.6, + "highs": -27.1, + "brilliance": -19.2 + }, + { + "t": 12.85, + "subBass": -10.6, + "lowBass": -8.8, + "lowMids": -20.7, + "mids": -25.8, + "upperMids": -38.0, + "highs": -54.0, + "brilliance": -56.1 + }, + { + "t": 12.95, + "subBass": -8.4, + "lowBass": -6.9, + "lowMids": -21.3, + "mids": -26.8, + "upperMids": -39.4, + "highs": -55.1, + "brilliance": -57.2 + }, + { + "t": 13.04, + "subBass": -6.2, + "lowBass": -8.5, + "lowMids": -29.5, + "mids": -22.2, + "upperMids": -37.6, + "highs": -51.4, + "brilliance": -79.1 + }, + { + "t": 13.13, + "subBass": -7.5, + "lowBass": -9.0, + "lowMids": -34.4, + "mids": -22.4, + "upperMids": -31.8, + "highs": -24.0, + "brilliance": -16.2 + }, + { + "t": 13.22, + "subBass": -7.4, + "lowBass": -8.4, + "lowMids": -35.3, + "mids": -22.8, + "upperMids": -33.8, + "highs": -27.5, + "brilliance": -19.8 + }, + { + "t": 13.32, + "subBass": -9.0, + "lowBass": -9.2, + "lowMids": -41.5, + "mids": -20.9, + "upperMids": -36.9, + "highs": -48.0, + "brilliance": -56.6 + }, + { + "t": 13.41, + "subBass": -6.9, + "lowBass": -6.9, + "lowMids": -29.2, + "mids": -21.3, + "upperMids": -36.4, + "highs": -48.3, + "brilliance": -54.8 + }, + { + "t": 13.5, + "subBass": -5.3, + "lowBass": -8.2, + "lowMids": -39.5, + "mids": -22.0, + "upperMids": -38.2, + "highs": -50.3, + "brilliance": -83.4 + }, + { + "t": 13.6, + "subBass": -8.5, + "lowBass": -9.2, + "lowMids": -25.1, + "mids": -24.8, + "upperMids": -31.5, + "highs": -24.0, + "brilliance": -15.9 + }, + { + "t": 13.69, + "subBass": -9.8, + "lowBass": -7.7, + "lowMids": -23.4, + "mids": -28.6, + "upperMids": -35.1, + "highs": -28.3, + "brilliance": -20.7 + }, + { + "t": 13.78, + "subBass": -12.2, + "lowBass": -8.7, + "lowMids": -21.6, + "mids": -26.7, + "upperMids": -38.0, + "highs": -52.4, + "brilliance": -58.7 + }, + { + "t": 13.87, + "subBass": -5.3, + "lowBass": -4.5, + "lowMids": -27.2, + "mids": -22.0, + "upperMids": -37.1, + "highs": -51.7, + "brilliance": -60.2 + }, + { + "t": 13.97, + "subBass": -4.6, + "lowBass": -8.8, + "lowMids": -22.6, + "mids": -26.2, + "upperMids": -39.6, + "highs": -61.3, + "brilliance": -72.7 + }, + { + "t": 14.06, + "subBass": -7.9, + "lowBass": -9.5, + "lowMids": -25.9, + "mids": -23.6, + "upperMids": -31.0, + "highs": -23.6, + "brilliance": -15.7 + }, + { + "t": 14.15, + "subBass": -8.7, + "lowBass": -7.7, + "lowMids": -29.7, + "mids": -23.5, + "upperMids": -35.2, + "highs": -29.2, + "brilliance": -21.6 + }, + { + "t": 14.25, + "subBass": -10.7, + "lowBass": -8.8, + "lowMids": -21.5, + "mids": -26.5, + "upperMids": -38.8, + "highs": -56.8, + "brilliance": -58.8 + }, + { + "t": 14.34, + "subBass": -7.5, + "lowBass": -6.9, + "lowMids": -31.3, + "mids": -21.1, + "upperMids": -36.5, + "highs": -48.4, + "brilliance": -54.6 + }, + { + "t": 14.43, + "subBass": -6.4, + "lowBass": -8.7, + "lowMids": -32.2, + "mids": -21.6, + "upperMids": -36.9, + "highs": -52.0, + "brilliance": -80.4 + }, + { + "t": 14.52, + "subBass": -7.7, + "lowBass": -8.9, + "lowMids": -24.4, + "mids": -24.9, + "upperMids": -30.4, + "highs": -23.1, + "brilliance": -15.3 + }, + { + "t": 14.62, + "subBass": -6.3, + "lowBass": -8.2, + "lowMids": -24.5, + "mids": -26.0, + "upperMids": -36.4, + "highs": -30.0, + "brilliance": -22.6 + }, + { + "t": 14.71, + "subBass": -9.1, + "lowBass": -9.3, + "lowMids": -42.4, + "mids": -21.5, + "upperMids": -37.1, + "highs": -49.7, + "brilliance": -58.1 + }, + { + "t": 14.78, + "subBass": -18.2, + "lowBass": -17.5, + "lowMids": -32.3, + "mids": -33.3, + "upperMids": -41.9, + "highs": -46.7, + "brilliance": -48.9 + } + ], + "spectralDetail": { + "spectralCentroid": 1027.5, + "spectralRolloff": 1264.3, + "spectralBandwidth": 2782.5, + "spectralFlatness": 0.107547, + "mfcc": [ + -738.4915, + 205.4349, + -1.7101, + 63.088, + 23.7295, + 18.8658, + 28.7747, + 15.4407, + 18.4548, + 16.4652, + 17.9787, + 15.473, + 14.9618 + ], + "chroma": [ + 0.0415, + 0.1756, + 0.0429, + 0.191, + 0.2523, + 0.0628, + 0.1971, + 0.1162, + 0.3132, + 0.115, + 0.3503, + 0.3631 + ], + "barkBands": [ + -22.8842, + -7.4646, + -11.1697, + -22.5971, + -29.5628, + -28.2235, + -26.9773, + -27.5063, + -31.3593, + -34.783, + -35.2757, + -33.9973, + -40.001, + -39.0523, + -41.015, + -42.4412, + -42.5889, + -42.9875, + -43.6306, + -42.7086, + -40.038, + -36.4273, + -36.4679, + -32.6915 + ], + "erbBands": [ + 10.152, + 18.3137, + 19.4526, + 13.6596, + 7.9028, + 4.2215, + 6.8201, + 13.4461, + 14.6268, + 15.5112, + 15.0926, + 10.5209, + 10.7066, + 10.0596, + 11.7062, + 10.9949, + 7.8507, + 7.6491, + 6.9768, + 5.4952, + 5.2941, + 4.8399, + 4.1877, + 3.9394, + 2.9865, + 4.2631, + 5.4792, + 6.5138, + 8.3693, + 9.2006, + 8.5376, + 10.2364, + 9.5018, + 9.9721, + 9.2391, + 9.0305, + 6.9922, + 3.2646, + -2.7205, + -12.195 + ], + "spectralContrast": [ + -0.2417, + -0.5634, + -0.6369, + -0.6994, + -0.73, + -0.7587 + ], + "spectralValley": [ + -5.5818, + -6.7781, + -7.7405, + -8.4542, + -9.3325, + -12.0928 + ] + }, + "stemAnalysis": null, + "transientDensityDetail": { + "subBass": { + "onsetRatePerSecond": 13.27, + "meanOnsetStrength": 0.261, + "peakOnsetStrength": 0.69, + "eventCount": 196 + }, + "lowBass": { + "onsetRatePerSecond": 8.19, + "meanOnsetStrength": 0.494, + "peakOnsetStrength": 1.38, + "eventCount": 121 + }, + "lowMids": { + "onsetRatePerSecond": 10.43, + "meanOnsetStrength": 0.955, + "peakOnsetStrength": 2.394, + "eventCount": 154 + }, + "mids": { + "onsetRatePerSecond": 10.77, + "meanOnsetStrength": 3.868, + "peakOnsetStrength": 8.442, + "eventCount": 159 + }, + "upperMids": { + "onsetRatePerSecond": 10.83, + "meanOnsetStrength": 4.141, + "peakOnsetStrength": 10.024, + "eventCount": 160 + }, + "highs": { + "onsetRatePerSecond": 10.77, + "meanOnsetStrength": 5.194, + "peakOnsetStrength": 13.839, + "eventCount": 159 + }, + "brilliance": { + "onsetRatePerSecond": 10.29, + "meanOnsetStrength": 5.116, + "peakOnsetStrength": 14.557, + "eventCount": 152 + } + }, + "saturationDetail": { + "clippedSampleCount": 0, + "clippedSamplePercent": 0.0, + "nearClippedSampleCount": 0, + "nearClippedSamplePercent": 0.0, + "peakRatio95to50": 2.491, + "rmsToPeakRatioDb": 9.98, + "saturationLikely": false + }, + "snareDetail": { + "hitCount": 61, + "hitsPerSecond": 4.13, + "meanAttackSharpness": 0.003, + "meanBodyEnergyRatio": 0.977, + "meanSnapEnergyRatio": 0.023, + "meanCentroidHz": 439.6, + "meanDecayFrames": 54.9, + "meanDecaySeconds": 0.319, + "bandHz": [ + 120.0, + 2000.0 + ] + }, + "hihatDetail": { + "hitCount": 32, + "hitsPerSecond": 2.17, + "meanAttackSharpness": 0.003, + "meanBodyEnergyRatio": 0.162, + "meanSnapEnergyRatio": 0.838, + "meanCentroidHz": 7961.1, + "meanDecayFrames": 8.3, + "meanDecaySeconds": 0.048, + "bandHz": [ + 2000.0, + 12000.0 + ] + }, + "rhythmDetail": { + "onsetRate": 2.17, + "beatGrid": [ + 0.348, + 0.72, + 1.149, + 1.614, + 2.067, + 2.531, + 2.995, + 3.46, + 3.913, + 4.377, + 4.841, + 5.306, + 5.759, + 6.223, + 6.687, + 7.152, + 7.605, + 8.069, + 8.533, + 8.998, + 9.451, + 9.915, + 10.379, + 10.844, + 11.297, + 11.761, + 12.225, + 12.69, + 13.142, + 13.607, + 14.071, + 14.536 + ], + "downbeats": [ + 0.72, + 2.531, + 4.377, + 6.223, + 8.069, + 9.915, + 11.761, + 13.607 + ], + "beatPositions": [ + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3, + 4, + 1, + 2, + 3 + ], + "downbeatSource": "kick_accent", + "downbeatConfidence": 0.0163, + "grooveAmount": 0.038, + "tempoStability": 0.962, + "phraseGrid": { + "phrases4Bar": [ + 0.72, + 8.069 + ], + "phrases8Bar": [ + 0.72 + ], + "phrases16Bar": [ + 0.72 + ], + "totalBars": 8, + "totalPhrases8Bar": 1 + }, + "tempoCurve": [ + { + "t": 0.53, + "bpm": 139.7 + }, + { + "t": 0.93, + "bpm": 136.1 + }, + { + "t": 1.38, + "bpm": 132.5 + }, + { + "t": 1.84, + "bpm": 129.2 + }, + { + "t": 2.3, + "bpm": 129.2 + }, + { + "t": 2.76, + "bpm": 129.2 + }, + { + "t": 3.23, + "bpm": 129.2 + }, + { + "t": 3.69, + "bpm": 129.2 + }, + { + "t": 4.14, + "bpm": 129.2 + }, + { + "t": 4.61, + "bpm": 129.2 + }, + { + "t": 5.07, + "bpm": 129.2 + }, + { + "t": 5.53, + "bpm": 129.2 + }, + { + "t": 5.99, + "bpm": 129.2 + }, + { + "t": 6.46, + "bpm": 129.2 + }, + { + "t": 6.92, + "bpm": 129.2 + }, + { + "t": 7.38, + "bpm": 129.2 + }, + { + "t": 7.84, + "bpm": 129.2 + }, + { + "t": 8.3, + "bpm": 129.2 + }, + { + "t": 8.77, + "bpm": 129.2 + }, + { + "t": 9.22, + "bpm": 129.2 + }, + { + "t": 9.68, + "bpm": 129.2 + }, + { + "t": 10.15, + "bpm": 129.2 + }, + { + "t": 10.61, + "bpm": 129.2 + }, + { + "t": 11.07, + "bpm": 129.2 + }, + { + "t": 11.53, + "bpm": 129.2 + }, + { + "t": 11.99, + "bpm": 129.2 + }, + { + "t": 12.46, + "bpm": 129.2 + }, + { + "t": 12.92, + "bpm": 129.2 + }, + { + "t": 13.37, + "bpm": 129.2 + }, + { + "t": 13.84, + "bpm": 129.2 + }, + { + "t": 14.3, + "bpm": 129.2 + } + ] + }, + "melodyDetail": { + "noteCount": 53, + "notes": [ + { + "midi": 43, + "onset": 0.232, + "duration": 0.215 + }, + { + "midi": 44, + "onset": 0.511, + "duration": 0.18 + }, + { + "midi": 41, + "onset": 0.697, + "duration": 0.221 + }, + { + "midi": 43, + "onset": 0.984, + "duration": 0.16 + }, + { + "midi": 44, + "onset": 1.149, + "duration": 0.229 + }, + { + "midi": 41, + "onset": 1.469, + "duration": 0.134 + }, + { + "midi": 43, + "onset": 1.608, + "duration": 0.223 + }, + { + "midi": 44, + "onset": 1.895, + "duration": 0.18 + }, + { + "midi": 41, + "onset": 2.081, + "duration": 0.223 + }, + { + "midi": 44, + "onset": 2.531, + "duration": 0.232 + }, + { + "midi": 41, + "onset": 2.853, + "duration": 0.134 + }, + { + "midi": 43, + "onset": 2.992, + "duration": 0.221 + }, + { + "midi": 44, + "onset": 3.28, + "duration": 0.18 + }, + { + "midi": 41, + "onset": 3.466, + "duration": 0.223 + }, + { + "midi": 43, + "onset": 3.75, + "duration": 0.16 + }, + { + "midi": 44, + "onset": 3.918, + "duration": 0.258 + }, + { + "midi": 43, + "onset": 4.386, + "duration": 0.218 + }, + { + "midi": 42, + "onset": 4.609, + "duration": 0.093 + }, + { + "midi": 44, + "onset": 4.708, + "duration": 0.136 + }, + { + "midi": 41, + "onset": 4.85, + "duration": 0.218 + }, + { + "midi": 43, + "onset": 5.135, + "duration": 0.16 + }, + { + "midi": 44, + "onset": 5.303, + "duration": 0.229 + }, + { + "midi": 44, + "onset": 6.06, + "duration": 0.165 + }, + { + "midi": 41, + "onset": 6.232, + "duration": 0.223 + }, + { + "midi": 43, + "onset": 6.519, + "duration": 0.157 + }, + { + "midi": 44, + "onset": 6.684, + "duration": 0.261 + }, + { + "midi": 43, + "onset": 7.155, + "duration": 0.215 + }, + { + "midi": 44, + "onset": 7.43, + "duration": 0.183 + }, + { + "midi": 41, + "onset": 7.619, + "duration": 0.223 + }, + { + "midi": 44, + "onset": 7.874, + "duration": 0.102 + }, + { + "midi": 43, + "onset": 7.982, + "duration": 0.093 + }, + { + "midi": 44, + "onset": 8.081, + "duration": 0.25 + }, + { + "midi": 44, + "onset": 8.815, + "duration": 0.183 + }, + { + "midi": 41, + "onset": 9.004, + "duration": 0.223 + }, + { + "midi": 43, + "onset": 9.288, + "duration": 0.157 + }, + { + "midi": 44, + "onset": 9.451, + "duration": 0.238 + }, + { + "midi": 44, + "onset": 10.199, + "duration": 0.183 + }, + { + "midi": 41, + "onset": 10.388, + "duration": 0.223 + }, + { + "midi": 43, + "onset": 10.672, + "duration": 0.16 + }, + { + "midi": 44, + "onset": 10.841, + "duration": 0.232 + }, + { + "midi": 43, + "onset": 11.308, + "duration": 0.215 + }, + { + "midi": 44, + "onset": 11.578, + "duration": 0.189 + }, + { + "midi": 41, + "onset": 11.773, + "duration": 0.223 + }, + { + "midi": 43, + "onset": 12.054, + "duration": 0.163 + }, + { + "midi": 44, + "onset": 12.225, + "duration": 0.232 + }, + { + "midi": 43, + "onset": 12.693, + "duration": 0.215 + }, + { + "midi": 44, + "onset": 12.963, + "duration": 0.189 + }, + { + "midi": 41, + "onset": 13.157, + "duration": 0.223 + }, + { + "midi": 43, + "onset": 13.439, + "duration": 0.165 + }, + { + "midi": 44, + "onset": 13.613, + "duration": 0.229 + }, + { + "midi": 43, + "onset": 14.1, + "duration": 0.192 + }, + { + "midi": 44, + "onset": 14.364, + "duration": 0.168 + }, + { + "midi": 41, + "onset": 14.539, + "duration": 0.177 + } + ], + "dominantNotes": [ + 44, + 43, + 41, + 42 + ], + "pitchRange": { + "min": 41, + "max": 44 + }, + "pitchConfidence": 0.0408, + "midiFile": "/Users/christiansmith/code/projects/asa/.claude/worktrees/goal-doc/apps/backend/tests/fixtures/recommendation_tracks/techno_rumble_130/audio_melody.mid", + "sourceSeparated": false, + "vibratoPresent": false, + "vibratoExtent": 0.0, + "vibratoRate": 0.0, + "vibratoConfidence": 0.0 + }, + "transcriptionDetail": null, + "pitchDetail": null, + "grooveDetail": { + "kickSwing": 0.2177, + "hihatSwing": 0.1902, + "kickAccent": [ + 0.1629, + 0.2912, + 0.3235, + 0.2699, + 0.2839, + 0.3133, + 0.2989, + 0.2833, + 0.3164, + 0.3002, + 0.2831, + 0.3199, + 0.2612, + 0.2821, + 0.3229, + 0.2324 + ], + "hihatAccent": [ + 0.0, + 0.0585, + 0.0343, + 0.038, + 0.0513, + 0.0371, + 0.0518, + 0.0512, + 0.0374, + 0.0516, + 0.0515, + 0.0373, + 0.0375, + 0.0515, + 0.0372, + 0.0534 + ], + "perDrumSwing": { + "kick": 0.2177, + "snare": 0.1897, + "hihat": 0.1902 + } + }, + "beatsLoudness": { + "kickDominantRatio": 0.8378, + "midDominantRatio": 0.0001, + "highDominantRatio": 0.1261, + "patternBeatsPerBar": 4, + "lowBandAccentPattern": [ + 0.9528, + 1.0, + 0.9837, + 0.9664 + ], + "midBandAccentPattern": [ + 1.0, + 0.8492, + 0.8231, + 0.7917 + ], + "highBandAccentPattern": [ + 0.8219, + 0.9758, + 0.9943, + 1.0 + ], + "overallAccentPattern": [ + 0.9409, + 1.0, + 0.9899, + 0.9784 + ], + "accentPattern": [ + 0.9409, + 1.0, + 0.9899, + 0.9784 + ], + "meanBeatLoudness": 0.3442, + "beatLoudnessVariation": 0.1104, + "beatCount": 32 + }, + "rhythmTimeline": { + "beatsPerBar": 4, + "stepsPerBeat": 4, + "availableBars": 8, + "selectionMethod": "representative_dsp_window", + "windows": [ + { + "bars": 8, + "startBar": 1, + "endBar": 8, + "lowBandSteps": [ + 0.1498, + 0.2199, + 0.3454, + 0.2289, + 0.3118, + 0.1847, + 0.552, + 0.3656, + 0.3921, + 0.2272, + 0.9106, + 0.4305, + 0.3708, + 0.2172, + 0.5781, + 0.4217, + 0.3957, + 0.2546, + 0.6056, + 0.4417, + 0.3945, + 0.2336, + 0.9553, + 0.4359, + 0.3914, + 0.2273, + 0.6365, + 0.4303, + 0.371, + 0.2367, + 0.5699, + 0.4218, + 0.3963, + 0.2404, + 1.0, + 0.4415, + 0.3937, + 0.2335, + 0.6179, + 0.4361, + 0.3914, + 0.2483, + 0.6076, + 0.4309, + 0.3716, + 0.2206, + 0.9252, + 0.4229, + 0.3952, + 0.2406, + 0.5943, + 0.4416, + 0.3942, + 0.2548, + 0.5911, + 0.4369, + 0.3922, + 0.2306, + 0.8944, + 0.4309, + 0.3711, + 0.2205, + 0.5845, + 0.4225, + 0.3963, + 0.2609, + 0.569, + 0.4426, + 0.3947, + 0.2373, + 0.9368, + 0.4366, + 0.3918, + 0.2314, + 0.6477, + 0.4313, + 0.3714, + 0.2431, + 0.5421, + 0.4236, + 0.3969, + 0.244, + 0.9775, + 0.4425, + 0.3941, + 0.238, + 0.6299, + 0.4369, + 0.392, + 0.255, + 0.5918, + 0.4318, + 0.3722, + 0.2246, + 0.9005, + 0.4231, + 0.3959, + 0.245, + 0.6121, + 0.4425, + 0.3945, + 0.2612, + 0.5682, + 0.4377, + 0.3922, + 0.2353, + 0.8678, + 0.4313, + 0.3714, + 0.2251, + 0.6031, + 0.4234, + 0.3966, + 0.2669, + 0.5412, + 0.4436, + 0.3948, + 0.2419, + 0.9053, + 0.4372, + 0.3921, + 0.2359, + 0.6658, + 0.432, + 0.0956, + 0.0906, + 0.0784, + 0.0497 + ], + "midBandSteps": [ + 0.4798, + 0.9208, + 0.619, + 0.2355, + 0.3051, + 0.3663, + 0.5164, + 0.6006, + 0.6484, + 0.8311, + 0.7537, + 0.6421, + 0.7244, + 0.8078, + 0.7216, + 0.7756, + 0.9115, + 1.0, + 0.6932, + 0.7218, + 0.7302, + 0.8873, + 0.657, + 0.7695, + 0.7361, + 0.7728, + 0.7996, + 0.733, + 0.7533, + 0.7944, + 0.6427, + 0.8336, + 0.8646, + 0.8928, + 0.6767, + 0.8315, + 0.7812, + 0.936, + 0.8578, + 0.6847, + 0.8163, + 0.8608, + 0.7135, + 0.6937, + 0.7587, + 0.6862, + 0.641, + 0.6643, + 0.9109, + 0.86, + 0.8293, + 0.7906, + 0.6836, + 0.9004, + 0.701, + 0.7966, + 0.7734, + 0.7098, + 0.7465, + 0.6952, + 0.7094, + 0.9085, + 0.7582, + 0.7319, + 0.831, + 0.839, + 0.838, + 0.7418, + 0.7311, + 0.7582, + 0.7843, + 0.8213, + 0.6829, + 0.7875, + 0.632, + 0.7024, + 0.7134, + 0.8968, + 0.7458, + 0.7262, + 0.7735, + 0.8474, + 0.8307, + 0.7436, + 0.7243, + 0.8853, + 0.7734, + 0.6847, + 0.7025, + 0.7472, + 0.6907, + 0.6939, + 0.5987, + 0.7339, + 0.7422, + 0.8117, + 0.8285, + 0.8314, + 0.9189, + 0.7461, + 0.7309, + 0.769, + 0.6771, + 0.798, + 0.7312, + 0.7351, + 0.7179, + 0.7398, + 0.6797, + 0.902, + 0.7799, + 0.7118, + 0.7849, + 0.7917, + 0.7678, + 0.6789, + 0.819, + 0.8179, + 0.679, + 0.7848, + 0.6508, + 0.9159, + 0.6716, + 0.6633, + 0.3101, + 0.0853, + 0.2807, + 0.0728 + ], + "highBandSteps": [ + 0.001, + 0.0001, + 0.0001, + 0.3016, + 0.0455, + 0.0007, + 0.0001, + 0.0003, + 0.7182, + 0.001, + 0.0001, + 0.0006, + 0.6042, + 0.0008, + 0.0007, + 0.0005, + 0.9796, + 0.0004, + 0.0009, + 0.0007, + 0.8509, + 0.0011, + 0.0005, + 0.0003, + 0.7059, + 0.0012, + 0.0, + 0.0003, + 0.6058, + 0.001, + 0.0008, + 0.0, + 0.9922, + 0.001, + 0.0007, + 0.0002, + 0.8394, + 0.0007, + 0.0, + 0.0006, + 0.7078, + 0.0007, + 0.0005, + 0.0005, + 0.6137, + 0.0014, + 0.0005, + 0.0009, + 0.991, + 0.0013, + 0.0004, + 0.0005, + 0.8423, + 0.0007, + 0.0006, + 0.0002, + 0.7128, + 0.0015, + 0.0002, + 0.0005, + 0.6034, + 0.0005, + 0.0003, + 0.0007, + 0.9916, + 0.0013, + 0.0004, + 0.0008, + 0.8515, + 0.0015, + 0.0003, + 0.0, + 0.709, + 0.001, + 0.0008, + 0.0005, + 0.6122, + 0.0005, + 0.0005, + 0.0007, + 1.0, + 0.0013, + 0.0001, + 0.0008, + 0.8428, + 0.0007, + 0.0003, + 0.0006, + 0.7148, + 0.001, + 0.0007, + 0.0005, + 0.6151, + 0.0013, + 0.0, + 0.0002, + 0.988, + 0.0013, + 0.0, + 0.0008, + 0.8491, + 0.0012, + 0.0009, + 0.0002, + 0.7178, + 0.0011, + 0.0002, + 0.0001, + 0.6036, + 0.0005, + 0.0001, + 0.0007, + 0.9924, + 0.0016, + 0.0007, + 0.0009, + 0.846, + 0.0009, + 0.0006, + 0.0002, + 0.7114, + 0.0005, + 0.0006, + 0.0007, + 0.5496, + 0.0, + 0.0003, + 0.0001 + ], + "overallSteps": [ + 0.1562, + 0.2328, + 0.3518, + 0.2434, + 0.3154, + 0.1887, + 0.5544, + 0.3714, + 0.4298, + 0.2385, + 0.9128, + 0.4363, + 0.405, + 0.2283, + 0.5836, + 0.4299, + 0.449, + 0.2684, + 0.6103, + 0.4488, + 0.4392, + 0.2457, + 0.9555, + 0.4438, + 0.4299, + 0.2376, + 0.6426, + 0.4377, + 0.4057, + 0.2473, + 0.5742, + 0.4309, + 0.4495, + 0.2525, + 1.0, + 0.4503, + 0.4388, + 0.2465, + 0.6252, + 0.4426, + 0.4314, + 0.2599, + 0.6127, + 0.4376, + 0.4068, + 0.2296, + 0.9255, + 0.4293, + 0.4491, + 0.2523, + 0.6014, + 0.4498, + 0.4378, + 0.2669, + 0.5961, + 0.4452, + 0.4317, + 0.2399, + 0.8967, + 0.4377, + 0.405, + 0.2331, + 0.5905, + 0.43, + 0.4488, + 0.272, + 0.5765, + 0.45, + 0.4395, + 0.2473, + 0.9393, + 0.4454, + 0.4296, + 0.242, + 0.651, + 0.4381, + 0.4058, + 0.2553, + 0.5484, + 0.4309, + 0.4488, + 0.2554, + 0.9803, + 0.4499, + 0.4384, + 0.25, + 0.6357, + 0.4434, + 0.4304, + 0.2646, + 0.5967, + 0.4385, + 0.4048, + 0.2344, + 0.9027, + 0.4318, + 0.4483, + 0.2561, + 0.6205, + 0.45, + 0.4392, + 0.2711, + 0.5731, + 0.4461, + 0.4312, + 0.2449, + 0.8699, + 0.4388, + 0.4048, + 0.2376, + 0.6093, + 0.4305, + 0.4484, + 0.2771, + 0.5479, + 0.4499, + 0.4408, + 0.2528, + 0.9064, + 0.4453, + 0.4295, + 0.2485, + 0.6695, + 0.4382, + 0.1236, + 0.091, + 0.0822, + 0.0504 + ] + } + ] + }, + "sidechainDetail": { + "pumpingStrength": 0.1677, + "pumpingRegularity": 0.0, + "pumpingRate": null, + "pumpingConfidence": 0.1384, + "envelopeShape": [ + 0.863, + 0.693, + 0.99, + 0.91, + 0.883, + 0.7, + 0.959, + 0.887, + 0.893, + 0.687, + 0.978, + 0.897, + 0.902, + 0.689, + 1.0, + 0.911 + ], + "envelopeShape32": [ + 0.863, + 0.768, + 0.693, + 0.573, + 0.904, + 0.99, + 0.91, + 0.786, + 0.883, + 0.76, + 0.7, + 0.571, + 0.881, + 0.959, + 0.887, + 0.798, + 0.893, + 0.737, + 0.687, + 0.566, + 0.894, + 0.978, + 0.897, + 0.749, + 0.902, + 0.739, + 0.689, + 0.579, + 0.878, + 1.0, + 0.911, + 0.795 + ] + }, + "acidDetail": { + "isAcid": true, + "confidence": 0.6, + "resonanceLevel": 1.0, + "centroidOscillationHz": 27, + "bassRhythmDensity": 2.0 + }, + "reverbDetail": { + "rt60": null, + "isWet": false, + "tailEnergyRatio": null, + "measured": false, + "perBandRt60": null, + "preDelayMs": null + }, + "vocalDetail": { + "hasVocals": false, + "confidence": 0.35, + "vocalEnergyRatio": 0.05, + "formantStrength": 0.27, + "mfccLikelihood": 0.86, + "stemEnergyRatio": null, + "stemOtherCorrelation": null + }, + "supersawDetail": { + "isSupersaw": true, + "confidence": 0.86, + "voiceCount": 7, + "avgDetuneCents": 28.1, + "spectralComplexity": 7.1 + }, + "bassDetail": { + "averageDecayMs": 1000, + "type": "sustained", + "transientRatio": 0.2, + "fundamentalHz": 90, + "transientCount": 0, + "swingPercent": 0, + "grooveType": "straight" + }, + "kickDetail": { + "isDistorted": true, + "thd": 0.27, + "harmonicRatio": 0.91, + "fundamentalHz": 81, + "kickCount": 117 + }, + "genreDetail": { + "genre": "dub-techno", + "confidence": 0.8882, + "secondaryGenre": "ambient", + "genreFamily": "techno", + "topScores": [ + { + "genre": "dub-techno", + "score": 0.8087 + }, + { + "genre": "ambient", + "score": 0.7104 + }, + { + "genre": "dubstep", + "score": 0.6902 + }, + { + "genre": "ambient-techno", + "score": 0.6647 + }, + { + "genre": "pop", + "score": 0.6644 + } + ] + }, + "effectsDetail": { + "gatingDetected": false, + "gatingRate": null, + "gatingRegularity": 0.0, + "gatingEventCount": 1 + }, + "synthesisCharacter": { + "inharmonicity": 0.0781, + "oddToEvenRatio": 1.5557 + }, + "danceability": { + "danceability": 3.9118, + "dfa": 0.2556 + }, + "structure": { + "segments": [ + { + "start": 0.0, + "end": 14.769, + "index": 0 + } + ], + "segmentCount": 1 + }, + "arrangementDetail": { + "noveltyCurve": [ + 0.0, + 0.0, + 0.0002, + 0.0009, + 0.1443, + 0.7084, + 0.3775, + 0.0026, + 0.0043, + 0.011, + 0.0064, + 0.0019, + 0.1551, + 0.6325, + 0.3194, + 0.0038, + 0.009, + 0.028, + 0.0156, + 0.0042, + 0.2341, + 0.9672, + 0.4902, + 0.0061, + 0.0062, + 0.011, + 0.0073, + 0.0066, + 0.1728, + 0.6795, + 0.3403, + 0.0053, + 0.0079, + 0.0215, + 0.0145, + 0.006, + 0.0575, + 0.2256, + 0.1137, + 0.0022, + 0.005, + 0.0137, + 0.0072, + 0.003, + 0.0472, + 0.1493, + 0.0587, + 0.0031, + 0.0034, + 0.0061, + 0.0032, + 0.0023, + 0.0683, + 0.1862, + 0.064, + 0.0018, + 0.0032, + 0.0079, + 0.0036, + 0.0012, + 0.0653, + 0.1252, + 0.0425, + 0.0016, + 0.0082, + 0.0153, + 0.0063, + 0.0005, + 0.1856, + 0.3247, + 0.1085, + 0.0009, + 0.0087, + 0.0152, + 0.0062, + 0.0013, + 0.3606, + 0.5821, + 0.1963, + 0.0036, + 0.0076, + 0.0116, + 0.008, + 0.0036, + 0.2925, + 0.4441, + 0.1508, + 0.0051, + 0.0137, + 0.0254, + 0.0095, + 0.0043, + 0.2533, + 0.4974, + 0.12, + 0.0084, + 0.0095, + 0.0134, + 0.0065, + 0.0069, + 0.1474, + 0.279, + 0.0618, + 0.0054, + 0.0081, + 0.0126, + 0.0036, + 0.0034, + 0.0793, + 0.1322, + 0.0156, + 0.0029, + 0.0076, + 0.0118, + 0.0018, + 0.0017, + 0.1105, + 0.1614, + 0.0033, + 0.0018, + 0.0029, + 0.004, + 0.0009, + 0.0012, + 0.2272, + 0.2864, + 0.0006, + 0.0006, + 0.0087, + 0.0118, + 0.0014, + 0.0013, + 0.2311, + 0.2607, + 0.0014, + 0.0016, + 0.0176, + 0.0184, + 0.0033, + 0.0029, + 0.5383, + 0.5559, + 0.0028, + 0.0031, + 0.0115, + 0.0117, + 0.0022, + 0.002, + 0.7473, + 0.7581, + 0.0059, + 0.0066, + 0.0229, + 0.0249, + 0.0062, + 0.0042, + 0.3851, + 0.3877, + 0.0027, + 0.0029, + 0.0131, + 0.0126, + 0.0047, + 0.0039, + 0.2404, + 0.2194, + 0.0026, + 0.0028, + 0.0056, + 0.0047, + 0.0052, + 0.0052, + 0.1354, + 0.1482, + 0.016, + 0.0018, + 0.0065, + 0.0083, + 0.0021, + 0.0049, + 0.0619, + 0.0586, + 0.0017, + 0.0016, + 0.0098, + 0.0117, + 0.0018, + 0.0657, + 0.3089, + 0.2441, + 0.0009, + 0.002, + 0.0041, + 0.0032, + 0.0009, + 0.0994, + 0.4012, + 0.3042, + 0.0019, + 0.0053, + 0.0134, + 0.0142, + 0.0042, + 0.139, + 0.4193, + 0.283, + 0.0015, + 0.0115, + 0.0279, + 0.0209, + 0.0035, + 0.172, + 0.5373, + 0.3659, + 0.005, + 0.0078, + 0.0108, + 0.0088, + 0.0042, + 0.1566, + 0.467, + 0.3097, + 0.002, + 0.0053, + 0.0126, + 0.0111, + 0.0048, + 0.0638, + 0.1854, + 0.122, + 0.0046, + 0.0094, + 0.0173, + 0.0099, + 0.0023, + 0.0673, + 0.1988, + 0.0892, + 0.0018, + 0.0034, + 0.0067, + 0.0038, + 0.0023, + 0.0828, + 0.2177, + 0.0688, + 0.0006, + 0.0059, + 0.0208, + 0.0087, + 0.0011, + 0.0779, + 0.1887, + 0.056, + 0.0014, + 0.0005 + ], + "noveltyPeaks": [ + { + "time": 1.207, + "strength": 0.9672 + }, + { + "time": 4.435, + "strength": 0.7484 + }, + { + "time": 8.591, + "strength": 1.0 + }, + { + "time": 12.283, + "strength": 0.7182 + }, + { + "time": 14.582, + "strength": 0.1887 + } + ], + "noveltyMean": 0.0909, + "noveltyStdDev": 0.1622 + }, + "segmentLoudness": [ + { + "segmentIndex": 0, + "start": 0.0, + "end": 14.769, + "lufs": -9.5, + "lra": 0.0 + } + ], + "segmentSpectral": [ + { + "segmentIndex": 0, + "barkBands": [ + -22.8842, + -7.4646, + -11.1697, + -22.5971, + -29.5628, + -28.2235, + -26.9773, + -27.5063, + -31.3593, + -34.783, + -35.2757, + -33.9973, + -40.001, + -39.0523, + -41.015, + -42.4412, + -42.5889, + -42.9875, + -43.6306, + -42.7086, + -40.038, + -36.4273, + -36.4679, + -32.6915 + ], + "spectralCentroid": 1027.5, + "spectralRolloff": 1264.3, + "stereoWidth": 0.0, + "stereoCorrelation": 1.0 + } + ], + "segmentStereo": [ + { + "segmentIndex": 0, + "stereoWidth": 0.0, + "stereoCorrelation": 1.0 + } + ], + "segmentKey": [ + { + "segmentIndex": 0, + "key": "F Minor", + "keyConfidence": 0.59 + } + ], + "chordDetail": { + "chordSequence": [ + "Bbm", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "Fm", + "C#", + "C#", + "C#", + "C#", + "C#", + "Fm", + "Fm", + "C#", + "C#", + "C#", + "C#", + "Fm", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#", + "C#" + ], + "chordStrength": 0.641, + "progression": [ + "Bbm", + "C#", + "Fm", + "C#", + "Fm", + "C#", + "Fm", + "C#", + "Fm", + "C#", + "Fm", + "C#", + "Fm", + "C#", + "Fm", + "C#" + ], + "dominantChords": [ + "C#", + "Fm", + "Cm", + "Bbm" + ], + "chordTimeline": [ + { + "startSec": 0.0, + "endSec": 14.814, + "label": "Fm", + "labelLong": "F minor", + "confidence": 0.5423 + } + ], + "chordChangeCount": 0, + "chordTimelineSource": "librosa_viterbi", + "chordTimelineAgreement": false + }, + "perceptual": { + "sharpness": 0.0614, + "roughness": 0.0 + }, + "essentiaFeatures": { + "zeroCrossingRate": 0.0327, + "hfc": 155.3578, + "spectralComplexity": 8.1144, + "dissonance": 0.0 + } +} \ No newline at end of file diff --git a/apps/backend/tests/test_recommendation_evaluation.py b/apps/backend/tests/test_recommendation_evaluation.py new file mode 100644 index 00000000..90c39c7c --- /dev/null +++ b/apps/backend/tests/test_recommendation_evaluation.py @@ -0,0 +1,406 @@ +"""Unit tests for the recommendation-quality scorer (GOAL.md sub-goal 2). + +Pure-stdlib — no Essentia, no network, no rendered audio required. The scoring +logic is exercised with hand-authored fixtures + recommendation sets so the +"does the score move correctly?" gate is fully deterministic and independent of +the needs-fixture corpus audio. +""" + +from __future__ import annotations + +import unittest +from pathlib import Path + +import recommendation_evaluation as rev + +FIXTURE_ROOT = Path(__file__).resolve().parent / "fixtures" / "recommendation_tracks" + + +def _spec(device: str, params: dict[str, str], family: str = "NATIVE") -> rev.SpecDevice: + return rev.SpecDevice( + device=device, + family=family, + parameters=tuple(rev.SpecParameter(name=k, value=v) for k, v in params.items()), + ) + + +def _make_fixture( + device_spec: dict[str, tuple[rev.SpecDevice, ...]], + fingerprint: dict | None = None, +) -> rev.Fixture: + return rev.Fixture( + slug="synthetic", + title="synthetic test fixture", + genre="house", + audio_path=None, + device_spec=device_spec, + measurable_intent=(), + phase1_fingerprint=fingerprint, + render={"sampleRateHz": 48000, "bitDepth": 24}, + ) + + +# A small Phase 1 fingerprint that the test citations resolve against. +FINGERPRINT = { + "bpm": 124, + "key": "A minor", + "kickDetail": {"fundamentalHz": 55.0}, + "sidechainDetail": {"pumpingStrength": 0.6, "pumpingRate": 2.07}, + "lufsIntegrated": -9.0, + "truePeak": 1.0, +} + + +class ValueParsingTests(unittest.TestCase): + def test_units_parse(self): + cases = { + "4 kHz": (4000.0, "hz"), + "3500 Hz": (3500.0, "hz"), + "-15 dB": (-15.0, "db"), + "200 ms": (200.0, "ms"), + "1.8 s": (1.8, "s"), + "3:1": (3.0, "ratio"), + "30%": (30.0, "pct"), + "+12st": (12.0, "st"), + "0.6": (0.6, ""), + } + for text, (num, unit) in cases.items(): + pv = rev.parse_value(text) + self.assertIsNotNone(pv, f"failed to parse {text!r}") + self.assertAlmostEqual(pv.number, num, places=4, msg=text) + self.assertEqual(pv.unit, unit, msg=text) + + def test_non_numeric_returns_none(self): + for text in ("Sine", "Auto", "Lowpass", "On", ""): + self.assertIsNone(rev.parse_value(text), text) + + +class ScoreValueTests(unittest.TestCase): + def test_within_band_full_credit(self): + self.assertEqual( + rev.score_value(rev.parse_value("2 dB"), rev.parse_value("3 dB")), 1.0 + ) + + def test_right_direction_half_credit(self): + # Both boosts vs neutral 0 dB, but |1 - 6| = 5 > 3 dB band. + self.assertEqual( + rev.score_value(rev.parse_value("1 dB"), rev.parse_value("6 dB")), 0.5 + ) + + def test_wrong_direction_zero(self): + self.assertEqual( + rev.score_value(rev.parse_value("-4 dB"), rev.parse_value("6 dB")), 0.0 + ) + + def test_unit_mismatch_zero(self): + self.assertEqual( + rev.score_value(rev.parse_value("4 kHz"), rev.parse_value("4 dB")), 0.0 + ) + + def test_hz_relative_band(self): + # 3200 Hz vs 3500 Hz target, ±20% band = ±700 Hz -> within. + self.assertEqual( + rev.score_value(rev.parse_value("3200 Hz"), rev.parse_value("3500 Hz")), 1.0 + ) + + +class DeviceEquivalenceTests(unittest.TestCase): + def test_exact_match(self): + self.assertTrue(rev.devices_match("Operator", "Operator")) + + def test_equivalent_compressors_match(self): + # The central equivalence caveat: Compressor satisfies a Glue Compressor spec. + self.assertTrue(rev.devices_match("Compressor", "Glue Compressor")) + self.assertTrue(rev.devices_match("Glue Compressor", "Compressor")) + + def test_equivalent_synths_match(self): + self.assertTrue(rev.devices_match("Wavetable", "Operator")) + + def test_unrelated_devices_do_not_match(self): + self.assertFalse(rev.devices_match("Reverb", "Operator")) + self.assertFalse(rev.devices_match("EQ Eight", "Compressor")) + + +class DomainInferenceTests(unittest.TestCase): + def test_track_context_wins(self): + self.assertEqual(rev.infer_domain("Kick bus", "DYNAMICS"), "kick") + self.assertEqual(rev.infer_domain("Bass", "SYNTHESIS"), "bass") + self.assertEqual(rev.infer_domain("Pluck lead", "SYNTHESIS"), "melody") + + def test_category_fallback(self): + self.assertEqual(rev.infer_domain(None, "STEREO"), "stereo") + self.assertEqual(rev.infer_domain(None, "MASTERING"), "master") + + def test_unknown(self): + self.assertEqual(rev.infer_domain(None, None), rev.UNKNOWN_DOMAIN) + + +class CustodyPathTests(unittest.TestCase): + def test_collect_paths(self): + paths = rev.collect_phase1_field_paths(FINGERPRINT) + self.assertIn("kickDetail", paths) + self.assertIn("kickDetail.fundamentalHz", paths) + self.assertIn("sidechainDetail.pumpingStrength", paths) + + def test_path_covers_tracked(self): + self.assertTrue(rev.path_covers_tracked("kickDetail", "kickDetail.fundamentalHz")) + self.assertTrue(rev.path_covers_tracked("kickDetail.fundamentalHz", "kickDetail")) + self.assertTrue( + rev.path_covers_tracked("stemAnalysis.bass.reverbDetail", "stemAnalysis.*.reverbDetail") + ) + self.assertFalse(rev.path_covers_tracked("kickDetail", "bassDetail")) + + +class ScoringTests(unittest.TestCase): + def setUp(self): + self.fixture = _make_fixture( + { + "kick": (_spec("Operator", {"Oscillator A Waveform": "Sine", "Amp Envelope Decay": "250 ms"}),), + "bass": (_spec("Operator", {"Oscillator A Waveform": "Sine", "Filter Frequency": "200 Hz"}),), + "master": (_spec("Glue Compressor", {"Threshold": "-18 dB", "Ratio": "2:1"}),), + }, + fingerprint=FINGERPRINT, + ) + + def _good_recs(self) -> list[rev.NormalizedRec]: + return [ + rev.NormalizedRec("kick", "Operator", "Oscillator A Waveform", "Sine", ("kickDetail.fundamentalHz",)), + rev.NormalizedRec("kick", "Operator", "Amp Envelope Decay", "240 ms", ("kickDetail.fundamentalHz",)), + rev.NormalizedRec("bass", "Operator", "Oscillator A Waveform", "Sine", ("sidechainDetail.pumpingStrength",)), + rev.NormalizedRec("bass", "Operator", "Filter Frequency", "220 Hz", ("bpm",)), + rev.NormalizedRec("master", "Glue Compressor", "Threshold", "-18 dB", ("lufsIntegrated",)), + rev.NormalizedRec("master", "Glue Compressor", "Ratio", "2:1", ("truePeak",)), + ] + + def test_good_recs_score_high(self): + score = rev.score_recommendations(self.fixture, self._good_recs(), "test-good") + self.assertGreater(score.aggregate, 0.8) + # Every specified domain was covered. + for domain in ("kick", "bass", "master"): + self.assertEqual(score.domain_scores[domain].role_recall, 1.0) + + def test_known_bad_rec_lowers_score(self): + """The core sub-goal 2 gate: injecting a known-bad rec moves the score down.""" + good = rev.score_recommendations(self.fixture, self._good_recs(), "good") + bad_recs = [ + # Wrong device for every domain + no citations. + rev.NormalizedRec("kick", "Reverb", "Decay Time", "2 s", ()), + rev.NormalizedRec("bass", "EQ Eight", "Band 1 Gain", "3 dB", ()), + rev.NormalizedRec("master", "Chorus-Ensemble", "Rate", "0.3 Hz", ()), + ] + bad = rev.score_recommendations(self.fixture, bad_recs, "bad") + self.assertLess(bad.aggregate, good.aggregate) + self.assertLess(bad.aggregate, 0.2) + + def test_equivalent_device_earns_recall(self): + """Compressor recommended where the spec says Glue Compressor still recalls.""" + recs = [ + rev.NormalizedRec("master", "Compressor", "Threshold", "-18 dB", ("lufsIntegrated",)), + rev.NormalizedRec("master", "Compressor", "Ratio", "2:1", ("truePeak",)), + ] + score = rev.score_recommendations(self.fixture, recs, "equiv") + self.assertEqual(score.domain_scores["master"].role_recall, 1.0) + + def test_custody_penalty_applies(self): + """Stripping citations lowers the aggregate even with full coverage.""" + cited = rev.score_recommendations(self.fixture, self._good_recs(), "cited") + uncited_recs = [ + rev.NormalizedRec(r.domain, r.device, r.parameter, r.value, ()) + for r in self._good_recs() + ] + uncited = rev.score_recommendations(self.fixture, uncited_recs, "uncited") + self.assertAlmostEqual(cited.raw_aggregate, uncited.raw_aggregate, places=6) + self.assertLess(uncited.aggregate, cited.aggregate) + self.assertEqual(uncited.custody.penalty, 0.0) # nothing cited, no fingerprint credit + + def test_full_coverage_uncited_must_not_outscore_lower_coverage_cited(self): + """GOAL.md 2.d: a high-coverage result that breaks the chain must not win.""" + # High coverage, zero citations. + high_uncited = [ + rev.NormalizedRec(r.domain, r.device, r.parameter, r.value, ()) + for r in self._good_recs() + ] + # Lower coverage (kick only), but fully + validly cited. + low_cited = [ + rev.NormalizedRec("kick", "Operator", "Oscillator A Waveform", "Sine", ("kickDetail.fundamentalHz",)), + ] + high = rev.score_recommendations(self.fixture, high_uncited, "high-uncited") + low = rev.score_recommendations(self.fixture, low_cited, "low-cited") + self.assertGreater(high.raw_aggregate, low.raw_aggregate) # more coverage + self.assertGreaterEqual(low.aggregate, high.aggregate) # but custody wins + + def test_scoring_is_deterministic(self): + """GOAL.md sub-goal 2.Done: re-running on unchanged inputs is deterministic.""" + recs = self._good_recs() + first = rev.score_recommendations(self.fixture, recs, "det").as_dict() + second = rev.score_recommendations(self.fixture, recs, "det").as_dict() + self.assertEqual(first, second) + + def test_baseline_source_scores_floor(self): + baseline = rev.score_recommendations( + self.fixture, rev.normalize_baseline(self.fixture), "baseline" + ) + self.assertEqual(baseline.aggregate, 0.0) + + def test_report_renders(self): + score = rev.score_recommendations(self.fixture, self._good_recs(), "rep") + md = rev.render_markdown_report([score]) + self.assertIn("Recommendation Evaluation Report", md) + self.assertIn("kick", md) + self.assertIn("Aggregate", md) + + +class CorpusVerificationTests(unittest.TestCase): + """Sub-goal 4 data source: per-domain match rates + support drive the badge.""" + + def _fixture(self): + return _make_fixture( + { + "kick": (_spec("Operator", {"Amp Envelope Decay": "250 ms"}),), + "master": (_spec("Glue Compressor", {"Ratio": "2:1"}),), + }, + fingerprint=FINGERPRINT, + ) + + def test_empty_scores_degrade_gracefully(self): + art = rev.aggregate_corpus_verification([]) + self.assertEqual(art["fixtures"], 0) + for domain in rev.DOMAINS: + self.assertEqual(art["perDomain"][domain]["support"], 0) + self.assertEqual(art["perDomain"][domain]["confidence"], "NONE") + + def test_support_drives_confidence_band(self): + fixture = self._fixture() + recs = [ + rev.NormalizedRec("kick", "Operator", "Amp Envelope Decay", "240 ms", ("kickDetail.fundamentalHz",)), + rev.NormalizedRec("master", "Glue Compressor", "Ratio", "2:1", ("lufsIntegrated",)), + ] + # Two fixtures' worth of scores -> support 2 -> LOW band (hedged). + scores = [ + rev.score_recommendations(fixture, recs, "s"), + rev.score_recommendations(fixture, recs, "s"), + ] + art = rev.aggregate_corpus_verification(scores) + self.assertEqual(art["perDomain"]["kick"]["support"], 2) + self.assertEqual(art["perDomain"]["kick"]["confidence"], "LOW") + self.assertGreater(art["perDomain"]["kick"]["meanRecall"], 0.0) + # A domain no fixture specified stays NONE. + self.assertEqual(art["perDomain"]["groove"]["confidence"], "NONE") + + +class IntentCoverageTests(unittest.TestCase): + """GOAL.md equivalence mechanism: measurableIntent paths earn credit when cited.""" + + def _intent_fixture(self): + return rev.Fixture( + slug="intent", + title="intent", + genre="house", + audio_path=None, + device_spec={"kick": (_spec("Operator", {"Amp Envelope Decay": "250 ms"}),)}, + measurable_intent=( + rev.IntentTarget(path="kickDetail.fundamentalHz", target=55, tolerance=15), + rev.IntentTarget(path="lufsIntegrated", target=-9, tolerance=2), + ), + phase1_fingerprint=FINGERPRINT, + render={}, + ) + + def test_intent_coverage_fraction(self): + fx = self._intent_fixture() + recs = [rev.NormalizedRec("kick", "Saturator", "Drive", "8 dB", ("kickDetail.fundamentalHz",))] + # 1 of 2 intent paths cited. + self.assertAlmostEqual(rev.intent_coverage(recs, fx), 0.5) + + def test_empty_intent_is_full(self): + fx = _make_fixture({"kick": (_spec("Operator", {"Amp Envelope Decay": "250 ms"}),)}) + self.assertEqual(rev.intent_coverage([], fx), 1.0) + + def test_intent_credit_rewards_measurement_grounded_recs(self): + """A processing rec that cites the spec's measurable intent earns credit + even though it names a different device than the source synth.""" + fx = self._intent_fixture() + # Names Saturator (not the spec's Operator) but cites both intent paths. + grounded = [ + rev.NormalizedRec("kick", "Saturator", "Drive", "8 dB", + ("kickDetail.fundamentalHz", "lufsIntegrated")), + ] + ungrounded = [ + rev.NormalizedRec("kick", "Saturator", "Drive", "8 dB", ("bpm",)), + ] + g = rev.score_recommendations(fx, grounded, "grounded") + u = rev.score_recommendations(fx, ungrounded, "ungrounded") + self.assertEqual(g.intent_coverage, 1.0) + self.assertLess(u.intent_coverage, g.intent_coverage) + self.assertGreater(g.aggregate, u.aggregate) + + +class Phase2AdapterTests(unittest.TestCase): + def test_normalize_phase2(self): + phase2 = { + "abletonRecommendations": [ + { + "device": "Operator", + "trackContext": "Kick", + "category": "SYNTHESIS", + "parameter": "Amp Envelope Decay", + "value": "250 ms", + "phase1Fields": ["kickDetail.fundamentalHz"], + }, + ], + "mixAndMasterChain": [ + { + "device": "Glue Compressor", + "parameter": "Threshold", + "value": "-18 dB", + "phase1Fields": ["lufsIntegrated"], + }, + ], + } + recs = rev.normalize_phase2(phase2) + self.assertEqual(len(recs), 2) + self.assertEqual(recs[0].domain, "kick") + self.assertEqual(recs[0].citations, ("kickDetail.fundamentalHz",)) + self.assertEqual(recs[1].domain, "master") # mix chain defaults to master + + +class AuthoredFixtureCatalogTests(unittest.TestCase): + """Regression: every committed example spec is catalog-valid.""" + + def test_example_fixtures_are_catalog_valid(self): + manifests = sorted(FIXTURE_ROOT.glob("*/manifest.json")) + self.assertGreaterEqual(len(manifests), 2, "expected >=2 example fixtures") + corpus_domains: set[str] = set() + for manifest in manifests: + fixture = rev.load_fixture(manifest) + issues = rev.validate_fixture_spec(fixture) + self.assertEqual( + issues, [], f"{fixture.slug} has catalog issues: {[i.message for i in issues]}" + ) + # GOAL.md: each fixture isolates a few decisions (>=3 domains), and the + # corpus collectively covers the full production surface (invariant #5). + domains = set(fixture.domains_with_spec()) + self.assertGreaterEqual( + len(domains), 3, f"{fixture.slug} should exercise at least 3 domains" + ) + corpus_domains |= domains + self.assertEqual( + corpus_domains, set(rev.DOMAINS), + f"corpus does not cover all domains; missing {set(rev.DOMAINS) - corpus_domains}", + ) + + def test_invalid_spec_is_caught(self): + bad = _make_fixture( + { + "kick": (_spec("Notadevice", {"Foo": "1"}),), + "bass": (_spec("Operator", {"Nonexistent Param": "1"}),), + } + ) + issues = rev.validate_fixture_spec(bad) + messages = " ".join(i.message for i in issues) + self.assertIn("not in catalog", messages) + self.assertIn("not allowed", messages) + + +if __name__ == "__main__": + unittest.main() diff --git a/apps/ui/src/components/AnalysisResults.tsx b/apps/ui/src/components/AnalysisResults.tsx index 465c030a..5010c2f5 100644 --- a/apps/ui/src/components/AnalysisResults.tsx +++ b/apps/ui/src/components/AnalysisResults.tsx @@ -46,6 +46,7 @@ import { PhaseSourceBadge } from './PhaseSourceBadge'; import { StickyNav, type StickyNavSection } from './StickyNav'; import { CitationBlock, CitationHeadline } from './CitationBlock'; import { ConfidenceBandBadge } from './sessionMusician/ConfidenceBandBadge'; +import { RecommendationVerificationBadge } from './RecommendationVerificationBadge'; import { toConfidenceBand } from '../services/sessionMusician/confidenceBand'; import { loadAppliedIds, toggleAppliedId } from '../services/appliedRecommendations'; import { @@ -2139,6 +2140,10 @@ export function AnalysisResults({ {card.category} + {/* Audit Finding #3: primary citation visible in the collapsed header so the chain-of-custody @@ -2308,6 +2313,10 @@ export function AnalysisResults({ {patch.category} + {/* Audit Finding #3: primary citation in the collapsed header so the chain-of-custody diff --git a/apps/ui/src/components/RecommendationVerificationBadge.tsx b/apps/ui/src/components/RecommendationVerificationBadge.tsx new file mode 100644 index 00000000..f286ec22 --- /dev/null +++ b/apps/ui/src/components/RecommendationVerificationBadge.tsx @@ -0,0 +1,68 @@ +/** + * Per-recommendation corpus-verification badge (GOAL.md sub-goal 4). + * + * Shows whether a recommendation type has been validated against the + * ground-truth corpus, and how strongly, grounded in + * `aggregate_corpus_verification`'s per-domain match rate + support. Honest per + * PURPOSE.md invariant #4: support drives the band, and the no-evidence case + * (confidence NONE — the current pre-render state for the whole corpus) renders + * nothing rather than implying a verification that does not exist. + * + * Built on the `ui/` Pill primitive + tokens (no one-off styled boxes). The + * hover detail uses the native `title` attribute to avoid a Radix tooltip + * provider dependency on the recommendation card. + */ + +import { Pill } from './ui/Pill'; +import type { VerificationConfidence } from '../data/recommendationVerification'; +import { verificationForRecommendation } from '../services/recommendationVerification'; + +type Tone = 'success' | 'warning'; +type Variant = 'solid' | 'outline'; + +const PRESENTATION: Record< + Exclude, + { tone: Tone; variant: Variant; label: string } +> = { + HIGH: { tone: 'success', variant: 'solid', label: 'Corpus-verified' }, + MED: { tone: 'success', variant: 'outline', label: 'Corpus-checked' }, + LOW: { tone: 'warning', variant: 'outline', label: 'Lightly checked' }, +}; + +export interface RecommendationVerificationBadgeProps { + trackContext?: string | null; + category?: string | null; +} + +export function RecommendationVerificationBadge({ + trackContext, + category, +}: RecommendationVerificationBadgeProps) { + const verification = verificationForRecommendation({ trackContext, category }); + if (!verification || verification.confidence === 'NONE') { + // Graceful degradation: no corpus evidence for this card -> no badge. + return null; + } + const { tone, variant, label } = PRESENTATION[verification.confidence]; + const recallPct = Math.round(verification.meanRecall * 100); + const title = + `Corpus support: ${verification.support} fixture(s); ` + + `mean device-role recall ${recallPct}%.` + + (verification.confidence === 'LOW' + ? ' Low corpus support — treat as tentative.' + : ''); + + return ( + + {label} + + ); +} diff --git a/apps/ui/src/data/recommendationVerification.ts b/apps/ui/src/data/recommendationVerification.ts new file mode 100644 index 00000000..7b26b05d --- /dev/null +++ b/apps/ui/src/data/recommendationVerification.ts @@ -0,0 +1,53 @@ +/** + * Corpus-verification artifact — the data source for the per-recommendation + * verification badge (GOAL.md sub-goal 4). + * + * GENERATED. Regenerate after scoring the corpus: + * ./venv/bin/python apps/backend/scripts/evaluate_recommendations.py \ + * --source gemini --verification-artifact /tmp/verification.json + * + * ⚠️ The current values are from SYNTHETIC PROXY renders (not Ableton) scored + * against the live Gemini source — see apps/backend/RECOMMENDATION_VERDICT.md. + * Re-generate from real Live renders for authoritative bands. Confidence factors + * BOTH corpus support and observed match quality (invariant #4): a domain the + * corpus exercised but where recs rarely matched stays NONE/LOW, never confident. + */ + +export type VerificationConfidence = 'NONE' | 'LOW' | 'MED' | 'HIGH'; + +/** The seven production domains (PURPOSE.md invariant #5). */ +export type RecommendationDomain = + | 'kick' + | 'bass' + | 'melody' + | 'groove' + | 'fx' + | 'stereo' + | 'master'; + +export interface DomainVerification { + support: number; + meanRecall: number; + meanScore: number; + confidence: VerificationConfidence; +} + +export interface RecommendationVerificationArtifact { + fixtures: number; + sources: string[]; + perDomain: Record; +} + +export const RECOMMENDATION_VERIFICATION: RecommendationVerificationArtifact = { + fixtures: 5, + sources: ["gemini"], + perDomain: { + kick: { support: 5, meanRecall: 0.0, meanScore: 0.0, confidence: "NONE" }, + bass: { support: 5, meanRecall: 0.2, meanScore: 0.11, confidence: "LOW" }, + melody: { support: 5, meanRecall: 0.6, meanScore: 0.325, confidence: "LOW" }, + groove: { support: 5, meanRecall: 0.0, meanScore: 0.0, confidence: "NONE" }, + fx: { support: 5, meanRecall: 0.0, meanScore: 0.0, confidence: "NONE" }, + stereo: { support: 5, meanRecall: 0.0, meanScore: 0.0, confidence: "NONE" }, + master: { support: 5, meanRecall: 0.5, meanScore: 0.5504, confidence: "MED" }, + }, +}; diff --git a/apps/ui/src/services/recommendationVerification.ts b/apps/ui/src/services/recommendationVerification.ts new file mode 100644 index 00000000..5b4f1a1f --- /dev/null +++ b/apps/ui/src/services/recommendationVerification.ts @@ -0,0 +1,96 @@ +/** + * Maps a recommendation to its corpus-verification status for the UI badge + * (GOAL.md sub-goal 4). Pure logic — node-environment testable (no DOM). + * + * Domain inference mirrors `recommendation_evaluation.infer_domain` in the + * backend scorer so the badge attributes a card to the same domain the harness + * scored it under: track context wins (it is specific — "Kick bus", "Bass", + * "Master"), then category, else no domain (→ no badge). + */ + +import { + RECOMMENDATION_VERIFICATION, + type DomainVerification, + type RecommendationDomain, + type RecommendationVerificationArtifact, +} from '../data/recommendationVerification'; + +// Keyword -> domain, mirroring the backend's _DOMAIN_KEYWORDS ordering (longer / +// more specific phrases first). +const DOMAIN_KEYWORDS: ReadonlyArray = [ + ['kick', 'kick'], + ['sub bass', 'bass'], + ['bassline', 'bass'], + ['bass', 'bass'], + ['808', 'bass'], + ['lead', 'melody'], + ['melod', 'melody'], + ['arp', 'melody'], + ['pluck', 'melody'], + ['chord', 'melody'], + ['pad', 'melody'], + ['synth', 'melody'], + ['harmon', 'melody'], + ['hi-hat', 'groove'], + ['hihat', 'groove'], + ['hat', 'groove'], + ['perc', 'groove'], + ['snare', 'groove'], + ['clap', 'groove'], + ['drum', 'groove'], + ['groove', 'groove'], + ['width', 'stereo'], + ['stereo', 'stereo'], + ['pan', 'stereo'], + ['imaging', 'stereo'], + ['master', 'master'], + ['mix bus', 'master'], +]; + +const CATEGORY_DOMAIN: Readonly> = { + STEREO: 'stereo', + MASTERING: 'master', + MIDI: 'groove', +}; + +/** + * Best-effort production-domain inference for a recommendation. Returns null + * when the card cannot be attributed (the badge then renders nothing). + */ +export function inferRecommendationDomain( + trackContext?: string | null, + category?: string | null, +): RecommendationDomain | null { + if (trackContext) { + const low = trackContext.toLowerCase(); + for (const [keyword, domain] of DOMAIN_KEYWORDS) { + if (low.includes(keyword)) return domain; + } + } + if (category) { + const mapped = CATEGORY_DOMAIN[category.toUpperCase()]; + if (mapped) return mapped; + } + return null; +} + +/** Verification entry for a domain, or null if the artifact has no entry. */ +export function verificationForDomain( + domain: RecommendationDomain | null, + artifact: RecommendationVerificationArtifact = RECOMMENDATION_VERIFICATION, +): DomainVerification | null { + if (!domain) return null; + return artifact.perDomain[domain] ?? null; +} + +/** + * Resolve a recommendation card to its verification entry. Returns null when the + * card has no inferable domain — the badge degrades to rendering nothing. + */ +export function verificationForRecommendation( + rec: { trackContext?: string | null; category?: string | null }, + artifact: RecommendationVerificationArtifact = RECOMMENDATION_VERIFICATION, +): DomainVerification | null { + const domain = inferRecommendationDomain(rec.trackContext, rec.category); + return verificationForDomain(domain, artifact); +} diff --git a/apps/ui/tests/services/recommendationVerification.test.ts b/apps/ui/tests/services/recommendationVerification.test.ts new file mode 100644 index 00000000..8a80d898 --- /dev/null +++ b/apps/ui/tests/services/recommendationVerification.test.ts @@ -0,0 +1,68 @@ +import { describe, it, expect } from 'vitest'; + +import { + inferRecommendationDomain, + verificationForDomain, + verificationForRecommendation, +} from '../../src/services/recommendationVerification'; +import { + RECOMMENDATION_VERIFICATION, + type RecommendationVerificationArtifact, +} from '../../src/data/recommendationVerification'; + +describe('inferRecommendationDomain', () => { + it('prefers track context over category', () => { + expect(inferRecommendationDomain('Kick bus', 'DYNAMICS')).toBe('kick'); + expect(inferRecommendationDomain('Bass', 'SYNTHESIS')).toBe('bass'); + expect(inferRecommendationDomain('Pluck lead', 'SYNTHESIS')).toBe('melody'); + expect(inferRecommendationDomain('Master bus', 'EQ')).toBe('master'); + }); + + it('falls back to category when context is silent', () => { + expect(inferRecommendationDomain(null, 'STEREO')).toBe('stereo'); + expect(inferRecommendationDomain(undefined, 'MASTERING')).toBe('master'); + }); + + it('returns null when nothing is attributable', () => { + expect(inferRecommendationDomain(null, null)).toBeNull(); + expect(inferRecommendationDomain('', 'EQ')).toBeNull(); + }); +}); + +describe('verificationForDomain', () => { + it('reads the per-domain entry', () => { + const entry = verificationForDomain('kick'); + expect(entry).not.toBeNull(); + expect(entry?.confidence).toBe('NONE'); // pre-render corpus state + }); + + it('returns null for a null domain', () => { + expect(verificationForDomain(null)).toBeNull(); + }); +}); + +describe('verificationForRecommendation', () => { + it('degrades to NONE (graceful) with the empty pre-render artifact', () => { + const v = verificationForRecommendation({ trackContext: 'Kick', category: 'SYNTHESIS' }); + expect(v?.confidence).toBe('NONE'); + }); + + it('returns null when the card has no inferable domain', () => { + expect(verificationForRecommendation({ trackContext: null, category: null })).toBeNull(); + }); + + it('surfaces a confident band once the corpus carries evidence', () => { + const populated: RecommendationVerificationArtifact = { + ...RECOMMENDATION_VERIFICATION, + fixtures: 6, + sources: ['gemini'], + perDomain: { + ...RECOMMENDATION_VERIFICATION.perDomain, + kick: { support: 6, meanRecall: 0.9, meanScore: 0.82, confidence: 'HIGH' }, + }, + }; + const v = verificationForRecommendation({ trackContext: 'Kick', category: 'SYNTHESIS' }, populated); + expect(v?.confidence).toBe('HIGH'); + expect(v?.meanRecall).toBeCloseTo(0.9); + }); +});