Как правильно разделить десятичное значение высоты тона MIDI на 2 отдельных 7-битных значения?
Я пытаюсь сделать что-то вроде пользовательского миди-плеера, для этого я использую массив, который уже правильно запомнил данные миди-сообщений, например:
int array[3000][4]={{time,status,data1,data2},{...},...}
Когда я хочу, чтобы моя программа отправила MIDI-сообщение (чтобы его можно было воспроизвести), я вызываю этот массив и делаю необходимые различия между Noteon / Off, Pitch-Bend и так далее. Значение изменения высоты тона (в диапазоне от 0 до 16383, но обычно составляет около 8192, что означает отсутствие сдвига высоты тона), все запоминается в data1 (array[i][2]). Для преобразования из int в два 7-битных значения для передачи в midiOutShortMsg() я использовал часть кода, найденного здесь. Вот код, который я на самом деле использую:
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("сгибание%d,%d") всегда печатает первый% d как 0, несмотря ни на что. Это первый раз, когда я программирую в миди, и мне никогда не приходилось иметь дело с 7-битными значениями раньше, поэтому я запутался, любая помощь будет оценена.
1 ответ
Для сообщения Pitch Bend data1 (ваш message.data[1]) является LSB, а data2 (message.data[2]) является MSB. Я не разработчик C, но вот как я делаю это в некотором псевдокоде:
(byte) data2 = pitchbend >> 7
(byte) data1 = pitchbend & 0x7F
По-английски:
- MSB: сдвиг бита высоты тона вправо 7
- LSB - это: шаг по битам И с маской 127
Для справки, сделать обратное (например, объединить два значения для вычисления изменения высоты тона, если вы получили их в сообщении), является простым вопросом:
pitchbend = (data2 * 128) + data1
Изменить: я прочитал ваш код более внимательно, и похоже, что вы уже делаете то, что я описал. IE:
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-данных могут попасть под это условие.