Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f47ca29
chore: drop Windows/Linux builds, focus on the native macOS app
flotttt Sep 10, 2026
663ff70
Merge pull request #1 from flotttt/chore/macos-only
flotttt Sep 10, 2026
4047d24
feat(macos): French localization (fr + en fallback)
flotttt Sep 10, 2026
b646cf7
Merge pull request #2 from flotttt/feat/trad
flotttt Sep 10, 2026
1da9d58
docs: menu bar app design spec
flotttt Sep 10, 2026
9e8a1d1
docs: menu bar app implementation plan
flotttt Sep 10, 2026
cdae371
feat(macos): menu bar agent app built with make (drop Xcode project a…
flotttt Sep 10, 2026
02ac559
test: reconnect/poll-guard/throttle logic, localization check, make test
flotttt Sep 10, 2026
886ba74
fix(xm6): read NC/ASM state on channel 0x19, decode 10-band equalizer…
flotttt Sep 10, 2026
b5e6228
fix(xm6): read NC/ASM state on channel 0x19, decode 10-band equalizer…
flotttt Sep 10, 2026
bdb2881
refactor(macos): menu-oriented HeadphonesModel (connection state, com…
flotttt Sep 10, 2026
f19743c
fix(bt): wait for the real ACK, ACK MDR_NO2 frames, keep 1-bit sequen…
flotttt Sep 10, 2026
06e6325
feat(macos): SwiftUI menu rows (header, level slider, switches, equal…
flotttt Sep 10, 2026
e0beefb
feat(macos): full headphones menu with per-mode status icon
flotttt Sep 10, 2026
cda1c3e
fix(build): make run launches via open --args; sandboxed app logs to …
flotttt Sep 11, 2026
cb877f7
fix(macos): menu layout (widths, insets, short values), EQ row height…
flotttt Sep 11, 2026
fd905d6
feat(macos): auto-connect, auto-reconnect and launch at login (menu o…
flotttt Sep 11, 2026
00fc2f7
add new shared
flotttt Sep 11, 2026
a32b3dd
Merge pull request #3 from flotttt/feat/settings
flotttt Sep 11, 2026
2aceb82
docs(readme): XM6 verified, drop release/stars badges, build-from-sou…
flotttt Sep 11, 2026
23ec865
add
flotttt Sep 11, 2026
d5680b4
Merge pull request #4 from flotttt/feat/parti8
flotttt Sep 11, 2026
b36aa29
docs: notch + local Spotify design spec (step 1)
flotttt Sep 11, 2026
61cf297
docs: notch step 1 implementation plan
flotttt Sep 11, 2026
5840cef
feat(notch): notch geometry and resting-state logic
flotttt Sep 11, 2026
2d07acc
feat(music): pure playback logic (now playing, clock, Spotify parsing)
flotttt Sep 17, 2026
eed95e2
feat(music): local Spotify source, music controller and Show Notch op…
flotttt Sep 17, 2026
d6613e4
feat(notch): notch panel with resting states and hover to open
flotttt Sep 17, 2026
e7226e5
feat(notch): headphones tab
flotttt Sep 17, 2026
2e18460
feat(notch): music player and headphones
flotttt Sep 17, 2026
e6d70d4
feat(notch): resting music control, notch
flotttt Sep 17, 2026
1305ccc
Merge pull request #5 from flotttt/feat/notch
flotttt Sep 17, 2026
4f758f1
chore: rename to SonyNotch, automatic releases, README rewrite
flotttt Sep 17, 2026
e9ed5b4
Merge pull request #6 from flotttt/feat/release
flotttt Sep 17, 2026
3c43394
add realese
flotttt Sep 17, 2026
8da50bc
docs: user-first README
flotttt Sep 17, 2026
ce02468
fix(notch): centre the playback controls, remove shuffle
flotttt Sep 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: macOS

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Test
run: make test
- name: Build (release, universal)
run: make release
- uses: actions/upload-artifact@v4
with:
name: SonyNotch-macOS
path: build/SonyNotch.zip
72 changes: 0 additions & 72 deletions .github/workflows/cmake.yml

This file was deleted.

50 changes: 50 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Release

# Push a version tag to publish a release:
# git tag v1.0.0 && git push origin v1.0.0
# The app gets its version from the tag, is tested and built for Apple Silicon and Intel, and the zip is attached
# to a GitHub release with its SHA-256 (used by the Homebrew cask).

on:
push:
tags: ["v*.*.*"]

permissions:
contents: write

jobs:
release:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4

- name: Set the app version from the tag
run: |
VERSION="${GITHUB_REF_NAME#v}"
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION" Client/macos/info.plist
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${{ github.run_number }}" Client/macos/info.plist

- name: Test
run: make test

- name: Build (release, universal)
run: make release

- name: Checksum
run: |
cd build
shasum -a 256 SonyNotch.zip | tee SonyNotch.zip.sha256

# A release already made by hand for this tag (title and notes written on GitHub) only gets the files.
- name: Publish the release
env:
GH_TOKEN: ${{ github.token }}
run: |
if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then
gh release upload "$GITHUB_REF_NAME" build/SonyNotch.zip build/SonyNotch.zip.sha256 --clobber
else
gh release create "$GITHUB_REF_NAME" build/SonyNotch.zip build/SonyNotch.zip.sha256 \
--title "SonyNotch $VERSION" \
--generate-notes
fi
55 changes: 0 additions & 55 deletions .github/workflows/xcodebuild.yml

This file was deleted.

5 changes: 2 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -523,10 +523,9 @@ MigrationBackup/
.ionide/

# End of https://www.toptal.com/developers/gitignore/api/c++,visualstudio,python
Client/imgui.ini

# vscode
.vscode/

# linux build
Client/linux/sonyheadphonesclient.build/
# brainstorming mockups (superpowers visual companion)
.superpowers/
3 changes: 0 additions & 3 deletions .gitmodules

This file was deleted.

30 changes: 23 additions & 7 deletions Client/BluetoothWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ BluetoothWrapper& BluetoothWrapper::operator=(BluetoothWrapper&& other) noexcept
int BluetoothWrapper::sendCommand(const std::vector<char>& bytes)
{
std::lock_guard guard(this->_connectorMtx);
auto data = CommandSerializer::packageDataForBt(bytes, DATA_TYPE::DATA_MDR, this->_seqNumber++);
// Use the current seq, don't advance it here: the next seq comes from the device's ACK
// (_waitForAck), so if this frame goes unanswered its seq is simply reused on the next call.
auto data = CommandSerializer::packageDataForBt(bytes, DATA_TYPE::DATA_MDR, this->_seqNumber);
auto bytesSent = this->_connector->send(data.data(), data.size());

this->_waitForAck();
Expand Down Expand Up @@ -68,7 +70,9 @@ SonyProtocolVersion BluetoothWrapper::getProtocolVersion() noexcept
Buffer BluetoothWrapper::sendCommandAndReadResponse(const std::vector<char>& bytes, unsigned char retCommandId, int retSubType)
{
std::lock_guard guard(this->_connectorMtx);
auto data = CommandSerializer::packageDataForBt(bytes, DATA_TYPE::DATA_MDR, this->_seqNumber++);
// Use the current seq, don't advance it here: the next seq comes from the device's ACK
// (handled below), so if this frame goes unanswered its seq is simply reused on the next call.
auto data = CommandSerializer::packageDataForBt(bytes, DATA_TYPE::DATA_MDR, this->_seqNumber);
this->_connector->send(data.data(), data.size());

// The device replies with an ACK and then the RET frame; unrelated notifications may interleave.
Expand All @@ -92,8 +96,19 @@ Buffer BluetoothWrapper::sendCommandAndReadResponse(const std::vector<char>& byt

void BluetoothWrapper::_waitForAck()
{
auto msg = this->_readMessage();
this->_seqNumber = msg.seqNumber;
// The device may send its own DATA_MDR notifications (already ACKed inside _readMessage) before
// the ACK for our frame arrives; skip those and keep reading until we see the actual ACK, so
// _seqNumber never gets set from an unrelated message's seq.
for (int i = 0; i < 16; i++)
{
auto msg = this->_readMessage();
if (msg.dataType == DATA_TYPE::ACK)
{
this->_seqNumber = msg.seqNumber;
return;
}
}
throw RecoverableException("No ACK received from device", true);
}

CommandSerializer::Message BluetoothWrapper::_readMessage()
Expand Down Expand Up @@ -150,9 +165,10 @@ CommandSerializer::Message BluetoothWrapper::_readMessage()

auto msg = CommandSerializer::unpackBtMessage(msgBytes);

// The device retransmits any DATA_MDR frame it sends until the host ACKs it. The ack carries the
// toggled 1-bit sequence number (1 - deviceSeq), matching the device's own ack-to-us behaviour.
if (msg.dataType == DATA_TYPE::DATA_MDR)
// The device retransmits any DATA_MDR or DATA_MDR_NO2 frame it sends until the host ACKs it (e.g.
// slider drags are echoed as DATA_MDR_NO2). The ack carries the toggled 1-bit sequence number
// (1 - deviceSeq), matching the device's own ack-to-us behaviour.
if (msg.dataType == DATA_TYPE::DATA_MDR || msg.dataType == DATA_TYPE::DATA_MDR_NO2)
{
auto ack = CommandSerializer::packageDataForBt({}, DATA_TYPE::ACK, (unsigned char)(1 - msg.seqNumber));
this->_connector->send(ack.data(), ack.size());
Expand Down
112 changes: 0 additions & 112 deletions Client/CMakeLists.txt

This file was deleted.

Loading