3

I'm sending MIDI messages to a proprietary turntable that has an LCD screen on it. The normal software sends out updates via MIDI SysEx to display the current tempo on the LCD. The MIDI is being received on a MKL25Z128VLK4, Cortex-M0+/ARMv6-M device. (I did disassemble the firmware .bin after digging in its guts for the type of chip it's using, but the result of that was ~30k lines of assembly) The LCD model number is inaccessible without desoldering

At this point, I can successfully update the screen but I'm having trouble figuring out the pattern from a given number and I'm hoping someone else has experience with this.

Here's what I have found so far:

Setting a single byte to anything from 9-126 results in 00.0

  BPM   B1    B2    B3    B4
 00.0   0     0     0     0
 00.0   0     0     0     1
 00.0   0     0     0     2
 00.0   0     0     0     3
 00.0   0     0     0     4
 00.0   0     0     0     5
 00.0   0     0     0     6
 00.0   0     0     0     7
 00.0   0     0     0     8
 00.0   0     0     0    16
 00.0   0     0     0    32
 00.0   0     0     0    64
 00.1   0     0     0   127
 00.1   0     0     1     0
 00.3   0     0     2     0
 00.4   0     0     3     0
 00.6   0     0     4     0
 00.8   0     0     5     0
 00.9   0     0     6     0
 01.1   0     0     7     0
 01.2   0     0     8     0
 00.0   0     0    16     0
 00.0   0     0    32     0
 00.0   0     0    64     0
 02.4   0     0   127     0
 02.5   0     1     0     0
 05.1   0     2     0     0
 07.6   0     3     0     0
 10.2   0     4     0     0
 12.8   0     5     0     0
 16.3   0     6     0     0
 17.9   0     7     0     0
 20.4   0     8     0     0
 00.0   0    16     0     0
 00.0   0    32     0     0
 00.0   0    64     0     0
 38.4   0   127     0     0
 40.9   1     0     0     0
 81.9   2     0     0     0
122.8   3     0     0     0
163.8   4     0     0     0
204.8   5     0     0     0
245.7   6     0     0     0
286.7   7     0     0     0
327.6   8     0     0     0
 00.0  16     0     0     0
 00.0  32     0     0     0
 00.0  64     0     0     0
614.4 127     0     0     0

Turning on multiple bytes adds them together with sometimes strange results

 40.9   1     0     0     0
 00.1   0     0     1     0
 41.1   1     0     1     0

 81.9   2     0     0     0
 00.1   0     0     1     0
 82.0   2     0     1     0

I'm wondering if there's some floating point or bitwise maths going on that I'm just not well versed in, and if so what are the real numbers and data types used for the calculations? I feel understanding this is crucial to solving this problem without a massive lookup table or gutting it and writing my own controller

  • What is the brand and model of the turntable? – Bavi_H May 30 at 10:57
  • Your table of byte values is not clear at all. Maybe just write out the full byte sequence for each display value? – Igor Skochinsky May 30 at 16:54
  • @Bavi_H Reloop RP-8000 (mk1 and mk2) – chason May 30 at 20:17
  • 1
    @IgorSkochinsky I struggled with that since Stack doesn't support tables. You're right, the full byte sequence is a lot clearer. I've updated the post for clarity and added a bunch of data points. Thanks – chason May 30 at 21:17
  • During your tests of setting only one byte to a non-zero value, are you sure that setting a particular byte to values from 9 to 126 results in a tempo of zero? Does 15 produce the same tempo that 127 does? (I suspect the tempo values will repeat in cycles of 16 values, meaning byte values 0-15, 16-31, 32-47, 48-63, 64-79, 80-95, 96-111, and 112-127 produce the same tempos.) – Bavi_H May 31 at 5:39
4

Binary

MIDI data bytes are 7 bits, meaning they can have decimal values from 0 to 127.

In a 7-bit binary number:

  • the bit on the right represents a decimal value of 1.
  • the next bit to the left represents a decimal value of 2.
  • the next bits to the left represent decimal values of 4, 8, 16, 32, and 64.

Decimal values from 0 to 127 can be expressed in seven bits, where each bit is a 0 or 1.

binary   decimal
0000001  1 = 1
0000010  2 = 2
0000011  3 = 2 + 1
0000100  4 = 4
0000101  5 = 4 + 1
0000110  6 = 4 + 2
0000111  7 = 4 + 2 + 1
0001000  8 = 8
0001001  9 = 8 + 1
...
1111111  127 = 64 + 32 + 16 + 8 + 4 + 2 + 1

Pattern

From the results you described, I suspect the turntable only cares about the lowest 4 bits in each byte. In other words, only the bits with decimal values of 1, 2, 4, and 8 will have an effect on the tempo display. This means only byte values 0 to 15 are useful.

I suspect the turntable is using the following pattern:

B1  B2  B3  B4  tempo  display
 0   0   0   0   .00     .0
 0   0   0   1   .01      "
 0   0   0   2   .02      "
 0   0   0   3   .03      "
 0   0   0   4   .04      "
 0   0   0   5   .05      "
 0   0   0   6   .06      "
 0   0   0   7   .07      "
 0   0   0   8   .08      "
 0   0   0   9   .09      "
 0   0   0  10   .10     .1
 0   0   0  11   .11      "
 0   0   0  12   .12      "
 0   0   0  13   .13      "
 0   0   0  14   .14      "
 0   0   0  15   .15      "
 0   0   1   0   .16      "
 0   0   1   1   .17      "
 0   0   1   2   .18      "
 0   0   1   3   .19      "
 0   0   1   4   .20     .2
...

The byte values represent tempo values in .01 units, but when the turntable displays the tempo, it hides the last digit.

This hidden digit explains why turning on multiple bytes doesn't always produce the sum of the tempos displayed by the individual byte values.

B1  B2  B3  B4  tempo  display
 1   0   0   0  40.96   40.9
 0   0   1   0    .16     .1
 1   0   1   0  41.12   41.1

Bitwise math

When only some bits are used, bitwise math is indeed useful.

For example, here's some Javascript to convert a tempo to the needed byte values:

t = 123.4;

v = 100 * t;

b1 = (v >> 12) & 15;
b2 = (v >> 8) & 15;
b3 = (v >> 4) & 15;
b4 = v & 15;

console.log(b1, b2, b3, b4);

x & 15 is a bitwise AND, in this case, to keep only the lowest four bits.

x >> 4 is a right shift, in this case shifting the value 4 bits to the right, which discards the lowest four bits. This has the same effect as dividing by 16 and discarding the remainder.

Here's some Javascript to convert the byte values to the displayed tempo:

b1 = 3;
b2 = 0;
b3 = 3;
b4 = 4;

b1 = b1 & 15;
b2 = b2 & 15;
b3 = b3 & 15;
b4 = b4 & 15;

v = 16*16*16*b1 + 16*16*b2 + 16*b3 + b4;

t = parseInt(v / 10) / 10;

console.log(t);

In your web browser, you can go to about:blank, then press F12 and go to Console to enter these small Javascript calculations. (For your safety, enter about:blank in the address box, and never run code from strangers if you don't understand it.)

| improve this answer | |
  • "I would suggest turning on each bit individually and see what tempo value is displayed. " Sorry if I wasn't clear, I definitely did that. Byte 3, for example: 0 comes out as 0 on the display. 1 is 2.5, 2 is 5.1, 3 is 7.6, 4 is 10.2, 5 is 10.2, 6 is 12.8. So it seems that the value is 2.5 and the tempo shown is byte * 2.5.... with some weird rounding errors I can't figure out I forgot about the splitting bytes thing, I've had to deal with that before. Total pain in the butt – chason May 30 at 9:18
  • I see. I don't know of a special pattern that could explain your results. If you want look for a pattern on your own, other ideas I would try if you have all the values written down: try plotting a graph, try calculating the difference from one tempo to the next and look for patterns in the differences, try calculating the multiplication factor from one tempo to the next and look for patterns in the multiplication factors. If you want help looking for patterns, what happens for data byte values of 8, 16, 32 and 64? (Or even, what are all the data values and resulting tempos you have gathered?) – Bavi_H May 30 at 10:57
  • I did some more point gathering today and re-formatted and updated the post. Anything from 9-126 shows a 00.0 which made creating the table a much less daunting task lol It's interesting that 127 is special somehow, I have no explanation for that – chason May 30 at 21:19
  • @chason Thanks for the update. I thought my proposed pattern was wrong after your comment which said for byte 3 (which you are now calling byte 2), value 4 causes tempo 10.2, and value 5 also causes tempo 10.2. But your updated question now shows for byte 2, value 4 causes tempo 10.2, and value 5 causes tempo 12.8. So I suspect my pattern may be right after all. I've edited my answer, hopefully it better explains the pattern I see. – Bavi_H May 31 at 8:56
  • "which you are now calling byte 2" Big oof. Too bad I can't edit the title of the post. The hidden digit explains a lot, I should have thought of that. Good call. Thanks for helping me work through it and for such a detailed answer. I wouldn't have made it without your help :) – chason Jun 1 at 0:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.