Repository navigation
dbserver: serve the CDJ's TRACK FILTER - #95
Merged
Merged
Conversation
2 tasks done
The deck's TRACK FILTER narrows its track lists by BPM, key, rating, colour and MyTag, and rekordbox does the filtering: the deck sends the conditions and rekordbox's TRACK list comes back narrowed. We acknowledged only 0x3007, ignored the rest, and filtered nothing, so the filter screen showed no settings and TRACK FILTER kept every track.
Decoded from real rekordbox captures of a CDJ-2000NXS2:
- 0x3007 [ctx, on] turns the filter on or off; 0x3207 [ctx, prop, 0, len, blob] sets one condition (little-endian: on, kind, u16 count, u32 values); 0x3107 [ctx] returns all four as 0x4004 [kind, 0, len, blob, 4], one big-endian FCND record each; 0x3307 and 0x3407 set the MyTag condition and its tags. Each player's settings are kept across sessions, and the 0x3107 replies match rekordbox's byte for byte.
- The deck works out each condition's values itself: a BPM range from the typed tempo and chosen percentage (126 at ±1% sends 12474-12726), and a key's related-key set as rekordbox key indices ("Am related" sends 8A, 8B, 7A, 9A). While the filter is on, the TRACK list at menu location 1 keeps tracks whose BPM lies within the range and whose key is in the set, as rekordbox's does. Against the captured library the counts match rekordbox's: 388 and 1441 for the two BPM ranges, 628 and 530 for the two key sets.
Library track rows now round BPM to hundredths, so a BPM like 124.74 isn't truncated just below a range's lower bound.
Rating, colour and MyTag conditions are stored and returned but don't narrow the list yet; their matching is still being decoded.
Decoded from real rekordbox captures of a CDJ-2000NXS2: - Rating [n, 0] keeps tracks rated exactly n stars: 5, 4, 2 and 1 star kept 2, 5, 3 and 0 tracks, as many as the captured library has at each rating. - Colour is a bitmask of colours, bit colour-1 (yellow, colour 4, is sent as 8; red, colour 2, as 2), and a zero mask, sent when no colour is chosen, keeps every track. Yellow and red kept 3 each, matching the library. Track rows now carry the track's rating for the filter.
…e session
Ticking a TRACK FILTER condition on a CDJ-2000NXS2 against Vynull unticked it straight away. The deck's 0x3207 sends its condition blob as a trailing binary argument, and the reader only waits for one on 0x2705 and 0x2805 (other requests advertise one they never send). So 0x3207 was answered without its condition, the blob bytes were then read as the start of a new message ("unexpected byte 0x14"), the session dropped, and the deck, reconnecting, unticked the filter. The reader now waits for 0x3207's blob too.
The deck's TRACK FILTER can also narrow track lists by MyTags, per MyTag column with an AND or OR mode. Decoded from a real rekordbox capture of a CDJ-2000NXS2: - 0x1015 [ctx, sort, parent, 0] lists the MyTag screen: parent 0 gives the columns, any other parent that column's tags, leaving out tags no track carries (rekordbox listed 22 of a column's 24 tags, the two unused ones missing). Rows are [0, id, len, name, 2, "", type, 0, mode, index]: type 0x4b marks a column whose condition is on or a ticked tag, 0x4a otherwise, and a column row carries its mode (0x10 AND, 0x11 OR) in argument 8. We didn't handle 0x1015, so the screen was empty and there was nothing to tick. - 0x3307 [ctx, 0, column, on, mode] turns a column's condition on or off with its mode; 0x3407 [ctx, 0, column, tag, add] ticks or unticks a tag. - While the filter is on, each column whose condition is on keeps tracks carrying all its ticked tags (AND) or any of them (OR). The captured sequence (Trap, Trap and Deep House, Deep House, then OR, then AND) kept 1, 0, 26, 26, 27 and 0 tracks, which the tests reproduce on a smaller library. The dbserver reads the tag store through a new MyTagSource, wired in main.go; categories are the columns, in rekordbox's order after an import.
vynulldev
force-pushed
the
cdj-track-filter
branch
from
October 18, 2026 20:54
3631c21 to
5603297
Compare
vynulldev
marked this pull request as ready for review
October 18, 2026 21:17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
The deck's TRACK FILTER narrows its track lists by BPM, key, rating, colour and MyTag. With rekordbox, the deck sends the conditions and rekordbox does the filtering, so its TRACK list comes back narrowed. Against Vynull, ticking a condition unticked it straight away, the filter screen showed no settings, the MyTag screen was empty, and TRACK FILTER kept every track. link-spec only names these commands, so everything here is decoded from real rekordbox captures of a CDJ-2000NXS2 setting each condition.
Commands
0x3007 [ctx, on]turns the filter on or off.0x3207 [ctx, prop, 0, len, blob]sets one condition. The blob is little-endian: on, kind, u16 count, u32 values.0x3107 [ctx]returns all four conditions as0x4004 [kind, 0, len, blob, 4], one big-endianFCNDrecord each.0x1015 [ctx, sort, parent, 0]lists the MyTag screen: the MyTag columns, or a column's tags (only tags some track carries, as rekordbox lists them). Ticked rows are typed0x4b, the rest0x4a, and a column row carries its AND/OR mode.0x3307 [ctx, 0, column, on, mode]turns a column's MyTag condition on with mode0x10(AND) or0x11(OR).0x3407 [ctx, 0, column, tag, add]ticks or unticks a tag.Each player's settings are kept across sessions. The
0x3107replies and the MyTag screen rows match rekordbox's byte for byte, checked against the captures.Filtering (the TRACK list at menu location 1, while the filter is on, as rekordbox does)
[n, 0]keeps tracks rated exactly n stars.Against the captured library, Vynull's counts match rekordbox's for every capture: 388 and 1,441 for two BPM ranges (1,283 for a third), 628 and 530 for two key sets, 2/5/3/0 for 5/4/2/1 stars, 3 each for yellow and red, and 1, 0, 26, 26, 27, 0 through the MyTag sequence.
Fixes along the way
0x3207sends its condition blob as a trailing binary argument, which the reader didn't wait for. The blob was then read as a malformed message, the session dropped, and the deck unticked the filter. The reader now waits for it.MyTagSource, wired inmain.go.Tests replay the captured commands and check the replies byte for byte, the read of a real
0x3207frame, and each condition's filtering. Conformance against rekordbox 7.2.19 is unchanged (2,764 of 4,250); link-spec has no TRACK FILTER suites.Hardware testing
Checklist
go build ./...,go vet ./..., andgo test ./...passgofmt -l .is cleanGPL-3.0-or-later)