Repository navigation
Releases
v1.0.3 — confirmed on hardware
What's new
The 1.0.2 fix is now confirmed on real hardware. Everything before this was
graded against Windows captures replayed offline. The V7 became available, so
the parser could finally be measured against the device — with a second process
subscribed to the CoreMIDI source, so the numbers are what a DJ application
actually receives rather than what OpenV7 believes it sent.
30 seconds of real scratching: 27,453 USB frames in, 52,572 MIDI messages
out, 22,137 position updates, and zero undecidable steps. Audibly hiccup-free
in VirtualDJ on two separate Apple Silicon Macs.
No bridge changes in this release. The parser fix shipped in 1.0.2 and is
unaltered. If you are already on 1.0.2, this is a test, docs, and icon release.
make corpus gates on frames swallowed
A new regression signal: frames that demonstrably arrived and produced no
position update. Unlike a timing gap it cannot be explained away by the device
idling or the capture pausing — the frames are known to have arrived.
| corpus | with the fix | with the 1.0.1 parser |
|---|---|---|
| steady rotation | 4 | 725 |
| scratching | 10 | 4,035 |
Verified in both directions. A gate that cannot fail is not a gate.
Two corrected claims
The docs said the platter counter carries ~20× headroom before its 64-count
ambiguity can fire; the test said ~6×. Both figures came from captures where
the motor drove the platter — smooth and bounded. A hand is not. Real
scratching produced a worst step of 35 counts, so the true margin is
~1.8×. Steps ≥64 were still zero, so the conclusion holds, but the old
numbers invited assuming slack that isn't there.
Two protocol facts only hardware could show
- The
0xE0timestamp pairs 1:1 across both decks. Subtracting the 22,137
deck-A positions from 26,261 timestamps implies 4,124 deck-B positions, which
the measured "other" bucket of 4,174 covers with 50 to spare. Those 50 are
inferred to be button traffic, not measured — the docs say so. No single-deck
capture could have revealed any of this. - The control endpoint is event-driven, not free-running. Untouched, the
deck sends nothing at all; it resumes at ~1000 frames/s on contact. This also
explains the 11.4 s hole in one of the tracked captures — an idle deck, not
lost frames.
Red icon
The app icon moves from blue to red.
Install
macOS 13.0+, Apple Silicon. Unsigned, so the first launch is blocked: approve
once in System Settings ▸ Privacy & Security ▸ Open Anyway. Control-click ▸
Open was removed in macOS 15 and no longer works.
Start OpenV7 before your DJ software — VirtualDJ enumerates MIDI sources at
launch only, and will not see the bridge if it starts first.
Still open
VirtualDJ on macOS binds to Numark V7 correctly for input, but does not drive
the platter motor. That is unexplained and unchanged in this release.
OpenV7 v1.0.2 — the platter jitter is fixed
The V7's motorized platter made VirtualDJ's audio hiccup on Apple Silicon. The cause is fixed, and it turned out to be in OpenV7's own MIDI parser rather than in the deck.
What was wrong
midi_feed reset its parser state after every run of 0xFD padding, treating each 42-byte USB frame as a self-contained message container. It isn't — it's a transport container. Against a capture of the stock Ploytec driver on Windows, where VirtualDJ has no hiccups, 11.7% of frames begin part-way through a message the previous frame started. Every one of those was discarded.
| positions | timestamps | largest step | undecidable steps | |
|---|---|---|---|---|
| 1.0.1 | 11,416 | 11,413 | 64 | 2 |
| 1.0.2 | 12,124 | 12,124 | 3 | 0 |
Those last two columns are the symptom. The old parser reported platter steps of 64 counts — the point where a 7-bit counter becomes genuinely undecidable — from a deck whose real maximum step is 3. Each one moved the playhead by up to a third of a revolution. That is what you were hearing.
5.8% of the platter stream was being thrown away, from a capture with zero USB loss.
Also fixed
- Stall recovery. A permanently stalled control pipe used to report "connected" forever while delivering nothing. It now resets the device and relaunches. Plus a fix for that detector firing on an idle deck.
- Frame terminator no longer parsed as MIDI (it fabricated a message after every 2-byte one).
--replay FILE— play a recorded capture into CoreMIDI with no hardware attached.--legacy-parserestores the old behaviour for A/B testing.--diag-jogno longer reports a stopped-and-restarted platter as multi-second jitter, and its implied-clock figure now divides by the window that actually elapsed.
Verification
make corpus grades the parser against 80,839 real frames captured from the vendor driver — 12,161 of steady rotation and 68,678 taken while VirtualDJ played and scratched. It runs in CI.
Measured, not yet heard: the numbers are reproducible offline, but nobody has confirmed by ear that they account for the whole symptom. Feedback welcome.
Install
Requires macOS 13.0+, Apple Silicon. Drag OpenV7 to Applications.
First launch is blocked — the app isn't notarized. Approve once in System Settings ▸ Privacy & Security ▸ Open Anyway. (Control-click ▸ Open was removed in macOS 15.)
Full detail in docs/PROTOCOL.md.
OpenV7 v1.0.1 — fixes "can't use this version of the application"
If you downloaded v1.0.0 and it refused to open, this is the fix. Replace the app with this build.
The bug
v1.0.0's binaries were stamped with the build machine's macOS version, not the one the app claims to support:
v1.0.0 minos 27.0 sdk 27.0 (Info.plist advertised macOS 13.0)
v1.0.1 minos 13.0 sdk 26.5
A Mach-O records two versions, and both gate launch — a floor (minos) and the SDK it was built against — while LSMinimumSystemVersion in the plist is a third, independent claim. v1.0.0 promised macOS 13 and shipped binaries that demanded macOS 27, so on every other Mac it failed with "You can't use this version of the application with this version of macOS". That reads like a corrupt download; it wasn't.
The cause: bare clang does not use the SDK xcrun reports — it resolves to the Command Line Tools SDK, which on a machine running a macOS seed is the seed's SDK. The build now pins the SDK, refuses to use one from an unreleased major, and verifies the stamps on the built artifact before packaging. Both bypass routes are covered by negative tests.
Install (no Terminal)
- Download OpenV7.dmg below.
- Open it and drag OpenV7 to Applications.
- Double-click OpenV7. macOS blocks it once (this build is ad-hoc signed, not notarized): approve it in System Settings ▸ Privacy & Security, scroll to Security, then Open Anyway.
Control-click ▸ Open no longer works — Apple removed that override in macOS 15 Sequoia. - A ◉ V7 menu-bar icon appears. Plug in the V7 — it shows connected.
- Optional: menu ▸ Open at Login.
Then open your DJ app (VirtualDJ, Mixxx, …) and select Numark V7 as a MIDI controller.
Requirements
macOS 13.0 or later, Apple Silicon. Self-contained — libusb is bundled, nothing else to install.
Unchanged from v1.0.0
- Full control surface in as MIDI (jog, buttons, faders)
- Motor and LEDs out (platter spins on command)
- Native audio (the V7's built-in 4-out soundcard) is still not implemented — use any other audio output for now; it's on the roadmap.
Verify your download
shasum -a 256 -c SHA256SUMS.txtReverse-engineered clean-room for interoperability; not affiliated with Numark/inMusic.
OpenV7 v1.0.0 — Numark V7 on Apple Silicon
First release. Brings the discontinued Numark V7 back to life on modern macOS
(Apple Silicon) with no kext and no vendor driver.
Install (no Terminal)
- Download OpenV7.dmg below.
- Open it and drag OpenV7 to Applications.
- Double-click OpenV7 (first launch: right-click ▸ Open ▸ Open).
- A ◉ V7 menu-bar icon appears. Plug in the V7 — it shows connected.
- Optional: menu ▸ Open at Login.
Then open your DJ app (VirtualDJ, Mixxx, …) and select Numark V7 as a MIDI controller.
What works
- Full control surface in as MIDI (jog, buttons, faders)
- Motor and LEDs out (platter spins on command)
- Self-contained — libusb bundled, nothing else to install
Not yet
- Native audio (the V7's built-in 4-out soundcard) — use any other audio
output for now; it's on the roadmap.
See the README and docs/PROTOCOL.md for details. Reverse-engineered clean-room
for interoperability; not affiliated with Numark/inMusic.