У меня есть uint32_t следующим образом:
uint32_t midiData=0x9FCC00;
Мне нужно разделить этот uint32_t на более мелкие части, так что 9 становится его собственной сущностью, F становится его собственной сущностью, а CC становится его собственной сущностью. Если вам интересно, что я делаю, я пытаюсь разбить части MIDI-сообщения, чтобы ими было легче управлять в моей программе.
я нашел это решение, но проблема в том, что я не знаю, как применить его к разделу CC, и что я не уверен, что этот метод работает с C ++.
Вот что у меня так далеко:
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
Это правильно для C ++? Причина, по которой я спрашиваю, заключается в том, что я никогда раньше не использовал C ++ и его синтаксис использования> и < всегда смущал меня (поэтому я стараюсь этого избегать).
Вы можете использовать оператор сдвига бит >>
и оператор битовой маскировки &
в C ++ также.
Есть, однако, некоторые вопросы о том, как вы его используете:
оператор v1 & v2
дает число, построенное из тех битов, которые установлены в обоих v1
а также v2
такой, что, например, 0x12 & 0xF0
дает 0x10
не 0x02
, Кроме того, оператор сдвига бит принимает количество битов, а одна цифра в шестнадцатеричном числе (которое обычно называется полубайтом) состоит из 4 битов (0x0..0xF требует 4 бита). Итак, если у вас есть 0x12
и хочу получить 0x01
, ты должен написать 0x12 >>4
,
Следовательно, ваши смены тоже должны быть адаптированы:
#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);
Вы имеете это задом наперед, в некотором смысле.
В булевой логике & является побитовым-И), И что-то с 0 исключит это. Знаю это F
в шестнадцатеричном виде 1111
в двоичном виде строка 0x9FCC00 & 0x0FFFFF
даст вам все шестнадцатеричные цифры, кроме 9, в противоположность тому, что вы хотите.
Итак, для статуса:
uint32_t status = 0xF000000 & midiData; // Retrieve 9
На самом деле, это даст вам 0x900000. Если вы хотите 0x9 (также 9 в десятичном виде), вам нужно сдвинуть результат в битах.
Теперь, правильный оператор сдвига битов (скажем, X >> 4) означает перемещение X 4 бит вправо; деление на 16. Это 4 бита, а не 4 шестнадцатеричных числа. 1 шестнадцатеричная цифра == 4 бита, поэтому для получения 9 из 0x900000 необходимо 0x900000 >> 20
,
Итак, чтобы собрать их вместе, чтобы получить статус 9:
uint32_t status = (0xF000000 & midiData) >> 20;
Подобный процесс даст вам остальные значения, которые вы хотите.
В общем, я бы рекомендовал сначала сместить, а затем замаскировать — это менее подвержено ошибкам:
uint8_t cmd = (midiData >> 16) & 0xff;
uint8_t note = (midiData >> 8) & 0x7f; // MSB can't be set
uint8_t velocity = (midiData >> 0) & 0x7f; // ditto
а затем разделить cmd
переменная:
uint8_t status = (cmd & 0xf0); // range 0x00 .. 0xf0
uint8_t channel = (cmd & 0x0f); // range 0 .. 15
Я лично не стал бы картировать status
значение обратно в диапазоне 0 .. 15 — обычно считается, что, например, 0x90
это «примечание», а не просто значение 9
,