Momentum Menu

A macOS menu bar app for the Sennheiser MOMENTUM 4.

Charging: a green bolt in the ring, a Charging pill beside aptX at 44.1 kHz, Also on iPhone, and Adaptive noise control.
Charging

Noise control off, and the Headphone row open: touch controls, on-head detection, Smart Pause, auto-answer and Comfort Calls.
Headphone settings
The paired devices open under the battery: iPhone connected, this Mac, and iPad with Connect dimmed because both slots are taken.
Paired devices

The Settings window: launch at login, menu bar options, the app icon picker, a type for each paired device, and About.
Settings
Custom noise control with the level slider and anti-wind on Auto, and the five equaliser band sliders open.
Equaliser bands

Disconnected: this Mac has let go of the headphones, with Reconnect and Quit.
Disconnected

Caution

Unofficial, reverse-engineered, and not notarised. Use it at your own risk.

Download

Releases carry a DMG built by GitHub Actions from the tagged commit, with a build provenance attestation and a SHA-256 file. Needs macOS 26 on Apple silicon.

gh attestation verify MomentumMenu-*.dmg -R agrmohit/momentum-menu

The app is ad hoc signed, not notarised, so macOS blocks its first launch whatever the attestation says. Open it once, then choose Open Anyway in System Settings > Privacy & Security, or run xattr -dr com.apple.quarantine /Applications/MomentumMenu.app.

Build and run

Needs macOS 26 and Xcode 26 (the Command Line Tools lack the SwiftUI macro plugin and XCTest).

make install    # builds, signs ad hoc, installs to ~/Applications
make check      # clean build with warnings as errors, then the tests; what CI runs
make            # every target and variable

Protocol notes

GAIA v3 frames start FF 03 00 LL, then the vendor (0x0495) and the command id. The feature is command >> 9.

WhatIdsNotes
Subscribe0x0007The device pushes nothing for a feature until it is registered. The app registers battery, ANC, EQ, transparency, audio (feature 4) and device management (feature 10).
Battery0x0603Steps of 10 only. HFP and Qualcomm's 001D:1A01 give the same steps, so finer is not possible.
Codec0x0800 read, 0x0880 pushOne byte, Smart Control's enum: 0 SBC, 1 AAC, 2 aptX, 3 aptX LL, 5 aptX HD, 8 aptX Adaptive, 9 aptX Lossless, 10 LC3, FF none. 11 is seen but unexplained.
Sample rate0x089A pushu32 big-endian Hz. Covers whichever device is streaming.
Noise mode table0x1A00Adaptive is written as an [id, value] pair, or the whole table where the pair is rejected; anti-wind always as the whole table. A write can reset the level, so the app skips no-op writes and reads the level back after the rest.
EQ and bass boost0x10xxFirmware 3.x only; 2.x rejects them with 0x05.
Paired devices0x1400-0x1409, 0x1484 pushCount, own index, limit (2), then [index, priority, connected, name, 00] per index. Addressed by index only, and indexes can reorder, so the list is re-read before any connect (0x1402) or disconnect (0x1403).

Safety lives in Commands.swift:

Credits

Not affiliated with Sennheiser or Sonova.

License

MIT