aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/design/2026-08-03-ambience-audio-handoff.org79
-rw-r--r--docs/specs/2026-07-06-radio-browser-lookup-spec.org2
-rw-r--r--docs/specs/2026-07-17-org-agenda-fullscreen-frame-spec.org5
3 files changed, 83 insertions, 3 deletions
diff --git a/docs/design/2026-08-03-ambience-audio-handoff.org b/docs/design/2026-08-03-ambience-audio-handoff.org
new file mode 100644
index 00000000..045e44ad
--- /dev/null
+++ b/docs/design/2026-08-03-ambience-audio-handoff.org
@@ -0,0 +1,79 @@
+#+TITLE: Ambience audio — build notes and source findings
+#+AUTHOR: Craig Jennings
+#+DATE: 2026-08-03
+
+Build notes for the ambient audio the music config plays. The audio itself
+is not tracked here; it lives at =~/documents/sounds/ambience/= and the
+playlist reaches it by relative path. This file is the technique and the
+measurements, which are the parts worth keeping.
+
+* What these are
+
+Three 1-hour ambient tracks built 2026-08-03:
+
+ cafe-1h 29 MB cafe murmur only
+ rain-1h 25 MB rain only
+ rain-plus-cafe65-1h 43 MB both, cafe at 65% of the rain
+
+* How they were built
+
+Sources are two short loops — cafe at 1:50 and rain at 2:32, both 24 kHz
+stereo at 56-64 kbps.
+
+The two pure tracks are =ffmpeg -stream_loop= with =-c copy=, so they carry
+no second-generation encoding loss: bit-identical to the source repeated
+about thirty times. Only the mix is re-encoded (libmp3lame 96k, 24 kHz to
+match source).
+
+The mix is rain at unity and cafe at =volume=0.65=, combined with
+=amix=normalize=0=.
+
+*The =normalize=0= is the part to remember.* =amix= normalizes by default,
+which halves both inputs and throws the 65% ratio away — the thing you were
+setting is silently discarded and the output still sounds plausible.
+
+Verified after building: peak -1.1 dBTP (no clipping), mean -23.3 dB.
+
+=cafe-1h= is 3599.26s rather than 3600 because a stream copy cuts on an MP3
+frame boundary. I took the lossless copy over the last 0.74s.
+
+* A better-sounding source set exists
+
+There is also a set built from openly-licensed field recordings, at
+=~/documents/sounds/ambience/cc0-*.mp3= — rain from "Lluvia En Riumors"
+(CC0 1.0, 18:08, lossless FLAC source) and cafe from "Cafe, Aldeburgh, UK"
+via radio aporee (Public Domain Mark 1.0, 17:33, 320 kbps).
+
+They sound better than the short loops for a structural reason: 44.1 kHz
+throughout, and an hour needs about four passes rather than thirty, so there
+is far less audible repetition.
+
+** Open thread — that set's rain is too percussive
+
+It was recorded on hard pavement, so you hear drop impacts you would never
+hear from inside a cafe.
+
+Measured: its energy above 2 kHz sits only 0.4 dB below full-band, against
+-19.9 dB for a real rain-through-a-window recording.
+
+Filtering the pavement rain to match does not work — it strips to sparse
+thumps, because that recording's rain character lives almost entirely above
+1 kHz. The fix is a different source recorded indoors, which is unresolved.
+
+Relevant if a rain-only mode ever gets built.
+
+* Note on the loop periods
+
+Measured separately when the 15-minute loops were cut: the periods are exact
+rather than estimated, because the files are literal stream-copy repeats, so
+the period is found by locating where the byte stream repeats. cafe is
+109.680s (4570 frames), rain is 151.584s (6316 frames).
+
+gcd(4570, 6316) = 2 frames, so the two layers coincide only every 14,432,060
+frames — 96.2 hours. No practical length wraps both cleanly, which is why the
+15-minute mix uses a 3s equal-power (qsin) crossfade folding its tail over its
+head so F(0) = F(L), rather than a naive cut.
+
+Measured across the wrap against the typical adjacent sample step inside the
+file: a naive 900s cut gives 4875 against 248 (19.7x, an audible click); the
+crossfaded version gives 236 against 229 (1.03x).
diff --git a/docs/specs/2026-07-06-radio-browser-lookup-spec.org b/docs/specs/2026-07-06-radio-browser-lookup-spec.org
index c65de850..89251418 100644
--- a/docs/specs/2026-07-06-radio-browser-lookup-spec.org
+++ b/docs/specs/2026-07-06-radio-browser-lookup-spec.org
@@ -162,7 +162,7 @@ Add cj/music-radio-search (query -> search -> completing-read multi-select -> wr
* Readiness dimensions
- Data model & ownership: a station plist (uuid, name, url, codec, bitrate, tags, country, votes, clickcount) derived from the API; the .m3u file is generated and owned by Craig once written. No local cache in v1.
-- Errors, empty states & failure: named user-errors — no server reachable, empty results, cancelled selection, write failure (naming the file). No silent data loss; overwrite reuses the existing cj/confirm-strong prompt from create-radio-station.
+- Errors, empty states & failure: named user-errors — no server reachable, empty results, cancelled selection, write failure (naming the file). No silent data loss; overwrite reuses the existing cj/confirm-destructive prompt from create-radio-station.
- Security & privacy: no credentials. The only outbound data is the search query and a User-Agent to a public API. No sensitive data logged.
- Observability: the command messages the server used, the result count, and each file written. Search is one short synchronous call; if it ever feels slow, a "Searching radio-browser…" message covers it.
- Performance & scale: result sets bounded by an explicit limit (default ~30). One GET per search. No scaling concern.
diff --git a/docs/specs/2026-07-17-org-agenda-fullscreen-frame-spec.org b/docs/specs/2026-07-17-org-agenda-fullscreen-frame-spec.org
index 567da53b..497131dc 100644
--- a/docs/specs/2026-07-17-org-agenda-fullscreen-frame-spec.org
+++ b/docs/specs/2026-07-17-org-agenda-fullscreen-frame-spec.org
@@ -4,10 +4,11 @@
#+TODO: TODO | DONE
#+TODO: DRAFT READY DOING | IMPLEMENTED SUPERSEDED CANCELLED
-* IMPLEMENTED org-agenda fullscreen frame
+* SUPERSEDED org-agenda fullscreen frame
:PROPERTIES:
:ID: 7705c94b-9bb7-47d8-9828-e9584172c54f
:END:
+- 2026-07-27 Mon @ 13:57 -0500 — SUPERSEDED. Craig replaced the whole design with a separate Emacs process that shows the agenda, toggles fullscreen on a key, and refreshes itself every five minutes. This reverses the "Not a separate OS process" non-goal below: the daemon frame bought live shared state, but paid for it with a default-deny read-only policy, engage-routing, auto-dim suspension, and a marker-cloning failure path — machinery that only existed because the agenda shared a process with the working frames. A separate process needs none of it. =modules/org-agenda-frame.el= and its two test files were deleted and =S-<f8>= returned to =cj/org-agenda-refresh-files=.
- 2026-07-20 Mon @ 15:33 -0500 — post-implementation correction: dropped =(fullscreen . fullboth)= from the spawned frame. Craig's "fullscreen" meant a normal frame at its full tiled position, not a compositor-wide fullscreen; the frame is now a plain =make-frame= that a tiling WM (Hyprland) places side by side with the working frame. The engage-routing and focus logic are unchanged and now matter more (open a task in the adjacent working pane). The spec's "fullscreen" wording and filename are retained as historical; read them as "dedicated tiled frame". Covered by =test-org-agenda-frame-parameters-normal-tiled-frame=.
- 2026-07-20 Mon @ 14:10 -0500 — IMPLEMENTED. Built both phases in =modules/org-agenda-frame.el= (58 ERT tests, full suite green, byte-compile clean, full init loads clean, live-reloaded into the daemon with all wiring confirmed). Phase 1: frame lookup/predicate/working-frame routing, the =F= today-anchored 7-day view + registration, the default-deny =cj/agenda-frame-mode= (allowlist + two message classes + menu removal + finalize re-enable), transactional spawn/raise/delete/toggle, engage routing, sticky/close lifecycle. Phase 2: the 5-min wall-clock =org-agenda-redo= timer with the window/focus contract, duplicate-timer prevention, deterministic point restoration, the frame-owned last-good snapshot with cloned markers + failure overlay + report-once latch, and the public =cj/agenda-frame-toggle= on =S-<f8>= with the force-rescan moved to =C-M-<f8>=. The compositor fullscreen/focus and real-redo behaviors are a residual manual check (VERIFY filed under Manual testing).
- 2026-07-20 Mon @ 13:30 -0500 — DOING. Decomposed into build tasks (Phase 1, Phase 2, flip-to-IMPLEMENTED) under the fullscreen-frame PROJECT in todo.org; =:SPEC_ID:= stamped. Building Phase 1.
@@ -27,7 +28,7 @@
- 2026-07-17 Fri @ 19:34:07 -0500 — drafted.
* Metadata
-| Status | implemented |
+| Status | superseded |
|----------+------------------------------------------------|
| Owner | Craig Jennings |
|----------+------------------------------------------------|