Tracking BPM and Beats

Beat Packets

For some time before this analysis was written, Afterglow was able to synchronize its light shows with music being played on Pioneer equipment by observing packets broadcast by the mixer to port 50001.

Using just that approach, however, it was not possible to tell which player was the master, so there was no way to determine the down beat (the start of each measure). Now that it is possible to to determine which CDJ is the master player using the CDJ status packets, these beat packets have become far more useful, and Afterglow now uses Beat Link, the library that resulted from this analysis, to track the down beat based on the beat number reported by the master player.

To track beats, open a socket and bind it to port 50001. The devices seem to broadcast two different kinds of packets to this port, a shorter packet containing 2d bytes of data, and a longer packet containing 60 bytes. The shorter packets contain information about which channels are on-air, and fader start/stop commands to the players.

The 60-byte packets are sent on each beat, so even the arrival of the packet is interesting information, it means that the player is starting a new beat. (CDJs send these packets only when they are playing and only for rekordbox-analyzed tracks. The mixer sends them all the time, acting as a backup metronome when no other device is counting beats.) These packets have the following structure:

0123456789abcdef5173707431576d4a4f4c280010Device Name (padded with 00)012000DlenrnextBeat2ndBeatnextBar304thBeat2ndBar8thBeatffffffff40ffffffffffffffffffffffffffffffff50ffffffffPitch0000BPMBb0000D
Beat packet.

This introduces our first packet structure variant around the device name. The packet header ends immediately after the packet type indicator in byte 0a, so the device name begins one byte earlier at byte 0b (this byte had the value 00 in the startup packets). As always, the byte after the name has the value 01, but the subtype value which follows that (at byte 20) has the value 00 here, rather than 02 as we saw in the startup packets. In packets of subtype 00 the subtype indicator is followed by the Device Number D at byte 21; this is the Player Number as displayed on the CDJ itself, or 21 for the mixer, or another value for a computer running rekordbox. And that is followed by a different kind of length indicator: lenr at bytes 22-23 reports the length of the rest of the packet, in other words, the number of bytes which come after lenr. In this packet lenr has the value 003c. For some reason, there is a redundant copy of D at the end of the packet, in byte 5f. That seems common in packets with subtype 00, and is one of many inefficiencies in the protocol.

To facilitate synchronization of variable-tempo tracks, the number of milliseconds after which a variety of upcoming beats will occur are reported.

The timing values for all these upcoming beats are always reported as if the track was being played at normal speed, with a pitch adjustment of 0%. If a pitch adjustment is in effect, you will need to perform the calculation to scale the beat timing values yourself.

nextBeat at bytes 24-27 is the number of milliseconds in which the very next beat will arrive. 2ndBeat (bytes 28-2b) is the number of milliseconds until the beat after that. nextBar (bytes 2c-2f) reports the number of milliseconds until the next measure of music begins, which may be from 1 to 4 beats away. 4thBeat (bytes 30-33) reports how many milliseconds will elapse until the fourth upcoming beat; 2ndBar (bytes 34-37) the interval until the second measure after the current one begins (which will occur in 5 to 8 beats, depending how far into the current measure we have reached); and 8thBeat (bytes 38-3b) tells how many millieconds we have to wait until the eighth upcoming beat will arrive.

The player’s current pitch adjustment[1] can be found in bytes 5457, labeled Pitch. It represents a four-byte pitch adjustment percentage, where 0x00100000 represents no adjustment (0%), 0x00000000 represents slowing all the way to a complete stop (−100%, reachable only in Wide tempo mode), and 0x00200000 represents playing at double speed (+100%).

The pitch adjustment percentage represented by Pitch is calculated by multipyling the following (hexadecimal) equation by decimal 100:

The current BPM of the track playing on the device[2] can be found at bytes 5a-5b (labeled BPM). It is a two-byte integer representing one hundred times the current track BPM. So, the current track BPM value to two decimal places can be calculated as (in this case only the byte offsets are hexadecimal):

In order to obtain the actual playing BPM (the value shown in the BPM display), this value must be multiplied by the current pitch adjustment. Since calculating the effective BPM reported by a CDJ is a common operation, here a simplified hexadecimal equation that results in the effective BPM to two decimal places, by combinining the BPM and Pitch values:[3]

The counter Bb at byte 5c counts out the beat within each bar, cycling 1 → 2 → 3 → 4 repeatedly, and can be used to identify the down beat if it is coming from the master player (and if the DJ has properly established the track’s beat grid).

1. The mixer always reports a pitch of +0%.
2. The mixer passes along the BPM of the master player.
3. Since the mixer always reports a pitch adjustment of +0%, its BPM value can be used directly without this additional step.