如何正确地将十进制 MIDI 弯音值分成 2 个分开的 7 位值?
How to divide a decimal MIDI pitch-bend value into 2 separated 7 bit values correctly?
我正在尝试制作一种自定义 midi 播放器,为此我使用了一个已经正确记住 midi 消息数据的数组,如下所示:
int array[3000][4]={{time,status,data1,data2},{...},...}
当我希望我的程序发送 MIDI 消息(以便可以播放)时,我调用
这个数组并在 noteon/off、弯音等之间做必要的区分。弯音值(范围从 0 到 16383,但通常在 8192 左右,这意味着没有音高变化)都存储在 data1(array[i][2])中。为了将 int 转换为两个 7 位值以传递给 midiOutShortMsg(),我使用了一些我发现的代码 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 位值,所以我很困惑,任何帮助将不胜感激。
对于弯音消息,数据 1(您的 message.data[1])是 LSB,数据 2(message.data[2])是 MSB。我不是 C 开发人员,但这是我在一些伪代码中的做法:
(byte) data2 = pitchbend >> 7
(byte) data1 = pitchbend & 0x7F
英语:
- MSB 是:弯音位右移 7
- LSB 是:弯音按位与掩码 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 数据可能属于这种情况。
我正在尝试制作一种自定义 midi 播放器,为此我使用了一个已经正确记住 midi 消息数据的数组,如下所示:
int array[3000][4]={{time,status,data1,data2},{...},...}
当我希望我的程序发送 MIDI 消息(以便可以播放)时,我调用 这个数组并在 noteon/off、弯音等之间做必要的区分。弯音值(范围从 0 到 16383,但通常在 8192 左右,这意味着没有音高变化)都存储在 data1(array[i][2])中。为了将 int 转换为两个 7 位值以传递给 midiOutShortMsg(),我使用了一些我发现的代码 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 位值,所以我很困惑,任何帮助将不胜感激。
对于弯音消息,数据 1(您的 message.data[1])是 LSB,数据 2(message.data[2])是 MSB。我不是 C 开发人员,但这是我在一些伪代码中的做法:
(byte) data2 = pitchbend >> 7
(byte) data1 = pitchbend & 0x7F
英语:
- MSB 是:弯音位右移 7
- LSB 是:弯音按位与掩码 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 数据可能属于这种情况。