问题
I'm trying to make a sort of custom midi player, to do so I'm using an array that already has memorized correctly the midi messages data like this:
int array[3000][4]={{time,status,data1,data2},{...},...}
when I want my program to send the midi message (so that it can be played) I call this array and do the needed distinctions between noteon/off, pitch-bend and such. The pitch-bend value (ranging from 0 to 16383, but usually is around 8192 which means no pitch shifting) is all memorized in data1 (array[i][2]). For the conversion from int to the two 7 bits values to pass to midiOutShortMsg() I've used some of the code I found here. Here is the code I'm actually using:
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++;
}
}
}}
The printf("bending %d,%d") function always prints the first %d as a 0, no matter what. It's the first time I program in midi and I never had to deal with 7 bits values before, so I'm getting quite confused, any help will be appreciated.
回答1:
For a pitch bend message data1 (your message.data[1]) is the LSB, and data2 (message.data[2]) is MSB. I'm not a C developer, but here's how I do it in some pseudo-code:
(byte) data2 = pitchbend >> 7
(byte) data1 = pitchbend & 0x7F
In English:
- MSB is: pitchbend bit shift right 7
- LSB is: pitchbend bitwise AND with a mask of 127
For reference, doing the reverse (combining the two values to calculate pitch bend, if you had received them in a message, for instance) is a simple matter of:
pitchbend = (data2 * 128) + data1
Edit: I read your code more closely, and it looks like you're already doing what I described. IE:
uint16_t mask = 0x007F;
bend = (uint16_t) array[i][2];
message.data[1] = bend & mask;
message.data[2] = (bend & (mask << 7)) >> 7;
What values for array[i][2]
are you trying to send? Anything that is an even multiple of 128 will result in an LSB (message.data[1]
) of zero. It is not uncommon for devices to ignore, or not use the added resolution provided by the low byte, so your sample MIDI data may fall under this condition.
来源:https://stackoverflow.com/questions/30332416/how-to-divide-a-decimal-midi-pitch-bend-value-into-2-separated-7-bit-values-corr