-1

I have a uint32_t as follows:

uint32_t midiData=0x9FCC00;

I need to separate this uint32_t into smaller parts so that 9 becomes its own entity, F becomes its own entity, and CC becomes its own entity. If you're wondering what I am doing, I am trying to break up the parts of a MIDI message so that they are easier to manage in my program.

I found this solution, but the problem is I don't know how to apply it to the CC section, and that I am not sure that this method works with C++.

Here is what I have so far:

uint32_t midiData=0x9FCC00;

uint32_t status = 0x0FFFFF & midiData; // Retrieve 9
uint32_t channel = (0xF0FFFF & midiData)>>4; //Retrieve F
uint32_t note = (0xFF00FF & midiData) >> 8; //Retrieve CC

Is this correct for C++? Reason I ask is cause I have never used C++ before and its syntax of using the > and < has always confused me (thus why I tend to avoid it).

Community
  • 1
  • 1
Midimistro
  • 315
  • 2
  • 12

3 Answers3

1

You can use bit shift operator >> and bit masking operator & in C++ as well. There are, however, some issues on how you use it:

Operator v1 & v2 gives a number built from those bits that are set in both v1 and v2, such that, for example, 0x12 & 0xF0 gives 0x10, not 0x02. Further, bit shift operator takes the number of bits, and a single digit in a hex number (which is usually called a nibble), consists of 4 bits (0x0..0xF requires 4 bits). So, if you have 0x12 and want to get 0x01, you have to write 0x12 >>4. Hence, your shifts need to be adapted, too:

#define BITS_OF_A_NIBBLE 4

unsigned char status = (midiData & 0x00F00000) >> (5*BITS_OF_A_NIBBLE);
unsigned char channel = (midiData & 0x000F0000) >> (4*BITS_OF_A_NIBBLE);
unsigned char note = (midiData & 0x0000FF00) >> (2*BITS_OF_A_NIBBLE);
unsigned char theRest = (midiData & 0x000000FF);
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
  • This works exactly how I need it, I just need it using uint8_t, uint16_t, or uint32_t. Will it work the same for a uint<#>_t? – Midimistro May 02 '17 at 18:30
  • Yes, as long as you take care not to shift more bits than the respective data type provides, and as long as you do not assign a to large value; i.e. `uint8_t x = (midiData & 0xFF000000) >> 4` is a problem as the result of the RHS does not fit into a 8 bit value, and `uint8_t y = 0xFF;y >> 10` is a problem since you shift more bits than the `y` has. – Stephan Lechner May 04 '17 at 08:44
0

You have it backwards, in a way.

In boolean logic (the & is a bitwise-AND), ANDing something with 0 will exclude it. Knowing that F in hex is 1111 in binary, a line like 0x9FCC00 & 0x0FFFFF will give you all the hex digits EXCEPT the 9, the opposite of what you want.

So, for status:

uint32_t status = 0xF000000 & midiData; // Retrieve 9

Actually, this will give you 0x900000. If you want 0x9 (also 9 in decimal), you need to bitshift the result over.

Now, the right bitshift operator (say, X >> 4) means move X 4 bits to the right; dividing by 16. That is 4 bits, not 4 hex digits. 1 hex digit == 4 bits, so to get 9 from 0x900000, you need 0x900000 >> 20.

So, to put them together, to get a status of 9:

uint32_t status = (0xF000000 & midiData) >> 20;

A similar process will get you the remaining values you want.

Phil M
  • 1,619
  • 1
  • 8
  • 10
0

In general I'd recommend shift first, then mask - it's less error prone:

uint8_t cmd = (midiData >> 16) & 0xff;
uint8_t note = (midiData >> 8) & 0x7f;     // MSB can't be set
uint8_t velocity = (midiData >> 0) & 0x7f; // ditto

and then split the cmd variable:

uint8_t status = (cmd & 0xf0);             // range 0x00 .. 0xf0
uint8_t channel = (cmd & 0x0f);            // range 0 .. 15

I personally wouldn't bother mapping the status value back into the range 0 .. 15 - it's commonly understood that e.g. 0x90 is a "note on", and not the plain value 9.

Alnitak
  • 334,560
  • 70
  • 407
  • 495