计算iOS的CoreMIDI Pitch Bend值?

我需要在iOS中从原始UInt16值手工组装14位MIDI Pitch Bend值。 我想知道有没有人有机会提出一个优雅的解决scheme? 这就是我所在的位置 – 我将有机会在今天晚些时候对此进行testing,但是如果在此之前我听到,很好:

首先,一些好奇的MIDI预备。

MIDI Pitch Bend被分成一个状态字节和两个数据字节(这是一个14位控制器),这两个数据字节都与它们的状态字节相关联,这两个数据字节都带有一个零状态 ,MIDI Spec使它们按照MSB – > LSB

(编辑:更新,它实际上是状态 – > LSB – > MSB

(即1110 0000,011111111,01111111)

我们面临的挑战是如何在iOS上将ARM / Intel 16位UInt16分解为两个7位段,并且对MIDI有意义?

请记住,因为我们正在处理一个无符号的整数,所以0值不是中性弯音,而是整个音高下降 – 中音弯曲定义为8192,而16,383是全音高。

所以这里是我最好的猜测如何做到这一点:

UInt16 msbAnd = base10ValueUInt16 & 16256; //clearing out LSB UInt16 msbAndShift = msbAnd << 1; //shift into leading Byte, with 0 status bit UInt16 lsbAnd = base10ValueUInt16 & 127; //isolating LSB UInt16 finalTwoBytePitchWord = msbFinalAndShift | lsbAnd; //make UInt16 word UInt16 finalTwoBytePitchWordFlipped = CFSwapInt16HostToBig(finalTwoBytePitchWord); //Endian tweak 

这段代码运行良好,似乎创build了所需的零状态位的两个数据字节,并翻转他们从小端英特尔/ ARM似乎是必要的MIDI(MIDI是STATUS – > MSB – > LSB):我可以巴掌稍后在适当的MIDI通道上领先的状态字节。

那么,这是否有意义? 有没有人想出一个更优雅的解决scheme? (有没有一个图书馆,我忽略?)…我会稍后检查,也让人们知道,如果这实际上对采样器我必须针对它的工作。

谢谢

我认为你的代码是接近正确的,但是它太复杂了。 这个问题与iOS或Endianness或ARM或Intel无关; 这只是一个普通的旧的C比特。 如果你写的代码是正确的,它可以在任何合理的平台上工作而不需要修改。 你不需要一个图书馆; 这只是几行代码。

最好以逐字节为基础使用MIDI。 你需要一个16位无符号整数(我们相信最多有14位值)的函数并返回两个单字节值,其中一个是最高有效位,一个是最低有效位。

稍后,当您发送消息时,可以按照适当的顺序组合字节。 根据规范 ,音调轮消息有三个字节:STATUS,LSB,MSB。 你有他们在你的问题!

最不重要的7位很容易:只是从原始值中屏蔽这些位。 最重要的7位是相似的:从原始值屏蔽下一个高7位,然后将其移下。

16位整数在你的机器的内存中是小端还是大端; 编译器会照顾到这一点。

这是一个function和testing工具。

 #include <stdio.h> #include <stdint.h> // 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; } 

在你的代码中,试图把结果的两个字节打包成一个16位的整数只会增加混淆。 我不知道你为什么要这样做,因为无论何时在其他地方发送MIDI,你都必须重新提取单个字节。 这就是任何担心sorting的问题,因为你的打包和拆包代码必须同意。 你可能不打扰。 我敢打赌你的代码是不正确的,但是你交换MSB和LSB的错误补偿了它。