A cafe in your menu bar
Background noise that sounds like somewhere, not like something. Chatter you can't quite make out, an espresso machine behind it, and two controls: which cafe, and where you're sitting in it — because in a real room, distance means darker and wetter, not just quieter.
No dock icon, no window, no content. Click the cup, pick a cafe and a seat, get on with it. Play and Stop sit at the top of the menu.
| Cafe | What you hear |
|---|---|
| Isle of Wight | Indistinct talk, rain outside |
| São Paulo | Busy chain cafe, steady hum |
| Indianapolis | Dense and close, binaural |
Three real field recordings, all public domain — sources in CREDITS.md. Each is downloaded the first time you pick it, verified against its SHA-256, and cached from then on. Switching cafes keeps the current one playing until the next is on disk, so you get a swap rather than a gap.
Each cafe, three rooms. The seat isn't a different file — it's the same recording heard from somewhere else, shaped in real time.
| Seat | What you hear |
|---|---|
| Counter | Espresso hiss, chatter up close |
| Corner table | Voices blur together |
| By the window | Muffled, with traffic outside |
Moving from the counter to the window drops the low-pass corner from 12 kHz to 2 kHz, roughly triples the reverb mix, trims the level, and fades in a quiet bed of generated street noise. Measured across the span: 22 dB of high-frequency energy gone, about 6 dB of overall level.
./run.sh
Builds with xcodebuild (ad-hoc signed) into build/ and launches the menu bar
app. Requires macOS 14+.
Or in Xcode:
open murmur.xcodeproj # ⌘R
- A real
NSMenuon a realNSStatusItem— so it behaves like every other menu bar item, including holding the menu bar open inside another app's fullscreen. Native checkmarks, native ⌘, and ⌘Q. The volume slider lives in anNSMenuItem's custom view, which is somethingNSMenuallows and SwiftUI's menu bridge does not. - The checkmark is the play state, not a stored selection — the tick sits next to whatever is actually sounding, and a dash means it's still downloading. So picking a cafe starts it, and picking the one already playing stops it. There's an explicit Play/Stop at the top of the menu too, since that gesture is something you'd have to know rather than discover.
- Settings (⌘,) holds launch-at-login, auto-play, update checks and the audio
credits — so the dropdown stays a thing you use rather than a thing you
configure. It's a hand-built
NSWindowhosting SwiftUI, because SwiftUI's ownSettingsscene can't reliably be opened from an app with no menus. - Scenes are downloaded on first play and cached in the app's sandbox container, pinned by SHA-256 — which is re-checked on every play, so a truncated file repairs itself. The app itself ships with no audio.
- Gapless looping straight off disk.
scheduleFileis queued twice and re-armed on each.dataConsumedcallback, so memory stays flat instead of holding a whole recording as PCM. - The loop seam is baked into the file, not crossfaded at runtime:
tools/prep-scene.shlays a recording's head over its own tail, so wrapping to frame 0 is already smooth. - The room is the node graph —
AVAudioUnitEQ→AVAudioUnitReverb, with a pink-noiseAVAudioSourceNodefor the street. Seat changes are parameter writes, so they take effect instantly and without a click. - One
PlaybackStateenum is the single source of truth for the UI, bridged into AppKit withwithObservationTracking. - Native macOS. No dependencies, no Electron.
tools/screen-candidate.sh raw-recording.flac --window 300
tools/prep-scene.sh raw-recording.flac cafe.m4a --start 35 --duration 300
The screener reports whether a recording is a usable bed — how much of its energy
is chatter, how steady it is, how often something jumps out — and finds the calmest
stretch, printing the prep-scene.sh line for it. The prep step trims, high-passes
away handling noise, normalises to −23 LUFS so it sits under whatever else you're
listening to, crossfades the loop seam, encodes AAC, and prints the SHA-256 to
paste into Scene.swift. Sources and licences go in CREDITS.md.
The room DSP can be measured rather than guessed at:
swiftc -O murmur/RoomDSP.swift tools/render-seats.swift -o /tmp/render-seats
/tmp/render-seats cafe.m4a /tmp/out
renders eight seconds per seat offline through the app's real graph. See AGENT.md for what the numbers should look like.
MIT for the code. The cafe recordings are public domain and credited separately in CREDITS.md.
