From e115867d68fe84070b25b74dee99ad320cbe35d6 Mon Sep 17 00:00:00 2001 From: prompt.ac/@jeffrey Date: Thu, 20 Aug 2026 04:40:11 +0000 Subject: [PATCH] loner: Lonerclub — one sentence, six passes, and a chart per take The record is Camille Klein's whistlegraph "loner" regulated onto a 122 floor: her line sung whole six times, the band telling the passes apart. THE OPENING /s/ went missing twice, for two different reasons, and both were structural rather than a matter of level. voice_line places a phrase at at(bar) − leadIn so the VOWEL lands on the beat and the consonant runs 1:1 before it — at bar 0 that is negative time, and emit() drops anything before sample 0, so the 220 ms sibilant was never written to the file. And WORLD systematically under-renders fricatives: the voiced half gets the formant lift, the air shelf and the breath, the unvoiced half is copied from the warped source and gets none of them, widening her own 15 dB vowel-to-/s/ gap to 19. halo3 now finds frames that are unvoiced AND bright — the same dim-but-bright test audit.py uses — and gives them 8 dB back. The record opens on the /s/ at 6 ms: PREROLL is exactly the phrase's own leadIn, so there is no silence and nothing is trimmed. A CHART PER TAKE (bin/takechart.py). The chart was two kinds of number tangled together: the composition (beats, durs, and the melody) and f-'s performance (13 hand-pinned onsets, 5 syllable seams, end — all seconds into one wav). singdub applied both, and never read lead/ants at all, so every other take arrived wearing one singer's phrasing with no consonant runway. Takes are now assembled from their per-word corpus files, which makes the 18 onsets exact, and only the seams need finding — in that take's own voice. Each then runs the whole halo3 pipeline. Three bugs found along the way, all real beyond this lane: · FLOOR was 140 Hz, set for her 283 Hz take. Ten of nineteen takes sing under it, and harvest below its floor returns the second harmonic, not a low note. The bracket is now measured per voice — and only ever widens, so the spine's 140/600 is untouched. · THE HOLD read the source analysis to pick its sustained tone, which silently undid the melody lock on every long note. "of" — the one octave leap in the lyric — came out 16 semitones under the chart. · singdub mapped words to units by index. 18 words against 24 units meant six words sung TWICE on adjacent notes. THE ARRANGEMENT is one voice, no background vocals, and a kit of kick, one offbeat hat and a clap. Swing at 0.575 with correlated per-bar lean rather than per-hit jitter; ghost snares brushed low; 3-against-4 and 5-against-4 running quietly underneath. A hook lifted from her first four notes (7 5 3 2) is stated at the head of each pass and answered by its inversion four bars later, handed to a different instrument each time. Claude-Session: https://claude.ai/code/session_01C7GM9itHCF6nXfnc62Dkdy --- chart-wizard/.gitignore | 2 ++ chart-wizard/Package.swift | 14 ++++++++++++++ chart-wizard/Sources/ChartWizard/AppDelegate.swift | 45 +++++++++++++++++++++++++++++++++++++++++++++ chart-wizard/Sources/ChartWizard/ChartModel.swift | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ chart-wizard/Sources/ChartWizard/RollView.swift | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ chart-wizard/Sources/ChartWizard/WarpEngine.swift | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ chart-wizard/Sources/ChartWizard/WizardController.swift | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ chart-wizard/Sources/ChartWizard/main.swift | 17 +++++++++++++++++ pop/lib/nervox.py | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pop/loner/.gitignore | 7 +++++++ pop/loner/bin/audit.py | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------- pop/loner/bin/dub.py | 388 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pop/loner/bin/halo3.py | 588 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------------- pop/loner/bin/singdub.py | 397 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pop/loner/bin/stage-takes.sh | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pop/loner/bin/takechart.py | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pop/loner/bin/takes.py | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pop/loner/bin/timeline.py | 9 +++++++-- pop/loner/bin/tryout-takes.sh | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pop/loner/bin/tryout.py | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pop/loner/bin/wizard.py | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pop/loner/c/cut-club.sh | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pop/loner/c/loner-chart.h | 350 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------ pop/loner/c/lonerremix.c | 1348 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ pop/loner/covers/club-floor.illy.txt | 31 +++++++++++++++++++++++++++++++ pop/loner/covers/lonerclub-cover-a-score-international.png | 0 pop/loner/covers/lonerclub-cover-a-score-international.png.illy.json | 44 ++++++++++++++++++++++++++++++++++++++++++++ pop/loner/covers/lonerclub-cover-b-stone.png | 0 pop/loner/covers/lonerclub-cover-b-stone.png.illy.json | 43 +++++++++++++++++++++++++++++++++++++++++++ pop/loner/covers/lonerclub-cover-c-club-floor.png | 0 pop/loner/covers/lonerclub-cover-c-club-floor.png.illy.json | 44 ++++++++++++++++++++++++++++++++++++++++++++ pop/loner/covers/refs/loner-curl-row.png | 0 pop/loner/covers/refs/loner-score-small.png | 0 pop/loner/covers/refs/loner-score.png | 0 pop/loner/covers/score-international.illy.txt | 36 ++++++++++++++++++++++++++++++++++++ pop/loner/covers/stone.illy.txt | 32 ++++++++++++++++++++++++++++++++ pop/loner/samples/.align.json | 72 ++++++++++++++++++++++++++++++++++++------------------------------------ pop/loner/samples/.manifest.json | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------------------------------------------------------------- pop/loner/samples/.takecharts.json | 3242 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pop/loner/samples/.takes.json | 625 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pop/loner/vox-dub/.carrier-da.mp3 | 0 pop/loner/vox-dub/.carrier-es.mp3 | 0 pop/loner/vox-dub/.carrier-fr.mp3 | 0 pop/loner/vox-dub/.carrier-hi.mp3 | 0 pop/loner/vox-dub/.carrier-ru.mp3 | 0 pop/loner/vox-dub/.dub.json | 29 +++++++++++++++++++++++++++++ pop/loner/vox-dub/.voice.json | 26 ++++++++++++++++++++++++++ pop/loner/vox-dub/.words.json | 681 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pop/loner/vox-dub/spoken-da.mp3 | 0 pop/loner/vox-dub/spoken-es.mp3 | 0 pop/loner/vox-dub/spoken-fr.mp3 | 0 pop/loner/vox-dub/sts-da.mp3 | 0 pop/loner/vox-dub/sts-es.mp3 | 0 pop/loner/vox-dub/sts-fr.mp3 | 0 pop/loner/vox-dub/sts-hi.mp3 | 0 pop/loner/vox-dub/sts-ru.mp3 | 0 pop/loner/vox-dub/whole-line-dub-da.mp3 | 0 pop/loner/vox-dub/whole-line-dub-es.mp3 | 0 pop/loner/vox-dub/whole-line-dub-fr.mp3 | 0 pop/loner/vox4/.chart.json | 2937 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------------------------------------------------- pop/loner/vox4/.manifest.json | 2885 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------------------------------------------------------------- pop/loner/vox4/.wizard.json | 1 + 62 file(s) changed, 15261 insertion(s)(+), 812 deletion(s)(-) diff --git a/chart-wizard/.gitignore b/chart-wizard/.gitignore new file mode 100644 --- /dev/null +++ b/chart-wizard/.gitignore @@ -0,0 +1,2 @@ +.build/ +bin/ diff --git a/chart-wizard/Package.swift b/chart-wizard/Package.swift new file mode 100644 --- /dev/null +++ b/chart-wizard/Package.swift @@ -0,0 +1,14 @@ +// swift-tools-version:5.9 +import PackageDescription + +let package = Package( + name: "ChartWizard", + platforms: [.macOS(.v12)], + targets: [ + .executableTarget( + name: "ChartWizard", + path: "Sources/ChartWizard", + resources: [.copy("Assets")] + ), + ] +) diff --git a/chart-wizard/Sources/ChartWizard/AppDelegate.swift b/chart-wizard/Sources/ChartWizard/AppDelegate.swift new file mode 100644 --- /dev/null +++ b/chart-wizard/Sources/ChartWizard/AppDelegate.swift @@ -0,0 +1,45 @@ +import AppKit + +final class ChartWizardAppDelegate: NSObject, NSApplicationDelegate { + var wizard: WizardController? + + func applicationDidFinishLaunching(_ notification: Notification) { + let args = CommandLine.arguments + let path = args.count >= 2 ? args[1] : defaultLane() + do { + let model = try ChartModel(wizardJSON: URL(fileURLWithPath: path)) + let w = WizardController(model: model) + wizard = w + w.showWindow(nil) + NSApp.activate(ignoringOtherApps: true) + } catch { + let a = NSAlert() + a.messageText = "ChartWizard could not open that chart" + a.informativeText = """ + \(error.localizedDescription) + + Expecting a lane's vox4/.wizard.json — build one with + pop/.venv/bin/python pop//bin/wizard.py + """ + a.runModal() + NSApp.terminate(nil) + } + } + + /// With no argument, open whichever lane most recently emitted one. + private func defaultLane() -> String { + let fm = FileManager.default + let pop = URL(fileURLWithPath: fm.currentDirectoryPath).appendingPathComponent("pop") + let lanes = (try? fm.contentsOfDirectory(at: pop, includingPropertiesForKeys: nil)) ?? [] + let charts = lanes.map { $0.appendingPathComponent("vox4/.wizard.json") } + .filter { fm.fileExists(atPath: $0.path) } + let newest = charts.max { + let a = (try? $0.resourceValues(forKeys: [.contentModificationDateKey]).contentModificationDate) ?? .distantPast + let b = (try? $1.resourceValues(forKeys: [.contentModificationDateKey]).contentModificationDate) ?? .distantPast + return a < b + } + return newest?.path ?? pop.appendingPathComponent("loner/vox4/.wizard.json").path + } + + func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { true } +} diff --git a/chart-wizard/Sources/ChartWizard/ChartModel.swift b/chart-wizard/Sources/ChartWizard/ChartModel.swift new file mode 100644 --- /dev/null +++ b/chart-wizard/Sources/ChartWizard/ChartModel.swift @@ -0,0 +1,237 @@ +// ChartModel.swift — the chart, in memory, and the sidecar it writes back. +// +// Reads pop//vox4/.wizard.json (bin/wizard.py) and writes +// pop//chart-edits.json, which halo3.py merges over its CHART +// literal. The GUI never touches the Python: the CHART keeps the prose +// explaining every number, and this file keeps only numbers. +import Foundation + +struct Unit: Codable { + var t: String // the word or syllable as it is sung + var beat: Double // where the block sits on the grid + var dur: Double // how many beats it holds + var st: Double // her measured semitone, vs the lane tonic + var src0: Double // which piece of the take the block plays, + var src1: Double // in slice seconds + + // which CHART knob owns this block's left edge (halo3 emits it) + var pin: Int? // pre-split word index + var cut: CutKind? // nil = the word's own start; k = its k-th + // syllable cut; .auto = halo3 found it +} + +enum CutKind: Codable, Equatable { + case syllable(Int) + case auto + + init(from decoder: Decoder) throws { + let c = try decoder.singleValueContainer() + if let k = try? c.decode(Int.self) { self = .syllable(k) } + else { self = .auto } + } + func encode(to encoder: Encoder) throws { + var c = encoder.singleValueContainer() + switch self { + case .syllable(let k): try c.encode(k) + case .auto: try c.encode("auto") + } + } + var isDraggable: Bool { self != .auto } +} + +struct Event: Codable { + var a: Double + var b: Double + var kind: String // NOTE · FRIC · PUFF + var st: Double? +} + +struct Frames: Codable { + var st: [Double?] // semitones vs tonic, nil where unvoiced + var db: [Double] // level, dB below the take's peak + var hf: [Double] // share of energy above 3 kHz +} + +struct Phrase: Codable { + var slice: String + var wav: String + var sr: Int + var leadIn: Double + var beats: Double + var units: [Unit] + var events: [Event] + var frames: Frames +} + +struct ChartDoc: Codable { + var lane: String + var bpm: Double + var tonic: Double + var frame_s: Double + var phrases: [String: Phrase] +} + +// ── what a drag writes ──────────────────────────────────────────────── +// Only the four knobs the roll can move. Everything else in the CHART — +// the stretch caps, nohold, end — stays where its reasons are written. +struct PhraseEdits: Codable { + var times: [String: Double]? + var sylls: [String: [[SyllCut]]]? + var durs: [String: Double]? + var gaps: [String: Double]? +} + +// a syllable cut is [seconds-or-null, label] in the Python literal, so it +// has to survive a round trip through a heterogeneous JSON array. +enum SyllCut: Codable { + case time(Double) + case none + case label(String) + + init(from decoder: Decoder) throws { + let c = try decoder.singleValueContainer() + if c.decodeNil() { self = .none } + else if let d = try? c.decode(Double.self) { self = .time(d) } + else { self = .label(try c.decode(String.self)) } + } + func encode(to encoder: Encoder) throws { + var c = encoder.singleValueContainer() + switch self { + case .time(let d): try c.encode(d) + case .none: try c.encodeNil() + case .label(let s): try c.encode(s) + } + } +} + +final class ChartModel { + let doc: ChartDoc + let laneDir: URL + private(set) var name: String + private(set) var units: [Unit] + private(set) var dirty = false + + var phrase: Phrase { doc.phrases[name]! } + var bpm: Double { doc.bpm } + var secondsPerBeat: Double { 60.0 / doc.bpm } + + init(wizardJSON: URL) throws { + let data = try Data(contentsOf: wizardJSON) + doc = try JSONDecoder().decode(ChartDoc.self, from: data) + // …/pop//vox4/.wizard.json → …/pop/ + laneDir = wizardJSON.deletingLastPathComponent().deletingLastPathComponent() + guard let first = doc.phrases.keys.sorted().first else { + throw NSError(domain: "ChartWizard", code: 1, userInfo: [ + NSLocalizedDescriptionKey: "no phrases in \(wizardJSON.lastPathComponent)"]) + } + name = first + units = doc.phrases[first]!.units + } + + func select(phrase p: String) { + guard let ph = doc.phrases[p] else { return } + name = p + units = ph.units + } + + // ── the two drags ──────────────────────────────────────────────── + // A block's LEFT EDGE is where her word begins in the take. Moving it + // moves the previous block's end with it — the warp is one sequential + // frame map, so units cannot overlap and cannot leave a hole. + func moveBoundary(_ i: Int, toSource t: Double) { + guard i > 0, i < units.count, units[i].cut?.isDraggable ?? true else { return } + let lo = units[i - 1].src0 + 0.040 // never starve a neighbour + let hi = units[i].src1 - 0.040 + let t = min(max(t, lo), hi) + units[i].src0 = t + units[i - 1].src1 = t + dirty = true + } + + // A block's POSITION on the grid. Moving it right takes beats from the + // rest before it and gives them back to the rest after, so everything + // downstream keeps the bar it already has — which is how this chart has + // been tuned by hand all along. + func moveBlock(_ i: Int, toBeat b: Double) { + guard i >= 0, i < units.count else { return } + let lo = i > 0 ? units[i - 1].beat + units[i - 1].dur : 0 + let hi = i + 1 < units.count ? units[i + 1].beat - units[i].dur : doc.phrases[name]!.beats - units[i].dur + units[i].beat = min(max(b, lo), max(lo, hi)) + dirty = true + } + + // A block's RIGHT EDGE is how long it holds — the beats it is warped + // into, not how much audio it owns. + func resizeBlock(_ i: Int, toDur d: Double) { + guard i >= 0, i < units.count else { return } + let hi = i + 1 < units.count ? units[i + 1].beat - units[i].beat : doc.phrases[name]!.beats - units[i].beat + units[i].dur = min(max(d, 0.25), max(0.25, hi)) + dirty = true + } + + func revert() { + units = doc.phrases[name]!.units + dirty = false + } + + // ── the sidecar ────────────────────────────────────────────────── + var editsURL: URL { laneDir.appendingPathComponent("chart-edits.json") } + + /// Only what actually moved. A block left alone writes nothing, so the + /// sidecar stays a short list of this session's decisions rather than a + /// second copy of the chart. + func edits() -> PhraseEdits { + let original = doc.phrases[name]!.units + var times: [String: Double] = [:] + var sylls: [String: [[SyllCut]]] = [:] + var durs: [String: Double] = [:] + var gaps: [String: Double] = [:] + + for (i, u) in units.enumerated() where i < original.count { + let o = original[i] + if abs(u.src0 - o.src0) > 1e-4, let pin = u.pin { + switch u.cut { + case nil: + times["\(pin)"] = round(u.src0 * 1000) / 1000 + case .syllable: + // one word's cuts are one list, so rebuild the whole + // list from every unit sharing this pin. + let family = units.filter { $0.pin == pin } + .sorted { $0.src0 < $1.src0 } + sylls["\(pin)"] = [family.enumerated().map { (k, f) -> [SyllCut] in + k == 0 ? [.none, .label(f.t)] + : [.time(round(f.src0 * 1000) / 1000), .label(f.t)] + }].flatMap { $0 } + case .auto: + break + } + } + if abs(u.dur - o.dur) > 1e-4 { durs["\(i)"] = round(u.dur * 100) / 100 } + // a block's grid position is the rest in front of it + let prevEnd = i > 0 ? units[i - 1].beat + units[i - 1].dur : 0 + let origPrevEnd = i > 0 ? original[i - 1].beat + original[i - 1].dur : 0 + let gap = u.beat - prevEnd, origGap = o.beat - origPrevEnd + if i > 0, abs(gap - origGap) > 1e-4 { + gaps["\(i - 1)"] = round(gap * 100) / 100 + } + } + return PhraseEdits(times: times.isEmpty ? nil : times, + sylls: sylls.isEmpty ? nil : sylls, + durs: durs.isEmpty ? nil : durs, + gaps: gaps.isEmpty ? nil : gaps) + } + + /// Merge into whatever is already on disk — another phrase's edits from + /// an earlier session must survive saving this one. + func save() throws { + var all: [String: PhraseEdits] = [:] + if let data = try? Data(contentsOf: editsURL) { + all = (try? JSONDecoder().decode([String: PhraseEdits].self, from: data)) ?? [:] + } + all[name] = edits() + let enc = JSONEncoder() + enc.outputFormatting = [.prettyPrinted, .sortedKeys] + try enc.encode(all).write(to: editsURL) + dirty = false + } +} diff --git a/chart-wizard/Sources/ChartWizard/RollView.swift b/chart-wizard/Sources/ChartWizard/RollView.swift new file mode 100644 --- /dev/null +++ b/chart-wizard/Sources/ChartWizard/RollView.swift @@ -0,0 +1,253 @@ +// RollView.swift — the chart, as something you can grab. +// +// Two clocks are on screen at once, which is the whole reason this is +// hard to do in a text editor. Horizontally the roll is the BEAT GRID — +// where each word lands in the bar. Inside every block, drawn to that +// block's own width, is the piece of the take it plays, in SOURCE +// seconds. Dragging the block moves it in the first clock; dragging its +// edge moves it in the second. Melodyne's arrangement, with her measured +// pitch on the vertical axis so a word sits at the note she sang. +// +// drag a block move it on the grid (steals from the rest +// in front, gives it back to the one behind, +// so nothing downstream moves) +// drag its LEFT edge move the boundary in her voice — the cut +// that decides which mouth belongs to which +// word. Snaps to measured event edges. +// drag its RIGHT edge how many beats it holds +// ⌥ while dragging no snapping +// click select · space plays from there +import AppKit + +protocol RollViewDelegate: AnyObject { + func rollDidEdit(_ view: RollView) + func rollDidSelect(_ view: RollView, unit: Int?) + func rollRequestsPlay(_ view: RollView, fromBeat: Double) +} + +final class RollView: NSView { + weak var delegate: RollViewDelegate? + var model: ChartModel? { didSet { needsDisplay = true } } + var playhead: Double? { didSet { needsDisplay = true } } // seconds + private(set) var selected: Int? + + private var pxPerBeat: CGFloat = 46 + private let topPad: CGFloat = 26 + private let lane: CGFloat = 15 // pixels per semitone + + // ── geometry ───────────────────────────────────────────────────── + private var stCenter: Double { + guard let m = model, !m.units.isEmpty else { return 4 } + let all = m.units.map { $0.st } + return (all.min()! + all.max()!) / 2 + } + private func x(beat: Double) -> CGFloat { CGFloat(beat) * pxPerBeat + 8 } + private func beat(x: CGFloat) -> Double { Double((x - 8) / pxPerBeat) } + private func y(st: Double) -> CGFloat { + bounds.midY + CGFloat(st - stCenter) * -lane + } + private func rect(_ u: Unit) -> NSRect { + NSRect(x: x(beat: u.beat), y: y(st: u.st) - 13, + width: max(6, CGFloat(u.dur) * pxPerBeat - 2), height: 26) + } + + override var isFlipped: Bool { false } + override var acceptsFirstResponder: Bool { true } + + override var intrinsicContentSize: NSSize { + guard let m = model else { return NSSize(width: 900, height: 380) } + return NSSize(width: CGFloat(m.phrase.beats + 2) * pxPerBeat + 16, height: 380) + } + + func zoom(by f: CGFloat) { + pxPerBeat = min(220, max(14, pxPerBeat * f)) + invalidateIntrinsicContentSize() + needsDisplay = true + } + + // ── drawing ────────────────────────────────────────────────────── + override func draw(_ dirtyRect: NSRect) { + NSColor(calibratedWhite: 0.08, alpha: 1).setFill() + dirtyRect.fill() + guard let m = model else { return } + let ph = m.phrase + + drawGrid(m) + for (i, u) in m.units.enumerated() { drawBlock(m, ph, u, index: i) } + drawPlayhead(m) + } + + private func drawGrid(_ m: ChartModel) { + let bars = Int((m.phrase.beats / 4).rounded(.up)) + for bar in 0...max(0, bars) { + let bx = x(beat: Double(bar * 4)) + NSColor(calibratedWhite: 0.30, alpha: 1).setFill() + NSRect(x: bx, y: 0, width: 1, height: bounds.height).fill() + let label = NSAttributedString(string: "\(bar)", attributes: [ + .font: NSFont.monospacedSystemFont(ofSize: 9, weight: .regular), + .foregroundColor: NSColor(calibratedWhite: 0.45, alpha: 1)]) + label.draw(at: NSPoint(x: bx + 3, y: bounds.height - topPad + 8)) + for b in 1..<4 { + let sx = x(beat: Double(bar * 4 + b)) + NSColor(calibratedWhite: 0.16, alpha: 1).setFill() + NSRect(x: sx, y: 0, width: 1, height: bounds.height).fill() + } + } + } + + // Her voice, drawn INSIDE the block at the block's width: peak per + // column over the source span. This is the part that makes a bad + // boundary visible — a word holding the next word's consonant shows + // it as a bright tail with nothing behind it. + private func drawBlock(_ m: ChartModel, _ ph: Phrase, _ u: Unit, index i: Int) { + let r = rect(u) + let isSel = (selected == i) + let body = isSel ? NSColor(calibratedRed: 0.98, green: 0.36, blue: 0.62, alpha: 0.22) + : NSColor(calibratedRed: 0.44, green: 0.62, blue: 0.98, alpha: 0.18) + body.setFill() + NSBezierPath(roundedRect: r, xRadius: 3, yRadius: 3).fill() + + let f0 = Int(u.src0 / m.doc.frame_s), f1 = Int(u.src1 / m.doc.frame_s) + let n = max(1, f1 - f0) + let cols = max(1, Int(r.width)) + NSColor(calibratedWhite: 0.92, alpha: 0.75).setFill() + for c in 0.. -60 else { continue } + let h = CGFloat((peak + 60) / 60) * (r.height * 0.44) + // a consonant is dim but BRIGHT — tint it so it can be seen + if bright > 0.5 { + NSColor(calibratedRed: 1.0, green: 0.85, blue: 0.35, alpha: 0.85).setFill() + } else { + NSColor(calibratedWhite: 0.92, alpha: 0.75).setFill() + } + NSRect(x: r.minX + CGFloat(c), y: r.midY - h, width: 1, height: h * 2).fill() + } + + (isSel ? NSColor(calibratedRed: 1, green: 0.45, blue: 0.7, alpha: 1) + : NSColor(calibratedWhite: 0.55, alpha: 1)).setStroke() + let p = NSBezierPath(roundedRect: r, xRadius: 3, yRadius: 3) + p.lineWidth = isSel ? 2 : 1 + p.stroke() + + // an edge no chart knob owns cannot be dragged — say so rather + // than letting a drag silently do nothing + if u.cut == .auto { + NSColor(calibratedWhite: 0.35, alpha: 1).setFill() + NSRect(x: r.minX, y: r.minY, width: 2, height: r.height).fill() + } + + let text = NSAttributedString(string: u.t, attributes: [ + .font: NSFont.monospacedSystemFont(ofSize: 10, weight: .medium), + .foregroundColor: NSColor(calibratedWhite: isSel ? 1.0 : 0.80, alpha: 1)]) + text.draw(at: NSPoint(x: r.minX + 3, y: r.maxY + 1)) + } + + private func drawPlayhead(_ m: ChartModel) { + guard let t = playhead else { return } + let px = x(beat: t / m.secondsPerBeat) + NSColor(calibratedRed: 1, green: 0.9, blue: 0.3, alpha: 0.9).setFill() + NSRect(x: px, y: 0, width: 1.5, height: bounds.height).fill() + } + + // ── dragging ───────────────────────────────────────────────────── + private enum Grab { case body(Int, Double), leftEdge(Int), rightEdge(Int) } + private var grab: Grab? + + private func hit(_ p: NSPoint) -> Grab? { + guard let m = model else { return nil } + for (i, u) in m.units.enumerated().reversed() { + let r = rect(u).insetBy(dx: 0, dy: -4) + guard r.contains(p) else { continue } + if p.x - r.minX < 6 { return .leftEdge(i) } + if r.maxX - p.x < 6 { return .rightEdge(i) } + return .body(i, beat(x: p.x) - u.beat) + } + return nil + } + + override func resetCursorRects() { + guard let m = model else { return } + for u in m.units { + let r = rect(u) + addCursorRect(NSRect(x: r.minX - 3, y: r.minY, width: 8, height: r.height), + cursor: .resizeLeftRight) + addCursorRect(NSRect(x: r.maxX - 5, y: r.minY, width: 8, height: r.height), + cursor: .resizeLeftRight) + } + } + + override func mouseDown(with e: NSEvent) { + let p = convert(e.locationInWindow, from: nil) + grab = hit(p) + switch grab { + case .body(let i, _), .leftEdge(let i), .rightEdge(let i): + selected = i + case nil: + selected = nil + } + delegate?.rollDidSelect(self, unit: selected) + needsDisplay = true + } + + override func mouseDragged(with e: NSEvent) { + guard let m = model, let g = grab else { return } + let p = convert(e.locationInWindow, from: nil) + let free = e.modifierFlags.contains(.option) + switch g { + case .body(let i, let offset): + var b = beat(x: p.x) - offset + if !free { b = (b * 2).rounded() / 2 } // half-beat grid + m.moveBlock(i, toBeat: b) + case .rightEdge(let i): + var d = beat(x: p.x) - m.units[i].beat + if !free { d = (d * 2).rounded() / 2 } + m.resizeBlock(i, toDur: d) + case .leftEdge(let i): + guard i > 0 else { return } + // the left edge lives in HER clock, not the grid's: how far + // into the block the pointer is, scaled back to source seconds + let u = m.units[i] + let r = rect(u) + let frac = Double((p.x - r.minX) / max(1, r.width)) + var t = u.src0 + frac * (u.src1 - u.src0) + if !free { t = snapToEvent(m, t) } + m.moveBoundary(i, toSource: t) + } + delegate?.rollDidEdit(self) + needsDisplay = true + } + + override func mouseUp(with e: NSEvent) { grab = nil } + + /// The audio already told us where the edges are. Snap to the nearest + /// measured event edge within 40 ms so a drag lands on a real onset + /// rather than near one. + private func snapToEvent(_ m: ChartModel, _ t: Double) -> Double { + var best = t, bestD = 0.040 + for e in m.phrase.events { + for edge in [e.a, e.b] where abs(edge - t) < bestD { + bestD = abs(edge - t); best = edge + } + } + return best + } + + override func keyDown(with e: NSEvent) { + guard let m = model else { return super.keyDown(with: e) } + switch e.charactersIgnoringModifiers { + case " ": + let from = selected.map { m.units[$0].beat } ?? 0 + delegate?.rollRequestsPlay(self, fromBeat: from) + case "=", "+": zoom(by: 1.25) + case "-", "_": zoom(by: 0.8) + default: super.keyDown(with: e) + } + } +} diff --git a/chart-wizard/Sources/ChartWizard/WarpEngine.swift b/chart-wizard/Sources/ChartWizard/WarpEngine.swift new file mode 100644 --- /dev/null +++ b/chart-wizard/Sources/ChartWizard/WarpEngine.swift @@ -0,0 +1,198 @@ +// WarpEngine.swift — hear the drag immediately. +// +// The real render is halo3's: WORLD analysis, a frame-axis warp where +// vowels absorb the stretch and consonants ride near 1:1, the pitch snap, +// the halos. It takes half a minute and it is the thing that ships. This +// is not that. This is WSOLA on the raw slice — overlap-add with a +// correlation search so the grains line up — assembled onto the beat grid +// with a kick, in a few milliseconds, so a boundary can be judged by ear +// while the mouse is still down. Timing is what it has to be honest +// about, and timing is exactly what WSOLA preserves. +import AVFoundation + +final class WarpEngine { + private let engine = AVAudioEngine() + private let player = AVAudioPlayerNode() + private var source: [Float] = [] + private var sr: Double = 44100 + private(set) var isPlaying = false + private var startHostTime: AVAudioTime? + private var renderedFrames: AVAudioFrameCount = 0 + + init() { + engine.attach(player) + engine.connect(player, to: engine.mainMixerNode, + format: AVAudioFormat(standardFormatWithSampleRate: 44100, channels: 1)) + } + + func load(wav: URL) throws { + let file = try AVAudioFile(forReading: wav) + sr = file.processingFormat.sampleRate + guard let buf = AVAudioPCMBuffer(pcmFormat: file.processingFormat, + frameCapacity: AVAudioFrameCount(file.length)) else { return } + try file.read(into: buf) + let n = Int(buf.frameLength) + var mono = [Float](repeating: 0, count: n) + if let ch = buf.floatChannelData { + let chans = Int(buf.format.channelCount) + for i in 0.., toLength out: Int) -> [Float] { + let src = Array(x) + guard out > 0 else { return [] } + guard src.count > 8 else { return [Float](repeating: 0, count: out) } + let rate = Double(src.count) / Double(out) + if abs(rate - 1.0) < 0.01 && src.count >= out { return Array(src[0.. 0 { + // line the next grain up with the tail we just wrote + var bestScore = -Float.greatestFiniteMagnitude + let lo = max(0, Int(anaPos.rounded()) - search) + let hi = min(src.count - win - 1, Int(anaPos.rounded()) + search) + if lo <= hi { + for cand in stride(from: lo, through: hi, by: 2) { + var score: Float = 0 + for k in stride(from: 0, to: synHop, by: 2) { + score += prevTail[k] * src[cand + k] + } + if score > bestScore { bestScore = score; best = cand } + } + } + } + best = min(max(0, best), max(0, src.count - win - 1)) + for k in 0..= Double(src.count - win) { anaPos = Double(max(0, src.count - win - 1)) } + } + for i in 0.. 1e-6 { y[i] /= norm[i] } + return Array(y[0.. AVAudioPCMBuffer? { + let total = Int(((totalBeats + 2) * spb) * sr) + guard total > 0, + let fmt = AVAudioFormat(standardFormatWithSampleRate: sr, channels: 1), + let buf = AVAudioPCMBuffer(pcmFormat: fmt, frameCapacity: AVAudioFrameCount(total)) + else { return nil } + buf.frameLength = AVAudioFrameCount(total) + guard let out = buf.floatChannelData?[0] else { return nil } + for i in 0..= 0, b > a, b <= source.count else { continue } + let target = Int(u.dur * spb * sr) + guard target > 0 else { continue } + let warped = wsola(source[a..= 0, i < total else { continue } + var g: Float = 1 + if k < fade { g = 0.5 - 0.5 * cos(.pi * Float(k) / Float(fade)) } + else if k >= warped.count - fade { + g = 0.5 - 0.5 * cos(.pi * Float(warped.count - k) / Float(fade)) + } + out[i] += v * g + } + } + + if kick { + let beats = Int(totalBeats.rounded(.up)) + let len = Int(0.09 * sr) + for beat in 0...max(0, beats) { + let at = Int(Double(beat) * spb * sr) + for k in 0..= 0, i < total else { break } + let t = Double(k) / sr + let env = exp(-t * 38.0) + let f = 118.0 * exp(-t * 26.0) + 44.0 + out[i] += Float(sin(2 * .pi * f * t) * env * 0.30) + } + } + } + return buf + } + + /// Play from a beat by slicing the assembled buffer — scheduleBuffer + /// has no start offset, and copying a few hundred KB is free next to + /// re-warping every unit. + func play(_ buf: AVAudioPCMBuffer, fromBeat beat: Double = 0, spb: Double = 0.5) { + stop() + do { try engine.start() } catch { return } + let skip = Int(max(0, beat * spb * sr)) + guard skip < Int(buf.frameLength) else { return } + let piece: AVAudioPCMBuffer + if skip == 0 { + piece = buf + } else { + let n = AVAudioFrameCount(Int(buf.frameLength) - skip) + guard let cut = AVAudioPCMBuffer(pcmFormat: buf.format, frameCapacity: n), + let src = buf.floatChannelData?[0], let dst = cut.floatChannelData?[0] + else { return } + cut.frameLength = n + for i in 0../vox4/.wizard.json] +// +// The lane's chart is authored in Python (halo3.py's CHART) and rendered +// through WORLD and a C engine. Everything about that is right except the +// loop: a boundary is a float you type, and hearing it costs half a +// minute. This is the same chart with a handle on it — the blocks are the +// units halo3 will warp, the audio inside them is the take, and Render +// hands the edits back to the pipeline that ships. +import AppKit + +let app = NSApplication.shared +let delegate = ChartWizardAppDelegate() +app.delegate = delegate +app.setActivationPolicy(.regular) +app.run() diff --git a/pop/lib/nervox.py b/pop/lib/nervox.py new file mode 100644 --- /dev/null +++ b/pop/lib/nervox.py @@ -0,0 +1,148 @@ +"""nervox — make a regulated voice sound nervous again. + +@jeffrey, 2026-08-19, on the loner lane: "i think wavering notes too / +flanging and wiggling the pitches · would be nice · so the voice sounds +more nervous · lets call this 'nervox' technique · and canonize it in our +/pop tooling setup". + +THE PROBLEM IT SOLVES. Every WORLD lane here ends up snapping the singer +onto a grid — cult's sing.py, loner's halo3, factory's chart.py. The snap +is what makes her notes read as NOTES against a strict beat, and it is +also what makes her sound like a machine: a held tone whose f0 is a +straight line does not occur in a human throat. Turning the snap down +gets the humanity back by giving up the regulation, which is the wrong +trade. nervox keeps the regulation and puts the tremor back on top. + +TWO PARTS, and they are different instruments: + + waver() f0 modulation. NOT vibrato — vibrato is periodic and + confident. This is three incommensurate rates beating + against each other plus a smoothed random walk, so the pitch + never repeats its own wobble. That irregularity is the whole + effect; a single clean LFO reads as an opera singer, and + these read as someone whose voice is not quite steady. + + flange() a modulated short delay through the voice. Sweeping comb + notches make the timbre itself unstable, which is the part + you hear as nerves rather than as tuning. + +TWO RULES, both learned the hard way on loner: + + 1. Waver HELD notes only. A slide is already moving; wobbling it makes + mush. Pass `rate` (semitones/second, smoothed) and frames above + GLIDE_ST_S are left alone — the same test that decides where the + pitch snap lets go, so the two agree by construction. + 2. Ramp in. A tremor present at the attack sounds like a broken + sample; one that grows over ~120 ms sounds like a held note going + unsteady, which is what a nervous singer actually does. + +Deterministic: everything is seeded, so a render is reproducible and two +runs of the same score are byte-comparable. + + from nervox import waver, flange + f0 = waver(f0, frame_s, rate=rate) # cents of tremor on f0 + x = flange(x, fs) # comb sweep on the audio +""" + +import numpy as np + +# the same threshold the pitch snap uses to decide she is sliding +GLIDE_ST_S = 18.0 + +WAVER_CENTS = 22.0 # depth of the tremor, cents peak +WAVER_RATES = (4.3, 5.9, 7.1) # incommensurate, so the wobble never repeats +WAVER_DRIFT_HZ = 0.7 # how fast the random walk under it moves +WAVER_RAMP_S = 0.120 # a tremor at the attack reads as a broken sample + +FLANGE_MS = (0.6, 4.5) # sweep range of the delay +FLANGE_HZ = 0.23 # the sweep +FLANGE_DRIFT_HZ = 0.07 # …and a slower drift under it, so it never cycles +FLANGE_FB = 0.35 +FLANGE_MIX = 0.38 + + +def _walk(n, rng, hz, frame_s): + """A smoothed random walk in [-1, 1] — the part that will not repeat.""" + if n <= 0: + return np.zeros(0) + step = max(1, int(round(1.0 / max(hz, 1e-6) / frame_s))) + knots = rng.uniform(-1.0, 1.0, size=n // step + 2) + w = np.interp(np.arange(n), np.arange(len(knots)) * step, knots) + k = max(1, step // 2) + return np.convolve(w, np.ones(k) / k, mode="same") + + +def waver(f0, frame_s, rate=None, cents=WAVER_CENTS, seed=0x10AE, + voiced=None, ramp_s=WAVER_RAMP_S): + """Put an unsteady tremor on a corrected f0 contour. + + f0 Hz per frame, 0 where unvoiced + rate |df0/dt| in semitones/second per frame; frames above + GLIDE_ST_S are left alone (she is sliding, not holding) + """ + f0 = np.asarray(f0, dtype=float) + n = len(f0) + if n == 0: + return f0 + v = (f0 > 0) if voiced is None else np.asarray(voiced, dtype=bool)[:n] + rng = np.random.default_rng(seed) + t = np.arange(n) * frame_s + + # three rates beating, each with its own slowly wandering depth + trem = np.zeros(n) + for i, hz in enumerate(WAVER_RATES): + depth = 0.55 + 0.45 * _walk(n, rng, WAVER_DRIFT_HZ, frame_s) + trem += depth * np.sin(2 * np.pi * hz * t + rng.uniform(0, 2 * np.pi)) + trem /= len(WAVER_RATES) + trem = 0.75 * trem + 0.25 * _walk(n, rng, WAVER_DRIFT_HZ * 1.6, frame_s) + + # held notes only — a slide is already moving + hold = np.ones(n) + if rate is not None: + r = np.asarray(rate, dtype=float)[:n] + hold = np.clip(1.0 - (r - GLIDE_ST_S) / GLIDE_ST_S, 0.0, 1.0) + + # …and ramp in from each voiced onset + ramp = np.zeros(n) + k = max(1, int(round(ramp_s / frame_s))) + run = 0 + for i in range(n): + run = run + 1 if v[i] else 0 + ramp[i] = min(1.0, run / k) + + out = f0.copy() + out[v] = f0[v] * 2.0 ** ((cents * trem * hold * ramp)[v] / 1200.0) + return out + + +def flange(x, fs, depth_ms=FLANGE_MS, hz=FLANGE_HZ, fb=FLANGE_FB, + mix=FLANGE_MIX, seed=0x11AE): + """A modulated short delay — the timbre goes unstable, not the tuning.""" + x = np.asarray(x, dtype=float) + n = len(x) + if n == 0: + return x + t = np.arange(n) / float(fs) + lo, hi = depth_ms[0] / 1000.0, depth_ms[1] / 1000.0 + rng = np.random.default_rng(seed) + ph = rng.uniform(0, 2 * np.pi) + sweep = 0.5 - 0.5 * np.cos(2 * np.pi * hz * t + ph) + sweep = 0.78 * sweep + 0.22 * (0.5 - 0.5 * np.cos(2 * np.pi * FLANGE_DRIFT_HZ * t)) + d = (lo + (hi - lo) * sweep) * fs + + # linear-interpolated delay line with feedback, written in place so the + # feedback path hears its own output the way a real flanger does + y = np.zeros(n) + buf = np.zeros(n) + for i in range(n): + di = d[i] + j = i - di + if j < 1: + v = 0.0 + else: + j0 = int(j) + fr = j - j0 + v = buf[j0] * (1 - fr) + buf[j0 + 1] * fr if j0 + 1 < n else buf[j0] + buf[i] = x[i] + fb * v + y[i] = v + return (1.0 - mix) * x + mix * y diff --git a/pop/loner/.gitignore b/pop/loner/.gitignore --- a/pop/loner/.gitignore +++ b/pop/loner/.gitignore @@ -30,3 +30,10 @@ # The compiled C engine. c/lonerremix out/.segments/ vox4/.cache/ + +# The dub/take bank — bin/singdub.py rebuilds every warped line from +# samples/ (a translation) or samples/corpus/ (another take). Derived +# media, same rule as vox4/: 37 MB of it, and none of it is a source. +# The ElevenLabs mp3s beside them ARE kept — those came from a paid API +# call against her cloned voice and cannot be regenerated for free. +vox-dub/sung-*.wav diff --git a/pop/loner/bin/audit.py b/pop/loner/bin/audit.py --- a/pop/loner/bin/audit.py +++ b/pop/loner/bin/audit.py @@ -11,13 +11,36 @@ # made each word's span swallow the head of the next one — that is what # "for" containing "time" was. So the transcript is never the authority; # the audio is. # -# This finds the sung EVENTS with no reference to any transcript — voiced, -# loud runs, split wherever the pitch plateau moves — and then asks of -# every charted unit: which events fall inside your span, and how much of -# each? A unit holding more than one event is carrying a neighbour's -# word. A unit holding a fraction of one is clipping it. +# This finds the sung EVENTS with no reference to any transcript, and then +# asks of every charted unit: which events fall inside your span? +# +# THREE KINDS OF EVENT, because a word is not only its vowel. Splitting on +# pitch alone — which is all this did at first — cannot see a consonant: a +# fricative has no pitch, so the estimator hands back a garbage number and +# the /s/ of "self" merges into the vowel of "my". That read every CORRECT +# sibilant boundary in the take as contamination and buried the three real +# ones under sixteen flags. So each run is split where the pitch plateau +# moves OR where the brightness does, and classified: +# +# NOTE voiced, dark — a sung syllable +# FRIC bright above 3 kHz — /s/ /f/ /ʃ/, an onset or a coda +# PUFF unvoiced, dark — a breath, a stop closure, a burst +# +# and the rule is the singer's, not the transcript's: a consonant belongs +# to the note it LEADS INTO. A unit may open with a fricative — that is +# its own onset — and may end with one when nothing follows it closely, +# which is a coda. A unit that ends with a fricative belonging to the next +# unit's note is carrying the next word's mouth, which is the bug that had +# "stone" entering as "-tone". +# +# ZOOM: given a time window, it stops summarising and prints the frames — +# level, pitch and brightness, one line per 5 ms — which is the view every +# boundary in this take has actually been pinned from. A fricative is DIM +# but BRIGHT (fd31ffd10), a stop closure is dim and DARK, and a note change +# is a step in the pitch column; those three shapes are the whole method. # # pop/.venv/bin/python pop/loner/bin/audit.py [phrase] +# pop/.venv/bin/python pop/loner/bin/audit.py [phrase] import json, os, sys import numpy as np @@ -31,19 +54,56 @@ TONIC = 237.0 SPB = 60.0 / 122.0 GATE_DB = -34.0 # a run must clear this to be a sung event MIN_EVENT_S = 0.070 # shorter than this is a transient, not a syllable +MIN_NOTE_S = 0.150 # a real sung syllable here; below it, a glide +MIN_CONS_S = 0.070 # below this, a click rather than a consonant +HELD_FRAC = 0.25 # a unit HOLDS an event at this share of it… +HELD_S = 0.100 # …or at this many seconds of it, whichever first +COVERED = 0.75 # an event played below this share is partly lost PITCH_STEP = 0.7 # semitones of sustained change that split an event +BRIGHT_STEP = 0.45 # change in >3 kHz share that splits an event +BRIGHT = 0.50 # above this share of energy, the frame is a fricative +VOICED = 0.50 # below this fraction of pitched frames, it is unvoiced +ONSET_GAP_S = 0.200 # a fricative this close to the next note is its onset -def events(x, fs): - """Sung events, straight from the audio. No transcript involved.""" +def columns(x, fs): + """f0, level and brightness per frame — the three columns every boundary + in this take has been read from, and the only measurements here.""" f0r, t = pw.harvest(x, fs, f0_floor=70.0, f0_ceil=600.0, frame_period=FRAME_S * 1000) f0 = pw.stonemask(x, f0r, t, fs) n = int(round(fs * FRAME_S)) m = min(len(f0), len(x) // n) - rms = np.sqrt((x[:m * n].reshape(m, n) ** 2).mean(axis=1)) - gate = (np.max(np.abs(x)) or 1.0) * 10.0 ** (GATE_DB / 20.0) - on = rms > gate - st = np.where(f0[:m] > 0, 12.0 * np.log2(np.maximum(f0[:m], 1e-6) / TONIC), np.nan) + fr = x[:m * n].reshape(m, n) + rms = np.sqrt((fr ** 2).mean(axis=1)) + peak = np.max(np.abs(x)) or 1.0 + + # the share of frame energy above 3 kHz. /s/ and /f/ run over 0.9 at + # levels a pure level gate calls silence; a stop closure runs low in + # BOTH columns, which is how the two are told apart. + win = np.hanning(n) + mag = np.abs(np.fft.rfft(fr * win, axis=1)) ** 2 + fk = np.fft.rfftfreq(n, 1.0 / fs) + hi = mag[:, fk >= 3000.0].sum(axis=1) / np.maximum(mag.sum(axis=1), 1e-20) + + f0 = f0[:m] + st = np.where(f0 > 0, 12.0 * np.log2(np.maximum(f0, 1e-6) / TONIC), np.nan) + return f0, st, rms, hi, peak, m + + +def classify(st, hi, u, v): + """NOTE, FRIC or PUFF — and the pitch, when it has one.""" + voiced = st[u:v][~np.isnan(st[u:v])] + if float(np.median(hi[u:v])) >= BRIGHT: + return "FRIC", float("nan") + if len(voiced) < VOICED * (v - u): + return "PUFF", float("nan") + return "NOTE", float(np.median(voiced)) + + +def events(x, fs): + """Sung events, straight from the audio. No transcript involved.""" + f0, st, rms, hi, peak, m = columns(x, fs) + on = rms > peak * 10.0 ** (GATE_DB / 20.0) runs, k = [], 0 while k < m: @@ -57,28 +117,50 @@ k = j else: k += 1 - out = [] # split each run where the pitch plateau moves + out = [] # split each run where pitch OR brightness steps W = int(round(0.080 / FRAME_S)) for (a, b) in runs: cuts = [a] for k in range(a + W, b - W): - lo, hi = st[k - W:k], st[k:k + W] - lo, hi = lo[~np.isnan(lo)], hi[~np.isnan(hi)] - if len(lo) >= W // 2 and len(hi) >= W // 2: - if abs(np.median(hi) - np.median(lo)) > PITCH_STEP and k - cuts[-1] > int(0.12 / FRAME_S): - cuts.append(k) + if k - cuts[-1] <= int(0.12 / FRAME_S): + continue + plo, phi = st[k - W:k], st[k:k + W] + plo, phi = plo[~np.isnan(plo)], phi[~np.isnan(phi)] + moved = (len(plo) >= W // 2 and len(phi) >= W // 2 + and abs(np.median(phi) - np.median(plo)) > PITCH_STEP) + lit = abs(np.median(hi[k:k + W]) - np.median(hi[k - W:k])) > BRIGHT_STEP + if moved or lit: + cuts.append(k) cuts.append(b) for u, v in zip(cuts[:-1], cuts[1:]): - seg = st[u:v][~np.isnan(st[u:v])] - out.append((u * FRAME_S, v * FRAME_S, - float(np.median(seg)) if len(seg) else float("nan"))) + kind, pitch = classify(st, hi, u, v) + out.append((u * FRAME_S, v * FRAME_S, pitch, kind)) return out +def zoom(x, fs, t0, t1, spans): + """Every frame in a window, so a boundary can be read rather than guessed.""" + f0, st, rms, hi, peak, m = columns(x, fs) + k0, k1 = max(0, int(t0 / FRAME_S)), min(m, int(t1 / FRAME_S) + 1) + edges = {round(a, 3): f"{t} starts" for (t, a, b) in spans} + for (t_, a, b) in spans: + edges.setdefault(round(b, 3), f"{t_} ends") + + print(f"\nframes {t0:.2f}–{t1:.2f}s " + f"(level dB rel take peak · pitch st vs {TONIC:.0f} Hz · >3 kHz share)") + for k in range(k0, k1): + tt = k * FRAME_S + db = 20.0 * np.log10(max(rms[k], 1e-9) / peak) + bar = "#" * int(max(0, (db + 60.0)) / 3.0) + mark = next((f" <-- {lab}" for e, lab in edges.items() + if abs(e - tt) < FRAME_S / 2), "") + pitch = f"{st[k]:+6.1f}st" if not np.isnan(st[k]) else " ---" + print(f" {tt:6.3f} {db:6.1f} {bar:<20} {pitch} hf {hi[k]:.2f}{mark}") + + def main(): phrase = sys.argv[1] if len(sys.argv) > 1 else "w-whole-line" man = json.load(open(os.path.join(LANE, "vox4", ".manifest.json")))[phrase] - align = json.load(open(os.path.join(LANE, "samples", ".align.json"))) chart = json.load(open(os.path.join(LANE, "vox4", ".chart.json")))[phrase] slice_name = man["slice"] x, fs = sf.read(os.path.join(LANE, "samples", f"{slice_name}.wav"), dtype="float64") @@ -86,39 +168,77 @@ if x.ndim > 1: x = x.mean(axis=1) ev = events(x, fs) - words = align[slice_name]["words"] if slice_name in align else [] - print(f"{phrase} · {slice_name} · {len(ev)} sung events, " + print(f"{phrase} · {slice_name} · {len(ev)} events, " f"{len(chart['notes'])} charted units\n") print("detected events (audio only):") - for i, (a, b, s) in enumerate(ev): - print(f" {i:2d} {a:6.2f}–{b:6.2f}s {b - a:.2f}s {s:+5.1f}st") + for i, (a, b, s, kind) in enumerate(ev): + pitch = f"{s:+5.1f}st" if not np.isnan(s) else "" + print(f" {i:2d} {a:6.2f}–{b:6.2f}s {b - a:.2f}s {kind} {pitch}") # the spans the chart ACTUALLY plays — emitted by halo3 after times, # sylls, snapping, attack pre-roll and the trim. Checking the raw # alignment instead would flag boundaries we already corrected. spans = [(t, a, b) for (t, a, b) in man["spans"]] + # Which units hold which events, and how much. A boundary that splits + # one event between two ADJACENT units is legato, not damage — she + # slides from note to note and the cut has to land somewhere inside + # the slide. What is damage is audio no unit plays at all. + held = [[] for _ in ev] + for si, (t, a, b) in enumerate(spans): + for i, (ea, eb, es, kind) in enumerate(ev): + ov = max(0.0, min(b, eb) - max(a, ea)) + if ov > 0.0: + held[i].append((si, ov / (eb - ea), ov)) + + def owns(i, si): + """Does unit si hold enough of event i to be playing it?""" + return any(s_ == si and (f >= HELD_FRAC or o >= HELD_S) for s_, f, o in held[i]) + print("\nper word — which events fall in its span:") flags = 0 - for (t, a, b) in spans: - inside = [] - for i, (ea, eb, es) in enumerate(ev): - ov = max(0.0, min(b, eb) - max(a, ea)) - if ov > 0.02: - inside.append((i, ov / (eb - ea), es)) - desc = " · ".join(f"#{i} {100 * f:.0f}%@{s:+.1f}st" for i, f, s in inside) or "—" + for si, (t, a, b) in enumerate(spans): + mine = [i for i in range(len(ev)) if owns(i, si)] + notes = [i for i in mine if ev[i][3] == "NOTE" and ev[i][1] - ev[i][0] >= MIN_NOTE_S] + bad = "" - if len(inside) > 1: - bad = " <== TWO EVENTS: carrying a neighbour" - flags += 1 - elif inside and inside[0][1] < 0.75: - bad = " <== PARTIAL: clipping this event" - flags += 1 - elif not inside: + if len(notes) > 1: + bad = f" <== TWO NOTES: carrying #{notes[0]} as well as #{notes[-1]}" + elif mine: + # a trailing consonant is this word's coda UNLESS a note starts + # right after it — then it is that note's onset, and this unit + # is holding the next word's mouth. + last = ev[mine[-1]] + if last[3] in ("FRIC", "PUFF") and last[1] - last[0] >= MIN_CONS_S: + nxt = next((j for j, e in enumerate(ev) + if e[3] == "NOTE" and e[0] >= last[1] - 0.01), None) + if nxt is not None and ev[nxt][0] - last[1] < ONSET_GAP_S and nxt not in mine: + bad = " <== TRAILING CONSONANT: the next word's onset" + if not bad: + # anything of hers this unit starts but nobody finishes + for i in mine: + floor = MIN_NOTE_S if ev[i][3] == "NOTE" else MIN_CONS_S + if ev[i][1] - ev[i][0] < floor: + continue + cover = sum(f for _, f, _ in held[i]) + if cover < COVERED: + bad = f" <== CLIPPED: only {100 * cover:.0f}% of {ev[i][3].lower()} #{i} is played" + break + if not mine: bad = " <== NO EVENT in this span" + if bad: flags += 1 + + desc = " · ".join( + f"#{i} {100 * f:.0f}% {ev[i][3]}" + + (f"@{ev[i][2]:+.1f}st" if not np.isnan(ev[i][2]) else "") + for i in range(len(ev)) + for s_, f, o in held[i] if s_ == si and o > 0.02) or "—" print(f" {t:>10} {a:6.2f}–{b:6.2f}s {desc}{bad}") print(f"\n{flags} flagged of {len(spans)} words") + + if len(sys.argv) > 3: + zoom(x, fs, float(sys.argv[2]), float(sys.argv[3]), spans) if __name__ == "__main__": diff --git a/pop/loner/bin/dub.py b/pop/loner/bin/dub.py new file mode 100644 --- /dev/null +++ b/pop/loner/bin/dub.py @@ -0,0 +1,388 @@ +# dub.py — Camille's voice, singing the line in another language. +# +# @jeffrey: "we have her consent · im thinking we can use it to translate +# the song across some languages · or have like a french verse or spanish +# or danish verse · similar to how we translated the goodiepal / prutti vid +# from danish to elevenlabs". +# +# Same move as the klokkentales reel (2026-08-13): the ElevenLabs Dubbing +# API is VOICE-PRESERVING — it does not read the line in a stock voice, it +# re-sings it in hers. There the direction was da→en on Prutti; here it is +# en→fr/es/da on Camille. +# +# THE GATE, which is the lane's and not mine: consent is on record +# (@jeffrey, 2026-08-19) and synthetic voice is ALWAYS labelled. Every +# output carries `-dub-` in its name and a line in .dub.json saying +# what made it, so a file can never drift loose from the fact that a +# machine sang it. Nothing here is presented as a take she performed. +# +# WHY `dub` ALONE DOES NOT WORK HERE, measured 2026-08-19: the Dubbing API +# returned status "dubbed" with no error for fr/es/da and handed back audio +# that is still English — because its transcript came back EMPTY. dubbing_v1 +# transcribes speech, and this is 24 s of slow unaccompanied singing on held +# vowels, so it heard no words, had nothing to translate, and passed the +# source through. The klokkentales reel worked because Prutti was TALKING. +# +# So the route for a SONG is different, and it is better anyway: dubbing +# preserves the prosody of the source, and we do not want her English +# phrasing on a French verse — we want the French words on HER MELODY, +# which is the thing this lane's warp already does. Hence: +# +# clone an IVC from her SPOKEN slices (o-heres-loner, n-emo-again, +# n-i-knew-it) — real speech, which is what an IVC wants +# say the translated lyric, spoken in that voice +# then hand it to align.py + halo3's chart, and she sings the +# translation on the melody she wrote +# +# ELEVENLABS_API_KEY=... pop/.venv/bin/python pop/loner/bin/dub.py clone +# ELEVENLABS_API_KEY=... pop/.venv/bin/python pop/loner/bin/dub.py say fr +# ELEVENLABS_API_KEY=... pop/.venv/bin/python pop/loner/bin/dub.py dub fr + +import json, os, sys, time, urllib.request + +HERE = os.path.dirname(os.path.abspath(__file__)) +LANE = os.path.dirname(HERE) +REPO = os.path.dirname(os.path.dirname(LANE)) +VAULT = os.path.join(REPO, "aesthetic-computer-vault", + ".devcontainer", "envs", "devcontainer.env") +API = "https://api.elevenlabs.io/v1" +SOURCE = os.path.join(LANE, "samples", "f-whole-line.wav") # the whole sentence +LANGS = {"fr": "French", "es": "Spanish", "da": "Danish", "de": "German", + "it": "Italian", "pt": "Portuguese", "ja": "Japanese", + "ru": "Russian", "hi": "Hindi"} + +# The whole song is one sentence, so each translation is one sentence too. +# Kept literal rather than singable — the melody does the singing, and a +# rhyme scheme she never wrote would be us writing her lyric for her. +LYRIC = { + "en": "sitting curled up in myself, i think of a stone, " + "just waiting very patiently for time to pass", + "fr": "assise recroquevillée en moi-même, je pense à une pierre, " + "qui attend très patiemment que le temps passe", + "es": "sentada acurrucada en mí misma, pienso en una piedra, " + "que espera muy pacientemente a que pase el tiempo", + "da": "jeg sidder krøllet sammen i mig selv, jeg tænker på en sten, " + "der bare venter meget tålmodigt på at tiden går", + "ru": "сижу, свернувшись в себе, я думаю о камне, " + "который очень терпеливо ждёт, пока пройдёт время", + "hi": "अपने भीतर सिमटी हुई बैठी हूँ, मैं एक पत्थर के बारे में सोचती हूँ, " + "जो बहुत धीरज से समय के बीतने का इंतज़ार कर रहा है", +} + +# her SPOKEN slices — an IVC trained on singing learns the singing, and +# then every line it speaks arrives on that melody +SPOKEN = ["o-heres-loner", "n-emo-again", "n-i-knew-it"] + +# …but eight seconds is not a voice, it is an impression of one. @jeffrey: +# "these aren't using her voice · like we did with prutti". The Prutti clone +# had a whole reel behind it. `clone --all` uses the WHOLE archive instead: +# nineteen posts, 7.7 minutes, downsampled to fit the upload budget. +# +# ONE take is excluded and must stay excluded: 6988619239657622790 is the +# ensemble performance, with @jeffrey and Alex singing on it. Their voices +# are not Camille's and were not consented into this clone; a model trained +# on all three is not her. +ENSEMBLE = "6988619239657622790" +VOICE_NAME = "Camille Klein · loner IVC (consented)" + + +def key(): + k = os.environ.get("ELEVENLABS_API_KEY") + if k: + return k + with open(VAULT) as f: + for line in f: + if line.startswith("ELEVENLABS_API_KEY="): + return line.split("=", 1)[1].strip().strip("'\"") + raise SystemExit("no ELEVENLABS_API_KEY (env or vault devcontainer.env)") + + +def post_multipart(url, k, fields, filepath): + b = "----acdub" + body = b"" + for name, val in fields.items(): + body += (f"--{b}\r\nContent-Disposition: form-data; name=\"{name}\"\r\n\r\n" + f"{val}\r\n").encode() + with open(filepath, "rb") as f: + data = f.read() + body += (f"--{b}\r\nContent-Disposition: form-data; name=\"file\"; " + f"filename=\"{os.path.basename(filepath)}\"\r\n" + f"Content-Type: audio/wav\r\n\r\n").encode() + data + b"\r\n" + body += f"--{b}--\r\n".encode() + req = urllib.request.Request(url, data=body, headers={ + "xi-api-key": k, "Content-Type": f"multipart/form-data; boundary={b}"}) + with urllib.request.urlopen(req, timeout=300) as r: + return json.load(r) + + +def get(url, k, raw=False, timeout=300): + req = urllib.request.Request(url, headers={"xi-api-key": k}) + with urllib.request.urlopen(req, timeout=timeout) as r: + return r.read() if raw else json.load(r) + + +def post_files(url, k, fields, paths): + b = "----acdub" + body = b"" + for name, val in fields.items(): + body += (f"--{b}\r\nContent-Disposition: form-data; name=\"{name}\"\r\n\r\n" + f"{val}\r\n").encode() + for fp in paths: + with open(fp, "rb") as f: + data = f.read() + body += (f"--{b}\r\nContent-Disposition: form-data; name=\"files\"; " + f"filename=\"{os.path.basename(fp)}\"\r\n" + f"Content-Type: audio/wav\r\n\r\n").encode() + data + b"\r\n" + body += f"--{b}--\r\n".encode() + req = urllib.request.Request(url, data=body, headers={ + "xi-api-key": k, "Content-Type": f"multipart/form-data; boundary={b}"}) + with urllib.request.urlopen(req, timeout=300) as r: + return json.load(r) + + +def voice_path(): + return os.path.join(LANE, "vox-dub", ".voice.json") + + +def clone(k, whole_archive=False): + if whole_archive: + import glob, subprocess, tempfile + src = sorted(glob.glob(os.path.join(LANE, "source", "*-48k.wav"))) + src = [p for p in src if ENSEMBLE not in os.path.basename(p)] + tmp = tempfile.mkdtemp(prefix="acdub-") + paths, total = [], 0.0 + for f in src: # 22 kHz mono mp3 — the upload has a budget + d = os.path.join(tmp, os.path.basename(f).replace("-48k.wav", ".mp3")) + subprocess.run(["ffmpeg", "-y", "-v", "error", "-i", f, "-ac", "1", + "-ar", "22050", "-b:a", "96k", d], check=True) + paths.append(d) + total += os.path.getsize(d) + print(f" {len(paths)} takes, {total / 1e6:.1f} MB — excluded the " + f"ensemble take {ENSEMBLE} (@jeffrey and Alex are on it)") + else: + paths = [os.path.join(LANE, "samples", f"{n}.wav") for n in SPOKEN] + paths = [p for p in paths if os.path.exists(p)] + if not paths: + raise SystemExit("no audio to clone from") + print(f"→ cloning from {len(paths)} spoken slices: " + f"{', '.join(os.path.basename(p) for p in paths)}") + r = post_files(f"{API}/voices/add", k, { + "name": VOICE_NAME, + "description": "Consented IVC of Camille Klein (@cksuperstore) for the " + "loner remix. SYNTHETIC VOICE — label on any release.", + }, paths) + vid = r.get("voice_id") + os.makedirs(os.path.join(LANE, "vox-dub"), exist_ok=True) + json.dump(dict(voice_id=vid, name=VOICE_NAME, + sources=[os.path.basename(p) for p in paths], + synthetic=True, + consent="Camille Klein (@cksuperstore), via @jeffrey 2026-08-19"), + open(voice_path(), "w"), indent=1) + print(f" ✓ voice_id {vid} → {voice_path()}") + return vid + + +def say(k, lang): + vp = voice_path() + if not os.path.exists(vp): + raise SystemExit("no voice yet — run: dub.py clone") + vid = json.load(open(vp))["voice_id"] + text = LYRIC[lang] + body = json.dumps({ + "text": text, "model_id": "eleven_multilingual_v2", + "voice_settings": {"stability": 0.55, "similarity_boost": 0.85, + "style": 0.20, "use_speaker_boost": True}, + }).encode() + req = urllib.request.Request( + f"{API}/text-to-speech/{vid}", data=body, + headers={"xi-api-key": k, "Content-Type": "application/json", + "Accept": "audio/mpeg"}) + with urllib.request.urlopen(req, timeout=300) as r: + audio = r.read() + out_dir = os.path.join(LANE, "vox-dub") + os.makedirs(out_dir, exist_ok=True) + dest = os.path.join(out_dir, f"spoken-{lang}.mp3") + open(dest, "wb").write(audio) + print(f" ✓ {LANGS[lang]}: {dest} ({len(audio) // 1024} KB)") + print(f" “{text}”") + return dest + + +# A native speaker of each language, to PERFORM the line before her voice +# is mapped onto it. Which premade voice matters less than that it is +# female and unhurried — speech-to-speech transfers timbre, not timing, so +# whatever phrasing this voice chooses is the phrasing she will have. +CARRIER = "XrExE9yKIg1WjnnlVkGX" # Matilda — even, unhurried + + +def sts(k, lang): + """TTS the translation with a carrier voice, then wear her timbre. + + Better than TTS straight from the IVC because the model only has to + move TIMBRE — the prosody is already a real reading of a real French + sentence, rather than an English-trained clone guessing at one. It is + also what the Prutti dub was doing underneath. + """ + vp = voice_path() + if not os.path.exists(vp): + raise SystemExit("no voice yet — run: dub.py clone --all") + vid = json.load(open(vp))["voice_id"] + + body = json.dumps({ + "text": LYRIC[lang], "model_id": "eleven_multilingual_v2", + "voice_settings": {"stability": 0.60, "similarity_boost": 0.75, + "style": 0.0, "use_speaker_boost": True}, + }).encode() + req = urllib.request.Request( + f"{API}/text-to-speech/{CARRIER}", data=body, + headers={"xi-api-key": k, "Content-Type": "application/json", + "Accept": "audio/mpeg"}) + with urllib.request.urlopen(req, timeout=300) as r: + carrier = r.read() + + out_dir = os.path.join(LANE, "vox-dub") + os.makedirs(out_dir, exist_ok=True) + carrier_path = os.path.join(out_dir, f".carrier-{lang}.mp3") + open(carrier_path, "wb").write(carrier) + + b = "----acsts" + fields = {"model_id": "eleven_multilingual_sts_v2", + "voice_settings": json.dumps({"stability": 0.45, + "similarity_boost": 0.90, + "style": 0.0, + "use_speaker_boost": True})} + payload = b"" + for name, val in fields.items(): + payload += (f"--{b}\r\nContent-Disposition: form-data; name=\"{name}\"\r\n\r\n" + f"{val}\r\n").encode() + payload += (f"--{b}\r\nContent-Disposition: form-data; name=\"audio\"; " + f"filename=\"carrier.mp3\"\r\nContent-Type: audio/mpeg\r\n\r\n" + ).encode() + carrier + b"\r\n" + payload += f"--{b}--\r\n".encode() + req = urllib.request.Request( + f"{API}/speech-to-speech/{vid}", data=payload, + headers={"xi-api-key": k, "Accept": "audio/mpeg", + "Content-Type": f"multipart/form-data; boundary={b}"}) + with urllib.request.urlopen(req, timeout=600) as r: + audio = r.read() + dest = os.path.join(out_dir, f"sts-{lang}.mp3") + open(dest, "wb").write(audio) + print(f" ✓ {LANGS[lang]}: {dest} ({len(audio) // 1024} KB)") + return dest + + +def scribe(k, lang): + """Word timestamps for a translation — the shape of ITS words. + + @jeffrey: "per language we should be able to map the shape of the + words etc". singdub was finding syllables in the audio with an energy + detector, which is guessing; here the text is already known, so the + words come back labelled and a French verse can be charted word by + word the way the English one was. Same ElevenLabs scribe step the + klokkentales reel used for its karaoke subs. + """ + # `lang` may also name a SLICE — scribing her own takes is the same + # job as scribing a translation, and singdub needs word spans for any + # take it is asked to put on the chart. + slice_wav = os.path.join(LANE, "samples", f"{lang}.wav") + src = os.path.join(LANE, "vox-dub", f"sts-{lang}.mp3") + if os.path.exists(slice_wav): + src = slice_wav + elif not os.path.exists(src): + raise SystemExit(f"no sts-{lang}.mp3 and no samples/{lang}.wav") + b = "----acscribe" + code = lang if lang in LANGS else "en" + fields = {"model_id": "scribe_v1", "language_code": code, + "timestamps_granularity": "word", "diarize": "false"} + payload = b"" + for name, val in fields.items(): + payload += (f"--{b}\r\nContent-Disposition: form-data; name=\"{name}\"\r\n\r\n" + f"{val}\r\n").encode() + with open(src, "rb") as f: + data = f.read() + mime = "audio/wav" if src.endswith(".wav") else "audio/mpeg" + payload += (f"--{b}\r\nContent-Disposition: form-data; name=\"file\"; " + f"filename=\"{os.path.basename(src)}\"\r\n" + f"Content-Type: {mime}\r\n\r\n").encode() + data + b"\r\n" + payload += f"--{b}--\r\n".encode() + req = urllib.request.Request( + f"{API}/speech-to-text", data=payload, + headers={"xi-api-key": k, + "Content-Type": f"multipart/form-data; boundary={b}"}) + with urllib.request.urlopen(req, timeout=600) as r: + res = json.load(r) + + words = [w for w in res.get("words", []) if w.get("type") == "word"] + out = os.path.join(LANE, "vox-dub", ".words.json") + allw = json.load(open(out)) if os.path.exists(out) else {} + allw[lang] = [dict(t=w["text"], start=round(w["start"], 3), + end=round(w["end"], 3)) for w in words] + json.dump(allw, open(out, "w"), indent=1, ensure_ascii=False) + print(f" ✓ {LANGS.get(lang, lang)}: {len(words)} words → {out}") + print(" " + " ".join(w["text"] for w in words)) + return allw[lang] + + +def main(): + argv = sys.argv[1:] + k = key() + if argv and argv[0] == "clone": + clone(k, whole_archive="--all" in argv); return + if argv and argv[0] == "scribe": + for lang in argv[1:] or ["fr"]: + scribe(k, lang) + return + if argv and argv[0] == "sts": + for lang in [a for a in argv[1:] if a in LANGS] or ["fr"]: + sts(k, lang) + return + if argv and argv[0] == "say": + for lang in [a for a in argv[1:] if a in LANGS] or ["fr"]: + say(k, lang) + return + langs = [a for a in argv if a in LANGS] or ["fr"] + k = key() + out_dir = os.path.join(LANE, "vox-dub") + os.makedirs(out_dir, exist_ok=True) + receipt_path = os.path.join(out_dir, ".dub.json") + receipt = json.load(open(receipt_path)) if os.path.exists(receipt_path) else {} + + for lang in langs: + print(f"→ {LANGS[lang]} ({lang}) — dubbing {os.path.basename(SOURCE)}") + job = post_multipart(f"{API}/dubbing", k, { + "target_lang": lang, "source_lang": "en", "num_speakers": "1", + "name": f"loner-{lang}", + }, SOURCE) + did = job.get("dubbing_id") + if not did: + print(f" ! no dubbing_id: {job}"); continue + + for _ in range(120): # ~10 min ceiling + st = get(f"{API}/dubbing/{did}", k) + s = st.get("status") + if s == "dubbed": + break + if s == "failed": + print(f" ! failed: {st.get('error')}"); did = None; break + time.sleep(5) + if not did: + continue + + audio = get(f"{API}/dubbing/{did}/audio/{lang}", k, raw=True) + dest = os.path.join(out_dir, f"whole-line-dub-{lang}.mp3") + open(dest, "wb").write(audio) + # …and the label travels with the file, not just in a README + receipt[lang] = dict( + language=LANGS[lang], source=os.path.relpath(SOURCE, LANE), + dubbing_id=did, engine="elevenlabs/dubbing", + synthetic=True, consent="Camille Klein (@cksuperstore), via @jeffrey", + note="SYNTHETIC VOICE — her voice model singing a translation; " + "not a take she performed. Label on any release.") + json.dump(receipt, open(receipt_path, "w"), indent=1, sort_keys=True) + print(f" ✓ {dest} ({len(audio) // 1024} KB)") + + print(f"\nreceipt: {receipt_path}") + + +if __name__ == "__main__": + main() diff --git a/pop/loner/bin/halo3.py b/pop/loner/bin/halo3.py --- a/pop/loner/bin/halo3.py +++ b/pop/loner/bin/halo3.py @@ -40,13 +40,15 @@ # chart from, so the band's notes ARE her notes. # # pop/.venv/bin/python pop/loner/bin/halo3.py -import json, os +import json, os, sys import numpy as np import soundfile as sf import pyworld as pw HERE = os.path.dirname(os.path.abspath(__file__)) LANE = os.path.dirname(HERE) +sys.path.insert(0, os.path.join(os.path.dirname(LANE), "lib")) +from nervox import waver as nervox_waver, flange as nervox_flange VOX4 = os.path.join(LANE, "vox4") CDIR = os.path.join(LANE, "c") os.makedirs(VOX4, exist_ok=True) @@ -59,9 +61,28 @@ FRAME_S = FRAME_MS / 1000.0 FLOOR = 140.0 SNAP = 0.92 # THE REGULATION (v3 was 0.70) SMOOTH_MS = 45.0 +GLIDE_ST_S = 18.0 # above this rate of change she is SLIDING, not + # holding a note — and a slide is not out of tune FORMANT_DB = 1.6 AIR_DB = 2.5 BREATH = 0.14 +# THE SIBILANT RESTORE — @jeffrey: "the opening 's' is not hearable". +# It was never missing. In her source the /s/ of "sitting" runs 15 dB under +# the vowel that follows it; in the render that gap opens to 19, because +# the voiced half gets the formant lift, the air shelf and the breath and +# the unvoiced half — which is copied straight from the warped source — +# gets none of them. Four dB does not sound like much until the floor is +# under it, and then the consonant is simply gone. +# +# So: find the frames that are UNVOICED AND BRIGHT (a fricative is dim but +# bright — the same test audit.py uses to call an event FRIC) and give them +# back the level the voiced frames were given, plus a little more, because +# a sung sibilant in a mix needs to beat a hi-hat and not just itself. +# Ramped over 30 ms so it lifts the consonant rather than gating it. +SIB_DB = 8.0 # the lift on an unvoiced bright frame +SIB_HI_HZ = 3000.0 # "bright" is measured above here… +SIB_SHARE = 0.45 # …and means this much of the frame's energy +SIB_RAMP_S = 0.030 HALO_DARK_HZ = 5500.0 HALO_BREATH_X = 1.5 UNVOICED_W = 0.18 # consonant share of any stretch @@ -110,33 +131,82 @@ """WORLD analysis is 2.3 s a slice and depends only on the audio and the analysis constants — never on the chart. Tuning a bar re-ran it every time. Cached on disk, keyed by the file's mtime and the parameters, so an edit pays for synthesis only.""" - key = f"{os.path.basename(path)}-{int(os.path.getmtime(path))}-{FRAME_MS}-{FLOOR}-{SNAP}-{SMOOTH_MS}" + key = (f"{os.path.basename(path)}-{int(os.path.getmtime(path))}" + f"-{FRAME_MS}-{FLOOR}-{SNAP}-{SMOOTH_MS}-{GLIDE_ST_S}-nervox1-fitfloor1") dest = os.path.join(CACHE, key + ".npz") if os.path.exists(dest): z = np.load(dest) return dict(x=x, fs=fs, f0=z["f0"], f0c=z["f0c"], sp=z["sp"].astype(np.float64), ap=z["ap"].astype(np.float64), - voiced=z["voiced"]) + voiced=z["voiced"], rate=z["rate"]) a = analyze(x, fs) os.makedirs(CACHE, exist_ok=True) - np.savez(dest, f0=a["f0"], f0c=a["f0c"], voiced=a["voiced"], + np.savez(dest, f0=a["f0"], f0c=a["f0c"], voiced=a["voiced"], rate=a["rate"], sp=a["sp"].astype(np.float32), ap=a["ap"].astype(np.float32)) return a def analyze(x, fs): - f0_raw, t = pw.harvest(x, fs, f0_floor=FLOOR, f0_ceil=600.0, frame_period=FRAME_MS) + # THE FLOOR HAS TO FIT THE VOICE. FLOOR was set for Camille's take, + # which sits at 283 Hz; harvest below its floor does not return a low + # note, it returns a wrong one — usually the second harmonic — or + # nothing. Half the bank sings lower than she does. rq, sh and pf are + # all around 121 Hz, well UNDER the 140 Hz floor, so every one of them + # was analysed from a broken pitch track and everything downstream — + # the snap, the melody lock, THE HOLD — was reading it. @jeffrey: "it + # sounds so glitchy". That is what it was. + # + # So the range is measured before it is used: one wide probe to find + # where this voice actually lives, then the real analysis bracketed + # around it. Wide-open on every take would be worse than a fixed + # floor — the lower you let harvest look, the more freely it picks a + # subharmonic on a bright voice — so the bracket is snug. + # …and it only ever WIDENS. The spine is the record, and a bracket + # recomputed from a probe would have moved her ceiling from 600 to 849 + # on the next rebuild for no reason at all. Nothing moves unless the + # voice does not fit: FLOOR/600 stands for anyone it already suits. + probe, _t = pw.harvest(x, fs, f0_floor=55.0, f0_ceil=900.0, + frame_period=FRAME_MS) + voiced_probe = probe[probe > 0] + med = float(np.median(voiced_probe)) if len(voiced_probe) else TONIC + floor, ceil = FLOOR, 600.0 + if med * 0.55 < floor: # a voice lower than hers + floor = max(55.0, med * 0.55) + if med * 2.0 > ceil: # …or higher + ceil = min(1000.0, med * 3.0) + f0_raw, t = pw.harvest(x, fs, f0_floor=floor, f0_ceil=ceil, frame_period=FRAME_MS) f0 = pw.stonemask(x, f0_raw, t, fs) - fft = pw.get_cheaptrick_fft_size(fs, f0_floor=FLOOR) - sp = pw.cheaptrick(x, f0, t, fs, fft_size=fft, f0_floor=FLOOR) + fft = pw.get_cheaptrick_fft_size(fs, f0_floor=floor) + sp = pw.cheaptrick(x, f0, t, fs, fft_size=fft, f0_floor=floor) ap = pw.d4c(x, f0, t, fs, fft_size=fft) voiced = f0 > 0 corr = np.zeros_like(f0) if voiced.any(): corr[voiced] = -cents_to_grid(f0[voiced]) * SNAP + # A SLIDE IS NOT OUT OF TUNE. Smoothing the correction keeps a glide + # SMOOTH but still drags it onto the grid tone by tone, so a fast + # scoop comes out as a staircase — @jeffrey on the leap into "pa": + # "it feels a little extreme · maybe we need better auto tune on + # it". That leap is 8.4 semitones in 30 ms. So the snap now fades + # out wherever her pitch is genuinely MOVING. f0 is smoothed over + # 60 ms before the derivative, so vibrato (±0.5 st at ~5 Hz, ~16 + # st/s instantaneous) averages away and only a real transition + # survives; unvoiced gaps are interpolated across first, or their + # edges would read as infinite glides and disable the snap at every + # onset. + st = 12.0 * np.log2(np.maximum(f0, 1e-6) / TONIC) + idx = np.arange(len(f0)) + st = np.interp(idx, idx[voiced], st[voiced]) + rate = np.abs(np.gradient(smooth(st, int(60.0 / FRAME_MS)), + FRAME_MS / 1000.0)) + corr *= np.clip(1.0 - (rate - GLIDE_ST_S) / GLIDE_ST_S, 0.0, 1.0) + else: + rate = np.zeros_like(f0) corr = smooth(corr, int(SMOOTH_MS / FRAME_MS)) f0c = np.where(voiced, f0 * 2.0 ** (corr / 1200.0), 0.0) - return dict(x=x, fs=fs, f0=f0, f0c=f0c, sp=sp, ap=ap, voiced=voiced) + # `rate` travels with the analysis so nervox wavers exactly the frames + # the snap regulated, and lets go exactly where the snap let go. + return dict(x=x, fs=fs, f0=f0, f0c=f0c, sp=sp, ap=ap, voiced=voiced, rate=rate) def vuv_mask(voiced, fs, n): @@ -187,7 +257,6 @@ # "myself" under the OpenAI alignment, where # "curled" is ONE word — under whisper.cpp's # sub-word tokens it was cur+led and this was 5. # durs are POST-split indices. - "splits": [0], # The bar map, one phrase per bar (@jeffrey: # "curled up should be bar 1 — not bar 1 and # half of bar 2 · and in my should be bar @@ -268,7 +337,18 @@ # to halfway past beat 3 — in takes the # half beat (2.0, 1.23×) and my gives it # back (1.5, 1.07×), so self keeps bar 3 # and nothing downstream moves. - 4: 1.5, 5: 1.5, 6: 2.0, + # IN takes two full beats — @jeffrey: + # "'in' should last two full beats and my + # should start on bar 2:3 now". At 1.5 it + # ran 1.10× and handed "my" the 2:2.5 line; + # at 2 it is 1.47×, still her voice and + # nowhere near the 1.8 hold, and "my" opens + # square on bar 2 beat 3. + # SELF grows so "i" opens on bar 3:3 — + # @jeffrey: "'i' should move so it starts + # on bar 3:3 now". self goes 2 → 2.5 + # (1.02× → 1.23×), which lands i on 14.0. + 4: 2.0, 5: 1.5, 6: 2.5, # think 1 (1.17×, her own speed — at 2 # it was a 2.3× held tone), so OF keeps # its 4 beats at 1.01×, her real octave, @@ -278,8 +358,99 @@ # my on bar 2 beat 4; "i" takes the # freed beat (1.78×, still her voice) # so "of" keeps beat 19 and stone its # bar 6 beat 2. + # …and "i" pays for it. Giving IN its + # second beat pushed the whole back half + # off its lines — self 2:4.5, think 3:4.5, + # stone 6:1.5. "i" was the one word with + # slack anywhere near it: 0.71 s stretched + # over 2 beats at 1.39×. At 1.5 it runs + # 1.04×, her own speed, and think · of · a · + # stone are all back on the lines they were + # tuned to. Only self and i sit a half beat + # later than before. + # THINK on bar 4:1 — @jeffrey: "and think + # should start on bar 4:1". "i" takes its + # second beat back (1.04× → 1.39×, still + # well under the 1.8 hold) so it ends on + # 16.0 and think opens the bar. + # 2.0, and it must STAY a beat value. + # The +0.22 slice shift caught this one + # by accident — it is the only `durs` + # entry that sits alone on a line before + # a comment, which is exactly the shape + # the times-bumping pass looked for — so + # "i" became 2.22 and every word after it + # sat 0.22 of a beat late: @jeffrey, + # "these boundaries are still off · check + # the rest of the words too". durs are + # BEATS; times are SECONDS. Nothing in + # here shifts with the slice. 7: 2.0, - 8: 2.0, 9: 4.0, 10: 3.0, 11: 3.0, + # …and "a" pays this one, for free. Once + # stone took back its own /s/, "a" was + # 0.43 s of audio over 3 beats — 3.4×, far + # past the 1.8 hold line, so it is already + # a synthesized grid tone rather than her + # voice. 2.5 beats is 2.9×: the same + # synthetic hold, half a beat shorter, and + # stone is back on bar 6:1 with everything + # after it. + # "a" pays again — and this is the last + # half beat it has. @jeffrey set its floor + # at two ("a should be at least two beats, + # its too short now"), so anything after + # this has to come from "of" or run + # downstream. + # STONE'S PEAK ON THE BAR 6 EDGE — + # @jeffrey: "'stone' should shift just a + # little · so its peak lands on the bar 6 + # edge". The block was already on 6:1, but + # the block now opens with the /s/ it took + # back, and a consonant rides 1:1 through + # the warp — so her NOTE arrived 0.75 of a + # beat late and her peak 1.24 beats late. + # PEAK_LEAD_MAX_S is 90 ms, a lean, so this + # is the grid's job. Aligning the RMS PEAK + # was wrong — @jeffrey: "whoa now stone + # starts too soon". The peak sits 0.21 s + # after her vowel, so peak-on-the-beat + # opened the block 1.24 beats early and the + # /s/ arrived most of a bar before 6. Her + # VOWEL is the anchor a listener hears: it + # starts 0.37 s in, consonants ride ~1:1, + # so the slot opens 0.75 of a beat early at + # 23.25 and the note lands on 24.0 with the + # sibilant leading into it. stone holds + # 3.75 (1.39×) and still hands "just" the + # bar 6:4 line; of keeps its 4, and "a" + # takes 1.25 — 1.43×, her own voice rather + # than the 2.3× synthetic hold it was at 2 + # beats. + # …and then right a bit more — @jeffrey: + # "it should move to the right a bit + # more". Half a beat, bought from "of" + # (4 → 4.5, 1.37×; it is the held octave + # and takes the extra) rather than from + # "a", which at 1.75 would tip back over + # the 1.8 hold and go synthetic again. + # stone opens 23.75, its /t/ lands 24.51. + # JUST ON BAR 7 — @jeffrey: "and 'just' + # should start on bar 7 now". stone holds + # the extra beat itself (3.25 → 4.25, + # 1.57×, still under the 1.8 hold) rather + # than moving, so its /t/ stays on 24.51 + # and only what follows "just" shifts. + # OF ENDS ON BAR 5:3 — @jeffrey: "'of' + # should end at bar 5:3 start, and 'a' + # should start there". of back to 4 + # (18–22, 1.22×). That pins BOTH of a's + # edges — 22 to stone's 23.75 — so it is + # 1.75 beats, 2.0×, just over the hold: "a" + # is a sustained grid tone again rather + # than her voice. That is the cost of the + # two placements, and it is the connective + # in "of a stone", so it holds well. + 8: 2.0, 9: 4.0, 10: 1.75, 11: 4.25, # very longer, patiently slower # the tail on bars: just and waiting # a bar each (waiting on bar 8:1), @@ -289,31 +460,100 @@ # too fast and abrupt # waiting splits like sitting did, so # "ing" lands on the half bar 12: 4.0, 13: 2.0, 14: 2.0, 15: 2.0, - 16: 2.0, 17: 2.0, 18: 2.5, 19: 2.5 }, + # BAR 10 HOLDS pa AND tient, BAR 11 OPENS + # WITH ly — @jeffrey: "can pa and tient be + # just within bar 10?" · "and ly should be + # bar 11 first three beats". tient 2.5 → 2 + # ends it on 44.0 (0.94×, a hair quicker + # than she sang it) so pa·tient fill bar 10 + # exactly, and ly takes the freed half beat + # itself — 3 beats, 44–47, at 1.76×, just + # under the 1.8 hold, which is right for + # the held last syllable of the word. "for" + # keeps bar 11:4 and nothing downstream + # moves. + 16: 2.0, 17: 2.0, 18: 2.0, 19: 2.0, + # for and time were still the auto scale's + # — @jeffrey: "and for is two beats too" · + # "and time is 4 beats". Pinning them ends + # the auto scale on this line entirely: + # every unit's length is now a decision. + # time at 4 is 1.80×, right on the hold + # line, so it sustains as a grid tone — + # which is what a held "time" wants. + # …then @jeffrey squared the tail off: + # "'ly' should be two beats" · "'for' + # should be two beats" · "and time to pass + # each of those is 1 full bar". ly 3 → 2 + # pulls for back to 11:3, and from there + # the last three words own a bar each — + # time bar 12, to bar 13, pass bar 14. + # "to" at 4 beats is 2.05×, over the hold, + # so it sustains as a grid tone; "pass" + # lands at 1.65× and stays her voice. + 20: 2.0, 21: 4.0, 22: 4.0, 23: 4.0 }, # words whose syllables carry a melody must not # be flattened to one tone by THE HOLD # patiently is pa·tient·ly, three notes - "sylls": { 4: [(None, "my"), (4.50, "self")], - 11: [(None, "wait"), (13.70, "ing")], - 12: [(None, "ve"), (15.05, "ry")], - 13: [(None, "pa"), (16.80, "tient"), - (17.70, "ly")] }, + # ve|ry and pa|tient were both cut off the + # brightness column (audit's zoom), not by ear. + # very is legato — no level dip anywhere, because + # /r/ is an approximant — so the only edge is the + # note: she holds A#3 flat to 15.165 and only then + # glides to G#3. The old 15.05 opened "ry" 115 ms + # inside "ve"'s pitch, so ry sang ve's note first. + # patiently's /ʃ/ runs 16.655–16.825 (hf 0.9+, level + # −30); the old 16.80 left 145 ms of it in "pa" and + # gave "tient" the last 25 ms of its own consonant. + # sit|ting is MEASURED now, not found. The + # automatic fricative split put it at 0.865, + # 140 ms inside her "sit" vowel while it was + # still at −7 dB — it had been fine until unit 0 + # reached back for the /s/, which moved every + # landmark the search leans on. Her vowel holds + # to 0.945, decays into the /t/ closure and + # bottoms at 1.015; the burst is 1.025 and "ting" + # arrives 1.035 on its own note. The closure + # belongs to the syllable it opens. + "sylls": { 0: [(None, "sitting·a"), (1.00, "sitting·b")], + 4: [(None, "my"), (4.72, "self")], + 11: [(None, "wait"), (13.92, "ing")], + 12: [(None, "ve"), (15.39, "ry")], + 13: [(None, "pa"), (16.875, "tient"), + (17.92, "ly")] }, # "pa" stays on the F4 she sings — the leap up # from very's A#3 is the point of the phrase, # not something to smooth away. (`shift` is # still there if a unit ever needs moving.) # source seconds, read off her onsets, for the # words whisper-1 mistimed. PRE-split indices. - "end": 24.25, - "times": { 1: 1.51, # curled — the aligner cut at 1.465, + # 24.33 — her /s/ tapers out at 24.30. In the + # slice's clock (see the cap below). + "end": 24.55, + # THE S OF SITTING — @jeffrey: "id love a stronger + # 'ssss' sound at start of first english + # 'sittting too'". Her sibilant runs 0.065–0.295 + # in the SOURCE and the slice used to open at + # 0.280, so 215 ms of a 230 ms /s/ was thrown + # away before anything here ever saw it. The + # slice now starts at 0.06 — and every + # slice-relative time in this chart moved +0.22 + # with it — so the whole sibilant exists; this + # pin is what makes unit 0 actually HOLD it, + # rather than opening at the aligner's word start + # 220 ms later. With lead 0 it plays 1:1 as the + # pre-roll, so the record opens on her ssss and + # lands on the downbeat. + "times": { 0: 0.0, + 1: 1.73, # curled — the aligner cut at 1.465, # inside ting's decay (18% there, # 8% at 1.48), so curled opened # holding the end of "sitting". # Her /k/ closure is 1.52–1.58 and # belongs to curled; ting's decay # bottoms out at 1.50. - 2: 2.40, - 7: 7.15, # of — her onset is 7.17; + 2: 2.62, + 7: 7.37, # of — her onset is 7.17; # the aligner opened its span # 115 ms of silence early # up — the alignment put this @@ -323,12 +563,47 @@ # curled's block ended on the # first 20 ms of "up". Her level # valley is 2.38–2.42; the # boundary belongs in it. - 11: 12.70, # waiting - 12: 14.40, # very - 14: 18.54, # for - 15: 19.48, # time - 16: 21.20, # to - 17: 23.00 }, # pass + # A CONSONANT BELONGS TO THE NOTE IT + # LEADS INTO. The aligner hands a word + # over where the transcript does, which + # is at the vowel — so four words were + # opening after their own mouth had + # already played inside the word before. + # Each of these is the brightness column + # (audit's zoom), not a guess. + 9: 9.41, # stone — her /s/ is 290 ms + # of hf 0.99 running + # 9.19–9.48, then the /t/ + # closure to 9.56 and the + # vowel at 9.60. Opening at + # 9.555 put the WHOLE + # sibilant in "a" and let + # stone enter as "-tone". + 10: 11.315, # just — the /dʒ/ affricate + # steps up at 11.095 and + # brightens to 0.9 by 11.115; + # opening at 11.195 caught + # its last 20 ms and dropped + # the rest on the floor. + 11: 12.92, # waiting + 12: 14.62, # very + 13: 16.12, # patiently — her /p/ and the + # breath into it run + # 15.90–15.98 and her voice + # arrives at 15.98; "ry" was + # holding all of it. + 14: 18.76, # for + 15: 19.535, # time — the /t/ burst is + # 30 ms of hf 0.97 at 19.315 + # with its aspiration to + # 19.42. At 19.48 the word + # started on its vowel and + # "for" said the t. + 16: 21.42, # to + 17: 23.03 }, # pass — /p/ + breath from + # 22.81, voice from 22.945. + # 23.00 was 55 ms into her + # own attack. # rest AFTER the given unit, in beats # "the in should start sooner — at start of # bar 2": the rest after up goes entirely, so @@ -640,7 +915,24 @@ lead_cap = int(round(PEAK_LEAD_MAX_S / FRAME_S)) ants, voiced_at = [], [] # frames ahead of the beat for (s0, s1) in unit_src: v0 = s0 - lim = min(s0 + int(0.20 / FRAME_S), s1 - 1, F - 1) + # TWO MECHANISMS, TWO WINDOWS. 0.20 s cannot see a real sibilant — + # "sitting" opens on 235 ms of /s/ — so for the FIRST unit the + # search gave up mid-fricative, decided the word had no unvoiced + # runway, and set Z = 0. The render then carried 330 ms of pre-roll + # that lead_in never reported and the engine placed the whole vocal + # that late: @jeffrey, "seems like all other utterances got bumped". + # + # But widening it for EVERY unit is a different change, and a worse + # one. `ants` also decides how far a word leans back into the word + # before it, and the back half of this line is almost all + # consonant-initial — just /dʒ/, for /f/, time /t/, to /t/, pass + # /p/. At 0.40 they all started leaning at once and the whole + # second half moved: "just waiting very patiently for time to pass + # is all offset". The pickup is about the take's opening; the lean + # is a per-word gesture with its own calibration. Wide window for + # unit 0 only. + wide = 0.40 if len(voiced_at) == 0 else 0.20 + lim = min(s0 + int(wide / FRAME_S), s1 - 1, F - 1) while v0 < lim and not a["voiced"][v0]: v0 += 1 if not a["voiced"][min(v0, F - 1)]: @@ -798,6 +1090,17 @@ xw = np.zeros(n) take = min(n, pos.size) xw[:take] = x[pos[:take]] out = mask * y + (1 - mask) * xw + # …and now give the fricatives back what the voiced half was given. + # sp_o is already the post-lift envelope, so the brightness test + # reads the frame as it will be heard. + band = freqs > SIB_HI_HZ + share = sp_o[:, band].sum(1) / (sp_o.sum(1) + 1e-12) + fric = (~voiced_o) & (share > SIB_SHARE) + if fric.any(): + gf = np.where(fric, 10.0 ** (SIB_DB / 20.0), 1.0) + gf = smooth(gf, max(1, int(SIB_RAMP_S / FRAME_S))) + g = np.repeat(gf, int(fs * FRAME_S)) + out *= g[:n] if len(g) >= n else np.pad(g, (0, n - len(g)), constant_values=1.0) for (q0, q1) in rests: # a long rest is her room tone ping-ponged; without this it # pulses. Let the breath sound, then settle to almost nothing. @@ -867,6 +1170,64 @@ manifest = _seed(os.path.join(VOX4, ".manifest.json")) chart_c = [] # (phrase, lead_in_s, beats_total, [(beat, dur, st, t, lead)]) VOICING = {} # per phrase, voiced runs in beats — vowels vs consonants +# TAKECHARTS — a chart per take, not one chart lent around. +# @jeffrey: "our envelopes etc are still fitting like the original samples · +# we need to like restart the whole process for each actual take · or it +# will sound wonky". bin/takechart.py assembles a take's line from its +# per-word corpus files and measures its OWN onsets, syllable seams and +# notes; it keeps only `durs` from w-whole-line, because unit lengths in +# beats are the song and everything else in that entry is f- on one day. +# Registering the result here rather than warping afterwards is the whole +# point: the take then goes through this file's real pipeline — consonant +# runway, boundary snap, energy trim, note re-measurement, THE HOLD, +# nervox, the sibilant restore — and gets an envelope of its own. +# OPT-IN. These are a BENCH, not the record — @jeffrey: "sounds bad i think +# we should stick to our original". Registered unconditionally they would +# join every bare halo3 run, get built into the bank, and be loaded as +# samples by an engine that never asks for them. bin/tryout-takes.sh sets +# TAKES=1; nothing else does, so the record's pipeline is untouched. +_takes_path = os.path.join(LANE, "samples", ".takecharts.json") +if os.environ.get("TAKES") and os.path.exists(_takes_path): + _takes = json.load(open(_takes_path)) + for _name, _r in _takes.items(): + SLICES[_r["chart"]["slice"]] = _r["slice"] + ALIGN[_r["chart"]["slice"]] = _r["align"] + _c = dict(_r["chart"]) + for _k in ("durs", "times"): + _c[_k] = {int(_i): _v for _i, _v in (_c.get(_k) or {}).items()} + _c["sylls"] = {int(_i): [(None if _c0 is None else float(_c0), _l) + for _c0, _l in _cuts] + for _i, _cuts in (_c.get("sylls") or {}).items()} + CHART[_name] = _c + print(f"→ .takecharts.json registered {len(_takes)} take(s): " + f"{' '.join(sorted(_takes))}") + +# CHART-EDITS — what ChartWizard dragged. The CHART literal above stays the +# score, with its reasons written next to every number; the GUI writes only +# the numbers, into a sidecar merged over the top. Two authors, one file +# each, so a drag can never eat a paragraph explaining why a boundary is +# where it is — and `git diff chart-edits.json` is a readable list of what +# a session moved by hand. +_edits_path = os.path.join(LANE, "chart-edits.json") +if os.path.exists(_edits_path): + _edits = json.load(open(_edits_path)) + for _name, _e in _edits.items(): + if _name not in CHART: + continue + _ch = CHART[_name] + for _k in ("times", "durs", "gaps", "stretch"): + if _k in _e: + _ch[_k] = {**(_ch.get(_k) or {}), + **{int(_i): _v for _i, _v in _e[_k].items()}} + if "sylls" in _e: # [[null|seconds, label], …] + _ch["sylls"] = {**(_ch.get("sylls") or {}), + **{int(_i): [(None if _c[0] is None else float(_c[0]), _c[1]) + for _c in _cuts] + for _i, _cuts in _e["sylls"].items()}} + if "end" in _e: + _ch["end"] = _e["end"] + print(f"→ chart-edits.json merged over {len(_edits)} phrase(s)") + ONLY = {p for p in os.environ.get("PHRASES", "").split(",") if p} LEAD_ONLY = os.environ.get("LEAD_ONLY") is not None @@ -891,12 +1252,20 @@ # labelled a second late means the word BEFORE it swallows it whole, # which is the extra syllable heard inside "for". These are read off # her own onsets in the source and pinned. aligned = slice_name in ALIGN + # PROVENANCE. Every unit's left edge is owned by exactly one knob in + # the CHART, and ChartWizard has to write a drag back to that knob and + # no other: `pin` is the pre-split word index, `cut` is None for the + # word's own start (times[pin]) or k for its k-th syllable cut + # (sylls[pin][k-1]). The fricative sub-split makes a ·b edge that no + # knob owns — halo3 finds it in the audio — so it carries cut="auto" + # and the GUI refuses to drag it. if aligned: words = [dict(t=w["t"], start=t0_slice + w["start"], end=t0_slice + w["end"], f0_hz=w["f0_hz"], - note=w["note"]) for w in ALIGN[slice_name]["words"]] + note=w["note"], pin=i, cut=None) + for i, w in enumerate(ALIGN[slice_name]["words"])] else: - words = list(entry["word_f0"]) + words = [dict(w, pin=i, cut=None) for i, w in enumerate(entry["word_f0"])] for wi, ts in (ch.get("times") or {}).items(): if 0 <= wi < len(words): words[wi]["start"] = t0_slice + ts @@ -918,7 +1287,8 @@ head = next((c[1] for c in cuts if c[0] is None), base["t"]) cuts = [c for c in cuts if c[0] is not None] edges = [base["start"]] + [t0_slice + c[0] for c in cuts] + [base["end"]] labels = [head] + [c[1] for c in cuts] - words[wi:wi + 1] = [dict(base, start=edges[k], end=edges[k + 1], t=labels[k]) + words[wi:wi + 1] = [dict(base, start=edges[k], end=edges[k + 1], + t=labels[k], pin=wi, cut=(None if k == 0 else k)) for k in range(len(labels))] syll_pins.update(labels[1:]) # a measured cut is a measurement too @@ -940,7 +1310,17 @@ for ui in sorted(ch.get("splits", []), reverse=True): w = words[ui] f0 = int(round((w["start"] - t0_slice) / FRAME_S)) f1 = int(round((w["end"] - t0_slice) / FRAME_S)) - lo, run, split_f = f0 + max(3, (f1 - f0) // 4), 0, None + # AN ONSET CONSONANT IS NOT AN INTERNAL ONE. The search used to + # start a quarter of the way into the unit, which was fine while + # "sitting" began at its vowel — once the block reached back to + # take her 220 ms /s/, that quarter-point landed INSIDE the + # sibilant and split sit·ting 110 ms early, inside the first + # syllable. Skip the word's own opening unvoiced run first, then + # look a quarter of the way through what is left. + v0 = f0 + while v0 < f1 - 1 and v0 < len(a["voiced"]) and not a["voiced"][v0]: + v0 += 1 + lo, run, split_f = v0 + max(3, (f1 - v0) // 4), 0, None for f in range(lo, min(f1, len(a["voiced"]))): if not a["voiced"][f]: run += 1 @@ -953,7 +1333,7 @@ if split_f is None: split_f = (f0 + f1) // 2 ts = t0_slice + split_f * FRAME_S first = dict(w, end=ts, t=w["t"] + "·a") - second = dict(w, start=ts, t=w["t"] + "·b") + second = dict(w, start=ts, t=w["t"] + "·b", cut="auto") words[ui:ui + 1] = [first, second] # RE-MEASURE THE NOTE. f0_hz came from the aligner, over the span the # aligner thought the word had. Once `times` repins a boundary or a @@ -983,10 +1363,19 @@ unit_src.append((max(0, s0), min(F, max(s0 + 1, s1)))) unit_src, trims, rest_src = trim_units(x, fs, unit_src, [w["t"] for w in words]) unit_src = keep_attacks(unit_src, rest_src, x, fs) + # ONE CLOCK. `end` used to subtract the slice offset while `times` and + # `sylls` add it, so an `end` written in the same seconds you read off + # the zoom landed 280 ms early — @jeffrey: "i can't hear the s in + # pass". Her /s/ is 24.03–24.30 and the cap was falling at 23.97, in + # the gap before it, so the sibilant was cut every render. It is the + # slice's clock now, like every other time in this chart. if ch.get("end"): # the last word stops at the cap too - cap = int(round((ch["end"] - t0_slice) / FRAME_S)) - a0, b0_ = unit_src[-1] - unit_src[-1] = (a0, min(b0_, max(a0 + 1, cap))) + # …and it SETS the last unit's end rather than only clipping it. + # The aligner stopped "pass" at 24.20, inside her /s/, and a cap + # that can only shorten could never give the rest back. + cap = int(round(ch["end"] / FRAME_S)) + a0, _ = unit_src[-1] + unit_src[-1] = (a0, min(F, max(a0 + 1, cap))) gapsb = [ch.get("gaps", {}).get(i, 0.0) for i in range(len(ch["units"]))] idx, holds, fade, Z, ants, rise, rests = build_warp( @@ -997,9 +1386,82 @@ int(round((ch["end"] - t0_slice) / FRAME_S)) if ch.get("end") else None) f0_o = a["f0c"][idx].copy() voiced_o = a["voiced"][idx] - # THE HOLD — long stretches flatten to the unit's median grid tone + # THE MELODY LOCK — another take, HER tune. + # @jeffrey: "whoa the pitches are way off now". A take chart keeps the + # composition and re-measures the performance, and the first cut of it + # counted only `durs` as composition. But the snap regulates a voice + # toward the nearest degree of the A#-minor grid, not toward a NOTE — + # so with its own notes re-measured, every take sang its own tune, in + # its own octave. Melody is the song exactly as much as rhythm is. + # + # Each unit is moved onto the spine's semitone by an OFFSET rather than + # by rewriting f0 flat, so the take keeps its own vibrato, scoops and + # glides inside the note and only the note itself is hers. The line is + # folded by WHOLE OCTAVES to wherever the take actually sings — several + # of these voices sit an octave below her — because forcing her + # register on a low voice is a different song, not the same one. + # + # THE OFFSET IS A CURVE, NOT A STAIRCASE. The first version multiplied + # each unit by a constant and stopped there — @jeffrey: "it sounds so + # glitchy". It did: the pitch stepped instantly at every unit boundary, + # by up to several semitones, and WORLD renders a hard f0 step as a + # click. rq came out with 425 frames jumping more than 2 st against the + # spine's 132. So the offsets are laid on a per-frame track and + # smoothed with the same window the snap uses — which is why a real + # melodic leap survives: it is the CORRECTION that is smoothed, and the + # octave jump on "of" lives in the take's own contour underneath. + melody = ch.get("melody") + locked = None + if melody and len(melody) == len(ch["units"]): + want, have = np.array(melody, dtype=float), np.full(len(melody), np.nan) + bounds = [] + for u, (bt, du) in enumerate(ch["units"]): + o0 = Z + int(round(bt * SPB / FRAME_S)) + o1 = Z + int(round((bt + du) * SPB / FRAME_S)) + o0, o1 = max(0, o0), min(len(f0_o), o1) + bounds.append((o0, o1)) + seg = f0_o[o0:o1][voiced_o[o0:o1]] + seg = seg[seg > 0] + if len(seg): + have[u] = 12.0 * np.log2(float(np.median(seg)) / TONIC) + ok = ~np.isnan(have) + if ok.any(): + octs = round(float(np.median((have - want)[ok])) / 12.0) + locked = want + 12.0 * octs + # a unit with no usable voiced median gets its neighbours' + # correction rather than a cliff back to zero + delta_u = np.where(ok, locked - have, np.nan) + idxs = np.arange(len(delta_u)) + delta_u = np.interp(idxs, idxs[ok], delta_u[ok]) + track = np.zeros(len(f0_o)) + for u, (o0, o1) in enumerate(bounds): + if o1 > o0: + track[o0:o1] = delta_u[u] + if bounds: + track[:bounds[0][0]] = delta_u[0] + track[bounds[-1][1]:] = delta_u[-1] + track = smooth(track, int(SMOOTH_MS / FRAME_MS)) + f0_o = np.where(voiced_o, f0_o * 2.0 ** (track / 12.0), 0.0) + print(f" melody locked: {int(ok.sum())}/{len(want)} units onto the " + f"spine, {octs:+d} octave{'' if abs(octs) == 1 else 's'}, " + f"median move {np.median(np.abs(delta_u)):.1f} st") + + # THE HOLD — long stretches flatten to the unit's median grid tone. + # It reads the SOURCE analysis, which is right for the take the chart + # was measured from and wrong for any other: with a melody lock in + # front of it, every held note was being flattened back onto the pitch + # the singer originally sang and the lock silently undone. That is why + # rq's seven bad units were all its LONG ones, and why "of" — the one + # octave leap in the lyric — came out 16 semitones under the chart. + # Where the melody is locked, the hold sustains the note as it will be + # SUNG. Without a lock it reads the source exactly as before, so the + # spine is untouched. for (o0, o1, s0, s1) in holds: - seg = a["f0c"][s0:s1][a["voiced"][s0:s1]] + if locked is not None: + seg = f0_o[o0:o1][voiced_o[o0:o1]] + seg = seg[seg > 0] + else: + seg = a["f0c"][s0:s1][a["voiced"][s0:s1]] if not len(seg): continue med = np.median(seg) @@ -1031,7 +1493,15 @@ if o1 > o0: f0_o[o0:o1] *= 2.0 ** (semis / 12.0) renders = {} - out, _ = synth_from(a, idx, f0_o, fade=fade, rise=rise, rests=rests) + # NERVOX — @jeffrey: "i think wavering notes too / flanging and wiggling + # the pitches · so the voice sounds more nervous · lets call this + # 'nervox' technique". The snap is what makes her notes NOTES; this is + # what stops them being a machine's notes. Held frames only — the same + # glide test the snap uses, so the two never fight. pop/lib/nervox.py. + rate_o = a["rate"][idx] + f0_n = nervox_waver(f0_o, FRAME_S, rate=rate_o, voiced=voiced_o) + out, _ = synth_from(a, idx, f0_n, fade=fade, rise=rise, rests=rests) + out = nervox_flange(out, a["fs"]) sf.write(os.path.join(VOX4, f"{name}.wav"), out, fs) renders["lead"] = round(len(out) / fs, 3) @@ -1081,12 +1551,27 @@ k = j else: k += 1 - notes = [] + # WHICH LYRIC WORD IS THIS UNIT. The chart plays 24 units but the + # lyric has 18 words — "patiently" is three units, "sitting" and + # "myself" and "waiting" and "very" are two each. Anything warping a + # DIFFERENT take onto this chart has to know that grouping, or it + # maps 18 source words onto 24 slots by index and sings six of them + # twice. Both split mechanisms mark a continuation with `cut`, so a + # unit opens a new word exactly when `cut` is None. + notes, wi = [], -1 for u, (wd, (beat, durb)) in enumerate(zip(words, ch["units"])): - st = int(np.round(12.0 * np.log2(wd["f0_hz"] / TONIC))) if wd["f0_hz"] else 0 + if wd.get("cut") is None: + wi += 1 + # what the band doubles is what the voice SINGS — the locked note + # where there is one, the measured note otherwise. + if locked is not None: + st = int(round(locked[u])) + else: + st = int(np.round(12.0 * np.log2(wd["f0_hz"] / TONIC))) if wd["f0_hz"] else 0 st += int((ch.get("shift") or {}).get(u, 0)) notes.append((beat, durb, st, wd["t"].strip(), - round(ants[u] * FRAME_S / SPB, 4) if u < len(ants) else 0.0)) + round(ants[u] * FRAME_S / SPB, 4) if u < len(ants) else 0.0, + wi)) chart_c.append((name, lead_in, beats_total, notes)) VOICING[name] = voiced_runs # THE SPANS ACTUALLY PLAYED — after times, sylls, snapping, attack @@ -1098,8 +1583,9 @@ # alignment use — adding the source offset here silently shifted the # audit against the audio it was checking. played = [[w["t"], round(a_ * FRAME_S, 3), round(b_ * FRAME_S, 3)] for w, (a_, b_) in zip(words, unit_src)] + pins = [dict(t=w["t"], pin=w.get("pin"), cut=w.get("cut")) for w in words] manifest[name] = dict(slice=slice_name, lead_in=round(lead_in, 3), - spans=played, + spans=played, pins=pins, beats=beats_total, renders=renders, snaps=snaps, trims=trims, words=entry["words"]) print(f" {name:22s} {renders['lead']:5.2f}s lead·8ve×2·low3·low5 «{entry['words']}»") @@ -1110,8 +1596,8 @@ print(f" trimmed: {' · '.join(trims)}") _new_chart = dict(_old_chart) _new_chart.update({name: dict(leadIn=round(li, 3), beats=bt, voiced=VOICING[name], - notes=[dict(beat=b, dur=d, st=s, t=t, lead=ld) - for (b, d, s, t, ld) in ns]) + notes=[dict(beat=b, dur=d, st=s, t=t, lead=ld, w=wi) + for (b, d, s, t, ld, wi) in ns]) for (name, li, bt, ns) in chart_c}) json.dump(manifest, open(os.path.join(VOX4, ".manifest.json"), "w"), indent=1) @@ -1128,19 +1614,21 @@ "", f"#define CHART_BPM {BPM}", f"#define CHART_TONIC {TONIC}", "", - "typedef struct { double beat, dur; int st; } ChartNote;", + "// `t` is the unit's label — the C addresses a word by name so a", + "// treatment can be written against \"pa\" rather than against unit 17.", + "typedef struct { double beat, dur; int st; const char *t; } ChartNote;", "typedef struct { const char *name; double leadIn; double beats;", " int n; const ChartNote *notes; } ChartPhrase;", "", ] _all = [(nm, _new_chart[nm]["leadIn"], _new_chart[nm]["beats"], - [(q["beat"], q["dur"], q["st"], q["t"], q.get("lead", 0.0)) - for q in _new_chart[nm]["notes"]]) for nm in _new_chart] + [(q["beat"], q["dur"], q["st"], q["t"], q.get("lead", 0.0), q.get("w", i)) + for i, q in enumerate(_new_chart[nm]["notes"])]) for nm in _new_chart] for name, lead_in, beats_total, notes in _all: ident = name.replace("-", "_") lines.append(f"static const ChartNote {ident}_notes[] = {{") - for (beat, durb, st, _t, _lead) in notes: - lines.append(f" {{ {beat:.2f}, {durb:.2f}, {st} }},") + for (beat, durb, st, _t, _lead, _w) in notes: + lines.append(f' {{ {beat:.2f}, {durb:.2f}, {st}, "{_t}" }},') lines.append("};") lines.append("") lines.append("static const ChartPhrase CHART[] = {") diff --git a/pop/loner/bin/singdub.py b/pop/loner/bin/singdub.py new file mode 100644 --- /dev/null +++ b/pop/loner/bin/singdub.py @@ -0,0 +1,397 @@ +# singdub.py — make a translated line SING her melody. +# +# @jeffrey: "i wanna hear the other langs being sung with the beat · in the +# mix". +# +# bin/dub.py returns the translation SPOKEN in her voice. Spoken is not a +# verse: it has its own prosody, its own length, and no relationship to the +# bar. This puts it on the chart — the same 60-beat melody, note for note, +# that halo3 warps her English take onto. +# +# The move is f0-replace ([[pop-world-autotune]]), not pitch correction: +# the spoken line's own contour is discarded and the CHART's semitone is +# written in its place, because the point is her tune, not the carrier's +# intonation. What survives from the recording is the part that carries the +# language — the formants, the consonants, the aperiodicity. +# +# MAPPING. Her line is 24 charted units; a translation has a different +# number of syllables in a different order, so a word-for-word mapping does +# not exist and pretending otherwise is how you get gibberish on the beat. +# Instead the spoken line is split into VOICED RUNS (its own syllable +# nuclei, found in the audio) and those runs are distributed across the +# chart's notes proportionally. A language with more syllables than she has +# notes puts several syllables inside one note — which is melisma's +# opposite and exactly what a translated verse does. +# +# pop/.venv/bin/python pop/loner/bin/singdub.py fr es da ru hi +# → vox-dub/sung-.wav, one phrase long, starting at beat 0 + +import json, os, subprocess, sys, tempfile +import numpy as np +import soundfile as sf +import pyworld as pw + +HERE = os.path.dirname(os.path.abspath(__file__)) +LANE = os.path.dirname(HERE) +sys.path.insert(0, HERE) +sys.path.insert(0, os.path.join(os.path.dirname(LANE), "lib")) +from nervox import waver as nervox_waver, flange as nervox_flange + +TONIC = 237.0 +BPM = 122.0 +SPB = 60.0 / BPM +FRAME_MS = 5.0 +FRAME_S = FRAME_MS / 1000.0 +GATE_DB = -34.0 +MIN_RUN_S = 0.070 +GLIDE_S = 0.055 # how long f0 takes to arrive at a new note +VALLEY = 0.55 # an energy dip this deep is a syllable boundary + +# THE STRETCH IS NOT UNIFORM. halo3 warps her English this way and singdub +# has to as well — @jeffrey: "we need better durations / syllable checking · +# consonsnant / vowerl stretching · it feels broken". A vowel can be held +# for a whole bar and still sound like the vowel; a consonant held for a +# whole bar is a smear. So the slot's extra time is spent almost entirely +# on voiced frames, and consonants ride near their natural length. +W_VOWEL = 1.0 +W_CONS = 0.18 +HOLD_RATIO = 2.2 # past this, sustain the vowel instead of stretching + + +def ratio_cap(r): + """How much a CONSONANT may be slowed even inside a held note.""" + return min(r, 1.6) + + +def load_mp3(path): + """No mp3 decoder in soundfile — go through ffmpeg.""" + tmp = tempfile.mktemp(suffix=".wav") + subprocess.run(["ffmpeg", "-y", "-v", "error", "-i", path, + "-ac", "1", "-ar", "44100", tmp], check=True) + x, fs = sf.read(tmp, dtype="float64") + os.unlink(tmp) + return x, fs + + +def voiced_runs(x, fs, f0): + """Syllable nuclei, straight from the audio. + + Splitting on unvoiced gaps ALONE is not enough and French proved it: + "recroquevillée en moi-même" is continuously voiced, so the whole + phrase came back as one run, got assigned to one note, and the words + inside it were stretched into mush — @jeffrey heard it immediately. + A voiced run is therefore cut again at its energy VALLEYS, which is + where one syllable hands over to the next in a legato language. + """ + n = int(round(fs * FRAME_S)) + m = min(len(f0), len(x) // n) + rms = np.sqrt((x[:m * n].reshape(m, n) ** 2).mean(axis=1)) + gate = (np.max(np.abs(x)) or 1.0) * 10.0 ** (GATE_DB / 20.0) + on = (rms > gate) & (f0[:m] > 0) + + gross, k = [], 0 + while k < m: + if on[k]: + j = k + while j < m and on[j]: + j += 1 + if (j - k) * FRAME_S >= MIN_RUN_S: + gross.append((k, j)) + k = j + else: + k += 1 + + # smooth the envelope, then cut at every dip that is a real valley: + # deep enough against BOTH neighbouring peaks, and far enough from the + # last cut to be a syllable rather than a wobble. + w = max(1, int(round(0.030 / FRAME_S))) + env = np.convolve(rms, np.ones(w) / w, mode="same") + minsep = int(round(MIN_RUN_S / FRAME_S)) + runs = [] + for (a, b) in gross: + cuts = [a] + i = a + minsep + while i < b - minsep: + lo = env[i] + left = env[cuts[-1]:i].max() if i > cuts[-1] else lo + right = env[i:min(b, i + 2 * minsep)].max() + if lo < VALLEY * min(left, right) and lo == env[i - minsep // 2:i + minsep // 2].min(): + cuts.append(i) + i += minsep + else: + i += 1 + cuts.append(b) + runs += [(u, v) for u, v in zip(cuts[:-1], cuts[1:]) if v - u >= minsep // 2] + return runs, m + + +# THE LYRIC, in order. bin/takes.py indexed every utterance across nineteen +# takes and ten of them have all eighteen of these words on their own — so +# a whole line can be BUILT from a take rather than sliced out of one, with +# boundaries that are exact instead of transcribed. +LYRIC = ("sitting curled up in myself i think of a stone just waiting " + "very patiently for time to pass").split() +CORPUS_GAP_S = 0.06 # a breath between words, so they do not run together + + +def corpus_line(take): + """One take's whole line, assembled from its per-word corpus files. + + @jeffrey: "i guess we could try and map out other takes and see how + they sound solo". This is the cheap way in. singdub's other sources — + a scribed dub, an energy-detected spoken line — both GUESS where the + words are; samples/corpus is already cut per word, so the spans it + returns are measured, and any take that owns all eighteen words can be + charted without a transcription step at all. + """ + d = os.path.join(LANE, "samples", "corpus") + if not os.path.isdir(d): + return None + idx = {} + for f in os.listdir(d): + if not f.endswith(".wav") or f.count("-") < 2: + continue + tk, _, w = f[:-4].split("-", 2) + if tk == take: + idx[w] = os.path.join(d, f) + if any(w not in idx for w in LYRIC): + return None + parts, spans, fs, n = [], [], None, 0 + for w in LYRIC: + y, fs = sf.read(idx[w], dtype="float64") + if y.ndim > 1: + y = y.mean(axis=1) + spans.append((n / fs, (n + len(y)) / fs)) + parts.append(y) + n += len(y) + gap = np.zeros(int(CORPUS_GAP_S * fs)) + parts.append(gap) + n += len(gap) + return np.concatenate(parts), fs, spans, list(LYRIC) + + +def main(): + langs = sys.argv[1:] or ["fr"] + chart = json.load(open(os.path.join(LANE, "vox4", ".chart.json")))["w-whole-line"] + notes = chart["notes"] + total_beats = chart["beats"] + + for lang in langs: + # `lang` may name a TAKE instead of a translation. @jeffrey: "lets + # work on swap lead and also use / bring in group takes · but the + # idea is we start small with camille's softest take then we build + # up each one". Putting another take on the chart is the same job + # as putting another language on it — different words in, her + # melody out — so s-whole-line and the ensemble o-whole-line go + # through this path rather than needing their own hand-pinned + # chart, which is a session's work each. + built = corpus_line(lang) + take = os.path.join(LANE, "samples", f"{lang}.wav") + src = os.path.join(LANE, "vox-dub", f"sts-{lang}.mp3") + if built: + x, fs, corpus_spans, corpus_labels = built + else: + corpus_spans = None + if os.path.exists(take): + src = take + elif not os.path.exists(src): + src = os.path.join(LANE, "vox-dub", f"spoken-{lang}.mp3") + if not os.path.exists(src): + print(f" {lang}: no corpus take, no samples/{lang}.wav, " + f"nothing in vox-dub/") + continue + if src.endswith(".wav"): + x, fs = sf.read(src, dtype="float64") + if x.ndim > 1: + x = x.mean(axis=1) + else: + x, fs = load_mp3(src) + + f0r, t = pw.harvest(x, fs, f0_floor=80.0, f0_ceil=600.0, frame_period=FRAME_MS) + f0 = pw.stonemask(x, f0r, t, fs) + fft = pw.get_cheaptrick_fft_size(fs, f0_floor=80.0) + sp = pw.cheaptrick(x, f0, t, fs, fft_size=fft, f0_floor=80.0) + ap = pw.d4c(x, f0, t, fs, fft_size=fft) + # PREFER THE WORDS. @jeffrey: "per language we should be able to map + # the shape of the words etc". dub.py scribe returns this language's + # real word spans, so the verse is charted word by word the way the + # English one is; the energy detector below is only the fallback for + # a language that has not been scribed yet. + wpath = os.path.join(LANE, "vox-dub", ".words.json") + words = json.load(open(wpath)).get(lang) if os.path.exists(wpath) else None + if corpus_spans: + runs = [(int(a_ / FRAME_S), int(b_ / FRAME_S)) + for (a_, b_) in corpus_spans] + labels = corpus_labels + src_kind = "corpus words" + elif words: + runs = [(int(w["start"] / FRAME_S), int(w["end"] / FRAME_S)) + for w in words] + runs = [(a_, b_) for (a_, b_) in runs if b_ > a_] + labels = [w["t"] for w in words] + src_kind = "words" + else: + runs, _m = voiced_runs(x, fs, f0) + labels = [f"~{i}" for i in range(len(runs))] + src_kind = "syllables" + if not runs: + print(f" {lang}: nothing to map"); continue + + # the output timeline: one phrase, on the grid + out_frames = int(round(total_beats * SPB / FRAME_S)) + idx = np.zeros(out_frames, dtype=int) + st_out = np.full(out_frames, np.nan) + ratios = [] # so a bad duration is visible, not just audible + + # distribute this language's syllables across her notes + # EVERY NOTE GETS A WORD. Mapping word→note leaves notes empty + # whenever a language has fewer words than she has notes — French + # left seven silent, Russian nine, and a melody with holes in it is + # not her melody. Mapping note→word instead guarantees coverage: a + # language with fewer words simply holds one across several notes, + # which is what a singer does with a long line and few syllables. + R = len(runs) + buckets = [[] for _ in notes] + nwords = max(nt.get("w", k) for k, nt in enumerate(notes)) + 1 + if R == nwords: + # THE SAME LYRIC, A DIFFERENT TAKE. This chart plays 24 units + # but the lyric is 18 words — "patiently" is three units, + # "sitting" and "myself" and "waiting" and "very" are two + # each. The index spread below is for TRANSLATIONS, where the + # word counts genuinely differ and holding one word across + # several notes is what a singer would do. Run it on another + # take of the same words and `k * 18 // 24` hands words 0, 3, + # 6, 9, 12 and 15 to two adjacent notes apiece — @jeffrey: + # "the second run of samples around 1:10 is all fucked up". + # It was: six words sung twice, then flattened by THE HOLD. + # + # When the counts match, the mapping is known exactly. Each + # word goes to ITS units, and a word spanning several units is + # CUT between them rather than repeated — proportionally by + # note length, then nudged onto the nearest unvoiced frame, + # because the seam inside "pa|tient|ly" is the /t/. + by_word = {} + for k, nt in enumerate(notes): + by_word.setdefault(nt.get("w", k), []).append(k) + for w, ks in sorted(by_word.items()): + u, v = runs[w] + durs = [notes[k]["dur"] for k in ks] + tot = sum(durs) or 1.0 + edges, acc = [u], 0.0 + for d in durs[:-1]: + acc += d + e = u + int(round((v - u) * acc / tot)) + # snap to a consonant: search ±12% of the word for a + # frame she is not voicing + win = max(2, int(0.12 * (v - u))) + cand = [f for f in range(max(u + 1, e - win), + min(v - 1, e + win)) + if f < len(f0) and f0[f] <= 0] + if cand: + e = min(cand, key=lambda f: abs(f - e)) + edges.append(max(edges[-1] + 1, e)) + edges.append(max(edges[-1] + 1, v)) + for j, k in enumerate(ks): + buckets[k] = [(edges[j], edges[j + 1])] + print(f" {lang}: same lyric — {R} words → {len(notes)} units, " + f"{len(notes) - R} syllable cuts") + else: + for k in range(len(notes)): + buckets[k].append(runs[min(R - 1, k * R // len(notes))]) + + for k, nt in enumerate(notes): + a = int(round(nt["beat"] * SPB / FRAME_S)) + b = int(round((nt["beat"] + nt["dur"]) * SPB / FRAME_S)) + a, b = max(0, a), min(out_frames, b) + if b <= a: + continue + group = buckets[k] + if not group: # nobody sings here — hold the + idx[a:b] = idx[a - 1] if a else 0 # previous frame, silently + continue + # this bucket's source frames… + srcf = np.concatenate([np.arange(u, v) for (u, v) in group]) + # …warped through a WEIGHTED clock, so the slot's extra time is + # spent on vowels and the consonants keep their own length. + wts = np.where(f0[srcf] > 0, W_VOWEL, W_CONS) + cum = np.concatenate([[0.0], np.cumsum(wts)]) + cum /= cum[-1] + pos = np.interp((np.arange(b - a) + 0.5) / (b - a), + cum, np.arange(len(cum), dtype=float)) - 0.5 + + # THE HOLD. A spoken syllable is ~0.15 s and one of her notes is + # up to 2 s, so the honest stretch is 10–30x — and marching + # through a syllable twenty times too slowly is a slur, not a + # held note. Past HOLD_RATIO the syllable stops being stretched + # and its VOWEL is sustained instead: the frame index dwells + # around the vowel's centre, drifting slowly so the spectrum + # keeps evolving rather than freezing into a buzz. Consonants + # are untouched — they still play once, at their own speed. + ratio = (b - a) / max(1, len(srcf)) + if ratio > HOLD_RATIO: + vi = np.where(f0[srcf] > 0)[0] + if len(vi) >= 3: + c0, c1 = vi[0], vi[-1] + head = int(c0 / max(ratio_cap(ratio), 1e-6)) + tail = int((len(srcf) - 1 - c1) / max(ratio_cap(ratio), 1e-6)) + n_out = b - a + head = min(head, n_out // 4) + tail = min(tail, n_out // 4) + body = max(1, n_out - head - tail) + mid, span = 0.5 * (c0 + c1), max(1.0, (c1 - c0) * 0.5) + # a slow triangle through the vowel — never the same + # frame twice in a row, never outside the vowel + ph = np.linspace(0, body / (0.55 / FRAME_S), body) + drift = mid + span * (2.0 / np.pi) * np.arcsin(np.sin(ph)) + pos = np.concatenate([ + np.linspace(0, c0, head, endpoint=False) if head else np.zeros(0), + drift, + np.linspace(c1, len(srcf) - 1, tail) if tail else np.zeros(0), + ])[:n_out] + if len(pos) < n_out: + pos = np.pad(pos, (0, n_out - len(pos)), mode="edge") + idx[a:b] = srcf[np.clip(np.round(pos).astype(int), 0, len(srcf) - 1)] + st_out[a:b] = nt["st"] + ratios.append((nt["t"], len(group), len(srcf) * FRAME_S, + (b - a) * FRAME_S)) + + # HER MELODY, written over the carrier's intonation. Glide into each + # new note instead of stepping — a step reads as a splice. + st_f = st_out.copy() + last = st_f[~np.isnan(st_f)][0] if np.any(~np.isnan(st_f)) else 0.0 + g = max(1, int(GLIDE_S / FRAME_S)) + for i in range(out_frames): + if np.isnan(st_f[i]): + st_f[i] = last + else: + last = st_f[i] + sm = np.convolve(st_f, np.ones(g) / g, mode="same") + f0_new = TONIC * 2.0 ** (sm / 12.0) + voiced_o = f0[idx] > 0 + f0_new = np.where(voiced_o, f0_new, 0.0) + f0_new = nervox_waver(f0_new, FRAME_S, voiced=voiced_o) + + y = pw.synthesize(f0_new, sp[idx].copy(order="C"), ap[idx].copy(order="C"), + fs, frame_period=FRAME_MS) + y = nervox_flange(y, fs) + pk = np.max(np.abs(y)) or 1.0 + y = y / pk * 0.85 + + dest = os.path.join(LANE, "vox-dub", f"sung-{lang}.wav") + sf.write(dest, y, fs) + # SYLLABLE CHECKING. A note holding four syllables, or one stretched + # 4x, is where a translated verse turns to mush — print it rather + # than wait to hear it. + worst = sorted(ratios, key=lambda r: -(r[3] / max(r[2], 1e-6)))[:3] + empty = len(notes) - len(ratios) + crowd = max((r[1] for r in ratios), default=0) + print(f" ✓ {lang}: {dest} {len(y) / fs:.1f}s · {R} syllables over " + f"{len(notes)} notes · {empty} notes empty · " + f"up to {crowd} syllables in one note") + for t, ns, src_s, slot_s in worst: + print(f" {t:>8} {ns} syll {src_s:.2f}s → {slot_s:.2f}s " + f"{slot_s / max(src_s, 1e-6):.2f}x") + + +if __name__ == "__main__": + main() diff --git a/pop/loner/bin/stage-takes.sh b/pop/loner/bin/stage-takes.sh new file mode 100644 --- /dev/null +++ b/pop/loner/bin/stage-takes.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +# stage-takes.sh — level-match every lead take before it enters the engine. +# +# @jeffrey: "i think we need to master / treat each vocal separate right?" +# Right. The three takes were recorded in three rooms at three distances: +# f- lands at −22.1 LUFS raw, s- at −16.8, o- (the group) at −12.2. Warping +# them onto the chart does not fix that — it carries it. Dropping them into +# the arrangement at hand-picked gains means every gain has to be re-guessed +# whenever a take is re-rendered. +# +# So each take is MEASURED and moved by ONE static dB to a common integrated +# loudness, exactly the way the lane masters a mix. After this, a gain in +# lonerremix.c means the same thing whichever take it is applied to, and the +# swap is a change of ROOM rather than a change of level. +set -euo pipefail +LANE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +# THE REFERENCE IS THE SPINE. f- is the take that was charted by hand, word +# by word; the others are warped onto ITS chart. So it sets the level too, +# rather than all three being moved to some outside number that would drift +# the moment halo3.py re-renders. +lufs() { ffmpeg -hide_banner -nostats -i "$1" -af ebur128 -f null - 2>&1 \ + | awk '/I:/{v=$2} END{print v}'; } +peak() { ffmpeg -hide_banner -nostats -i "$1" -af volumedetect -f null - 2>&1 \ + | awk -F': ' '/max_volume/{gsub(/ dB/,"",$2); print $2}'; } + +TARGET="${TARGET:-$(lufs "$LANE/vox4/w-whole-line.wav")}" + +stage() { # stage + local src="$1" dest="$LANE/vox4/$2.wav" + local i g + i=$(lufs "$src") + # THE LANE'S MASTERING LAW, on one voice: MEASURE → one static dB → true- + # peak limiter. Clamping the static gain instead — taking the smaller of + # the loudness move and whatever kept the peak at −1 — sounds safe and is + # not: a take with sharp word onsets (the corpus lines are cut per word, + # so every word starts with one) loses the whole match. try-pf wanted + # +6.0 dB, the clamp allowed +0.4, and it arrived nearly 6 dB under the + # take it was being compared against. A limiter catching the top few dB + # of a sparse vocal is far less of a change than that. + g=$(awk -v i="$i" -v t="$TARGET" 'BEGIN{printf "%.2f", t-i}') + # PCM_16, matching what halo3 writes into the bank. The C loader reads + # anything, but bin/timeline.py draws its waveform through the stdlib + # `wave` module and that refuses float ("unknown format: 3") — which + # killed the whole audition batch after the first take. + ffmpeg -y -v error -i "$src" \ + -af "volume=${g}dB,alimiter=limit=0.891:attack=4:release=60:level=disabled" \ + -c:a pcm_s16le "$dest" + printf " %-12s %8s LUFS → %+6s dB → %s LUFS, peak %s dB\n" \ + "$2" "$i" "$g" "$(lufs "$dest")" "$(peak "$dest")" +} + +# stage-takes.sh stages exactly that one and stops — +# bin/tryout-takes.sh uses this to bench a take without touching the record. +if [ $# -eq 2 ]; then + echo "→ level-matching $2 to the f- spine ($TARGET LUFS)" + stage "$1" "$2" + exit 0 +fi + +echo "→ level-matching leads to the f- spine ($TARGET LUFS)" +stage "$LANE/vox-dub/sung-s-whole-line.wav" alt-soft +# THE GROUP TAKE IS NOT STAGED. o-whole-line is Camille, @jeffrey and Alex +# together, and @jeffrey: "lets not do the group vocals anymore · they are +# weird". The chart is one pitch contour and singdub f0-REPLACES the take +# with it — fine for a solo, where harvest tracks one larynx cleanly, but +# three voices singing slightly apart give an f0 estimate that flickers +# between whoever is loudest, and the warp smears the ensemble into one +# synthetic voice. To use that take it would have to be PLACED as a +# performance rather than resynthesised: +# stage "$LANE/vox-dub/sung-o-whole-line.wav" alt-group diff --git a/pop/loner/bin/takechart.py b/pop/loner/bin/takechart.py new file mode 100644 --- /dev/null +++ b/pop/loner/bin/takechart.py @@ -0,0 +1,230 @@ +# takechart.py — give a take its OWN chart, instead of borrowing hers. +# +# @jeffrey: "our envelopes etc are still fitting like the original samples · +# we need to like restart the whole process for each actual take · or it +# will sound wonky". +# +# He is right, and it is a structural thing rather than a mixing one. +# bin/singdub.py warps another take onto the chart halo3 built FROM f-, and +# that chart is two different kinds of number tangled together: +# +# THE COMPOSITION beats, and `durs` — how many BEATS each unit gets. +# This is the music. It is the same for every take. +# F-'S PERFORMANCE `times` (13 hand-pinned onsets), `sylls` (5 measured +# syllable cuts), `end`. All SECONDS into +# f-whole-line.wav. These describe one singer on one +# day, and nothing about them transfers. +# +# singdub also never reads `lead`/`ants`, so every word it places starts AT +# the slot edge — where halo3 puts the VOWEL on the beat and runs the +# consonant 1:1 before it, the way a singer leans in. A borrowed envelope +# and no runway is exactly "wonky". +# +# So this restarts the process. It keeps the composition and re-measures +# everything else against the take's own audio, which is cheap because +# samples/corpus is already cut per word: the 18 onsets that took a session +# to pin by hand for f- are simply the file boundaries here. Only the +# syllable cuts inside the five multi-syllable words have to be found, and +# they are found in THAT take's voice. +# +# The output is a sidecar halo3 reads, so each take then goes through the +# WHOLE pipeline — consonant runway, boundary snap, energy trim, note +# re-measurement, the weighted warp clock, THE HOLD, nervox, the sibilant +# restore — rather than a warp bolted on afterwards. +# +# pop/.venv/bin/python pop/loner/bin/takechart.py rq sh lg +# PHRASES=w-rq LEAD_ONLY=1 pop/.venv/bin/python pop/loner/bin/halo3.py +import json, os, sys +import numpy as np +import soundfile as sf +import pyworld as pw + +HERE = os.path.dirname(os.path.abspath(__file__)) +LANE = os.path.dirname(HERE) +FRAME_MS = 5.0 +FRAME_S = FRAME_MS / 1000.0 +TONIC = 237.0 +# THE ASSEMBLER HAS TO LEAVE ROOM FOR THE RUNWAY. halo3 puts a word's +# VOWEL on its beat and runs the consonant 1:1 before it, so a word needs +# space to lean back into. The measured runways here reach 0.53 beats +# (0.26 s), and butting the corpus files together at 0.10 s meant a +# consonant either did not fit or ate the end of the word before it. +# The head pad is the same thing for word 0: with "sitting" starting at +# sample 0 there was nowhere for its /s/ to go and the phrase came out +# with leadIn 0.000 — the opening sibilant missing, exactly as it went +# missing from the record. +GAP_S = 0.25 +HEAD_S = 0.40 +# EVERY CUT EDGE IS A CLICK. The corpus files were sliced out of longer +# takes, so each one starts and ends on whatever sample the cut landed on +# — butting eighteen of them together left 754 step discontinuities in +# rq-line against 386 in her own unbroken take, and @jeffrey heard the +# difference: "it sounds so glitchy". A 6 ms cosine at each edge costs +# nothing audible and removes all of them. +EDGE_S = 0.006 +NAMES = "C C# D D# E F F# G G# A A# B".split() + +LYRIC = ("sitting curled up in myself i think of a stone just waiting " + "very patiently for time to pass").split() +# how many syllables each word is sung across — the only thing about the +# split that is compositional. WHERE the cut falls is per-take and measured. +SYLLS = {0: ["sitting·a", "sitting·b"], 4: ["my", "self"], + 11: ["wait", "ing"], 12: ["ve", "ry"], 13: ["pa", "tient", "ly"]} + + +def note_name(hz): + if not hz: + return "?" + m = int(round(69 + 12 * np.log2(hz / 440.0))) + return f"{NAMES[m % 12]}{m // 12 - 1}" + + +def take_words(take): + d = os.path.join(LANE, "samples", "corpus") + idx = {} + for f in os.listdir(d): + if f.endswith(".wav") and f.count("-") >= 2: + tk, _, w = f[:-4].split("-", 2) + if tk == take: + idx[w] = os.path.join(d, f) + return idx if all(w in idx for w in LYRIC) else None + + +def syllable_cuts(x, fs, f0, s, e, k): + """The k−1 seams inside one sung word, found in this take's own voice. + + A syllable boundary is where the voice thins: an unvoiced frame (the + /t/ of pa|tient|ly), or failing that the deepest dip in energy. Score + every interior frame for both, then take the best k−1 that are far + enough apart to be real syllables rather than one wobble counted twice. + """ + f_a, f_b = int(s / FRAME_S), int(e / FRAME_S) + f_b = min(f_b, len(f0)) + if k < 2 or f_b - f_a < 8: + return [] + hop = int(FRAME_S * fs) + rms = np.array([np.sqrt(np.mean(x[i * hop:(i + 1) * hop] ** 2)) + 1e-9 + for i in range(f_a, f_b)]) + db = 20 * np.log10(rms / rms.max()) + voiced = f0[f_a:f_b] > 0 + # skip the word's own onset consonant — that is an edge, not a seam + lo = int(np.argmax(voiced)) if voiced.any() else 0 + lo = max(lo + 2, int(0.12 * len(db))) + hi = len(db) - max(2, int(0.12 * len(db))) + if hi - lo < k: + return [] + score = (~voiced).astype(float) * 6.0 - db / 6.0 + sep = max(2, (hi - lo) // (k + 1)) + picked = [] + order = sorted(range(lo, hi), key=lambda i: -score[i]) + for i in order: + if len(picked) == k - 1: + break + if all(abs(i - j) >= sep for j in picked): + picked.append(i) + return [round(s + i * FRAME_S, 4) for i in sorted(picked)] + + +def build(take, durs, melody, beats): + idx = take_words(take) + if not idx: + print(f" {take}: does not own all 18 lyric words") + return None + y0, fs = sf.read(idx[LYRIC[0]], dtype="float64") + parts, spans, n = [np.zeros(int(HEAD_S * fs))], [], int(HEAD_S * fs) + for w in LYRIC: + y, fs = sf.read(idx[w], dtype="float64") + if y.ndim > 1: + y = y.mean(axis=1) + e = min(int(EDGE_S * fs), len(y) // 4) + if e > 1: + ramp = 0.5 - 0.5 * np.cos(np.linspace(0.0, np.pi, e)) + y = y.copy() + y[:e] *= ramp + y[-e:] *= ramp[::-1] + spans.append((n / fs, (n + len(y)) / fs)) + parts.append(y) + n += len(y) + g = np.zeros(int(GAP_S * fs)) + parts.append(g) + n += len(g) + x = np.concatenate(parts[:-1]) # no trailing breath + slice_name = f"{take}-line" + sf.write(os.path.join(LANE, "samples", f"{slice_name}.wav"), x, fs) + + f0r, t = pw.harvest(x, fs, f0_floor=80.0, f0_ceil=600.0, frame_period=FRAME_MS) + f0 = pw.stonemask(x, f0r, t, fs) + + words = [] + for i, (w, (s, e)) in enumerate(zip(LYRIC, spans)): + seg = f0[int(s / FRAME_S):int(e / FRAME_S)] + seg = seg[seg > 0] + hz = float(np.median(seg)) if len(seg) else 0.0 + words.append(dict(t=w, start=round(s, 4), end=round(e, 4), + f0_hz=round(hz, 1), note=note_name(hz))) + + sylls = {} + for wi, labels in SYLLS.items(): + s, e = spans[wi] + cuts = syllable_cuts(x, fs, f0, s, e, len(labels)) + if len(cuts) != len(labels) - 1: + print(f" {take}: could not seam {LYRIC[wi]} — left whole") + continue + sylls[str(wi)] = [[None, labels[0]]] + [[c, labels[j + 1]] + for j, c in enumerate(cuts)] + + med = float(np.median(f0[f0 > 0])) if (f0 > 0).any() else 0.0 + return dict( + slice=dict(source=f"corpus/{take}", start=0.0, end=round(len(x) / fs, 3), + words="the whole lyric, assembled from corpus", + dur=round(len(x) / fs, 3), median_f0_hz=round(med, 1), + word_f0=words), + align=dict(model="corpus", text=" ".join(LYRIC), words=words), + chart=dict(slice=slice_name, beats=beats, lead=0.0, + durs={str(i): d for i, d in enumerate(durs)}, + # THE MELODY IS THE SONG, not the singer. The first cut + # of this file kept only `durs` as compositional and let + # each take's notes be re-measured from its own voice — + # @jeffrey: "whoa the pitches are way off now". They + # were: every take was being autotuned to the nearest + # scale degree of ITS OWN contour, so it sang its own + # tune in its own octave. Rhythm AND melody are the + # composition; only the TIMING — onsets, syllable + # seams, consonant runways — belongs to the take. + melody=melody, + sylls=sylls, + times={str(i): round(s, 4) for i, (s, _) in enumerate(spans)}, + end=round(spans[-1][1], 4)), + name=slice_name) + + +def main(): + takes = sys.argv[1:] + if not takes: + print("usage: takechart.py [take…]"); return + # THE COMPOSITION, read off the built chart rather than restated: unit + # lengths in BEATS, which is the one part of w-whole-line that is the + # song and not the singer. + built = json.load(open(os.path.join(LANE, "vox4", ".chart.json")))["w-whole-line"] + durs = [n["dur"] for n in built["notes"]] + melody = [n["st"] for n in built["notes"]] + beats = round(sum(durs), 4) + print(f"→ the composition: {len(durs)} units, {beats} beats, " + f"melody {min(melody)}..{max(melody)} st") + + path = os.path.join(LANE, "samples", ".takecharts.json") + out = json.load(open(path)) if os.path.exists(path) else {} + for tk in takes: + r = build(tk, durs, melody, beats) + if not r: + continue + out[f"w-{tk}"] = r + cuts = sum(len(v) - 1 for v in r["chart"]["sylls"].values()) + print(f" ✓ w-{tk:4s} → samples/{r['name']}.wav " + f"{r['slice']['dur']:5.2f}s · 18 words pinned exactly · " + f"{cuts} syllable seams found · median {r['slice']['median_f0_hz']:.0f} Hz") + json.dump(out, open(path, "w"), indent=1) + print(f"WROTE {path} ({len(out)} takes)") + + +main() diff --git a/pop/loner/bin/takes.py b/pop/loner/bin/takes.py new file mode 100644 --- /dev/null +++ b/pop/loner/bin/takes.py @@ -0,0 +1,99 @@ +# takes.py — every utterance she has, across every take. +# +# @jeffrey: "process other takes of the whistlegraph / other lyrics / +# samples · that we can use for harmonizes and other lines / swap out +# utterances as needed or whjatnot". +# +# Swapping a word today means remembering which take had a better "pa" +# and hunting for it. This makes it a lookup: every aligned slice's words, +# each with the span that holds it, the pitch she actually sings there, +# and how far that sits off the A# minor grid in her own 237 Hz frame. +# Words are keyed by their lowercased text, so `stone` lists every stone +# in the bank side by side and a swap is a choice between measured +# options rather than a memory. +# +# Same measurements as audit.py — one instrument for the whole lane. +# +# pop/.venv/bin/python pop/loner/bin/takes.py # the index +# pop/.venv/bin/python pop/loner/bin/takes.py stone # one word + +import json, os, sys +import numpy as np +import soundfile as sf + +HERE = os.path.dirname(os.path.abspath(__file__)) +LANE = os.path.dirname(HERE) +sys.path.insert(0, HERE) +from audit import columns, TONIC, FRAME_S + +MINOR = [0, 2, 3, 5, 7, 8, 10] +NAMES = ["A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A"] + + +def note_name(st): + """Her semitone, as a name in the take's own frame (A#3 = 0).""" + k = int(round(st)) + return f"{NAMES[k % 12]}{3 + (k + 0) // 12}" + + +def off_grid(st): + """Cents from the nearest scale tone — how far she is from the grid.""" + pc = (st * 100.0) % 1200.0 + return min(((pc - g * 100.0 + 600) % 1200) - 600 for g in MINOR + [12]) + + +def main(): + want = sys.argv[1].lower() if len(sys.argv) > 1 else None + align = json.load(open(os.path.join(LANE, "samples", ".align.json"))) + man = json.load(open(os.path.join(LANE, "samples", ".manifest.json"))) + index = {} + + for slice_name in sorted(align): + wav = os.path.join(LANE, "samples", f"{slice_name}.wav") + if not os.path.exists(wav): + continue + x, fs = sf.read(wav, dtype="float64") + if x.ndim > 1: + x = x.mean(axis=1) + f0, st, rms, hi, peak, m = columns(x, fs) + + for w in align[slice_name]["words"]: + a, b = w["start"], w["end"] + k0, k1 = int(a / FRAME_S), min(m, int(b / FRAME_S)) + seg = st[k0:max(k0 + 1, k1)] + seg = seg[~np.isnan(seg)] + if not len(seg): + continue + med = float(np.median(seg)) + db = 20.0 * np.log10(max(float(np.max(rms[k0:max(k0 + 1, k1)])), 1e-9) / peak) + index.setdefault(w["t"].lower().strip(".,!?"), []).append(dict( + slice=slice_name, take=slice_name.split("-")[0], + start=round(a, 3), end=round(b, 3), dur=round(b - a, 3), + st=round(med, 2), note=note_name(med), + cents=round(off_grid(med)), peak_db=round(db, 1))) + + path = os.path.join(LANE, "samples", ".takes.json") + json.dump(index, open(path, "w"), indent=1, sort_keys=True) + + words = [want] if want else sorted(index) + multi = sum(1 for k in index if len({e["take"] for e in index[k]}) > 1) + if not want: + print(f"{len(index)} distinct utterances across " + f"{len({e['slice'] for v in index.values() for e in v})} takes · " + f"{multi} exist in more than one take\n") + for k in words: + if k not in index: + print(f" {k}: not in the bank") + continue + rows = sorted(index[k], key=lambda e: (e["take"], e["slice"])) + print(f" {k}") + for e in rows: + print(f" {e['take']} {e['slice']:<22} {e['start']:6.2f}–{e['end']:6.2f}s " + f"({e['dur']:.2f}s) {e['note']:>4} {e['st']:+6.2f}st " + f"{e['cents']:+4d}¢ peak {e['peak_db']:.0f}dB") + if not want: + print(f"\nWROTE {path}") + + +if __name__ == "__main__": + main() diff --git a/pop/loner/bin/timeline.py b/pop/loner/bin/timeline.py --- a/pop/loner/bin/timeline.py +++ b/pop/loner/bin/timeline.py @@ -89,7 +89,12 @@ LYRIC_OFF = (238, 234, 230, 110) BEAT_TINT = [(255, 92, 162, 34), (132, 158, 236, 14), (238, 234, 230, 10), (132, 158, 236, 14)] -chart = json.load(open(os.path.join(LANE, "vox4", ".chart.json")))["w-whole-line"] +# WHICH TAKE IS BEING SCRUTINISED. Every take has its own chart now, with +# its own boundaries and its own consonant runways, so drawing f-'s blocks +# over another take's audio would be a picture of the wrong performance. +PHRASE = os.environ.get("TAKE") or "w-whole-line" +LEADWAV = os.environ.get("TAKE_WAV") or PHRASE +chart = json.load(open(os.path.join(LANE, "vox4", ".chart.json")))[PHRASE] LINE_BEATS = chart["beats"] LINE_BARS = math.ceil(LINE_BEATS / 4.0) PASSES = [0.0] # ONE pass, and no count-in: @@ -122,7 +127,7 @@ # @jeffrey: "check the length of the actual waveforms in the utterances, # not just ur trim etc — map / render those waveforms directly into the # clips". The lead render (vox4/w-whole-line.wav) IS what the study # plays; chart beat b lives at leadIn + b·SPB seconds in that file. -with wave.open(os.path.join(LANE, "vox4", "w-whole-line.wav"), "rb") as wf: +with wave.open(os.path.join(LANE, "vox4", f"{LEADWAV}.wav"), "rb") as wf: VFS = wf.getframerate() VOX = np.frombuffer(wf.readframes(wf.getnframes()), dtype=np.int16).astype(np.float64) / 32768.0 diff --git a/pop/loner/bin/tryout-takes.sh b/pop/loner/bin/tryout-takes.sh new file mode 100644 --- /dev/null +++ b/pop/loner/bin/tryout-takes.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# tryout-takes.sh — hear another take of the line, solo, on ITS OWN chart. +# +# @jeffrey: "our envelopes etc are still fitting like the original samples · +# we need to like restart the whole process for each actual take · or it +# will sound wonky". +# +# It did, and it was. The first version of this script warped a take onto +# the chart halo3 built from f- — f-'s hand-pinned onsets, f-'s syllable +# seams, f-'s consonant runways — so every take arrived wearing one +# singer's phrasing. This restarts the process instead: +# +# 1. takechart.py assemble the line from that take's per-word corpus +# files, pin all 18 onsets exactly, find the syllable +# seams in ITS voice, keep only `durs` from the score +# 2. halo3.py the FULL pipeline on that chart — consonant runway, +# boundary snap, energy trim, note re-measurement, the +# weighted warp clock, THE HOLD, nervox, the sibilant +# restore +# 3. stage one static dB to the f- spine's loudness, so takes are +# compared on performance and not on mic distance +# 4. the study kick + that vocal, and the scrolling piano roll drawn +# from that take's chart rather than from f-'s +# +# Any of the ten takes owning all eighteen lyric words: s pf cp f rq lg sh +# rd hk o — though hk is f- sliced a second time, not a second take. +# +# bash pop/loner/bin/tryout-takes.sh rq sh lg +# → out/takes/-timeline.mp4 (+ .mp3), and on the Desktop +set -euo pipefail +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LANE="$(dirname "$HERE")" +REPO="$(dirname "$(dirname "$LANE")")" +PY="$REPO/pop/.venv/bin/python" +OUT="$LANE/out/takes" +mkdir -p "$OUT" +cd "$REPO" + +[ $# -gt 0 ] || { echo "usage: tryout-takes.sh [take…]" >&2; exit 1; } + +bash "$LANE/c/build.sh" >/dev/null +"$PY" "$HERE/takechart.py" "$@" 2>/dev/null | grep -E "✓|composition|could not|does not" + +# ONE BAD TAKE MUST NOT END THE BENCH. `set -e` plus a bench loop meant a +# single failure — a take halo3 could not build, a wav timeline.py could +# not open — threw away every take queued behind it. +fail=0 +for t in "$@"; do + echo "── $t ────────────────────────────────────────────" + ( set -e + TAKES=1 PHRASES="w-$t" LEAD_ONLY=1 "$PY" "$HERE/halo3.py" 2>/dev/null \ + | grep -E "^ w-$t" || { echo " ! halo3 built nothing for w-$t"; continue; } + bash "$HERE/stage-takes.sh" "$LANE/vox4/w-$t.wav" "try-$t" + TAKE="w-$t" TAKE_WAV="try-$t" MINIMAL=1 "$LANE/c/lonerremix" | tail -1 + TAKE="w-$t" TAKE_WAV="try-$t" python3 "$HERE/timeline.py" | tail -1 + ffmpeg -y -v error -i "$LANE/out/loner-kickvox-full.wav" \ + -codec:a libmp3lame -q:a 0 "$OUT/$t.mp3" + mv "$LANE/out/loner-kickvox-timeline.mp4" "$OUT/$t-timeline.mp4" + cp "$OUT/$t-timeline.mp4" ~/Desktop/ 2>/dev/null || true + echo " ✓ $OUT/$t-timeline.mp4" ) || { echo " ! $t failed — moving on"; fail=$((fail+1)); } +done +[ "$fail" -eq 0 ] || echo "→ $fail take(s) failed; the rest are in $OUT" diff --git a/pop/loner/bin/tryout.py b/pop/loner/bin/tryout.py new file mode 100644 --- /dev/null +++ b/pop/loner/bin/tryout.py @@ -0,0 +1,107 @@ +# tryout.py — audition every version of a word she actually sang. +# +# @jeffrey: "can we try using other takes for the lead too / go back to +# vocal tests with that? · especially i wanna try out new iterations of +# 'patiently'". +# +# bin/takes.py says WHICH takes hold a word and at what pitch; this one +# renders them, so the choice is made by ear instead of from a table. Each +# candidate goes through the same WORLD chain the chart uses — snap to the +# A# minor grid in her own 237 Hz frame, nervox tremor on the held frames — +# and they are laid out one after another with a gap, loudest-first, so a +# swap can be auditioned before it is charted. +# +# Every variant here is HER, from a take she sang. Generating syllables she +# never sang (an ElevenLabs IVC of Camille, the way the Prutti dub kept +# Prutti's voice) is a different thing and wants her sign-off first — the +# klokkentales gate: label synthetic voice, collab-invite is the consent. +# +# pop/.venv/bin/python pop/loner/bin/tryout.py patiently +# → out/tryout-patiently.wav + a printed legend + +import json, os, sys +import numpy as np +import soundfile as sf +import pyworld as pw + +HERE = os.path.dirname(os.path.abspath(__file__)) +LANE = os.path.dirname(HERE) +sys.path.insert(0, HERE) +sys.path.insert(0, os.path.join(os.path.dirname(LANE), "lib")) +from audit import columns, TONIC, FRAME_S +from nervox import waver as nervox_waver, flange as nervox_flange + +MINOR = np.array([0, 2, 3, 5, 7, 8, 10]) +SNAP = 0.92 +GAP_S = 0.45 + + +def cents_to_grid(hz): + cents = 1200.0 * np.log2(hz / TONIC) + pc = np.mod(cents, 1200.0) + grid = np.concatenate([MINOR * 100.0, [1200.0]]) + dev = pc[:, None] - grid[None, :] + return dev[np.arange(len(pc)), np.argmin(np.abs(dev), axis=1)] + + +def render(x, fs, snap=SNAP, nervy=True): + """The chart's chain, on one word.""" + f0r, t = pw.harvest(x, fs, f0_floor=140.0, f0_ceil=600.0, frame_period=5.0) + f0 = pw.stonemask(x, f0r, t, fs) + fft = pw.get_cheaptrick_fft_size(fs, f0_floor=140.0) + sp = pw.cheaptrick(x, f0, t, fs, fft_size=fft, f0_floor=140.0) + ap = pw.d4c(x, f0, t, fs, fft_size=fft) + v = f0 > 0 + corr = np.zeros_like(f0) + if v.any(): + corr[v] = -cents_to_grid(f0[v]) * snap + f0c = np.where(v, f0 * 2.0 ** (corr / 1200.0), 0.0) + if nervy: + f0c = nervox_waver(f0c, 0.005, voiced=v) + y = pw.synthesize(f0c, sp, ap, fs, frame_period=5.0) + return nervox_flange(y, fs) if nervy else y + + +def main(): + word = (sys.argv[1] if len(sys.argv) > 1 else "patiently").lower() + idx_path = os.path.join(LANE, "samples", ".takes.json") + if not os.path.exists(idx_path): + print("run bin/takes.py first"); return + index = json.load(open(idx_path)) + if word not in index: + print(f"'{word}' is not in the bank — bin/takes.py lists what is"); return + + out, legend, sr = [], [], None + for e in sorted(index[word], key=lambda e: (e["take"], e["slice"])): + wav = os.path.join(LANE, "samples", f"{e['slice']}.wav") + x, fs = sf.read(wav, dtype="float64") + if x.ndim > 1: + x = x.mean(axis=1) + sr = fs + seg = x[int(e["start"] * fs):int(e["end"] * fs)] + if len(seg) < int(0.05 * fs): + continue + for nervy in (False, True): + y = render(seg, fs, nervy=nervy) + pk = np.max(np.abs(y)) or 1.0 + out.append(y / pk * 0.72) + out.append(np.zeros(int(GAP_S * fs))) + legend.append(f"{e['take']}-take {e['slice']:<20} {e['note']:>4} " + f"{e['st']:+5.2f}st {e['dur']:.2f}s " + f"{'nervox' if nervy else 'plain '}") + + if not out: + print("nothing renderable"); return + y = np.concatenate(out) + dest = os.path.join(LANE, "out", f"tryout-{word}.wav") + sf.write(dest, y, sr) + print(f"'{word}' — {len(legend)} variants, in order:\n") + at = 0.0 + for i, l in enumerate(legend): + print(f" {at:5.1f}s {i + 1}. {l}") + at += len(out[i * 2]) / sr + GAP_S + print(f"\nWROTE {dest} ({len(y) / sr:.1f}s)") + + +if __name__ == "__main__": + main() diff --git a/pop/loner/bin/wizard.py b/pop/loner/bin/wizard.py new file mode 100644 --- /dev/null +++ b/pop/loner/bin/wizard.py @@ -0,0 +1,85 @@ +# wizard.py — hand the chart to ChartWizard. +# +# @jeffrey: "can we maybe work on a drag and drop gui for this · so i can +# better adjust timing in realtime for these · like melodyne style · then +# we can recompute and play it back?" +# +# Everything the GUI draws has already been measured somewhere in this +# lane — the warped spans in vox4/.manifest.json, the beat slots and sung +# semitones in vox4/.chart.json, and audit.py's three columns (pitch, +# level, brightness) plus the NOTE/FRIC/PUFF events it splits them into. +# None of that should be re-derived in Swift, where it would drift from +# what halo3 actually renders. So this collects it into one file the app +# opens, and the app writes its edits back to chart-edits.json, which +# halo3 merges over the CHART literal. +# +# pop/.venv/bin/python pop/loner/bin/wizard.py # → vox4/.wizard.json + +import json, os, sys +import numpy as np +import soundfile as sf + +HERE = os.path.dirname(os.path.abspath(__file__)) +LANE = os.path.dirname(HERE) +sys.path.insert(0, HERE) +from audit import columns, events, TONIC, FRAME_S # one set of measurements + +BPM = 122.0 + + +def main(): + chart = json.load(open(os.path.join(LANE, "vox4", ".chart.json"))) + man = json.load(open(os.path.join(LANE, "vox4", ".manifest.json"))) + out = {"lane": os.path.basename(LANE), "bpm": BPM, "tonic": TONIC, + "frame_s": FRAME_S, "phrases": {}} + + for name, ch in chart.items(): + # a phrase only reaches the GUI once halo3 has actually warped it — + # a partial build (PHRASES=…) leaves the others without spans. + if name not in man or "spans" not in man[name]: + continue + slice_name = man[name]["slice"] + wav = os.path.join(LANE, "samples", f"{slice_name}.wav") + if not os.path.exists(wav): + continue + x, fs = sf.read(wav, dtype="float64") + if x.ndim > 1: + x = x.mean(axis=1) + + f0, st, rms, hi, peak, m = columns(x, fs) + db = 20.0 * np.log10(np.maximum(rms, 1e-9) / peak) + spans = {t: (a, b) for (t, a, b) in man[name]["spans"]} + + # a unit is one word block: where it sits on the grid, and which + # piece of her the block plays. The GUI drags exactly these two. + units = [] + for n in ch["notes"]: + a, b = spans.get(n["t"], (0.0, 0.0)) + units.append({"t": n["t"], "beat": n["beat"], "dur": n["dur"], + "st": n["st"], "src0": a, "src1": b}) + + out["phrases"][name] = { + "slice": slice_name, "wav": wav, "sr": int(fs), + "leadIn": ch.get("leadIn", 0.0), "beats": ch["beats"], + "units": units, + "events": [{"a": a, "b": b, "kind": k, + "st": (None if np.isnan(s) else round(float(s), 2))} + for (a, b, s, k) in events(x, fs)], + # the three columns, rounded to what a screen can show + "frames": { + "st": [None if np.isnan(v) else round(float(v), 2) for v in st], + "db": [round(float(v), 1) for v in db], + "hf": [round(float(v), 2) for v in hi], + }, + } + print(f" {name:>20} {len(units)} units · {len(out['phrases'][name]['events'])} events " + f"· {m} frames") + + path = os.path.join(LANE, "vox4", ".wizard.json") + json.dump(out, open(path, "w")) + print(f"WROTE {path} ({os.path.getsize(path) // 1024} KB, " + f"{len(out['phrases'])} phrases)") + + +if __name__ == "__main__": + main() diff --git a/pop/loner/c/cut-club.sh b/pop/loner/c/cut-club.sh new file mode 100644 --- /dev/null +++ b/pop/loner/c/cut-club.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# cut-club.sh — Lonerclub, mastered hot. +# +# @jeffrey: "make a nice hot club mix". cut-v4.sh targets −14 LUFS, which +# is a release level; a club plays loud and wants the record to arrive +# already committed. This targets −9. +# +# It keeps the lane's mastering law — MEASURE → one static dB → true-peak +# limiter, never a second loudnorm — and buys the extra 5 dB the honest +# way rather than by slamming the limiter with it: +# +# 1. a gentle bus COMPRESSOR first, so the limiter is catching peaks +# rather than doing the levelling. 5 dB of limiting with no +# compression is where a master starts to flap. +# 2. a shelf pair, not a smile: +1.2 dB under 90 Hz for the floor and a +# NARROW +1 dB at 2.8 kHz for her consonants. No broad treble lift — +# pop/wattajetta: master treble boosts read as tang on laptop +# speakers, and this cut has bells in the sixth octave now. +# 3. the limiter sits at 0.82, not at the ceiling. mp3 encoding +# invents inter-sample peaks: limiting to −1.0 dBFS measured −0.3 +# dBTP after the encode. Leaving 1.7 dB of headroom in the wav is +# what actually lands the MP3 under −1. Louder than that is not +# loudness, it is distortion on someone's phone. +set -euo pipefail + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LANE="$(dirname "$HERE")" +OUT="$LANE/out" + +FULL="${1:-$OUT/loner-remix-v4-full.wav}" +DEST="${2:-$OUT/lonerclub.mp3}" +TARGET="${TARGET:--9.0}" + +echo "→ measure $(basename "$FULL")" +STATS=$(ffmpeg -hide_banner -nostats -i "$FULL" \ + -af loudnorm=I="$TARGET":TP=-1.0:LRA=9:print_format=json -f null - 2>&1 | awk '/^\{/,/^\}/') +MI=$(echo "$STATS" | grep '"input_i"' | head -1 | sed 's/.*: *"\([^"]*\)".*/\1/') +# leave room for the compressor to find; the static move is the rest. +# 2.2 dB was right when the bus glue was the ONLY levelling in the chain. +# The vox bus now carries its own compressor (lonerremix.c, "THE VOCAL +# CHAIN"), so asking this one for the same work again squashed LRA to 1.9 +# — a flat master. It only has to catch peaks now. +GAIN=$(awk -v i="$MI" -v t="$TARGET" 'BEGIN{printf "%.2f", t-i-1.1}') +echo " measured I=$MI → static ${GAIN} dB, then glue, then limit" + +ffmpeg -y -v error -i "$FULL" -af "\ +volume=${GAIN}dB,\ +acompressor=threshold=0.22:ratio=1.5:attack=30:release=240:makeup=1.1:knee=6,\ +equalizer=f=90:t=q:w=0.9:g=1.2,\ +equalizer=f=2800:t=q:w=1.6:g=1.0,\ +alimiter=limit=0.82:attack=4:release=90:level=disabled" \ + -ar 48000 -c:a pcm_s24le "$OUT/lonerclub-master.wav" + +ffmpeg -y -v error -i "$OUT/lonerclub-master.wav" -c:a libmp3lame -b:a 320k \ + -metadata title="Lonerclub" \ + -metadata artist="Whistlegraph" -metadata album="pop / loner" \ + -metadata comment="Camille Klein's whistlegraph 'loner', regulated onto a strict 122 floor: one sung sentence looped five times, harmony accumulating. WORLD snap 0.92 with nervox tremor, per-word beat chart, FEM bells, her own backup 3rds and 5ths." \ + "$DEST" + +ffmpeg -hide_banner -nostats -i "$DEST" -af ebur128=peak=true -f null - 2>&1 \ + | grep -E "^\s+(I|LRA|Peak):" +echo "✓ $DEST" diff --git a/pop/loner/c/loner-chart.h b/pop/loner/c/loner-chart.h --- a/pop/loner/c/loner-chart.h +++ b/pop/loner/c/loner-chart.h @@ -8,100 +8,318 @@ #define CHART_BPM 122.0 #define CHART_TONIC 237.0 -typedef struct { double beat, dur; int st; } ChartNote; +// `t` is the unit's label — the C addresses a word by name so a +// treatment can be written against "pa" rather than against unit 17. +typedef struct { double beat, dur; int st; const char *t; } ChartNote; typedef struct { const char *name; double leadIn; double beats; int n; const ChartNote *notes; } ChartPhrase; static const ChartNote w_whole_line_notes[] = { - { 0.00, 2.00, 7 }, - { 2.00, 2.00, 5 }, - { 4.00, 1.91, 3 }, - { 5.91, 2.09, 2 }, - { 8.00, 1.50, 0 }, - { 9.50, 1.50, 5 }, - { 11.00, 2.00, 2 }, - { 13.00, 2.00, -2 }, - { 15.00, 2.00, -5 }, - { 17.00, 4.00, 12 }, - { 21.00, 3.00, 10 }, - { 24.00, 3.00, 5 }, - { 27.00, 4.00, 2 }, - { 31.00, 2.00, 3 }, - { 33.00, 2.00, 2 }, - { 35.00, 2.00, 0 }, - { 37.00, 2.00, -2 }, - { 39.00, 2.00, 7 }, - { 41.00, 2.50, 5 }, - { 43.50, 2.50, 3 }, - { 46.00, 2.00, 5 }, - { 48.00, 4.00, 7 }, - { 52.00, 4.00, 3 }, - { 56.00, 3.00, 3 }, + { 0.00, 2.00, 7, "sitting·a" }, + { 2.00, 2.00, 5, "sitting·b" }, + { 4.00, 1.91, 3, "curled" }, + { 5.91, 2.09, 2, "up" }, + { 8.00, 2.00, 0, "in" }, + { 10.00, 1.50, 5, "my" }, + { 11.50, 2.50, 2, "self" }, + { 14.00, 2.00, -2, "i" }, + { 16.00, 2.00, -5, "think" }, + { 18.00, 4.00, 12, "of" }, + { 22.00, 1.75, 10, "a" }, + { 23.75, 4.25, 5, "stone" }, + { 28.00, 4.00, 2, "just" }, + { 32.00, 2.00, 3, "wait" }, + { 34.00, 2.00, 2, "ing" }, + { 36.00, 2.00, 0, "ve" }, + { 38.00, 2.00, -2, "ry" }, + { 40.00, 2.00, 7, "pa" }, + { 42.00, 2.00, 5, "tient" }, + { 44.00, 2.00, 3, "ly" }, + { 46.00, 2.00, 5, "for" }, + { 48.00, 4.00, 7, "time" }, + { 52.00, 4.00, 3, "to" }, + { 56.00, 4.00, 3, "pass" }, }; static const ChartNote w_sitting_curled_notes[] = { - { 0.00, 3.00, 6 }, - { 3.00, 2.00, 3 }, - { 5.00, 1.50, 2 }, - { 6.50, 1.50, 0 }, - { 8.00, 3.00, 5 }, + { 0.00, 3.00, 6, "Sitting" }, + { 3.00, 2.00, 3, "curled" }, + { 5.00, 1.50, 2, "up" }, + { 6.50, 1.50, 0, "in" }, + { 8.00, 3.00, 5, "myself" }, }; static const ChartNote w_i_think_notes[] = { - { 0.00, 2.00, -2 }, - { 2.00, 1.50, -5 }, + { 0.00, 2.00, -2, "I" }, + { 2.00, 1.50, -5, "think" }, }; static const ChartNote w_of_a_stone_notes[] = { - { 0.00, 4.00, 12 }, - { 4.00, 2.00, 10 }, - { 6.00, 2.00, 5 }, + { 0.00, 4.00, 12, "of" }, + { 4.00, 2.00, 10, "a" }, + { 6.00, 2.00, 5, "stone" }, }; static const ChartNote w_just_waiting_notes[] = { - { 0.00, 3.50, 2 }, - { 3.50, 3.00, 3 }, + { 0.00, 3.50, 2, "Just" }, + { 3.50, 3.00, 3, "waiting" }, }; static const ChartNote w_very_patiently_notes[] = { - { 0.00, 5.00, 0 }, - { 5.00, 3.50, 7 }, + { 0.00, 5.00, 0, "very" }, + { 5.00, 3.50, 7, "patiently" }, }; static const ChartNote w_for_time_to_pass_notes[] = { - { 0.00, 2.00, 5 }, - { 2.00, 2.50, 7 }, - { 4.50, 4.00, 3 }, - { 8.50, 4.00, 3 }, + { 0.00, 2.00, 5, "for" }, + { 2.00, 2.50, 7, "time" }, + { 4.50, 4.00, 3, "to" }, + { 8.50, 4.00, 3, "pass" }, }; static const ChartNote w_n_getting_curled_notes[] = { - { 0.00, 1.50, 5 }, - { 1.50, 2.50, 3 }, - { 4.00, 0.50, 1 }, - { 4.50, 1.50, 0 }, - { 6.00, 2.50, 4 }, - { 8.50, 2.00, -2 }, - { 10.50, 0.50, -5 }, + { 0.00, 1.50, 5, "getting" }, + { 1.50, 2.50, 3, "curled" }, + { 4.00, 0.50, 1, "up" }, + { 4.50, 1.50, 0, "in" }, + { 6.00, 2.50, 4, "myself" }, + { 8.50, 2.00, -2, "i" }, + { 10.50, 0.50, -5, "think" }, }; static const ChartNote w_n_stone_waiting_notes[] = { - { 0.00, 2.00, 12 }, - { 2.00, 2.00, 9 }, - { 4.00, 4.00, 5 }, - { 8.00, 4.00, 3 }, - { 12.00, 3.00, 0 }, - { 15.00, 2.00, 6 }, + { 0.00, 2.00, 12, "A" }, + { 2.00, 2.00, 9, "stone" }, + { 4.00, 4.00, 5, "just" }, + { 8.00, 4.00, 3, "waiting" }, + { 12.00, 3.00, 0, "very" }, + { 15.00, 2.00, 6, "patiently" }, }; static const ChartNote w_n_for_time_to_pass_notes[] = { - { 0.00, 0.50, 5 }, - { 0.50, 1.00, 7 }, - { 1.50, 2.50, 3 }, - { 4.00, 1.50, 3 }, + { 0.00, 0.50, 5, "the" }, + { 0.50, 1.00, 7, "time" }, + { 1.50, 2.50, 3, "to" }, + { 4.00, 1.50, 3, "pass" }, +}; +static const ChartNote w_rq_notes[] = { + { 0.00, 2.00, -5, "sitting·a" }, + { 2.00, 2.00, -7, "sitting·b" }, + { 4.00, 1.91, -9, "curled" }, + { 5.91, 2.09, -10, "up" }, + { 8.00, 2.00, -12, "in" }, + { 10.00, 1.50, -7, "my" }, + { 11.50, 2.50, -10, "self" }, + { 14.00, 2.00, -14, "i" }, + { 16.00, 2.00, -17, "think" }, + { 18.00, 4.00, 0, "of" }, + { 22.00, 1.75, -2, "a" }, + { 23.75, 4.25, -7, "stone" }, + { 28.00, 4.00, -10, "just" }, + { 32.00, 2.00, -9, "wait" }, + { 34.00, 2.00, -10, "ing" }, + { 36.00, 2.00, -12, "ve" }, + { 38.00, 2.00, -14, "ry" }, + { 40.00, 2.00, -5, "pa" }, + { 42.00, 2.00, -7, "tient" }, + { 44.00, 2.00, -9, "ly" }, + { 46.00, 2.00, -7, "for" }, + { 48.00, 4.00, -5, "time" }, + { 52.00, 4.00, -9, "to" }, + { 56.00, 4.00, -9, "pass" }, +}; +static const ChartNote w_sh_notes[] = { + { 0.00, 2.00, -5, "sitting·a" }, + { 2.00, 2.00, -7, "sitting·b" }, + { 4.00, 1.91, -9, "curled" }, + { 5.91, 2.09, -10, "up" }, + { 8.00, 2.00, -12, "in" }, + { 10.00, 1.50, -7, "my" }, + { 11.50, 2.50, -10, "self" }, + { 14.00, 2.00, -14, "i" }, + { 16.00, 2.00, -17, "think" }, + { 18.00, 4.00, 0, "of" }, + { 22.00, 1.75, -2, "a" }, + { 23.75, 4.25, -7, "stone" }, + { 28.00, 4.00, -10, "just" }, + { 32.00, 2.00, -9, "wait" }, + { 34.00, 2.00, -10, "ing" }, + { 36.00, 2.00, -12, "ve" }, + { 38.00, 2.00, -14, "ry" }, + { 40.00, 2.00, -5, "pa" }, + { 42.00, 2.00, -7, "tient" }, + { 44.00, 2.00, -9, "ly" }, + { 46.00, 2.00, -7, "for" }, + { 48.00, 4.00, -5, "time" }, + { 52.00, 4.00, -9, "to" }, + { 56.00, 4.00, -9, "pass" }, +}; +static const ChartNote w_lg_notes[] = { + { 0.00, 2.00, 7, "sitting·a" }, + { 2.00, 2.00, 5, "sitting·b" }, + { 4.00, 1.91, 3, "curled" }, + { 5.91, 2.09, 2, "up" }, + { 8.00, 2.00, 0, "in" }, + { 10.00, 1.50, 5, "my" }, + { 11.50, 2.50, 2, "self" }, + { 14.00, 2.00, -2, "i" }, + { 16.00, 2.00, -5, "think" }, + { 18.00, 4.00, 12, "of" }, + { 22.00, 1.75, 10, "a" }, + { 23.75, 4.25, 5, "stone" }, + { 28.00, 4.00, 2, "just" }, + { 32.00, 2.00, 3, "wait" }, + { 34.00, 2.00, 2, "ing" }, + { 36.00, 2.00, 0, "ve" }, + { 38.00, 2.00, -2, "ry" }, + { 40.00, 2.00, 7, "pa" }, + { 42.00, 2.00, 5, "tient" }, + { 44.00, 2.00, 3, "ly" }, + { 46.00, 2.00, 5, "for" }, + { 48.00, 4.00, 7, "time" }, + { 52.00, 4.00, 3, "to" }, + { 56.00, 4.00, 3, "pass" }, +}; +static const ChartNote w_pf_notes[] = { + { 0.00, 2.00, 7, "sitting·a" }, + { 2.00, 2.00, 5, "sitting·b" }, + { 4.00, 1.91, 3, "curled" }, + { 5.91, 2.09, 2, "up" }, + { 8.00, 2.00, 0, "in" }, + { 10.00, 1.50, 5, "my" }, + { 11.50, 2.50, 2, "self" }, + { 14.00, 2.00, -2, "i" }, + { 16.00, 2.00, -5, "think" }, + { 18.00, 4.00, 12, "of" }, + { 22.00, 1.75, 10, "a" }, + { 23.75, 4.25, 5, "stone" }, + { 28.00, 4.00, 2, "just" }, + { 32.00, 2.00, 3, "wait" }, + { 34.00, 2.00, 2, "ing" }, + { 36.00, 2.00, 0, "ve" }, + { 38.00, 2.00, -2, "ry" }, + { 40.00, 2.00, 7, "pa" }, + { 42.00, 2.00, 5, "tient" }, + { 44.00, 2.00, 3, "ly" }, + { 46.00, 2.00, 5, "for" }, + { 48.00, 4.00, 7, "time" }, + { 52.00, 4.00, 3, "to" }, + { 56.00, 4.00, 3, "pass" }, +}; +static const ChartNote w_rd_notes[] = { + { 0.00, 2.00, 7, "sitting·a" }, + { 2.00, 2.00, 5, "sitting·b" }, + { 4.00, 1.91, 3, "curled" }, + { 5.91, 2.09, 2, "up" }, + { 8.00, 2.00, 0, "in" }, + { 10.00, 1.50, 5, "my" }, + { 11.50, 2.50, 2, "self" }, + { 14.00, 2.00, -2, "i" }, + { 16.00, 2.00, -5, "think" }, + { 18.00, 4.00, 12, "of" }, + { 22.00, 1.75, 10, "a" }, + { 23.75, 4.25, 5, "stone" }, + { 28.00, 4.00, 2, "just" }, + { 32.00, 2.00, 3, "wait" }, + { 34.00, 2.00, 2, "ing" }, + { 36.00, 2.00, 0, "ve" }, + { 38.00, 2.00, -2, "ry" }, + { 40.00, 2.00, 7, "pa" }, + { 42.00, 2.00, 5, "tient" }, + { 44.00, 2.00, 3, "ly" }, + { 46.00, 2.00, 5, "for" }, + { 48.00, 4.00, 7, "time" }, + { 52.00, 4.00, 3, "to" }, + { 56.00, 4.00, 3, "pass" }, +}; +static const ChartNote w_cp_notes[] = { + { 0.00, 2.00, -5, "sitting·a" }, + { 2.00, 2.00, -7, "sitting·b" }, + { 4.00, 1.91, -9, "curled" }, + { 5.91, 2.09, -10, "up" }, + { 8.00, 2.00, -12, "in" }, + { 10.00, 1.50, -7, "my" }, + { 11.50, 2.50, -10, "self" }, + { 14.00, 2.00, -14, "i" }, + { 16.00, 2.00, -17, "think" }, + { 18.00, 4.00, 0, "of" }, + { 22.00, 1.75, -2, "a" }, + { 23.75, 4.25, -7, "stone" }, + { 28.00, 4.00, -10, "just" }, + { 32.00, 2.00, -9, "wait" }, + { 34.00, 2.00, -10, "ing" }, + { 36.00, 2.00, -12, "ve" }, + { 38.00, 2.00, -14, "ry" }, + { 40.00, 2.00, -5, "pa" }, + { 42.00, 2.00, -7, "tient" }, + { 44.00, 2.00, -9, "ly" }, + { 46.00, 2.00, -7, "for" }, + { 48.00, 4.00, -5, "time" }, + { 52.00, 4.00, -9, "to" }, + { 56.00, 4.00, -9, "pass" }, +}; +static const ChartNote w_s_notes[] = { + { 0.00, 2.00, 7, "sitting·a" }, + { 2.00, 2.00, 5, "sitting·b" }, + { 4.00, 1.91, 3, "curled" }, + { 5.91, 2.09, 2, "up" }, + { 8.00, 2.00, 0, "in" }, + { 10.00, 1.50, 5, "my" }, + { 11.50, 2.50, 2, "self" }, + { 14.00, 2.00, -2, "i" }, + { 16.00, 2.00, -5, "think" }, + { 18.00, 4.00, 12, "of" }, + { 22.00, 1.75, 10, "a" }, + { 23.75, 4.25, 5, "stone" }, + { 28.00, 4.00, 2, "just" }, + { 32.00, 2.00, 3, "wait" }, + { 34.00, 2.00, 2, "ing" }, + { 36.00, 2.00, 0, "ve" }, + { 38.00, 2.00, -2, "ry" }, + { 40.00, 2.00, 7, "pa" }, + { 42.00, 2.00, 5, "tient" }, + { 44.00, 2.00, 3, "ly" }, + { 46.00, 2.00, 5, "for" }, + { 48.00, 4.00, 7, "time" }, + { 52.00, 4.00, 3, "to" }, + { 56.00, 4.00, 3, "pass" }, +}; +static const ChartNote w_o_notes[] = { + { 0.00, 2.00, 7, "sitting·a" }, + { 2.00, 2.00, 5, "sitting·b" }, + { 4.00, 1.91, 3, "curled" }, + { 5.91, 2.09, 2, "up" }, + { 8.00, 2.00, 0, "in" }, + { 10.00, 1.50, 5, "my" }, + { 11.50, 2.50, 2, "self" }, + { 14.00, 2.00, -2, "i" }, + { 16.00, 2.00, -5, "think" }, + { 18.00, 4.00, 12, "of" }, + { 22.00, 1.75, 10, "a" }, + { 23.75, 4.25, 5, "stone" }, + { 28.00, 4.00, 2, "just" }, + { 32.00, 2.00, 3, "wait" }, + { 34.00, 2.00, 2, "ing" }, + { 36.00, 2.00, 0, "ve" }, + { 38.00, 2.00, -2, "ry" }, + { 40.00, 2.00, 7, "pa" }, + { 42.00, 2.00, 5, "tient" }, + { 44.00, 2.00, 3, "ly" }, + { 46.00, 2.00, 5, "for" }, + { 48.00, 4.00, 7, "time" }, + { 52.00, 4.00, 3, "to" }, + { 56.00, 4.00, 3, "pass" }, }; static const ChartPhrase CHART[] = { - { "w-whole-line", 0.040, 59.00, 24, w_whole_line_notes }, - { "w-sitting-curled", 0.020, 11.00, 5, w_sitting_curled_notes }, - { "w-i-think", 0.020, 3.50, 2, w_i_think_notes }, + { "w-whole-line", 0.330, 60.00, 24, w_whole_line_notes }, + { "w-sitting-curled", 0.040, 11.00, 5, w_sitting_curled_notes }, + { "w-i-think", 0.040, 3.50, 2, w_i_think_notes }, { "w-of-a-stone", 0.000, 8.00, 3, w_of_a_stone_notes }, - { "w-just-waiting", 0.075, 6.50, 2, w_just_waiting_notes }, + { "w-just-waiting", 0.150, 6.50, 2, w_just_waiting_notes }, { "w-very-patiently", 0.000, 8.50, 2, w_very_patiently_notes }, - { "w-for-time-to-pass", 0.035, 12.50, 4, w_for_time_to_pass_notes }, + { "w-for-time-to-pass", 0.070, 12.50, 4, w_for_time_to_pass_notes }, { "w-n-getting-curled", 0.000, 11.00, 7, w_n_getting_curled_notes }, { "w-n-stone-waiting", 0.000, 17.00, 6, w_n_stone_waiting_notes }, { "w-n-for-time-to-pass", 0.000, 5.50, 4, w_n_for_time_to_pass_notes }, + { "w-rq", 0.430, 60.00, 24, w_rq_notes }, + { "w-sh", 0.840, 60.00, 24, w_sh_notes }, + { "w-lg", 0.575, 60.00, 24, w_lg_notes }, + { "w-pf", 0.765, 60.00, 24, w_pf_notes }, + { "w-rd", 0.405, 60.00, 24, w_rd_notes }, + { "w-cp", 0.430, 60.00, 24, w_cp_notes }, + { "w-s", 0.370, 60.00, 24, w_s_notes }, + { "w-o", 0.550, 60.00, 24, w_o_notes }, }; -#define CHART_N 10 +#define CHART_N 18 diff --git a/pop/loner/c/lonerremix.c b/pop/loner/c/lonerremix.c --- a/pop/loner/c/lonerremix.c +++ b/pop/loner/c/lonerremix.c @@ -65,7 +65,14 @@ #define SR 48000 #define TAU 6.283185307179586 static const double BPM = CHART_BPM; // 122 — the chart's clock static const double TONIC = CHART_TONIC; // 237 Hz — Camille's frame -#define BARS 76 +// @jeffrey: "instrumental intro" → "can the intro be like just 1 bar" → +// "can we start it as sitting from the first beat?". None, in the end, and +// it is the right answer for this song: three minutes of one sentence does +// not need announcing. The first sound on the record is her /s/. +#define INTRO 0 +#define BARS (INTRO + 96) // Lonerclub — six passes after the intro +// the passes, addressed by number rather than by remembering an offset +#define L(n) (INTRO + (n) * 16) #define TAIL_S 6.0 static double BEAT, BAR, STEP; // set in main static long N; @@ -74,7 +81,11 @@ // ── buses ────────────────────────────────────────────────────────────── static float *drumsL, *drumsR, *musicL, *musicR, *voxL, *voxR; static float *sideV, *sideB, *dlySend, *rvbSend; -static const double VOXG = 1.42; +// @jeffrey: "could we have the vocals be deeper in the mix". 1.42 put her +// right at the front of the speaker. Depth is not just a smaller number +// though — a quiet close voice is still a close voice — so the fader comes +// down AND the sends go up AND the chest comes out (see THE VOCAL CHAIN). +static const double VOXG = 0.82; // ── helpers ──────────────────────────────────────────────────────────── static double clampd(double v, double a, double b) { return v < a ? a : v > b ? b : v; } @@ -83,12 +94,55 @@ static double tail_fade(long i, long n) { double u = (double)(n - 1 - i) / (0.010 * SR); return u >= 1 ? 1 : u <= 0 ? 0 : u * u * (3 - 2 * u); } -static double at(double bar) { return bar * BAR; } +// THE CONSONANT RUNWAY NEEDS SOMEWHERE TO LIVE. voice_line places a phrase +// at at(bar) − leadIn, so her VOWEL lands on the beat and the consonant +// runs 1:1 before it, the way a singer leans in. At bar 0 that is NEGATIVE +// TIME, and emit() drops anything before sample 0 — so the 220 ms /s/ that +// opens "sitting" was not buried under the kick, it was never written to +// the file at all. Only the first pass lost it; bars 16, 48 and 80 have +// their runway. @jeffrey, twice: "the opening 's' is not hearable". +// +// @jeffrey: "can we start it as sitting from the first beat?" — with no +// intro at all, which puts the problem straight back: her /s/ has to run +// before the downbeat and there is nothing before the downbeat. +// +// A whole BEAT of pre-roll was the crude fix and it left 492 ms of silence +// at the head of the record. The exact fix is the phrase's own leadIn: +// pre-roll by precisely the runway that phrase needs, so the file opens ON +// the first sample of her /s/, her vowel lands on beat 1, and there is no +// silence anywhere. Nothing is trimmed and nothing is padded. +static double PREROLL = 0.0; +static double at(double bar) { return PREROLL + bar * BAR; } static double hz_of(double st) { return TONIC * pow(2.0, st / 12.0); } static uint32_t seed = 20260817u; static double rnd(void) { seed = seed * 1664525u + 1013904223u; return seed / 4294967296.0; } static double jit(double ms) { return ((rnd() - 0.5) * 2 * ms) / 1000.0; } + +// ── BOP ─────────────────────────────────────────────────────────────── +// @jeffrey: "any way we can add more bop / more jazz and humanization to +// the beat too?" +// +// SWING is the whole of the first half. A straight 16th grid is a machine +// counting; pushing every odd 16th late is what makes a beat walk. 0.58 +// is a light shuffle — 0.5 is dead straight, 0.667 is full triplet swing — +// and it applies to everything that lands off the beat, so the kit, the +// bassline and the stabs all lean the same way rather than fighting. +#define SWING 0.575 +static double sw(double step16) { // a 16th step index → seconds + double beat = floor(step16 / 2.0), odd = fmod(step16, 2.0); + return (beat + (odd ? 2.0 * SWING : 0.0)) * BEAT; +} + +// …and LEAN is the second half. A player does not vary each hit at +// random, they push through one bar and drag through the next: the error +// is CORRELATED, and that is what random jitter can never sound like. Two +// slow incommensurate waves plus a little noise, in milliseconds. +static double lean(double bar, double beat) { + double x = bar + beat / 4.0; + return (0.0075 * sin(TAU * x / 7.0) + 0.0042 * sin(TAU * x / 2.6) + + 0.0018 * sin(TAU * x / 1.37)); +} static uint32_t nseed = 20210725u; static double nrnd(void) { nseed ^= nseed << 13; nseed ^= nseed >> 17; nseed ^= nseed << 5; @@ -226,12 +280,15 @@ } static int missingN = 0; // ── the one-shot player (render3's shot(), ported) ───────────────────── +// `rate` is the playback speed and `rate_to` where it ends up: 1.0 plays +// the sample as recorded, 0.7 plays it slow AND low — which is the whole +// of "screwed", one number. Ramping between the two is a tape stop. typedef struct { - double gain, pan, side, dark, dur, dly, rvb, off, attack; + double gain, pan, side, dark, dur, dly, rvb, off, attack, rate, rate_to; int bus, rev; } Shot; static Shot shot_defaults(void) { - Shot o = { 1, 0, 0.35, 0, 0, 0, 0, 0, 0.0015, BUS_VOX, 0 }; + Shot o = { 1, 0, 0.35, 0, 0, 0, 0, 0, 0.0015, 1.0, 0.0, BUS_VOX, 0 }; return o; } static void shot(const char *name, double t, const Shot *o) { @@ -241,7 +298,13 @@ long start = lround(o->off * SR); if (start < 0) start = 0; if (start > s->n - 2) start = s->n - 2; long avail = o->rev ? (start ? start : s->n - 2) : (s->n - 2 - start); - long n = o->dur > 0 ? (long)fmin((double)avail, o->dur * SR) : avail; + double r0 = o->rate > 0 ? o->rate : 1.0; + double r1 = o->rate_to > 0 ? o->rate_to : r0; + // slower playback covers less tape in the same time, so a screwed slice + // of a given SOURCE length occupies more output than it used to + double rmid = 0.5 * (r0 + r1); + long n = o->dur > 0 ? (long)fmin(avail / fmax(rmid, 1e-6), o->dur * SR) + : (long)(avail / fmax(rmid, 1e-6)); if (n <= 4) return; long i0 = lround(t * SR); Spatial sp = spatial(o->pan * 1.2); @@ -256,56 +319,262 @@ if (o->dark > 0) { lp += (1 - o->dark) * (v - lp); v = lp; } double env = smoothstep((i / (double)SR) / o->attack); emit(o->bus, i0 + i, v * env * o->gain * tail_fade(i, n), o->pan, &sp, o->side, o->dly, o->rvb); - pos += o->rev ? -1.0 : 1.0; + double r = r0 + (r1 - r0) * (i / (double)n); + pos += o->rev ? -r : r; } } // lead + halo + optional backup, all locked to the same chart warp static void sung(const char *name, double t, double gain, double pan, double dly) { Shot o = shot_defaults(); - o.gain = gain; o.pan = pan; o.side = 0.5; o.dly = dly; o.rvb = 0.28; + // more room, more repeat: what puts a voice BEHIND the band is the + // ratio of what you hear directly to what you hear off the walls. + o.gain = gain; o.pan = pan; o.side = 0.5; + o.dly = dly > 0 ? dly + 0.14 : 0.0; o.rvb = 0.58; shot(name, t, &o); } -static void halo(const char *name, double t, double g) { - char nm[96]; +// the chart placer: subtracts the phrase's consonant lead-in so word 0 +// lands ON the beat +static const ChartPhrase *phrase_of(const char *name) { + for (int i = 0; i < CHART_N; i++) + if (!strcmp(CHART[i].name, name)) return &CHART[i]; + fprintf(stderr, " ! no chart phrase %s\n", name); exit(1); +} + +// ONE VOICE. The halo and the backup 3rd/5th used to hang off every call +// here; @jeffrey: "lets not have background vocals anymore". There is +// nothing to fade down to zero — the layers are not built and not sung. +static void voice_line(const char *name, double bar, double gain) { + const ChartPhrase *p = phrase_of(name); + sung(name, at(bar) - p->leadIn, gain, 0, 0.13); +} +// ── the vibraphone ──────────────────────────────────────────────────── +// @jeffrey: "maybe we should add more instruments · more vibes". Taken +// literally, and it is the right instrument for this record: the bank is +// all struck-and-decaying already (pluck, fembell) or all sustain (pads), +// and a vibraphone sits exactly between them. What makes one recognisable +// is not its spectrum, it is the MOTOR — rotating discs over the +// resonators chopping the sound about six times a second — so the tremolo +// is the point and the partials are just a bar being hit. +static void vibe(double t, double st, double dur, double gain, double pan) { + double ring = fmin(dur * 1.6 + 0.9, 4.2); + long n = lround(ring * SR), i0 = lround(t * SR); + Spatial sp = spatial(pan * 1.2); + double f = hz_of(st); + double p1 = 0, p2 = 0, p3 = 0, trem = 0; + for (long i = 0; i < n; i++) { + double u = i / (double)SR; + p1 += (TAU * f) / SR; + p2 += (TAU * f * 4.0) / SR; // the bar's strong 4th partial + p3 += (TAU * f * 9.2) / SR; // and the metallic one, brief + trem += (TAU * 5.6) / SR; + double body = sin(p1) + 0.30 * sin(p2) * exp(-u * 2.6) + + 0.10 * sin(p3) * exp(-u * 11.0); + double env = smoothstep(u / 0.006) * exp(-u * (1.5 + 0.9 / fmax(dur, 0.2))); + double motor = 1.0 - 0.42 * (0.5 - 0.5 * cos(trem)); + emit(BUS_MUSIC, i0 + i, body * 0.30 * env * motor * gain * tail_fade(i, n), + pan, &sp, 0.7, 0.14, 0.44); + } +} + +// ── a word, on its own ──────────────────────────────────────────────── +// @jeffrey: "can 'patiently' especially 'pa' be cooler". Every unit of the +// chart knows its label and its beat, and shot() already takes an offset +// and a length, so any single word can be lifted straight out of the +// rendered line and played again. `pa` is the one big gesture in the take +// — an 8.4-semitone scoop the glide guard deliberately leaves unsnapped — +// and it goes past in half a bar. This gives it the treatment it deserves. +static const ChartNote *unit_named(const ChartPhrase *p, const char *label) { + for (int i = 0; i < p->n; i++) + if (!strcmp(p->notes[i].t, label)) return &p->notes[i]; + fprintf(stderr, " ! no unit %s in %s\n", label, p->name); exit(1); +} +// THE THROW — the word again, an octave up, thrown at the delay and gone. +// Nothing is doubled underneath it: the line has already moved on, so what +// answers back is the scoop alone, arriving off the beat. +static void word_throw(const char *phrase, const char *label, double bar, + double gain, double late, double pan) { + const ChartPhrase *p = phrase_of(phrase); + const ChartNote *n = unit_named(p, label); Shot o = shot_defaults(); - o.side = 0.9; o.rvb = 0.62; o.attack = 0.35; o.bus = BUS_VOX; - snprintf(nm, sizeof nm, "%s-8ve-a", name); - o.gain = g; o.pan = -0.55; o.dly = 0.20; shot(nm, t + 0.028, &o); - snprintf(nm, sizeof nm, "%s-8ve-b", name); - o.gain = g * 0.92; o.pan = 0.55; o.dly = 0.24; shot(nm, t + 0.041, &o); + o.off = p->leadIn + n->beat * BEAT; + o.dur = n->dur * BEAT * 1.15; + o.gain = gain; o.pan = pan; o.side = 0.85; + o.dly = 0.62; o.rvb = 0.55; o.dark = 0.30; o.attack = 0.010; + shot(phrase, at(bar) - p->leadIn + n->beat * BEAT + late, &o); +} +// THE STUTTER — the first 80 ms of the word, three times on 16ths, walking +// up in level so the word itself is the fourth and loudest hit. It runs +// BEFORE the word, so the line is not interrupted; the scoop is announced. +static void word_stutter(const char *phrase, const char *label, double bar, + double gain, double pan) { + const ChartPhrase *p = phrase_of(phrase); + const ChartNote *n = unit_named(p, label); + double t0 = at(bar) - p->leadIn + n->beat * BEAT; + for (int k = 0; k < 3; k++) { + Shot o = shot_defaults(); + o.off = p->leadIn + n->beat * BEAT; + o.dur = 0.080; + o.gain = gain * (0.42 + 0.24 * k); + o.pan = pan * ((k % 2) ? -1 : 1); + o.side = 0.75; o.dly = 0.28; o.rvb = 0.22; o.attack = 0.004; + shot(phrase, t0 - (3 - k) * (BEAT / 4.0), &o); + } } -static void backup(const char *name, double t, double g, int five) { - char nm[96]; + +// ── A GHOST OF A WORD ───────────────────────────────────────────────── +// One word, slowed and soaked, at the level of something remembered +// rather than sung. The intro is built out of these: @jeffrey, "can the +// intro be more / have more previews". A preview is not a quieter copy of +// the section it announces, it is a GLIMPSE — the right length is one +// word, and the right level is under the band. +static void ghost_word(const char *phrase, const char *label, double t, + double rate, double gain, double pan) { + const ChartPhrase *p = phrase_of(phrase); + const ChartNote *nn = unit_named(p, label); Shot o = shot_defaults(); - o.side = 0.7; o.rvb = 0.45; o.attack = 0.06; o.dark = 0.25; - snprintf(nm, sizeof nm, "%s-low3", name); - o.gain = g; o.pan = -0.3; o.dly = 0.12; shot(nm, t, &o); - if (five) { - snprintf(nm, sizeof nm, "%s-low5", name); - o.gain = g * 0.8; o.pan = 0.3; o.dly = 0.14; shot(nm, t, &o); + o.off = p->leadIn + nn->beat * BEAT; + o.dur = nn->dur * BEAT * 1.4; + o.rate = rate; + o.gain = gain; o.pan = pan; o.side = 0.9; + o.dly = 0.52; o.rvb = 0.66; o.dark = 0.42; o.attack = 0.06; + shot(phrase, t, &o); +} + +// ── THE SCRATCH ─────────────────────────────────────────────────────── +// @jeffrey: "and scratches and stuff". A scratch is not a sound, it is a +// GESTURE: the same fragment of record dragged forward and back under the +// hand, so what you hear is one slice played at a shifting rate in +// alternating directions. shot() has both now, so this is the technique +// itself rather than an imitation of it — a baby scratch is `n` passes, +// each one faster and shorter than the last. +static void scratch(const char *phrase, const char *label, double t, + int passes, double gain, double pan) { + const ChartPhrase *p = phrase_of(phrase); + const ChartNote *nn = unit_named(p, label); + double cur = t; + for (int k = 0; k < passes; k++) { + double span = 0.13 / (1.0 + 0.42 * k); // tightening + double rate = 0.85 + 0.55 * k; // …and speeding up + Shot o = shot_defaults(); + o.off = p->leadIn + nn->beat * BEAT + 0.05; + o.dur = span; + o.rate = rate; o.rate_to = rate * (k % 2 ? 0.72 : 1.28); + o.rev = k % 2; // …dragged back + o.gain = gain * (0.68 + 0.32 * (k / (double)passes)); + o.pan = pan * ((k % 2) ? -0.7 : 1.0); + o.side = 0.9; o.dly = 0.24; o.rvb = 0.16; o.attack = 0.002; + shot(phrase, cur, &o); + cur += span; } } -// the chart placer: subtracts the phrase's consonant lead-in so word 0 -// lands ON the beat -static const ChartPhrase *phrase(const char *name) { - for (int i = 0; i < CHART_N; i++) - if (!strcmp(CHART[i].name, name)) return &CHART[i]; - fprintf(stderr, " ! no chart phrase %s\n", name); exit(1); + +// ── THE RISER ───────────────────────────────────────────────────────── +// Deleted with the rest of the ornaments when the kit was stripped, and +// wanted back now — @jeffrey: "and more epic drop". Noise through a +// bandpass that climbs, with the whole thing swelling: the oldest way of +// making a bar feel like it is about to end. +static void riser(double t, double dur, double gain) { + long n = lround(dur * SR), i0 = lround(t * SR); + double bp = 0, bp2 = 0; + for (long i = 0; i < n; i++) { + double u = i / (double)SR, f = u / dur; + double hz = 300.0 * pow(38.0, f); + double k = 1 - exp((-TAU * hz) / SR); + double k2 = 1 - exp((-TAU * hz * 0.55) / SR); + double w = nrnd(); + bp += k * (w - bp); bp2 += k2 * (w - bp2); + double env = f * f * (0.35 + 0.65 * (0.5 - 0.5 * cos(TAU * 5.0 * u))); + emit(BUS_DRUMS, i0 + i, (bp - bp2) * 1.5 * env * gain * tail_fade(i, n), + 0.1 * sin(TAU * 0.7 * u), NULL, 0, 0.10, 0.42); + } } -static void voice_line(const char *name, double bar, double gain, - double haloG, double backupG, int five) { - const ChartPhrase *p = phrase(name); - double t = at(bar) - p->leadIn; - sung(name, t, gain, 0, 0.13); - if (haloG > 0) halo(name, t, haloG); - if (backupG > 0) backup(name, t, backupG, five); + +// ── THE SCREW DOWN ──────────────────────────────────────────────────── +// The tape stopping. One long slice whose rate ramps to a crawl, so the +// pitch falls with it — which is the whole trick of "screwed", and the +// reason it belongs in front of a drop: everything sags, and then the +// floor comes back at full speed. +static void screw_down(const char *phrase, const char *label, double t, + double dur, double gain) { + const ChartPhrase *p = phrase_of(phrase); + const ChartNote *nn = unit_named(p, label); + Shot o = shot_defaults(); + o.off = p->leadIn + nn->beat * BEAT; + o.dur = dur; + o.rate = 1.0; o.rate_to = 0.34; + o.gain = gain; o.side = 0.8; o.dly = 0.40; o.rvb = 0.52; + o.dark = 0.30; o.attack = 0.02; + shot(phrase, t, &o); +} + +// ── THE VOCAL BREAK ─────────────────────────────────────────────────── +// @jeffrey: "cooler vocal breaks". Two bars where the band steps out of +// the way and the words come back chopped: 16th slices of a handful of +// units, accelerating, each one thrown further into the delay than the +// last, so the section is a voice disintegrating rather than a gap. The +// kick keeps running underneath — @jeffrey, earlier: "once the beat / +// kick starts it shouldn't stop it should run through the whole time" — +// and it is the hats and claps that clear out, which is what makes the +// return of the full kit land. +static void vocal_break(const char *phrase, double bar, + const char **words, int nw, double gain) { + const ChartPhrase *p = phrase_of(phrase); + // sixteen slices over two bars, tightening from 8ths to 16ths + for (int k = 0; k < 16; k++) { + double frac = k / 15.0; + double step = (k < 6) ? (BEAT / 2.0) : (BEAT / 4.0); + double t = at(bar) + (k < 6 ? k * (BEAT / 2.0) + : 3.0 * BEAT + (k - 6) * (BEAT / 4.0)); + const ChartNote *n = unit_named(p, words[k % nw]); + Shot o = shot_defaults(); + o.off = p->leadIn + n->beat * BEAT; + // slices shorten as the figure tightens, so it stutters rather + // than overlapping into mush + o.dur = fmin(step * 0.92, 0.055 + 0.16 * (1.0 - frac)); + o.gain = gain * (0.42 + 0.58 * frac); + o.pan = ((k % 2) ? 0.34 : -0.34) * (0.4 + 0.6 * frac); + o.side = 0.85; + o.dly = 0.22 + 0.46 * frac; + o.rvb = 0.30 + 0.34 * frac; + o.dark = 0.42 * (1.0 - frac); // opens up as it accelerates + o.attack = 0.004; + // SCREWED, not merely chopped — @jeffrey: "can we make it even + // more chopped and screwed". Every third slice drags: played at + // two-thirds speed it is also six semitones down, which is the + // technique in one number. Every fourth runs backwards. The rest + // stay square so the figure keeps its pulse. + if (k % 3 == 2) { o.rate = 0.66; o.dur *= 1.5; o.gain *= 1.15; } + if (k % 4 == 3) { o.rev = 1; o.rate = 0.84; } + shot(phrase, t, &o); + // …and a double-trigger under the tightest half: the same slice + // again a 32nd later, quieter, which is the hand slipping + if (k >= 10 && (k % 2 == 0)) { + Shot d = o; + d.gain *= 0.5; d.pan = -o.pan; d.rev = 0; d.rate = 1.28; + d.dur = fmin(o.dur, 0.05); + shot(phrase, t + BEAT / 8.0, &d); + } + } +} + +// A DIFFERENT TAKE OF THE SAME SENTENCE. bin/singdub.py warps s- and o- +// onto this chart and writes exactly its 60 beats, starting at beat 0 — +// so there is no consonant runway to subtract the way voice_line does for +// the take the chart was measured FROM. bin/stage-takes.sh has already +// matched the level, so `gain` here means the same thing it means above +// and the swap reads as a change of room, not of volume. +__attribute__((unused)) +static void alt_line(const char *name, double bar, double gain, double side) { + Shot o = shot_defaults(); + o.gain = gain; o.side = side; o.dly = 0.15; o.rvb = 0.36; + shot(name, at(bar), &o); } // ── the kit — four on the floor, synthesized ─────────────────────────── #define MAX_KICKS 2048 static double kickT[MAX_KICKS]; static int kickN = 0; -static const double KSAT_D = 0.999329299739067; // tanh(3.8) +static const double KSAT_24 = 0.983674092938487; // tanh(2.4) // A HARDER KICK, for the speakers it will actually be heard on. // @jeffrey: "can the kick be harder · so i can hear it better on laptop // speakers with the AC on lol". A laptop cannot reproduce 50 Hz at all, @@ -317,20 +586,51 @@ // tighter, the pitch envelope drops faster, and the click is louder, // longer and two-toned instead of a 2 ms blip at 0.07. static void kick(double t, double gain) { if (kickN < MAX_KICKS) kickT[kickN++] = t; - long n = lround(0.34 * SR), i0 = lround(t * SR); + long n = lround(0.46 * SR), i0 = lround(t * SR); // room for the tail double ph = 0, sub = 0, knk = 0; for (long i = 0; i < n; i++) { double u = i / (double)SR; - double f = 50 + 130 * exp(-u * 58); // snappier drop + // DEEPER — @jeffrey: "maybe a deeper kick". The body used to bottom + // out at 50 Hz and get there in 17 ms; it now falls to 38 and takes + // its time about it, which is what a big kick actually is — not + // more level down low but longer SPENT down low. The sub under it + // drops from 45 to 36 Hz and rings twice as long. The knock and the + // click are untouched: they are what carries the kick on a laptop + // speaker, and none of this is audible there at all. + // …AND DEEP FROM THE FIRST SAMPLE — @jeffrey: "it should be deeper + // especially at the beginnign". Measured, the old attack was not + // deep at all: over its first 25 ms only 5% of the energy sat + // under 60 Hz, with 63% at 60–150 and 31% above that. All the low + // end was in the TAIL. A pitch envelope starting at 180 Hz means + // the sound you hear land is a midrange thump and the depth only + // catches up afterwards, which reads as sharp however gently the + // click is treated. It now starts at 112 and settles to 34. + double f = 34 + 78 * exp(-u * 30); ph += (TAU * f) / SR; - sub += (TAU * 45) / SR; + sub += (TAU * 36) / SR; knk += (TAU * 300) / SR; - double env = (0.6 * exp(-u * 30) + 0.5 * exp(-u * 9)) * fmin(1, u / 0.0008); - double body = tanh(sin(ph) * env * 3.8) / KSAT_D; - double low = sin(sub) * exp(-u * 7) * 0.20; - double knock = sin(knk) * exp(-u * 95) * 0.36; // ~10 ms at 300 Hz - double click = exp(-u * 190) * 0.30 * - (sin(TAU * 2400 * u) + 0.7 * sin(TAU * 4300 * u)); + // TOO SHARP — @jeffrey. Three things were making the edge, and all + // three were deliberate once: the drive was pushed to 3.8 (nearly + // a square wave) and the click to 0.30 back when the brief was + // "can the kick be harder · so i can hear it better on laptop + // speakers with the AC on lol". That kick had to fight; this one + // does not — it is deep now, and a deep kick with a square top is + // just a click sitting on a note. + // + // So the drive comes back to 2.4, where the saturation is adding + // harmonics rather than corners; the click drops to a third and + // moves down an octave, from 2.4/4.3 kHz to 1.5/2.7; and the + // attack takes 2.2 ms instead of 0.8, which is the difference + // between a beater and a spike. The knock stays — that is the part + // a laptop can actually reproduce. + double env = (0.6 * exp(-u * 30) + 0.5 * exp(-u * 9)) * fmin(1, u / 0.0022); + double body = tanh(sin(ph) * env * 2.4) / KSAT_24; + // the sub is at full from sample zero — it is the only part of the + // kick that is already low when the hit arrives + double low = sin(sub) * exp(-u * 3.2) * 0.52; + double knock = sin(knk) * exp(-u * 95) * 0.17; // ~10 ms at 300 Hz + double click = exp(-u * 150) * 0.10 * + (sin(TAU * 1500 * u) + 0.7 * sin(TAU * 2700 * u)); emit(BUS_DRUMS, i0 + i, (body + low + knock + click) * 0.86 * gain * tail_fade(i, n), 0, NULL, 0, 0, 0); @@ -357,61 +657,93 @@ emit(BUS_DRUMS, i0 + i, s * 0.46 * gain * fmin(1, u / 0.001) * tail_fade(i, n), pan, &sp, 0.35, 0, 0.06); } } -static void snare(double t, double gain, double pan) { - long n = lround(0.18 * SR), i0 = lround(t * SR); +// airhat — the offbeat open hat, longer and breathier +// @jeffrey: "can we make it cooler? more up beat". The kit stays simple — +// kick, one offbeat hat, clap on 2 and 4 — but a closed hat on every +// offbeat is a metronome. `open` lets the hat RING, and an open hat on the +// offbeat is the oldest lift in house: it pulls the ear onto the "and" +// instead of onto the beat, and the track starts pushing forward rather +// than marking time. +static void airhat(double t, double gain, double pan, int open) { + double ring = open ? 0.38 : 0.14; + double decay = open ? 7.0 : 24.0; + long n = lround(ring * SR), i0 = lround(t * SR); Spatial sp = spatial(pan * 1.2); - double ph = 0, bp = 0, bp2 = 0; - double k = 1 - exp((-TAU * 3200) / SR), k2 = 1 - exp((-TAU * 1200) / SR); + double bp = 0, bp2 = 0; + double k = 1 - exp((-TAU * (open ? 9200 : 10500)) / SR); + double k2 = 1 - exp((-TAU * 7200) / SR); for (long i = 0; i < n; i++) { double u = i / (double)SR; - ph += (TAU * 196) / SR; double w = nrnd(); bp += k * (w - bp); bp2 += k2 * (w - bp2); - double noise = (bp - bp2) * exp(-u * 22); - double knock = sin(ph) * exp(-u * 30) * 0.5; - double s = tanh((noise * 1.6 + knock) * 1.4); - emit(BUS_DRUMS, i0 + i, s * 0.52 * gain * fmin(1, u / 0.001) * tail_fade(i, n), - pan, &sp, 0.3, 0, 0.05); + emit(BUS_DRUMS, i0 + i, + (bp - bp2) * exp(-u * decay) * 1.1 * gain * (open ? 0.86 : 1.0) + * tail_fade(i, n), + pan, &sp, 0.45, 0, open ? 0.10 : 0.03); } } -// tick — a synthesized closed hat: 8 kHz-centred noise, 30 ms -static void tick(double t, double gain, double pan) { - long n = lround(0.030 * SR), i0 = lround(t * SR); + +// ── the snare — brushed, not cracked ────────────────────────────────── +// @jeffrey: "snares too". The old one was deleted with the rest of the +// ornaments when the kit was stripped, and it was a crack: noise through a +// high band with a fast spike, which is the wrong instrument for a record +// that has just spent an evening getting its kick to stop being sharp. +// +// This is a brush instead. The band sits LOW — 190 Hz to 1.4 kHz rather +// than up where a rimshot lives — there is a tuned shell tone under it at +// 185 Hz, and the attack takes 4 ms, so it arrives rather than snapping. +// `wire` is how much snare-wire rattle rides on top; at 0 it is a tom, at +// 1 it is a backbeat, and the ghosts in between are most of the groove. +static void snare(double t, double gain, double wire, double pan) { + long n = lround((0.16 + 0.10 * wire) * SR), i0 = lround(t * SR); Spatial sp = spatial(pan * 1.2); - double bp = 0, bp2 = 0; - double k = 1 - exp((-TAU * 9500) / SR), k2 = 1 - exp((-TAU * 6000) / SR); + double bp = 0, bp2 = 0, sh = 0, sh2 = 0; + double k = 1 - exp((-TAU * 1400.0) / SR), k2 = 1 - exp((-TAU * 190.0) / SR); for (long i = 0; i < n; i++) { double u = i / (double)SR; double w = nrnd(); bp += k * (w - bp); bp2 += k2 * (w - bp2); - emit(BUS_DRUMS, i0 + i, (bp - bp2) * exp(-u * 90) * 1.6 * gain * tail_fade(i, n), - pan, &sp, 0.4, 0, 0); + double brush = (bp - bp2) * exp(-u * (26.0 - 9.0 * wire)); + sh += (TAU * 185.0) / SR; sh2 += (TAU * 262.0) / SR; + double shell = (sin(sh) + 0.45 * sin(sh2)) * exp(-u * 30.0) * 0.42; + double env = fmin(1.0, u / 0.004); + emit(BUS_DRUMS, i0 + i, + (brush * (0.35 + 0.65 * wire) + shell) * 0.55 * env * gain + * tail_fade(i, n), + pan, &sp, 0.5, 0.05, 0.20 + 0.16 * wire); } } -// airhat — the offbeat open hat, longer and breathier -static void airhat(double t, double gain, double pan) { - long n = lround(0.14 * SR), i0 = lround(t * SR); + +// ── the stab — a chord on the offbeat ────────────────────────────────── +// The other half of "more up beat", and it is musical rather than +// percussive: a short filtered chord landing on the "and", which is what +// makes a house record feel like it is leaning forward. Sharp attack, a +// decay under a beat, and a lowpass that opens with the arrangement, so +// the same figure reads as muffled in an early pass and bright in a late +// one. +static void stab(double t, const double *tones, int n_t, double dur, + double gain, double open, double pan) { + long n = lround((dur + 0.10) * SR), i0 = lround(t * SR); Spatial sp = spatial(pan * 1.2); - double bp = 0, bp2 = 0; - double k = 1 - exp((-TAU * 10500) / SR), k2 = 1 - exp((-TAU * 7200) / SR); + double ph[4] = {0, 0, 0, 0}, det[4] = {1.0, 1.0032, 0.9971, 1.0018}; + double lp = 0, lp2 = 0; + double cut = 520.0 + 3400.0 * open; + double k = 1 - exp((-TAU * cut) / SR); for (long i = 0; i < n; i++) { double u = i / (double)SR; - double w = nrnd(); - bp += k * (w - bp); bp2 += k2 * (w - bp2); - emit(BUS_DRUMS, i0 + i, (bp - bp2) * exp(-u * 24) * 1.1 * gain * tail_fade(i, n), - pan, &sp, 0.45, 0, 0.03); - } -} -static void riser(double t, double dur, double gain) { - long n = lround(dur * SR), i0 = lround(t * SR); - double bp = 0; - for (long i = 0; i < n; i++) { - double u = i / (double)n; - double w = nrnd(); - double kf = 1 - exp((-TAU * (600 + 8000 * u * u)) / SR); - bp += kf * (w - bp); - emit(BUS_DRUMS, i0 + i, bp * u * u * gain * tail_fade(i, n), - (u - 0.5) * 0.4, NULL, 0, 0, 0.10); + double env = smoothstep(u / 0.004) * exp(-u * (3.4 / fmax(dur, 0.05))); + double v = 0; + for (int j = 0; j < n_t && j < 4; j++) { + double f = hz_of(tones[j]); + ph[j] += (TAU * f * det[j]) / SR; + // a saw, so the filter has something to bite on + double x = fmod(ph[j] / TAU, 1.0) * 2.0 - 1.0; + v += x; + } + v /= (double)(n_t ? n_t : 1); + lp += k * (v - lp); lp2 += k * (lp - lp2); // 12 dB/oct + emit(BUS_MUSIC, i0 + i, lp2 * 0.5 * env * gain * tail_fade(i, n), + pan, &sp, 0.6, 0.16, 0.30); } } @@ -481,7 +813,7 @@ } // play a chart phrase's melody as pluck notes — the band doubling her, // or answering in the gaps (octave 0 doubles; +12 answers up high) static void pluck_line(const char *name, double bar, double gain, int oct, double pan) { - const ChartPhrase *p = phrase(name); + const ChartPhrase *p = phrase_of(name); for (int i = 0; i < p->n; i++) { const ChartNote *nn = &p->notes[i]; pluck(at(bar) + nn->beat * BEAT + jit(3), nn->st + oct, @@ -489,86 +821,302 @@ nn->dur * BEAT, gain * (1 - 0.03 * i), pan * ((i % 2) ? -1 : 1)); } } -// ── the harp (vox3's arp bank, LCG-swung) ────────────────────────────── -static const int ARP_I[] = { 12, 15, 19, 24, 27 }; -static const int ARP_III[] = { 15, 19, 22, 27 }; -static const int ARP_IV[] = { 17, 20, 24 }; -static const int ARP_VI[] = { 15, 20, 24, 27 }; -static const int ARP_VII[] = { 17, 22, 26 }; -static void arp(double t, const int *tones, int ntones, const char *vowel, - int count, int up, double gap, double gain, double pan) { - for (int k = 0; k < count; k++) { - int st = tones[up ? k % ntones : ntones - 1 - (k % ntones)] - + 12 * (k / ntones) * (up ? 1 : -1); - char nm[32]; snprintf(nm, sizeof nm, "arp-%s-%d", vowel, st); - if (!bank_get(nm)) continue; - Shot o = shot_defaults(); - o.gain = gain * (1 - 0.06 * k); - o.pan = pan * ((k % 2) ? -1 : 1); - o.side = 0.8; o.dly = 0.30; o.rvb = 0.5; o.dur = 0.22; o.attack = 0.022; - shot(nm, t + k * gap + jit(4) + ((k % 2) ? 0.010 : 0), &o); - } -} +// ── FEM bells — the /pop bell voice, in this engine ──────────────────── +// @jeffrey: "lets extend this now a bit and add fem bells · bring in our +// usual /pop sounds". pop/bell/ solves a real shell by finite elements and +// bakes wavs; that is the right tool for a bell record and the wrong one +// for a voice inside a 2-minute dance cut, so this is its OUTPUT shape: a +// modal sum on the partial ratios a struck bell actually has, each partial +// with its own decay and a little beating between a detuned pair. +// +// The house rules from pop/wattajetta come with it, and they are rules +// because breaking them made that record tangy on a laptop: +// · runs stay at or under E5 — see BELL_CEIL_ST +// · bells NEVER pass through saturation; this writes to BUS_MUSIC clean +// · a choked strike gets a real fade, never a truncation +static const double BELL_PARTIAL[6] = { 0.5, 1.0, 1.19, 1.5, 2.0, 2.51 }; +static const double BELL_GAIN[6] = { 0.42, 1.0, 0.55, 0.38, 0.30, 0.14 }; +static const double BELL_DECAY[6] = { 1.6, 2.6, 3.4, 4.2, 5.4, 8.0 }; +// THE CEILING, RAISED. @jeffrey: "lets bring up the fem bel pitch". The +// E5 line came from pop/wattajetta, where E5–E6 runs read "too high and +// tangy on my macbook speakers" — that lesson is about MELODIC bell runs +// carrying the tune, and these are answering a vocal rather than carrying +// it. So the ceiling goes to A5 and the runs start an octave higher, with +// the compensation the same memory prescribes: the sixth octave is for +// SPARKLE, so anything above E5 loses gain rather than keeping it. Bells +// still never touch saturation — that is the part of the rule that is not +// negotiable, and it is why they go straight to BUS_MUSIC. +#define BELL_CEIL_ST 23.0 // A5 in the take's frame +#define BELL_TANG_ST 18.0 // …but above E5 it pays for the altitude -// ── tape ─────────────────────────────────────────────────────────────── -static void hiss_bed(void) { - double lp = 0, hp = 0, prev = 0, lvl = 0.010; - double kLp = 1 - exp((-TAU * 5200) / SR); - double hpRc = 1 / (TAU * 320), hpA = hpRc / (hpRc + 1.0 / SR); - for (long i = 0; i < N; i++) { - double bar = i / (double)SR / BAR; - double target = bar < 32 ? 0.0040 : bar < 40 ? 0.0095 : - bar < 60 ? 0.0040 : 0.011; - lvl += 0.000004 * (target - lvl); - double w = nrnd(); - lp += kLp * (w - lp); - hp = hpA * (hp + lp - prev); prev = lp; - musicL[i] += hp * lvl; musicR[i] += hp * lvl * 0.94; +static void fembell(double t, double st, double dur, double gain, double pan) { + while (st > BELL_CEIL_ST) st -= 12; // the ceiling is not optional + if (st > BELL_TANG_ST) // sparkle, not melody + gain *= 1.0 - 0.42 * ((st - BELL_TANG_ST) / (BELL_CEIL_ST - BELL_TANG_ST)); + double ring = fmin(dur * 1.4 + 0.5, 3.2); + long n = lround(ring * SR), i0 = lround(t * SR); + Spatial sp = spatial(pan); + double f = hz_of(st); + double ph[6][2] = {{0}}; + // the strike: a short bright contact before the modes take over + long nc = lround(0.006 * SR); + for (long i = 0; i < n; i++) { + double u = i / (double)SR; + double s = 0; + for (int k = 0; k < 6; k++) { + double fk = f * BELL_PARTIAL[k]; + ph[k][0] += (TAU * fk) / SR; + ph[k][1] += (TAU * fk * 1.0018) / SR; // the beat in a real bell + s += BELL_GAIN[k] * exp(-u * BELL_DECAY[k]) + * (sin(ph[k][0]) + 0.8 * sin(ph[k][1])); + } + s /= 3.4; + if (i < nc) s += 0.30 * (rnd() * 2 - 1) * (1 - i / (double)nc); + // a truncated ring clicks — fade the last 80 ms, always + double env = 1.0; + double left = (n - i) / (double)SR; + if (left < 0.080) env = left / 0.080; + emit(BUS_MUSIC, i0 + i, s * env * gain * tail_fade(i, n), pan, &sp, + 0.45, 0.18, 0.42); } } -static void dust(double t, double gain) { - long n = lround(0.0022 * SR), i0 = lround(t * SR); - for (long i = 0; i < n; i++) - emit(BUS_MUSIC, i0 + i, nrnd() * exp(-i / (0.0006 * SR)) * gain, - nrnd() * 0.5, NULL, 0, 0, 0); -} + + // ── harmony — the v3 chords on a one-bar dance rhythm ────────────────── -typedef struct { double root; double tones[3]; } Chord; -static const Chord CH_i = { 0, { 0, 3, 7 } }; -static const Chord CH_III = { 3, { 3, 7, 10 } }; -static const Chord CH_VI = { -4, { -4, 0, 3 } }; -static const Chord CH_VII = { -2, { -2, 2, 5 } }; +// …and the SEVENTH. @jeffrey: "more jazz". A triad is a fact; a seventh is +// an opinion. These are the same four chords the record has always used — +// nothing about the harmony moves — but each now carries the note that +// makes it lean somewhere: minor sevenths on i and VI, a major seventh on +// III where the tune is already at its brightest, and a ninth on VII +// because it is the turnaround and wants to be unresolved. Only the stab +// and the pad reach for it; the bass and the bells stay on the triad, so +// the colour arrives without the bottom getting muddy. +typedef struct { double root; double tones[3]; double sev; } Chord; +static const Chord CH_i = { 0, { 0, 3, 7 }, 10 }; // i7 +static const Chord CH_III = { 3, { 3, 7, 10 }, 14 }; // III maj7 → 9 +static const Chord CH_VI = { -4, { -4, 0, 3 }, 6 }; // VI7 +static const Chord CH_VII = { -2, { -2, 2, 5 }, 9 }; // VII add9 // per section: 8-bar rows (dance harmonic rhythm: one chord per bar) static const Chord *ROW_VERSE[8] = { &CH_i, &CH_i, &CH_VI, &CH_VI, &CH_III, &CH_III, &CH_VII, &CH_VII }; static const Chord *ROW_HOOK[8] = { &CH_VI, &CH_VII, &CH_i, &CH_i, &CH_VI, &CH_VII, &CH_III, &CH_VII }; static const Chord *ROW_BREAK[8] = { &CH_i, &CH_i, &CH_VI, &CH_VI, &CH_i, &CH_i, &CH_VII, &CH_VII }; +// LONERCLUB, the narrative — @jeffrey: "i want our mix to have drops and +// arepggios · and like nice overall narrative · lets call the track +// Lonerclub". Every block that holds the whole take is SIXTEEN bars now: +// the charted line runs 60 beats, and the old 12-bar blocks made her +// sing straight through the section after her. +// +// SIX PASSES, AND THE LEAD CHANGES HANDS. @jeffrey: "lets work on swap +// lead and also use / bring in group takes · but the idea is we start +// small with camille's softest take then we build up each one · maybe +// even alonging / getting things longer a bit". The takes were MEASURED +// and they already form the arc: f −22.1 LUFS (the Feral spine, softest, +// solo), s −16.8 (roomier and lower, solo), o −12.2 (the ensemble, with +// @jeffrey and Alex). So the record starts on the quietest thing she ever +// sang and ends with a room full of people singing it. +// +// L1 0–16 0:00 f- alone. No harmony at all. +// L2 16–32 0:31 f- and her low 3rd +// L3 32–48 1:03 the S TAKE takes the lead — floor thins, kick stays +// L4 48–64 1:34 f- back, 3rd and 5th, bells arpeggiating +// L5 64–80 2:06 the GROUP take leads. The club sings it. +// L6 80–96 2:37 the ghost, thinning to the pluck alone static const Chord *chord_at(int bar) { - if (bar < 12) return ROW_VERSE[bar % 8]; - if (bar < 20) return ROW_HOOK[bar % 8]; - if (bar < 28) return ROW_VERSE[bar % 8]; - if (bar < 40) return ROW_BREAK[bar % 8]; - if (bar < 58) return (bar < 52) ? ROW_VERSE[bar % 8] : ROW_HOOK[bar % 8]; - return ROW_BREAK[bar % 8]; + int b = bar - INTRO; // the intro rides L1's changes + if (b < 0) b += 16; + if (b < 16) return ROW_VERSE[b % 8]; + if (b < 32) return ROW_HOOK[b % 8]; + if (b < 48) return ROW_BREAK[b % 8]; + if (b < 64) return ROW_VERSE[b % 8]; + if (b < 80) return ROW_HOOK[b % 8]; + return ROW_BREAK[b % 8]; } static int kick_on(int bar) { // the strict floor: where it runs - return !(bar >= 28 && bar < 40) && bar < 72; + return !(bar >= L(2) && bar < L(3)) && bar < BARS - 4; +} + +// A bell RUN — chord tones climbing from the tonic, swung a little so it +// rolls rather than marches. This is the arpeggio @jeffrey asked the mix +// for ("i want our mix to have drops and arepggios"), played by the bell. +static void bell_run(double t, const Chord *c, int count, double step, + double gain, int up, double pan) { + for (int k = 0; k < count; k++) { + int idx = up ? k : count - 1 - k; + double st = c->tones[idx % 3] + 12 * (idx / 3) + 12; + fembell(t + k * step + ((k % 2) ? step * 0.08 : 0) + jit(3), + st, step * 1.6, gain * (1 - 0.05 * k), + pan * ((k % 2) ? -1 : 1)); + } +} + +// ── THE HOOK ────────────────────────────────────────────────────────── +// @jeffrey: "our instrumentation should be smarter compositionally / more +// structured". What it was doing was texture: every part played all the +// time inside its section, the pluck doubled her line in unison, and the +// bells ran the same arpeggio whatever bar they were in. Nothing was ever +// STATED, so nothing could be answered or returned to. +// +// This is the figure the record quotes. It is the first four notes of her +// own melody — 7 5 3 2, the descent under "sit-ting curled up" — because a +// hook the band invents is decoration, and a hook lifted from the singer +// is the song. It is stated at the head of a phrase and ANSWERED four bars +// later by its inversion, which is the oldest structure there is: +// antecedent, then consequent. +static const int HOOK[4] = { 7, 5, 3, 2 }; +static const int HOOK_ANS[4] = { 2, 3, 5, 7 }; +enum { VOICE_PLUCK, VOICE_VIBE, VOICE_BELL }; + +static void hook_say(double t, const int *fig, int oct, int voice, + double gain, double pan) { + for (int k = 0; k < 4; k++) { + double u = t + k * (BEAT / 2.0) + jit(4); + double st = fig[k] + oct; + double p = pan * ((k % 2) ? -0.6 : 1.0); + switch (voice) { + case VOICE_VIBE: vibe(u, st, 0.9, gain, p); break; + case VOICE_BELL: fembell(u, st, 1.1, gain * 0.8, p); break; + default: pluck(u, st, 0.75, gain, p); break; + } + } +} + +// THE TURNAROUND. Eight-bar rows that simply repeat have no edge to them; +// this marks bar 7 of each row so the ear can hear a phrase close and +// another begin. It is the VII chord walking up into the downbeat — the +// one place in the harmony that is already unresolved. +static void turnaround(double bar, double gain) { + static const int UP[3] = { -2, 2, 5 }; + for (int k = 0; k < 3; k++) + pluck(at(bar) + (2.0 + k * 0.5) * BEAT + jit(4), UP[k] + 12, + 0.5, gain * (0.7 + 0.15 * k), (k % 2) ? 0.30 : -0.26); + fembell(at(bar) + 3.5 * BEAT, 9, 0.9, gain * 0.5, 0.2); +} + + +// ── the backing voice — one sine, one note at a time, under her ──────── +// @jeffrey: "canwe start to bring in piano / sine pad accompaniment · +// just a single voice to back the vocal". Deliberately NOT the chord +// stack the bed already plays: one voice, held, moving as little as the +// harmony will let it and re-articulating only when it has to move. It +// lives in the octave under her lowest sung note (G#3), so it holds the +// chord up without ever arriving in the same place as a word — and it is +// `pad()` with nst = 1, which is already a detuned sine pair under a +// tape-wow lid, rather than a second synth doing the same job. +// The register. It was A#2–G3 (103–195 Hz) — genuinely under her, and +// genuinely inaudible on anything without a woofer: @jeffrey, "im not +// hearing those instruments". Moved up a fifth into the range a laptop +// and a phone actually reproduce, still below her sung line (her lowest +// is G#3, −5, and she spends the song above it). +#define BACK_LO (-7.0) // F3 up to C4 +#define BACK_HI (3.0) +static double backing_note(const Chord *c, double from, int first) { + double best = BACK_LO, bestd = 1e9; + for (int k = 0; k < 3; k++) + for (int oct = -2; oct <= 1; oct++) { + double st = c->tones[k] + 12 * oct; + if (st < BACK_LO || st > BACK_HI) continue; + // voice-leading: the nearest tone to where the voice already + // is. Only the first note is placed by register instead. + double d = first ? fabs(st + 9) : fabs(st - from); + if (d < bestd) { bestd = d; best = st; } + } + return best; +} +// One call per HELD note, not per bar — a bar whose chord keeps the +// voice's note just lets it ring rather than striking it again. +static void backing_line(int bar0, int bars, double off, double gain) { + double cur = 0; + int start = -1; + for (int bar = 0; bar <= bars; bar++) { + double st = 0; + int have = bar < bars; + if (have) st = backing_note(chord_at(bar0 + bar), cur, start < 0); + if (start >= 0 && (!have || st != cur)) { + pad(off + at(bar0 + start), &cur, 1, (bar - start) * BAR - 0.06, + gain, 0.55, 0.0, 0.35, 0.08, 0.26); + start = -1; + } + if (have && start < 0) { cur = st; start = bar; } + } } // ── the floor — one bar of the dance kit ─────────────────────────────── -static const double VEL[16] = { 1, 0.45, 0.7, 0.5, 0.9, 0.45, 0.72, 0.5, - 1, 0.45, 0.7, 0.5, 0.85, 0.5, 0.78, 0.55 }; -static void floor_bar(int bar, double kickG, double hatG, int claps, int fills) { +// @jeffrey: "simple perc". Kick on the four, one hat on the offbeat, a +// clap on 2 and 4. The 16th-note tick bed, the snare backbeat, the fills +// and the risers are gone. They were the difference between a track that +// moves and a track that is busy, and every one of them lived in the same +// 4–8 kHz band as her consonants. +// VELOCITY, as a player would place it. Four identical kicks a bar is the +// machine; a drummer leans on 1, lets 2 breathe, half-leans on 3. The +// pattern repeats over two bars so it is a groove and not a wobble. +static const double KV[8] = { 1.00, 0.90, 0.96, 0.88, 0.98, 0.87, 0.94, 0.91 }; +static const double HV[8] = { 0.92, 1.00, 0.86, 0.97, 0.95, 1.00, 0.84, 0.99 }; + +static void floor_bar(int bar, double kickG, double hatG, int claps) { double t = at(bar); - for (int b = 0; b < 4; b++) kick(t + b * BEAT, kickG * (b == 0 ? 1.0 : 0.94)); - if (claps) { clap(t + 1 * BEAT, 0.85, 0.08); clap(t + 3 * BEAT, 0.82, -0.06); } - for (int b = 0; b < 4; b++) airhat(t + (b + 0.5) * BEAT, 0.16, (b % 2) ? 0.3 : -0.3); - for (int s = 0; s < 16; s++) tick(t + s * STEP + jit(2), hatG * VEL[s], (s % 2) ? 0.3 : -0.24); - if (fills && bar % 4 == 3) { - snare(t + 14 * STEP, 0.30, 0.2); - snare(t + 15 * STEP, 0.36, -0.15); + for (int b = 0; b < 4; b++) { + double d = lean(bar, b); + kick(t + b * BEAT + d, kickG * KV[(bar * 4 + b) % 8]); + } + if (claps) { + // the clap lands a hair LATE, always — it is the one thing in a + // house bar that is allowed to be behind the beat, and it is most + // of what makes the two and four feel like a person + clap(t + 1 * BEAT + lean(bar, 1) + 0.010, 0.66, 0.08); + clap(t + 3 * BEAT + lean(bar, 3) + 0.013, 0.64, -0.06); + } + // the "and" of 2 and 4 rings; the other two stay closed — and every + // one of them is SWUNG, so the offbeat arrives late the way a + // shuffle does rather than exactly halfway + for (int b = 0; b < 4; b++) + airhat(t + sw(b * 2 + 1) + lean(bar, b + 0.5), + hatG * HV[(bar * 4 + b) % 8], (b % 2) ? 0.28 : -0.24, b % 2); + // GHOST HATS on the last 16th of every other beat: barely there, + // swung with everything else, and the reason the bar has an inside. + for (int b = 0; b < 4; b++) { + if ((bar + b) % 2) continue; + airhat(t + sw(b * 2 + 1.5) + lean(bar, b + 0.75), + hatG * 0.34, (b % 2) ? -0.36 : 0.34, 0); + } + // GHOST SNARES — the brush, under everything, on the 16ths a drummer + // fills with their left hand. Never on 2 and 4: the clap owns those, + // and doubling them would just make the backbeat louder rather than + // making the bar breathe. + if (claps) { + snare(t + sw(2.5) + lean(bar, 1.25), 0.16, 0.30, -0.22); + snare(t + sw(6.5) + lean(bar, 3.25), 0.13, 0.26, 0.24); + if (bar % 4 == 3) { + snare(t + sw(6) + lean(bar, 3.0), 0.22, 0.55, 0.10); + snare(t + sw(7) + lean(bar, 3.5), 0.30, 0.75, -0.12); + } + } + + // ── POLYRHYTHM ──────────────────────────────────────────────────── + // @jeffrey: "and polythyrhtms!". Two of them, both against the same + // 4/4 floor and neither of them agreeing with it: + // + // THREE against four — a brush every 3 sixteenths. Sixteen 16ths in + // a bar and a period of 3 means the pattern only lands on the + // downbeat again every THREE bars, so the same figure keeps + // arriving somewhere new. + // FIVE against four — a closed hat every 5 sixteenths, which takes + // FIVE bars to come round. The two cycles agree once every fifteen. + // + // Both are quiet. A polyrhythm you can pick out is a competing beat; + // one you can only feel is a groove. + { + long step = (long)bar * 16; + for (int q = 0; q < 16; q++) { + long g = step + q; + if (g % 3 == 0) + snare(t + sw(q) + lean(bar, q / 4.0), 0.085, 0.16, + (g % 6) ? 0.40 : -0.40); + if (g % 5 == 0) + airhat(t + sw(q) + lean(bar, q / 4.0), hatG * 0.30, + (g % 10) ? -0.42 : 0.42, 0); + } } - if (bar % 2 == 1) snare(t + 7 * STEP, 0.20, -0.2); } // ── sidechain — the pump, keyed by every kick ────────────────────────── @@ -597,7 +1145,7 @@ // ═══ main ══════════════════════════════════════════════════════════════ static int minimal_bars(void) { // the line once, plus a bar to breathe — and never past bar 16 // (@jeffrey: "no need to go past bar 16"); the line ends inside 15. - int b = (int)(ceil(phrase("w-whole-line")->beats / 4.0) + 2); + int b = (int)(ceil(phrase_of("w-whole-line")->beats / 4.0) + 2); return b < 16 ? b : 16; } @@ -606,9 +1154,12 @@ // MINIMAL=1 → the study pass: kick + the unbroken vocal, nothing // else — "lets start with just kick and vocals and get that right". int minimal = getenv("MINIMAL") != NULL; BEAT = 60.0 / BPM; BAR = 4 * BEAT; STEP = BEAT / 4; + // exactly the runway the first sung phrase needs, and not a sample + // more — see the note above at(). + PREROLL = INTRO > 0 ? 0.0 : phrase_of("w-whole-line")->leadIn; // the study stops at bar 16 and needs only enough tail for the last // note to ring — six seconds of nothing was six seconds of watching - N = lround(((minimal ? minimal_bars() : BARS) * BAR + N = lround((PREROLL + (minimal ? minimal_bars() : BARS) * BAR + (minimal ? 2.0 : TAIL_S)) * SR); drumsL = calloc(N, 4); drumsR = calloc(N, 4); musicL = calloc(N, 4); musicR = calloc(N, 4); @@ -630,7 +1181,14 @@ // NO COUNT-IN — the file opens on her pickup. The render starts // at the /s/ of "sitting"; the phrase's beat 0, and the first // kick with it, land one lead-in later, so the downbeat IS the // first word rather than the third bar of waiting. - const ChartPhrase *p = phrase("w-whole-line"); + // WHOSE CHART GOVERNS THE STUDY. Each take now has one of its own + // (bin/takechart.py), and its leadIn is its own measured consonant + // runway — 0.37 beats for s-, 0.84 for sh-. Reading f-'s here + // would put every other take's pickup in the wrong place, which + // is the borrowed-envelope problem the takecharts exist to end. + const char *takeEnv = getenv("TAKE"); + const char *takePhrase = (takeEnv && *takeEnv) ? takeEnv : "w-whole-line"; + const ChartPhrase *p = phrase_of(takePhrase); double lineBars = ceil(p->beats / 4.0); int kickBars = (int)(lineBars + 1); if (kickBars > 16) kickBars = 16; @@ -645,14 +1203,58 @@ // give the subdivision the words are actually being placed on. // no pickup kick — there is no pickup beat any more for (int bar = 0; bar < kickBars; bar++) { double t = off + at(bar); - for (int b = 0; b < 4; b++) kick(t + b * BEAT, 0.95); + for (int b = 0; b < 4; b++) kick(t + b * BEAT, 0.62); for (int b = 0; b < 4; b++) - airhat(t + (b + 0.5) * BEAT, 0.15, (b % 2) ? 0.3 : -0.3); - for (int s = 0; s < 16; s++) - tick(t + s * STEP, (s % 4 == 0) ? 0.10 : 0.05, - (s % 2) ? 0.28 : -0.22); + airhat(t + (b + 0.5) * BEAT, 0.14, (b % 2) ? 0.3 : -0.3, b % 2); + } + // the backing voice, under the words — one held note at a time + backing_line(0, kickBars, off, 0.55); + // …and the bed under THAT — @jeffrey: "and also lets add the synth + // pads / sine accompaniment now!". The full mix's voicing, at study + // level: a low pair on two-bar chords, and the mid triad a beat + // behind it so the chord arrives rather than lands. + for (int bar = 0; bar < kickBars; bar += 2) { + const Chord *c = chord_at(bar); + double lows[3] = { c->root - 24, c->root - 12, c->tones[1] - 12 }; + pad(off + at(bar) + 0.02, lows, 3, 2 * BAR - 0.1, 0.42, 1.1, 0, 0.55, 0, 0.30); + double mids[3] = { c->tones[0], c->tones[1], c->tones[2] }; + pad(off + at(bar) + 0.15, mids, 3, 2 * BAR - 0.3, 0.55, 1.5, 0.18, 0.7, 0.10, 0.36); } - sung("w-whole-line", 0.0, 0.98, 0, 0.0); + // HER MELODY, on the music box — @jeffrey: "lets start working on + // more accompaniment". The pluck plays ONLY charted notes, so the + // band's line IS her line: it doubles under every word and rings + // on through the gaps she leaves. + { + const ChartPhrase *pp = phrase_of("w-whole-line"); + for (int i = 0; i < pp->n; i++) { + const ChartNote *nn = &pp->notes[i]; + // IN OCTAVES — @jeffrey: "i was hoping for notes in the + // octaves · like so we could have the lyrics and melody + // being more closely mapped". Her note, the octave under + // it for weight, and the octave over it for the mapping + // to be unmissable. The low octave leads slightly so the + // top one reads as the melody rather than as a chord. + double t0 = off + nn->beat * BEAT + jit(3); + double d = nn->dur * BEAT; + double pn = (i % 2) ? -0.12 : 0.12; + pluck(t0, nn->st, d, 0.62, pn); + pluck(t0 - 0.006, nn->st - 12, d, 0.30, -pn * 0.5); + pluck(t0 + 0.010, nn->st + 12, d, 0.36, pn * 1.6); + } + } + // and the sub, offbeat, answering each kick + for (int bar = 0; bar < kickBars; bar++) { + const Chord *c = chord_at(bar); + for (int b = 0; b < 4; b++) + bass(off + at(bar) + (b + 0.5) * BEAT, c->root - 24, + 0.30, 0.55, 0.012); + } + // …and TAKE_WAV is what it actually sings, so the study can play a + // level-matched copy of a take while still reading that take's + // own chart. @jeffrey: "see how they sound solo · with mp4 vocal + // tests again?" + const char *wavEnv = getenv("TAKE_WAV"); + sung((wavEnv && *wavEnv) ? wavEnv : takePhrase, 0.0, 0.98, 0, 0.0); goto mixdown; } @@ -661,121 +1263,283 @@ // break gets the slow-attack ballad voicing. for (int bar = 0; bar < BARS - 4; bar++) { const Chord *c = chord_at(bar); double lows[3] = { c->root - 24, c->root - 12, c->tones[1] - 12 }; - int brk = (bar >= 32 && bar < 40), outro = bar >= 60; + int brk = (bar >= L(2) && bar < L(3)), outro = bar >= L(5); if (bar % 2 == 0) { double g = brk ? 0.15 : outro ? 0.13 : 0.16; pad(at(bar) + 0.02, lows, 3, 2 * BAR - 0.1, g, brk ? 2.4 : 1.1, 0, 0.55, 0, 0.30); if (!brk && !outro) { - double mids[3] = { c->tones[0], c->tones[1], c->tones[2] }; - pad(at(bar) + 0.15, mids, 3, 2 * BAR - 0.3, g * 0.68, + double mids[4] = { c->tones[0], c->tones[1], c->tones[2], c->sev }; + pad(at(bar) + 0.15, mids, 4, 2 * BAR - 0.3, g * 0.68, 1.5, 0.18, 0.7, 0.10, 0.36); } } - // THE BASS — offbeat house sub answering every kick + // THE BASS — @jeffrey: "can we make it cooler? more up beat". + // It was four identical offbeat subs a bar, at root−24, which is + // a pad with a rhythm rather than a bassline: nothing in it moves, + // so nothing in it pushes. Now it walks. Root on the offbeats, the + // fifth under beat 3 so the bar turns over, and a 16th PUSH into + // the next downbeat — the note that arrives early is what makes a + // house bar feel like it is falling forward. An octave up on the + // last offbeat of every other bar keeps it from settling. if (kick_on(bar)) { - for (int b = 0; b < 4; b++) - bass(at(bar) + (b + 0.5) * BEAT, c->root - 24, 0.30, 0.9, 0.012); + for (int b = 0; b < 4; b++) { + double st = c->root - 24; + if (b == 2) st = c->tones[2] - 24; // the fifth, mid-bar + if (b == 3 && (bar % 2)) st += 12; // …and a lift out + // swung with the hats: if the bass sat square while the kit + // shuffled they would fight, and the groove would read as + // sloppy rather than as swung + bass(at(bar) + sw(b * 2 + 1) + lean(bar, b + 0.5), st, + 0.30, 0.92 * KV[(bar * 4 + b) % 8], 0.012); + } + // the push: a 16th before the next bar, short and quiet, so the + // downbeat is arrived AT rather than merely landed on + bass(at(bar) + sw(7.5) + lean(bar, 3.75), c->root - 24, + 0.13, 0.62, 0.008); } else { bass(at(bar), c->root - 24, BAR - 0.12, 0.5, 0.045); } } // THE FLOOR + // THE FLOOR NEVER STOPS. @jeffrey: "once the beat / kick starts it + // shouldn't stop it should run through the whole time". The BREAK used + // to take the kick out entirely for sixteen bars — a dance-record + // reflex, and the wrong one here: this is a club cut and the floor is + // the thing you are standing on. So the break still empties, but it + // empties AROUND the kick: no claps, no hats, no ticks, and the kick + // itself pulled back to 0.72 so the room opens without the ground + // disappearing. Everything that made the section an event — the + // harmony thinning, the riser back in — is still there. + // THE VOCAL BREAKS clear the kit for their two bars — no claps, hats + // right down — while the kick keeps running. See vocal_break(). for (int bar = 0; bar < BARS; bar++) { - if (!kick_on(bar)) continue; - double build = bar >= 38 ? 0 : 1; (void)build; - double kg = bar < 12 ? 0.92 : bar < 20 ? 0.98 : bar < 28 ? 0.95 : 1.0; - double hg = bar < 12 ? 0.065 : 0.085; - int claps = bar >= 4; - floor_bar(bar, kg, hg, claps, bar >= 12); + int brk = (bar >= L(2) && bar < L(3)); + int vb = (bar >= L(1) - 2 && bar < L(1)) || (bar >= L(2) - 2 && bar < L(2)) || + (bar >= L(4) - 2 && bar < L(4)) || (bar >= L(5) - 2 && bar < L(5)); + double kg = vb ? 0.82 + : brk ? 0.72 + : bar < L(1) ? 0.88 : bar < L(2) ? 0.95 + : bar < L(5) ? 1.0 : 0.84; + double hg = vb ? 0.03 : brk ? 0.05 : bar < L(1) ? 0.10 : 0.15; + int claps = (bar >= L(1)) && !brk && !vb; + floor_bar(bar, kg, hg, claps); } - // the rebuild rush out of the break - riser(at(38), 2 * BAR, 0.26); - for (int s = 0; s < 8; s++) snare(at(39) + (8 + s) * STEP, 0.18 + 0.04 * s, (s % 2) ? 0.25 : -0.25); + { // the words each break is built from — the scoop, the low held + // note, and the last word of the sentence + static const char *W1[] = { "pa", "stone" }; + static const char *W2[] = { "pa", "stone", "pass" }; + static const char *W3[] = { "pa", "think", "stone", "pass" }; + vocal_break("w-whole-line", L(1) - 2, W1, 2, 0.34); + vocal_break("w-whole-line", L(2) - 2, W2, 3, 0.44); + vocal_break("w-whole-line", L(4) - 2, W3, 4, 0.50); + vocal_break("w-whole-line", L(5) - 2, W2, 3, 0.38); + } + // ── LONERCLUB — SIX PASSES OF ONE SENTENCE, ONE VOICE ───────────── + // @jeffrey: "i want to try and just get a real clean track for now... + // simple perc simple vocals... and lets not have background vocals + // anymore". + // + // So every halo, every backup 3rd and 5th, every "ah"/"oh" arp and + // every ensemble texture shot is gone. What is left is HER LINE, sung + // whole, six times, and a band that never sings. The passes are told + // apart by what the band does — the pluck thickening, the bells + // arriving, the floor thinning — and nothing else. + // + // ONE TAKE THROUGHOUT — @jeffrey: "stick with our original mapped + // take". f- is the one that was charted by hand, word by word, over a + // whole session; the others are warped onto ITS chart by singdub and + // are auditioned separately (bin/tryout-takes.sh) rather than dropped + // into the record. alt_line() is still here and still correct for + // when one of them earns a pass. + // + // L1 0–16 f- alone. Kick and one hat. + // L2 16–32 f- clap on 2 and 4; the bells arrive + // L3 32–48 f- the floor thins to the kick; the pads open + // L4 48–64 f- everything the band has + // L5 64–80 f- widest, bells running every bar + // L6 80–96 f- the ghost. thinning back to the pluck alone. - // ── V1 0–12 — THE UNBROKEN TAKE, first word ON beat 0 of bar 0 ───── - // One 12-bar continuous vocal; the pluck doubles her INSIDE the - // line — no answer gaps, the held vowels are the arrangement. - voice_line("w-whole-line", 0, 0.96, 0.18, 0, 0); - pluck_line("w-whole-line", 0, 0.5, 0, 0.3); - arp(at(4.5), ARP_III, 4, "oh", 5, 1, 0.15, 0.12, 0.35); // inside "stone…" - arp(at(8.5), ARP_VII, 3, "ah", 5, 0, 0.15, 0.12, -0.35); // inside "patiently…" + // THE DOWNBEAT still gets its bell, but it rings UNDER her first word + // now rather than in front of it — the record opens on a note and a + // voice at the same instant. + fembell(at(0), 0, 2.6, 0.26, 0.0); + fembell(at(0) + 0.012, 12, 2.2, 0.14, 0.28); + + // ── THE ROTA ───────────────────────────────────────────────────── + // Who says the hook, pass by pass. Handing one figure between + // instruments is what makes an arrangement read as structured rather + // than merely layered: the same four notes arrive in a different + // voice each time, so the ear tracks a thread instead of a texture. + // The statement lands on bar 1 of the pass; the ANSWER — the same + // figure inverted — lands on bar 5, and again on bar 13, so every + // pass is two four-bar sentences and a repeat. + // + // The turnaround closes each eight-bar row underneath all of it. + { + static const struct { int voice, oct; double gain; } SAYS[6] = { + { VOICE_PLUCK, 0, 0.30 }, // L1 the music box, alone + { VOICE_VIBE, 0, 0.34 }, // L2 the vibraphone takes it + { VOICE_BELL, 0, 0.24 }, // L3 bare section: bells only + { VOICE_VIBE, 12, 0.30 }, // L4 up an octave, the drop + { VOICE_PLUCK, 12, 0.28 }, // L5 widest — pluck and vibe + { VOICE_VIBE, 0, 0.22 }, // L6 the vibraphone, last + }; + for (int pass = 0; pass < 6; pass++) { + double b0 = L(pass); + double g = SAYS[pass].gain; + hook_say(at(b0 + 1), HOOK, SAYS[pass].oct, SAYS[pass].voice, g, 0.32); + hook_say(at(b0 + 5), HOOK_ANS, SAYS[pass].oct, SAYS[pass].voice, g * 0.9, -0.32); + hook_say(at(b0 + 13), HOOK_ANS, SAYS[pass].oct, SAYS[pass].voice, g * 0.8, 0.28); + if (pass == 4) // the widest pass says it in two voices + hook_say(at(b0 + 5) + 0.5 * BEAT, HOOK_ANS, 0, VOICE_VIBE, + g * 0.7, -0.36); + for (int row = 0; row < 2; row++) + turnaround(b0 + row * 8 + 7, pass == 2 ? 0.16 : 0.26); + } + } + + // ── L1 — alone ─────────────────────────────────────────────────── + // @jeffrey: "the vocal coming in should be softer". She was arriving + // at 0.96, the same level she holds for the rest of the record, which + // makes the first word an announcement. It is the softest take in the + // bank and the intro has just spent sixteen bars getting quiet for it; + // 0.62 lets her be heard rather than delivered, and the next pass is + // where she comes up to full. + voice_line("w-whole-line", L(0), 0.62); + pluck_line("w-whole-line", L(0), 0.44, 0, 0.3); + bell_run(at(L(0) + 6), &CH_VI, 3, 0.30, 0.13, 1, 0.35); + bell_run(at(L(0) + 13), &CH_VII, 3, 0.28, 0.12, 0, -0.35); + + // THE VIBRAPHONE answers her held notes. Every unit four beats or + // longer is a place where she stops moving, and the vibe fills it with + // a falling three-note figure off the bar's chord — so the new + // instrument is not another layer running in parallel, it plays in the + // gaps the singer leaves. + { + const ChartPhrase *pp = phrase_of("w-whole-line"); + for (int pass = 1; pass < 6; pass++) { + if (pass == 2) continue; // L3 stays bare + double base = L(pass); + double g = (pass == 1) ? 0.26 : (pass == 5) ? 0.20 : 0.34; + for (int i = 0; i < pp->n; i++) { + const ChartNote *nn = &pp->notes[i]; + if (nn->dur < 4.0) continue; + double t0 = at(base) + (nn->beat + nn->dur * 0.55) * BEAT; + const Chord *c = chord_at((int)(base + nn->beat / 4.0)); + for (int k = 0; k < 3; k++) + vibe(t0 + k * 0.5 * BEAT, c->tones[2 - k] + 12, + 1.2, g * (1.0 - 0.18 * k), (k % 2 ? 0.34 : -0.30)); + } + } + } + + // ── L2 16–32 — the clap, and her melody in octaves ──────────────── + voice_line("w-whole-line", L(1), 0.88); + pluck_line("w-whole-line", L(1), 0.52, 0, 0.3); + pluck_line("w-whole-line", L(1), 0.24, 12, -0.3); + for (int bar = L(1) + 2; bar < L(2); bar += 4) + bell_run(at(bar) + 2.5 * BEAT, chord_at(bar), 4, 0.26, 0.16, + (bar / 4) % 2 == 0, 0.4); + // THE STAB arrives with the clap, still muffled — the filter opens + // pass by pass, so one figure carries the whole build. + for (int bar = L(1) + 4; bar < L(2); bar++) { + const Chord *c = chord_at(bar); + double v[4] = { c->tones[0], c->tones[1], c->tones[2], c->sev }; + stab(at(bar) + sw(3) + lean(bar, 1.5), v, 4, 0.34, 0.26, 0.22, 0.30); + stab(at(bar) + sw(7) + lean(bar, 3.5), v, 4, 0.30, 0.22, 0.22, -0.30); + } - // ── HOOK 12–20 — her held STONE opens it; the stab waits till 14 ─── - { Shot o = shot_defaults(); o.gain = 0.32; o.side = 0.85; o.dly = 0.3; o.rvb = 0.6; - o.attack = 0.5; shot("stone-long-12", at(12), &o); } - pluck_line("w-of-a-stone", 12, 0.55, 0, 0.3); // the melody leads - voice_line("w-of-a-stone", 14, 1.0, 0.24, 0.30, 0); - { Shot o = shot_defaults(); o.gain = 0.5; o.pan = 0.3; o.dly = 0.2; o.rvb = 0.4; - shot("hk-of-a", at(14) - 0.05, &o); } - voice_line("w-of-a-stone", 16, 0.72, 0.18, 0, 0); // the echo stab - voice_line("w-of-a-stone", 18, 1.0, 0.26, 0.32, 1); // crowned, tiles to V2 - pluck_line("w-of-a-stone", 18, 0.6, 12, -0.3); - { Shot o = shot_defaults(); o.gain = 0.26; o.side = 0.9; o.dly = 0.32; o.rvb = 0.65; - o.attack = 0.5; shot("stone-long-5", at(19), &o); } - { Shot o = shot_defaults(); o.gain = 0.20; o.pan = 0.4; o.side = 0.8; o.rvb = 0.5; - o.attack = 0.6; shot("ens-o-2", at(15), &o); } - arp(at(13.5), ARP_I, 5, "oh", 6, 1, 0.13, 0.15, 0.35); - arp(at(15.5), ARP_VI, 4, "ah", 6, 0, 0.13, 0.15, -0.35); - arp(at(17.5), ARP_III, 4, "oh", 6, 1, 0.13, 0.15, 0.35); - arp(at(19.5), ARP_VII, 3, "ah", 7, 0, 0.13, 0.15, -0.35); + // ── L3 32–48 — the floor thins ─────────────────────────────────── + voice_line("w-whole-line", L(2), 0.98); + pluck_line("w-whole-line", L(2), 0.40, 0, 0.3); + for (int bar = L(2) + 1; bar < L(2) + 14; bar += 3) + fembell(at(bar), chord_at(bar)->root, 2.2, 0.22, (bar % 6) ? 0.3 : -0.3); - // ── V2 20–28 — the "not again!" verse at HER pace, seamless ──────── - // (10.5 + 16.5 + 6 beats back-to-back: she sings straight through) - voice_line("w-n-getting-curled", 20, 0.92, 0.20, 0.26, 0); - pluck_line("w-n-getting-curled", 20, 0.5, 0, 0.3); - voice_line("w-n-stone-waiting", 22.625, 0.92, 0.20, 0.26, 0); - pluck_line("w-n-stone-waiting", 22.625, 0.5, 0, -0.3); - voice_line("w-n-for-time-to-pass", 26.5, 0.94, 0.22, 0.28, 1); - pluck_line("w-n-for-time-to-pass", 26.5, 0.55, 0, 0.3); - arp(at(26.5), ARP_IV, 3, "oh", 6, 1, 0.13, 0.14, 0.35); - arp(at(27.2), ARP_VII, 3, "ah", 7, 1, 0.12, 0.16, -0.35); + // ── THE DROP ───────────────────────────────────────────────────── + // @jeffrey: "and more epic drop". Four bars of preparation instead of + // none: the riser runs the whole way, the scratches answer each other + // across the stereo, and in the last bar the tape STOPS — screw_down + // drags "stone" from full speed to a third of it, so the pitch sags + // out from under the room. Then the floor returns at tempo, and a bell + // is struck on the downbeat itself so the drop arrives on a note and + // not only on a kick. + riser(at(L(3) - 4), 4 * BAR, 0.20); + scratch("w-whole-line", "pa", at(L(3) - 4) + 2 * BEAT, 4, 0.34, 0.40); + scratch("w-whole-line", "pass", at(L(3) - 3) + 2 * BEAT, 5, 0.36, -0.40); + scratch("w-whole-line", "pa", at(L(3) - 2) + 1 * BEAT, 6, 0.40, 0.42); + screw_down("w-whole-line", "stone", at(L(3) - 1), 1.5 * BAR, 0.62); + fembell(at(L(3)), 0, 3.4, 0.62, 0); + fembell(at(L(3)) + 0.012, 12, 3.4, 0.34, 0.25); + // the floor already puts a kick on this downbeat; these are the three + // 16ths AFTER it, so the drop stutters in rather than doubling a hit + for (int b = 1; b < 4; b++) + kick(at(L(3)) + b * (BEAT / 4.0), 0.54 - 0.12 * b); + + // ── L4 48–64 — everything the band has ─────────────────────────── + voice_line("w-whole-line", L(3), 0.98); + pluck_line("w-whole-line", L(3), 0.55, 0, 0.3); + pluck_line("w-whole-line", L(3), 0.28, 12, -0.3); + for (int bar = L(3); bar < L(4); bar += 2) + bell_run(at(bar) + 1.0 * BEAT, chord_at(bar), 5, 0.24, 0.20, + (bar / 2) % 2, (bar % 4) ? 0.42 : -0.42); + for (int bar = L(3); bar < L(4); bar++) { + // THE STAB RESTS WHERE THE HOOK SPEAKS. Two ideas on the offbeat + // at once is not counterpoint, it is a pile; the arrangement reads + // as deliberate the moment something stops to let something else + // through. + int said = (bar == L(3) + 1 || bar == L(3) + 5 || bar == L(3) + 13); + if (said) continue; + const Chord *c = chord_at(bar); + double v[4] = { c->tones[0], c->tones[1], c->tones[2], c->sev }; + stab(at(bar) + sw(3) + lean(bar, 1.5), v, 4, 0.36, 0.34, 0.58, 0.32); + stab(at(bar) + sw(7) + lean(bar, 3.5), v, 4, 0.32, 0.30, 0.58, -0.32); + if (bar % 4 == 3) + stab(at(bar) + sw(5.5) + lean(bar, 2.75), v, 4, 0.18, 0.24, 0.72, 0.0); + } + // PA — announced, then answered. @jeffrey: "can 'patiently' especially + // 'pa' be cooler". The stutter runs three 16ths into it so the scoop is + // heard coming; the throw is the same word an octave later, off the + // beat, gone into the delay. + word_stutter("w-whole-line", "pa", L(3), 0.40, 0.34); + word_throw("w-whole-line", "pa", L(3), 0.52, 0.75 * BEAT, -0.36); - // ── BREAK 28–40 — the whole take again, naked over pads ──────────── - voice_line("w-whole-line", 28, 1.0, 0.15, 0, 0); - { Shot o = shot_defaults(); o.gain = 0.22; o.side = 0.9; o.dly = 0.3; o.rvb = 0.7; - o.attack = 0.8; shot("stone-long-echo", at(33), &o); } - dust(at(30) + 1.1, 0.013); dust(at(35) + 2.3, 0.015); - arp(at(36.5), ARP_I, 5, "oh", 4, 1, 0.28, 0.09, 0.3); + // …and the door the last pass comes through + riser(at(L(4) - 3), 3 * BAR, 0.17); + scratch("w-whole-line", "think", at(L(4) - 2) + 2 * BEAT, 5, 0.32, -0.38); + screw_down("w-whole-line", "pa", at(L(4) - 1) + 2 * BEAT, 0.9 * BAR, 0.52); + fembell(at(L(4)), -4, 3.2, 0.46, -0.2); - // ── DROP 40–58 — the unbroken take with everything she has ───────── - voice_line("w-whole-line", 40, 0.98, 0.24, 0.32, 1); - pluck_line("w-whole-line", 40, 0.55, 0, 0.3); - { Shot o = shot_defaults(); o.gain = 0.5; o.pan = -0.3; o.dly = 0.2; o.rvb = 0.4; - shot("hk-of-a", at(43.25) - 0.05, &o); } // under "of a" - { Shot o = shot_defaults(); o.gain = 0.24; o.side = 0.85; o.dly = 0.3; o.rvb = 0.6; - o.attack = 0.5; shot("pass-long-15", at(49.6), &o); } - voice_line("w-of-a-stone", 52, 1.0, 0.26, 0.34, 1); - pluck_line("w-of-a-stone", 52, 0.6, 12, 0.35); - { Shot o = shot_defaults(); o.gain = 0.30; o.side = 0.9; o.dly = 0.34; o.rvb = 0.7; - o.attack = 0.5; shot("stone-long-17", at(53), &o); } - { Shot o = shot_defaults(); o.gain = 0.22; o.pan = -0.4; o.side = 0.85; o.rvb = 0.55; - o.attack = 0.7; shot("ens-du-2", at(53), &o); } - voice_line("w-of-a-stone", 54, 0.78, 0.20, 0, 0); - voice_line("w-for-time-to-pass", 56, 0.92, 0.22, 0.28, 0); // flows into the OUT - for (int bar = 40; bar < 58; bar += 2) { - const int *tones = (bar % 8 < 2) ? ARP_I : (bar % 8 < 4) ? ARP_VI : - (bar % 8 < 6) ? ARP_III : ARP_VII; - int nt = (tones == ARP_III) ? 4 : (tones == ARP_VII) ? 3 : - (tones == ARP_I) ? 5 : 4; - arp(at(bar) + 0.5 * BAR, tones, nt, (bar % 4) ? "ah" : "oh", - 7, (bar / 2) % 2 == 0, 0.12, 0.16, 0.35); + // ── L5 64–80 — widest ──────────────────────────────────────────── + voice_line("w-whole-line", L(4), 0.98); + pluck_line("w-whole-line", L(4), 0.52, 0, 0.3); + pluck_line("w-whole-line", L(4), 0.30, 12, -0.3); + pluck_line("w-whole-line", L(4), 0.18, -12, 0.15); + for (int bar = L(4); bar < L(5); bar += 2) + bell_run(at(bar) + 1.0 * BEAT, chord_at(bar), 5, 0.22, 0.22, + (bar / 2) % 2, (bar % 4) ? 0.44 : -0.44); + for (int bar = L(4); bar < L(5); bar++) { + int said = (bar == L(4) + 1 || bar == L(4) + 5 || bar == L(4) + 13); + if (said) continue; + const Chord *c = chord_at(bar); + double v[4] = { c->tones[0], c->tones[1], c->tones[2], c->sev }; + stab(at(bar) + sw(3) + lean(bar, 1.5), v, 4, 0.36, 0.36, 0.86, 0.34); + stab(at(bar) + sw(7) + lean(bar, 3.5), v, 4, 0.32, 0.32, 0.86, -0.34); + if (bar % 2 == 1) + stab(at(bar) + sw(5.5) + lean(bar, 2.75), v, 4, 0.18, 0.26, 0.95, 0.0); } + word_stutter("w-whole-line", "pa", L(4), 0.46, 0.36); + word_throw("w-whole-line", "pa", L(4), 0.58, 0.75 * BEAT, 0.38); + word_throw("w-whole-line", "pa", L(4), 0.30, 2.25 * BEAT, -0.42); - // ── OUT 58–76 — the ghost: the whole take once more, far away, - // under the pluck singing the same line ──────────────────────────── - voice_line("w-whole-line", 58, 0.55, 0.16, 0, 0); - pluck_line("w-whole-line", 58, 0.5, 0, 0.3); - pluck_line("w-for-time-to-pass", 70, 0.36, 12, 0.35); - { Shot o = shot_defaults(); o.gain = 0.18; o.side = 0.9; o.dly = 0.3; o.rvb = 0.75; - o.attack = 0.8; shot("pass-long-3", at(72), &o); } - { Shot o = shot_defaults(); o.gain = 0.14; o.pan = 0.3; o.side = 0.8; o.rvb = 0.6; - o.attack = 0.9; shot("ens-o-3", at(70), &o); } - arp(at(73), ARP_I, 5, "oh", 4, 0, 0.28, 0.09, 0.3); - arp(at(74.5), ARP_I, 5, "ah", 3, 0, 0.30, 0.07, -0.3); - dust(at(59) + 0.4, 0.012); dust(at(69) + 2.1, 0.014); dust(at(74) + 1.2, 0.013); - hiss_bed(); + // ── L6 80–96 — the ghost. she is the last one left ─────────────── + voice_line("w-whole-line", L(5), 0.72); + pluck_line("w-whole-line", L(5), 0.50, 0, 0.3); + pluck_line("w-whole-line", L(5), 0.20, 12, -0.3); + bell_run(at(L(5) + 2), &CH_i, 4, 0.30, 0.16, 0, 0.35); + bell_run(at(L(5) + 6), &CH_VI, 3, 0.32, 0.12, 0, -0.35); + fembell(at(L(5) + 10), 0, 3.0, 0.12, 0.2); mixdown: if (missingN) fprintf(stderr, " ! %d missing samples\n", missingN); @@ -858,8 +1622,88 @@ // "side chained into the lyrics": every kick ducks the vox 0.34 and // the bed 0.52; drums never duck. // harsher sidechain — deeper on both buses and a faster grab, so // the pump is something you feel rather than infer - float *envBed = duck_env(0.68, 0.008, 0.26); - float *envVox = duck_env(0.52, 0.008, 0.22); + // The STUDY's kick lands on all four, so the dance mix's 0.68 duck + // holds the bed down almost continuously and the pads never surface + // — @jeffrey: "also the pads arent sounding". A monitor wants to hear + // what it is judging; the dance depth stays on the real cut. + // @jeffrey: "and side chainnig!" — it was already here, doing its job + // quietly. The point of asking for it out loud is that you want to + // HEAR it, and what makes a pump audible is not depth, it is the + // RELEASE: a duck that recovers in 260 ms is most of the way back + // before the next kick and reads as a level change. Shortening it to + // 190 ms and grabbing faster makes the bed breathe in and out between + // every beat, which is the sound. Depth up a little too, but the + // release is what you notice. + float *envBed = duck_env(minimal ? 0.28 : 0.76, 0.005, 0.19); + // …and the duck on the voice comes back to the 0.34 the comment above + // always claimed. 0.52 is six dB of movement on the lead four times a + // bar, which reads as pumping rather than as a floor once the 16ths + // are gone and there is nothing else covering it. + float *envVox = duck_env(0.38, 0.006, 0.20); + // SOLO=music (or drums / vox, comma-separated) mutes the rest — + // @jeffrey: "im not hearing those instruments · are they toggled + // off?". A bus you cannot solo can only be argued about; this makes + // the question answerable in one render. + const char *soloEnv = getenv("SOLO"); + double gD = 1, gM = 1, gV = 1; + if (soloEnv && *soloEnv) { + gD = strstr(soloEnv, "drums") ? 1 : 0; + gM = strstr(soloEnv, "music") ? 1 : 0; + gV = strstr(soloEnv, "vox") ? 1 : 0; + printf(" SOLO=%s — drums %.0f · music %.0f · vox %.0f\n", soloEnv, gD, gM, gV); + } + // ── THE VOCAL CHAIN — @jeffrey: "we need to master / treat each + // vocal separate right?". Right. Until now the vox bus got a static + // gain and a sidechain duck and nothing else, and her line swings 23 + // dB across one sentence — "sitting" peaks at −6, "waiting" sits at + // −29. A single fader cannot serve both: set it for the loud words + // and the quiet ones fall under the floor; set it for the quiet ones + // and she shouts. So the lead gets its own compressor, linked across + // the pair so the image does not wander, ahead of the mix and ahead + // of the master. + { + const double th = 0.10; // ≈ −20 dBFS on this bus + const double ratio = 3.0, mk = 2.1; + const double aA = 1 - exp(-1.0 / (0.012 * SR)); // 12 ms + const double aR = 1 - exp(-1.0 / (0.140 * SR)); // 140 ms + // …and a scoop where PROXIMITY lives. A voice close to a mic is + // thick between about 150 and 800 Hz; taking some of that out is + // what makes it read as further away, and unlike a lowpass it + // leaves the sibilant restore alone — the /s/ that took all day to + // find stays exactly as loud as it was. + const double kLo = 1 - exp((-TAU * 150.0) / SR); + const double kHi = 1 - exp((-TAU * 800.0) / SR); + // …further back again — @jeffrey, twice now: "i think the voice + // should be deeper in the [m]ix". Each of the three levers moves + // together, because only moving the fader makes a quiet close + // voice rather than a distant one: 1.02 → 0.82 direct, 0.46 → 0.58 + // room, and the proximity scoop from a third to nearly half. + const double chest = 0.44; + double lo[2] = {0, 0}, hi[2] = {0, 0}; + double env = 0, gr = 1, worst = 1; + for (long i = 0; i < N; i++) { + double d = fmax(fabs((double)voxL[i]), fabs((double)voxR[i])); + env += (d > env ? aA : aR) * (d - env); + double want = env > th ? (th + (env - th) / ratio) / env : 1.0; + gr += (want < gr ? aA : aR) * (want - gr); + if (gr < worst) worst = gr; + double l = voxL[i] * gr * mk, r = voxR[i] * gr * mk; + lo[0] += kLo * (l - lo[0]); hi[0] += kHi * (l - hi[0]); + lo[1] += kLo * (r - lo[1]); hi[1] += kHi * (r - hi[1]); + voxL[i] = (float)(l - chest * (hi[0] - lo[0])); + voxR[i] = (float)(r - chest * (hi[1] - lo[1])); + } + printf(" vox comp — max %.1f dB down\n", 20 * log10(worst)); + } + { // bus peaks, so a silent bus is visible rather than argued about + double pd = 0, pm = 0, pv = 0; + for (long i = 0; i < N; i++) { + pd = fmax(pd, fabs((double)drumsL[i])); + pm = fmax(pm, fabs((double)musicL[i])); + pv = fmax(pv, fabs((double)voxL[i])); + } + printf(" bus peaks — drums %.3f · music %.3f · vox %.3f\n", pd, pm, pv); + } float *L = calloc(N, 4), *R = calloc(N, 4); // band-limited antisymmetric side (one-pole at 6 kHz) double kSide = 1 - exp((-TAU * 6000) / SR); @@ -868,8 +1712,8 @@ for (long i = 0; i < N; i++) { sV += kSide * (sideV[i] - sV); sB += kSide * (sideB[i] - sB); double bed = envBed[i], vx = envVox[i] * VOXG; - double l = drumsL[i] + (musicL[i] + sB) * bed + (voxL[i] + sV) * vx; - double r = drumsR[i] + (musicR[i] - sB) * bed + (voxR[i] - sV) * vx; + double l = drumsL[i] * gD + (musicL[i] + sB) * bed * gM + (voxL[i] + sV) * vx * gV; + double r = drumsR[i] * gD + (musicR[i] - sB) * bed * gM + (voxR[i] - sV) * vx * gV; L[i] = (float)l; R[i] = (float)r; } double peak = 0; diff --git a/pop/loner/covers/club-floor.illy.txt b/pop/loner/covers/club-floor.illy.txt new file mode 100644 --- /dev/null +++ b/pop/loner/covers/club-floor.illy.txt @@ -0,0 +1,31 @@ +a photograph of a colored-pencil and gouache drawing on deep indigo paper. +square, 1:1. seen from directly overhead, straight down, flat plan view. + +a dancefloor with thirty people on it, and every one of them is alone. + +each person is the same figure from the reference score, drawn here as one +continuous white chalk line on the dark floor: sitting curled up, knees to the +chest, arms wrapped round the shins, head down on the knees, long thin lines +trailing past the feet. wobbling, un-erased, one unbroken stroke each, overlaps +visible. they are laid out on the score's own grid — six rows of five, evenly +spaced, none of them touching, none of them turned toward another. + +light is diegetic and comes from the floor: one small coloured lamp set into +the boards beside each figure — magenta, cyan, chartreuse, amber, violet, +mixed through the grid — each throwing a pool that reaches to the edge of its +own person and stops. thirty little islands of light. the floor between them +stays dark indigo, and the chalk lines outside a pool read only as faint grey. +the boards are visible in the pools: plain worn wood, no pattern, no logo. + +chalked on the floor beside six of the figures — one word each, small, +lowercase, in the same hand as the drawing: + + sitting · assise · sentada · sidder · сижу · बैठी + +six languages, one posture, nobody talking to anybody. that is the club. + +NO motion blur, NO soft-focus haze, NO lens flare, NO overlay glow — the light +is drawn, and the chalk stays crisp. NO title lettering, NO artist name, NO +band or label logo, NO barcode, NO url, NO @handle, NO brand signage, NO +flags, NO emblems, NO dj booth, NO speakers, NO disco ball. those six words +are the only text in the picture. diff --git a/pop/loner/covers/lonerclub-cover-a-score-international.png b/pop/loner/covers/lonerclub-cover-a-score-international.png new file mode 100644 --- /dev/null +++ b/pop/loner/covers/lonerclub-cover-a-score-international.png diff --git a/pop/loner/covers/lonerclub-cover-a-score-international.png.illy.json b/pop/loner/covers/lonerclub-cover-a-score-international.png.illy.json new file mode 100644 --- /dev/null +++ b/pop/loner/covers/lonerclub-cover-a-score-international.png.illy.json @@ -0,0 +1,44 @@ +{ + "schema": "illy/v1", + "createdAt": "2026-08-19T16:18:42.896Z", + "pipeline": "pop-cover", + "provider": "openai", + "model": "gpt-image-2", + "mode": "edit", + "size": "1024x1024", + "quality": "high", + "output": "/Users/jas/aesthetic-computer/pop/loner/covers/lonerclub-cover-a-score-international.png", + "promptPath": "/Users/jas/aesthetic-computer/pop/loner/covers/score-international.illy.txt", + "promptHash": "b0cf687caa36be591ba1a032ca135d18fcaf1dbc459f6cff0174211d6dd5b747", + "references": [ + "/Users/jas/aesthetic-computer/pop/loner/covers/refs/loner-score-small.png", + "/Users/jas/aesthetic-computer/pop/loner/covers/refs/loner-curl-row.png" + ], + "contracts": [ + "physical-accuracy" + ], + "stages": [ + "resolve-inputs", + "apply-contracts", + "select-provider", + "generate", + "archive", + "provenance" + ], + "durationSeconds": 138.86, + "archived": null, + "requestId": null, + "usage": { + "input_tokens": 2824, + "input_tokens_details": { + "image_tokens": 2156, + "text_tokens": 668 + }, + "output_tokens": 7024, + "output_tokens_details": { + "image_tokens": 7024, + "text_tokens": 0 + }, + "total_tokens": 9848 + } +} diff --git a/pop/loner/covers/lonerclub-cover-b-stone.png b/pop/loner/covers/lonerclub-cover-b-stone.png new file mode 100644 --- /dev/null +++ b/pop/loner/covers/lonerclub-cover-b-stone.png diff --git a/pop/loner/covers/lonerclub-cover-b-stone.png.illy.json b/pop/loner/covers/lonerclub-cover-b-stone.png.illy.json new file mode 100644 --- /dev/null +++ b/pop/loner/covers/lonerclub-cover-b-stone.png.illy.json @@ -0,0 +1,43 @@ +{ + "schema": "illy/v1", + "createdAt": "2026-08-19T16:20:54.630Z", + "pipeline": "pop-cover", + "provider": "openai", + "model": "gpt-image-2", + "mode": "edit", + "size": "1024x1024", + "quality": "high", + "output": "/Users/jas/aesthetic-computer/pop/loner/covers/lonerclub-cover-b-stone.png", + "promptPath": "/Users/jas/aesthetic-computer/pop/loner/covers/stone.illy.txt", + "promptHash": "6518f5a93c9032240f38d4483b6656b5b25e575b6c6ae996c09e64bc6bb95f95", + "references": [ + "/Users/jas/aesthetic-computer/pop/loner/covers/refs/loner-curl-row.png" + ], + "contracts": [ + "physical-accuracy" + ], + "stages": [ + "resolve-inputs", + "apply-contracts", + "select-provider", + "generate", + "archive", + "provenance" + ], + "durationSeconds": 129.524, + "archived": null, + "requestId": null, + "usage": { + "input_tokens": 1297, + "input_tokens_details": { + "image_tokens": 660, + "text_tokens": 637 + }, + "output_tokens": 7024, + "output_tokens_details": { + "image_tokens": 7024, + "text_tokens": 0 + }, + "total_tokens": 8321 + } +} diff --git a/pop/loner/covers/lonerclub-cover-c-club-floor.png b/pop/loner/covers/lonerclub-cover-c-club-floor.png new file mode 100644 --- /dev/null +++ b/pop/loner/covers/lonerclub-cover-c-club-floor.png diff --git a/pop/loner/covers/lonerclub-cover-c-club-floor.png.illy.json b/pop/loner/covers/lonerclub-cover-c-club-floor.png.illy.json new file mode 100644 --- /dev/null +++ b/pop/loner/covers/lonerclub-cover-c-club-floor.png.illy.json @@ -0,0 +1,44 @@ +{ + "schema": "illy/v1", + "createdAt": "2026-08-19T16:28:06.947Z", + "pipeline": "pop-cover", + "provider": "openai", + "model": "gpt-image-2", + "mode": "edit", + "size": "1024x1024", + "quality": "high", + "output": "/Users/jas/aesthetic-computer/pop/loner/covers/lonerclub-cover-c-club-floor.png", + "promptPath": "/Users/jas/aesthetic-computer/pop/loner/covers/club-floor.illy.txt", + "promptHash": "59e9cc2d66cb07f0e1cdfbeaa5da8e321e99a1a24260a3b1c7d5bf0b6f1bb6e8", + "references": [ + "/Users/jas/aesthetic-computer/pop/loner/covers/refs/loner-curl-row.png", + "/Users/jas/aesthetic-computer/pop/loner/covers/refs/loner-score-small.png" + ], + "contracts": [ + "physical-accuracy" + ], + "stages": [ + "resolve-inputs", + "apply-contracts", + "select-provider", + "generate", + "archive", + "provenance" + ], + "durationSeconds": 162.591, + "archived": null, + "requestId": null, + "usage": { + "input_tokens": 2816, + "input_tokens_details": { + "image_tokens": 2156, + "text_tokens": 660 + }, + "output_tokens": 7024, + "output_tokens_details": { + "image_tokens": 7024, + "text_tokens": 0 + }, + "total_tokens": 9840 + } +} diff --git a/pop/loner/covers/refs/loner-curl-row.png b/pop/loner/covers/refs/loner-curl-row.png new file mode 100644 --- /dev/null +++ b/pop/loner/covers/refs/loner-curl-row.png diff --git a/pop/loner/covers/refs/loner-score-small.png b/pop/loner/covers/refs/loner-score-small.png new file mode 100644 --- /dev/null +++ b/pop/loner/covers/refs/loner-score-small.png diff --git a/pop/loner/covers/refs/loner-score.png b/pop/loner/covers/refs/loner-score.png new file mode 100644 --- /dev/null +++ b/pop/loner/covers/refs/loner-score.png diff --git a/pop/loner/covers/score-international.illy.txt b/pop/loner/covers/score-international.illy.txt new file mode 100644 --- /dev/null +++ b/pop/loner/covers/score-international.illy.txt @@ -0,0 +1,36 @@ +a photograph of a hand-drawn graphic score on white paper. square, 1:1. + +the reference image is the score this is made from — copy its line exactly. +one figure, drawn in ONE continuous grey marker stroke, curling from standing +to a ball: upright, then a bend at the waist, then the knees rise, then the +arms wrap the shins, then the head goes down onto the knees and long thin +lines trail past the feet. wobbling, un-erased, mid-grey, every overlap left +visible. no shading, no fill, no outline weight changes — just the one line. + +six rows. five figures per row. the same curl runs left to right in every row, +so the whole page is one person sitting down thirty times. even spacing, +generous white margin on all four sides, no border, no frame, no box. + +what changes row to row is the handwriting underneath. under each row, ONE +word, small, lowercase, hand-lettered in soft pencil in the same hand as the +drawing: + + row 1 — sitting + row 2 — assise + row 3 — sentada + row 4 — sidder + row 5 — сижу + row 6 — बैठी + +one word per row, centred under the row, nothing else. the drawing is the +language everybody already reads — the words are just the annotation. + +the remix lives in the colour. five of the thirty figures are drawn in +saturated marker instead of grey — magenta, cyan, chartreuse, orange, violet — +one per row, stepping diagonally down the page from top-left to bottom-right, +so a pulse walks through the sentence. every other figure stays grey. + +NO title lettering, NO artist name, NO band or label logo, NO barcode, NO url, +NO @handle, NO brand signage, NO flags, NO country names, NO emblems. the six +words above are the only text in the picture. the drawing dissolves to plain +white paper at the edges. diff --git a/pop/loner/covers/stone.illy.txt b/pop/loner/covers/stone.illy.txt new file mode 100644 --- /dev/null +++ b/pop/loner/covers/stone.illy.txt @@ -0,0 +1,32 @@ +a photograph of a colored-pencil and gouache drawing on pure white paper. +square, 1:1. + +one stone. grey, palm-sized, ordinary — the kind you pick up and keep for no +reason. it sits alone in the middle of the page with one soft hatched shadow +under it. built from confident hatching and striping, tapered pencil edges, +visible paper grain, tertiary greys made by overlaying strokes rather than +blending. no floor, no horizon, no room — the stone floats on the white with a +generous margin on all four sides. + +drawn ON the stone, following the curve of the rock like a petroglyph: a person +sitting curled up — knees to the chest, arms round the shins, head down, long +thin lines trailing past the feet — in ONE continuous grey marker stroke, +wobbling and un-erased, exactly the hand in the reference score. the line lies +on the surface and bends where the surface bends, dimming slightly where the +stone turns away from the light. it is not floating in front of the stone. + +around the base, following the stone's silhouette like a tide line, one word +written six times in small pencil handwriting, one per script, evenly spaced, +lowercase where the script has a lowercase: + + stone · pierre · piedra · sten · камень · पत्थर + +the same thing, named six ways, waiting. + +light is one soft daylight source from the upper left. NO glow overlay, NO +motion blur, NO soft-focus haze — the pencil is crisp from front to back. + +NO title lettering, NO artist name, NO band or label logo, NO barcode, NO url, +NO @handle, NO brand signage, NO flags, NO emblems. those six words are the +only text in the picture. the drawing dissolves to plain white paper at the +edges — no border, no frame. diff --git a/pop/loner/samples/.align.json b/pop/loner/samples/.align.json --- a/pop/loner/samples/.align.json +++ b/pop/loner/samples/.align.json @@ -5,127 +5,127 @@ "text": "sitting curled up in myself i think of a stone, just waiting very patiently for time to pass", "words": [ { "t": "sitting", - "start": 0.0, - "end": 1.4, + "start": 0.22, + "end": 1.62, "f0_hz": 348.8, "note": "F4" }, { "t": "curled", - "start": 1.4, - "end": 2.44, + "start": 1.62, + "end": 2.66, "f0_hz": 278.2, "note": "C#4" }, { "t": "up", - "start": 2.44, - "end": 3.14, + "start": 2.66, + "end": 3.36, "f0_hz": 265.3, "note": "C4" }, { "t": "in", - "start": 3.14, - "end": 3.94, + "start": 3.36, + "end": 4.16, "f0_hz": 237.3, "note": "A#3" }, { "t": "myself", - "start": 3.94, - "end": 5.32, + "start": 4.16, + "end": 5.54, "f0_hz": 309.4, "note": "D#4" }, { "t": "i", - "start": 5.32, - "end": 6.26, + "start": 5.54, + "end": 6.48, "f0_hz": 211.0, "note": "G#3" }, { "t": "think", - "start": 6.26, - "end": 6.86, + "start": 6.48, + "end": 7.08, "f0_hz": 175.6, "note": "F3" }, { "t": "of", - "start": 6.86, - "end": 8.8, + "start": 7.08, + "end": 9.02, "f0_hz": 470.6, "note": "A#4" }, { "t": "a", - "start": 8.8, - "end": 9.6, + "start": 9.02, + "end": 9.82, "f0_hz": 429.4, "note": "G#4" }, { "t": "stone", - "start": 9.6, - "end": 10.48, + "start": 9.82, + "end": 10.7, "f0_hz": 317.4, "note": "D#4" }, { "t": "just", - "start": 11.115, - "end": 12.38, + "start": 11.335, + "end": 12.6, "f0_hz": 268.1, "note": "C4" }, { "t": "waiting", - "start": 12.38, - "end": 14.04, + "start": 12.6, + "end": 14.26, "f0_hz": 279.9, "note": "C#4" }, { "t": "very", - "start": 14.04, - "end": 15.96, + "start": 14.26, + "end": 16.18, "f0_hz": 237.3, "note": "A#3" }, { "t": "patiently", - "start": 15.96, - "end": 17.26, + "start": 16.18, + "end": 17.48, "f0_hz": 357.2, "note": "F4" }, { "t": "for", - "start": 17.26, - "end": 19.16, + "start": 17.48, + "end": 19.38, "f0_hz": 283.8, "note": "C#4" }, { "t": "time", - "start": 19.16, - "end": 20.5, + "start": 19.38, + "end": 20.72, "f0_hz": 357.5, "note": "F4" }, { "t": "to", - "start": 20.5, - "end": 22.64, + "start": 20.72, + "end": 22.86, "f0_hz": 282.4, "note": "C#4" }, { "t": "pass", - "start": 22.64, - "end": 24.2, + "start": 22.86, + "end": 24.42, "f0_hz": 282.0, "note": "C#4" } diff --git a/pop/loner/samples/.manifest.json b/pop/loner/samples/.manifest.json --- a/pop/loner/samples/.manifest.json +++ b/pop/loner/samples/.manifest.json @@ -19,35 +19,35 @@ "t": "cur", "start": 1.74, "end": 2.48, "f0_hz": 278, - "note": "C♯4" + "note": "C\u266f4" }, { "t": "led", "start": 2.48, "end": 3.47, "f0_hz": 271.6, - "note": "C♯4" + "note": "C\u266f4" }, { "t": "up", "start": 3.47, "end": 3.72, "f0_hz": 236.5, - "note": "A♯3" + "note": "A\u266f3" }, { "t": "in", "start": 3.72, "end": 4.22, "f0_hz": 237.8, - "note": "A♯3" + "note": "A\u266f3" }, { "t": "myself", "start": 4.22, "end": 5.76, "f0_hz": 317.5, - "note": "D♯4" + "note": "D\u266f4" } ] }, @@ -64,14 +64,14 @@ "t": "I", "start": 5.76, "end": 5.96, "f0_hz": 209.5, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "think", "start": 5.96, "end": 7.46, "f0_hz": 210.7, - "note": "G♯3" + "note": "G\u266f3" } ] }, @@ -88,14 +88,14 @@ "t": "of", "start": 7.46, "end": 8.06, "f0_hz": 470.2, - "note": "A♯4" + "note": "A\u266f4" }, { "t": "a", "start": 8.06, "end": 8.59, "f0_hz": 472.9, - "note": "A♯4" + "note": "A\u266f4" }, { "t": "stone", @@ -119,28 +119,28 @@ "t": "I", "start": 5.76, "end": 5.96, "f0_hz": 209.5, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "think", "start": 5.96, "end": 7.46, "f0_hz": 210.7, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "of", "start": 7.46, "end": 8.06, "f0_hz": 470.2, - "note": "A♯4" + "note": "A\u266f4" }, { "t": "a", "start": 8.06, "end": 8.59, "f0_hz": 472.9, - "note": "A♯4" + "note": "A\u266f4" }, { "t": "stone", @@ -188,21 +188,21 @@ "t": "waiting", "start": 13.01, "end": 14.71, "f0_hz": 279.6, - "note": "C♯4" + "note": "C\u266f4" }, { "t": "very", "start": 14.71, "end": 16.29, "f0_hz": 236.5, - "note": "A♯3" + "note": "A\u266f3" }, { "t": "patiently", "start": 16.29, "end": 18.82, "f0_hz": 317.5, - "note": "D♯4" + "note": "D\u266f4" } ] }, @@ -226,7 +226,7 @@ "t": "waiting", "start": 13.01, "end": 14.71, "f0_hz": 279.6, - "note": "C♯4" + "note": "C\u266f4" } ] }, @@ -243,14 +243,14 @@ "t": "very", "start": 14.71, "end": 16.29, "f0_hz": 236.5, - "note": "A♯3" + "note": "A\u266f3" }, { "t": "patiently", "start": 16.29, "end": 18.82, "f0_hz": 317.5, - "note": "D♯4" + "note": "D\u266f4" } ] }, @@ -267,7 +267,7 @@ "t": "for", "start": 18.82, "end": 19.78, "f0_hz": 319.3, - "note": "D♯4" + "note": "D\u266f4" }, { "t": "time", @@ -281,14 +281,14 @@ "t": "to", "start": 21.4, "end": 23.12, "f0_hz": 282.8, - "note": "C♯4" + "note": "C\u266f4" }, { "t": "pass", "start": 23.12, "end": 24.99, "f0_hz": 282.8, - "note": "C♯4" + "note": "C\u266f4" } ] }, @@ -305,150 +305,150 @@ "t": "pass", "start": 23.12, "end": 24.99, "f0_hz": 282.8, - "note": "C♯4" + "note": "C\u266f4" } ] }, "f-whole-line": { "source": "7108062006980201771", - "start": 0.28, + "start": 0.06, "end": 25.45, "words": "the whole lyric, one take", - "dur": 24.307, + "dur": 24.527, "median_f0_hz": 282.8, "word_f0": [ { "t": "Sitting", - "start": 0.33, - "end": 1.74, + "start": 0.55, + "end": 1.96, "f0_hz": 348.2, "note": "F4" }, { "t": "cur", - "start": 1.74, - "end": 2.48, + "start": 1.96, + "end": 2.7, "f0_hz": 278, - "note": "C♯4" + "note": "C\u266f4" }, { "t": "led", - "start": 2.48, - "end": 3.47, + "start": 2.7, + "end": 3.69, "f0_hz": 271.6, - "note": "C♯4" + "note": "C\u266f4" }, { "t": "up", - "start": 3.47, - "end": 3.72, + "start": 3.69, + "end": 3.94, "f0_hz": 236.5, - "note": "A♯3" + "note": "A\u266f3" }, { "t": "in", - "start": 3.72, - "end": 4.22, + "start": 3.94, + "end": 4.44, "f0_hz": 237.8, - "note": "A♯3" + "note": "A\u266f3" }, { "t": "myself", - "start": 4.22, - "end": 5.76, + "start": 4.44, + "end": 5.98, "f0_hz": 317.5, - "note": "D♯4" + "note": "D\u266f4" }, { "t": "I", - "start": 5.76, - "end": 5.96, + "start": 5.98, + "end": 6.18, "f0_hz": 209.5, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "think", - "start": 5.96, - "end": 7.46, + "start": 6.18, + "end": 7.68, "f0_hz": 210.7, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "of", - "start": 7.46, - "end": 8.06, + "start": 7.68, + "end": 8.28, "f0_hz": 470.2, - "note": "A♯4" + "note": "A\u266f4" }, { "t": "a", - "start": 8.06, - "end": 8.59, + "start": 8.28, + "end": 8.81, "f0_hz": 472.9, - "note": "A♯4" + "note": "A\u266f4" }, { "t": "stone", - "start": 8.59, - "end": 11.29, + "start": 8.81, + "end": 11.51, "f0_hz": 325.8, "note": "E4" }, { "t": "just", - "start": 11.42, - "end": 13.01, + "start": 11.64, + "end": 13.23, "f0_hz": 268.5, "note": "C4" }, { "t": "waiting", - "start": 13.01, - "end": 14.71, + "start": 13.23, + "end": 14.93, "f0_hz": 279.6, - "note": "C♯4" + "note": "C\u266f4" }, { "t": "very", - "start": 14.71, - "end": 16.29, + "start": 14.93, + "end": 16.51, "f0_hz": 236.5, - "note": "A♯3" + "note": "A\u266f3" }, { "t": "patiently", - "start": 16.29, - "end": 18.82, + "start": 16.51, + "end": 19.04, "f0_hz": 317.5, - "note": "D♯4" + "note": "D\u266f4" }, { "t": "for", - "start": 18.82, - "end": 19.78, + "start": 19.04, + "end": 20.0, "f0_hz": 319.3, - "note": "D♯4" + "note": "D\u266f4" }, { "t": "time", - "start": 19.78, - "end": 21.4, + "start": 20.0, + "end": 21.62, "f0_hz": 358.4, "note": "F4" }, { "t": "to", - "start": 21.4, - "end": 23.12, + "start": 21.62, + "end": 23.34, "f0_hz": 282.8, - "note": "C♯4" + "note": "C\u266f4" }, { "t": "pass", - "start": 23.12, - "end": 24.99, + "start": 23.34, + "end": 25.21, "f0_hz": 282.8, - "note": "C♯4" + "note": "C\u266f4" } ] }, @@ -465,14 +465,14 @@ "t": "are", "start": 0.51, "end": 0.68, "f0_hz": 206.5, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "doing", "start": 0.85, "end": 1.14, "f0_hz": 303.1, - "note": "D♯4" + "note": "D\u266f4" }, { "t": "whistle", @@ -493,7 +493,7 @@ "t": "again", "start": 2.07, "end": 2.36, "f0_hz": 156.9, - "note": "D♯3" + "note": "D\u266f3" } ] }, @@ -510,7 +510,7 @@ "t": "Getting", "start": 3.14, "end": 4.4, "f0_hz": 308.4, - "note": "D♯4" + "note": "D\u266f4" }, { "t": "cur", @@ -524,21 +524,21 @@ "t": "led", "start": 4.96, "end": 5.46, "f0_hz": 236.5, - "note": "A♯3" + "note": "A\u266f3" }, { "t": "up", "start": 5.46, "end": 5.82, "f0_hz": 239.2, - "note": "A♯3" + "note": "A\u266f3" }, { "t": "in", "start": 5.82, "end": 6.18, "f0_hz": 310.2, - "note": "D♯4" + "note": "D\u266f4" }, { "t": "myself", @@ -552,14 +552,14 @@ "t": "I", "start": 7.25, "end": 7.43, "f0_hz": 207.1, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "think", "start": 7.43, "end": 8.36, "f0_hz": 205.9, - "note": "G♯3" + "note": "G\u266f3" } ] }, @@ -576,21 +576,21 @@ "t": "Of", "start": 9.16, "end": 9.67, "f0_hz": 467.5, - "note": "A♯4" + "note": "A\u266f4" }, { "t": "a", "start": 9.67, "end": 9.92, "f0_hz": 463.5, - "note": "A♯4" + "note": "A\u266f4" }, { "t": "stone", "start": 9.92, "end": 11.19, "f0_hz": 409.3, - "note": "G♯4" + "note": "G\u266f4" } ] }, @@ -607,35 +607,35 @@ "t": "Of", "start": 9.16, "end": 9.67, "f0_hz": 467.5, - "note": "A♯4" + "note": "A\u266f4" }, { "t": "a", "start": 9.67, "end": 9.92, "f0_hz": 463.5, - "note": "A♯4" + "note": "A\u266f4" }, { "t": "stone", "start": 9.92, "end": 11.19, "f0_hz": 409.3, - "note": "G♯4" + "note": "G\u266f4" }, { "t": "just", "start": 11.19, "end": 12.22, "f0_hz": 313.8, - "note": "D♯4" + "note": "D\u266f4" }, { "t": "waiting", "start": 12.22, "end": 13.99, "f0_hz": 281.2, - "note": "C♯4" + "note": "C\u266f4" }, { "t": "very", @@ -649,7 +649,7 @@ "t": "patiently", "start": 15.01, "end": 17.3, "f0_hz": 312, - "note": "D♯4" + "note": "D\u266f4" } ] }, @@ -680,14 +680,14 @@ "t": "to", "start": 20.71, "end": 21.27, "f0_hz": 276.4, - "note": "C♯4" + "note": "C\u266f4" }, { "t": "pass", "start": 21.27, "end": 22.28, "f0_hz": 281.2, - "note": "C♯4" + "note": "C\u266f4" } ] }, @@ -712,7 +712,7 @@ "o-heres-loner": { "source": "6988619239657622790", "start": 0.18, "end": 4.5, - "words": "here's a whistlegraph by camille called loner — ready? (spoken)", + "words": "here's a whistlegraph by camille called loner \u2014 ready? (spoken)", "dur": 4.32, "median_f0_hz": 155.1, "word_f0": [ @@ -721,7 +721,7 @@ "t": "a", "start": 0.34, "end": 0.39, "f0_hz": 208.9, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "Cam", @@ -735,7 +735,7 @@ "t": "ille", "start": 1.37, "end": 1.6, "f0_hz": 155.1, - "note": "D♯3" + "note": "D\u266f3" } ] }, @@ -759,7 +759,7 @@ "t": "cur", "start": 5.92, "end": 6.44, "f0_hz": 239.2, - "note": "A♯3" + "note": "A\u266f3" }, { "t": "led", @@ -773,21 +773,21 @@ "t": "up", "start": 6.95, "end": 7.65, "f0_hz": 204.7, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "in", "start": 7.65, "end": 8.16, "f0_hz": 180.3, - "note": "F♯3" + "note": "F\u266f3" }, { "t": "myself", "start": 8.16, "end": 9.68, "f0_hz": 205.9, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "I", @@ -801,7 +801,7 @@ "t": "think", "start": 10.23, "end": 11.04, "f0_hz": 141.4, - "note": "C♯3" + "note": "C\u266f3" }, { "t": "of", @@ -822,7 +822,7 @@ "t": "stone", "start": 12.06, "end": 13.59, "f0_hz": 315.7, - "note": "D♯4" + "note": "D\u266f4" }, { "t": "just", @@ -836,7 +836,7 @@ "t": "waiting", "start": 15.68, "end": 17.24, "f0_hz": 204.1, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "very", @@ -857,7 +857,7 @@ "t": "for", "start": 21.52, "end": 22.51, "f0_hz": 271.6, - "note": "C♯4" + "note": "C\u266f4" }, { "t": "time", @@ -888,14 +888,14 @@ "t": "ib", "start": 0.49, "end": 0.67, "f0_hz": 278, - "note": "C♯4" + "note": "C\u266f4" }, { "t": "bing", "start": 0.67, "end": 1.57, "f0_hz": 276.4, - "note": "C♯4" + "note": "C\u266f4" }, { "t": "cur", @@ -916,21 +916,21 @@ "t": "up", "start": 2.91, "end": 3.36, "f0_hz": 202.3, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "in", "start": 3.36, "end": 3.81, "f0_hz": 183.4, - "note": "F♯3" + "note": "F\u266f3" }, { "t": "myself", "start": 3.81, "end": 5.27, "f0_hz": 204.7, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "I", @@ -951,14 +951,14 @@ "t": "of", "start": 6.6, "end": 7.14, "f0_hz": 362.6, - "note": "F♯4" + "note": "F\u266f4" }, { "t": "a", "start": 7.14, "end": 7.53, "f0_hz": 360.5, - "note": "F♯4" + "note": "F\u266f4" }, { "t": "stone", @@ -972,7 +972,7 @@ "t": "Just", "start": 9.48, "end": 10.51, "f0_hz": 202.9, - "note": "G♯3" + "note": "G\u266f3" }, { "t": "waiting", @@ -986,7 +986,7 @@ "t": "very", "start": 12.31, "end": 13.34, "f0_hz": 182.3, - "note": "F♯3" + "note": "F\u266f3" }, { "t": "patiently", @@ -1007,7 +1007,7 @@ "t": "time", "start": 16.76, "end": 18.21, "f0_hz": 136.6, - "note": "C♯3" + "note": "C\u266f3" }, { "t": "to", diff --git a/pop/loner/samples/.takecharts.json b/pop/loner/samples/.takecharts.json new file mode 100644 --- /dev/null +++ b/pop/loner/samples/.takecharts.json @@ -0,0 +1,3242 @@ +{ + "w-rq": { + "slice": { + "source": "corpus/rq", + "start": 0.0, + "end": 26.974, + "words": "the whole lyric, assembled from corpus", + "dur": 26.974, + "median_f0_hz": 121.4, + "word_f0": [ + { + "t": "sitting", + "start": 0.4, + "end": 1.794, + "f0_hz": 147.0, + "note": "D3" + }, + { + "t": "curled", + "start": 2.044, + "end": 3.8105, + "f0_hz": 116.8, + "note": "A#2" + }, + { + "t": "up", + "start": 4.0605, + "end": 4.2945, + "f0_hz": 146.7, + "note": "D3" + }, + { + "t": "in", + "start": 4.5445, + "end": 5.0885, + "f0_hz": 103.7, + "note": "G#2" + }, + { + "t": "myself", + "start": 5.3385, + "end": 6.97, + "f0_hz": 128.2, + "note": "C3" + }, + { + "t": "i", + "start": 7.22, + "end": 7.5565, + "f0_hz": 91.5, + "note": "F#2" + }, + { + "t": "think", + "start": 7.8065, + "end": 8.7505, + "f0_hz": 148.5, + "note": "D3" + }, + { + "t": "of", + "start": 9.0005, + "end": 9.817, + "f0_hz": 198.2, + "note": "G3" + }, + { + "t": "a", + "start": 10.067, + "end": 10.611, + "f0_hz": 198.6, + "note": "G3" + }, + { + "t": "stone", + "start": 10.861, + "end": 13.1975, + "f0_hz": 175.8, + "note": "F3" + }, + { + "t": "just", + "start": 13.4475, + "end": 14.9865, + "f0_hz": 112.0, + "note": "A2" + }, + { + "t": "waiting", + "start": 15.2365, + "end": 16.8305, + "f0_hz": 116.3, + "note": "A#2" + }, + { + "t": "very", + "start": 17.0805, + "end": 18.717, + "f0_hz": 103.0, + "note": "G#2" + }, + { + "t": "patiently", + "start": 18.967, + "end": 21.1585, + "f0_hz": 131.5, + "note": "C3" + }, + { + "t": "for", + "start": 21.4085, + "end": 22.055, + "f0_hz": 134.3, + "note": "C3" + }, + { + "t": "time", + "start": 22.305, + "end": 24.3415, + "f0_hz": 150.4, + "note": "D3" + }, + { + "t": "to", + "start": 24.5915, + "end": 25.153, + "f0_hz": 117.8, + "note": "A#2" + }, + { + "t": "pass", + "start": 25.403, + "end": 26.9745, + "f0_hz": 117.9, + "note": "A#2" + } + ] + }, + "align": { + "model": "corpus", + "text": "sitting curled up in myself i think of a stone just waiting very patiently for time to pass", + "words": [ + { + "t": "sitting", + "start": 0.4, + "end": 1.794, + "f0_hz": 147.0, + "note": "D3" + }, + { + "t": "curled", + "start": 2.044, + "end": 3.8105, + "f0_hz": 116.8, + "note": "A#2" + }, + { + "t": "up", + "start": 4.0605, + "end": 4.2945, + "f0_hz": 146.7, + "note": "D3" + }, + { + "t": "in", + "start": 4.5445, + "end": 5.0885, + "f0_hz": 103.7, + "note": "G#2" + }, + { + "t": "myself", + "start": 5.3385, + "end": 6.97, + "f0_hz": 128.2, + "note": "C3" + }, + { + "t": "i", + "start": 7.22, + "end": 7.5565, + "f0_hz": 91.5, + "note": "F#2" + }, + { + "t": "think", + "start": 7.8065, + "end": 8.7505, + "f0_hz": 148.5, + "note": "D3" + }, + { + "t": "of", + "start": 9.0005, + "end": 9.817, + "f0_hz": 198.2, + "note": "G3" + }, + { + "t": "a", + "start": 10.067, + "end": 10.611, + "f0_hz": 198.6, + "note": "G3" + }, + { + "t": "stone", + "start": 10.861, + "end": 13.1975, + "f0_hz": 175.8, + "note": "F3" + }, + { + "t": "just", + "start": 13.4475, + "end": 14.9865, + "f0_hz": 112.0, + "note": "A2" + }, + { + "t": "waiting", + "start": 15.2365, + "end": 16.8305, + "f0_hz": 116.3, + "note": "A#2" + }, + { + "t": "very", + "start": 17.0805, + "end": 18.717, + "f0_hz": 103.0, + "note": "G#2" + }, + { + "t": "patiently", + "start": 18.967, + "end": 21.1585, + "f0_hz": 131.5, + "note": "C3" + }, + { + "t": "for", + "start": 21.4085, + "end": 22.055, + "f0_hz": 134.3, + "note": "C3" + }, + { + "t": "time", + "start": 22.305, + "end": 24.3415, + "f0_hz": 150.4, + "note": "D3" + }, + { + "t": "to", + "start": 24.5915, + "end": 25.153, + "f0_hz": 117.8, + "note": "A#2" + }, + { + "t": "pass", + "start": 25.403, + "end": 26.9745, + "f0_hz": 117.9, + "note": "A#2" + } + ] + }, + "chart": { + "slice": "rq-line", + "beats": 60.0, + "lead": 0.0, + "durs": { + "0": 2.0, + "1": 2.0, + "2": 1.91, + "3": 2.09, + "4": 2.0, + "5": 1.5, + "6": 2.5, + "7": 2.0, + "8": 2.0, + "9": 4.0, + "10": 1.75, + "11": 4.25, + "12": 4.0, + "13": 2.0, + "14": 2.0, + "15": 2.0, + "16": 2.0, + "17": 2.0, + "18": 2.0, + "19": 2.0, + "20": 2.0, + "21": 4.0, + "22": 4.0, + "23": 4.0 + }, + "melody": [ + 7, + 5, + 3, + 2, + 0, + 5, + 2, + -2, + -5, + 12, + 10, + 5, + 2, + 3, + 2, + 0, + -2, + 7, + 5, + 3, + 5, + 7, + 3, + 3 + ], + "sylls": { + "0": [ + [ + null, + "sitting\u00b7a" + ], + [ + 1.615, + "sitting\u00b7b" + ] + ], + "4": [ + [ + null, + "my" + ], + [ + 6.0885, + "self" + ] + ], + "11": [ + [ + null, + "wait" + ], + [ + 16.1615, + "ing" + ] + ], + "12": [ + [ + null, + "ve" + ], + [ + 18.4955, + "ry" + ] + ], + "13": [ + [ + null, + "pa" + ], + [ + 19.802, + "tient" + ], + [ + 20.342, + "ly" + ] + ] + }, + "times": { + "0": 0.4, + "1": 2.044, + "2": 4.0605, + "3": 4.5445, + "4": 5.3385, + "5": 7.22, + "6": 7.8065, + "7": 9.0005, + "8": 10.067, + "9": 10.861, + "10": 13.4475, + "11": 15.2365, + "12": 17.0805, + "13": 18.967, + "14": 21.4085, + "15": 22.305, + "16": 24.5915, + "17": 25.403 + }, + "end": 26.9745 + }, + "name": "rq-line" + }, + "w-sh": { + "slice": { + "source": "corpus/sh", + "start": 0.0, + "end": 26.974, + "words": "the whole lyric, assembled from corpus", + "dur": 26.974, + "median_f0_hz": 121.4, + "word_f0": [ + { + "t": "sitting", + "start": 0.4, + "end": 2.044, + "f0_hz": 234.7, + "note": "A#3" + }, + { + "t": "curled", + "start": 2.294, + "end": 3.7905, + "f0_hz": 110.2, + "note": "A2" + }, + { + "t": "up", + "start": 4.0405, + "end": 4.512, + "f0_hz": 0.0, + "note": "?" + }, + { + "t": "in", + "start": 4.762, + "end": 5.3985, + "f0_hz": 179.5, + "note": "F3" + }, + { + "t": "myself", + "start": 5.6485, + "end": 7.195, + "f0_hz": 110.5, + "note": "A2" + }, + { + "t": "i", + "start": 7.445, + "end": 7.734, + "f0_hz": 168.1, + "note": "E3" + }, + { + "t": "think", + "start": 7.984, + "end": 8.943, + "f0_hz": 165.2, + "note": "E3" + }, + { + "t": "of", + "start": 9.193, + "end": 9.827, + "f0_hz": 177.7, + "note": "F3" + }, + { + "t": "a", + "start": 10.077, + "end": 10.4084, + "f0_hz": 180.9, + "note": "F#3" + }, + { + "t": "stone", + "start": 10.6584, + "end": 12.7149, + "f0_hz": 153.3, + "note": "D#3" + }, + { + "t": "just", + "start": 12.9649, + "end": 14.5539, + "f0_hz": 104.6, + "note": "G#2" + }, + { + "t": "waiting", + "start": 14.8039, + "end": 16.5254, + "f0_hz": 108.9, + "note": "A2" + }, + { + "t": "very", + "start": 16.7754, + "end": 17.9519, + "f0_hz": 175.9, + "note": "F3" + }, + { + "t": "patiently", + "start": 18.2019, + "end": 20.6184, + "f0_hz": 120.1, + "note": "B2" + }, + { + "t": "for", + "start": 20.8684, + "end": 21.785, + "f0_hz": 122.3, + "note": "B2" + }, + { + "t": "time", + "start": 22.035, + "end": 23.274, + "f0_hz": 136.6, + "note": "C#3" + }, + { + "t": "to", + "start": 23.524, + "end": 24.6255, + "f0_hz": 108.3, + "note": "A2" + }, + { + "t": "pass", + "start": 24.8755, + "end": 26.9745, + "f0_hz": 108.3, + "note": "A2" + } + ] + }, + "align": { + "model": "corpus", + "text": "sitting curled up in myself i think of a stone just waiting very patiently for time to pass", + "words": [ + { + "t": "sitting", + "start": 0.4, + "end": 2.044, + "f0_hz": 234.7, + "note": "A#3" + }, + { + "t": "curled", + "start": 2.294, + "end": 3.7905, + "f0_hz": 110.2, + "note": "A2" + }, + { + "t": "up", + "start": 4.0405, + "end": 4.512, + "f0_hz": 0.0, + "note": "?" + }, + { + "t": "in", + "start": 4.762, + "end": 5.3985, + "f0_hz": 179.5, + "note": "F3" + }, + { + "t": "myself", + "start": 5.6485, + "end": 7.195, + "f0_hz": 110.5, + "note": "A2" + }, + { + "t": "i", + "start": 7.445, + "end": 7.734, + "f0_hz": 168.1, + "note": "E3" + }, + { + "t": "think", + "start": 7.984, + "end": 8.943, + "f0_hz": 165.2, + "note": "E3" + }, + { + "t": "of", + "start": 9.193, + "end": 9.827, + "f0_hz": 177.7, + "note": "F3" + }, + { + "t": "a", + "start": 10.077, + "end": 10.4084, + "f0_hz": 180.9, + "note": "F#3" + }, + { + "t": "stone", + "start": 10.6584, + "end": 12.7149, + "f0_hz": 153.3, + "note": "D#3" + }, + { + "t": "just", + "start": 12.9649, + "end": 14.5539, + "f0_hz": 104.6, + "note": "G#2" + }, + { + "t": "waiting", + "start": 14.8039, + "end": 16.5254, + "f0_hz": 108.9, + "note": "A2" + }, + { + "t": "very", + "start": 16.7754, + "end": 17.9519, + "f0_hz": 175.9, + "note": "F3" + }, + { + "t": "patiently", + "start": 18.2019, + "end": 20.6184, + "f0_hz": 120.1, + "note": "B2" + }, + { + "t": "for", + "start": 20.8684, + "end": 21.785, + "f0_hz": 122.3, + "note": "B2" + }, + { + "t": "time", + "start": 22.035, + "end": 23.274, + "f0_hz": 136.6, + "note": "C#3" + }, + { + "t": "to", + "start": 23.524, + "end": 24.6255, + "f0_hz": 108.3, + "note": "A2" + }, + { + "t": "pass", + "start": 24.8755, + "end": 26.9745, + "f0_hz": 108.3, + "note": "A2" + } + ] + }, + "chart": { + "slice": "sh-line", + "beats": 60.0, + "lead": 0.0, + "durs": { + "0": 2.0, + "1": 2.0, + "2": 1.91, + "3": 2.09, + "4": 2.0, + "5": 1.5, + "6": 2.5, + "7": 2.0, + "8": 2.0, + "9": 4.0, + "10": 1.75, + "11": 4.25, + "12": 4.0, + "13": 2.0, + "14": 2.0, + "15": 2.0, + "16": 2.0, + "17": 2.0, + "18": 2.0, + "19": 2.0, + "20": 2.0, + "21": 4.0, + "22": 4.0, + "23": 4.0 + }, + "melody": [ + 7, + 5, + 3, + 2, + 0, + 5, + 2, + -2, + -5, + 12, + 10, + 5, + 2, + 3, + 2, + 0, + -2, + 7, + 5, + 3, + 5, + 7, + 3, + 3 + ], + "sylls": { + "0": [ + [ + null, + "sitting\u00b7a" + ], + [ + 1.48, + "sitting\u00b7b" + ] + ], + "4": [ + [ + null, + "my" + ], + [ + 6.9785, + "self" + ] + ], + "11": [ + [ + null, + "wait" + ], + [ + 15.0789, + "ing" + ] + ], + "12": [ + [ + null, + "ve" + ], + [ + 17.7654, + "ry" + ] + ], + "13": [ + [ + null, + "pa" + ], + [ + 18.5369, + "tient" + ], + [ + 19.8169, + "ly" + ] + ] + }, + "times": { + "0": 0.4, + "1": 2.294, + "2": 4.0405, + "3": 4.762, + "4": 5.6485, + "5": 7.445, + "6": 7.984, + "7": 9.193, + "8": 10.077, + "9": 10.6584, + "10": 12.9649, + "11": 14.8039, + "12": 16.7754, + "13": 18.2019, + "14": 20.8684, + "15": 22.035, + "16": 23.524, + "17": 24.8755 + }, + "end": 26.9745 + }, + "name": "sh-line" + }, + "w-lg": { + "slice": { + "source": "corpus/lg", + "start": 0.0, + "end": 26.812, + "words": "the whole lyric, assembled from corpus", + "dur": 26.812, + "median_f0_hz": 229.4, + "word_f0": [ + { + "t": "sitting", + "start": 0.4, + "end": 1.974, + "f0_hz": 285.9, + "note": "D4" + }, + { + "t": "curled", + "start": 2.224, + "end": 3.6605, + "f0_hz": 226.8, + "note": "A#3" + }, + { + "t": "up", + "start": 3.9105, + "end": 4.4445, + "f0_hz": 133.7, + "note": "C3" + }, + { + "t": "in", + "start": 4.6945, + "end": 5.2835, + "f0_hz": 192.3, + "note": "G3" + }, + { + "t": "myself", + "start": 5.5335, + "end": 7.25, + "f0_hz": 222.4, + "note": "A3" + }, + { + "t": "i", + "start": 7.5, + "end": 7.6965, + "f0_hz": 171.7, + "note": "F3" + }, + { + "t": "think", + "start": 7.9465, + "end": 8.8055, + "f0_hz": 171.4, + "note": "F3" + }, + { + "t": "of", + "start": 9.0555, + "end": 9.9345, + "f0_hz": 375.1, + "note": "F#4" + }, + { + "t": "a", + "start": 10.1845, + "end": 10.676, + "f0_hz": 378.4, + "note": "F#4" + }, + { + "t": "stone", + "start": 10.926, + "end": 13.4075, + "f0_hz": 325.3, + "note": "E4" + }, + { + "t": "just", + "start": 13.6575, + "end": 15.054, + "f0_hz": 214.7, + "note": "A3" + }, + { + "t": "waiting", + "start": 15.304, + "end": 17.028, + "f0_hz": 218.2, + "note": "A3" + }, + { + "t": "very", + "start": 17.278, + "end": 18.5245, + "f0_hz": 188.8, + "note": "F#3" + }, + { + "t": "patiently", + "start": 18.7745, + "end": 20.986, + "f0_hz": 247.5, + "note": "B3" + }, + { + "t": "for", + "start": 21.236, + "end": 22.205, + "f0_hz": 255.2, + "note": "C4" + }, + { + "t": "time", + "start": 22.455, + "end": 23.6515, + "f0_hz": 280.7, + "note": "C#4" + }, + { + "t": "to", + "start": 23.9015, + "end": 24.8605, + "f0_hz": 222.1, + "note": "A3" + }, + { + "t": "pass", + "start": 25.1105, + "end": 26.812, + "f0_hz": 221.3, + "note": "A3" + } + ] + }, + "align": { + "model": "corpus", + "text": "sitting curled up in myself i think of a stone just waiting very patiently for time to pass", + "words": [ + { + "t": "sitting", + "start": 0.4, + "end": 1.974, + "f0_hz": 285.9, + "note": "D4" + }, + { + "t": "curled", + "start": 2.224, + "end": 3.6605, + "f0_hz": 226.8, + "note": "A#3" + }, + { + "t": "up", + "start": 3.9105, + "end": 4.4445, + "f0_hz": 133.7, + "note": "C3" + }, + { + "t": "in", + "start": 4.6945, + "end": 5.2835, + "f0_hz": 192.3, + "note": "G3" + }, + { + "t": "myself", + "start": 5.5335, + "end": 7.25, + "f0_hz": 222.4, + "note": "A3" + }, + { + "t": "i", + "start": 7.5, + "end": 7.6965, + "f0_hz": 171.7, + "note": "F3" + }, + { + "t": "think", + "start": 7.9465, + "end": 8.8055, + "f0_hz": 171.4, + "note": "F3" + }, + { + "t": "of", + "start": 9.0555, + "end": 9.9345, + "f0_hz": 375.1, + "note": "F#4" + }, + { + "t": "a", + "start": 10.1845, + "end": 10.676, + "f0_hz": 378.4, + "note": "F#4" + }, + { + "t": "stone", + "start": 10.926, + "end": 13.4075, + "f0_hz": 325.3, + "note": "E4" + }, + { + "t": "just", + "start": 13.6575, + "end": 15.054, + "f0_hz": 214.7, + "note": "A3" + }, + { + "t": "waiting", + "start": 15.304, + "end": 17.028, + "f0_hz": 218.2, + "note": "A3" + }, + { + "t": "very", + "start": 17.278, + "end": 18.5245, + "f0_hz": 188.8, + "note": "F#3" + }, + { + "t": "patiently", + "start": 18.7745, + "end": 20.986, + "f0_hz": 247.5, + "note": "B3" + }, + { + "t": "for", + "start": 21.236, + "end": 22.205, + "f0_hz": 255.2, + "note": "C4" + }, + { + "t": "time", + "start": 22.455, + "end": 23.6515, + "f0_hz": 280.7, + "note": "C#4" + }, + { + "t": "to", + "start": 23.9015, + "end": 24.8605, + "f0_hz": 222.1, + "note": "A3" + }, + { + "t": "pass", + "start": 25.1105, + "end": 26.812, + "f0_hz": 221.3, + "note": "A3" + } + ] + }, + "chart": { + "slice": "lg-line", + "beats": 60.0, + "lead": 0.0, + "durs": { + "0": 2.0, + "1": 2.0, + "2": 1.91, + "3": 2.09, + "4": 2.0, + "5": 1.5, + "6": 2.5, + "7": 2.0, + "8": 2.0, + "9": 4.0, + "10": 1.75, + "11": 4.25, + "12": 4.0, + "13": 2.0, + "14": 2.0, + "15": 2.0, + "16": 2.0, + "17": 2.0, + "18": 2.0, + "19": 2.0, + "20": 2.0, + "21": 4.0, + "22": 4.0, + "23": 4.0 + }, + "melody": [ + 7, + 5, + 3, + 2, + 0, + 5, + 2, + -2, + -5, + 12, + 10, + 5, + 2, + 3, + 2, + 0, + -2, + 7, + 5, + 3, + 5, + 7, + 3, + 3 + ], + "sylls": { + "0": [ + [ + null, + "sitting\u00b7a" + ], + [ + 1.345, + "sitting\u00b7b" + ] + ], + "4": [ + [ + null, + "my" + ], + [ + 7.0035, + "self" + ] + ], + "11": [ + [ + null, + "wait" + ], + [ + 16.189, + "ing" + ] + ], + "12": [ + [ + null, + "ve" + ], + [ + 18.358, + "ry" + ] + ], + "13": [ + [ + null, + "pa" + ], + [ + 19.6445, + "tient" + ], + [ + 20.2445, + "ly" + ] + ] + }, + "times": { + "0": 0.4, + "1": 2.224, + "2": 3.9105, + "3": 4.6945, + "4": 5.5335, + "5": 7.5, + "6": 7.9465, + "7": 9.0555, + "8": 10.1845, + "9": 10.926, + "10": 13.6575, + "11": 15.304, + "12": 17.278, + "13": 18.7745, + "14": 21.236, + "15": 22.455, + "16": 23.9015, + "17": 25.1105 + }, + "end": 26.812 + }, + "name": "lg-line" + }, + "w-pf": { + "slice": { + "source": "corpus/pf", + "start": 0.0, + "end": 26.529, + "words": "the whole lyric, assembled from corpus", + "dur": 26.529, + "median_f0_hz": 120.7, + "word_f0": [ + { + "t": "sitting", + "start": 0.4, + "end": 1.9665, + "f0_hz": 134.4, + "note": "C3" + }, + { + "t": "curled", + "start": 2.2165, + "end": 3.713, + "f0_hz": 109.9, + "note": "A2" + }, + { + "t": "up", + "start": 3.963, + "end": 4.4895, + "f0_hz": 198.2, + "note": "G3" + }, + { + "t": "in", + "start": 4.7395, + "end": 5.376, + "f0_hz": 105.4, + "note": "G#2" + }, + { + "t": "myself", + "start": 5.626, + "end": 7.1175, + "f0_hz": 112.1, + "note": "A2" + }, + { + "t": "i", + "start": 7.3675, + "end": 7.569, + "f0_hz": 0.0, + "note": "?" + }, + { + "t": "think", + "start": 7.819, + "end": 8.8655, + "f0_hz": 0.0, + "note": "?" + }, + { + "t": "of", + "start": 9.1155, + "end": 9.8545, + "f0_hz": 179.5, + "note": "F3" + }, + { + "t": "a", + "start": 10.1045, + "end": 10.4285, + "f0_hz": 181.0, + "note": "F#3" + }, + { + "t": "stone", + "start": 10.6785, + "end": 12.6575, + "f0_hz": 133.0, + "note": "C3" + }, + { + "t": "just", + "start": 12.9075, + "end": 14.179, + "f0_hz": 104.0, + "note": "G#2" + }, + { + "t": "waiting", + "start": 14.429, + "end": 15.9555, + "f0_hz": 109.4, + "note": "A2" + }, + { + "t": "very", + "start": 16.2055, + "end": 17.4545, + "f0_hz": 179.3, + "note": "F3" + }, + { + "t": "patiently", + "start": 17.7045, + "end": 20.1735, + "f0_hz": 120.9, + "note": "B2" + }, + { + "t": "for", + "start": 20.4235, + "end": 21.34, + "f0_hz": 122.5, + "note": "B2" + }, + { + "t": "time", + "start": 21.59, + "end": 22.829, + "f0_hz": 136.5, + "note": "C#3" + }, + { + "t": "to", + "start": 23.079, + "end": 24.053, + "f0_hz": 108.2, + "note": "A2" + }, + { + "t": "pass", + "start": 24.303, + "end": 26.5295, + "f0_hz": 107.7, + "note": "A2" + } + ] + }, + "align": { + "model": "corpus", + "text": "sitting curled up in myself i think of a stone just waiting very patiently for time to pass", + "words": [ + { + "t": "sitting", + "start": 0.4, + "end": 1.9665, + "f0_hz": 134.4, + "note": "C3" + }, + { + "t": "curled", + "start": 2.2165, + "end": 3.713, + "f0_hz": 109.9, + "note": "A2" + }, + { + "t": "up", + "start": 3.963, + "end": 4.4895, + "f0_hz": 198.2, + "note": "G3" + }, + { + "t": "in", + "start": 4.7395, + "end": 5.376, + "f0_hz": 105.4, + "note": "G#2" + }, + { + "t": "myself", + "start": 5.626, + "end": 7.1175, + "f0_hz": 112.1, + "note": "A2" + }, + { + "t": "i", + "start": 7.3675, + "end": 7.569, + "f0_hz": 0.0, + "note": "?" + }, + { + "t": "think", + "start": 7.819, + "end": 8.8655, + "f0_hz": 0.0, + "note": "?" + }, + { + "t": "of", + "start": 9.1155, + "end": 9.8545, + "f0_hz": 179.5, + "note": "F3" + }, + { + "t": "a", + "start": 10.1045, + "end": 10.4285, + "f0_hz": 181.0, + "note": "F#3" + }, + { + "t": "stone", + "start": 10.6785, + "end": 12.6575, + "f0_hz": 133.0, + "note": "C3" + }, + { + "t": "just", + "start": 12.9075, + "end": 14.179, + "f0_hz": 104.0, + "note": "G#2" + }, + { + "t": "waiting", + "start": 14.429, + "end": 15.9555, + "f0_hz": 109.4, + "note": "A2" + }, + { + "t": "very", + "start": 16.2055, + "end": 17.4545, + "f0_hz": 179.3, + "note": "F3" + }, + { + "t": "patiently", + "start": 17.7045, + "end": 20.1735, + "f0_hz": 120.9, + "note": "B2" + }, + { + "t": "for", + "start": 20.4235, + "end": 21.34, + "f0_hz": 122.5, + "note": "B2" + }, + { + "t": "time", + "start": 21.59, + "end": 22.829, + "f0_hz": 136.5, + "note": "C#3" + }, + { + "t": "to", + "start": 23.079, + "end": 24.053, + "f0_hz": 108.2, + "note": "A2" + }, + { + "t": "pass", + "start": 24.303, + "end": 26.5295, + "f0_hz": 107.7, + "note": "A2" + } + ] + }, + "chart": { + "slice": "pf-line", + "beats": 60.0, + "lead": 0.0, + "durs": { + "0": 2.0, + "1": 2.0, + "2": 1.91, + "3": 2.09, + "4": 2.0, + "5": 1.5, + "6": 2.5, + "7": 2.0, + "8": 2.0, + "9": 4.0, + "10": 1.75, + "11": 4.25, + "12": 4.0, + "13": 2.0, + "14": 2.0, + "15": 2.0, + "16": 2.0, + "17": 2.0, + "18": 2.0, + "19": 2.0, + "20": 2.0, + "21": 4.0, + "22": 4.0, + "23": 4.0 + }, + "melody": [ + 7, + 5, + 3, + 2, + 0, + 5, + 2, + -2, + -5, + 12, + 10, + 5, + 2, + 3, + 2, + 0, + -2, + 7, + 5, + 3, + 5, + 7, + 3, + 3 + ], + "sylls": { + "0": [ + [ + null, + "sitting\u00b7a" + ], + [ + 0.945, + "sitting\u00b7b" + ] + ], + "4": [ + [ + null, + "my" + ], + [ + 6.396, + "self" + ] + ], + "11": [ + [ + null, + "wait" + ], + [ + 14.634, + "ing" + ] + ], + "12": [ + [ + null, + "ve" + ], + [ + 17.2605, + "ry" + ] + ], + "13": [ + [ + null, + "pa" + ], + [ + 18.0945, + "tient" + ], + [ + 19.3745, + "ly" + ] + ] + }, + "times": { + "0": 0.4, + "1": 2.2165, + "2": 3.963, + "3": 4.7395, + "4": 5.626, + "5": 7.3675, + "6": 7.819, + "7": 9.1155, + "8": 10.1045, + "9": 10.6785, + "10": 12.9075, + "11": 14.429, + "12": 16.2055, + "13": 17.7045, + "14": 20.4235, + "15": 21.59, + "16": 23.079, + "17": 24.303 + }, + "end": 26.5295 + }, + "name": "pf-line" + }, + "w-rd": { + "slice": { + "source": "corpus/rd", + "start": 0.0, + "end": 24.505, + "words": "the whole lyric, assembled from corpus", + "dur": 24.505, + "median_f0_hz": 126.6, + "word_f0": [ + { + "t": "sitting", + "start": 0.4, + "end": 2.0365, + "f0_hz": 128.7, + "note": "C3" + }, + { + "t": "curled", + "start": 2.2865, + "end": 3.7155, + "f0_hz": 113.4, + "note": "A#2" + }, + { + "t": "up", + "start": 3.9655, + "end": 4.5045, + "f0_hz": 98.6, + "note": "G2" + }, + { + "t": "in", + "start": 4.7545, + "end": 5.126, + "f0_hz": 99.8, + "note": "G2" + }, + { + "t": "myself", + "start": 5.376, + "end": 6.9275, + "f0_hz": 126.0, + "note": "B2" + }, + { + "t": "i", + "start": 7.1775, + "end": 7.3965, + "f0_hz": 97.5, + "note": "G2" + }, + { + "t": "think", + "start": 7.6465, + "end": 8.3355, + "f0_hz": 184.2, + "note": "F#3" + }, + { + "t": "of", + "start": 8.5855, + "end": 9.362, + "f0_hz": 194.4, + "note": "G3" + }, + { + "t": "a", + "start": 9.612, + "end": 9.791, + "f0_hz": 173.0, + "note": "F3" + }, + { + "t": "stone", + "start": 10.041, + "end": 11.63, + "f0_hz": 128.6, + "note": "C3" + }, + { + "t": "just", + "start": 11.88, + "end": 13.069, + "f0_hz": 109.0, + "note": "A2" + }, + { + "t": "waiting", + "start": 13.319, + "end": 15.3205, + "f0_hz": 112.1, + "note": "A2" + }, + { + "t": "very", + "start": 15.5705, + "end": 16.6945, + "f0_hz": 184.6, + "note": "F#3" + }, + { + "t": "patiently", + "start": 16.9445, + "end": 19.5985, + "f0_hz": 129.9, + "note": "C3" + }, + { + "t": "for", + "start": 19.8485, + "end": 20.6725, + "f0_hz": 129.0, + "note": "C3" + }, + { + "t": "time", + "start": 20.9225, + "end": 22.139, + "f0_hz": 143.0, + "note": "D3" + }, + { + "t": "to", + "start": 22.389, + "end": 23.118, + "f0_hz": 113.0, + "note": "A2" + }, + { + "t": "pass", + "start": 23.368, + "end": 24.5045, + "f0_hz": 115.0, + "note": "A#2" + } + ] + }, + "align": { + "model": "corpus", + "text": "sitting curled up in myself i think of a stone just waiting very patiently for time to pass", + "words": [ + { + "t": "sitting", + "start": 0.4, + "end": 2.0365, + "f0_hz": 128.7, + "note": "C3" + }, + { + "t": "curled", + "start": 2.2865, + "end": 3.7155, + "f0_hz": 113.4, + "note": "A#2" + }, + { + "t": "up", + "start": 3.9655, + "end": 4.5045, + "f0_hz": 98.6, + "note": "G2" + }, + { + "t": "in", + "start": 4.7545, + "end": 5.126, + "f0_hz": 99.8, + "note": "G2" + }, + { + "t": "myself", + "start": 5.376, + "end": 6.9275, + "f0_hz": 126.0, + "note": "B2" + }, + { + "t": "i", + "start": 7.1775, + "end": 7.3965, + "f0_hz": 97.5, + "note": "G2" + }, + { + "t": "think", + "start": 7.6465, + "end": 8.3355, + "f0_hz": 184.2, + "note": "F#3" + }, + { + "t": "of", + "start": 8.5855, + "end": 9.362, + "f0_hz": 194.4, + "note": "G3" + }, + { + "t": "a", + "start": 9.612, + "end": 9.791, + "f0_hz": 173.0, + "note": "F3" + }, + { + "t": "stone", + "start": 10.041, + "end": 11.63, + "f0_hz": 128.6, + "note": "C3" + }, + { + "t": "just", + "start": 11.88, + "end": 13.069, + "f0_hz": 109.0, + "note": "A2" + }, + { + "t": "waiting", + "start": 13.319, + "end": 15.3205, + "f0_hz": 112.1, + "note": "A2" + }, + { + "t": "very", + "start": 15.5705, + "end": 16.6945, + "f0_hz": 184.6, + "note": "F#3" + }, + { + "t": "patiently", + "start": 16.9445, + "end": 19.5985, + "f0_hz": 129.9, + "note": "C3" + }, + { + "t": "for", + "start": 19.8485, + "end": 20.6725, + "f0_hz": 129.0, + "note": "C3" + }, + { + "t": "time", + "start": 20.9225, + "end": 22.139, + "f0_hz": 143.0, + "note": "D3" + }, + { + "t": "to", + "start": 22.389, + "end": 23.118, + "f0_hz": 113.0, + "note": "A2" + }, + { + "t": "pass", + "start": 23.368, + "end": 24.5045, + "f0_hz": 115.0, + "note": "A#2" + } + ] + }, + "chart": { + "slice": "rd-line", + "beats": 60.0, + "lead": 0.0, + "durs": { + "0": 2.0, + "1": 2.0, + "2": 1.91, + "3": 2.09, + "4": 2.0, + "5": 1.5, + "6": 2.5, + "7": 2.0, + "8": 2.0, + "9": 4.0, + "10": 1.75, + "11": 4.25, + "12": 4.0, + "13": 2.0, + "14": 2.0, + "15": 2.0, + "16": 2.0, + "17": 2.0, + "18": 2.0, + "19": 2.0, + "20": 2.0, + "21": 4.0, + "22": 4.0, + "23": 4.0 + }, + "melody": [ + 7, + 5, + 3, + 2, + 0, + 5, + 2, + -2, + -5, + 12, + 10, + 5, + 2, + 3, + 2, + 0, + -2, + 7, + 5, + 3, + 5, + 7, + 3, + 3 + ], + "sylls": { + "0": [ + [ + null, + "sitting\u00b7a" + ], + [ + 1.665, + "sitting\u00b7b" + ] + ], + "4": [ + [ + null, + "my" + ], + [ + 6.606, + "self" + ] + ], + "11": [ + [ + null, + "wait" + ], + [ + 13.674, + "ing" + ] + ], + "12": [ + [ + null, + "ve" + ], + [ + 16.3155, + "ry" + ] + ], + "13": [ + [ + null, + "pa" + ], + [ + 18.0295, + "tient" + ], + [ + 18.6195, + "ly" + ] + ] + }, + "times": { + "0": 0.4, + "1": 2.2865, + "2": 3.9655, + "3": 4.7545, + "4": 5.376, + "5": 7.1775, + "6": 7.6465, + "7": 8.5855, + "8": 9.612, + "9": 10.041, + "10": 11.88, + "11": 13.319, + "12": 15.5705, + "13": 16.9445, + "14": 19.8485, + "15": 20.9225, + "16": 22.389, + "17": 23.368 + }, + "end": 24.5045 + }, + "name": "rd-line" + }, + "w-cp": { + "slice": { + "source": "corpus/cp", + "start": 0.0, + "end": 22.062, + "words": "the whole lyric, assembled from corpus", + "dur": 22.062, + "median_f0_hz": 149.3, + "word_f0": [ + { + "t": "sitting", + "start": 0.4, + "end": 1.299, + "f0_hz": 193.1, + "note": "G3" + }, + { + "t": "curled", + "start": 1.549, + "end": 2.5305, + "f0_hz": 163.7, + "note": "E3" + }, + { + "t": "up", + "start": 2.7805, + "end": 3.152, + "f0_hz": 134.3, + "note": "C3" + }, + { + "t": "in", + "start": 3.402, + "end": 3.646, + "f0_hz": 167.0, + "note": "E3" + }, + { + "t": "myself", + "start": 3.896, + "end": 5.005, + "f0_hz": 167.2, + "note": "E3" + }, + { + "t": "i", + "start": 5.255, + "end": 5.5765, + "f0_hz": 123.5, + "note": "B2" + }, + { + "t": "think", + "start": 5.8265, + "end": 6.518, + "f0_hz": 133.2, + "note": "C3" + }, + { + "t": "of", + "start": 6.768, + "end": 7.8345, + "f0_hz": 252.5, + "note": "B3" + }, + { + "t": "a", + "start": 8.0845, + "end": 8.456, + "f0_hz": 216.8, + "note": "A3" + }, + { + "t": "stone", + "start": 8.706, + "end": 9.31, + "f0_hz": 170.4, + "note": "F3" + }, + { + "t": "just", + "start": 9.56, + "end": 10.704, + "f0_hz": 166.8, + "note": "E3" + }, + { + "t": "waiting", + "start": 10.954, + "end": 13.388, + "f0_hz": 151.3, + "note": "D#3" + }, + { + "t": "very", + "start": 13.638, + "end": 14.447, + "f0_hz": 126.9, + "note": "B2" + }, + { + "t": "patiently", + "start": 14.697, + "end": 17.4285, + "f0_hz": 132.1, + "note": "C3" + }, + { + "t": "for", + "start": 17.6785, + "end": 18.385, + "f0_hz": 148.4, + "note": "D3" + }, + { + "t": "time", + "start": 18.635, + "end": 19.769, + "f0_hz": 120.6, + "note": "B2" + }, + { + "t": "to", + "start": 20.019, + "end": 20.6605, + "f0_hz": 124.5, + "note": "B2" + }, + { + "t": "pass", + "start": 20.9105, + "end": 22.062, + "f0_hz": 0.0, + "note": "?" + } + ] + }, + "align": { + "model": "corpus", + "text": "sitting curled up in myself i think of a stone just waiting very patiently for time to pass", + "words": [ + { + "t": "sitting", + "start": 0.4, + "end": 1.299, + "f0_hz": 193.1, + "note": "G3" + }, + { + "t": "curled", + "start": 1.549, + "end": 2.5305, + "f0_hz": 163.7, + "note": "E3" + }, + { + "t": "up", + "start": 2.7805, + "end": 3.152, + "f0_hz": 134.3, + "note": "C3" + }, + { + "t": "in", + "start": 3.402, + "end": 3.646, + "f0_hz": 167.0, + "note": "E3" + }, + { + "t": "myself", + "start": 3.896, + "end": 5.005, + "f0_hz": 167.2, + "note": "E3" + }, + { + "t": "i", + "start": 5.255, + "end": 5.5765, + "f0_hz": 123.5, + "note": "B2" + }, + { + "t": "think", + "start": 5.8265, + "end": 6.518, + "f0_hz": 133.2, + "note": "C3" + }, + { + "t": "of", + "start": 6.768, + "end": 7.8345, + "f0_hz": 252.5, + "note": "B3" + }, + { + "t": "a", + "start": 8.0845, + "end": 8.456, + "f0_hz": 216.8, + "note": "A3" + }, + { + "t": "stone", + "start": 8.706, + "end": 9.31, + "f0_hz": 170.4, + "note": "F3" + }, + { + "t": "just", + "start": 9.56, + "end": 10.704, + "f0_hz": 166.8, + "note": "E3" + }, + { + "t": "waiting", + "start": 10.954, + "end": 13.388, + "f0_hz": 151.3, + "note": "D#3" + }, + { + "t": "very", + "start": 13.638, + "end": 14.447, + "f0_hz": 126.9, + "note": "B2" + }, + { + "t": "patiently", + "start": 14.697, + "end": 17.4285, + "f0_hz": 132.1, + "note": "C3" + }, + { + "t": "for", + "start": 17.6785, + "end": 18.385, + "f0_hz": 148.4, + "note": "D3" + }, + { + "t": "time", + "start": 18.635, + "end": 19.769, + "f0_hz": 120.6, + "note": "B2" + }, + { + "t": "to", + "start": 20.019, + "end": 20.6605, + "f0_hz": 124.5, + "note": "B2" + }, + { + "t": "pass", + "start": 20.9105, + "end": 22.062, + "f0_hz": 0.0, + "note": "?" + } + ] + }, + "chart": { + "slice": "cp-line", + "beats": 60.0, + "lead": 0.0, + "durs": { + "0": 2.0, + "1": 2.0, + "2": 1.91, + "3": 2.09, + "4": 2.0, + "5": 1.5, + "6": 2.5, + "7": 2.0, + "8": 2.0, + "9": 4.0, + "10": 1.75, + "11": 4.25, + "12": 4.0, + "13": 2.0, + "14": 2.0, + "15": 2.0, + "16": 2.0, + "17": 2.0, + "18": 2.0, + "19": 2.0, + "20": 2.0, + "21": 4.0, + "22": 4.0, + "23": 4.0 + }, + "melody": [ + 7, + 5, + 3, + 2, + 0, + 5, + 2, + -2, + -5, + 12, + 10, + 5, + 2, + 3, + 2, + 0, + -2, + 7, + 5, + 3, + 5, + 7, + 3, + 3 + ], + "sylls": { + "0": [ + [ + null, + "sitting\u00b7a" + ], + [ + 0.825, + "sitting\u00b7b" + ] + ], + "4": [ + [ + null, + "my" + ], + [ + 4.846, + "self" + ] + ], + "11": [ + [ + null, + "wait" + ], + [ + 11.664, + "ing" + ] + ], + "12": [ + [ + null, + "ve" + ], + [ + 14.348, + "ry" + ] + ], + "13": [ + [ + null, + "pa" + ], + [ + 15.672, + "tient" + ], + [ + 16.877, + "ly" + ] + ] + }, + "times": { + "0": 0.4, + "1": 1.549, + "2": 2.7805, + "3": 3.402, + "4": 3.896, + "5": 5.255, + "6": 5.8265, + "7": 6.768, + "8": 8.0845, + "9": 8.706, + "10": 9.56, + "11": 10.954, + "12": 13.638, + "13": 14.697, + "14": 17.6785, + "15": 18.635, + "16": 20.019, + "17": 20.9105 + }, + "end": 22.062 + }, + "name": "cp-line" + }, + "w-s": { + "slice": { + "source": "corpus/s", + "start": 0.0, + "end": 25.34, + "words": "the whole lyric, assembled from corpus", + "dur": 25.34, + "median_f0_hz": 212.8, + "word_f0": [ + { + "t": "sitting", + "start": 0.4, + "end": 1.954, + "f0_hz": 270.3, + "note": "C#4" + }, + { + "t": "curled", + "start": 2.204, + "end": 3.563, + "f0_hz": 217.6, + "note": "A3" + }, + { + "t": "up", + "start": 3.813, + "end": 4.322, + "f0_hz": 203.6, + "note": "G#3" + }, + { + "t": "in", + "start": 4.572, + "end": 5.056, + "f0_hz": 182.8, + "note": "F#3" + }, + { + "t": "myself", + "start": 5.306, + "end": 6.81, + "f0_hz": 209.2, + "note": "G#3" + }, + { + "t": "i", + "start": 7.06, + "end": 7.224, + "f0_hz": 164.0, + "note": "E3" + }, + { + "t": "think", + "start": 7.474, + "end": 8.453, + "f0_hz": 144.4, + "note": "D3" + }, + { + "t": "of", + "start": 8.703, + "end": 9.3395, + "f0_hz": 355.0, + "note": "F4" + }, + { + "t": "a", + "start": 9.5895, + "end": 10.021, + "f0_hz": 358.1, + "note": "F4" + }, + { + "t": "stone", + "start": 10.271, + "end": 12.165, + "f0_hz": 310.9, + "note": "D#4" + }, + { + "t": "just", + "start": 12.415, + "end": 13.449, + "f0_hz": 206.4, + "note": "G#3" + }, + { + "t": "waiting", + "start": 13.699, + "end": 15.6555, + "f0_hz": 218.4, + "note": "A3" + }, + { + "t": "very", + "start": 15.9055, + "end": 16.867, + "f0_hz": 181.8, + "note": "F#3" + }, + { + "t": "patiently", + "start": 17.117, + "end": 19.871, + "f0_hz": 201.0, + "note": "G3" + }, + { + "t": "for", + "start": 20.121, + "end": 20.9125, + "f0_hz": 135.4, + "note": "C#3" + }, + { + "t": "time", + "start": 21.1625, + "end": 22.5615, + "f0_hz": 136.1, + "note": "C#3" + }, + { + "t": "to", + "start": 22.8115, + "end": 24.0255, + "f0_hz": 110.0, + "note": "A2" + }, + { + "t": "pass", + "start": 24.2755, + "end": 25.3395, + "f0_hz": 216.3, + "note": "A3" + } + ] + }, + "align": { + "model": "corpus", + "text": "sitting curled up in myself i think of a stone just waiting very patiently for time to pass", + "words": [ + { + "t": "sitting", + "start": 0.4, + "end": 1.954, + "f0_hz": 270.3, + "note": "C#4" + }, + { + "t": "curled", + "start": 2.204, + "end": 3.563, + "f0_hz": 217.6, + "note": "A3" + }, + { + "t": "up", + "start": 3.813, + "end": 4.322, + "f0_hz": 203.6, + "note": "G#3" + }, + { + "t": "in", + "start": 4.572, + "end": 5.056, + "f0_hz": 182.8, + "note": "F#3" + }, + { + "t": "myself", + "start": 5.306, + "end": 6.81, + "f0_hz": 209.2, + "note": "G#3" + }, + { + "t": "i", + "start": 7.06, + "end": 7.224, + "f0_hz": 164.0, + "note": "E3" + }, + { + "t": "think", + "start": 7.474, + "end": 8.453, + "f0_hz": 144.4, + "note": "D3" + }, + { + "t": "of", + "start": 8.703, + "end": 9.3395, + "f0_hz": 355.0, + "note": "F4" + }, + { + "t": "a", + "start": 9.5895, + "end": 10.021, + "f0_hz": 358.1, + "note": "F4" + }, + { + "t": "stone", + "start": 10.271, + "end": 12.165, + "f0_hz": 310.9, + "note": "D#4" + }, + { + "t": "just", + "start": 12.415, + "end": 13.449, + "f0_hz": 206.4, + "note": "G#3" + }, + { + "t": "waiting", + "start": 13.699, + "end": 15.6555, + "f0_hz": 218.4, + "note": "A3" + }, + { + "t": "very", + "start": 15.9055, + "end": 16.867, + "f0_hz": 181.8, + "note": "F#3" + }, + { + "t": "patiently", + "start": 17.117, + "end": 19.871, + "f0_hz": 201.0, + "note": "G3" + }, + { + "t": "for", + "start": 20.121, + "end": 20.9125, + "f0_hz": 135.4, + "note": "C#3" + }, + { + "t": "time", + "start": 21.1625, + "end": 22.5615, + "f0_hz": 136.1, + "note": "C#3" + }, + { + "t": "to", + "start": 22.8115, + "end": 24.0255, + "f0_hz": 110.0, + "note": "A2" + }, + { + "t": "pass", + "start": 24.2755, + "end": 25.3395, + "f0_hz": 216.3, + "note": "A3" + } + ] + }, + "chart": { + "slice": "s-line", + "beats": 60.0, + "lead": 0.0, + "durs": { + "0": 2.0, + "1": 2.0, + "2": 1.91, + "3": 2.09, + "4": 2.0, + "5": 1.5, + "6": 2.5, + "7": 2.0, + "8": 2.0, + "9": 4.0, + "10": 1.75, + "11": 4.25, + "12": 4.0, + "13": 2.0, + "14": 2.0, + "15": 2.0, + "16": 2.0, + "17": 2.0, + "18": 2.0, + "19": 2.0, + "20": 2.0, + "21": 4.0, + "22": 4.0, + "23": 4.0 + }, + "melody": [ + 7, + 5, + 3, + 2, + 0, + 5, + 2, + -2, + -5, + 12, + 10, + 5, + 2, + 3, + 2, + 0, + -2, + 7, + 5, + 3, + 5, + 7, + 3, + 3 + ], + "sylls": { + "0": [ + [ + null, + "sitting\u00b7a" + ], + [ + 0.665, + "sitting\u00b7b" + ] + ], + "4": [ + [ + null, + "my" + ], + [ + 6.146, + "self" + ] + ], + "11": [ + [ + null, + "wait" + ], + [ + 14.374, + "ing" + ] + ], + "12": [ + [ + null, + "ve" + ], + [ + 16.1305, + "ry" + ] + ], + "13": [ + [ + null, + "pa" + ], + [ + 17.597, + "tient" + ], + [ + 18.377, + "ly" + ] + ] + }, + "times": { + "0": 0.4, + "1": 2.204, + "2": 3.813, + "3": 4.572, + "4": 5.306, + "5": 7.06, + "6": 7.474, + "7": 8.703, + "8": 9.5895, + "9": 10.271, + "10": 12.415, + "11": 13.699, + "12": 15.9055, + "13": 17.117, + "14": 20.121, + "15": 21.1625, + "16": 22.8115, + "17": 24.2755 + }, + "end": 25.3395 + }, + "name": "s-line" + }, + "w-o": { + "slice": { + "source": "corpus/o", + "start": 0.0, + "end": 26.592, + "words": "the whole lyric, assembled from corpus", + "dur": 26.592, + "median_f0_hz": 215.2, + "word_f0": [ + { + "t": "sitting", + "start": 0.4, + "end": 1.7565, + "f0_hz": 265.3, + "note": "C4" + }, + { + "t": "curled", + "start": 2.0065, + "end": 3.148, + "f0_hz": 215.2, + "note": "A3" + }, + { + "t": "up", + "start": 3.398, + "end": 4.1145, + "f0_hz": 201.0, + "note": "G3" + }, + { + "t": "in", + "start": 4.3645, + "end": 4.8785, + "f0_hz": 179.6, + "note": "F3" + }, + { + "t": "myself", + "start": 5.1285, + "end": 6.7175, + "f0_hz": 205.4, + "note": "G#3" + }, + { + "t": "i", + "start": 6.9675, + "end": 7.6165, + "f0_hz": 159.9, + "note": "D#3" + }, + { + "t": "think", + "start": 7.8665, + "end": 8.6755, + "f0_hz": 134.6, + "note": "C3" + }, + { + "t": "of", + "start": 8.9255, + "end": 9.6145, + "f0_hz": 352.5, + "note": "F4" + }, + { + "t": "a", + "start": 9.8645, + "end": 10.2035, + "f0_hz": 351.5, + "note": "F4" + }, + { + "t": "stone", + "start": 10.4535, + "end": 12.1125, + "f0_hz": 309.3, + "note": "D#4" + }, + { + "t": "just", + "start": 12.3625, + "end": 14.464, + "f0_hz": 197.6, + "note": "G3" + }, + { + "t": "waiting", + "start": 14.714, + "end": 16.2505, + "f0_hz": 207.4, + "note": "G#3" + }, + { + "t": "very", + "start": 16.5005, + "end": 18.002, + "f0_hz": 175.5, + "note": "F3" + }, + { + "t": "patiently", + "start": 18.252, + "end": 21.101, + "f0_hz": 241.9, + "note": "B3" + }, + { + "t": "for", + "start": 21.351, + "end": 22.38, + "f0_hz": 270.3, + "note": "C#4" + }, + { + "t": "time", + "start": 22.63, + "end": 23.934, + "f0_hz": 216.2, + "note": "A3" + }, + { + "t": "to", + "start": 24.184, + "end": 24.8555, + "f0_hz": 214.5, + "note": "A3" + }, + { + "t": "pass", + "start": 25.1055, + "end": 26.592, + "f0_hz": 148.7, + "note": "D3" + } + ] + }, + "align": { + "model": "corpus", + "text": "sitting curled up in myself i think of a stone just waiting very patiently for time to pass", + "words": [ + { + "t": "sitting", + "start": 0.4, + "end": 1.7565, + "f0_hz": 265.3, + "note": "C4" + }, + { + "t": "curled", + "start": 2.0065, + "end": 3.148, + "f0_hz": 215.2, + "note": "A3" + }, + { + "t": "up", + "start": 3.398, + "end": 4.1145, + "f0_hz": 201.0, + "note": "G3" + }, + { + "t": "in", + "start": 4.3645, + "end": 4.8785, + "f0_hz": 179.6, + "note": "F3" + }, + { + "t": "myself", + "start": 5.1285, + "end": 6.7175, + "f0_hz": 205.4, + "note": "G#3" + }, + { + "t": "i", + "start": 6.9675, + "end": 7.6165, + "f0_hz": 159.9, + "note": "D#3" + }, + { + "t": "think", + "start": 7.8665, + "end": 8.6755, + "f0_hz": 134.6, + "note": "C3" + }, + { + "t": "of", + "start": 8.9255, + "end": 9.6145, + "f0_hz": 352.5, + "note": "F4" + }, + { + "t": "a", + "start": 9.8645, + "end": 10.2035, + "f0_hz": 351.5, + "note": "F4" + }, + { + "t": "stone", + "start": 10.4535, + "end": 12.1125, + "f0_hz": 309.3, + "note": "D#4" + }, + { + "t": "just", + "start": 12.3625, + "end": 14.464, + "f0_hz": 197.6, + "note": "G3" + }, + { + "t": "waiting", + "start": 14.714, + "end": 16.2505, + "f0_hz": 207.4, + "note": "G#3" + }, + { + "t": "very", + "start": 16.5005, + "end": 18.002, + "f0_hz": 175.5, + "note": "F3" + }, + { + "t": "patiently", + "start": 18.252, + "end": 21.101, + "f0_hz": 241.9, + "note": "B3" + }, + { + "t": "for", + "start": 21.351, + "end": 22.38, + "f0_hz": 270.3, + "note": "C#4" + }, + { + "t": "time", + "start": 22.63, + "end": 23.934, + "f0_hz": 216.2, + "note": "A3" + }, + { + "t": "to", + "start": 24.184, + "end": 24.8555, + "f0_hz": 214.5, + "note": "A3" + }, + { + "t": "pass", + "start": 25.1055, + "end": 26.592, + "f0_hz": 148.7, + "note": "D3" + } + ] + }, + "chart": { + "slice": "o-line", + "beats": 60.0, + "lead": 0.0, + "durs": { + "0": 2.0, + "1": 2.0, + "2": 1.91, + "3": 2.09, + "4": 2.0, + "5": 1.5, + "6": 2.5, + "7": 2.0, + "8": 2.0, + "9": 4.0, + "10": 1.75, + "11": 4.25, + "12": 4.0, + "13": 2.0, + "14": 2.0, + "15": 2.0, + "16": 2.0, + "17": 2.0, + "18": 2.0, + "19": 2.0, + "20": 2.0, + "21": 4.0, + "22": 4.0, + "23": 4.0 + }, + "melody": [ + 7, + 5, + 3, + 2, + 0, + 5, + 2, + -2, + -5, + 12, + 10, + 5, + 2, + 3, + 2, + 0, + -2, + 7, + 5, + 3, + 5, + 7, + 3, + 3 + ], + "sylls": { + "0": [ + [ + null, + "sitting\u00b7a" + ], + [ + 1.445, + "sitting\u00b7b" + ] + ], + "4": [ + [ + null, + "my" + ], + [ + 5.8735, + "self" + ] + ], + "11": [ + [ + null, + "wait" + ], + [ + 15.894, + "ing" + ] + ], + "12": [ + [ + null, + "ve" + ], + [ + 17.6755, + "ry" + ] + ], + "13": [ + [ + null, + "pa" + ], + [ + 20.062, + "tient" + ], + [ + 20.672, + "ly" + ] + ] + }, + "times": { + "0": 0.4, + "1": 2.0065, + "2": 3.398, + "3": 4.3645, + "4": 5.1285, + "5": 6.9675, + "6": 7.8665, + "7": 8.9255, + "8": 9.8645, + "9": 10.4535, + "10": 12.3625, + "11": 14.714, + "12": 16.5005, + "13": 18.252, + "14": 21.351, + "15": 22.63, + "16": 24.184, + "17": 25.1055 + }, + "end": 26.592 + }, + "name": "o-line" + } +} \ No newline at end of file diff --git a/pop/loner/samples/.takes.json b/pop/loner/samples/.takes.json new file mode 100644 --- /dev/null +++ b/pop/loner/samples/.takes.json @@ -0,0 +1,625 @@ +{ + "a": [ + { + "cents": -471, + "dur": 0.8, + "end": 2.42, + "note": "G#3", + "peak_db": -7.1, + "slice": "f-of-a-stone", + "st": 10.29, + "start": 1.62, + "take": "f" + }, + { + "cents": -469, + "dur": 0.8, + "end": 9.82, + "note": "G#3", + "peak_db": -8.0, + "slice": "f-whole-line", + "st": 10.31, + "start": 9.02, + "take": "f" + }, + { + "cents": -521, + "dur": 0.76, + "end": 0.76, + "note": "A#4", + "peak_db": -11.6, + "slice": "n-stone-waiting", + "st": 11.79, + "start": 0.0, + "take": "n" + } + ], + "curled": [ + { + "cents": -524, + "dur": 0.92, + "end": 2.46, + "note": "C#3", + "peak_db": -7.8, + "slice": "f-sitting-curled", + "st": 2.76, + "start": 1.54, + "take": "f" + }, + { + "cents": -523, + "dur": 1.04, + "end": 2.66, + "note": "C#3", + "peak_db": -9.2, + "slice": "f-whole-line", + "st": 2.77, + "start": 1.62, + "take": "f" + }, + { + "cents": -537, + "dur": 0.8, + "end": 1.58, + "note": "C#3", + "peak_db": -9.3, + "slice": "n-getting-curled", + "st": 2.63, + "start": 0.78, + "take": "n" + } + ], + "for": [ + { + "cents": -480, + "dur": 0.62, + "end": 0.62, + "note": "D#3", + "peak_db": -6.5, + "slice": "f-for-time-to-pass", + "st": 5.2, + "start": 0.0, + "take": "f" + }, + { + "cents": -487, + "dur": 1.9, + "end": 19.38, + "note": "C#3", + "peak_db": -7.0, + "slice": "f-whole-line", + "st": 3.13, + "start": 17.48, + "take": "f" + } + ], + "getting": [ + { + "cents": -534, + "dur": 0.78, + "end": 0.78, + "note": "D#3", + "peak_db": -12.9, + "slice": "n-getting-curled", + "st": 4.66, + "start": 0.0, + "take": "n" + } + ], + "i": [ + { + "cents": -501, + "dur": 0.64, + "end": 0.64, + "note": "G#2", + "peak_db": -8.2, + "slice": "f-i-think", + "st": -2.01, + "start": 0.0, + "take": "f" + }, + { + "cents": -501, + "dur": 0.94, + "end": 6.48, + "note": "G#2", + "peak_db": -13.3, + "slice": "f-whole-line", + "st": -2.01, + "start": 5.54, + "take": "f" + }, + { + "cents": -540, + "dur": 0.78, + "end": 4.78, + "note": "G#2", + "peak_db": -7.1, + "slice": "n-getting-curled", + "st": -2.4, + "start": 4.0, + "take": "n" + } + ], + "in": [ + { + "cents": -499, + "dur": 0.72, + "end": 3.86, + "note": "A#3", + "peak_db": -9.5, + "slice": "f-sitting-curled", + "st": 0.01, + "start": 3.14, + "take": "f" + }, + { + "cents": -498, + "dur": 0.8, + "end": 4.16, + "note": "A#3", + "peak_db": -7.4, + "slice": "f-whole-line", + "st": 0.02, + "start": 3.36, + "take": "f" + }, + { + "cents": -496, + "dur": 0.62, + "end": 2.76, + "note": "A#3", + "peak_db": -13.2, + "slice": "n-getting-curled", + "st": 0.04, + "start": 2.14, + "take": "n" + } + ], + "just": [ + { + "cents": -586, + "dur": 1.46, + "end": 1.46, + "note": "C3", + "peak_db": -5.9, + "slice": "f-just-waiting", + "st": 2.14, + "start": 0.0, + "take": "f" + }, + { + "cents": -585, + "dur": 1.265, + "end": 12.6, + "note": "C3", + "peak_db": -8.4, + "slice": "f-whole-line", + "st": 2.15, + "start": 11.335, + "take": "f" + }, + { + "cents": -583, + "dur": 1.88, + "end": 3.94, + "note": "D3", + "peak_db": -10.2, + "slice": "n-stone-waiting", + "st": 4.17, + "start": 2.06, + "take": "n" + } + ], + "myself": [ + { + "cents": -538, + "dur": 1.36, + "end": 5.22, + "note": "D#3", + "peak_db": -6.0, + "slice": "f-sitting-curled", + "st": 4.62, + "start": 3.86, + "take": "f" + }, + { + "cents": -542, + "dur": 1.38, + "end": 5.54, + "note": "D#3", + "peak_db": -9.0, + "slice": "f-whole-line", + "st": 4.58, + "start": 4.16, + "take": "f" + }, + { + "cents": -401, + "dur": 1.24, + "end": 4.0, + "note": "D3", + "peak_db": -6.0, + "slice": "n-getting-curled", + "st": 3.99, + "start": 2.76, + "take": "n" + } + ], + "of": [ + { + "cents": -511, + "dur": 1.62, + "end": 1.62, + "note": "A#4", + "peak_db": -6.4, + "slice": "f-of-a-stone", + "st": 11.89, + "start": 0.0, + "take": "f" + }, + { + "cents": -513, + "dur": 1.94, + "end": 9.02, + "note": "A#4", + "peak_db": -7.4, + "slice": "f-whole-line", + "st": 11.87, + "start": 7.08, + "take": "f" + } + ], + "pass": [ + { + "cents": -499, + "dur": 1.86, + "end": 5.7, + "note": "C#3", + "peak_db": -8.2, + "slice": "f-for-time-to-pass", + "st": 3.01, + "start": 3.84, + "take": "f" + }, + { + "cents": -498, + "dur": 1.56, + "end": 24.42, + "note": "C#3", + "peak_db": -8.7, + "slice": "f-whole-line", + "st": 3.02, + "start": 22.86, + "take": "f" + }, + { + "cents": -524, + "dur": 0.92, + "end": 3.56, + "note": "C#3", + "peak_db": -5.9, + "slice": "n-for-time-to-pass", + "st": 2.76, + "start": 2.64, + "take": "n" + } + ], + "patiently": [ + { + "cents": -490, + "dur": 1.52, + "end": 2.92, + "note": "F3", + "peak_db": -5.3, + "slice": "f-very-patiently", + "st": 7.1, + "start": 1.4, + "take": "f" + }, + { + "cents": -490, + "dur": 1.3, + "end": 17.48, + "note": "F3", + "peak_db": -5.3, + "slice": "f-whole-line", + "st": 7.1, + "start": 16.18, + "take": "f" + }, + { + "cents": -580, + "dur": 1.18, + "end": 8.04, + "note": "E3", + "peak_db": -5.7, + "slice": "n-stone-waiting", + "st": 6.2, + "start": 6.86, + "take": "n" + } + ], + "sitting": [ + { + "cents": -570, + "dur": 1.54, + "end": 1.54, + "note": "E3", + "peak_db": -5.2, + "slice": "f-sitting-curled", + "st": 6.3, + "start": 0.0, + "take": "f" + }, + { + "cents": -531, + "dur": 1.4, + "end": 1.62, + "note": "F3", + "peak_db": -6.6, + "slice": "f-whole-line", + "st": 6.69, + "start": 0.22, + "take": "f" + } + ], + "stone": [ + { + "cents": -497, + "dur": 0.74, + "end": 3.16, + "note": "D#3", + "peak_db": -7.6, + "slice": "f-of-a-stone", + "st": 5.03, + "start": 2.42, + "take": "f" + }, + { + "cents": -494, + "dur": 0.88, + "end": 10.7, + "note": "D#3", + "peak_db": -8.5, + "slice": "f-whole-line", + "st": 5.06, + "start": 9.82, + "take": "f" + }, + { + "cents": -595, + "dur": 1.3, + "end": 2.06, + "note": "G3", + "peak_db": -4.5, + "slice": "n-stone-waiting", + "st": 9.05, + "start": 0.76, + "take": "n" + } + ], + "the": [ + { + "cents": -533, + "dur": 0.16, + "end": 0.16, + "note": "D#3", + "peak_db": -8.8, + "slice": "n-for-time-to-pass", + "st": 4.67, + "start": 0.0, + "take": "n" + } + ], + "think": [ + { + "cents": -477, + "dur": 0.68, + "end": 1.32, + "note": "F2", + "peak_db": -10.5, + "slice": "f-i-think", + "st": -4.77, + "start": 0.64, + "take": "f" + }, + { + "cents": -490, + "dur": 0.6, + "end": 7.08, + "note": "F2", + "peak_db": -15.6, + "slice": "f-whole-line", + "st": -4.9, + "start": 6.48, + "take": "f" + }, + { + "cents": -537, + "dur": 0.32, + "end": 5.1, + "note": "F2", + "peak_db": -14.0, + "slice": "n-getting-curled", + "st": -5.37, + "start": 4.78, + "take": "n" + } + ], + "time": [ + { + "cents": -489, + "dur": 1.44, + "end": 2.06, + "note": "F3", + "peak_db": -7.4, + "slice": "f-for-time-to-pass", + "st": 7.11, + "start": 0.62, + "take": "f" + }, + { + "cents": -488, + "dur": 1.34, + "end": 20.72, + "note": "F3", + "peak_db": -7.9, + "slice": "f-whole-line", + "st": 7.12, + "start": 19.38, + "take": "f" + }, + { + "cents": -528, + "dur": 0.94, + "end": 1.1, + "note": "F3", + "peak_db": -7.9, + "slice": "n-for-time-to-pass", + "st": 6.72, + "start": 0.16, + "take": "n" + } + ], + "to": [ + { + "cents": -496, + "dur": 1.78, + "end": 3.84, + "note": "C#3", + "peak_db": -11.5, + "slice": "f-for-time-to-pass", + "st": 3.04, + "start": 2.06, + "take": "f" + }, + { + "cents": -496, + "dur": 2.14, + "end": 22.86, + "note": "C#3", + "peak_db": -12.0, + "slice": "f-whole-line", + "st": 3.04, + "start": 20.72, + "take": "f" + }, + { + "cents": -539, + "dur": 1.54, + "end": 2.64, + "note": "C#3", + "peak_db": -8.9, + "slice": "n-for-time-to-pass", + "st": 2.61, + "start": 1.1, + "take": "n" + } + ], + "up": [ + { + "cents": -506, + "dur": 0.68, + "end": 3.14, + "note": "C3", + "peak_db": -8.5, + "slice": "f-sitting-curled", + "st": 1.94, + "start": 2.46, + "take": "f" + }, + { + "cents": -504, + "dur": 0.7, + "end": 3.36, + "note": "C3", + "peak_db": -10.0, + "slice": "f-whole-line", + "st": 1.96, + "start": 2.66, + "take": "f" + }, + { + "cents": -526, + "dur": 0.56, + "end": 2.14, + "note": "C3", + "peak_db": -12.9, + "slice": "n-getting-curled", + "st": 1.74, + "start": 1.58, + "take": "n" + } + ], + "very": [ + { + "cents": -505, + "dur": 1.4, + "end": 1.4, + "note": "A#3", + "peak_db": -10.2, + "slice": "f-very-patiently", + "st": -0.05, + "start": 0.0, + "take": "f" + }, + { + "cents": -498, + "dur": 1.92, + "end": 16.18, + "note": "A#3", + "peak_db": -10.2, + "slice": "f-whole-line", + "st": 0.02, + "start": 14.26, + "take": "f" + }, + { + "cents": -541, + "dur": 1.44, + "end": 6.86, + "note": "A#3", + "peak_db": -10.3, + "slice": "n-stone-waiting", + "st": -0.41, + "start": 5.42, + "take": "n" + } + ], + "waiting": [ + { + "cents": -510, + "dur": 1.48, + "end": 2.94, + "note": "C#3", + "peak_db": -5.4, + "slice": "f-just-waiting", + "st": 2.9, + "start": 1.46, + "take": "f" + }, + { + "cents": -511, + "dur": 1.66, + "end": 14.26, + "note": "C#3", + "peak_db": -7.9, + "slice": "f-whole-line", + "st": 2.89, + "start": 12.6, + "take": "f" + }, + { + "cents": -513, + "dur": 1.48, + "end": 5.42, + "note": "C#3", + "peak_db": -5.7, + "slice": "n-stone-waiting", + "st": 2.87, + "start": 3.94, + "take": "n" + } + ] +} \ No newline at end of file diff --git a/pop/loner/vox-dub/.carrier-da.mp3 b/pop/loner/vox-dub/.carrier-da.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/.carrier-da.mp3 diff --git a/pop/loner/vox-dub/.carrier-es.mp3 b/pop/loner/vox-dub/.carrier-es.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/.carrier-es.mp3 diff --git a/pop/loner/vox-dub/.carrier-fr.mp3 b/pop/loner/vox-dub/.carrier-fr.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/.carrier-fr.mp3 diff --git a/pop/loner/vox-dub/.carrier-hi.mp3 b/pop/loner/vox-dub/.carrier-hi.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/.carrier-hi.mp3 diff --git a/pop/loner/vox-dub/.carrier-ru.mp3 b/pop/loner/vox-dub/.carrier-ru.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/.carrier-ru.mp3 diff --git a/pop/loner/vox-dub/.dub.json b/pop/loner/vox-dub/.dub.json new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/.dub.json @@ -0,0 +1,29 @@ +{ + "da": { + "consent": "Camille Klein (@cksuperstore), via @jeffrey", + "dubbing_id": "RGpvxSGiNvpqkm40Ivcn", + "engine": "elevenlabs/dubbing", + "language": "Danish", + "note": "SYNTHETIC VOICE \u2014 her voice model singing a translation; not a take she performed. Label on any release.", + "source": "samples/f-whole-line.wav", + "synthetic": true + }, + "es": { + "consent": "Camille Klein (@cksuperstore), via @jeffrey", + "dubbing_id": "hvb44SHj5ZVljGDuzQGY", + "engine": "elevenlabs/dubbing", + "language": "Spanish", + "note": "SYNTHETIC VOICE \u2014 her voice model singing a translation; not a take she performed. Label on any release.", + "source": "samples/f-whole-line.wav", + "synthetic": true + }, + "fr": { + "consent": "Camille Klein (@cksuperstore), via @jeffrey", + "dubbing_id": "XoHEYSdVJyHdfciUMNSH", + "engine": "elevenlabs/dubbing", + "language": "French", + "note": "SYNTHETIC VOICE \u2014 her voice model singing a translation; not a take she performed. Label on any release.", + "source": "samples/f-whole-line.wav", + "synthetic": true + } +} \ No newline at end of file diff --git a/pop/loner/vox-dub/.voice.json b/pop/loner/vox-dub/.voice.json new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/.voice.json @@ -0,0 +1,26 @@ +{ + "voice_id": "UzFG8DoU8szypvfbc4Rl", + "name": "Camille Klein \u00b7 loner IVC (consented)", + "sources": [ + "6955972523087416582.mp3", + "6974224412614675718.mp3", + "6988954628167585030.mp3", + "6994920700746206470.mp3", + "6996714516234947845.mp3", + "7021262898479549702.mp3", + "7076361738786213166.mp3", + "7100768279983181099.mp3", + "7108062006980201771.mp3", + "7168612922757877035.mp3", + "7168939549962308906.mp3", + "7173130377798716714.mp3", + "7226114462145695018.mp3", + "7226226683349798190.mp3", + "7226527805008268586.mp3", + "7230893600219942186.mp3", + "7233760335990230315.mp3", + "7233886426910330158.mp3" + ], + "synthetic": true, + "consent": "Camille Klein (@cksuperstore), via @jeffrey 2026-08-19" +} \ No newline at end of file diff --git a/pop/loner/vox-dub/.words.json b/pop/loner/vox-dub/.words.json new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/.words.json @@ -0,0 +1,681 @@ +{ + "fr": [ + { + "t": "Assise", + "start": 0.079, + "end": 0.5 + }, + { + "t": "recroquevillée", + "start": 0.56, + "end": 1.179 + }, + { + "t": "en", + "start": 1.22, + "end": 1.279 + }, + { + "t": "moi-même,", + "start": 1.319, + "end": 1.719 + }, + { + "t": "je", + "start": 2.379, + "end": 2.5 + }, + { + "t": "pense", + "start": 2.539, + "end": 2.759 + }, + { + "t": "à", + "start": 2.819, + "end": 2.839 + }, + { + "t": "une", + "start": 2.899, + "end": 3.019 + }, + { + "t": "pierre", + "start": 3.059, + "end": 3.439 + }, + { + "t": "qui", + "start": 3.959, + "end": 4.059 + }, + { + "t": "attend", + "start": 4.119, + "end": 4.42 + }, + { + "t": "très", + "start": 4.46, + "end": 4.639 + }, + { + "t": "patiemment", + "start": 4.699, + "end": 5.179 + }, + { + "t": "que", + "start": 5.239, + "end": 5.279 + }, + { + "t": "le", + "start": 5.339, + "end": 5.38 + }, + { + "t": "temps", + "start": 5.46, + "end": 5.639 + }, + { + "t": "passe", + "start": 5.699, + "end": 6.039 + } + ], + "es": [ + { + "t": "Sentada", + "start": 0.119, + "end": 0.56 + }, + { + "t": "acurrucada", + "start": 0.579, + "end": 1.159 + }, + { + "t": "en", + "start": 1.179, + "end": 1.259 + }, + { + "t": "mí", + "start": 1.279, + "end": 1.379 + }, + { + "t": "misma,", + "start": 1.419, + "end": 1.759 + }, + { + "t": "pienso", + "start": 2.259, + "end": 2.559 + }, + { + "t": "en", + "start": 2.599, + "end": 2.659 + }, + { + "t": "una", + "start": 2.7, + "end": 2.799 + }, + { + "t": "piedra", + "start": 2.899, + "end": 3.259 + }, + { + "t": "que", + "start": 3.879, + "end": 3.98 + }, + { + "t": "espera", + "start": 4.059, + "end": 4.439 + }, + { + "t": "muy", + "start": 4.48, + "end": 4.579 + }, + { + "t": "pacientemente", + "start": 4.659, + "end": 5.38 + }, + { + "t": "a", + "start": 5.42, + "end": 5.46 + }, + { + "t": "que", + "start": 5.539, + "end": 5.579 + }, + { + "t": "pase", + "start": 5.679, + "end": 5.899 + }, + { + "t": "el", + "start": 5.92, + "end": 6.019 + }, + { + "t": "tiempo", + "start": 6.059, + "end": 6.439 + } + ], + "da": [ + { + "t": "Jeg", + "start": 0.079, + "end": 0.159 + }, + { + "t": "sidder", + "start": 0.239, + "end": 0.459 + }, + { + "t": "krøllet", + "start": 0.519, + "end": 0.819 + }, + { + "t": "sammen", + "start": 0.859, + "end": 1.1 + }, + { + "t": "i", + "start": 1.139, + "end": 1.179 + }, + { + "t": "mig", + "start": 1.22, + "end": 1.36 + }, + { + "t": "selv.", + "start": 1.399, + "end": 1.639 + }, + { + "t": "Jeg", + "start": 2.159, + "end": 2.259 + }, + { + "t": "tænker", + "start": 2.299, + "end": 2.539 + }, + { + "t": "på", + "start": 2.579, + "end": 2.639 + }, + { + "t": "en", + "start": 2.659, + "end": 2.759 + }, + { + "t": "sten,", + "start": 2.799, + "end": 3.079 + }, + { + "t": "der", + "start": 3.24, + "end": 3.319 + }, + { + "t": "bare", + "start": 3.359, + "end": 3.46 + }, + { + "t": "venter", + "start": 3.519, + "end": 3.779 + }, + { + "t": "meget", + "start": 3.819, + "end": 3.979 + }, + { + "t": "tålmodigt", + "start": 4.039, + "end": 4.5 + }, + { + "t": "på,", + "start": 4.559, + "end": 4.679 + }, + { + "t": "at", + "start": 4.92, + "end": 5.0 + }, + { + "t": "tiden", + "start": 5.079, + "end": 5.299 + }, + { + "t": "går", + "start": 5.339, + "end": 5.559 + } + ], + "ru": [ + { + "t": "Сижу,", + "start": 0.119, + "end": 0.5 + }, + { + "t": "свернувшись", + "start": 0.659, + "end": 1.24 + }, + { + "t": "в", + "start": 1.279, + "end": 1.339 + }, + { + "t": "себе.", + "start": 1.399, + "end": 1.679 + }, + { + "t": "Я", + "start": 2.22, + "end": 2.259 + }, + { + "t": "думаю", + "start": 2.339, + "end": 2.559 + }, + { + "t": "о", + "start": 2.599, + "end": 2.7 + }, + { + "t": "камне,", + "start": 2.759, + "end": 3.099 + }, + { + "t": "который", + "start": 3.279, + "end": 3.599 + }, + { + "t": "очень", + "start": 3.679, + "end": 3.899 + }, + { + "t": "терпеливо", + "start": 3.939, + "end": 4.38 + }, + { + "t": "ждет,", + "start": 4.42, + "end": 4.699 + }, + { + "t": "пока", + "start": 4.859, + "end": 5.039 + }, + { + "t": "пройдет", + "start": 5.119, + "end": 5.42 + }, + { + "t": "время", + "start": 5.46, + "end": 5.779 + } + ], + "hi": [ + { + "t": "अपने", + "start": 0.059, + "end": 0.319 + }, + { + "t": "भीतर", + "start": 0.359, + "end": 0.699 + }, + { + "t": "सिमटी", + "start": 0.74, + "end": 1.019 + }, + { + "t": "हुई", + "start": 1.079, + "end": 1.199 + }, + { + "t": "बैठी", + "start": 1.24, + "end": 1.459 + }, + { + "t": "हूँ।", + "start": 1.539, + "end": 2.22 + }, + { + "t": "मैं", + "start": 2.259, + "end": 2.359 + }, + { + "t": "एक", + "start": 2.399, + "end": 2.539 + }, + { + "t": "पत्थर", + "start": 2.579, + "end": 2.819 + }, + { + "t": "के", + "start": 2.879, + "end": 2.98 + }, + { + "t": "बारे", + "start": 3.019, + "end": 3.199 + }, + { + "t": "में", + "start": 3.22, + "end": 3.339 + }, + { + "t": "सोचती", + "start": 3.359, + "end": 3.659 + }, + { + "t": "हूँ", + "start": 3.72, + "end": 3.819 + }, + { + "t": "जो", + "start": 4.46, + "end": 4.559 + }, + { + "t": "बहुत", + "start": 4.599, + "end": 4.839 + }, + { + "t": "धीरज", + "start": 4.88, + "end": 5.179 + }, + { + "t": "से", + "start": 5.239, + "end": 5.359 + }, + { + "t": "समय", + "start": 5.4, + "end": 5.619 + }, + { + "t": "के", + "start": 5.659, + "end": 5.759 + }, + { + "t": "बीतने", + "start": 5.799, + "end": 6.079 + }, + { + "t": "का", + "start": 6.139, + "end": 6.179 + }, + { + "t": "इंतजार", + "start": 6.239, + "end": 6.599 + }, + { + "t": "कर", + "start": 6.639, + "end": 6.739 + }, + { + "t": "रहा", + "start": 6.779, + "end": 6.94 + }, + { + "t": "है।", + "start": 7.0, + "end": 7.179 + } + ], + "s-whole-line": [ + { + "t": "Sitting", + "start": 0.439, + "end": 1.719 + }, + { + "t": "curled", + "start": 1.939, + "end": 2.72 + }, + { + "t": "up", + "start": 2.819, + "end": 3.359 + }, + { + "t": "in", + "start": 3.439, + "end": 3.859 + }, + { + "t": "myself,", + "start": 4.039, + "end": 5.239 + }, + { + "t": "I", + "start": 5.519, + "end": 5.759 + }, + { + "t": "think", + "start": 5.94, + "end": 6.279 + }, + { + "t": "of", + "start": 6.699, + "end": 7.899 + }, + { + "t": "a", + "start": 8.099, + "end": 8.3 + }, + { + "t": "stone", + "start": 8.5, + "end": 9.22 + }, + { + "t": "just", + "start": 9.96, + "end": 10.679 + }, + { + "t": "waiting", + "start": 11.259, + "end": 12.46 + }, + { + "t": "very", + "start": 12.619, + "end": 13.479 + }, + { + "t": "patiently", + "start": 13.88, + "end": 15.699 + }, + { + "t": "for", + "start": 15.899, + "end": 16.379 + }, + { + "t": "time", + "start": 16.6, + "end": 17.319 + }, + { + "t": "to", + "start": 17.859, + "end": 18.52 + }, + { + "t": "pass", + "start": 19.119, + "end": 20.159 + } + ], + "o-whole-line": [ + { + "t": "Sitting", + "start": 0.14, + "end": 1.459 + }, + { + "t": "curled", + "start": 1.639, + "end": 2.46 + }, + { + "t": "up", + "start": 2.599, + "end": 3.119 + }, + { + "t": "in", + "start": 3.259, + "end": 3.539 + }, + { + "t": "myself,", + "start": 3.819, + "end": 5.119 + }, + { + "t": "I", + "start": 5.299, + "end": 5.619 + }, + { + "t": "think", + "start": 5.819, + "end": 6.259 + }, + { + "t": "of", + "start": 6.599, + "end": 7.899 + }, + { + "t": "a", + "start": 8.0, + "end": 8.239 + }, + { + "t": "stone", + "start": 8.479, + "end": 9.22 + }, + { + "t": "just", + "start": 9.96, + "end": 10.699 + }, + { + "t": "waiting", + "start": 11.319, + "end": 12.559 + }, + { + "t": "very", + "start": 12.719, + "end": 13.579 + }, + { + "t": "patiently", + "start": 13.96, + "end": 15.779 + }, + { + "t": "for", + "start": 16.0, + "end": 16.42 + }, + { + "t": "time", + "start": 16.659, + "end": 17.42 + }, + { + "t": "to", + "start": 17.94, + "end": 18.52 + }, + { + "t": "pass", + "start": 19.079, + "end": 20.339 + } + ] +} \ No newline at end of file diff --git a/pop/loner/vox-dub/spoken-da.mp3 b/pop/loner/vox-dub/spoken-da.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/spoken-da.mp3 diff --git a/pop/loner/vox-dub/spoken-es.mp3 b/pop/loner/vox-dub/spoken-es.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/spoken-es.mp3 diff --git a/pop/loner/vox-dub/spoken-fr.mp3 b/pop/loner/vox-dub/spoken-fr.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/spoken-fr.mp3 diff --git a/pop/loner/vox-dub/sts-da.mp3 b/pop/loner/vox-dub/sts-da.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/sts-da.mp3 diff --git a/pop/loner/vox-dub/sts-es.mp3 b/pop/loner/vox-dub/sts-es.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/sts-es.mp3 diff --git a/pop/loner/vox-dub/sts-fr.mp3 b/pop/loner/vox-dub/sts-fr.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/sts-fr.mp3 diff --git a/pop/loner/vox-dub/sts-hi.mp3 b/pop/loner/vox-dub/sts-hi.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/sts-hi.mp3 diff --git a/pop/loner/vox-dub/sts-ru.mp3 b/pop/loner/vox-dub/sts-ru.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/sts-ru.mp3 diff --git a/pop/loner/vox-dub/whole-line-dub-da.mp3 b/pop/loner/vox-dub/whole-line-dub-da.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/whole-line-dub-da.mp3 diff --git a/pop/loner/vox-dub/whole-line-dub-es.mp3 b/pop/loner/vox-dub/whole-line-dub-es.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/whole-line-dub-es.mp3 diff --git a/pop/loner/vox-dub/whole-line-dub-fr.mp3 b/pop/loner/vox-dub/whole-line-dub-fr.mp3 new file mode 100644 --- /dev/null +++ b/pop/loner/vox-dub/whole-line-dub-fr.mp3 diff --git a/pop/loner/vox4/.chart.json b/pop/loner/vox4/.chart.json --- a/pop/loner/vox4/.chart.json +++ b/pop/loner/vox4/.chart.json @@ -1,59 +1,67 @@ { "w-whole-line": { - "leadIn": 0.04, - "beats": 59.0, + "leadIn": 0.33, + "beats": 60.0, "voiced": [ [ - -0.0407, + -0.183, 7.9605 ], [ 8.0012, - 11.5087 + 12.139 ], [ - 11.529, - 12.9218 + 12.1695, + 13.8978 ], [ - 12.9523, - 16.8258 + 13.9385, + 17.8222 ], [ - 16.9885, - 23.607 + 17.9848, + 23.8002 ], [ - 23.9527, - 30.8558 + 23.8307, + 24.4813 ], [ - 30.9575, - 38.6537 + 24.5322, + 27.5923 ], [ - 38.7655, - 40.87 + 27.816, + 31.8522 ], [ - 40.9412, - 42.8932 + 31.964, + 39.6093 ], [ - 42.9847, - 45.9432 + 39.833, + 42.4052 ], [ - 45.9838, - 47.824 + 42.4458, + 43.6557 ], [ - 47.8647, - 55.5913 + 43.6963, + 45.9635 ], [ - 55.7743, - 59.8105 + 45.994, + 48.2205 + ], + [ + 48.2815, + 55.4795 + ], + [ + 55.815, + 59.8715 ] ], "notes": [ @@ -62,177 +70,205 @@ "beat": 0.0, "dur": 2.0, "st": 7, "t": "sitting\u00b7a", - "lead": 0.0813 + "lead": 0.671, + "w": 0 }, { "beat": 2.0, "dur": 2.0, "st": 5, "t": "sitting\u00b7b", - "lead": 0.0 + "lead": 0.0, + "w": 0 }, { "beat": 4.0, "dur": 1.91, "st": 3, "t": "curled", - "lead": 0.0 + "lead": 0.0, + "w": 1 }, { "beat": 5.91, "dur": 2.09, "st": 2, "t": "up", - "lead": 0.0 + "lead": 0.0, + "w": 2 }, { "beat": 8.0, - "dur": 1.5, + "dur": 2.0, "st": 0, "t": "in", - "lead": 0.0 + "lead": 0.0, + "w": 3 }, { - "beat": 9.5, + "beat": 10.0, "dur": 1.5, "st": 5, "t": "my", - "lead": 0.0 + "lead": 0.0, + "w": 4 }, { - "beat": 11.0, - "dur": 2.0, + "beat": 11.5, + "dur": 2.5, "st": 2, "t": "self", - "lead": 0.0 + "lead": 0.0, + "w": 4 }, { - "beat": 13.0, + "beat": 14.0, "dur": 2.0, "st": -2, "t": "i", - "lead": 0.0 + "lead": 0.0, + "w": 5 }, { - "beat": 15.0, + "beat": 16.0, "dur": 2.0, "st": -5, "t": "think", - "lead": 0.0 + "lead": 0.0, + "w": 6 }, { - "beat": 17.0, + "beat": 18.0, "dur": 4.0, "st": 12, "t": "of", - "lead": 0.0203 + "lead": 0.0203, + "w": 7 }, { - "beat": 21.0, - "dur": 3.0, + "beat": 22.0, + "dur": 1.75, "st": 10, "t": "a", - "lead": 0.0 + "lead": 0.0, + "w": 8 }, { - "beat": 24.0, - "dur": 3.0, + "beat": 23.75, + "dur": 4.25, "st": 5, "t": "stone", - "lead": 0.1017 + "lead": 0.0, + "w": 9 }, { - "beat": 27.0, + "beat": 28.0, "dur": 4.0, "st": 2, "t": "just", - "lead": 0.0 + "lead": 0.4067, + "w": 10 }, { - "beat": 31.0, + "beat": 32.0, "dur": 2.0, "st": 3, "t": "wait", - "lead": 0.0813 + "lead": 0.0813, + "w": 11 }, { - "beat": 33.0, + "beat": 34.0, "dur": 2.0, "st": 2, "t": "ing", - "lead": 0.0 + "lead": 0.0, + "w": 11 }, { - "beat": 35.0, + "beat": 36.0, "dur": 2.0, "st": 0, "t": "ve", - "lead": 0.0 + "lead": 0.0, + "w": 12 }, { - "beat": 37.0, + "beat": 38.0, "dur": 2.0, "st": -2, "t": "ry", - "lead": 0.0 + "lead": 0.0, + "w": 12 }, { - "beat": 39.0, + "beat": 40.0, "dur": 2.0, "st": 7, "t": "pa", - "lead": 0.0 + "lead": 0.3253, + "w": 13 }, { - "beat": 41.0, - "dur": 2.5, + "beat": 42.0, + "dur": 2.0, "st": 5, "t": "tient", - "lead": 0.122 + "lead": 0.0, + "w": 13 }, { - "beat": 43.5, - "dur": 2.5, + "beat": 44.0, + "dur": 2.0, "st": 3, "t": "ly", - "lead": 0.0 + "lead": 0.0, + "w": 13 }, { "beat": 46.0, "dur": 2.0, "st": 5, "t": "for", - "lead": 0.0 + "lead": 0.0, + "w": 14 }, { "beat": 48.0, "dur": 4.0, "st": 7, "t": "time", - "lead": 0.0 + "lead": 0.0, + "w": 15 }, { "beat": 52.0, "dur": 4.0, "st": 3, "t": "to", - "lead": 0.0 + "lead": 0.0, + "w": 16 }, { "beat": 56.0, - "dur": 3.0, + "dur": 4.0, "st": 3, "t": "pass", - "lead": 0.0 + "lead": 0.5185, + "w": 17 } ] }, "w-sitting-curled": { - "leadIn": 0.02, + "leadIn": 0.04, "beats": 11.0, "voiced": [ [ - 0.0, + -0.0407, + 6.466 + ], + [ + 6.4965, 9.8617 ], [ @@ -250,44 +286,49 @@ "beat": 0.0, "dur": 3.0, "st": 6, "t": "Sitting", - "lead": 0.0407 + "lead": 0.0813, + "w": 0 }, { "beat": 3.0, "dur": 2.0, "st": 3, "t": "curled", - "lead": 0.0 + "lead": 0.0, + "w": 1 }, { "beat": 5.0, "dur": 1.5, "st": 2, "t": "up", - "lead": 0.0 + "lead": 0.0, + "w": 2 }, { "beat": 6.5, "dur": 1.5, "st": 0, "t": "in", - "lead": 0.0 + "lead": 0.0, + "w": 3 }, { "beat": 8.0, "dur": 3.0, "st": 5, "t": "myself", - "lead": 0.0 + "lead": 0.0, + "w": 4 } ] }, "w-i-think": { - "leadIn": 0.02, + "leadIn": 0.04, "beats": 3.5, "voiced": [ [ - 0.0, + -0.0407, 3.4567 ], [ @@ -305,14 +346,16 @@ "beat": 0.0, "dur": 2.0, "st": -2, "t": "I", - "lead": 0.0407 + "lead": 0.0813, + "w": 0 }, { "beat": 2.0, "dur": 1.5, "st": -5, "t": "think", - "lead": 0.0 + "lead": 0.0, + "w": 1 } ] }, @@ -322,10 +365,10 @@ "beats": 8.0, "voiced": [ [ 0.0, - 5.8052 + 5.7645 ], [ - 5.9983, + 5.9475, 8.3265 ] ], @@ -335,31 +378,34 @@ "beat": 0.0, "dur": 4.0, "st": 12, "t": "of", - "lead": 0.0 + "lead": 0.0, + "w": 0 }, { "beat": 4.0, "dur": 2.0, "st": 10, "t": "a", - "lead": 0.0 + "lead": 0.0, + "w": 1 }, { "beat": 6.0, "dur": 2.0, "st": 5, "t": "stone", - "lead": 0.0508 + "lead": 0.1017, + "w": 2 } ] }, "w-just-waiting": { - "leadIn": 0.075, + "leadIn": 0.15, "beats": 6.5, "voiced": [ [ - 0.0, - 3.3855 + -0.1525, + 3.3652 ], [ 3.4973, @@ -372,14 +418,16 @@ "beat": 0.0, "dur": 3.5, "st": 2, "t": "Just", - "lead": 0.1525 + "lead": 0.305, + "w": 0 }, { "beat": 3.5, "dur": 3.0, "st": 3, "t": "waiting", - "lead": 0.0 + "lead": 0.0, + "w": 1 } ] }, @@ -389,10 +437,14 @@ "beats": 8.5, "voiced": [ [ 0.0, - 7.3912 + 4.636 ], [ - 7.4217, + 4.7377, + 7.3607 + ], + [ + 7.4013, 8.4993 ], [ @@ -410,27 +462,29 @@ "beat": 0.0, "dur": 5.0, "st": 0, "t": "very", - "lead": 0.0 + "lead": 0.0, + "w": 0 }, { "beat": 5.0, "dur": 3.5, "st": 7, "t": "patiently", - "lead": 0.0 + "lead": 0.0, + "w": 1 } ] }, "w-for-time-to-pass": { - "leadIn": 0.035, + "leadIn": 0.07, "beats": 12.5, "voiced": [ [ - 0.0, - 1.8605 + -0.0712, + 1.7385 ], [ - 2.0028, + 1.8808, 4.4937 ], [ @@ -448,28 +502,32 @@ "beat": 0.0, "dur": 2.0, "st": 5, "t": "for", - "lead": 0.0712 + "lead": 0.1423, + "w": 0 }, { "beat": 2.0, "dur": 2.5, "st": 7, "t": "time", - "lead": 0.122 + "lead": 0.244, + "w": 1 }, { "beat": 4.5, "dur": 4.0, "st": 3, "t": "to", - "lead": 0.0 + "lead": 0.0, + "w": 2 }, { "beat": 8.5, "dur": 4.0, "st": 3, "t": "pass", - "lead": 0.0 + "lead": 0.0, + "w": 3 } ] }, @@ -494,7 +552,11 @@ 7.4623, 8.5095 ], [ - 8.5298, + 8.5197, + 10.3903 + ], + [ + 10.4005, 11.1427 ] ], @@ -504,49 +566,56 @@ "beat": 0.0, "dur": 1.5, "st": 5, "t": "getting", - "lead": 0.0 + "lead": 0.0, + "w": 0 }, { "beat": 1.5, "dur": 2.5, "st": 3, "t": "curled", - "lead": 0.0 + "lead": 0.0, + "w": 1 }, { "beat": 4.0, "dur": 0.5, "st": 1, "t": "up", - "lead": 0.0 + "lead": 0.0, + "w": 2 }, { "beat": 4.5, "dur": 1.5, "st": 0, "t": "in", - "lead": 0.0 + "lead": 0.0, + "w": 3 }, { "beat": 6.0, "dur": 2.5, "st": 4, "t": "myself", - "lead": 0.0 + "lead": 0.0, + "w": 4 }, { "beat": 8.5, "dur": 2.0, "st": -2, "t": "i", - "lead": 0.0 + "lead": 0.0, + "w": 5 }, { "beat": 10.5, "dur": 0.5, "st": -5, "t": "think", - "lead": 0.0 + "lead": 0.0, + "w": 6 } ] }, @@ -556,18 +625,26 @@ "beats": 17.0, "voiced": [ [ 0.0, - 3.3042 + 1.8808 ], [ - 3.4363, - 8.0012 + 1.9012, + 3.2635 ], [ - 8.0622, - 16.3073 + 3.4058, + 7.9605 + ], + [ + 8.052, + 14.8433 + ], + [ + 14.8738, + 16.2972 ], [ - 16.3378, + 16.3277, 17.3443 ] ], @@ -577,42 +654,48 @@ "beat": 0.0, "dur": 2.0, "st": 12, "t": "A", - "lead": 0.0 + "lead": 0.0, + "w": 0 }, { "beat": 2.0, "dur": 2.0, "st": 9, "t": "stone", - "lead": 0.0 + "lead": 0.0, + "w": 1 }, { "beat": 4.0, "dur": 4.0, "st": 5, "t": "just", - "lead": 0.0 + "lead": 0.0, + "w": 2 }, { "beat": 8.0, "dur": 4.0, "st": 3, "t": "waiting", - "lead": 0.0 + "lead": 0.0, + "w": 3 }, { "beat": 12.0, "dur": 3.0, "st": 0, "t": "very", - "lead": 0.0 + "lead": 0.0, + "w": 4 }, { "beat": 15.0, "dur": 2.0, "st": 6, "t": "patiently", - "lead": 0.0 + "lead": 0.0, + "w": 5 } ] }, @@ -643,28 +726,2624 @@ "beat": 0.0, "dur": 0.5, "st": 5, "t": "the", - "lead": 0.0 + "lead": 0.0, + "w": 0 }, { "beat": 0.5, "dur": 1.0, "st": 7, "t": "time", - "lead": 0.0 + "lead": 0.0, + "w": 1 }, { "beat": 1.5, "dur": 2.5, "st": 3, "t": "to", - "lead": 0.0 + "lead": 0.0, + "w": 2 + }, + { + "beat": 4.0, + "dur": 1.5, + "st": 3, + "t": "pass", + "lead": 0.0, + "w": 3 + } + ] + }, + "w-rq": { + "leadIn": 0.43, + "beats": 60.0, + "voiced": [ + [ + -0.061, + 3.9142 + ], + [ + 3.9752, + 5.7848 + ], + [ + 5.8458, + 7.9097 + ], + [ + 7.9605, + 9.8718 + ], + [ + 9.943, + 11.2952 + ], + [ + 11.3968, + 13.8572 + ], + [ + 13.969, + 15.616 + ], + [ + 15.8193, + 17.2528 + ], + [ + 17.446, + 17.8832 + ], + [ + 17.9442, + 21.9193 + ], + [ + 21.9905, + 23.6273 + ], + [ + 23.6883, + 25.01 + ], + [ + 25.0812, + 27.2365 + ], + [ + 27.3178, + 27.6432 + ], + [ + 27.8465, + 31.232 + ], + [ + 31.6997, + 31.8522 + ], + [ + 31.9335, + 35.8578 + ], + [ + 35.929, + 37.4947 + ], + [ + 37.515, + 37.5557 + ], + [ + 37.8302, + 39.5585 + ], + [ + 39.9448, + 41.968 + ], + [ + 41.9883, + 43.7777 + ], + [ + 43.8895, + 45.8822 + ], + [ + 45.9432, + 46.36 + ], + [ + 46.4007, + 47.9053 + ], + [ + 47.9562, + 51.5755 + ], + [ + 51.5857, + 51.789 + ], + [ + 51.8093, + 51.9008 + ], + [ + 51.9517, + 55.9167 + ], + [ + 55.998, + 57.3908 + ], + [ + 57.4213, + 57.8382 + ], + [ + 57.889, + 60.817 + ] + ], + "notes": [ + { + "beat": 0.0, + "dur": 2.0, + "st": -5, + "t": "sitting\u00b7a", + "lead": 0.122, + "w": 0 + }, + { + "beat": 2.0, + "dur": 2.0, + "st": -7, + "t": "sitting\u00b7b", + "lead": 0.0, + "w": 0 + }, + { + "beat": 4.0, + "dur": 1.91, + "st": -9, + "t": "curled", + "lead": 0.0712, + "w": 1 + }, + { + "beat": 5.91, + "dur": 2.09, + "st": -10, + "t": "up", + "lead": 0.122, + "w": 2 + }, + { + "beat": 8.0, + "dur": 2.0, + "st": -12, + "t": "in", + "lead": 0.0813, + "w": 3 + }, + { + "beat": 10.0, + "dur": 1.5, + "st": -7, + "t": "my", + "lead": 0.122, + "w": 4 + }, + { + "beat": 11.5, + "dur": 2.5, + "st": -10, + "t": "self", + "lead": 0.2033, + "w": 4 + }, + { + "beat": 14.0, + "dur": 2.0, + "st": -14, + "t": "i", + "lead": 0.061, + "w": 5 + }, + { + "beat": 16.0, + "dur": 2.0, + "st": -17, + "t": "think", + "lead": 0.3762, + "w": 6 + }, + { + "beat": 18.0, + "dur": 4.0, + "st": 0, + "t": "of", + "lead": 0.1017, + "w": 7 + }, + { + "beat": 22.0, + "dur": 1.75, + "st": -2, + "t": "a", + "lead": 0.0712, + "w": 8 + }, + { + "beat": 23.75, + "dur": 4.25, + "st": -7, + "t": "stone", + "lead": 0.122, + "w": 9 + }, + { + "beat": 28.0, + "dur": 4.0, + "st": -10, + "t": "just", + "lead": 0.305, + "w": 10 + }, + { + "beat": 32.0, + "dur": 2.0, + "st": -9, + "t": "wait", + "lead": 0.1423, + "w": 11 + }, + { + "beat": 34.0, + "dur": 2.0, + "st": -10, + "t": "ing", + "lead": 0.0, + "w": 11 + }, + { + "beat": 36.0, + "dur": 2.0, + "st": -12, + "t": "ve", + "lead": 0.1423, + "w": 12 + }, + { + "beat": 38.0, + "dur": 2.0, + "st": -14, + "t": "ry", + "lead": 0.4372, + "w": 12 + }, + { + "beat": 40.0, + "dur": 2.0, + "st": -5, + "t": "pa", + "lead": 0.1017, + "w": 13 + }, + { + "beat": 42.0, + "dur": 2.0, + "st": -7, + "t": "tient", + "lead": 0.0203, + "w": 13 + }, + { + "beat": 44.0, + "dur": 2.0, + "st": -9, + "t": "ly", + "lead": 0.2237, + "w": 13 + }, + { + "beat": 46.0, + "dur": 2.0, + "st": -7, + "t": "for", + "lead": 0.122, + "w": 14 + }, + { + "beat": 48.0, + "dur": 4.0, + "st": -5, + "t": "time", + "lead": 0.0813, + "w": 15 + }, + { + "beat": 52.0, + "dur": 4.0, + "st": -9, + "t": "to", + "lead": 0.1017, + "w": 16 + }, + { + "beat": 56.0, + "dur": 4.0, + "st": -9, + "t": "pass", + "lead": 0.0712, + "w": 17 + } + ] + }, + "w-sh": { + "leadIn": 0.84, + "beats": 60.0, + "voiced": [ + [ + -0.183, + 1.9622 + ], + [ + 1.9927, + 3.904 + ], + [ + 3.9548, + 4.3818 + ], + [ + 4.392, + 5.7848 + ], + [ + 5.8662, + 6.2118 + ], + [ + 7.93, + 8.6417 + ], + [ + 8.7027, + 9.9227 + ], + [ + 9.9735, + 10.8275 + ], + [ + 10.8783, + 11.4477 + ], + [ + 11.4782, + 12.6168 + ], + [ + 13.176, + 13.7148 + ], + [ + 13.9893, + 15.4737 + ], + [ + 15.8295, + 16.6022 + ], + [ + 16.9783, + 17.751 + ], + [ + 17.9442, + 19.4997 + ], + [ + 19.581, + 21.8685 + ], + [ + 21.9397, + 23.6477 + ], + [ + 23.7087, + 25.7725 + ], + [ + 25.7928, + 26.0572 + ], + [ + 26.0673, + 27.8872 + ], + [ + 27.9482, + 28.1515 + ], + [ + 28.2837, + 29.3003 + ], + [ + 29.3512, + 30.9677 + ], + [ + 30.9982, + 31.8013 + ], + [ + 33.5297, + 35.929 + ], + [ + 35.99, + 36.478 + ], + [ + 36.4983, + 37.027 + ], + [ + 37.0473, + 37.9013 + ], + [ + 37.9522, + 39.894 + ], + [ + 40.7378, + 42.9338 + ], + [ + 42.944, + 43.6455 + ], + [ + 43.8285, + 45.567 + ], + [ + 45.8212, + 47.5698 + ], + [ + 47.6003, + 47.8952 + ], + [ + 47.946, + 51.1688 + ], + [ + 51.2197, + 51.7687 + ], + [ + 51.972, + 55.3575 + ], + [ + 55.4083, + 55.7438 + ], + [ + 55.876, + 56.2217 + ], + [ + 56.2318, + 56.5775 + ], + [ + 56.608, + 58.743 + ], + [ + 58.987, + 59.4852 + ], + [ + 59.5157, + 59.8105 + ], + [ + 59.8308, + 59.963 + ], + [ + 60.0037, + 60.0748 + ], + [ + 60.4103, + 60.5425 + ] + ], + "notes": [ + { + "beat": 0.0, + "dur": 2.0, + "st": -5, + "t": "sitting\u00b7a", + "lead": 0.9557, + "w": 0 + }, + { + "beat": 2.0, + "dur": 2.0, + "st": -7, + "t": "sitting\u00b7b", + "lead": 0.0203, + "w": 0 + }, + { + "beat": 4.0, + "dur": 1.91, + "st": -9, + "t": "curled", + "lead": 0.0813, + "w": 1 + }, + { + "beat": 5.91, + "dur": 2.09, + "st": -10, + "t": "up", + "lead": 0.0813, + "w": 2 + }, + { + "beat": 8.0, + "dur": 2.0, + "st": -12, + "t": "in", + "lead": 0.1423, + "w": 3 + }, + { + "beat": 10.0, + "dur": 1.5, + "st": -7, + "t": "my", + "lead": 0.061, + "w": 4 + }, + { + "beat": 11.5, + "dur": 2.5, + "st": -10, + "t": "self", + "lead": 0.0407, + "w": 4 + }, + { + "beat": 14.0, + "dur": 2.0, + "st": -14, + "t": "i", + "lead": 0.1423, + "w": 5 + }, + { + "beat": 16.0, + "dur": 2.0, + "st": -17, + "t": "think", + "lead": 0.5185, + "w": 6 + }, + { + "beat": 18.0, + "dur": 4.0, + "st": 0, + "t": "of", + "lead": 0.1017, + "w": 7 + }, + { + "beat": 22.0, + "dur": 1.75, + "st": -2, + "t": "a", + "lead": 0.122, + "w": 8 + }, + { + "beat": 23.75, + "dur": 4.25, + "st": -7, + "t": "stone", + "lead": 0.0915, + "w": 9 + }, + { + "beat": 28.0, + "dur": 4.0, + "st": -10, + "t": "just", + "lead": 0.1017, + "w": 10 + }, + { + "beat": 32.0, + "dur": 2.0, + "st": -9, + "t": "wait", + "lead": 0.0, + "w": 11 + }, + { + "beat": 34.0, + "dur": 2.0, + "st": -10, + "t": "ing", + "lead": 0.0, + "w": 11 + }, + { + "beat": 36.0, + "dur": 2.0, + "st": -12, + "t": "ve", + "lead": 0.0712, + "w": 12 + }, + { + "beat": 38.0, + "dur": 2.0, + "st": -14, + "t": "ry", + "lead": 0.1017, + "w": 12 + }, + { + "beat": 40.0, + "dur": 2.0, + "st": -5, + "t": "pa", + "lead": 0.0, + "w": 13 + }, + { + "beat": 42.0, + "dur": 2.0, + "st": -7, + "t": "tient", + "lead": 0.0, + "w": 13 + }, + { + "beat": 44.0, + "dur": 2.0, + "st": -9, + "t": "ly", + "lead": 0.3457, + "w": 13 + }, + { + "beat": 46.0, + "dur": 2.0, + "st": -7, + "t": "for", + "lead": 0.4372, + "w": 14 + }, + { + "beat": 48.0, + "dur": 4.0, + "st": -5, + "t": "time", + "lead": 0.1017, + "w": 15 + }, + { + "beat": 52.0, + "dur": 4.0, + "st": -9, + "t": "to", + "lead": 0.061, + "w": 16 + }, + { + "beat": 56.0, + "dur": 4.0, + "st": -9, + "t": "pass", + "lead": 0.244, + "w": 17 + } + ] + }, + "w-lg": { + "leadIn": 0.575, + "beats": 60.0, + "voiced": [ + [ + -0.183, + 3.8633 + ], + [ + 3.9345, + 4.2802 + ], + [ + 4.2903, + 5.9068 + ], + [ + 7.1065, + 7.8588 + ], + [ + 7.9402, + 9.8922 + ], + [ + 9.9532, + 10.8783 + ], + [ + 10.9088, + 11.4985 + ], + [ + 13.9487, + 15.8803 + ], + [ + 15.9515, + 16.714 + ], + [ + 16.7852, + 17.7815 + ], + [ + 18.3508, + 21.899 + ], + [ + 21.9702, + 23.6578 + ], + [ + 23.729, + 25.6607 + ], + [ + 25.7725, + 27.4703 + ], + [ + 27.8465, + 28.7818 + ], + [ + 28.8123, + 30.7135 + ], + [ + 31.9437, + 35.8985 + ], + [ + 35.9493, + 37.9623 + ], + [ + 40.077, + 41.724 + ], + [ + 41.8663, + 43.6963 + ], + [ + 43.9302, + 45.4857 + ], + [ + 45.8212, + 47.5393 + ], + [ + 47.6207, + 47.8647 + ], + [ + 47.9358, + 51.0977 + ], + [ + 51.8195, + 55.9167 + ], + [ + 56.6283, + 59.5157 + ] + ], + "notes": [ + { + "beat": 0.0, + "dur": 2.0, + "st": 7, + "t": "sitting\u00b7a", + "lead": 0.4168, + "w": 0 + }, + { + "beat": 2.0, + "dur": 2.0, + "st": 5, + "t": "sitting\u00b7b", + "lead": 0.0, + "w": 0 + }, + { + "beat": 4.0, + "dur": 1.91, + "st": 3, + "t": "curled", + "lead": 0.122, + "w": 1 + }, + { + "beat": 5.91, + "dur": 2.09, + "st": 2, + "t": "up", + "lead": 0.0, + "w": 2 + }, + { + "beat": 8.0, + "dur": 2.0, + "st": 0, + "t": "in", + "lead": 0.122, + "w": 3 + }, + { + "beat": 10.0, + "dur": 1.5, + "st": 5, + "t": "my", + "lead": 0.1017, + "w": 4 + }, + { + "beat": 11.5, + "dur": 2.5, + "st": 2, + "t": "self", + "lead": 0.0, + "w": 4 + }, + { + "beat": 14.0, + "dur": 2.0, + "st": -2, + "t": "i", + "lead": 0.1017, + "w": 5 + }, + { + "beat": 16.0, + "dur": 2.0, + "st": -5, + "t": "think", + "lead": 0.1017, + "w": 6 + }, + { + "beat": 18.0, + "dur": 4.0, + "st": 12, + "t": "of", + "lead": 0.0, + "w": 7 + }, + { + "beat": 22.0, + "dur": 1.75, + "st": 10, + "t": "a", + "lead": 0.0915, + "w": 8 + }, + { + "beat": 23.75, + "dur": 4.25, + "st": 5, + "t": "stone", + "lead": 0.0813, + "w": 9 + }, + { + "beat": 28.0, + "dur": 4.0, + "st": 2, + "t": "just", + "lead": 0.305, + "w": 10 + }, + { + "beat": 32.0, + "dur": 2.0, + "st": 3, + "t": "wait", + "lead": 0.122, + "w": 11 + }, + { + "beat": 34.0, + "dur": 2.0, + "st": 2, + "t": "ing", + "lead": 0.0, + "w": 11 + }, + { + "beat": 36.0, + "dur": 2.0, + "st": 0, + "t": "ve", + "lead": 0.1017, + "w": 12 + }, + { + "beat": 38.0, + "dur": 2.0, + "st": -2, + "t": "ry", + "lead": 0.0, + "w": 12 + }, + { + "beat": 40.0, + "dur": 2.0, + "st": 7, + "t": "pa", + "lead": 0.0, + "w": 13 + }, + { + "beat": 42.0, + "dur": 2.0, + "st": 5, + "t": "tient", + "lead": 0.2643, + "w": 13 + }, + { + "beat": 44.0, + "dur": 2.0, + "st": 3, + "t": "ly", + "lead": 0.1423, + "w": 13 + }, + { + "beat": 46.0, + "dur": 2.0, + "st": 5, + "t": "for", + "lead": 0.5083, + "w": 14 + }, + { + "beat": 48.0, + "dur": 4.0, + "st": 7, + "t": "time", + "lead": 0.122, + "w": 15 + }, + { + "beat": 52.0, + "dur": 4.0, + "st": 3, + "t": "to", + "lead": 0.5795, + "w": 16 + }, + { + "beat": 56.0, + "dur": 4.0, + "st": 3, + "t": "pass", + "lead": 0.0, + "w": 17 + } + ] + }, + "w-pf": { + "leadIn": 0.765, + "beats": 60.0, + "voiced": [ + [ + -0.183, + 1.9012 + ], + [ + 2.44, + 3.7007 + ], + [ + 4.148, + 5.0935 + ], + [ + 5.1647, + 5.7543 + ], + [ + 6.6083, + 7.8588 + ], + [ + 7.9402, + 8.4587 + ], + [ + 8.54, + 9.9837 + ], + [ + 11.3968, + 13.4302 + ], + [ + 13.7657, + 13.9893 + ], + [ + 15.9515, + 16.4497 + ], + [ + 16.5717, + 17.3545 + ], + [ + 17.9442, + 19.4285 + ], + [ + 19.7335, + 21.8888 + ], + [ + 21.9498, + 23.6375 + ], + [ + 23.6985, + 26.1995 + ], + [ + 26.413, + 27.8363 + ], + [ + 28.3853, + 31.0693 + ], + [ + 33.8143, + 34.4142 + ], + [ + 34.4243, + 34.7802 + ], + [ + 34.7903, + 35.38 + ], + [ + 35.4003, + 35.6748 + ], + [ + 35.9087, + 37.1185 + ], + [ + 37.1287, + 37.8098 + ], + [ + 39.9448, + 40.3108 + ], + [ + 40.4328, + 41.541 + ], + [ + 44.3165, + 45.4043 + ], + [ + 45.8212, + 46.482 + ], + [ + 47.153, + 47.824 + ], + [ + 47.9155, + 49.9183 + ], + [ + 52.3177, + 53.4055 + ], + [ + 53.6292, + 55.6523 + ], + [ + 56.4657, + 57.5433 + ], + [ + 57.5738, + 59.0988 + ] + ], + "notes": [ + { + "beat": 0.0, + "dur": 2.0, + "st": 7, + "t": "sitting\u00b7a", + "lead": 0.8032, + "w": 0 + }, + { + "beat": 2.0, + "dur": 2.0, + "st": 5, + "t": "sitting\u00b7b", + "lead": 0.0, + "w": 0 }, { "beat": 4.0, + "dur": 1.91, + "st": 3, + "t": "curled", + "lead": 0.0, + "w": 1 + }, + { + "beat": 5.91, + "dur": 2.09, + "st": 2, + "t": "up", + "lead": 0.0, + "w": 2 + }, + { + "beat": 8.0, + "dur": 2.0, + "st": 0, + "t": "in", + "lead": 0.122, + "w": 3 + }, + { + "beat": 10.0, "dur": 1.5, + "st": 5, + "t": "my", + "lead": 0.0, + "w": 4 + }, + { + "beat": 11.5, + "dur": 2.5, + "st": 2, + "t": "self", + "lead": 0.2033, + "w": 4 + }, + { + "beat": 14.0, + "dur": 2.0, + "st": -2, + "t": "i", + "lead": 0.0, + "w": 5 + }, + { + "beat": 16.0, + "dur": 2.0, + "st": -5, + "t": "think", + "lead": 0.1017, + "w": 6 + }, + { + "beat": 18.0, + "dur": 4.0, + "st": 12, + "t": "of", + "lead": 0.1017, + "w": 7 + }, + { + "beat": 22.0, + "dur": 1.75, + "st": 10, + "t": "a", + "lead": 0.1017, + "w": 8 + }, + { + "beat": 23.75, + "dur": 4.25, + "st": 5, + "t": "stone", + "lead": 0.1017, + "w": 9 + }, + { + "beat": 28.0, + "dur": 4.0, + "st": 2, + "t": "just", + "lead": 0.0, + "w": 10 + }, + { + "beat": 32.0, + "dur": 2.0, + "st": 3, + "t": "wait", + "lead": 0.0, + "w": 11 + }, + { + "beat": 34.0, + "dur": 2.0, + "st": 2, + "t": "ing", + "lead": 0.3965, + "w": 11 + }, + { + "beat": 36.0, + "dur": 2.0, + "st": 0, + "t": "ve", + "lead": 0.3253, + "w": 12 + }, + { + "beat": 38.0, + "dur": 2.0, + "st": -2, + "t": "ry", + "lead": 0.183, + "w": 12 + }, + { + "beat": 40.0, + "dur": 2.0, + "st": 7, + "t": "pa", + "lead": 0.1017, + "w": 13 + }, + { + "beat": 42.0, + "dur": 2.0, + "st": 5, + "t": "tient", + "lead": 0.0, + "w": 13 + }, + { + "beat": 44.0, + "dur": 2.0, + "st": 3, + "t": "ly", + "lead": 0.0, + "w": 13 + }, + { + "beat": 46.0, + "dur": 2.0, + "st": 5, + "t": "for", + "lead": 0.366, + "w": 14 + }, + { + "beat": 48.0, + "dur": 4.0, + "st": 7, + "t": "time", + "lead": 0.1627, + "w": 15 + }, + { + "beat": 52.0, + "dur": 4.0, + "st": 3, + "t": "to", + "lead": 0.0, + "w": 16 + }, + { + "beat": 56.0, + "dur": 4.0, "st": 3, "t": "pass", - "lead": 0.0 + "lead": 0.0, + "w": 17 + } + ] + }, + "w-rd": { + "leadIn": 0.405, + "beats": 60.0, + "voiced": [ + [ + -0.0203, + 1.3827 + ], + [ + 1.9215, + 3.8328 + ], + [ + 3.9345, + 4.9105 + ], + [ + 4.9308, + 5.7238 + ], + [ + 6.3135, + 7.8893 + ], + [ + 7.9503, + 9.8312 + ], + [ + 10.3802, + 11.4883 + ], + [ + 12.0475, + 13.969 + ], + [ + 16.714, + 17.8018 + ], + [ + 17.9747, + 21.8685 + ], + [ + 21.9397, + 23.6375 + ], + [ + 23.6985, + 25.681 + ], + [ + 25.864, + 27.1552 + ], + [ + 27.8262, + 30.5407 + ], + [ + 31.8827, + 32.0047 + ], + [ + 33.8753, + 34.1295 + ], + [ + 34.5565, + 34.9937 + ], + [ + 35.014, + 35.6443 + ], + [ + 35.685, + 35.8985 + ], + [ + 35.9493, + 37.9115 + ], + [ + 37.9928, + 39.9042 + ], + [ + 40.26, + 40.443 + ], + [ + 40.4532, + 41.9883 + ], + [ + 46.848, + 47.885 + ], + [ + 47.946, + 47.9968 + ], + [ + 48.1493, + 48.7492 + ], + [ + 48.8, + 50.5283 + ], + [ + 50.5588, + 51.5653 + ], + [ + 57.34, + 60.817 + ] + ], + "notes": [ + { + "beat": 0.0, + "dur": 2.0, + "st": 7, + "t": "sitting\u00b7a", + "lead": 0.0712, + "w": 0 + }, + { + "beat": 2.0, + "dur": 2.0, + "st": 5, + "t": "sitting\u00b7b", + "lead": 0.1627, + "w": 0 + }, + { + "beat": 4.0, + "dur": 1.91, + "st": 3, + "t": "curled", + "lead": 0.122, + "w": 1 + }, + { + "beat": 5.91, + "dur": 2.09, + "st": 2, + "t": "up", + "lead": 0.0, + "w": 2 + }, + { + "beat": 8.0, + "dur": 2.0, + "st": 0, + "t": "in", + "lead": 0.1017, + "w": 3 + }, + { + "beat": 10.0, + "dur": 1.5, + "st": 5, + "t": "my", + "lead": 0.0, + "w": 4 + }, + { + "beat": 11.5, + "dur": 2.5, + "st": 2, + "t": "self", + "lead": 0.0, + "w": 4 + }, + { + "beat": 14.0, + "dur": 2.0, + "st": -2, + "t": "i", + "lead": 0.0, + "w": 5 + }, + { + "beat": 16.0, + "dur": 2.0, + "st": -5, + "t": "think", + "lead": 0.0, + "w": 6 + }, + { + "beat": 18.0, + "dur": 4.0, + "st": 12, + "t": "of", + "lead": 0.0712, + "w": 7 + }, + { + "beat": 22.0, + "dur": 1.75, + "st": 10, + "t": "a", + "lead": 0.122, + "w": 8 + }, + { + "beat": 23.75, + "dur": 4.25, + "st": 5, + "t": "stone", + "lead": 0.1017, + "w": 9 + }, + { + "beat": 28.0, + "dur": 4.0, + "st": 2, + "t": "just", + "lead": 0.3457, + "w": 10 + }, + { + "beat": 32.0, + "dur": 2.0, + "st": 3, + "t": "wait", + "lead": 0.244, + "w": 11 + }, + { + "beat": 34.0, + "dur": 2.0, + "st": 2, + "t": "ing", + "lead": 0.5287, + "w": 11 + }, + { + "beat": 36.0, + "dur": 2.0, + "st": 0, + "t": "ve", + "lead": 0.1017, + "w": 12 + }, + { + "beat": 38.0, + "dur": 2.0, + "st": -2, + "t": "ry", + "lead": 0.0203, + "w": 12 + }, + { + "beat": 40.0, + "dur": 2.0, + "st": 7, + "t": "pa", + "lead": 0.0, + "w": 13 + }, + { + "beat": 42.0, + "dur": 2.0, + "st": 5, + "t": "tient", + "lead": 0.0, + "w": 13 + }, + { + "beat": 44.0, + "dur": 2.0, + "st": 3, + "t": "ly", + "lead": 0.0, + "w": 13 + }, + { + "beat": 46.0, + "dur": 2.0, + "st": 5, + "t": "for", + "lead": 0.0, + "w": 14 + }, + { + "beat": 48.0, + "dur": 4.0, + "st": 7, + "t": "time", + "lead": 0.1017, + "w": 15 + }, + { + "beat": 52.0, + "dur": 4.0, + "st": 3, + "t": "to", + "lead": 0.0, + "w": 16 + }, + { + "beat": 56.0, + "dur": 4.0, + "st": 3, + "t": "pass", + "lead": 0.0, + "w": 17 + } + ] + }, + "w-cp": { + "leadIn": 0.43, + "beats": 60.0, + "voiced": [ + [ + -0.061, + 3.6498 + ], + [ + 3.8837, + 5.4392 + ], + [ + 5.7238, + 5.7645 + ], + [ + 6.4457, + 7.8792 + ], + [ + 7.9605, + 9.9023 + ], + [ + 9.9633, + 11.4985 + ], + [ + 16.6225, + 17.7612 + ], + [ + 17.934, + 21.8685 + ], + [ + 21.9397, + 23.7392 + ], + [ + 24.2882, + 27.8973 + ], + [ + 27.9685, + 30.1848 + ], + [ + 30.5203, + 30.6525 + ], + [ + 30.7135, + 31.8928 + ], + [ + 31.9538, + 33.0925 + ], + [ + 33.8143, + 35.4105 + ], + [ + 35.8375, + 35.99 + ], + [ + 42.7712, + 43.2287 + ], + [ + 43.8183, + 45.8923 + ], + [ + 45.9533, + 47.5597 + ], + [ + 55.8252, + 56.3843 + ] + ], + "notes": [ + { + "beat": 0.0, + "dur": 2.0, + "st": -5, + "t": "sitting\u00b7a", + "lead": 0.122, + "w": 0 + }, + { + "beat": 2.0, + "dur": 2.0, + "st": -7, + "t": "sitting\u00b7b", + "lead": 0.0, + "w": 0 + }, + { + "beat": 4.0, + "dur": 1.91, + "st": -9, + "t": "curled", + "lead": 0.3253, + "w": 1 + }, + { + "beat": 5.91, + "dur": 2.09, + "st": -10, + "t": "up", + "lead": 0.4677, + "w": 2 + }, + { + "beat": 8.0, + "dur": 2.0, + "st": -12, + "t": "in", + "lead": 0.0915, + "w": 3 + }, + { + "beat": 10.0, + "dur": 1.5, + "st": -7, + "t": "my", + "lead": 0.0915, + "w": 4 + }, + { + "beat": 11.5, + "dur": 2.5, + "st": -10, + "t": "self", + "lead": 0.0, + "w": 4 + }, + { + "beat": 14.0, + "dur": 2.0, + "st": -14, + "t": "i", + "lead": 0.0, + "w": 5 + }, + { + "beat": 16.0, + "dur": 2.0, + "st": -17, + "t": "think", + "lead": 0.0, + "w": 6 + }, + { + "beat": 18.0, + "dur": 4.0, + "st": 0, + "t": "of", + "lead": 0.122, + "w": 7 + }, + { + "beat": 22.0, + "dur": 1.75, + "st": -2, + "t": "a", + "lead": 0.122, + "w": 8 + }, + { + "beat": 23.75, + "dur": 4.25, + "st": -7, + "t": "stone", + "lead": 0.0, + "w": 9 + }, + { + "beat": 28.0, + "dur": 4.0, + "st": -10, + "t": "just", + "lead": 0.0915, + "w": 10 + }, + { + "beat": 32.0, + "dur": 2.0, + "st": -9, + "t": "wait", + "lead": 0.1017, + "w": 11 + }, + { + "beat": 34.0, + "dur": 2.0, + "st": -10, + "t": "ing", + "lead": 0.5388, + "w": 11 + }, + { + "beat": 36.0, + "dur": 2.0, + "st": -12, + "t": "ve", + "lead": 0.5083, + "w": 12 + }, + { + "beat": 38.0, + "dur": 2.0, + "st": -14, + "t": "ry", + "lead": 0.0, + "w": 12 + }, + { + "beat": 40.0, + "dur": 2.0, + "st": -5, + "t": "pa", + "lead": 0.0, + "w": 13 + }, + { + "beat": 42.0, + "dur": 2.0, + "st": -7, + "t": "tient", + "lead": 0.0, + "w": 13 + }, + { + "beat": 44.0, + "dur": 2.0, + "st": -9, + "t": "ly", + "lead": 0.366, + "w": 13 + }, + { + "beat": 46.0, + "dur": 2.0, + "st": -7, + "t": "for", + "lead": 0.1017, + "w": 14 + }, + { + "beat": 48.0, + "dur": 4.0, + "st": -5, + "t": "time", + "lead": 0.0, + "w": 15 + }, + { + "beat": 52.0, + "dur": 4.0, + "st": -9, + "t": "to", + "lead": 0.0, + "w": 16 + }, + { + "beat": 56.0, + "dur": 4.0, + "st": -9, + "t": "pass", + "lead": 0.3457, + "w": 17 + } + ] + }, + "w-s": { + "leadIn": 0.37, + "beats": 60.0, + "voiced": [ + [ + 1.8198, + 3.8938 + ], + [ + 3.9447, + 7.1675 + ], + [ + 7.3403, + 7.8792 + ], + [ + 7.9503, + 9.8718 + ], + [ + 9.943, + 11.4477 + ], + [ + 11.4782, + 13.6945 + ], + [ + 13.7148, + 13.908 + ], + [ + 13.969, + 15.8803 + ], + [ + 15.9515, + 16.6327 + ], + [ + 16.7038, + 16.8055 + ], + [ + 16.8258, + 17.0698 + ], + [ + 17.1003, + 17.5578 + ], + [ + 17.629, + 17.8832 + ], + [ + 17.9442, + 21.8888 + ], + [ + 21.96, + 23.6172 + ], + [ + 23.6883, + 25.986 + ], + [ + 26.108, + 27.9583 + ], + [ + 28.1108, + 31.9945 + ], + [ + 33.9465, + 35.8782 + ], + [ + 35.9392, + 39.8838 + ], + [ + 39.9448, + 41.7037 + ], + [ + 41.8663, + 43.8895 + ], + [ + 43.9607, + 44.6418 + ], + [ + 44.6825, + 45.7703 + ], + [ + 45.811, + 45.8822 + ], + [ + 45.9432, + 47.1632 + ], + [ + 47.1937, + 47.885 + ], + [ + 47.9663, + 50.5385 + ], + [ + 51.1383, + 51.8703 + ], + [ + 51.9415, + 54.534 + ], + [ + 54.778, + 55.8862 + ], + [ + 55.9472, + 59.6173 + ] + ], + "notes": [ + { + "beat": 0.0, + "dur": 2.0, + "st": 7, + "t": "sitting\u00b7a", + "lead": 0.0, + "w": 0 + }, + { + "beat": 2.0, + "dur": 2.0, + "st": 5, + "t": "sitting\u00b7b", + "lead": 0.4473, + "w": 0 + }, + { + "beat": 4.0, + "dur": 1.91, + "st": 3, + "t": "curled", + "lead": 0.1017, + "w": 1 + }, + { + "beat": 5.91, + "dur": 2.09, + "st": 2, + "t": "up", + "lead": 0.0, + "w": 2 + }, + { + "beat": 8.0, + "dur": 2.0, + "st": 0, + "t": "in", + "lead": 0.1017, + "w": 3 + }, + { + "beat": 10.0, + "dur": 1.5, + "st": 5, + "t": "my", + "lead": 0.122, + "w": 4 + }, + { + "beat": 11.5, + "dur": 2.5, + "st": 2, + "t": "self", + "lead": 0.0407, + "w": 4 + }, + { + "beat": 14.0, + "dur": 2.0, + "st": -2, + "t": "i", + "lead": 0.0813, + "w": 5 + }, + { + "beat": 16.0, + "dur": 2.0, + "st": -5, + "t": "think", + "lead": 0.1017, + "w": 6 + }, + { + "beat": 18.0, + "dur": 4.0, + "st": 12, + "t": "of", + "lead": 0.1017, + "w": 7 + }, + { + "beat": 22.0, + "dur": 1.75, + "st": 10, + "t": "a", + "lead": 0.1017, + "w": 8 + }, + { + "beat": 23.75, + "dur": 4.25, + "st": 5, + "t": "stone", + "lead": 0.122, + "w": 9 + }, + { + "beat": 28.0, + "dur": 4.0, + "st": 2, + "t": "just", + "lead": 0.0, + "w": 10 + }, + { + "beat": 32.0, + "dur": 2.0, + "st": 3, + "t": "wait", + "lead": 0.0, + "w": 11 + }, + { + "beat": 34.0, + "dur": 2.0, + "st": 2, + "t": "ing", + "lead": 0.0, + "w": 11 + }, + { + "beat": 36.0, + "dur": 2.0, + "st": 0, + "t": "ve", + "lead": 0.122, + "w": 12 + }, + { + "beat": 38.0, + "dur": 2.0, + "st": -2, + "t": "ry", + "lead": 0.0, + "w": 12 + }, + { + "beat": 40.0, + "dur": 2.0, + "st": 7, + "t": "pa", + "lead": 0.1017, + "w": 13 + }, + { + "beat": 42.0, + "dur": 2.0, + "st": 5, + "t": "tient", + "lead": 0.2643, + "w": 13 + }, + { + "beat": 44.0, + "dur": 2.0, + "st": 3, + "t": "ly", + "lead": 0.0813, + "w": 13 + }, + { + "beat": 46.0, + "dur": 2.0, + "st": 5, + "t": "for", + "lead": 0.122, + "w": 14 + }, + { + "beat": 48.0, + "dur": 4.0, + "st": 7, + "t": "time", + "lead": 0.1017, + "w": 15 + }, + { + "beat": 52.0, + "dur": 4.0, + "st": 3, + "t": "to", + "lead": 0.122, + "w": 16 + }, + { + "beat": 56.0, + "dur": 4.0, + "st": 3, + "t": "pass", + "lead": 0.1017, + "w": 17 + } + ] + }, + "w-o": { + "leadIn": 0.55, + "beats": 60.0, + "voiced": [ + [ + -0.183, + 3.8633 + ], + [ + 3.9345, + 5.8052 + ], + [ + 5.856, + 7.7572 + ], + [ + 7.9503, + 9.8922 + ], + [ + 9.9532, + 11.1122 + ], + [ + 11.3562, + 13.7555 + ], + [ + 13.9283, + 15.6262 + ], + [ + 16.0023, + 16.2158 + ], + [ + 16.2565, + 16.47 + ], + [ + 16.5615, + 16.7852 + ], + [ + 16.8258, + 17.385 + ], + [ + 17.934, + 21.8685 + ], + [ + 21.9397, + 23.7392 + ], + [ + 23.7493, + 26.2402 + ], + [ + 26.3012, + 27.9177 + ], + [ + 27.9787, + 28.7513 + ], + [ + 28.9343, + 31.2523 + ], + [ + 31.476, + 31.8522 + ], + [ + 31.9335, + 35.8883 + ], + [ + 35.9493, + 37.576 + ], + [ + 37.8607, + 39.8533 + ], + [ + 39.9347, + 40.504 + ], + [ + 40.5243, + 41.8765 + ], + [ + 41.9375, + 45.872 + ], + [ + 45.9432, + 47.458 + ], + [ + 47.5597, + 47.885 + ], + [ + 47.946, + 50.8638 + ], + [ + 50.9858, + 51.8907 + ], + [ + 51.9517, + 55.9675 + ], + [ + 57.6043, + 59.1395 + ] + ], + "notes": [ + { + "beat": 0.0, + "dur": 2.0, + "st": 7, + "t": "sitting\u00b7a", + "lead": 0.366, + "w": 0 + }, + { + "beat": 2.0, + "dur": 2.0, + "st": 5, + "t": "sitting\u00b7b", + "lead": 0.0, + "w": 0 + }, + { + "beat": 4.0, + "dur": 1.91, + "st": 3, + "t": "curled", + "lead": 0.122, + "w": 1 + }, + { + "beat": 5.91, + "dur": 2.09, + "st": 2, + "t": "up", + "lead": 0.1017, + "w": 2 + }, + { + "beat": 8.0, + "dur": 2.0, + "st": 0, + "t": "in", + "lead": 0.1017, + "w": 3 + }, + { + "beat": 10.0, + "dur": 1.5, + "st": 5, + "t": "my", + "lead": 0.1017, + "w": 4 + }, + { + "beat": 11.5, + "dur": 2.5, + "st": 2, + "t": "self", + "lead": 0.3863, + "w": 4 + }, + { + "beat": 14.0, + "dur": 2.0, + "st": -2, + "t": "i", + "lead": 0.1423, + "w": 5 + }, + { + "beat": 16.0, + "dur": 2.0, + "st": -5, + "t": "think", + "lead": 0.3558, + "w": 6 + }, + { + "beat": 18.0, + "dur": 4.0, + "st": 12, + "t": "of", + "lead": 0.122, + "w": 7 + }, + { + "beat": 22.0, + "dur": 1.75, + "st": 10, + "t": "a", + "lead": 0.122, + "w": 8 + }, + { + "beat": 23.75, + "dur": 4.25, + "st": 5, + "t": "stone", + "lead": 0.0, + "w": 9 + }, + { + "beat": 28.0, + "dur": 4.0, + "st": 2, + "t": "just", + "lead": 0.0813, + "w": 10 + }, + { + "beat": 32.0, + "dur": 2.0, + "st": 3, + "t": "wait", + "lead": 0.1423, + "w": 11 + }, + { + "beat": 34.0, + "dur": 2.0, + "st": 2, + "t": "ing", + "lead": 0.0, + "w": 11 + }, + { + "beat": 36.0, + "dur": 2.0, + "st": 0, + "t": "ve", + "lead": 0.1017, + "w": 12 + }, + { + "beat": 38.0, + "dur": 2.0, + "st": -2, + "t": "ry", + "lead": 0.4168, + "w": 12 + }, + { + "beat": 40.0, + "dur": 2.0, + "st": 7, + "t": "pa", + "lead": 0.122, + "w": 13 + }, + { + "beat": 42.0, + "dur": 2.0, + "st": 5, + "t": "tient", + "lead": 0.122, + "w": 13 + }, + { + "beat": 44.0, + "dur": 2.0, + "st": 3, + "t": "ly", + "lead": 0.0, + "w": 13 + }, + { + "beat": 46.0, + "dur": 2.0, + "st": 5, + "t": "for", + "lead": 0.122, + "w": 14 + }, + { + "beat": 48.0, + "dur": 4.0, + "st": 7, + "t": "time", + "lead": 0.1017, + "w": 15 + }, + { + "beat": 52.0, + "dur": 4.0, + "st": 3, + "t": "to", + "lead": 0.1017, + "w": 16 + }, + { + "beat": 56.0, + "dur": 4.0, + "st": 3, + "t": "pass", + "lead": 0.0, + "w": 17 } ] } diff --git a/pop/loner/vox4/.manifest.json b/pop/loner/vox4/.manifest.json --- a/pop/loner/vox4/.manifest.json +++ b/pop/loner/vox4/.manifest.json @@ -1,161 +1,331 @@ { "w-whole-line": { "slice": "f-whole-line", - "lead_in": 0.04, + "lead_in": 0.33, "spans": [ [ "sitting\u00b7a", 0.0, - 0.755 + 1.0 ], [ "sitting\u00b7b", - 0.755, - 1.51 + 1.0, + 1.73 ], [ "curled", - 1.51, - 2.4 + 1.73, + 2.62 ], [ "up", - 2.4, - 2.995 + 2.62, + 3.215 ], [ "in", - 3.22, - 3.89 + 3.44, + 4.11 ], [ "my", - 3.89, - 4.5 + 4.11, + 4.72 ], [ "self", - 4.5, - 5.5 + 4.72, + 5.72 ], [ "i", - 5.5, - 6.215 + 5.72, + 6.44 ], [ "think", - 6.215, - 7.15 + 6.44, + 7.37 ], [ "of", - 7.15, - 8.76 + 7.37, + 8.98 ], [ "a", - 8.76, - 9.555 + 8.98, + 9.41 ], [ "stone", - 9.555, - 10.52 + 9.41, + 10.74 ], [ "just", - 11.195, - 12.425 + 11.285, + 12.645 ], [ "wait", - 12.67, - 13.7 + 12.89, + 13.92 ], [ "ing", - 13.7, - 14.4 + 13.92, + 14.62 ], [ "ve", - 14.4, - 15.05 + 14.62, + 15.39 ], [ "ry", - 15.05, - 16.04 + 15.39, + 16.12 ], [ "pa", - 16.04, - 16.8 + 16.12, + 16.875 ], [ "tient", - 16.8, - 17.7 + 16.875, + 17.92 ], [ "ly", - 17.7, - 18.54 + 17.92, + 18.76 ], [ "for", - 18.54, - 19.48 + 18.76, + 19.535 ], [ "time", - 19.48, - 20.405 + 19.535, + 20.625 ], [ "to", - 21.2, - 23.0 + 21.42, + 22.38 ], [ "pass", 23.0, - 23.97 + 24.55 ] ], - "beats": 59.0, + "pins": [ + { + "t": "sitting\u00b7a", + "pin": 0, + "cut": null + }, + { + "t": "sitting\u00b7b", + "pin": 0, + "cut": 1 + }, + { + "t": "curled", + "pin": 1, + "cut": null + }, + { + "t": "up", + "pin": 2, + "cut": null + }, + { + "t": "in", + "pin": 3, + "cut": null + }, + { + "t": "my", + "pin": 4, + "cut": null + }, + { + "t": "self", + "pin": 4, + "cut": 1 + }, + { + "t": "i", + "pin": 5, + "cut": null + }, + { + "t": "think", + "pin": 6, + "cut": null + }, + { + "t": "of", + "pin": 7, + "cut": null + }, + { + "t": "a", + "pin": 8, + "cut": null + }, + { + "t": "stone", + "pin": 9, + "cut": null + }, + { + "t": "just", + "pin": 10, + "cut": null + }, + { + "t": "wait", + "pin": 11, + "cut": null + }, + { + "t": "ing", + "pin": 11, + "cut": 1 + }, + { + "t": "ve", + "pin": 12, + "cut": null + }, + { + "t": "ry", + "pin": 12, + "cut": 1 + }, + { + "t": "pa", + "pin": 13, + "cut": null + }, + { + "t": "tient", + "pin": 13, + "cut": 1 + }, + { + "t": "ly", + "pin": 13, + "cut": 2 + }, + { + "t": "for", + "pin": 14, + "cut": null + }, + { + "t": "time", + "pin": 15, + "cut": null + }, + { + "t": "to", + "pin": 16, + "cut": null + }, + { + "t": "pass", + "pin": 17, + "cut": null + } + ], + "beats": 60.0, "renders": { - "lead": 29.455 + "lead": 30.24 }, "snaps": [ "in +80ms", "my -50ms", "i +180ms", - "think -45ms", - "a -40ms", - "stone -45ms", - "just +80ms", - "pa +80ms" + "think -40ms", + "a -40ms" ], "trims": [ "up \u2212225ms", - "stone \u2212675ms", + "stone \u2212575ms", "just \u2212275ms", - "time \u2212795ms" + "time \u2212795ms", + "to \u2212650ms" ], "words": "the whole lyric, one take" }, "w-sitting-curled": { "slice": "f-sitting-curled", - "lead_in": 0.02, + "lead_in": 0.04, + "spans": [ + [ + "Sitting", + 0.0, + 1.54 + ], + [ + "curled", + 1.54, + 2.44 + ], + [ + "up", + 2.44, + 2.995 + ], + [ + "in", + 3.22, + 3.89 + ], + [ + "myself", + 3.89, + 5.22 + ] + ], + "pins": [ + { + "t": "Sitting", + "pin": 0, + "cut": null + }, + { + "t": "curled", + "pin": 1, + "cut": null + }, + { + "t": "up", + "pin": 2, + "cut": null + }, + { + "t": "in", + "pin": 3, + "cut": null + }, + { + "t": "myself", + "pin": 4, + "cut": null + } + ], "beats": 11.0, "renders": { - "lead": 5.735, - "8ve-a": 5.735, - "8ve-b": 5.735, - "low3": 5.735, - "low5": 5.735 + "lead": 5.755 }, "snaps": [ "up -20ms", @@ -163,20 +333,40 @@ "in +80ms", "myself +30ms" ], "trims": [ - "up \u2212400ms" + "up \u2212225ms" ], "words": "sitting curled up in myself" }, "w-i-think": { "slice": "f-i-think", - "lead_in": 0.02, + "lead_in": 0.04, + "spans": [ + [ + "I", + 0.0, + 0.8 + ], + [ + "think", + 0.8, + 1.32 + ] + ], + "pins": [ + { + "t": "I", + "pin": 0, + "cut": null + }, + { + "t": "think", + "pin": 1, + "cut": null + } + ], "beats": 3.5, "renders": { - "lead": 2.225, - "8ve-a": 2.225, - "8ve-b": 2.225, - "low3": 2.225, - "low5": 2.225 + "lead": 2.245 }, "snaps": [ "think +160ms" @@ -187,13 +377,43 @@ }, "w-of-a-stone": { "slice": "f-of-a-stone", "lead_in": 0.0, + "spans": [ + [ + "of", + 0.0, + 1.58 + ], + [ + "a", + 1.58, + 2.38 + ], + [ + "stone", + 2.38, + 3.16 + ] + ], + "pins": [ + { + "t": "of", + "pin": 0, + "cut": null + }, + { + "t": "a", + "pin": 1, + "cut": null + }, + { + "t": "stone", + "pin": 2, + "cut": null + } + ], "beats": 8.0, "renders": { - "lead": 4.095, - "8ve-a": 4.095, - "8ve-b": 4.095, - "low3": 4.095, - "low5": 4.095 + "lead": 4.095 }, "snaps": [ "a -40ms", @@ -204,72 +424,220 @@ "words": "of a stone" }, "w-just-waiting": { "slice": "f-just-waiting", - "lead_in": 0.075, + "lead_in": 0.15, + "spans": [ + [ + "Just", + 0.0, + 1.33 + ], + [ + "waiting", + 1.655, + 2.94 + ] + ], + "pins": [ + { + "t": "Just", + "pin": 0, + "cut": null + }, + { + "t": "waiting", + "pin": 1, + "cut": null + } + ], "beats": 6.5, "renders": { - "lead": 3.71, - "8ve-a": 3.71, - "8ve-b": 3.71, - "low3": 3.71, - "low5": 3.71 + "lead": 3.785 }, "snaps": [ "waiting +195ms" ], "trims": [ - "Just \u2212340ms" + "Just \u2212325ms" ], "words": "just waiting" }, "w-very-patiently": { "slice": "f-very-patiently", "lead_in": 0.0, + "spans": [ + [ + "very", + 0.0, + 1.64 + ], + [ + "patiently", + 1.64, + 2.92 + ] + ], + "pins": [ + { + "t": "very", + "pin": 0, + "cut": null + }, + { + "t": "patiently", + "pin": 1, + "cut": null + } + ], "beats": 8.5, "renders": { - "lead": 5.435, - "8ve-a": 5.435, - "8ve-b": 5.435, - "low3": 5.435, - "low5": 5.435 + "lead": 5.435 }, "snaps": [ "patiently +240ms" ], - "trims": [ - "very \u2212520ms" - ], + "trims": [], "words": "very patiently" }, "w-for-time-to-pass": { "slice": "f-for-time-to-pass", - "lead_in": 0.035, + "lead_in": 0.07, + "spans": [ + [ + "for", + 0.0, + 0.865 + ], + [ + "time", + 0.865, + 1.985 + ], + [ + "to", + 1.985, + 3.66 + ], + [ + "pass", + 3.81, + 5.7 + ] + ], + "pins": [ + { + "t": "for", + "pin": 0, + "cut": null + }, + { + "t": "time", + "pin": 1, + "cut": null + }, + { + "t": "to", + "pin": 2, + "cut": null + }, + { + "t": "pass", + "pin": 3, + "cut": null + } + ], "beats": 12.5, "renders": { - "lead": 6.695, - "8ve-a": 6.695, - "8ve-b": 6.695, - "low3": 6.695, - "low5": 6.695 + "lead": 6.73 }, "snaps": [ "time +245ms", "to -75ms" ], "trims": [ - "to \u2212185ms" + "to \u2212180ms" ], "words": "for time to pass" }, "w-n-getting-curled": { "slice": "n-getting-curled", "lead_in": 0.0, + "spans": [ + [ + "getting", + 0.0, + 0.725 + ], + [ + "curled", + 0.725, + 1.825 + ], + [ + "up", + 1.825, + 1.905 + ], + [ + "in", + 1.905, + 2.72 + ], + [ + "myself", + 2.72, + 3.89 + ], + [ + "i", + 3.89, + 4.865 + ], + [ + "think", + 4.865, + 5.1 + ] + ], + "pins": [ + { + "t": "getting", + "pin": 0, + "cut": null + }, + { + "t": "curled", + "pin": 1, + "cut": null + }, + { + "t": "up", + "pin": 2, + "cut": null + }, + { + "t": "in", + "pin": 3, + "cut": null + }, + { + "t": "myself", + "pin": 4, + "cut": null + }, + { + "t": "i", + "pin": 5, + "cut": null + }, + { + "t": "think", + "pin": 6, + "cut": null + } + ], "beats": 11.0, "renders": { - "lead": 5.635, - "8ve-a": 5.635, - "8ve-b": 5.635, - "low3": 5.635, - "low5": 5.635 + "lead": 5.635 }, "snaps": [ "curled -55ms", @@ -279,21 +647,79 @@ "myself -40ms", "i -110ms", "think +85ms" ], - "trims": [ - "i \u2212165ms" - ], + "trims": [], "words": "getting curled up in myself i think" }, "w-n-stone-waiting": { "slice": "n-stone-waiting", "lead_in": 0.0, + "spans": [ + [ + "A", + 0.0, + 0.915 + ], + [ + "stone", + 0.915, + 1.845 + ], + [ + "just", + 1.845, + 3.715 + ], + [ + "waiting", + 3.715, + 5.65 + ], + [ + "very", + 5.65, + 7.06 + ], + [ + "patiently", + 7.06, + 8.04 + ] + ], + "pins": [ + { + "t": "A", + "pin": 0, + "cut": null + }, + { + "t": "stone", + "pin": 1, + "cut": null + }, + { + "t": "just", + "pin": 2, + "cut": null + }, + { + "t": "waiting", + "pin": 3, + "cut": null + }, + { + "t": "very", + "pin": 4, + "cut": null + }, + { + "t": "patiently", + "pin": 5, + "cut": null + } + ], "beats": 17.0, "renders": { - "lead": 8.59, - "8ve-a": 8.59, - "8ve-b": 8.59, - "low3": 8.59, - "low5": 8.59 + "lead": 8.59 }, "snaps": [ "stone +155ms", @@ -302,23 +728,59 @@ "waiting -225ms", "very +230ms", "patiently +200ms" ], - "trims": [ - "A \u2212215ms", - "just \u2212265ms", - "very \u2212400ms" - ], + "trims": [], "words": "of a stone just waiting very patiently" }, "w-n-for-time-to-pass": { "slice": "n-for-time-to-pass", "lead_in": 0.0, + "spans": [ + [ + "the", + 0.0, + 0.36 + ], + [ + "time", + 0.36, + 1.1 + ], + [ + "to", + 1.1, + 2.69 + ], + [ + "pass", + 2.69, + 3.56 + ] + ], + "pins": [ + { + "t": "the", + "pin": 0, + "cut": null + }, + { + "t": "time", + "pin": 1, + "cut": null + }, + { + "t": "to", + "pin": 2, + "cut": null + }, + { + "t": "pass", + "pin": 3, + "cut": null + } + ], "beats": 5.5, "renders": { - "lead": 3.13, - "8ve-a": 3.13, - "8ve-b": 3.13, - "low3": 3.13, - "low5": 3.13 + "lead": 3.13 }, "snaps": [ "time +200ms", @@ -326,5 +788,2190 @@ "pass +50ms" ], "trims": [], "words": "for time to pass" + }, + "w-rq": { + "slice": "rq-line", + "lead_in": 0.43, + "spans": [ + [ + "sitting\u00b7a", + 0.37, + 1.615 + ], + [ + "sitting\u00b7b", + 1.615, + 1.845 + ], + [ + "curled", + 2.015, + 3.86 + ], + [ + "up", + 4.03, + 4.345 + ], + [ + "in", + 4.515, + 5.14 + ], + [ + "my", + 5.31, + 6.09 + ], + [ + "self", + 6.09, + 7.02 + ], + [ + "i", + 7.19, + 7.605 + ], + [ + "think", + 7.775, + 8.8 + ], + [ + "of", + 8.97, + 9.865 + ], + [ + "a", + 10.035, + 10.66 + ], + [ + "stone", + 10.83, + 13.25 + ], + [ + "just", + 13.42, + 15.035 + ], + [ + "wait", + 15.205, + 16.16 + ], + [ + "ing", + 16.16, + 16.88 + ], + [ + "ve", + 17.05, + 18.495 + ], + [ + "ry", + 18.495, + 18.765 + ], + [ + "pa", + 18.935, + 19.8 + ], + [ + "tient", + 19.8, + 20.34 + ], + [ + "ly", + 20.34, + 21.21 + ], + [ + "for", + 21.38, + 22.105 + ], + [ + "time", + 22.275, + 24.39 + ], + [ + "to", + 24.56, + 25.205 + ], + [ + "pass", + 25.375, + 26.975 + ] + ], + "pins": [ + { + "t": "sitting\u00b7a", + "pin": 0, + "cut": null + }, + { + "t": "sitting\u00b7b", + "pin": 0, + "cut": 1 + }, + { + "t": "curled", + "pin": 1, + "cut": null + }, + { + "t": "up", + "pin": 2, + "cut": null + }, + { + "t": "in", + "pin": 3, + "cut": null + }, + { + "t": "my", + "pin": 4, + "cut": null + }, + { + "t": "self", + "pin": 4, + "cut": 1 + }, + { + "t": "i", + "pin": 5, + "cut": null + }, + { + "t": "think", + "pin": 6, + "cut": null + }, + { + "t": "of", + "pin": 7, + "cut": null + }, + { + "t": "a", + "pin": 8, + "cut": null + }, + { + "t": "stone", + "pin": 9, + "cut": null + }, + { + "t": "just", + "pin": 10, + "cut": null + }, + { + "t": "wait", + "pin": 11, + "cut": null + }, + { + "t": "ing", + "pin": 11, + "cut": 1 + }, + { + "t": "ve", + "pin": 12, + "cut": null + }, + { + "t": "ry", + "pin": 12, + "cut": 1 + }, + { + "t": "pa", + "pin": 13, + "cut": null + }, + { + "t": "tient", + "pin": 13, + "cut": 1 + }, + { + "t": "ly", + "pin": 13, + "cut": 2 + }, + { + "t": "for", + "pin": 14, + "cut": null + }, + { + "t": "time", + "pin": 15, + "cut": null + }, + { + "t": "to", + "pin": 16, + "cut": null + }, + { + "t": "pass", + "pin": 17, + "cut": null + } + ], + "beats": 60.0, + "renders": { + "lead": 30.34 + }, + "snaps": [], + "trims": [ + "sitting\u00b7b \u2212200ms", + "curled \u2212200ms", + "up \u2212200ms", + "in \u2212200ms", + "self \u2212200ms", + "i \u2212200ms", + "think \u2212200ms", + "of \u2212200ms", + "a \u2212200ms", + "stone \u2212200ms", + "just \u2212200ms", + "ing \u2212200ms", + "ry \u2212200ms", + "ly \u2212200ms", + "for \u2212200ms", + "time \u2212200ms", + "to \u2212200ms" + ], + "words": "the whole lyric, assembled from corpus" + }, + "w-sh": { + "slice": "sh-line", + "lead_in": 0.84, + "spans": [ + [ + "sitting\u00b7a", + 0.37, + 1.48 + ], + [ + "sitting\u00b7b", + 1.48, + 2.095 + ], + [ + "curled", + 2.265, + 3.84 + ], + [ + "up", + 4.01, + 4.56 + ], + [ + "in", + 4.73, + 5.45 + ], + [ + "my", + 5.62, + 6.98 + ], + [ + "self", + 6.98, + 7.245 + ], + [ + "i", + 7.415, + 7.785 + ], + [ + "think", + 7.955, + 8.995 + ], + [ + "of", + 9.165, + 9.875 + ], + [ + "a", + 10.045, + 10.46 + ], + [ + "stone", + 10.63, + 12.765 + ], + [ + "just", + 12.935, + 14.605 + ], + [ + "wait", + 14.775, + 15.08 + ], + [ + "ing", + 15.08, + 16.575 + ], + [ + "ve", + 16.745, + 17.765 + ], + [ + "ry", + 17.765, + 18.0 + ], + [ + "pa", + 18.17, + 18.535 + ], + [ + "tient", + 18.535, + 19.815 + ], + [ + "ly", + 19.815, + 20.67 + ], + [ + "for", + 20.84, + 21.835 + ], + [ + "time", + 22.005, + 23.325 + ], + [ + "to", + 23.495, + 24.675 + ], + [ + "pass", + 24.845, + 26.975 + ] + ], + "pins": [ + { + "t": "sitting\u00b7a", + "pin": 0, + "cut": null + }, + { + "t": "sitting\u00b7b", + "pin": 0, + "cut": 1 + }, + { + "t": "curled", + "pin": 1, + "cut": null + }, + { + "t": "up", + "pin": 2, + "cut": null + }, + { + "t": "in", + "pin": 3, + "cut": null + }, + { + "t": "my", + "pin": 4, + "cut": null + }, + { + "t": "self", + "pin": 4, + "cut": 1 + }, + { + "t": "i", + "pin": 5, + "cut": null + }, + { + "t": "think", + "pin": 6, + "cut": null + }, + { + "t": "of", + "pin": 7, + "cut": null + }, + { + "t": "a", + "pin": 8, + "cut": null + }, + { + "t": "stone", + "pin": 9, + "cut": null + }, + { + "t": "just", + "pin": 10, + "cut": null + }, + { + "t": "wait", + "pin": 11, + "cut": null + }, + { + "t": "ing", + "pin": 11, + "cut": 1 + }, + { + "t": "ve", + "pin": 12, + "cut": null + }, + { + "t": "ry", + "pin": 12, + "cut": 1 + }, + { + "t": "pa", + "pin": 13, + "cut": null + }, + { + "t": "tient", + "pin": 13, + "cut": 1 + }, + { + "t": "ly", + "pin": 13, + "cut": 2 + }, + { + "t": "for", + "pin": 14, + "cut": null + }, + { + "t": "time", + "pin": 15, + "cut": null + }, + { + "t": "to", + "pin": 16, + "cut": null + }, + { + "t": "pass", + "pin": 17, + "cut": null + } + ], + "beats": 60.0, + "renders": { + "lead": 30.75 + }, + "snaps": [], + "trims": [ + "sitting\u00b7b \u2212200ms", + "curled \u2212200ms", + "up \u2212200ms", + "in \u2212200ms", + "self \u2212200ms", + "i \u2212200ms", + "think \u2212200ms", + "of \u2212200ms", + "a \u2212200ms", + "stone \u2212200ms", + "just \u2212200ms", + "ing \u2212200ms", + "ry \u2212200ms", + "ly \u2212200ms", + "for \u2212200ms", + "time \u2212200ms", + "to \u2212200ms" + ], + "words": "the whole lyric, assembled from corpus" + }, + "w-lg": { + "slice": "lg-line", + "lead_in": 0.575, + "spans": [ + [ + "sitting\u00b7a", + 0.37, + 1.345 + ], + [ + "sitting\u00b7b", + 1.345, + 2.025 + ], + [ + "curled", + 2.195, + 3.71 + ], + [ + "up", + 3.88, + 4.495 + ], + [ + "in", + 4.665, + 5.335 + ], + [ + "my", + 5.505, + 7.005 + ], + [ + "self", + 7.005, + 7.3 + ], + [ + "i", + 7.47, + 7.75 + ], + [ + "think", + 7.915, + 8.855 + ], + [ + "of", + 9.025, + 9.985 + ], + [ + "a", + 10.155, + 10.725 + ], + [ + "stone", + 10.895, + 13.455 + ], + [ + "just", + 13.66, + 15.105 + ], + [ + "wait", + 15.275, + 16.19 + ], + [ + "ing", + 16.19, + 17.08 + ], + [ + "ve", + 17.25, + 18.36 + ], + [ + "ry", + 18.36, + 18.575 + ], + [ + "pa", + 18.745, + 19.645 + ], + [ + "tient", + 19.645, + 20.245 + ], + [ + "ly", + 20.245, + 21.035 + ], + [ + "for", + 21.205, + 22.255 + ], + [ + "time", + 22.425, + 23.7 + ], + [ + "to", + 23.87, + 24.91 + ], + [ + "pass", + 25.08, + 26.81 + ] + ], + "pins": [ + { + "t": "sitting\u00b7a", + "pin": 0, + "cut": null + }, + { + "t": "sitting\u00b7b", + "pin": 0, + "cut": 1 + }, + { + "t": "curled", + "pin": 1, + "cut": null + }, + { + "t": "up", + "pin": 2, + "cut": null + }, + { + "t": "in", + "pin": 3, + "cut": null + }, + { + "t": "my", + "pin": 4, + "cut": null + }, + { + "t": "self", + "pin": 4, + "cut": 1 + }, + { + "t": "i", + "pin": 5, + "cut": null + }, + { + "t": "think", + "pin": 6, + "cut": null + }, + { + "t": "of", + "pin": 7, + "cut": null + }, + { + "t": "a", + "pin": 8, + "cut": null + }, + { + "t": "stone", + "pin": 9, + "cut": null + }, + { + "t": "just", + "pin": 10, + "cut": null + }, + { + "t": "wait", + "pin": 11, + "cut": null + }, + { + "t": "ing", + "pin": 11, + "cut": 1 + }, + { + "t": "ve", + "pin": 12, + "cut": null + }, + { + "t": "ry", + "pin": 12, + "cut": 1 + }, + { + "t": "pa", + "pin": 13, + "cut": null + }, + { + "t": "tient", + "pin": 13, + "cut": 1 + }, + { + "t": "ly", + "pin": 13, + "cut": 2 + }, + { + "t": "for", + "pin": 14, + "cut": null + }, + { + "t": "time", + "pin": 15, + "cut": null + }, + { + "t": "to", + "pin": 16, + "cut": null + }, + { + "t": "pass", + "pin": 17, + "cut": null + } + ], + "beats": 60.0, + "renders": { + "lead": 30.485 + }, + "snaps": [], + "trims": [ + "sitting\u00b7b \u2212200ms", + "curled \u2212200ms", + "up \u2212200ms", + "in \u2212200ms", + "self \u2212200ms", + "i \u2212195ms", + "think \u2212200ms", + "of \u2212200ms", + "a \u2212200ms", + "stone \u2212205ms", + "just \u2212200ms", + "ing \u2212200ms", + "ry \u2212200ms", + "ly \u2212200ms", + "for \u2212200ms", + "time \u2212200ms", + "to \u2212200ms" + ], + "words": "the whole lyric, assembled from corpus" + }, + "w-pf": { + "slice": "pf-line", + "lead_in": 0.765, + "spans": [ + [ + "sitting\u00b7a", + 0.37, + 0.945 + ], + [ + "sitting\u00b7b", + 0.945, + 2.015 + ], + [ + "curled", + 2.185, + 3.765 + ], + [ + "up", + 3.935, + 4.54 + ], + [ + "in", + 4.71, + 5.425 + ], + [ + "my", + 5.595, + 6.395 + ], + [ + "self", + 6.395, + 7.165 + ], + [ + "i", + 7.37, + 7.62 + ], + [ + "think", + 7.79, + 8.915 + ], + [ + "of", + 9.085, + 9.905 + ], + [ + "a", + 10.075, + 10.48 + ], + [ + "stone", + 10.65, + 12.705 + ], + [ + "just", + 12.88, + 14.23 + ], + [ + "wait", + 14.4, + 14.635 + ], + [ + "ing", + 14.635, + 16.005 + ], + [ + "ve", + 16.175, + 17.26 + ], + [ + "ry", + 17.26, + 17.505 + ], + [ + "pa", + 17.675, + 18.095 + ], + [ + "tient", + 18.095, + 19.375 + ], + [ + "ly", + 19.375, + 20.225 + ], + [ + "for", + 20.395, + 21.39 + ], + [ + "time", + 21.56, + 22.88 + ], + [ + "to", + 23.05, + 24.105 + ], + [ + "pass", + 24.305, + 26.53 + ] + ], + "pins": [ + { + "t": "sitting\u00b7a", + "pin": 0, + "cut": null + }, + { + "t": "sitting\u00b7b", + "pin": 0, + "cut": 1 + }, + { + "t": "curled", + "pin": 1, + "cut": null + }, + { + "t": "up", + "pin": 2, + "cut": null + }, + { + "t": "in", + "pin": 3, + "cut": null + }, + { + "t": "my", + "pin": 4, + "cut": null + }, + { + "t": "self", + "pin": 4, + "cut": 1 + }, + { + "t": "i", + "pin": 5, + "cut": null + }, + { + "t": "think", + "pin": 6, + "cut": null + }, + { + "t": "of", + "pin": 7, + "cut": null + }, + { + "t": "a", + "pin": 8, + "cut": null + }, + { + "t": "stone", + "pin": 9, + "cut": null + }, + { + "t": "just", + "pin": 10, + "cut": null + }, + { + "t": "wait", + "pin": 11, + "cut": null + }, + { + "t": "ing", + "pin": 11, + "cut": 1 + }, + { + "t": "ve", + "pin": 12, + "cut": null + }, + { + "t": "ry", + "pin": 12, + "cut": 1 + }, + { + "t": "pa", + "pin": 13, + "cut": null + }, + { + "t": "tient", + "pin": 13, + "cut": 1 + }, + { + "t": "ly", + "pin": 13, + "cut": 2 + }, + { + "t": "for", + "pin": 14, + "cut": null + }, + { + "t": "time", + "pin": 15, + "cut": null + }, + { + "t": "to", + "pin": 16, + "cut": null + }, + { + "t": "pass", + "pin": 17, + "cut": null + } + ], + "beats": 60.0, + "renders": { + "lead": 30.675 + }, + "snaps": [], + "trims": [ + "sitting\u00b7b \u2212200ms", + "curled \u2212200ms", + "up \u2212200ms", + "in \u2212200ms", + "self \u2212205ms", + "i \u2212200ms", + "think \u2212200ms", + "of \u2212200ms", + "a \u2212200ms", + "stone \u2212205ms", + "just \u2212200ms", + "ing \u2212200ms", + "ry \u2212200ms", + "ly \u2212200ms", + "for \u2212200ms", + "time \u2212200ms", + "to \u2212200ms" + ], + "words": "the whole lyric, assembled from corpus" + }, + "w-rd": { + "slice": "rd-line", + "lead_in": 0.405, + "spans": [ + [ + "sitting\u00b7a", + 0.37, + 1.665 + ], + [ + "sitting\u00b7b", + 1.665, + 2.09 + ], + [ + "curled", + 2.255, + 3.765 + ], + [ + "up", + 3.935, + 4.555 + ], + [ + "in", + 4.725, + 5.175 + ], + [ + "my", + 5.345, + 6.605 + ], + [ + "self", + 6.605, + 6.98 + ], + [ + "i", + 7.18, + 7.445 + ], + [ + "think", + 7.615, + 8.385 + ], + [ + "of", + 8.555, + 9.41 + ], + [ + "a", + 9.58, + 9.84 + ], + [ + "stone", + 10.01, + 11.68 + ], + [ + "just", + 11.85, + 13.12 + ], + [ + "wait", + 13.29, + 13.675 + ], + [ + "ing", + 13.675, + 15.37 + ], + [ + "ve", + 15.54, + 16.315 + ], + [ + "ry", + 16.315, + 16.745 + ], + [ + "pa", + 16.915, + 18.03 + ], + [ + "tient", + 18.03, + 18.62 + ], + [ + "ly", + 18.62, + 19.65 + ], + [ + "for", + 19.82, + 20.725 + ], + [ + "time", + 20.89, + 22.19 + ], + [ + "to", + 22.36, + 23.17 + ], + [ + "pass", + 23.37, + 24.505 + ] + ], + "pins": [ + { + "t": "sitting\u00b7a", + "pin": 0, + "cut": null + }, + { + "t": "sitting\u00b7b", + "pin": 0, + "cut": 1 + }, + { + "t": "curled", + "pin": 1, + "cut": null + }, + { + "t": "up", + "pin": 2, + "cut": null + }, + { + "t": "in", + "pin": 3, + "cut": null + }, + { + "t": "my", + "pin": 4, + "cut": null + }, + { + "t": "self", + "pin": 4, + "cut": 1 + }, + { + "t": "i", + "pin": 5, + "cut": null + }, + { + "t": "think", + "pin": 6, + "cut": null + }, + { + "t": "of", + "pin": 7, + "cut": null + }, + { + "t": "a", + "pin": 8, + "cut": null + }, + { + "t": "stone", + "pin": 9, + "cut": null + }, + { + "t": "just", + "pin": 10, + "cut": null + }, + { + "t": "wait", + "pin": 11, + "cut": null + }, + { + "t": "ing", + "pin": 11, + "cut": 1 + }, + { + "t": "ve", + "pin": 12, + "cut": null + }, + { + "t": "ry", + "pin": 12, + "cut": 1 + }, + { + "t": "pa", + "pin": 13, + "cut": null + }, + { + "t": "tient", + "pin": 13, + "cut": 1 + }, + { + "t": "ly", + "pin": 13, + "cut": 2 + }, + { + "t": "for", + "pin": 14, + "cut": null + }, + { + "t": "time", + "pin": 15, + "cut": null + }, + { + "t": "to", + "pin": 16, + "cut": null + }, + { + "t": "pass", + "pin": 17, + "cut": null + } + ], + "beats": 60.0, + "renders": { + "lead": 30.315 + }, + "snaps": [], + "trims": [ + "sitting\u00b7b \u2212195ms", + "curled \u2212200ms", + "up \u2212200ms", + "in \u2212200ms", + "self \u2212200ms", + "i \u2212200ms", + "think \u2212200ms", + "of \u2212200ms", + "a \u2212200ms", + "stone \u2212200ms", + "just \u2212200ms", + "ing \u2212200ms", + "ry \u2212200ms", + "ly \u2212200ms", + "for \u2212195ms", + "time \u2212200ms", + "to \u2212200ms" + ], + "words": "the whole lyric, assembled from corpus" + }, + "w-cp": { + "slice": "cp-line", + "lead_in": 0.43, + "spans": [ + [ + "sitting\u00b7a", + 0.37, + 0.825 + ], + [ + "sitting\u00b7b", + 0.825, + 1.35 + ], + [ + "curled", + 1.52, + 2.58 + ], + [ + "up", + 2.75, + 3.2 + ], + [ + "in", + 3.37, + 3.695 + ], + [ + "my", + 3.865, + 4.845 + ], + [ + "self", + 4.845, + 5.055 + ], + [ + "i", + 5.225, + 5.625 + ], + [ + "think", + 5.795, + 6.57 + ], + [ + "of", + 6.74, + 7.885 + ], + [ + "a", + 8.055, + 8.505 + ], + [ + "stone", + 8.675, + 9.36 + ], + [ + "just", + 9.53, + 10.755 + ], + [ + "wait", + 10.925, + 11.58 + ], + [ + "ing", + 11.635, + 13.44 + ], + [ + "ve", + 13.64, + 14.35 + ], + [ + "ry", + 14.35, + 14.495 + ], + [ + "pa", + 14.665, + 15.67 + ], + [ + "tient", + 15.67, + 16.875 + ], + [ + "ly", + 16.875, + 17.48 + ], + [ + "for", + 17.65, + 18.435 + ], + [ + "time", + 18.605, + 19.82 + ], + [ + "to", + 19.99, + 20.71 + ], + [ + "pass", + 20.88, + 22.06 + ] + ], + "pins": [ + { + "t": "sitting\u00b7a", + "pin": 0, + "cut": null + }, + { + "t": "sitting\u00b7b", + "pin": 0, + "cut": 1 + }, + { + "t": "curled", + "pin": 1, + "cut": null + }, + { + "t": "up", + "pin": 2, + "cut": null + }, + { + "t": "in", + "pin": 3, + "cut": null + }, + { + "t": "my", + "pin": 4, + "cut": null + }, + { + "t": "self", + "pin": 4, + "cut": 1 + }, + { + "t": "i", + "pin": 5, + "cut": null + }, + { + "t": "think", + "pin": 6, + "cut": null + }, + { + "t": "of", + "pin": 7, + "cut": null + }, + { + "t": "a", + "pin": 8, + "cut": null + }, + { + "t": "stone", + "pin": 9, + "cut": null + }, + { + "t": "just", + "pin": 10, + "cut": null + }, + { + "t": "wait", + "pin": 11, + "cut": null + }, + { + "t": "ing", + "pin": 11, + "cut": 1 + }, + { + "t": "ve", + "pin": 12, + "cut": null + }, + { + "t": "ry", + "pin": 12, + "cut": 1 + }, + { + "t": "pa", + "pin": 13, + "cut": null + }, + { + "t": "tient", + "pin": 13, + "cut": 1 + }, + { + "t": "ly", + "pin": 13, + "cut": 2 + }, + { + "t": "for", + "pin": 14, + "cut": null + }, + { + "t": "time", + "pin": 15, + "cut": null + }, + { + "t": "to", + "pin": 16, + "cut": null + }, + { + "t": "pass", + "pin": 17, + "cut": null + } + ], + "beats": 60.0, + "renders": { + "lead": 30.34 + }, + "snaps": [], + "trims": [ + "sitting\u00b7b \u2212200ms", + "curled \u2212200ms", + "up \u2212200ms", + "in \u2212200ms", + "self \u2212200ms", + "i \u2212200ms", + "think \u2212200ms", + "of \u2212200ms", + "a \u2212200ms", + "stone \u2212200ms", + "just \u2212200ms", + "wait \u221285ms", + "ing \u2212200ms", + "ry \u2212200ms", + "ly \u2212200ms", + "for \u2212200ms", + "time \u2212200ms", + "to \u2212200ms" + ], + "words": "the whole lyric, assembled from corpus" + }, + "w-s": { + "slice": "s-line", + "lead_in": 0.37, + "spans": [ + [ + "sitting\u00b7a", + 0.37, + 0.665 + ], + [ + "sitting\u00b7b", + 0.665, + 2.005 + ], + [ + "curled", + 2.175, + 3.615 + ], + [ + "up", + 3.815, + 4.375 + ], + [ + "in", + 4.54, + 5.105 + ], + [ + "my", + 5.275, + 6.145 + ], + [ + "self", + 6.145, + 6.86 + ], + [ + "i", + 7.03, + 7.275 + ], + [ + "think", + 7.445, + 8.505 + ], + [ + "of", + 8.675, + 9.39 + ], + [ + "a", + 9.56, + 10.07 + ], + [ + "stone", + 10.24, + 12.215 + ], + [ + "just", + 12.385, + 13.5 + ], + [ + "wait", + 13.67, + 14.375 + ], + [ + "ing", + 14.375, + 15.705 + ], + [ + "ve", + 15.875, + 16.13 + ], + [ + "ry", + 16.13, + 16.92 + ], + [ + "pa", + 17.085, + 17.595 + ], + [ + "tient", + 17.595, + 18.375 + ], + [ + "ly", + 18.375, + 19.92 + ], + [ + "for", + 20.09, + 20.965 + ], + [ + "time", + 21.13, + 22.61 + ], + [ + "to", + 22.78, + 24.075 + ], + [ + "pass", + 24.245, + 25.34 + ] + ], + "pins": [ + { + "t": "sitting\u00b7a", + "pin": 0, + "cut": null + }, + { + "t": "sitting\u00b7b", + "pin": 0, + "cut": 1 + }, + { + "t": "curled", + "pin": 1, + "cut": null + }, + { + "t": "up", + "pin": 2, + "cut": null + }, + { + "t": "in", + "pin": 3, + "cut": null + }, + { + "t": "my", + "pin": 4, + "cut": null + }, + { + "t": "self", + "pin": 4, + "cut": 1 + }, + { + "t": "i", + "pin": 5, + "cut": null + }, + { + "t": "think", + "pin": 6, + "cut": null + }, + { + "t": "of", + "pin": 7, + "cut": null + }, + { + "t": "a", + "pin": 8, + "cut": null + }, + { + "t": "stone", + "pin": 9, + "cut": null + }, + { + "t": "just", + "pin": 10, + "cut": null + }, + { + "t": "wait", + "pin": 11, + "cut": null + }, + { + "t": "ing", + "pin": 11, + "cut": 1 + }, + { + "t": "ve", + "pin": 12, + "cut": null + }, + { + "t": "ry", + "pin": 12, + "cut": 1 + }, + { + "t": "pa", + "pin": 13, + "cut": null + }, + { + "t": "tient", + "pin": 13, + "cut": 1 + }, + { + "t": "ly", + "pin": 13, + "cut": 2 + }, + { + "t": "for", + "pin": 14, + "cut": null + }, + { + "t": "time", + "pin": 15, + "cut": null + }, + { + "t": "to", + "pin": 16, + "cut": null + }, + { + "t": "pass", + "pin": 17, + "cut": null + } + ], + "beats": 60.0, + "renders": { + "lead": 30.28 + }, + "snaps": [], + "trims": [ + "sitting\u00b7b \u2212200ms", + "curled \u2212200ms", + "up \u2212195ms", + "in \u2212200ms", + "self \u2212200ms", + "i \u2212200ms", + "think \u2212200ms", + "of \u2212200ms", + "a \u2212200ms", + "stone \u2212200ms", + "just \u2212200ms", + "ing \u2212200ms", + "ry \u2212195ms", + "ly \u2212200ms", + "for \u2212195ms", + "time \u2212200ms", + "to \u2212200ms" + ], + "words": "the whole lyric, assembled from corpus" + }, + "w-o": { + "slice": "o-line", + "lead_in": 0.55, + "spans": [ + [ + "sitting\u00b7a", + 0.37, + 1.445 + ], + [ + "sitting\u00b7b", + 1.445, + 1.805 + ], + [ + "curled", + 1.975, + 3.2 + ], + [ + "up", + 3.37, + 4.165 + ], + [ + "in", + 4.335, + 4.93 + ], + [ + "my", + 5.1, + 5.875 + ], + [ + "self", + 5.875, + 6.77 + ], + [ + "i", + 6.94, + 7.665 + ], + [ + "think", + 7.835, + 8.725 + ], + [ + "of", + 8.895, + 9.665 + ], + [ + "a", + 9.835, + 10.255 + ], + [ + "stone", + 10.455, + 12.16 + ], + [ + "just", + 12.33, + 14.515 + ], + [ + "wait", + 14.685, + 15.895 + ], + [ + "ing", + 15.895, + 16.3 + ], + [ + "ve", + 16.47, + 17.675 + ], + [ + "ry", + 17.675, + 18.055 + ], + [ + "pa", + 18.22, + 20.06 + ], + [ + "tient", + 20.06, + 20.67 + ], + [ + "ly", + 20.67, + 21.15 + ], + [ + "for", + 21.32, + 22.43 + ], + [ + "time", + 22.6, + 23.985 + ], + [ + "to", + 24.155, + 24.905 + ], + [ + "pass", + 25.075, + 26.59 + ] + ], + "pins": [ + { + "t": "sitting\u00b7a", + "pin": 0, + "cut": null + }, + { + "t": "sitting\u00b7b", + "pin": 0, + "cut": 1 + }, + { + "t": "curled", + "pin": 1, + "cut": null + }, + { + "t": "up", + "pin": 2, + "cut": null + }, + { + "t": "in", + "pin": 3, + "cut": null + }, + { + "t": "my", + "pin": 4, + "cut": null + }, + { + "t": "self", + "pin": 4, + "cut": 1 + }, + { + "t": "i", + "pin": 5, + "cut": null + }, + { + "t": "think", + "pin": 6, + "cut": null + }, + { + "t": "of", + "pin": 7, + "cut": null + }, + { + "t": "a", + "pin": 8, + "cut": null + }, + { + "t": "stone", + "pin": 9, + "cut": null + }, + { + "t": "just", + "pin": 10, + "cut": null + }, + { + "t": "wait", + "pin": 11, + "cut": null + }, + { + "t": "ing", + "pin": 11, + "cut": 1 + }, + { + "t": "ve", + "pin": 12, + "cut": null + }, + { + "t": "ry", + "pin": 12, + "cut": 1 + }, + { + "t": "pa", + "pin": 13, + "cut": null + }, + { + "t": "tient", + "pin": 13, + "cut": 1 + }, + { + "t": "ly", + "pin": 13, + "cut": 2 + }, + { + "t": "for", + "pin": 14, + "cut": null + }, + { + "t": "time", + "pin": 15, + "cut": null + }, + { + "t": "to", + "pin": 16, + "cut": null + }, + { + "t": "pass", + "pin": 17, + "cut": null + } + ], + "beats": 60.0, + "renders": { + "lead": 30.46 + }, + "snaps": [], + "trims": [ + "sitting\u00b7b \u2212200ms", + "curled \u2212200ms", + "up \u2212200ms", + "in \u2212200ms", + "self \u2212200ms", + "i \u2212200ms", + "think \u2212200ms", + "of \u2212200ms", + "a \u2212200ms", + "stone \u2212200ms", + "just \u2212200ms", + "ing \u2212200ms", + "ry \u2212195ms", + "ly \u2212200ms", + "for \u2212200ms", + "time \u2212200ms", + "to \u2212200ms" + ], + "words": "the whole lyric, assembled from corpus" } } \ No newline at end of file diff --git a/pop/loner/vox4/.wizard.json b/pop/loner/vox4/.wizard.json new file mode 100644 --- /dev/null +++ b/pop/loner/vox4/.wizard.json @@ -0,0 +1,1 @@ +{"lane": "loner", "bpm": 122.0, "tonic": 237.0, "frame_s": 0.005, "phrases": {"w-whole-line": {"slice": "f-whole-line", "wav": "/Users/jas/aesthetic-computer/pop/loner/samples/f-whole-line.wav", "sr": 48000, "leadIn": 0.04, "beats": 60.0, "units": [{"t": "sitting\u00b7a", "beat": 0.0, "dur": 2.0, "st": 7, "src0": 0.0, "src1": 0.755}, {"t": "sitting\u00b7b", "beat": 2.0, "dur": 2.0, "st": 5, "src0": 0.755, "src1": 1.51}, {"t": "curled", "beat": 4.0, "dur": 1.91, "st": 3, "src0": 1.51, "src1": 2.4}, {"t": "up", "beat": 5.91, "dur": 2.09, "st": 2, "src0": 2.4, "src1": 2.995}, {"t": "in", "beat": 8.0, "dur": 2.0, "st": 0, "src0": 3.22, "src1": 3.89}, {"t": "my", "beat": 10.0, "dur": 1.5, "st": 5, "src0": 3.89, "src1": 4.5}, {"t": "self", "beat": 11.5, "dur": 2.5, "st": 2, "src0": 4.5, "src1": 5.5}, {"t": "i", "beat": 14.0, "dur": 2.0, "st": -2, "src0": 5.5, "src1": 6.215}, {"t": "think", "beat": 16.0, "dur": 2.0, "st": -5, "src0": 6.215, "src1": 7.15}, {"t": "of", "beat": 18.0, "dur": 4.0, "st": 12, "src0": 7.15, "src1": 8.76}, {"t": "a", "beat": 22.0, "dur": 1.75, "st": 10, "src0": 8.76, "src1": 9.19}, {"t": "stone", "beat": 23.75, "dur": 4.25, "st": 5, "src0": 9.19, "src1": 10.52}, {"t": "just", "beat": 28.0, "dur": 4.0, "st": 2, "src0": 11.065, "src1": 12.425}, {"t": "wait", "beat": 32.0, "dur": 2.0, "st": 3, "src0": 12.67, "src1": 13.7}, {"t": "ing", "beat": 34.0, "dur": 2.0, "st": 2, "src0": 13.7, "src1": 14.4}, {"t": "ve", "beat": 36.0, "dur": 2.0, "st": 0, "src0": 14.4, "src1": 15.17}, {"t": "ry", "beat": 38.0, "dur": 2.0, "st": -2, "src0": 15.17, "src1": 15.9}, {"t": "pa", "beat": 40.0, "dur": 2.0, "st": 7, "src0": 15.9, "src1": 16.655}, {"t": "tient", "beat": 42.0, "dur": 2.0, "st": 5, "src0": 16.655, "src1": 17.7}, {"t": "ly", "beat": 44.0, "dur": 2.0, "st": 3, "src0": 17.7, "src1": 18.54}, {"t": "for", "beat": 46.0, "dur": 2.0, "st": 5, "src0": 18.54, "src1": 19.315}, {"t": "time", "beat": 48.0, "dur": 4.0, "st": 7, "src0": 19.315, "src1": 20.405}, {"t": "to", "beat": 52.0, "dur": 4.0, "st": 3, "src0": 21.2, "src1": 22.16}, {"t": "pass", "beat": 56.0, "dur": 4.0, "st": 3, "src0": 22.78, "src1": 24.31}], "events": [{"a": 0.05, "b": 0.785, "kind": "NOTE", "st": 6.86}, {"a": 0.785, "b": 1.5, "kind": "NOTE", "st": 4.8}, {"a": 1.585, "b": 2.69, "kind": "NOTE", "st": 2.73}, {"a": 3.19, "b": 3.81, "kind": "NOTE", "st": 0.01}, {"a": 3.81, "b": 3.935, "kind": "NOTE", "st": 1.32}, {"a": 3.935, "b": 4.47, "kind": "NOTE", "st": 5.16}, {"a": 4.47, "b": 4.73, "kind": "FRIC", "st": null}, {"a": 4.74, "b": 5.175, "kind": "NOTE", "st": 2.15}, {"a": 5.485, "b": 6.11, "kind": "NOTE", "st": -2.0}, {"a": 6.3, "b": 6.545, "kind": "NOTE", "st": -4.86}, {"a": 7.18, "b": 8.685, "kind": "NOTE", "st": 11.89}, {"a": 8.78, "b": 9.145, "kind": "NOTE", "st": 10.34}, {"a": 9.265, "b": 9.475, "kind": "FRIC", "st": null}, {"a": 9.565, "b": 10.465, "kind": "NOTE", "st": 5.06}, {"a": 11.11, "b": 11.235, "kind": "FRIC", "st": null}, {"a": 11.235, "b": 11.975, "kind": "NOTE", "st": 2.16}, {"a": 12.73, "b": 14.450000000000001, "kind": "NOTE", "st": 2.68}, {"a": 14.450000000000001, "b": 15.165000000000001, "kind": "NOTE", "st": 0.03}, {"a": 15.165000000000001, "b": 15.44, "kind": "NOTE", "st": -2.0}, {"a": 15.92, "b": 16.045, "kind": "NOTE", "st": 6.45}, {"a": 16.045, "b": 16.615000000000002, "kind": "NOTE", "st": 7.22}, {"a": 16.615000000000002, "b": 16.830000000000002, "kind": "FRIC", "st": null}, {"a": 16.845, "b": 17.16, "kind": "NOTE", "st": 5.09}, {"a": 17.66, "b": 18.365000000000002, "kind": "NOTE", "st": 2.94}, {"a": 18.53, "b": 19.225, "kind": "NOTE", "st": 5.2}, {"a": 19.315, "b": 19.45, "kind": "PUFF", "st": null}, {"a": 19.48, "b": 20.345, "kind": "NOTE", "st": 7.14}, {"a": 21.11, "b": 21.215, "kind": "FRIC", "st": null}, {"a": 21.245, "b": 22.1, "kind": "NOTE", "st": 3.06}, {"a": 22.825, "b": 22.985, "kind": "PUFF", "st": null}, {"a": 22.985, "b": 23.92, "kind": "NOTE", "st": 3.02}], "frames": {"st": [null, null, null, null, 10.04, 8.1, 5.35, 4.44, 3.1, 6.53, 7.52, 8.09, 7.97, 7.52, 7.32, 7.25, 7.3, 7.23, 7.23, 7.21, 7.24, 7.21, 7.18, 7.12, 7.09, 7.02, 7.0, 6.94, 6.96, 6.9, 6.9, 6.95, 6.94, 6.94, 6.96, 6.98, 6.99, 6.98, 6.99, 6.99, 7.01, 6.98, 6.97, 6.99, 6.96, 6.95, 6.92, 6.97, 6.95, 6.96, 6.96, 7.0, 6.96, 6.99, 6.98, 6.96, 6.95, 6.99, 6.95, 6.96, 6.99, 6.93, 6.97, 6.96, 6.96, 6.96, 6.89, 6.89, 6.91, 6.88, 6.84, 6.83, 6.87, 6.86, 6.83, 6.87, 6.85, 6.87, 6.84, 6.88, 6.86, 6.86, 6.86, 6.89, 6.88, 6.92, 6.89, 6.88, 6.87, 6.84, 6.86, 6.88, 6.83, 6.84, 6.82, 6.83, 6.8, 6.81, 6.83, 6.81, 6.78, 6.78, 6.82, 6.8, 6.8, 6.79, 6.73, 6.75, 6.77, 6.71, 6.76, 6.78, 6.76, 6.77, 6.78, 6.8, 6.77, 6.77, 6.78, 6.79, 6.75, 6.77, 6.73, 6.75, 6.74, 6.74, 6.75, 6.72, 6.73, 6.76, 6.74, 6.7, 6.73, 6.75, 6.73, 6.69, 6.7, 6.73, 6.73, 6.72, 6.69, 6.73, 6.72, 6.68, 6.68, 6.66, 6.54, 6.51, 6.42, 6.3, 5.83, 6.21, 6.25, 5.98, 6.3, 6.25, 6.6, 6.7, 6.55, 6.56, 6.84, 6.6, 6.91, 6.37, 5.69, 5.29, 4.98, 5.11, 5.08, 4.95, 4.94, 4.89, 4.87, 4.85, 4.87, 4.82, 4.92, 4.94, 4.94, 4.96, 4.92, 4.95, 5.04, 5.05, 5.07, 5.1, 5.08, 5.11, 5.1, 5.15, 5.14, 5.13, 5.09, 5.08, 5.1, 5.05, 5.03, 5.11, 5.04, 5.06, 5.02, 5.06, 4.98, 5.01, 5.03, 4.98, 4.93, 4.95, 4.99, 4.9, 4.91, 4.87, 4.88, 4.88, 4.89, 4.83, 4.83, 4.84, 4.86, 4.79, 4.83, 4.79, 4.81, 4.79, 4.76, 4.78, 4.76, 4.8, 4.72, 4.81, 4.75, 4.72, 4.72, 4.69, 4.66, 4.67, 4.68, 4.68, 4.72, 4.79, 4.76, 4.76, 4.78, 4.78, 4.78, 4.81, 4.8, 4.81, 4.79, 4.78, 4.76, 4.74, 4.8, 4.79, 4.76, 4.73, 4.78, 4.76, 4.79, 4.71, 4.76, 4.8, 4.76, 4.75, 4.77, 4.76, 4.8, 4.73, 4.74, 4.76, 4.84, 4.75, 4.77, 4.78, 4.76, 4.73, 4.73, 4.78, 4.71, 4.81, 4.76, 4.79, 4.78, 4.77, 4.79, 4.75, 4.76, 4.67, 4.67, 4.65, 4.68, 4.59, 4.51, 4.39, 4.41, 4.35, 4.37, 4.3, 4.48, 4.49, 4.29, 3.95, 2.3, 2.5, -3.74, -10.62, -10.77, -11.85, -13.03, -13.72, -10.15, -6.95, -2.78, -7.07, -1.97, -1.91, -1.98, 0.31, -0.17, 2.61, 1.37, 2.4, 1.49, 2.33, 1.97, 1.95, 2.42, 2.38, 2.47, 2.44, 2.41, 2.35, 2.47, 2.59, 2.53, 2.54, 2.63, 2.6, 2.56, 2.56, 2.58, 2.56, 2.63, 2.63, 2.66, 2.7, 2.69, 2.71, 2.73, 2.75, 2.71, 2.77, 2.77, 2.78, 2.77, 2.77, 2.77, 2.79, 2.79, 2.75, 2.73, 2.75, 2.77, 2.74, 2.72, 2.77, 2.74, 2.72, 2.73, 2.73, 2.76, 2.74, 2.78, 2.78, 2.78, 2.78, 2.82, 2.85, 2.85, 2.85, 2.83, 2.84, 2.85, 2.8, 2.81, 2.8, 2.76, 2.76, 2.79, 2.79, 2.78, 2.75, 2.78, 2.81, 2.78, 2.77, 2.78, 2.79, 2.75, 2.82, 2.79, 2.79, 2.78, 2.79, 2.76, 2.75, 2.79, 2.76, 2.78, 2.76, 2.77, 2.8, 2.79, 2.78, 2.81, 2.83, 2.86, 2.81, 2.79, 2.8, 2.82, 2.76, 2.78, 2.76, 2.8, 2.76, 2.79, 2.79, 2.78, 2.81, 2.81, 2.79, 2.81, 2.84, 2.87, 2.83, 2.85, 2.84, 2.89, 2.88, 2.88, 2.88, 2.91, 2.92, 2.9, 2.91, 2.95, 2.94, 2.96, 2.89, 2.91, 2.88, 2.85, 2.81, 2.81, 2.83, 2.8, 2.82, 2.82, 2.77, 2.79, 2.73, 2.75, 2.72, 2.69, 2.7, 2.69, 2.73, 2.71, 2.72, 2.75, 2.72, 2.71, 2.71, 2.66, 2.64, 2.64, 2.63, 2.56, 2.43, 2.32, 2.3, 2.26, 2.31, 2.21, 2.23, 2.14, 2.04, 2.34, 2.69, 2.7, 2.5, 2.41, 2.26, 2.23, 2.19, 2.13, 2.06, 2.11, 1.95, 1.95, 1.98, 1.96, 1.92, 1.92, 1.92, 1.89, 1.9, 1.92, 1.91, 1.9, 1.94, 1.98, 2.03, 2.0, 2.05, 2.05, 2.06, 2.06, 2.09, 2.15, 2.08, 2.08, 2.05, 2.11, 2.02, 2.08, 2.0, 1.97, 1.92, 1.64, 0.96, 1.2, 1.55, -0.76, 2.3, 1.88, 1.86, 2.64, 2.33, 1.71, 1.85, 2.0, 2.1, 1.85, 1.64, 1.51, 1.65, 1.14, 2.32, 1.38, 3.45, 2.85, 1.52, 1.92, 1.1, 1.04, 1.82, -3.05, -6.06, -6.37, -3.8, -4.61, -4.82, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -1.99, -2.19, 0.9, -0.08, 3.17, 4.12, 3.17, 1.18, 3.85, 0.27, 0.01, 0.24, 0.13, 0.16, 0.16, 0.11, 0.06, 0.04, 0.01, -0.04, 0.0, -0.03, -0.11, -0.17, -0.18, -0.1, -0.13, -0.15, -0.17, -0.12, -0.19, -0.2, -0.22, -0.19, -0.2, -0.22, -0.17, -0.15, -0.18, -0.06, -0.14, -0.1, -0.11, -0.07, -0.03, -0.06, -0.06, 0.0, -0.01, 0.03, 0.01, 0.09, 0.04, 0.04, -0.02, -0.01, -0.1, -0.14, -0.53, -0.62, -0.57, -0.5, -0.55, -0.43, -0.31, -0.25, -0.22, -0.25, -0.18, -0.04, -0.12, -0.15, -0.02, -0.2, 0.04, -0.11, 0.01, -0.02, 0.01, 0.0, 0.0, 0.12, 0.03, 0.01, 0.11, 0.02, 0.06, 0.01, 0.1, 0.06, 0.01, 0.03, -0.04, 0.01, 0.03, 0.03, 0.01, -0.02, -0.09, 0.04, -0.11, 0.05, 0.02, 0.12, -0.04, 0.11, 0.05, 0.14, 0.02, 0.06, 0.02, 0.03, 0.12, -0.01, 0.06, 0.16, 0.01, 0.04, 0.07, 0.17, 0.09, 0.11, 0.21, 0.18, 0.24, 0.19, 0.28, 0.31, 0.36, 0.35, 0.43, 0.51, 0.57, 0.61, 0.63, 0.77, 0.78, 0.9, 0.91, 0.91, 1.23, 1.14, 1.32, 1.76, 2.38, 3.45, 2.49, 2.27, 2.56, 2.61, 2.95, 3.65, 5.59, 4.83, 4.97, 5.07, 5.05, 5.25, 5.44, 5.36, 5.32, 5.58, 5.5, 5.5, 5.35, 5.4, 5.44, 5.35, 5.33, 5.34, 5.3, 5.25, 5.26, 5.21, 5.21, 5.21, 5.17, 5.17, 5.13, 5.13, 5.1, 5.11, 5.14, 5.14, 5.15, 5.18, 5.2, 5.14, 5.2, 5.17, 5.16, 5.16, 5.17, 5.15, 5.16, 5.15, 5.17, 5.16, 5.17, 5.12, 5.12, 5.15, 5.12, 5.15, 5.13, 5.1, 5.18, 5.11, 5.14, 5.18, 5.11, 5.14, 5.19, 5.17, 5.14, 5.16, 5.16, 5.19, 5.17, 5.18, 5.13, 5.14, 5.12, 5.09, 5.11, 5.08, 5.06, 5.03, 5.07, 5.03, 5.04, 4.98, 4.97, 4.98, 4.98, 5.02, 5.01, 5.01, 5.02, 5.05, 5.1, 5.08, 5.15, 5.13, 5.19, 5.2, 5.21, 5.25, 5.26, 5.28, 5.24, 5.32, 5.33, 5.33, 5.26, 5.28, 5.23, 5.2, 5.18, 5.11, 5.12, 5.07, 4.99, 4.86, 4.76, 4.67, 4.71, 4.62, 4.53, 4.44, 4.16, 4.36, 3.85, 3.9, 4.88, 4.39, 4.2, 4.41, 5.95, 4.8, 4.23, 4.88, 4.82, 4.58, 5.12, 5.2, 4.93, 4.94, 6.72, 5.0, 4.92, 6.43, 4.12, 4.4, 4.02, 8.65, 6.11, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -0.33, 1.34, 3.69, 3.08, 3.21, 3.35, 3.38, 2.9, 2.67, 2.45, 2.31, 2.32, 2.27, 2.2, 2.17, 2.21, 2.19, 2.15, 2.19, 2.18, 2.25, 2.26, 2.25, 2.3, 2.3, 2.27, 2.28, 2.29, 2.22, 2.26, 2.21, 2.26, 2.21, 2.23, 2.21, 2.2, 2.21, 2.24, 2.22, 2.21, 2.16, 2.17, 2.12, 2.08, 2.09, 2.06, 2.08, 2.08, 2.06, 2.06, 2.04, 2.05, 2.04, 2.0, 2.01, 1.97, 2.0, 1.98, 1.93, 1.97, 1.98, 2.03, 2.01, 1.96, 2.0, 2.01, 2.06, 2.05, 2.04, 2.06, 2.04, 2.12, 2.11, 2.12, 2.17, 2.2, 2.21, 2.2, 2.2, 2.21, 2.15, 2.12, 2.06, 2.01, 1.95, 1.96, 2.15, 2.12, 2.12, 2.02, 1.88, 2.15, 2.23, 1.75, 2.43, 2.05, 1.85, 2.16, 2.12, 1.78, 2.23, 2.39, 2.13, 0.94, 2.06, 1.63, 1.89, 1.32, 2.26, 2.35, 2.84, 1.96, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -20.62, -20.43, -20.37, -20.25, -20.66, -19.5, -18.77, -18.25, -17.17, -17.03, -17.65, -11.95, -5.51, -4.75, 1.85, 3.32, 4.03, 1.17, 1.55, 0.61, -0.75, -1.76, -1.85, -2.0, -1.94, -2.01, -2.1, -2.05, -2.05, -2.11, -2.11, -2.11, -2.19, -2.17, -2.17, -2.19, -2.22, -2.14, -2.12, -2.08, -2.11, -2.11, -2.08, -2.14, -2.11, -2.15, -2.14, -2.16, -2.1, -2.13, -2.14, -2.1, -2.08, -2.13, -2.0, -1.97, -1.93, -1.96, -1.84, -1.92, -1.81, -1.71, -1.72, -1.71, -1.74, -1.72, -1.71, -1.72, -1.71, -1.75, -1.77, -1.82, -1.76, -1.84, -1.86, -1.87, -1.95, -1.97, -1.95, -1.98, -2.0, -2.07, -2.1, -2.01, -2.0, -2.01, -2.01, -2.0, -1.97, -1.97, -2.07, -2.09, -2.09, -2.13, -2.07, -2.11, -2.17, -2.25, -2.2, -2.22, -2.15, -2.28, -2.22, -2.13, -2.21, -2.13, -2.15, -2.12, -2.09, -2.11, -2.01, -1.98, -1.97, -2.0, -1.96, -1.97, -1.94, -2.03, -1.99, -1.97, -2.04, -1.9, -2.01, -1.86, -1.75, -1.89, -1.83, -1.88, -1.94, -1.91, -1.85, -1.96, -1.9, -1.96, -1.93, -1.81, -1.74, -1.81, -1.83, -1.82, -2.34, -1.92, -1.96, -0.95, -0.52, -2.02, -0.8, -1.14, -2.02, -2.29, -1.18, -2.04, -1.77, -2.67, -0.02, -1.78, -1.82, 0.1, -1.12, -1.78, -1.41, -1.91, -3.41, -0.88, -3.95, -3.48, -5.48, -3.72, -8.11, -5.42, -6.1, -9.33, -3.59, -4.45, -2.87, -5.84, -7.0, -5.88, -6.31, -5.87, -5.08, -2.62, -2.2, -6.84, -3.72, -6.32, -5.41, -5.64, -5.32, -5.28, -5.41, -5.37, -5.37, -5.32, -5.4, -5.32, -5.21, -5.22, -5.11, -5.06, -4.93, -4.9, -4.89, -4.83, -4.86, -4.75, -4.73, -4.77, -4.78, -4.65, -4.58, -4.78, -4.79, -4.81, -4.76, -4.79, -5.08, -4.79, -4.63, -4.69, -5.06, -4.82, -4.81, -4.57, -4.7, -4.57, -4.85, -5.32, -5.14, -5.55, -5.0, -5.21, -4.87, -4.81, -4.47, -5.19, -3.7, -7.09, -7.26, -5.9, -6.17, -5.91, -8.81, -3.83, -3.98, -1.97, -0.48, -3.73, -0.92, -3.04, -8.87, -10.44, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -10.79, -8.72, -8.15, -9.01, -9.77, -13.96, -17.14, -16.38, -16.22, -18.67, -19.02, -18.95, -19.14, -19.02, -18.58, -17.67, -17.58, -17.09, -10.97, -10.1, -10.25, -9.86, -12.89, -12.22, -11.36, -6.7, -6.4, -6.45, -5.66, -3.98, -6.87, -5.5, -6.05, -5.95, -7.91, -8.57, -6.04, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -19.36, -19.36, -19.23, -19.37, -19.3, -18.95, -17.97, -16.24, -15.81, -18.42, -22.47, -21.68, -20.38, -18.49, -16.44, -17.43, -20.98, -21.5, -19.48, -8.54, 4.84, 12.84, 13.31, 13.48, 13.08, 14.57, 11.39, 12.09, 12.3, 12.03, 12.06, 12.27, 12.22, 12.28, 12.37, 12.38, 12.35, 12.33, 12.27, 12.26, 12.23, 12.17, 12.15, 12.06, 12.08, 12.06, 12.02, 12.02, 12.0, 11.94, 11.92, 11.89, 11.87, 11.84, 11.81, 11.83, 11.88, 11.92, 11.86, 11.9, 11.93, 11.88, 11.87, 11.91, 11.92, 11.9, 11.89, 11.89, 11.88, 11.88, 11.9, 11.96, 12.0, 12.01, 11.97, 12.01, 12.02, 11.91, 11.91, 11.91, 11.88, 11.86, 11.85, 11.87, 11.89, 11.87, 11.86, 11.88, 11.88, 11.91, 11.88, 11.94, 11.91, 11.93, 11.97, 11.97, 11.89, 11.87, 11.9, 11.95, 11.87, 11.85, 11.87, 11.84, 11.84, 11.84, 11.86, 11.84, 11.82, 11.82, 11.76, 11.85, 11.79, 11.77, 11.72, 11.73, 11.75, 11.72, 11.82, 11.76, 11.77, 11.76, 11.66, 11.76, 11.88, 11.89, 11.83, 11.81, 11.96, 11.88, 11.96, 11.96, 11.94, 11.81, 11.93, 11.93, 11.9, 12.01, 11.89, 12.03, 11.97, 11.91, 11.95, 11.89, 11.96, 11.99, 11.96, 12.0, 11.97, 11.88, 11.87, 11.95, 11.92, 11.87, 11.87, 11.9, 11.92, 11.89, 11.96, 11.97, 11.91, 11.88, 11.96, 12.02, 11.99, 12.02, 11.98, 11.96, 11.98, 11.89, 11.87, 11.97, 11.88, 11.98, 12.02, 12.02, 12.1, 11.98, 12.1, 12.13, 12.06, 11.98, 11.95, 11.91, 12.07, 11.94, 11.92, 11.95, 11.99, 11.92, 11.99, 12.0, 11.97, 12.01, 12.02, 11.92, 12.05, 12.02, 11.93, 12.08, 12.0, 12.04, 11.95, 11.94, 12.03, 11.98, 11.99, 11.94, 11.85, 11.76, 11.91, 11.82, 11.85, 11.87, 11.88, 11.82, 11.87, 11.81, 11.85, 11.88, 11.77, 11.85, 11.89, 11.87, 11.92, 11.86, 11.91, 11.87, 11.8, 11.83, 11.85, 11.86, 11.89, 11.84, 11.84, 11.81, 11.78, 11.88, 11.84, 11.72, 11.79, 11.79, 11.73, 11.87, 11.86, 11.79, 11.87, 11.84, 11.88, 11.89, 11.81, 11.88, 11.85, 11.83, 11.93, 12.08, 11.96, 11.88, 11.87, 11.97, 11.83, 11.81, 11.86, 11.84, 11.81, 11.79, 11.93, 11.73, 11.74, 11.82, 11.74, 11.78, 11.79, 11.81, 11.86, 11.78, 11.91, 11.83, 11.8, 11.82, 11.82, 11.83, 11.87, 11.86, 11.77, 11.91, 11.96, 11.95, 12.01, 11.87, 11.91, 11.87, 11.85, 11.89, 11.89, 11.89, 11.84, 11.97, 11.82, 11.83, 11.83, 11.84, 11.91, 11.88, 11.79, 11.81, 11.83, 11.92, 11.84, 11.85, 11.8, 11.89, 11.82, 11.73, 11.92, 11.88, 11.87, 11.87, 11.76, 11.81, 11.83, 11.65, 11.75, 11.58, 11.84, 11.65, 11.89, 11.83, 11.77, 11.9, 11.6, 11.77, 12.12, 11.82, 11.88, 12.17, 12.39, 11.81, 11.65, 11.64, 11.78, 13.15, 8.78, 11.65, 12.93, 11.18, 10.9, 10.75, 10.55, 10.61, 10.54, 10.49, 10.51, 10.45, 10.4, 10.36, 10.37, 10.33, 10.27, 10.31, 10.22, 10.23, 10.29, 10.34, 10.34, 10.44, 10.43, 10.48, 10.49, 10.48, 10.48, 10.51, 10.47, 10.48, 10.48, 10.43, 10.46, 10.39, 10.43, 10.41, 10.38, 10.38, 10.31, 10.32, 10.27, 10.29, 10.25, 10.25, 10.25, 10.16, 10.15, 10.22, 10.13, 10.14, 10.12, 10.05, 10.04, 10.04, 9.95, 10.11, 10.05, 10.11, 10.22, 10.25, 10.12, 10.2, 10.31, 10.25, 10.28, 10.09, 10.15, 10.21, 10.37, 10.43, 10.54, 10.37, 10.61, 10.48, 10.9, 10.49, 10.94, 10.53, 10.45, 10.5, 10.09, 9.84, 9.98, 9.85, 9.88, 10.59, 10.09, 10.6, 12.64, 11.62, 12.27, 9.34, 11.71, 10.25, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -14.12, -13.99, -13.05, -11.36, -7.27, -9.26, -11.38, -11.39, -11.01, null, null, null, null, null, null, null, null, null, null, 0.04, 0.81, 6.13, 5.43, 6.67, 7.01, 6.13, 5.93, 5.85, 5.66, 5.58, 5.57, 5.55, 5.59, 5.53, 5.47, 5.47, 5.46, 5.44, 5.34, 5.34, 5.3, 5.28, 5.26, 5.26, 5.24, 5.26, 5.18, 5.2, 5.15, 5.16, 5.11, 5.14, 5.06, 5.13, 5.13, 5.13, 5.1, 5.13, 5.1, 5.09, 5.07, 5.09, 5.08, 5.06, 5.07, 5.06, 5.06, 5.05, 5.12, 5.08, 5.12, 5.11, 5.08, 5.16, 5.09, 5.09, 5.06, 5.06, 5.04, 4.99, 5.0, 5.0, 5.01, 5.02, 4.99, 5.03, 5.03, 5.03, 5.04, 4.97, 5.0, 4.95, 4.98, 4.93, 4.98, 4.94, 4.91, 4.95, 4.92, 4.91, 4.93, 4.91, 4.9, 4.95, 4.94, 4.88, 4.94, 4.92, 4.94, 4.92, 4.9, 4.89, 4.89, 4.87, 4.94, 4.97, 4.96, 4.95, 4.96, 4.98, 4.97, 5.0, 4.92, 4.94, 4.92, 4.93, 4.93, 4.93, 4.93, 4.9, 4.97, 4.93, 5.0, 4.99, 4.99, 5.03, 5.01, 5.08, 5.05, 5.04, 5.05, 5.04, 5.03, 4.96, 4.98, 4.99, 5.07, 4.99, 4.97, 4.99, 4.97, 5.01, 5.02, 4.96, 5.02, 5.07, 5.09, 4.98, 5.02, 5.13, 4.99, 4.86, 4.99, 5.11, 5.1, 5.05, 5.11, 5.1, 5.18, 5.15, 5.13, 5.23, 5.23, 5.25, 5.17, 5.21, 5.24, 5.26, 5.2, 5.19, 5.15, 5.16, 5.23, 5.18, 5.11, 5.08, 5.19, 5.06, 5.19, 5.12, 5.12, 5.23, 5.14, 4.97, 5.25, 5.08, 5.02, 4.93, 5.12, 5.75, 4.42, 4.78, 5.09, 5.29, 4.66, 5.72, 4.68, 1.76, 3.18, 1.88, 2.14, -2.25, -6.52, -16.58, -15.88, -15.02, -13.44, -17.87, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -21.07, -20.41, -18.55, -14.16, -12.37, -13.13, null, null, null, null, -15.12, -16.62, -17.93, -20.34, -20.47, -20.14, -18.63, -17.44, -16.3, -18.57, -21.57, null, null, null, null, null, -20.22, -16.85, -11.57, -12.87, -14.22, -17.79, -19.56, -19.47, -18.73, -18.44, -18.22, -19.16, -19.61, null, null, null, null, null, null, -13.91, -14.4, -8.04, -7.31, -8.24, -2.42, -5.24, -3.27, -2.73, -1.21, -2.6, -4.45, -3.46, 0.15, 2.12, 2.55, 1.84, 0.63, 1.5, 1.79, 2.47, 2.49, 2.22, 2.14, 2.17, 2.08, 2.07, 2.02, 2.07, 2.08, 2.05, 2.08, 2.05, 2.12, 2.14, 2.12, 2.2, 2.25, 2.3, 2.38, 2.42, 2.54, 2.59, 2.6, 2.62, 2.61, 2.59, 2.6, 2.61, 2.58, 2.56, 2.55, 2.53, 2.51, 2.53, 2.48, 2.53, 2.5, 2.48, 2.44, 2.35, 2.24, 2.24, 2.16, 2.15, 2.1, 2.14, 2.17, 2.15, 2.13, 2.12, 2.1, 2.13, 2.11, 2.07, 2.1, 2.1, 2.11, 2.12, 2.14, 2.2, 2.15, 2.22, 2.23, 2.22, 2.22, 2.22, 2.22, 2.22, 2.18, 2.28, 2.24, 2.26, 2.24, 2.33, 2.26, 2.31, 2.27, 2.25, 2.28, 2.28, 2.24, 2.23, 2.23, 2.23, 2.24, 2.19, 2.18, 2.2, 2.19, 2.2, 2.17, 2.18, 2.2, 2.19, 2.16, 2.18, 2.16, 2.16, 2.14, 2.13, 2.12, 2.11, 2.11, 2.1, 2.1, 2.09, 2.08, 2.1, 2.14, 2.1, 2.11, 2.11, 2.14, 2.14, 2.13, 2.16, 2.13, 2.13, 2.1, 2.17, 2.1, 2.1, 2.15, 2.15, 2.16, 2.11, 2.16, 2.13, 2.14, 2.12, 2.1, 2.11, 2.11, 2.08, 2.13, 2.12, 2.08, 2.16, 2.16, 2.12, 2.17, 2.16, 2.13, 2.09, 2.04, 2.02, 2.13, 2.17, 2.11, 2.12, 2.57, 2.64, 2.11, 1.92, 2.15, 2.2, 2.47, 2.13, 1.82, 2.23, 2.03, 2.03, 1.62, 1.32, 0.77, 1.89, 2.13, 2.43, 0.51, 2.55, -1.75, 1.97, 2.25, -0.33, 1.57, 2.1, 2.19, 1.66, 2.63, -1.36, -2.5, -8.62, -15.35, -20.26, -21.44, -22.81, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -22.12, -20.36, -20.37, -20.17, -20.64, -20.58, -20.07, -19.83, -18.41, -17.41, -17.6, -20.97, -21.89, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -13.02, -6.22, -7.65, -6.88, -7.65, -10.87, -13.76, -12.36, -10.61, -7.23, -3.43, 1.73, 4.14, 2.12, 0.8, 3.46, 2.49, 1.47, 2.83, 3.04, 3.07, 3.12, 2.83, 2.5, 2.18, 2.29, 2.4, 2.45, 2.55, 2.48, 2.53, 2.59, 2.53, 2.62, 2.63, 2.7, 2.82, 2.93, 2.91, 2.94, 2.86, 2.88, 2.95, 3.05, 2.96, 3.01, 3.03, 3.05, 2.95, 2.97, 2.88, 2.91, 2.86, 2.85, 2.79, 2.79, 2.8, 2.8, 2.76, 2.81, 2.79, 2.83, 2.88, 2.86, 2.9, 2.91, 2.88, 2.93, 2.95, 2.91, 2.88, 2.85, 2.88, 2.9, 2.9, 2.88, 2.92, 2.93, 2.95, 2.89, 2.9, 2.92, 2.91, 2.92, 2.97, 2.95, 2.99, 3.0, 3.0, 3.01, 2.98, 3.03, 2.98, 3.0, 3.04, 3.06, 3.04, 3.12, 3.13, 3.19, 3.08, 3.03, 3.03, 3.07, 3.02, 3.06, 3.03, 3.11, 3.08, 3.14, 3.16, 3.15, 3.09, 3.1, 3.09, 3.11, 3.03, 3.02, 2.99, 2.97, 3.03, 3.0, 3.03, 3.06, 3.02, 3.08, 3.02, 3.04, 3.01, 3.03, 2.99, 3.04, 3.0, 3.04, 3.01, 3.03, 3.04, 3.02, 2.99, 2.97, 2.95, 2.99, 2.98, 2.96, 3.0, 2.94, 2.95, 2.93, 2.97, 2.98, 3.0, 2.94, 2.95, 2.98, 2.92, 2.91, 2.91, 2.94, 2.9, 2.89, 2.96, 2.99, 2.93, 2.98, 2.93, 2.95, 3.0, 3.06, 2.99, 3.0, 3.02, 2.96, 2.87, 2.93, 2.95, 3.03, 3.02, 2.94, 2.99, 2.97, 2.98, 2.98, 2.93, 2.94, 2.94, 2.98, 2.96, 2.94, 2.93, 2.97, 2.87, 2.81, 2.79, 2.79, 2.74, 2.67, 2.47, 0.77, 1.04, 1.96, 2.49, 2.68, 3.69, 2.68, 2.89, 4.13, 4.17, 2.97, 2.75, 2.46, 2.23, 2.25, 2.2, 2.17, 2.2, 2.15, 2.08, 2.02, 1.97, 2.02, 1.94, 1.93, 1.91, 1.95, 2.05, 2.02, 2.05, 2.06, 2.06, 2.0, 2.05, 2.15, 2.09, 2.08, 2.05, 2.03, 2.01, 2.06, 2.02, 2.02, 1.95, 2.04, 2.03, 2.02, 2.07, 2.01, 2.02, 2.03, 1.96, 2.04, 2.01, 2.0, 1.99, 2.04, 2.05, 2.0, 2.07, 1.96, 2.05, 1.98, 1.92, 1.85, 1.88, 1.74, 1.72, 1.79, 1.79, 1.81, 1.73, 1.78, 1.74, 1.83, 1.8, 1.84, 1.81, 1.88, 1.84, 1.85, 1.9, 1.9, 1.97, 2.04, 1.98, 2.02, 1.99, 1.97, 2.03, 2.0, 2.04, 1.99, 2.08, 2.07, 2.06, 1.91, 2.04, 1.82, 1.9, 1.75, 1.95, 1.78, 1.98, 1.73, 1.78, 1.66, 1.8, 1.93, 1.93, 1.82, 1.9, 1.86, 1.71, 1.83, 1.88, 1.93, 1.85, 1.86, 1.84, 1.68, 1.88, 1.91, 1.8, 1.83, 1.95, 1.88, 1.82, 1.89, 1.84, 1.91, 1.73, 1.99, 1.82, 1.8, 1.78, 2.07, 1.78, 1.8, 1.95, 1.83, 1.97, 1.76, 1.5, 1.88, 1.95, 1.38, 1.45, 1.81, 1.57, 1.46, 1.56, 1.1, 1.17, 1.49, 0.89, 0.79, -0.22, -0.23, 0.9, 1.21, 1.43, 1.44, 1.64, 1.37, 1.19, 1.04, 1.0, 0.9, 0.75, 0.67, 0.57, 0.56, 0.45, 0.34, 0.28, 0.36, 0.19, 0.21, 0.31, 0.2, 0.17, 0.21, 0.15, 0.12, 0.09, 0.02, 0.13, 0.1, 0.08, 0.1, 0.1, 0.13, 0.16, 0.14, 0.12, 0.21, 0.2, 0.17, 0.17, 0.17, 0.24, 0.19, 0.23, 0.23, 0.23, 0.18, 0.26, 0.28, 0.23, 0.21, 0.2, 0.23, 0.18, 0.18, 0.2, 0.2, 0.19, 0.12, 0.17, 0.16, 0.15, 0.11, 0.1, 0.08, 0.07, 0.05, 0.0, -0.01, -0.03, -0.04, -0.02, -0.02, -0.04, -0.07, -0.07, -0.12, -0.13, -0.08, -0.06, -0.03, -0.05, -0.03, -0.02, -0.05, 0.01, -0.02, 0.02, 0.02, 0.01, 0.02, 0.03, 0.03, 0.05, 0.11, -0.0, -0.0, 0.03, 0.02, -0.04, -0.01, -0.03, -0.05, -0.01, -0.04, -0.04, -0.01, -0.05, -0.02, -0.07, -0.09, 0.07, 0.0, -0.04, -0.1, -0.06, -0.06, -0.21, -0.14, -0.18, -0.23, -0.23, -0.23, -0.19, -0.21, -0.19, -0.13, -0.11, -0.03, -0.04, -0.0, 0.05, 0.03, 0.1, 0.03, -0.01, 0.08, 0.06, 0.03, 0.02, 0.1, 0.04, 0.01, -0.01, -0.01, -0.11, -0.13, -0.17, -0.26, -0.3, -0.4, -0.52, -0.55, -0.6, -0.65, -0.77, -0.77, -0.92, -1.09, -1.32, -1.66, -1.66, -1.73, -1.8, -1.89, -2.08, -2.07, -2.11, -2.21, -2.34, -2.4, -2.5, -2.45, -2.44, -2.45, -2.31, -2.29, -2.16, -2.21, -2.2, -2.24, -2.26, -2.3, -2.28, -2.24, -2.22, -2.18, -2.16, -2.11, -2.06, -1.99, -1.93, -2.02, -1.79, -1.75, -1.81, -1.82, -2.0, -1.71, -2.16, -1.79, -1.93, -1.2, -0.47, -1.87, -1.13, -1.51, -1.33, -2.33, -1.23, -2.4, -5.9, -2.29, -2.7, -2.03, -2.05, -1.58, -2.08, -2.08, -2.21, -7.0, -5.52, -10.33, -9.37, -10.46, -14.11, -14.47, -14.16, -14.52, -14.51, -13.12, -14.0, -12.76, -11.41, -13.07, -16.82, -17.11, -17.77, -20.73, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -1.01, 1.25, 0.78, 0.66, 3.59, 7.43, 6.41, 6.48, 6.45, 6.61, 6.49, 6.45, 7.04, 7.19, 7.16, 7.28, 7.38, 7.49, 7.57, 7.64, 7.54, 7.58, 7.58, 7.62, 7.55, 7.53, 7.54, 7.53, 7.54, 7.58, 7.6, 7.54, 7.56, 7.54, 7.64, 7.63, 7.53, 7.53, 7.48, 7.4, 7.42, 7.36, 7.34, 7.34, 7.34, 7.33, 7.34, 7.3, 7.29, 7.31, 7.36, 7.29, 7.26, 7.27, 7.26, 7.21, 7.24, 7.23, 7.24, 7.21, 7.22, 7.16, 7.21, 7.22, 7.25, 7.21, 7.21, 7.22, 7.21, 7.16, 7.18, 7.18, 7.16, 7.14, 7.16, 7.16, 7.15, 7.14, 7.12, 7.09, 7.14, 7.15, 7.11, 7.13, 7.15, 7.13, 7.11, 7.06, 7.07, 7.07, 7.1, 7.09, 7.09, 7.13, 7.13, 7.13, 7.12, 7.12, 7.1, 7.13, 7.11, 7.13, 7.12, 7.17, 7.1, 7.12, 7.14, 7.1, 7.11, 7.05, 7.06, 7.05, 7.06, 7.1, 7.12, 7.17, 7.2, 7.4, 7.47, 7.49, 7.46, 7.46, 7.49, 7.51, 7.35, 7.34, 7.37, 7.27, 7.01, 7.03, 7.33, 7.25, 7.42, 7.47, 7.69, 7.74, 7.59, 8.1, 8.22, 6.29, 8.61, 8.37, 6.23, 6.67, 8.05, 8.3, 7.79, 8.13, 4.91, 5.96, 6.09, 6.75, 6.36, 4.93, 6.11, 8.64, 8.02, 8.73, null, null, null, null, null, null, null, null, null, null, null, null, 2.04, 5.65, 7.58, 5.56, 5.87, 5.74, 5.09, 5.14, 5.11, 5.13, 5.15, 5.1, 5.07, 5.1, 5.02, 5.02, 5.07, 5.01, 4.98, 4.97, 5.05, 5.03, 5.04, 5.06, 5.01, 5.1, 5.1, 5.07, 5.09, 5.05, 5.07, 5.08, 5.07, 5.09, 5.1, 5.14, 5.11, 5.15, 5.19, 5.16, 5.14, 5.12, 5.14, 5.1, 5.09, 5.02, 4.97, 4.85, 4.84, 4.86, 4.81, 4.88, 4.89, 4.92, 4.9, 4.92, 4.92, 4.97, 4.92, 5.09, 5.22, 5.3, 5.4, 5.36, 5.41, 5.24, 5.27, 5.39, 6.07, 5.53, 5.34, 5.08, 4.45, 5.16, 4.49, 5.2, 4.85, 5.41, 4.75, 5.87, 4.7, 4.81, 4.91, 4.2, 5.17, 3.38, 4.03, 2.71, 2.33, 2.72, -0.98, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -4.74, -3.42, -3.64, -3.55, -5.39, -4.07, -3.7, -5.99, -2.71, -1.16, -1.33, -3.54, -4.21, -5.71, -5.13, -4.71, 0.59, 2.69, 1.97, 3.64, 2.89, 2.76, 2.31, 2.47, 2.49, 2.35, 2.54, 2.48, 2.52, 2.59, 2.6, 2.51, 2.64, 2.66, 2.62, 2.71, 2.75, 2.71, 2.74, 2.79, 2.78, 2.81, 2.88, 2.91, 2.89, 2.98, 3.02, 3.05, 3.05, 3.04, 3.02, 3.19, 3.11, 3.08, 3.19, 3.12, 3.18, 3.13, 3.04, 3.06, 3.09, 3.02, 3.06, 3.07, 3.06, 3.06, 3.04, 3.04, 3.04, 3.01, 3.0, 2.97, 3.0, 2.97, 2.92, 2.92, 2.91, 2.93, 2.98, 2.91, 3.01, 2.92, 3.01, 2.94, 2.97, 3.04, 2.94, 2.89, 2.89, 2.91, 2.87, 2.89, 2.88, 2.9, 2.98, 3.0, 3.02, 3.07, 3.06, 3.04, 3.0, 3.02, 3.06, 3.0, 2.97, 2.9, 2.94, 2.94, 2.86, 2.85, 2.89, 2.86, 2.79, 2.86, 2.86, 2.86, 2.9, 2.83, 3.0, 3.11, 3.01, 3.08, 3.16, 3.15, 3.19, 3.13, 3.14, 3.12, 3.12, 3.08, 3.05, 2.96, 2.82, 2.81, 3.22, 6.45, 2.97, 3.24, 3.12, 3.19, 2.91, 2.73, 2.75, 2.84, 2.94, 2.81, 2.62, 2.63, 2.67, 2.55, 2.43, 2.34, 3.55, 3.76, 2.47, 2.25, 2.43, 1.43, 2.38, 1.35, 3.59, 2.05, 1.01, 4.77, 3.75, 3.92, 0.68, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 6.49, 3.65, 5.11, 6.21, 5.67, 5.37, 5.25, 5.25, 5.34, 5.32, 5.44, 5.34, 5.37, 5.41, 5.35, 5.32, 5.3, 5.25, 5.26, 5.2, 5.22, 5.18, 5.2, 5.23, 5.19, 5.26, 5.22, 5.24, 5.2, 5.21, 5.2, 5.21, 5.2, 5.27, 5.22, 5.24, 5.2, 5.21, 5.2, 5.2, 5.22, 5.24, 5.15, 5.19, 5.15, 5.19, 5.21, 5.18, 5.16, 5.19, 5.21, 5.22, 5.19, 5.21, 5.2, 5.2, 5.16, 5.18, 5.22, 5.21, 5.22, 5.24, 5.23, 5.26, 5.27, 5.28, 5.25, 5.24, 5.25, 5.2, 5.21, 5.18, 5.22, 5.15, 5.15, 5.13, 5.15, 5.16, 5.14, 5.15, 5.15, 5.14, 5.13, 5.16, 5.17, 5.14, 5.15, 5.14, 5.14, 5.17, 5.14, 5.16, 5.22, 5.15, 5.2, 5.17, 5.2, 5.16, 5.18, 5.22, 5.18, 5.15, 5.22, 5.2, 5.18, 5.2, 5.16, 5.2, 5.22, 5.18, 5.15, 5.22, 5.2, 5.17, 5.17, 5.17, 5.2, 5.21, 5.17, 5.19, 5.2, 5.2, 5.19, 5.21, 5.2, 5.2, 5.18, 5.2, 5.15, 4.99, 4.82, 4.79, 4.85, 4.99, 4.87, 4.7, 4.85, 4.87, 5.09, 5.24, 5.4, 5.25, 5.15, 5.16, 5.37, 5.03, 4.97, 5.03, 5.04, 4.96, 3.99, 5.3, 5.13, 5.52, 5.12, 4.7, 6.81, 5.12, 3.7, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 4.23, 7.29, 6.63, 5.13, 2.71, 4.24, 6.27, 7.44, 7.72, 8.52, 6.46, 6.65, 7.44, 7.08, 7.19, 7.01, 7.16, 7.23, 7.43, 7.47, 7.56, 7.31, 7.32, 7.33, 7.25, 7.26, 7.24, 7.2, 7.2, 7.14, 7.11, 7.08, 7.12, 7.13, 7.14, 7.17, 7.18, 7.2, 7.17, 7.21, 7.17, 7.24, 7.2, 7.23, 7.23, 7.24, 7.23, 7.2, 7.22, 7.23, 7.23, 7.19, 7.19, 7.2, 7.16, 7.19, 7.2, 7.18, 7.15, 7.16, 7.17, 7.16, 7.14, 7.17, 7.17, 7.18, 7.19, 7.18, 7.16, 7.19, 7.2, 7.17, 7.18, 7.17, 7.16, 7.16, 7.16, 7.12, 7.11, 7.12, 7.1, 7.12, 7.12, 7.14, 7.14, 7.13, 7.14, 7.15, 7.17, 7.14, 7.16, 7.15, 7.14, 7.15, 7.12, 7.1, 7.11, 7.09, 7.07, 7.06, 7.06, 7.01, 7.01, 7.02, 6.96, 6.99, 6.95, 6.94, 6.94, 6.94, 6.94, 6.93, 6.93, 6.93, 6.93, 6.93, 6.93, 6.91, 6.96, 6.97, 6.99, 7.02, 7.05, 7.1, 7.09, 7.15, 7.11, 7.14, 7.12, 7.14, 7.11, 7.12, 7.08, 7.06, 7.05, 7.12, 7.14, 7.19, 7.15, 7.13, 7.14, 7.09, 7.05, 7.03, 7.0, 6.99, 6.97, 6.92, 6.91, 6.93, 6.92, 6.92, 6.92, 6.9, 6.93, 6.93, 7.01, 7.02, 7.04, 7.06, 7.1, 7.1, 7.09, 7.1, 7.17, 7.21, 7.16, 7.14, 7.18, 7.22, 7.2, 7.2, 7.37, 7.4, 7.37, 7.32, 7.5, 7.42, 7.35, 7.26, 7.42, 7.4, 7.25, 7.24, 7.26, 6.97, 7.21, 5.91, 7.54, 7.55, 7.65, 5.94, 7.04, 7.31, 6.93, 6.92, 9.1, 6.95, 7.14, 4.97, 0.83, -0.04, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -21.0, -18.11, -18.54, -19.14, -19.39, -19.95, -20.23, -21.0, null, null, null, null, null, null, null, null, null, null, null, -6.34, -6.49, -7.37, -5.03, -4.23, -0.89, -0.44, 0.73, -1.27, 3.22, 3.06, 2.01, 2.81, 3.03, 3.21, 3.09, 3.11, 3.12, 3.14, 3.09, 3.13, 3.08, 3.03, 3.03, 2.99, 2.99, 2.95, 2.9, 2.92, 2.93, 2.93, 2.9, 2.95, 2.97, 2.98, 3.01, 2.97, 3.05, 3.02, 3.04, 3.06, 3.09, 3.12, 3.05, 3.05, 3.02, 2.98, 3.0, 3.0, 2.96, 2.99, 2.94, 2.97, 2.97, 2.96, 3.01, 2.98, 2.98, 2.98, 3.05, 3.01, 3.07, 3.05, 3.08, 3.03, 3.04, 3.08, 3.08, 3.07, 3.07, 3.13, 3.12, 3.16, 3.21, 3.18, 3.17, 3.18, 3.18, 3.2, 3.14, 3.08, 3.08, 3.04, 3.01, 2.96, 2.97, 2.95, 2.96, 2.93, 2.96, 2.95, 2.99, 2.99, 3.06, 2.99, 2.99, 3.0, 3.0, 2.97, 2.94, 2.95, 2.96, 2.96, 3.02, 3.0, 2.99, 3.06, 3.06, 3.09, 3.07, 3.17, 3.13, 3.09, 3.06, 3.1, 3.1, 3.07, 3.08, 3.05, 3.03, 3.05, 3.06, 3.08, 3.05, 3.11, 3.04, 3.06, 3.03, 3.04, 2.98, 3.07, 2.97, 3.03, 3.06, 3.11, 3.06, 3.03, 3.04, 3.11, 3.03, 3.02, 3.17, 3.07, 2.97, 3.11, 3.02, 3.08, 3.11, 3.07, 3.08, 3.06, 3.17, 3.18, 3.23, 3.2, 3.18, 3.17, 3.18, 3.09, 3.22, 3.16, 3.27, 3.28, 3.26, 3.24, 3.2, 3.18, 3.26, 3.17, 3.43, 3.42, 3.36, 3.26, 3.2, 3.31, 3.3, 3.14, 3.09, 3.2, 3.16, 3.54, 3.07, 2.38, 3.25, 2.93, 2.66, 4.42, 5.24, 2.88, 2.59, 2.38, 2.45, 3.29, -0.95, -9.5, -17.15, -19.75, -20.46, -20.41, -20.3, -19.44, -18.45, -19.65, -20.79, -20.16, -19.12, -19.0, -19.5, -20.17, -21.01, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 1.51, 0.99, 2.85, 2.79, 2.38, 2.08, 2.57, 2.24, 2.61, 2.78, 2.99, 3.17, 3.29, 3.17, 3.24, 3.28, 3.29, 3.39, 3.32, 3.32, 3.29, 3.24, 3.27, 3.18, 3.19, 3.18, 3.18, 3.2, 3.19, 3.16, 3.18, 3.12, 3.15, 3.1, 3.12, 3.1, 3.06, 3.06, 3.06, 3.04, 3.01, 2.99, 2.95, 2.98, 2.93, 2.91, 2.91, 2.89, 2.9, 2.92, 2.93, 2.91, 2.94, 2.89, 2.92, 2.93, 3.01, 2.95, 2.97, 2.96, 2.96, 2.94, 2.94, 2.95, 2.97, 3.02, 3.0, 2.99, 3.02, 3.01, 3.03, 2.95, 2.95, 3.0, 2.95, 2.94, 3.0, 2.96, 2.95, 2.97, 2.98, 2.99, 3.0, 2.98, 3.01, 2.96, 2.96, 2.97, 2.98, 2.98, 2.95, 2.95, 2.95, 2.95, 2.95, 2.99, 2.95, 2.99, 2.98, 2.99, 3.0, 3.02, 3.05, 3.03, 3.01, 3.05, 3.06, 2.99, 3.03, 3.01, 2.99, 3.02, 3.0, 3.02, 3.01, 3.04, 3.02, 3.02, 3.03, 3.05, 3.03, 3.05, 3.01, 3.02, 3.0, 2.99, 2.95, 3.03, 2.99, 3.01, 2.99, 3.03, 3.01, 3.01, 3.02, 3.06, 3.09, 3.08, 3.07, 3.01, 3.09, 3.0, 3.12, 3.08, 3.02, 3.02, 3.11, 3.04, 3.04, 3.15, 3.05, 3.14, 3.06, 3.02, 3.13, 3.05, 3.2, 3.08, 3.1, 3.17, 3.16, 3.07, 3.16, 3.11, 3.09, 3.05, 3.24, 3.02, 3.07, 3.13, 3.01, 3.19, 3.29, 3.22, 3.22, 3.17, 3.16, 3.06, 3.15, 3.03, 3.15, 3.09, 3.05, 3.13, 3.03, 3.05, 3.06, 2.93, 2.94, 3.41, 2.94, 2.75, 3.01, 3.31, 3.28, 2.55, 3.16, 3.15, 2.83, 3.07, 3.04, 2.82, 3.32, 2.71, 2.23, 0.8, 3.53, 2.81, 2.65, 3.23, 3.03, null, null, -14.79, -19.27, -20.1, -20.23, -19.9, -19.92, -19.28, -18.25, -18.42, -18.81, -19.17, -18.4, -16.65, -16.87, -18.85, -19.69, -19.46, -19.01, -19.39, -17.72, -17.32, -19.62, -19.25, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], "db": [-33.7, -29.3, -30.0, -33.2, -33.9, -34.4, -38.5, -37.2, -39.9, -37.3, -22.1, -13.9, -12.8, -11.8, -10.9, -10.1, -10.5, -10.4, -10.4, -9.6, -8.8, -8.7, -9.1, -9.1, -8.6, -8.3, -8.8, -9.8, -8.8, -8.6, -9.1, -9.1, -8.7, -8.2, -8.2, -8.4, -9.1, -8.3, -7.8, -8.2, -8.9, -8.2, -7.8, -8.1, -8.3, -8.5, -8.0, -7.9, -8.5, -9.3, -8.4, -8.1, -8.7, -9.2, -8.5, -8.4, -8.3, -8.5, -8.9, -8.2, -7.8, -8.3, -8.9, -8.0, -7.7, -8.2, -8.8, -8.6, -8.2, -8.2, -8.9, -9.5, -8.7, -8.6, -9.2, -9.8, -8.8, -8.4, -9.2, -9.7, -8.8, -8.7, -9.3, -9.9, -9.0, -8.9, -9.4, -9.8, -9.4, -9.0, -9.0, -9.5, -9.5, -8.7, -8.7, -9.3, -9.7, -8.6, -8.3, -9.1, -9.3, -8.3, -7.8, -8.2, -8.7, -7.5, -6.9, -7.6, -7.9, -7.0, -6.7, -7.1, -7.8, -6.8, -6.6, -7.4, -8.0, -7.1, -6.9, -7.7, -8.2, -7.3, -6.9, -7.6, -8.0, -7.0, -7.0, -7.6, -8.0, -6.9, -7.0, -7.6, -8.0, -7.0, -6.9, -7.7, -7.8, -6.8, -6.8, -7.4, -7.6, -6.7, -7.0, -7.8, -8.1, -7.7, -8.4, -10.1, -11.4, -14.5, -18.2, -17.8, -16.8, -17.1, -19.5, -23.1, -27.9, -30.5, -30.6, -33.0, -32.3, -23.7, -13.1, -12.2, -11.7, -10.7, -11.4, -9.4, -9.4, -9.3, -9.1, -10.6, -9.7, -10.9, -9.7, -10.5, -9.4, -9.5, -11.0, -9.6, -10.9, -9.9, -10.5, -10.4, -9.5, -10.9, -10.4, -10.6, -10.1, -9.4, -11.0, -10.2, -10.6, -10.0, -9.7, -10.9, -9.8, -10.8, -10.3, -10.4, -10.5, -9.9, -11.1, -10.5, -10.9, -10.3, -10.1, -11.3, -10.3, -11.2, -10.5, -11.0, -10.4, -9.8, -11.1, -10.2, -11.5, -10.6, -11.1, -10.8, -10.5, -11.3, -10.2, -11.2, -10.9, -11.2, -10.7, -10.7, -11.1, -10.7, -11.5, -11.1, -11.9, -11.9, -12.2, -11.9, -11.7, -11.8, -10.9, -11.3, -10.8, -11.2, -11.3, -11.2, -11.4, -10.9, -11.4, -10.8, -11.2, -11.3, -11.3, -11.4, -11.0, -11.4, -10.8, -11.4, -10.9, -11.2, -11.4, -11.4, -11.2, -10.6, -11.3, -10.6, -11.1, -10.9, -11.1, -11.3, -11.1, -11.1, -10.8, -11.6, -11.1, -11.4, -11.5, -11.8, -11.9, -11.2, -11.6, -11.0, -11.8, -11.2, -11.6, -11.7, -11.8, -11.8, -11.4, -12.0, -11.6, -12.5, -12.3, -13.1, -13.3, -14.5, -15.1, -16.5, -18.5, -21.2, -24.6, -29.1, -34.0, -37.2, -37.3, -37.6, -28.1, -24.7, -24.4, -33.3, -31.6, -31.3, -32.6, -35.3, -34.8, -33.7, -34.1, -36.5, -34.5, -33.5, -32.0, -31.3, -28.2, -26.6, -26.1, -23.9, -23.7, -21.8, -20.2, -18.0, -18.1, -16.5, -15.6, -16.0, -14.0, -14.0, -14.6, -12.5, -14.4, -12.5, -12.6, -13.7, -11.5, -12.3, -12.5, -10.8, -12.6, -10.4, -11.4, -12.3, -10.1, -12.2, -10.7, -10.9, -12.2, -10.1, -11.3, -10.9, -10.3, -11.6, -10.1, -10.7, -11.2, -9.6, -11.2, -10.1, -10.6, -11.4, -9.2, -10.9, -9.9, -10.0, -11.0, -9.2, -10.5, -10.0, -9.5, -10.4, -9.4, -10.2, -10.3, -9.7, -11.2, -10.4, -11.0, -11.1, -10.3, -12.1, -11.1, -11.6, -11.9, -10.2, -12.1, -10.7, -11.2, -11.8, -9.9, -12.2, -10.4, -11.0, -11.9, -10.3, -11.9, -10.8, -11.2, -12.2, -11.0, -11.7, -11.6, -10.8, -12.4, -10.9, -11.7, -12.1, -10.2, -12.1, -10.5, -11.4, -12.0, -10.1, -11.9, -10.6, -11.7, -12.1, -10.2, -12.1, -10.7, -11.1, -11.8, -10.3, -11.3, -10.9, -10.4, -11.7, -10.6, -11.1, -11.4, -9.9, -11.7, -10.7, -11.4, -11.9, -10.4, -12.4, -11.0, -11.5, -11.9, -10.5, -12.6, -11.0, -11.8, -11.8, -11.3, -13.0, -11.4, -12.4, -12.5, -11.2, -12.8, -11.2, -12.1, -12.9, -11.0, -13.2, -11.6, -12.3, -13.2, -10.7, -12.6, -11.5, -11.3, -12.5, -10.6, -11.9, -12.3, -10.7, -13.2, -12.3, -14.0, -15.5, -14.5, -16.2, -17.1, -16.7, -16.9, -17.1, -18.9, -18.3, -18.7, -17.6, -14.6, -13.2, -10.1, -11.8, -10.8, -11.2, -11.7, -11.5, -11.0, -11.0, -10.7, -10.2, -10.7, -10.7, -10.0, -10.8, -11.0, -10.3, -11.4, -11.8, -10.5, -11.6, -12.6, -11.2, -11.8, -12.7, -11.1, -12.0, -12.7, -11.6, -13.0, -13.4, -12.2, -13.6, -13.9, -13.1, -14.0, -14.7, -14.1, -15.9, -15.9, -16.7, -22.6, -28.9, -27.0, -29.4, -31.1, -32.5, -29.9, -33.5, -39.3, -35.1, -31.5, -29.8, -30.6, -32.6, -32.8, -32.1, -35.5, -35.6, -35.8, -35.3, -37.0, -37.6, -37.2, -37.2, -39.4, -40.8, -43.6, -42.3, -41.6, -40.4, -42.9, -42.2, -40.6, -38.1, -41.8, -43.2, -42.9, -44.1, -45.8, -47.4, -45.3, -42.4, -43.2, -42.2, -39.7, -47.3, -45.2, -48.8, -47.5, -54.1, -47.6, -52.5, -50.7, -50.4, -46.1, -45.6, -50.3, -46.8, -44.2, -48.6, -46.0, -45.8, -46.1, -53.3, -53.4, -53.8, -50.7, -50.5, -47.5, -46.6, -39.8, -40.7, -41.2, -40.5, -44.5, -46.7, -47.4, -49.8, -44.5, -52.7, -47.7, -52.4, -58.7, -62.4, -54.0, -53.7, -52.2, -49.6, -50.5, -56.8, -54.8, -54.2, -49.5, -52.4, -47.8, -48.8, -43.2, -48.8, -46.7, -46.7, -47.2, -47.6, -46.6, -46.8, -45.6, -43.8, -41.6, -37.3, -33.9, -18.0, -12.7, -10.9, -11.3, -11.2, -12.7, -13.0, -12.2, -12.4, -12.4, -13.3, -13.3, -12.8, -11.9, -11.7, -13.7, -13.7, -13.8, -12.1, -12.7, -12.7, -13.8, -13.5, -13.5, -11.7, -12.7, -12.6, -13.3, -13.4, -13.2, -11.6, -12.7, -13.4, -14.0, -13.8, -12.8, -12.6, -12.7, -14.1, -14.1, -14.0, -12.2, -13.8, -13.9, -14.6, -14.7, -13.8, -15.0, -15.5, -17.5, -19.5, -21.7, -18.9, -18.7, -19.0, -17.4, -16.9, -17.5, -16.8, -16.7, -18.0, -17.6, -17.9, -19.2, -18.2, -18.5, -18.8, -17.7, -18.4, -17.6, -16.6, -17.2, -16.8, -16.8, -17.1, -16.1, -17.0, -16.9, -16.6, -17.8, -16.8, -17.5, -18.0, -17.2, -18.0, -18.8, -17.4, -18.5, -17.7, -18.4, -18.8, -17.1, -18.3, -18.4, -17.9, -18.8, -18.2, -18.0, -19.0, -18.1, -18.8, -19.2, -18.1, -19.1, -18.5, -18.7, -19.7, -18.2, -19.0, -18.9, -18.7, -19.3, -18.3, -18.3, -18.4, -17.7, -18.5, -17.5, -17.4, -17.9, -16.7, -17.6, -16.2, -16.8, -16.5, -15.9, -16.3, -15.3, -16.2, -15.1, -15.9, -14.9, -16.6, -16.3, -18.0, -19.1, -21.4, -25.4, -24.1, -19.7, -16.1, -14.5, -14.4, -14.9, -15.9, -9.1, -7.4, -9.8, -8.8, -9.4, -10.3, -10.2, -10.9, -10.3, -10.7, -11.8, -10.1, -10.9, -11.1, -10.4, -11.9, -10.7, -11.1, -11.0, -10.3, -11.2, -10.6, -10.6, -10.4, -9.4, -10.7, -10.0, -10.2, -9.7, -9.5, -10.9, -9.8, -10.5, -10.2, -9.8, -11.1, -10.1, -10.7, -10.3, -9.4, -11.1, -10.0, -10.9, -10.2, -9.3, -11.1, -9.7, -10.6, -9.9, -9.2, -11.0, -9.6, -10.6, -10.1, -9.7, -11.1, -9.9, -10.8, -10.1, -10.0, -10.2, -9.3, -10.5, -9.6, -9.8, -9.4, -9.0, -10.4, -9.3, -9.9, -9.2, -9.1, -10.6, -9.4, -10.4, -9.7, -9.7, -10.7, -10.1, -11.2, -10.6, -11.3, -10.4, -10.5, -11.9, -11.3, -12.0, -11.1, -11.1, -11.7, -11.4, -11.9, -11.5, -11.3, -12.2, -11.4, -12.2, -11.4, -10.6, -11.6, -10.7, -11.8, -11.1, -10.4, -11.8, -10.9, -12.0, -11.2, -10.6, -11.7, -11.5, -12.0, -12.1, -12.3, -13.0, -15.0, -17.2, -20.3, -24.3, -28.1, -31.4, -31.0, -29.3, -32.5, -31.0, -32.2, -30.7, -28.3, -28.5, -21.4, -20.5, -20.1, -26.2, -23.4, -22.0, -24.7, -24.2, -23.4, -22.1, -25.3, -23.2, -24.2, -21.9, -20.6, -20.0, -22.3, -19.1, -22.7, -22.9, -21.8, -20.1, -22.0, -21.0, -22.1, -22.6, -21.8, -27.0, -26.2, -24.9, -27.1, -31.4, -33.0, -35.0, -35.2, -24.9, -15.9, -10.3, -11.6, -10.7, -10.7, -11.6, -11.5, -10.6, -10.9, -10.7, -10.1, -10.0, -10.7, -10.3, -10.9, -10.6, -10.6, -11.7, -10.8, -11.8, -12.6, -11.2, -11.9, -12.0, -10.9, -11.7, -11.6, -10.6, -11.4, -11.5, -10.7, -11.4, -11.3, -10.9, -11.8, -11.7, -11.1, -11.8, -11.6, -11.3, -11.9, -11.5, -11.6, -12.3, -11.7, -11.8, -12.5, -12.2, -12.5, -12.8, -12.7, -12.9, -13.5, -13.3, -13.1, -13.6, -13.8, -13.5, -14.0, -14.0, -13.6, -14.4, -14.2, -13.9, -14.8, -14.6, -14.5, -15.3, -15.1, -15.2, -15.9, -15.3, -16.4, -16.9, -16.8, -18.3, -18.3, -19.6, -20.8, -20.5, -22.9, -23.1, -25.8, -28.6, -29.3, -31.3, -34.4, -36.0, -38.7, -38.8, -38.4, -37.2, -37.9, -38.4, -38.2, -38.2, -42.2, -39.4, -41.0, -41.5, -41.6, -42.4, -40.8, -42.3, -42.0, -38.1, -39.1, -37.0, -40.1, -38.2, -39.7, -42.0, -40.2, -36.8, -37.3, -37.2, -38.4, -41.0, -41.3, -40.9, -37.3, -39.7, -39.3, -36.3, -36.0, -36.4, -35.7, -41.5, -40.7, -38.4, -38.7, -35.9, -39.5, -34.3, -32.4, -33.1, -33.3, -33.7, -36.4, -36.9, -36.5, -38.6, -37.4, -36.5, -39.9, -41.9, -38.8, -38.4, -25.4, -16.7, -15.4, -14.0, -14.6, -13.9, -14.6, -14.3, -13.5, -13.4, -13.3, -13.6, -13.3, -13.6, -14.0, -14.2, -14.8, -14.9, -15.6, -15.4, -14.9, -14.9, -14.3, -14.5, -15.3, -15.3, -15.4, -16.3, -16.4, -16.1, -15.8, -16.9, -16.8, -16.8, -16.8, -16.5, -16.8, -16.5, -16.7, -16.9, -17.0, -16.7, -15.6, -15.6, -15.5, -15.4, -14.4, -13.7, -14.7, -14.4, -14.5, -14.2, -14.7, -14.8, -14.5, -14.0, -13.7, -14.6, -14.0, -14.5, -14.9, -15.1, -14.6, -15.6, -16.0, -16.1, -16.6, -16.3, -16.9, -16.5, -16.7, -17.2, -17.6, -16.7, -17.7, -18.0, -17.8, -18.3, -18.7, -18.2, -18.6, -18.1, -18.5, -18.3, -17.8, -17.8, -17.4, -17.3, -17.6, -17.7, -17.7, -18.2, -18.6, -18.7, -18.5, -18.8, -19.5, -18.4, -18.8, -18.3, -18.6, -19.1, -19.1, -19.3, -19.5, -19.3, -19.6, -19.6, -19.5, -19.6, -19.5, -19.2, -20.2, -20.3, -19.8, -20.0, -20.1, -20.6, -21.0, -20.8, -21.6, -23.4, -24.2, -27.4, -32.7, -38.9, -37.8, -35.4, -33.5, -34.1, -34.4, -32.7, -38.0, -38.5, -38.8, -38.7, -40.4, -38.9, -36.1, -39.1, -36.2, -36.6, -41.1, -43.2, -43.0, -42.5, -43.8, -40.8, -43.5, -40.7, -42.3, -41.2, -41.8, -42.6, -44.4, -42.1, -41.9, -40.7, -37.3, -34.7, -40.1, -36.7, -37.4, -22.2, -16.5, -20.8, -16.8, -18.2, -16.7, -20.2, -18.8, -18.2, -16.9, -17.3, -16.5, -16.8, -17.6, -19.1, -16.9, -16.9, -16.6, -16.5, -16.5, -15.6, -16.8, -17.1, -18.2, -17.0, -17.5, -17.3, -18.3, -17.8, -18.6, -18.4, -19.9, -20.9, -20.9, -20.5, -20.8, -21.3, -21.6, -21.2, -20.6, -22.0, -22.0, -23.1, -23.1, -23.9, -27.2, -29.1, -32.5, -33.2, -35.6, -36.8, -36.6, -35.8, -36.6, -43.2, -39.1, -42.1, -47.2, -40.3, -40.4, -41.0, -50.9, -52.0, -56.0, -53.5, -49.5, -48.1, -34.5, -37.4, -39.0, -38.4, -36.3, -35.6, -41.2, -36.2, -35.7, -34.8, -41.1, -43.5, -40.3, -39.5, -43.0, -45.6, -42.8, -48.4, -54.2, -49.4, -50.6, -46.5, -42.3, -43.2, -43.2, -43.1, -41.5, -45.0, -45.0, -40.5, -39.5, -41.8, -41.4, -42.7, -46.9, -45.4, -43.9, -42.5, -42.4, -40.6, -43.7, -44.4, -42.6, -45.3, -46.3, -44.7, -40.5, -41.2, -45.4, -43.2, -40.2, -45.2, -45.1, -45.9, -45.7, -41.5, -45.1, -41.6, -43.2, -44.5, -46.3, -49.4, -48.9, -47.3, -45.0, -47.5, -48.1, -50.8, -45.5, -49.8, -48.2, -47.5, -52.3, -49.4, -52.8, -52.3, -54.9, -56.4, -50.6, -53.6, -55.4, -50.7, -47.6, -51.1, -51.0, -52.3, -50.9, -52.7, -55.5, -53.1, -57.1, -56.6, -53.4, -50.1, -50.4, -50.4, -52.0, -49.8, -48.8, -45.6, -44.4, -42.6, -42.3, -41.8, -40.7, -42.1, -41.1, -42.3, -37.4, -27.1, -19.0, -17.9, -15.4, -14.7, -12.0, -11.4, -10.6, -9.2, -9.4, -8.4, -8.7, -7.7, -8.2, -8.4, -7.4, -8.5, -8.2, -8.4, -8.8, -8.1, -8.6, -9.0, -8.1, -9.1, -9.4, -9.1, -10.4, -9.4, -9.4, -10.4, -9.5, -10.1, -10.6, -9.4, -9.9, -10.8, -10.5, -10.8, -10.6, -9.8, -10.5, -10.7, -10.0, -11.1, -10.1, -10.2, -10.3, -9.8, -10.1, -9.7, -9.0, -9.8, -9.1, -8.7, -9.7, -8.5, -8.5, -8.9, -8.1, -8.8, -9.5, -9.0, -9.7, -10.4, -9.4, -9.5, -9.5, -8.8, -9.9, -9.0, -9.2, -10.3, -9.3, -10.0, -9.8, -9.6, -9.5, -9.7, -8.7, -9.4, -9.7, -8.8, -9.1, -9.5, -8.4, -9.1, -9.1, -8.3, -9.5, -9.6, -8.9, -10.5, -10.0, -9.4, -10.4, -10.1, -10.5, -11.4, -11.0, -10.1, -11.5, -10.8, -11.1, -11.0, -9.9, -10.5, -10.2, -9.7, -10.0, -10.3, -9.0, -9.6, -9.7, -9.9, -10.4, -9.7, -10.4, -10.8, -10.0, -10.9, -10.9, -10.0, -11.0, -10.8, -9.7, -11.1, -10.3, -11.0, -11.2, -10.4, -10.5, -10.9, -10.4, -10.9, -11.9, -10.4, -10.8, -11.4, -11.3, -12.0, -11.1, -11.1, -11.7, -11.1, -11.7, -11.7, -11.6, -12.7, -12.0, -12.2, -12.5, -11.3, -12.1, -11.6, -10.7, -11.7, -11.6, -11.4, -11.4, -10.4, -12.1, -11.8, -10.1, -11.3, -11.3, -10.6, -11.3, -10.4, -10.9, -12.2, -10.6, -10.4, -11.1, -10.4, -11.1, -11.0, -10.5, -11.8, -10.6, -11.1, -11.8, -11.1, -11.4, -12.0, -11.2, -11.1, -11.6, -10.7, -11.2, -11.1, -11.1, -12.3, -10.8, -11.6, -12.6, -11.5, -11.3, -12.2, -10.9, -11.9, -12.2, -10.8, -11.5, -11.4, -10.5, -10.9, -11.6, -11.2, -11.5, -11.1, -11.9, -11.6, -11.1, -12.3, -12.1, -11.1, -12.7, -12.8, -11.4, -12.3, -13.4, -11.4, -11.8, -12.1, -11.3, -12.6, -11.7, -11.6, -12.6, -11.6, -11.3, -12.7, -11.4, -11.7, -11.5, -10.9, -11.9, -11.6, -10.7, -11.4, -11.4, -11.0, -12.1, -11.7, -11.0, -11.6, -11.9, -11.0, -12.3, -11.6, -11.8, -12.5, -11.4, -12.1, -13.3, -12.9, -13.1, -13.5, -12.7, -13.0, -13.2, -13.1, -13.3, -13.3, -11.7, -12.6, -12.2, -11.4, -12.4, -11.6, -12.1, -12.4, -11.7, -11.5, -12.1, -12.3, -12.8, -12.8, -12.6, -14.3, -13.8, -14.1, -14.0, -13.5, -15.0, -15.0, -14.7, -14.9, -15.2, -15.2, -15.3, -16.2, -16.1, -17.7, -19.1, -19.9, -23.3, -25.5, -27.7, -31.5, -34.8, -36.3, -35.8, -36.5, -37.8, -38.0, -39.4, -38.9, -39.9, -41.0, -42.2, -43.6, -44.1, -46.3, -47.0, -46.6, -42.9, -43.6, -36.4, -21.1, -13.3, -10.5, -10.9, -10.9, -10.7, -9.4, -9.4, -9.0, -9.4, -9.3, -9.7, -10.2, -10.6, -11.3, -12.5, -12.6, -12.0, -11.7, -10.5, -10.3, -9.9, -9.4, -9.1, -9.3, -8.1, -8.5, -8.6, -8.7, -8.7, -8.9, -8.0, -8.9, -9.2, -9.5, -9.8, -10.6, -11.0, -11.9, -12.7, -12.4, -12.7, -12.7, -12.7, -12.2, -12.1, -13.8, -14.0, -14.8, -15.4, -15.5, -17.0, -17.0, -17.4, -19.2, -20.6, -22.0, -21.9, -22.0, -23.5, -23.7, -24.4, -26.4, -27.0, -28.2, -29.2, -28.9, -29.5, -29.6, -30.5, -30.8, -32.1, -33.7, -35.1, -36.5, -38.5, -40.3, -41.0, -41.5, -41.7, -41.7, -43.1, -41.2, -38.3, -38.4, -33.9, -33.2, -31.1, -30.3, -30.5, -30.2, -29.8, -28.5, -29.8, -28.6, -30.7, -34.6, -30.8, -32.8, -31.6, -31.1, -29.9, -32.8, -29.8, -29.9, -29.3, -25.4, -25.0, -28.0, -27.0, -25.1, -22.2, -25.1, -20.7, -22.2, -19.6, -22.2, -22.4, -23.2, -23.0, -22.1, -23.6, -26.6, -22.4, -26.1, -23.2, -20.4, -24.0, -23.8, -19.6, -21.0, -18.2, -22.3, -24.6, -23.7, -25.8, -27.9, -29.2, -33.7, -34.7, -42.0, -43.7, -45.0, -43.3, -43.5, -45.0, -46.3, -49.6, -46.7, -48.0, -50.5, -52.1, -51.2, -52.6, -52.2, -55.4, -50.7, -31.2, -28.7, -26.1, -25.4, -25.4, -30.2, -26.6, -13.5, -10.8, -11.6, -11.0, -10.7, -11.9, -11.3, -10.5, -11.9, -10.7, -10.5, -11.6, -10.1, -11.1, -10.4, -9.9, -11.4, -10.0, -10.3, -10.3, -9.0, -10.4, -9.7, -9.8, -9.9, -8.6, -10.3, -9.5, -10.3, -9.3, -8.5, -10.2, -9.5, -9.9, -9.3, -8.6, -10.0, -9.3, -9.7, -9.3, -9.0, -9.5, -9.1, -9.8, -9.5, -9.8, -9.2, -9.0, -10.1, -9.6, -10.0, -9.5, -9.1, -10.2, -9.8, -10.2, -9.6, -9.6, -9.8, -9.5, -10.3, -9.9, -10.4, -9.7, -9.5, -10.6, -10.2, -10.9, -10.2, -10.1, -10.3, -10.1, -11.0, -10.3, -11.0, -10.6, -10.4, -10.7, -10.3, -11.4, -10.6, -11.1, -10.5, -10.2, -10.9, -10.1, -11.0, -10.6, -11.1, -10.4, -9.7, -10.8, -10.3, -11.1, -10.6, -10.9, -10.8, -10.3, -11.3, -10.9, -11.6, -11.2, -11.0, -11.2, -10.8, -11.9, -11.5, -12.0, -11.6, -11.5, -11.9, -11.6, -12.3, -12.1, -12.2, -12.2, -11.8, -12.7, -12.8, -12.8, -12.6, -12.7, -13.2, -12.8, -13.5, -13.3, -13.5, -13.5, -13.1, -14.0, -14.1, -14.7, -14.3, -14.3, -15.0, -15.4, -16.3, -17.2, -18.0, -18.3, -18.6, -18.9, -19.6, -20.0, -19.8, -19.6, -20.1, -20.4, -20.8, -20.4, -20.4, -20.7, -20.9, -20.9, -20.3, -20.1, -20.8, -20.9, -21.0, -21.2, -21.6, -22.5, -23.2, -23.5, -23.8, -24.7, -25.2, -26.1, -27.6, -28.1, -29.4, -30.8, -33.0, -34.4, -37.5, -39.1, -42.8, -45.1, -47.6, -50.9, -53.3, -52.5, -55.0, -51.2, -50.8, -52.9, -47.5, -49.8, -54.8, -48.4, -46.0, -50.7, -53.8, -54.3, -57.9, -56.8, -54.2, -56.5, -49.1, -50.1, -61.7, -50.0, -51.1, -51.5, -52.4, -47.6, -50.0, -49.1, -45.7, -50.2, -48.7, -50.8, -51.2, -47.7, -46.5, -51.9, -43.6, -42.9, -46.3, -45.4, -41.8, -47.1, -45.1, -48.6, -46.9, -48.2, -48.5, -48.2, -43.3, -42.1, -46.1, -43.7, -43.3, -44.8, -47.0, -45.7, -45.7, -47.5, -44.8, -42.5, -41.2, -40.7, -51.6, -43.6, -44.1, -49.7, -47.2, -55.0, -47.9, -44.6, -51.6, -49.8, -51.1, -48.3, -54.7, -46.0, -46.6, -45.3, -46.3, -48.3, -51.9, -52.7, -51.5, -58.2, -55.1, -53.5, -55.5, -56.5, -64.6, -62.5, -59.3, -52.0, -50.7, -53.3, -52.0, -48.4, -55.6, -58.4, -55.1, -57.2, -53.6, -52.4, -55.9, -47.0, -47.8, -51.0, -49.6, -49.6, -50.9, -48.0, -47.0, -49.4, -55.8, -47.4, -47.7, -51.8, -52.6, -53.5, -51.6, -37.1, -39.2, -37.6, -29.7, -29.6, -28.5, -27.8, -26.8, -26.5, -25.0, -24.7, -25.1, -26.2, -25.9, -23.8, -24.2, -23.1, -24.8, -23.5, -25.6, -24.7, -28.8, -32.0, -32.9, -32.3, -21.0, -16.1, -12.9, -13.0, -12.5, -10.8, -12.8, -12.9, -10.8, -11.3, -11.2, -9.7, -10.1, -10.7, -9.3, -10.2, -11.1, -10.1, -11.7, -12.8, -12.9, -14.8, -14.4, -14.5, -13.7, -11.1, -11.3, -11.2, -12.1, -11.9, -11.0, -11.6, -12.9, -11.7, -12.6, -12.3, -13.5, -13.4, -12.7, -13.1, -13.3, -13.5, -13.6, -13.2, -12.2, -12.1, -12.5, -10.3, -10.7, -11.3, -9.2, -9.9, -10.2, -8.8, -9.4, -9.7, -8.4, -9.5, -10.0, -9.0, -10.1, -10.7, -10.3, -10.9, -11.4, -11.1, -12.1, -12.7, -12.6, -13.1, -14.0, -13.8, -13.8, -14.4, -14.2, -14.1, -13.8, -14.0, -13.8, -13.6, -14.1, -13.3, -13.1, -13.7, -13.2, -13.0, -13.2, -13.2, -12.8, -12.5, -13.2, -12.5, -12.4, -13.2, -12.7, -12.7, -13.4, -13.1, -13.2, -13.2, -13.3, -13.3, -12.6, -13.0, -13.3, -12.4, -13.0, -13.4, -12.4, -13.4, -13.7, -13.0, -13.8, -14.1, -13.8, -14.6, -14.5, -14.2, -15.0, -14.7, -14.6, -15.4, -15.4, -15.2, -15.8, -15.4, -15.8, -16.4, -16.0, -16.2, -17.2, -16.9, -16.9, -17.7, -17.5, -17.3, -18.5, -18.1, -17.9, -19.3, -18.7, -18.6, -19.8, -20.2, -20.2, -21.1, -22.5, -22.9, -24.7, -28.6, -30.9, -34.0, -34.9, -34.1, -36.0, -34.1, -34.1, -34.5, -33.9, -32.5, -32.6, -33.4, -32.3, -35.0, -33.0, -37.9, -30.6, -34.7, -33.0, -33.5, -33.4, -32.9, -36.2, -35.9, -34.7, -31.7, -35.4, -38.8, -39.3, -39.3, -35.0, -38.4, -36.6, -35.8, -36.5, -35.1, -36.9, -35.9, -38.3, -37.4, -40.0, -38.0, -39.4, -39.0, -38.1, -34.6, -39.8, -36.7, -35.3, -39.3, -41.5, -39.6, -36.7, -40.1, -41.2, -42.7, -44.4, -45.4, -47.7, -47.2, -48.9, -51.3, -51.7, -51.4, -55.0, -58.2, -58.4, -53.1, -49.1, -51.4, -50.7, -51.4, -48.6, -34.3, -39.4, -36.8, -34.1, -39.0, -42.4, -39.6, -43.9, -43.9, -41.8, -43.9, -44.0, -45.6, -53.2, -50.0, -48.1, -45.9, -48.0, -44.9, -43.2, -45.9, -43.9, -53.1, -49.1, -59.4, -56.4, -47.8, -44.3, -49.6, -45.6, -54.9, -50.7, -63.9, -53.1, -62.0, -56.9, -48.8, -50.2, -52.5, -61.9, -52.8, -57.1, -49.8, -53.4, -53.7, -57.8, -53.1, -64.0, -61.1, -56.5, -61.5, -58.3, -60.0, -66.0, -57.3, -56.1, -64.4, -61.8, -56.9, -51.7, -48.4, -49.6, -52.9, -48.0, -50.7, -48.9, -50.6, -46.6, -44.9, -47.0, -43.2, -43.7, -40.2, -38.8, -36.7, -39.5, -40.7, -39.8, -34.9, -31.2, -25.6, -21.7, -19.5, -17.3, -16.6, -17.5, -17.5, -16.7, -15.9, -15.3, -15.8, -14.0, -13.6, -14.0, -13.2, -12.7, -12.2, -10.8, -11.3, -10.1, -10.3, -11.8, -10.6, -12.6, -10.6, -10.7, -10.8, -9.1, -10.6, -8.4, -9.4, -9.2, -9.1, -10.0, -9.0, -9.9, -9.9, -9.3, -10.0, -9.3, -9.5, -9.8, -8.5, -9.7, -8.8, -9.1, -9.5, -7.9, -9.8, -8.8, -9.0, -9.4, -8.1, -9.9, -8.7, -8.9, -9.6, -8.0, -10.0, -8.8, -9.0, -9.9, -8.6, -10.6, -9.5, -9.8, -10.8, -9.5, -11.9, -10.5, -11.2, -11.6, -11.1, -13.2, -11.3, -12.6, -12.3, -12.1, -13.5, -11.8, -14.2, -13.1, -13.0, -13.8, -12.5, -14.6, -12.6, -13.3, -13.2, -12.7, -14.2, -12.2, -14.1, -13.1, -12.8, -13.7, -12.6, -14.7, -13.1, -13.5, -13.8, -13.4, -14.7, -12.8, -14.2, -13.6, -13.5, -14.5, -13.0, -14.7, -13.7, -13.5, -14.0, -13.6, -15.2, -13.6, -13.9, -13.9, -13.9, -14.9, -13.5, -14.8, -14.2, -14.3, -15.0, -14.1, -15.5, -14.7, -14.8, -15.5, -14.8, -15.7, -14.8, -15.2, -15.3, -15.1, -15.8, -14.9, -15.3, -15.6, -15.3, -16.0, -15.2, -15.4, -15.6, -15.3, -16.1, -15.3, -15.5, -15.3, -15.7, -16.3, -15.6, -16.1, -15.4, -15.8, -16.6, -15.3, -15.9, -15.3, -15.8, -16.4, -15.3, -16.1, -15.5, -15.6, -16.0, -14.9, -16.2, -15.2, -15.3, -15.9, -15.3, -17.0, -15.8, -16.0, -16.9, -17.1, -19.0, -22.2, -21.0, -21.4, -23.4, -28.2, -31.1, -28.3, -26.9, -25.2, -17.5, -12.7, -12.4, -14.5, -12.5, -12.6, -14.0, -11.6, -12.3, -13.0, -11.5, -13.2, -14.2, -13.3, -14.2, -15.5, -14.1, -14.4, -15.6, -14.1, -14.8, -15.2, -13.8, -15.0, -15.4, -14.1, -15.2, -16.0, -15.1, -16.0, -16.4, -15.0, -16.2, -16.7, -15.5, -16.1, -17.1, -15.8, -16.8, -17.2, -16.2, -17.4, -18.2, -16.8, -18.0, -18.9, -17.8, -19.0, -19.7, -18.8, -20.3, -20.6, -20.3, -22.0, -22.9, -21.9, -24.3, -23.5, -23.2, -24.1, -22.4, -22.7, -22.7, -21.9, -22.5, -21.3, -21.6, -22.3, -21.2, -22.0, -22.2, -21.1, -21.9, -22.1, -21.7, -22.7, -22.2, -21.7, -23.5, -23.1, -23.0, -24.8, -23.8, -24.2, -25.5, -24.2, -23.8, -25.3, -24.8, -23.9, -25.5, -24.7, -24.8, -25.6, -24.5, -25.9, -25.2, -25.4, -25.8, -24.3, -24.3, -24.9, -24.1, -24.4, -24.8, -23.9, -24.4, -23.1, -23.1, -24.2, -22.6, -22.3, -23.8, -22.9, -23.2, -23.5, -23.1, -24.0, -24.2, -24.1, -24.2, -23.9, -24.0, -24.8, -23.7, -24.3, -25.5, -24.1, -25.6, -24.8, -25.3, -26.6, -25.9, -26.0, -29.1, -25.7, -27.1, -26.7, -25.9, -29.0, -25.8, -25.6, -26.1, -26.2, -25.7, -26.3, -26.9, -28.6, -28.7, -28.1, -27.6, -29.0, -24.8, -21.4, -19.8, -16.6, -16.2, -16.1, -15.0, -12.9, -13.3, -14.2, -14.1, -13.0, -12.8, -13.5, -13.7, -13.5, -12.5, -12.1, -12.4, -13.1, -13.0, -12.9, -12.1, -12.4, -13.6, -13.3, -12.9, -11.8, -11.4, -12.9, -12.7, -12.7, -11.1, -10.8, -12.2, -11.6, -11.8, -10.8, -10.2, -11.9, -11.9, -12.0, -10.8, -10.4, -12.0, -11.9, -12.2, -10.8, -10.6, -12.4, -12.1, -12.2, -11.0, -10.5, -12.2, -12.1, -12.2, -10.9, -10.9, -12.5, -12.4, -12.4, -11.4, -11.2, -12.5, -12.6, -12.6, -12.5, -11.9, -12.0, -13.3, -13.6, -13.6, -12.2, -12.1, -13.8, -13.8, -13.7, -13.4, -12.6, -12.4, -13.7, -13.1, -13.1, -12.0, -11.8, -13.1, -12.8, -13.0, -12.2, -11.8, -12.0, -12.7, -12.8, -12.8, -11.5, -11.4, -12.7, -12.7, -12.6, -11.6, -11.9, -12.9, -13.0, -12.7, -12.9, -12.2, -12.3, -13.2, -13.0, -13.2, -11.8, -12.0, -13.0, -13.0, -13.1, -13.0, -12.5, -12.9, -14.4, -14.2, -14.4, -14.3, -14.2, -14.0, -15.2, -15.1, -15.1, -13.9, -14.0, -15.2, -15.0, -15.0, -14.4, -13.8, -13.9, -14.9, -14.6, -14.6, -13.2, -13.3, -14.9, -14.7, -15.0, -14.1, -14.5, -14.9, -16.2, -16.3, -16.5, -15.5, -16.1, -15.2, -16.3, -16.0, -15.8, -15.8, -16.0, -15.9, -16.1, -16.0, -15.4, -15.4, -15.0, -15.5, -15.9, -15.9, -16.5, -16.9, -16.4, -16.6, -16.5, -15.9, -15.5, -15.3, -15.2, -15.3, -15.6, -16.2, -16.8, -17.0, -17.4, -17.5, -18.0, -18.5, -18.1, -18.5, -18.9, -19.6, -20.0, -20.7, -21.9, -21.4, -22.0, -21.5, -22.2, -22.5, -23.1, -22.8, -25.6, -27.6, -35.1, -35.3, -36.5, -34.3, -35.5, -35.6, -36.0, -40.9, -43.1, -44.2, -46.3, -42.5, -42.1, -42.0, -43.4, -41.4, -43.7, -42.5, -43.5, -45.5, -42.3, -44.1, -44.6, -39.8, -42.6, -42.7, -41.5, -42.5, -42.6, -43.3, -42.5, -40.4, -40.9, -42.1, -42.5, -41.7, -40.8, -40.9, -42.3, -40.8, -45.8, -42.2, -40.2, -42.1, -39.8, -39.0, -42.5, -43.5, -40.8, -43.0, -45.6, -46.4, -43.9, -45.0, -43.0, -42.5, -41.3, -41.9, -41.3, -44.6, -48.2, -47.6, -46.9, -46.5, -44.7, -45.3, -44.8, -47.1, -47.6, -53.1, -53.2, -52.1, -53.1, -55.5, -57.5, -61.2, -60.0, -64.2, -62.4, -58.7, -55.3, -61.7, -57.7, -57.3, -57.5, -50.1, -49.2, -45.1, -47.0, -48.5, -47.5, -44.3, -41.9, -38.9, -37.2, -34.1, -28.6, -25.7, -27.6, -27.2, -27.5, -29.3, -26.4, -27.8, -29.4, -29.4, -30.7, -32.5, -31.8, -33.3, -32.3, -31.0, -31.3, -28.7, -25.0, -22.8, -19.1, -17.6, -15.7, -11.0, -8.4, -8.1, -6.7, -6.1, -5.3, -6.0, -6.2, -7.1, -6.6, -7.2, -7.8, -8.4, -8.0, -9.0, -8.3, -8.3, -8.7, -9.2, -9.1, -10.0, -9.1, -9.0, -9.0, -9.6, -9.6, -10.4, -9.4, -9.3, -9.2, -9.3, -9.7, -8.6, -8.5, -8.2, -8.5, -8.6, -8.4, -7.9, -7.8, -8.2, -8.2, -8.6, -7.9, -7.6, -8.3, -8.2, -8.6, -7.7, -7.8, -8.7, -8.2, -8.4, -7.5, -7.6, -8.4, -8.2, -8.3, -7.8, -7.7, -8.4, -8.5, -8.1, -7.8, -8.0, -8.4, -9.1, -8.0, -7.9, -8.4, -8.4, -9.4, -8.2, -7.9, -8.7, -8.6, -9.1, -8.3, -8.4, -9.2, -9.5, -8.7, -8.6, -9.0, -9.2, -9.8, -8.7, -8.6, -9.5, -9.4, -9.6, -8.8, -9.1, -10.2, -10.1, -9.7, -9.3, -10.1, -10.5, -11.2, -10.0, -10.3, -11.4, -11.1, -11.8, -11.1, -11.4, -12.7, -12.7, -14.0, -14.0, -14.1, -15.1, -16.1, -17.3, -19.5, -21.3, -25.1, -27.0, -27.4, -27.8, -28.1, -30.1, -29.9, -29.5, -29.5, -29.7, -29.1, -27.8, -29.9, -26.5, -28.4, -28.7, -30.2, -28.1, -28.5, -28.3, -28.1, -27.8, -28.4, -25.8, -25.8, -27.8, -23.7, -25.6, -27.0, -25.7, -24.6, -24.8, -24.3, -24.9, -24.4, -23.2, -27.0, -23.5, -24.4, -26.1, -27.8, -29.5, -34.7, -35.2, -34.4, -23.2, -13.5, -10.7, -10.2, -10.7, -9.8, -9.5, -9.1, -8.8, -10.1, -8.9, -9.9, -9.1, -9.0, -10.1, -8.8, -10.1, -9.5, -9.9, -9.8, -9.1, -10.8, -9.7, -10.2, -9.8, -9.3, -10.6, -9.6, -10.3, -9.9, -9.8, -10.5, -9.8, -10.8, -10.5, -10.3, -10.7, -10.2, -11.5, -11.3, -11.3, -11.9, -12.2, -13.7, -13.8, -13.2, -13.1, -13.0, -13.1, -12.9, -13.9, -14.4, -15.2, -15.6, -16.6, -17.7, -18.1, -19.2, -21.0, -22.9, -25.5, -27.5, -30.5, -34.2, -36.9, -37.5, -36.8, -38.1, -40.4, -39.6, -42.8, -41.0, -42.1, -41.0, -43.9, -45.4, -49.3, -43.5, -44.6, -43.8, -47.9, -45.2, -49.4, -41.8, -41.3, -41.2, -42.8, -40.2, -45.5, -50.4, -51.4, -47.1, -47.8, -48.7, -54.7, -52.6, -46.5, -47.4, -48.6, -48.7, -45.3, -47.7, -49.2, -47.5, -50.7, -54.3, -49.5, -54.0, -52.5, -54.1, -52.6, -53.3, -49.7, -50.9, -43.3, -46.4, -42.4, -44.1, -44.9, -47.0, -43.5, -41.3, -49.8, -49.0, -50.9, -48.7, -45.0, -47.2, -44.5, -43.1, -43.8, -45.1, -47.4, -50.5, -47.6, -45.4, -47.8, -47.4, -46.1, -42.4, -41.0, -44.3, -45.7, -42.7, -44.6, -41.3, -39.1, -41.3, -38.9, -36.9, -36.1, -34.8, -33.9, -32.6, -32.3, -32.2, -33.2, -33.2, -32.5, -32.5, -33.1, -33.2, -34.2, -32.4, -31.8, -32.4, -30.7, -33.1, -31.1, -33.4, -31.6, -30.1, -18.4, -14.2, -14.0, -13.5, -15.1, -13.8, -12.8, -14.6, -11.4, -11.6, -11.8, -10.5, -12.5, -11.0, -11.4, -12.6, -11.2, -11.0, -10.6, -10.6, -11.5, -10.5, -10.2, -10.5, -10.7, -11.3, -10.8, -11.2, -11.2, -11.7, -12.1, -11.5, -12.0, -11.6, -11.4, -11.7, -11.5, -11.7, -11.6, -11.3, -11.2, -11.3, -11.7, -11.3, -11.6, -11.4, -11.3, -11.4, -11.4, -11.9, -11.9, -11.6, -11.9, -12.2, -13.0, -12.5, -12.7, -12.7, -13.2, -13.5, -12.8, -13.0, -12.7, -13.2, -13.6, -12.9, -13.7, -13.3, -13.6, -14.3, -13.8, -14.6, -13.9, -14.0, -14.4, -13.5, -13.8, -13.2, -13.6, -14.0, -13.9, -14.3, -13.8, -14.3, -14.5, -14.5, -15.2, -14.7, -14.8, -14.8, -15.2, -15.6, -15.2, -15.5, -15.3, -15.5, -16.0, -15.1, -14.9, -14.8, -15.5, -15.9, -14.9, -15.2, -15.1, -15.5, -15.6, -15.5, -15.6, -15.6, -15.4, -15.6, -16.0, -17.4, -18.4, -21.1, -27.1, -29.0, -26.0, -25.9, -25.2, -25.3, -25.8, -26.4, -26.7, -27.7, -29.1, -29.2, -28.9, -29.0, -30.3, -31.7, -34.6, -36.4, -40.4, -38.6, -38.2, -37.0, -38.5, -38.5, -39.9, -39.5, -40.5, -42.5, -41.4, -41.7, -41.2, -42.4, -41.3, -41.7, -40.4, -39.7, -38.7, -37.0, -37.6, -37.6, -34.2, -33.3, -34.0, -32.6, -31.5, -32.6, -33.1, -34.5, -34.5, -33.7, -31.8, -27.8, -17.0, -10.3, -9.7, -10.6, -9.4, -9.4, -9.2, -8.6, -9.9, -9.0, -8.5, -10.2, -9.1, -10.1, -9.2, -8.5, -9.6, -8.6, -9.6, -8.4, -7.6, -8.7, -7.8, -8.6, -7.5, -7.3, -8.6, -7.7, -8.5, -7.3, -7.2, -8.3, -7.5, -8.2, -7.3, -7.3, -8.2, -7.2, -8.2, -7.3, -7.2, -8.0, -7.0, -8.2, -7.2, -7.0, -8.0, -7.5, -8.5, -7.4, -7.3, -8.1, -7.6, -8.6, -7.4, -7.2, -8.2, -7.5, -8.4, -7.2, -7.2, -8.3, -7.2, -8.2, -7.5, -7.3, -8.2, -7.3, -8.2, -7.8, -7.5, -8.5, -7.6, -8.5, -7.9, -7.4, -8.4, -8.0, -8.8, -8.1, -7.6, -8.6, -8.3, -8.9, -8.0, -7.6, -8.6, -8.3, -8.7, -8.1, -7.6, -8.8, -8.3, -8.9, -8.4, -8.1, -8.9, -8.5, -9.2, -8.7, -8.3, -9.2, -8.7, -9.5, -9.0, -8.5, -9.0, -8.8, -9.6, -8.7, -8.4, -9.1, -8.9, -9.5, -8.8, -8.7, -9.2, -9.1, -9.7, -9.0, -9.0, -9.5, -9.2, -9.9, -9.4, -9.6, -10.4, -11.8, -14.8, -18.2, -21.5, -26.2, -30.9, -33.3, -32.4, -33.6, -35.5, -36.2, -40.1, -36.8, -36.0, -40.9, -41.0, -44.3, -41.5, -42.0, -42.8, -41.6, -46.3, -45.3, -45.9, -44.7, -48.8, -44.9, -32.6, -28.8, -25.0, -20.7, -21.5, -20.8, -24.4, -25.9, -28.2, -28.1, -30.5, -31.2, -32.4, -33.9, -33.2, -33.7, -32.3, -33.7, -32.7, -32.4, -32.8, -33.9, -33.5, -33.9, -31.1, -31.9, -32.4, -35.3, -34.8, -34.5, -35.3, -36.3, -35.8, -30.0, -25.8, -23.3, -19.4, -18.4, -16.0, -12.6, -10.3, -10.0, -10.0, -10.7, -9.0, -8.3, -8.4, -8.9, -10.3, -8.7, -8.5, -8.8, -9.1, -9.6, -8.2, -8.4, -8.8, -9.5, -9.1, -8.4, -8.4, -8.8, -9.4, -8.8, -8.3, -8.1, -8.5, -9.4, -8.7, -8.4, -8.0, -8.5, -9.3, -8.5, -8.1, -8.1, -8.6, -9.6, -8.2, -7.9, -7.9, -8.4, -9.4, -8.2, -8.2, -8.4, -8.8, -9.3, -8.2, -8.0, -8.5, -8.8, -9.0, -8.4, -8.3, -8.7, -9.2, -9.0, -8.4, -8.4, -8.9, -9.7, -8.7, -8.6, -8.3, -8.9, -10.2, -8.9, -8.6, -8.8, -9.1, -9.7, -8.6, -8.7, -9.2, -9.9, -9.3, -8.6, -8.4, -8.9, -10.0, -8.2, -8.1, -8.5, -9.2, -9.4, -8.5, -8.4, -9.1, -10.2, -8.6, -8.5, -9.3, -10.2, -9.4, -9.1, -9.5, -10.2, -10.7, -10.0, -10.2, -10.9, -11.9, -10.6, -10.6, -11.3, -11.5, -11.5, -10.6, -10.3, -10.9, -11.4, -10.7, -10.6, -10.9, -11.7, -12.9, -11.7, -11.9, -12.8, -12.7, -13.5, -12.6, -12.7, -13.6, -14.0, -13.6, -13.5, -14.3, -14.8, -15.7, -15.1, -15.8, -16.9, -17.9, -17.0, -17.4, -18.4, -18.6, -18.6, -18.6, -19.2, -19.6, -20.9, -20.3, -20.5, -21.6, -21.7, -23.1, -22.3, -22.8, -23.8, -23.3, -23.6, -23.6, -23.4, -24.7, -23.8, -24.8, -24.9, -25.8, -26.8, -28.1, -28.8, -30.6, -31.8, -34.7, -35.1, -36.1, -38.8, -40.6, -43.3, -41.5, -41.9, -46.6, -49.4, -49.3, -51.7, -53.1, -48.4, -44.7, -44.3, -49.3, -43.6, -41.4, -43.6, -47.2, -46.7, -43.7, -44.4, -47.1, -50.8, -47.5, -53.7, -58.0, -54.8, -50.7, -49.8, -56.5, -52.6, -50.1, -50.6, -50.6, -49.2, -51.7, -47.4, -44.7, -46.4, -46.9, -54.4, -49.5, -50.0, -53.6, -45.9, -42.0, -40.1, -38.8, -41.4, -44.0, -43.4, -43.7, -43.8, -45.5, -44.2, -47.1, -48.7, -47.5, -47.7, -46.6, -45.6, -46.7, -42.1, -42.0, -42.9, -46.1, -45.5, -49.0, -49.7, -44.9, -45.9, -44.5, -42.0, -41.2, -42.6, -49.5, -49.0, -48.4, -48.7, -45.8, -46.8, -45.6, -39.3, -39.4, -42.4, -46.2, -44.0, -46.1, -44.9, -41.2, -43.9, -44.8, -44.0, -43.2, -39.0, -40.3, -43.9, -40.9, -42.5, -39.9, -41.3, -47.6, -44.3, -42.5, -43.8, -50.1, -52.1, -48.4, -47.3, -47.1, -48.8, -51.1, -59.7, -51.0, -48.6, -44.0, -44.2, -42.0, -45.8, -52.9, -47.9, -46.7, -46.5, -47.1, -46.3, -47.2, -49.8, -45.5, -45.2, -51.0, -50.5, -52.8, -50.7, -57.3, -54.6, -54.2, -51.0, -51.6, -65.5, -54.7, -53.0, -53.6, -57.1, -59.4, -54.7, -51.1, -49.4, -54.5, -51.6, -48.4, -31.7, -28.5, -26.7, -23.8, -24.5, -25.4, -25.3, -24.6, -27.3, -27.1, -27.3, -28.7, -29.6, -32.1, -30.2, -30.1, -30.0, -30.5, -31.1, -31.7, -32.4, -34.0, -35.4, -35.2, -36.2, -36.7, -35.3, -30.7, -27.3, -23.5, -19.5, -15.8, -14.0, -13.3, -13.0, -13.7, -12.5, -12.9, -12.8, -12.9, -13.5, -12.8, -14.5, -13.4, -13.2, -13.8, -12.9, -14.7, -13.2, -13.4, -13.8, -13.4, -14.9, -13.3, -13.9, -13.8, -13.6, -14.7, -12.6, -13.9, -13.4, -13.2, -14.3, -12.4, -14.5, -13.1, -12.9, -14.1, -12.7, -14.8, -13.1, -13.3, -13.7, -13.0, -14.8, -12.8, -13.9, -13.3, -13.1, -14.4, -12.2, -14.2, -13.1, -12.8, -13.9, -12.3, -14.6, -12.9, -13.0, -13.6, -13.5, -14.3, -12.7, -14.4, -13.2, -13.0, -13.0, -12.5, -14.0, -12.3, -13.2, -12.8, -12.5, -14.0, -12.0, -13.9, -13.2, -13.3, -14.4, -12.6, -15.0, -13.5, -13.7, -14.3, -13.3, -15.6, -13.8, -14.4, -14.6, -14.0, -15.9, -13.7, -14.9, -14.4, -14.2, -15.7, -13.2, -15.4, -14.8, -14.9, -15.2, -14.4, -16.4, -14.5, -15.3, -15.0, -14.6, -16.0, -13.8, -15.8, -14.9, -14.6, -15.4, -14.1, -16.5, -15.2, -15.4, -15.7, -15.2, -17.2, -15.2, -16.5, -15.9, -15.8, -16.8, -15.0, -16.9, -16.0, -16.1, -16.6, -15.6, -18.2, -16.5, -17.1, -17.0, -16.4, -18.1, -16.2, -18.5, -17.1, -16.8, -17.3, -16.6, -17.8, -16.7, -18.1, -17.3, -16.6, -17.7, -16.9, -17.9, -17.1, -18.0, -17.9, -17.6, -18.5, -18.0, -19.0, -19.1, -20.8, -22.1, -22.7, -24.6, -26.1, -27.6, -29.0, -30.9, -32.8, -34.1, -37.7, -41.9, -42.2, -43.4, -39.9, -39.6, -41.9, -42.8, -43.4, -41.9, -42.1, -43.7, -42.1, -43.7, -44.2, -47.1, -46.2, -46.5, -51.0, -49.9, -48.4, -54.0, -51.4, -54.2, -53.3, -49.5, -49.5, -50.0, -46.2, -45.7, -49.4, -51.1, -52.8, -55.6, -52.1, -45.5, -49.8, -52.6, -48.9, -51.5, -52.0, -51.1, -54.2, -45.7, -48.1, -49.6, -45.9, -45.7, -48.2, -46.9, -46.4, -46.4, -45.8, -44.5, -42.6, -43.9, -48.5, -47.1, -51.9, -50.6, -55.1, -45.0, -42.6, -51.3, -44.1, -47.9, -54.7, -55.3, -51.3, -46.8, -46.4, -51.6, -46.6, -44.4, -46.0, -54.7, -41.9, -39.6, -41.7, -49.7, -53.8, -48.0, -49.2, -51.3, -48.2, -54.4, -51.3, -52.2, -53.0, -54.2, -56.1, -51.4, -54.9, -50.8, -53.5, -52.9, -50.5, -57.7, -60.5, -57.6, -59.1, -51.5, -46.7, -47.5, -57.9, -49.7, -49.0, -48.3, -51.3, -50.5, -49.5, -48.4, -44.8, -43.8, -50.5, -48.2, -49.4, -49.6, -50.0, -47.9, -46.0, -47.8, -47.0, -60.8, -50.6, -53.5, -47.5, -50.8, -48.4, -50.2, -53.4, -53.6, -55.5, -61.7, -51.7, -48.3, -48.1, -53.9, -50.0, -47.0, -46.8, -39.1, -38.0, -35.5, -32.7, -29.9, -30.5, -29.1, -30.9, -29.2, -31.3, -28.0, -30.7, -29.5, -27.4, -31.0, -30.3, -30.4, -30.0, -31.6, -32.8, -31.8, -31.0, -31.1, -30.5, -32.6, -33.1, -29.3, -30.6, -33.0, -31.2, -32.6, -31.9, -27.1, -25.4, -23.5, -21.5, -19.2, -16.7, -15.9, -14.8, -13.0, -13.2, -11.4, -12.9, -11.4, -11.0, -10.2, -10.2, -10.7, -8.8, -10.0, -9.4, -9.4, -9.9, -9.0, -9.8, -8.7, -9.9, -9.5, -9.2, -10.3, -9.2, -10.3, -9.7, -9.8, -10.5, -10.0, -10.7, -9.9, -10.7, -11.0, -11.1, -11.7, -11.1, -12.3, -11.8, -12.4, -12.9, -11.9, -13.2, -12.2, -12.5, -13.0, -11.5, -12.5, -12.0, -12.4, -13.1, -11.7, -13.0, -12.4, -12.5, -12.8, -11.5, -13.0, -12.0, -12.4, -12.3, -12.3, -13.4, -12.0, -12.9, -12.5, -12.9, -13.5, -12.2, -13.1, -12.5, -13.0, -13.2, -11.8, -13.0, -12.6, -12.9, -13.2, -12.1, -13.3, -12.7, -12.7, -13.5, -12.2, -13.6, -12.6, -12.9, -13.3, -12.2, -13.6, -11.9, -12.7, -12.2, -12.2, -12.9, -11.1, -12.6, -12.0, -12.0, -12.9, -11.8, -13.0, -12.7, -12.8, -13.8, -12.9, -14.1, -12.9, -13.5, -13.6, -13.5, -13.9, -12.5, -14.2, -13.8, -14.3, -14.7, -13.4, -14.9, -14.4, -14.2, -15.1, -14.3, -15.5, -14.2, -14.5, -14.9, -14.6, -15.6, -14.8, -16.3, -15.7, -16.9, -16.4, -16.4, -17.5, -16.7, -17.0, -16.7, -17.2, -17.4, -16.5, -17.4, -16.7, -17.1, -17.1, -16.4, -17.9, -17.0, -17.7, -16.7, -18.2, -18.2, -17.4, -18.4, -17.6, -19.3, -17.5, -19.2, -19.9, -19.4, -19.5, -18.8, -19.2, -19.8, -20.3, -21.7, -21.2, -22.5, -22.1, -23.5, -25.3, -24.8, -26.5, -25.7, -28.4, -28.1, -30.2, -30.5, -29.8, -31.4, -31.5, -33.0, -32.0, -32.9, -35.1, -34.2, -35.2, -37.5, -40.5, -42.6, -43.1, -42.0, -41.5, -46.3, -45.3, -40.9, -42.4, -48.3, -48.7, -43.5, -43.9, -48.3, -44.1, -46.4, -44.7, -42.7, -44.0, -46.2, -45.6, -46.2, -42.8, -38.9, -39.7, -39.1, -41.0, -40.7, -37.3, -34.4, -34.3, -35.1, -31.2, -28.8, -33.3, -33.4, -30.5, -29.1, -31.4, -34.7, -33.9, -34.6, -34.2, -35.3, -32.8, -33.3, -32.6, -37.5, -35.9, -34.9, -35.4, -33.0, -34.2, -33.4, -33.1, -37.7, -34.8, -37.3, -37.1, -39.3, -37.5, -39.0, -38.5, -40.6, -38.1, -37.8, -40.4, -38.6, -41.5, -41.3, -41.3, -42.5, -49.3], "hf": [0.98, 0.98, 0.98, 0.88, 0.74, 0.89, 0.67, 0.33, 0.14, 0.17, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.02, 0.02, 0.07, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.02, 0.01, 0.01, 0.29, 0.13, 0.12, 0.3, 0.23, 0.12, 0.05, 0.11, 0.21, 0.15, 0.11, 0.14, 0.11, 0.12, 0.07, 0.05, 0.02, 0.01, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.03, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01, 0.0, 0.01, 0.02, 0.02, 0.04, 0.02, 0.02, 0.03, 0.06, 0.06, 0.05, 0.13, 0.06, 0.03, 0.05, 0.01, 0.01, 0.03, 0.11, 0.02, 0.0, 0.03, 0.0, 0.0, 0.0, 0.01, 0.0, 0.03, 0.0, 0.01, 0.0, 0.01, 0.0, 0.04, 0.03, 0.02, 0.03, 0.01, 0.01, 0.01, 0.04, 0.03, 0.01, 0.01, 0.0, 0.03, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.01, 0.08, 0.0, 0.01, 0.01, 0.01, 0.0, 0.03, 0.01, 0.03, 0.0, 0.0, 0.01, 0.02, 0.14, 0.04, 0.01, 0.01, 0.11, 0.38, 0.06, 0.5, 0.15, 0.08, 0.02, 0.11, 0.16, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.02, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.01, 0.01, 0.01, 0.05, 0.01, 0.01, 0.0, 0.03, 0.02, 0.03, 0.01, 0.01, 0.01, 0.01, 0.02, 0.02, 0.01, 0.01, 0.01, 0.01, 0.02, 0.01, 0.0, 0.0, 0.0, 0.01, 0.03, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.01, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.02, 0.05, 0.09, 0.41, 0.61, 0.67, 0.81, 0.93, 0.97, 0.93, 0.88, 0.92, 0.99, 0.99, 0.99, 0.95, 0.98, 0.99, 0.98, 0.99, 0.99, 0.99, 0.97, 0.99, 0.99, 0.99, 0.99, 1.0, 0.99, 1.0, 0.99, 0.99, 0.99, 0.99, 0.99, 1.0, 1.0, 1.0, 0.99, 0.98, 0.98, 0.98, 0.98, 0.94, 0.75, 0.61, 0.81, 0.14, 0.01, 0.01, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.01, 0.03, 0.05, 0.01, 0.02, 0.04, 0.04, 0.04, 0.04, 0.02, 0.04, 0.06, 0.14, 0.11, 0.13, 0.14, 0.09, 0.16, 0.16, 0.12, 0.16, 0.17, 0.4, 0.1, 0.13, 0.44, 0.24, 0.14, 0.09, 0.26, 0.08, 0.15, 0.34, 0.19, 0.08, 0.55, 0.13, 0.07, 0.18, 0.18, 0.09, 0.13, 0.38, 0.07, 0.12, 0.12, 0.1, 0.02, 0.02, 0.09, 0.02, 0.03, 0.11, 0.02, 0.03, 0.08, 0.05, 0.07, 0.09, 0.26, 0.06, 0.09, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.0, 0.0, 0.01, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.02, 0.02, 0.02, 0.01, 0.01, 0.01, 0.0, 0.01, 0.03, 0.03, 0.01, 0.04, 0.05, 0.06, 0.02, 0.01, 0.01, 0.17, 0.17, 0.14, 0.08, 0.14, 0.06, 0.14, 0.05, 0.09, 0.08, 0.17, 0.08, 0.16, 0.05, 0.2, 0.19, 0.06, 0.02, 0.28, 0.01, 0.05, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.02, 0.03, 0.01, 0.01, 0.01, 0.1, 0.0, 0.0, 0.02, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.0, 0.0, 0.01, 0.02, 0.04, 0.09, 0.1, 0.07, 0.05, 0.04, 0.03, 0.08, 0.02, 0.07, 0.09, 0.1, 0.05, 0.05, 0.05, 0.08, 0.11, 0.13, 0.25, 0.03, 0.12, 0.01, 0.01, 0.04, 0.05, 0.02, 0.02, 0.04, 0.04, 0.05, 0.01, 0.07, 0.03, 0.01, 0.01, 0.03, 0.03, 0.05, 0.06, 0.02, 0.06, 0.02, 0.01, 0.0, 0.02, 0.01, 0.01, 0.01, 0.01, 0.0, 0.02, 0.02, 0.05, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.01, 0.01, 0.05, 0.01, 0.09, 0.02, 0.03, 0.05, 0.03, 0.01, 0.05, 0.18, 0.13, 0.19, 0.22, 0.04, 0.05, 0.11, 0.11, 0.03, 0.08, 0.38, 0.16, 0.38, 0.07, 0.03, 0.0, 0.0, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.01, 0.04, 0.02, 0.01, 0.02, 0.02, 0.02, 0.03, 0.04, 0.04, 0.09, 0.07, 0.1, 0.09, 0.2, 0.25, 0.41, 0.08, 0.09, 0.03, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.01, 0.04, 0.04, 0.02, 0.01, 0.01, 0.02, 0.02, 0.03, 0.04, 0.05, 0.04, 0.05, 0.04, 0.05, 0.08, 0.11, 0.09, 0.23, 0.23, 0.11, 0.16, 0.29, 0.27, 0.27, 0.34, 0.68, 0.85, 0.87, 0.95, 0.95, 0.96, 0.98, 0.99, 0.98, 0.99, 0.98, 0.99, 0.99, 0.99, 0.98, 0.99, 0.97, 0.99, 0.99, 0.99, 0.99, 0.99, 0.99, 1.0, 0.99, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.99, 0.94, 0.98, 0.98, 0.97, 0.95, 0.88, 0.94, 0.82, 0.7, 0.82, 0.82, 0.68, 0.61, 0.47, 0.81, 0.58, 0.27, 0.83, 0.98, 0.98, 0.94, 0.6, 0.06, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.02, 0.01, 0.0, 0.01, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.05, 0.02, 0.01, 0.02, 0.01, 0.0, 0.05, 0.01, 0.01, 0.01, 0.01, 0.0, 0.01, 0.0, 0.0, 0.01, 0.01, 0.01, 0.01, 0.0, 0.01, 0.03, 0.0, 0.0, 0.01, 0.01, 0.0, 0.02, 0.01, 0.01, 0.01, 0.02, 0.01, 0.01, 0.0, 0.01, 0.02, 0.03, 0.01, 0.01, 0.01, 0.02, 0.01, 0.01, 0.01, 0.02, 0.0, 0.0, 0.02, 0.0, 0.0, 0.02, 0.0, 0.01, 0.0, 0.0, 0.01, 0.0, 0.01, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.01, 0.0, 0.01, 0.01, 0.01, 0.01, 0.01, 0.17, 0.12, 0.01, 0.0, 0.01, 0.02, 0.0, 0.0, 0.01, 0.12, 0.01, 0.03, 0.01, 0.01, 0.05, 0.01, 0.01, 0.02, 0.0, 0.0, 0.02, 0.01, 0.01, 0.02, 0.12, 0.01, 0.0, 0.0, 0.01, 0.16, 0.18, 0.15, 0.32, 0.35, 0.23, 0.75, 0.83, 0.87, 0.88, 0.91, 0.9, 0.91, 0.91, 0.89, 0.85, 0.82, 0.91, 0.92, 0.9, 0.84, 0.82, 0.7, 0.74, 0.6, 0.41, 0.36, 0.02, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.02, 0.04, 0.11, 0.39, 0.35, 0.4, 0.71, 0.4, 0.31, 0.55, 0.46, 0.86, 0.81, 0.92, 0.74, 0.7, 0.69, 0.87, 0.94, 0.87, 0.89, 0.61, 0.72, 0.49, 0.77, 0.66, 0.81, 0.98, 0.91, 0.87, 0.84, 0.46, 0.41, 0.87, 0.82, 0.86, 0.94, 0.9, 0.96, 0.82, 0.88, 0.76, 0.8, 0.49, 0.97, 0.93, 0.67, 0.87, 0.46, 0.87, 0.77, 0.56, 0.45, 0.16, 0.15, 0.43, 0.11, 0.04, 0.14, 0.13, 0.09, 0.13, 0.09, 0.2, 0.04, 0.01, 0.05, 0.01, 0.02, 0.04, 0.02, 0.58, 0.31, 0.71, 0.37, 0.32, 0.08, 0.38, 0.03, 0.01, 0.15, 0.1, 0.07, 0.2, 0.08, 0.01, 0.01, 0.22, 0.01, 0.0, 0.01, 0.01, 0.03, 0.0, 0.23, 0.08, 0.0, 0.0, 0.02, 0.0, 0.02, 0.0, 0.08, 0.0, 0.05, 0.01, 0.0, 0.01, 0.01, 0.09, 0.02, 0.13, 0.0, 0.02, 0.03, 0.04, 0.01, 0.18, 0.05, 0.01, 0.01, 0.02, 0.18, 0.13, 0.02, 0.01, 0.03, 0.05, 0.03, 0.01, 0.03, 0.01, 0.05, 0.04, 0.13, 0.05, 0.5, 0.14, 0.04, 0.09, 0.23, 0.63, 0.16, 0.08, 0.09, 0.83, 0.1, 0.12, 0.16, 0.08, 0.03, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.01, 0.0, 0.01, 0.0, 0.01, 0.01, 0.0, 0.01, 0.0, 0.01, 0.01, 0.0, 0.01, 0.01, 0.02, 0.01, 0.02, 0.02, 0.01, 0.02, 0.01, 0.02, 0.01, 0.01, 0.02, 0.01, 0.02, 0.01, 0.01, 0.02, 0.01, 0.03, 0.01, 0.02, 0.02, 0.01, 0.03, 0.01, 0.02, 0.01, 0.01, 0.03, 0.01, 0.03, 0.01, 0.02, 0.02, 0.01, 0.03, 0.01, 0.02, 0.02, 0.01, 0.03, 0.01, 0.03, 0.01, 0.01, 0.03, 0.01, 0.03, 0.02, 0.01, 0.02, 0.02, 0.03, 0.02, 0.02, 0.03, 0.01, 0.03, 0.02, 0.02, 0.04, 0.02, 0.03, 0.02, 0.02, 0.02, 0.02, 0.02, 0.01, 0.01, 0.02, 0.01, 0.02, 0.01, 0.02, 0.01, 0.01, 0.03, 0.01, 0.03, 0.01, 0.01, 0.02, 0.0, 0.03, 0.01, 0.01, 0.02, 0.01, 0.03, 0.01, 0.02, 0.02, 0.0, 0.02, 0.01, 0.01, 0.02, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.01, 0.01, 0.02, 0.02, 0.01, 0.01, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.02, 0.01, 0.01, 0.03, 0.02, 0.01, 0.06, 0.01, 0.01, 0.04, 0.02, 0.01, 0.01, 0.01, 0.01, 0.03, 0.02, 0.01, 0.06, 0.03, 0.02, 0.06, 0.02, 0.02, 0.05, 0.02, 0.02, 0.08, 0.05, 0.03, 0.07, 0.05, 0.04, 0.09, 0.08, 0.04, 0.08, 0.07, 0.06, 0.06, 0.05, 0.04, 0.04, 0.02, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.01, 0.0, 0.01, 0.02, 0.01, 0.0, 0.01, 0.01, 0.0, 0.0, 0.01, 0.03, 0.01, 0.03, 0.01, 0.01, 0.02, 0.03, 0.01, 0.02, 0.01, 0.02, 0.01, 0.01, 0.0, 0.0, 0.01, 0.01, 0.01, 0.0, 0.02, 0.05, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, 0.0, 0.02, 0.01, 0.01, 0.0, 0.0, 0.01, 0.01, 0.01, 0.0, 0.0, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.01, 0.02, 0.02, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.02, 0.02, 0.03, 0.04, 0.04, 0.07, 0.07, 0.07, 0.11, 0.17, 0.06, 0.1, 0.17, 0.12, 0.1, 0.1, 0.19, 0.15, 0.11, 0.29, 0.16, 0.13, 0.09, 0.05, 0.04, 0.08, 0.09, 0.37, 0.08, 0.05, 0.21, 0.06, 0.1, 0.09, 0.1, 0.08, 0.11, 0.13, 0.17, 0.08, 0.14, 0.05, 0.06, 0.07, 0.04, 0.02, 0.03, 0.05, 0.05, 0.05, 0.01, 0.0, 0.03, 0.0, 0.0, 0.01, 0.03, 0.01, 0.04, 0.03, 0.02, 0.01, 0.06, 0.05, 0.14, 0.05, 0.01, 0.01, 0.47, 0.22, 0.39, 0.21, 0.48, 0.03, 0.21, 0.52, 0.72, 0.24, 0.05, 0.1, 0.1, 0.03, 0.01, 0.01, 0.02, 0.05, 0.04, 0.01, 0.35, 0.03, 0.2, 0.45, 0.27, 0.37, 0.14, 0.35, 0.41, 0.26, 0.15, 0.31, 0.08, 0.07, 0.01, 0.03, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.02, 0.01, 0.01, 0.01, 0.0, 0.01, 0.01, 0.01, 0.01, 0.0, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.02, 0.02, 0.02, 0.06, 0.1, 0.21, 0.27, 0.64, 0.78, 0.64, 0.88, 0.87, 0.75, 0.94, 0.96, 0.95, 0.92, 0.94, 0.96, 0.94, 0.92, 0.94, 0.9, 0.96, 0.98, 0.97, 0.91, 0.98, 0.94, 0.93, 0.97, 0.95, 0.96, 0.92, 0.92, 0.96, 0.86, 0.95, 0.92, 0.92, 0.96, 0.93, 0.49, 0.75, 0.28, 0.02, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.02, 0.01, 0.0, 0.01, 0.0, 0.01, 0.07, 0.01, 0.0, 0.01, 0.0, 0.01, 0.07, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.05, 0.0, 0.01, 0.01, 0.04, 0.04, 0.01, 0.01, 0.01, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.03, 0.01, 0.02, 0.01, 0.0, 0.01, 0.0, 0.0, 0.01, 0.0, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.02, 0.02, 0.04, 0.1, 0.13, 0.31, 0.19, 0.24, 0.18, 0.21, 0.44, 0.24, 0.43, 0.45, 0.25, 0.24, 0.16, 0.27, 0.44, 0.22, 0.14, 0.19, 0.16, 0.21, 0.32, 0.1, 0.13, 0.21, 0.09, 0.16, 0.07, 0.16, 0.18, 0.07, 0.01, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.01, 0.01, 0.0, 0.01, 0.01, 0.01, 0.01, 0.01, 0.02, 0.01, 0.01, 0.02, 0.0, 0.03, 0.01, 0.02, 0.01, 0.01, 0.03, 0.01, 0.03, 0.02, 0.01, 0.02, 0.01, 0.03, 0.01, 0.01, 0.02, 0.01, 0.02, 0.01, 0.01, 0.02, 0.02, 0.03, 0.01, 0.02, 0.01, 0.02, 0.02, 0.01, 0.03, 0.02, 0.03, 0.02, 0.01, 0.02, 0.01, 0.02, 0.02, 0.01, 0.03, 0.01, 0.02, 0.02, 0.02, 0.03, 0.03, 0.03, 0.02, 0.01, 0.02, 0.01, 0.01, 0.01, 0.01, 0.02, 0.01, 0.02, 0.01, 0.01, 0.01, 0.01, 0.02, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.02, 0.01, 0.02, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.02, 0.01, 0.0, 0.01, 0.04, 0.02, 0.01, 0.03, 0.03, 0.03, 0.05, 0.03, 0.12, 0.14, 0.27, 0.28, 0.56, 0.7, 0.49, 0.74, 0.9, 0.87, 0.86, 0.81, 0.91, 0.93, 0.71, 0.53, 0.54, 0.7, 0.6, 0.67, 0.56, 0.6, 0.63, 0.48, 0.35, 0.37, 0.22, 0.33, 0.42, 0.45, 0.37, 0.16, 0.14, 0.29, 0.25, 0.52, 0.21, 0.14, 0.03, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.03, 0.0, 0.0, 0.0, 0.01, 0.01, 0.21, 0.74, 0.97, 0.89, 0.99, 0.98, 0.85, 0.89, 0.88, 0.47, 0.7, 0.46, 0.41, 0.62, 0.34, 0.33, 0.35, 0.39, 0.45, 0.42, 0.5, 0.22, 0.16, 0.33, 0.18, 0.27, 0.12, 0.24, 0.12, 0.2, 0.13, 0.27, 0.11, 0.05, 0.01, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01, 0.0, 0.02, 0.02, 0.04, 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.02, 0.01, 0.08, 0.01, 0.01, 0.05, 0.01, 0.01, 0.01, 0.01, 0.03, 0.03, 0.03, 0.01, 0.02, 0.01, 0.01, 0.01, 0.02, 0.07, 0.03, 0.01, 0.03, 0.02, 0.03, 0.02, 0.0, 0.0, 0.0, 0.01, 0.0, 0.01, 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01, 0.01, 0.02, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.01, 0.01, 0.02, 0.01, 0.02, 0.03, 0.04, 0.0, 0.0, 0.19, 0.02, 0.03, 0.01, 0.01, 0.03, 0.02, 0.01, 0.0, 0.01, 0.01, 0.01, 0.56, 0.96, 0.98, 0.98, 0.88, 0.79, 0.99, 0.88, 0.91, 0.82, 0.93, 0.73, 0.82, 0.84, 0.57, 0.65, 0.71, 0.57, 0.55, 0.54, 0.38, 0.43, 0.61, 0.34, 0.34, 0.18, 0.1, 0.03, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.01, 0.01, 0.01, 0.01, 0.0, 0.01, 0.0, 0.01, 0.0, 0.01, 0.01, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.01, 0.01, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.01, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.01, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.02, 0.02, 0.01, 0.0, 0.0, 0.0, 0.02, 0.0, 0.0, 0.01, 0.02, 0.0, 0.02, 0.0, 0.0, 0.01, 0.02, 0.0, 0.0, 0.02, 0.0, 0.02, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.01, 0.0, 0.0, 0.03, 0.0, 0.0, 0.02, 0.05, 0.01, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.02, 0.01, 0.01, 0.01, 0.01, 0.02, 0.0, 0.0, 0.0, 0.0, 0.02, 0.03, 0.02, 0.02, 0.01, 0.0, 0.0, 0.08, 0.01, 0.01, 0.03, 0.04, 0.03, 0.1, 0.03, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.01, 0.0, 0.05, 0.0, 0.01, 0.0, 0.02, 0.0, 0.0, 0.03, 0.03, 0.01, 0.14, 0.01, 0.0, 0.01, 0.06, 0.01, 0.0, 0.0, 0.01, 0.0, 0.02, 0.03, 0.03, 0.07, 0.14, 0.06, 0.12, 0.15, 0.04, 0.15, 0.22, 0.11, 0.44, 0.39, 0.14, 0.19, 0.1, 0.19, 0.27, 0.08, 0.17, 0.12, 0.15, 0.17, 0.09, 0.16, 0.14, 0.05, 0.05, 0.08, 0.03, 0.03, 0.03, 0.01, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.03, 0.0, 0.0, 0.03, 0.0, 0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.02, 0.01, 0.01, 0.05, 0.03, 0.38, 0.4, 0.84, 0.46, 0.23, 0.64, 0.93, 0.91, 0.68, 0.7, 0.99, 0.93, 0.94, 0.96, 1.0, 1.0, 0.99, 0.99, 0.99, 0.97, 0.98, 0.96, 0.91, 0.98, 0.95, 0.98, 0.99, 0.96, 0.98, 0.96, 0.99, 0.98, 0.96, 0.99, 0.99, 0.94, 0.98, 0.98, 0.99, 0.96, 0.99, 0.81, 0.86, 0.97, 0.97, 0.94, 0.98, 0.99, 0.98, 1.0, 0.98, 0.92, 0.68, 0.74, 0.91]}}}} \ No newline at end of file -- tangled.sh