如何正确地将十进制 MIDI 弯音值划分为 2 个分隔的 7 位值?
Posted
技术标签:
【中文标题】如何正确地将十进制 MIDI 弯音值划分为 2 个分隔的 7 位值?【英文标题】:How to divide a decimal MIDI pitch-bend value into 2 separated 7 bit values correctly? 【发布时间】:2015-05-19 17:35:19 【问题描述】:我正在尝试制作一种自定义的 midi 播放器,为此我使用了一个已经正确记住了 midi 消息数据的数组,如下所示:
int array[3000][4]=time,status,data1,data2,...,...
当我希望我的程序发送 midi 消息(以便可以播放)时,我调用 这个数组并在noteon/off、pitch-bend等之间进行必要的区分。弯音值(范围从 0 到 16383,但通常在 8192 左右,这意味着没有音高偏移)全部存储在 data1(array[i][2])中。对于从 int 到要传递给 midiOutShortMsg() 的两个 7 位值的转换,我使用了我找到的一些代码 here。这是我实际使用的代码:
union unsigned long word; unsigned char data[4]; message;
int main(int argc, char** argv)
int midiport; // select which MIDI output port to open
uint16_t bend;
int flag,u; // monitor the status of returning functions
uint16_t mask = 0x007F;
HMIDIOUT device; // MIDI device interface for sending MIDI output
message.data[0] = 0x90;
message.data[1] = 60;
message.data[2] = 100;
message.data[3] = 0; // Unused parameter
// Assign the MIDI output port number (from input or default to 0)
if (!midiOutGetNumDevs())
printf("non ci sono devices");
if (argc < 2)
midiport = 0;
else
midiport = 0;
printf("MIDI output port set to %d.\n", midiport);
// Open the MIDI output port
flag = midiOutOpen(&device, midiport, 0, 0, CALLBACK_NULL);
if (flag != MMSYSERR_NOERROR)
printf("Error opening MIDI Output.\n");
return 1;
i = 0;
message.data[0] = 0xC0;
message.data[1] = 25;
message.data[2] = 0;
flag = midiOutShortMsg(device, message.word); //program change to steel guitar
if (flag != MMSYSERR_NOERROR)
printf("Warning: MIDI Output is not open.\n");
while (1)
if (array[i][1] == 1) //note on
this_works();i++;
else if (array[i][1] == 0)//note off
this_also_works();i++;
else if (array[i][1] == 2)//pitch bend
while (array[i][1] == 2)
Sleep(10);
message.data[0] = 0xE0;
bend = (uint16_t) array[i][2];
message.data[1] = bend & mask;
message.data[2] = (bend & (mask << 7)) >> 7;
printf("bending %d, %d\n", message.data[1],message.data[2]);
flag = midiOutShortMsg(device, message.word);
if (flag != MMSYSERR_NOERROR)
printf("Warning: MIDI Output is not open.\n");
i++;
无论如何,printf("bending %d,%d") 函数总是将第一个 %d 打印为 0。这是我第一次用 midi 编程,以前我从来没有处理过 7 位值,所以我很困惑,任何帮助将不胜感激。
【问题讨论】:
bend = array[i][2]
,查看位置 2 中的数组初始化,有一个名为 byte1
的变量,因此如果您将掩码移动到前七个位 bend & (mask << 7)
之后抓取,您只会得到最后一个byte1 中的位,对于 midi 字节应始终为零。
如果数组中的数据已经被分割成两个字节,为什么还要再分割呢?只需将 array[i][2] 和 array[i][3] 放入 message.data[1] 和 message.data[2]
我想你可能误解了byte1和byte2的意思,我将它们重命名为data1和data2。 data1(ex byte1)变量包含一个从 0 到 16383 的 int 数,我必须将其分成 2 个独立的变量,每个变量 7 位(message.data[1] 和 message.data[2])。我将编辑我的问题。
【参考方案1】:
对于弯音消息,data1(您的 message.data[1])是 LSB,data2(message.data[2])是 MSB。我不是 C 开发人员,但这是我在一些伪代码中的做法:
(byte) data2 = pitchbend >> 7
(byte) data1 = pitchbend & 0x7F
英文:
MSB 为:pitchbend 位移右 7 位 LSB 是:pitchbend 按位与掩码为 127作为参考,做相反的事情(例如,如果您在消息中收到它们,则结合这两个值来计算弯音)是一个简单的问题:
pitchbend = (data2 * 128) + data1
编辑:我更仔细地阅读了你的代码,看起来你已经在做我描述的事情了。即:
uint16_t mask = 0x007F;
bend = (uint16_t) array[i][2];
message.data[1] = bend & mask;
message.data[2] = (bend & (mask << 7)) >> 7;
您要发送array[i][2]
的什么值?任何 128 的偶数倍数都将导致 LSB (message.data[1]
) 为零。设备忽略或不使用低字节提供的附加分辨率的情况并不少见,因此您的示例 MIDI 数据可能属于这种情况。
【讨论】:
按位与 == & 逻辑与 == && 这太复杂了,因为data2只是pitchbend >> 7;由于 2 个 MSB 为零,因此不需要额外的屏蔽。 @Justin Ryan 我没有注意到实际上我存储的所有弯音值都是 128 的倍数。但我不明白为什么 midi 播放器不按应有的方式播放实际的弯音.听起来它比一个半音弯曲得少(少得多),而它听起来应该像一个半音的弯曲,最后是颤音。 @Miguel 我不确定我是否理解你的建议 @Aki 我尝试了你的建议,这是真的,它仍然给出相同的结果(无论是数字还是中间)。以上是关于如何正确地将十进制 MIDI 弯音值划分为 2 个分隔的 7 位值?的主要内容,如果未能解决你的问题,请参考以下文章