Calculating CoreMIDI Pitch Bend Values For iOS?

后端 未结 1 1198
旧时难觅i
旧时难觅i 2021-01-07 09:41

I need to hand assemble 14bit MIDI Pitch Bend values from raw UInt16 values in iOS. I\'m wondering if anybody out there has had a chance to come up with an

1条回答
  •  心在旅途
    2021-01-07 10:08

    I think your code is close to right, but it's overly complicated. This question has nothing to do with iOS or endianness or ARM or Intel; it's just plain old C bit-twiddling. If you write the code correctly, it will work on any reasonable platform without modification. You don't need a library; it's only a couple lines of code.

    It's best to work with MIDI on a byte-by-byte basis. You want a function that takes a 16-bit unsigned integer (which we'll trust has at most 14 bits worth of value) and returns two single-byte values, one with the most significant bits, one with the least significant bits.

    Later on, when you send the message, you assemble the bytes in the appropriate order. According to the specification, pitch wheel messages are three bytes: STATUS, then LSB, then MSB. You have them backwards in your question!

    The least-significant 7 bits are easy: just mask off those bits from the original value. The most-significant 7 bits are similar: mask off the next higher 7 bits from the original value, then shift them down.

    It doesn't matter whether the 16-bit integers are little-endian or big-endian in memory on your machine; the compiler takes care of that.

    Here's a function and a test tool.

    #include 
    #include   // for C standard uint8_t and uint16_t
    // or, if you prefer, use unsigned char and unsigned short, or Byte and UInt16;
    // they'll all work, although some are more portable than others
    
    void encode14BitValue(uint16_t value, uint8_t *out_msb, uint8_t *out_lsb)
    {
        uint16_t mask = 0x007F;  // low 7 bits on
                                 // "(1 << 7) - 1" is arguably clearer
        *out_lsb = value & mask;
        *out_msb = (value & (mask << 7)) >> 7;
    }
    
    int main(int argc, const char * argv[])
    {
        typedef struct {
            uint16_t in;
            uint8_t expected_msb;
            uint8_t expected_lsb;
        } test_case;
    
        test_case cases[] = {
            { 0x0000, 0x00, 0x00 },
            { 0x0001, 0x00, 0x01 },
            { 0x0002, 0x00, 0x02 },
            { 0x0004, 0x00, 0x04 },
            { 0x0008, 0x00, 0x08 },
            { 0x0009, 0x00, 0x09 },
            { 0x000F, 0x00, 0x0F },
            { 0x0010, 0x00, 0x10 },
            { 0x0011, 0x00, 0x11 },
            { 0x001F, 0x00, 0x1F },
            { 0x0020, 0x00, 0x20 },
            { 0x0040, 0x00, 0x40 },
            { 0x0070, 0x00, 0x70 },
            { 0x007F, 0x00, 0x7F },
            { 0x0080, 0x01, 0x00 },
            { 0x0081, 0x01, 0x01 },
            { 0x008F, 0x01, 0x0F },
            { 0x0090, 0x01, 0x10 },
            { 0x00FF, 0x01, 0x7F },
            { 0x0100, 0x02, 0x00 },
            { 0x0200, 0x04, 0x00 },
            { 0x0400, 0x08, 0x00 },
            { 0x0800, 0x10, 0x00 },
            { 0x1000, 0x20, 0x00 },
            { 0x1FFF, 0x3F, 0x7F },
            { 0x2000, 0x40, 0x00 },
            { 0x2001, 0x40, 0x01 },
            { 0x3FFF, 0x7F, 0x7F },
        };
    
        int passed = 1;
        for (int i = 0, c = sizeof(cases) / sizeof(cases[0]); i < c; i++) {
            uint8_t msb, lsb;
            encode14BitValue(cases[i].in, &msb, &lsb);
    
            if (cases[i].expected_msb != msb || cases[i].expected_lsb != lsb) {
                printf("failed: 0x%04hX expected 0x%02hhX 0x%02hhX got 0x%02hhX 0x%02hhX\n", cases[i].in, cases[i].expected_msb, cases[i].expected_lsb, msb, lsb);
                passed = 0;
            }
        }
    
        return passed ? 0 : 1;
    }
    

    In your code, trying to pack the two bytes of result into one 16-bit integer just adds confusion. I don't know why you're doing that, since you're going to have to extract individual bytes again, whenever you send the MIDI anywhere else. That's where any worries about endianness come up, since your packing and unpacking code have to agree. You might as well not bother. I bet your code was incorrect, but your error in swapping MSB and LSB compensated for it.

    0 讨论(0)
提交回复
热议问题