Мне нужно получить значение темпа из midi файла. Я узнал, что команда set_tempo имеет значение 0x51, поэтому у меня есть эта часть кода:
for (int i = 0; i < tracks[0].size(); i++) {
MidiEvent event = tracks[0].get(i);
MidiMessage message = event.getMessage();
if (message instanceof MetaMessage) {
MetaMessage mm = (MetaMessage) message;
if(mm.getType()==SET_TEMPO){
// now what?
mm.getData();
}
}
}
Но метод getData() возвращает массив байтов! Как я могу преобразовать его в обычную человеческую форму, ака целое? Я прочитал, что он хранится в таком формате: "tt tt tt", но все большие/маленькие endian, signed/unsigned и переменная длина делают его слишком запутанным.
Темп - это 3-байтовое целочисленное целое число, а бит в минуту вычисляется как BPM = 60,000,000/(tt tt tt)
byte[] data = mm.getData();
int tempo = (data[0] & 0xff) << 16 | (data[1] & 0xff) << 8 | (data[2] & 0xff);
int bpm = 60000000 / tempo;
Я использую:
mpq = ((data[0] & 0x7f) << 14) | ((data[1] & 0x7f) << 7) | (data[2] & 0x7f);
Где mpq
представляет микросекунды на четверть ноты или микросекунды за такт.
Причиной этого является то, что сообщения Midi используют только 7 бит в каждом байте для представления данных. Следует также отметить, что в Java
тип данных байта (из которых - массив) является целым числом со знаком и имеет только место для 7 бит данных.
С момента создания этого сообщения у меня был следующий ответ от Ассоциации MIDI:
Номер параметра (tttttt) - это 24-битное целое число без знака, в формате большого конца.
"Установить темп" - это мета-событие, относящееся к спецификации SMF. Он применяется только к стандартным MIDI файлам, и, как и другие мета-события, не должны передаваться по проводам в реальном времени. С другой стороны, описание байта данных, которое вас сбивает с толку, относится к протоколу over-the-wire.
Поэтому исходный ответ на эту тему является правильным.