我正在尝试获取 MIDI 序列的音轨数量:
File file = new File(strSource);
Sequence sequence = MidiSystem.getSequence(file);
int numTracks = sequence.getTracks().length;
。其中 strSource 是我的.mid文件的完整路径+文件名。numTracks 是 1,但.mid文件有 16 个音轨(当我在另一个 MIDI 编辑器中打开它时可以看到)。文件类型为 0。
我在某处读到,Type-0 文件不能在同一频道上有多个轨道。在这种情况下,所有轨道都强制进入单个轨道。这是对的吗?我怎样才能避免这种情况?
看来你是对的,Type-0 文件在一个文件中包含多个轨道。在这里,您有一些信息。
无法从类型 0 文件中提取每个单独的轨道。
检查 MIDI 文件类型,如果外部 MIDI 编辑器可以检测到多个音轨,则它可以是类型 1 或类型 2 文件,即使扩展名不匹配。
我用十六进制工具查看了该文件......它实际上只有一条轨道。
另一个编辑器自行创建多个轨道。它似乎搜索程序更改消息,然后将事件放入新轨道。
我编写了一个小函数,可以将类型 # 0 序列转换为类型 # 1 序列
/**
* Make multiple tracks from file0 track
* @param in : Sequence with single track
* @return Multiple track sequence
*/
private Sequence extractFile0Tracks (Sequence in) throws InvalidMidiDataException
{
Track inTrack = in.getTracks()[0];
HashMap<Integer, ArrayList<MidiEvent>> msgMap = new HashMap<>();
// Distribute events per channel to ArrayList map
for (int i = 0; i < inTrack.size(); i++)
{
MidiEvent event = inTrack.get(i);
MidiMessage message = event.getMessage();
if (message instanceof ShortMessage)
{
ShortMessage sm = (ShortMessage) message;
int channel = sm.getChannel() + 1;
ArrayList<MidiEvent> msgList = msgMap.computeIfAbsent(channel, k -> new ArrayList<>());
msgList.add(event);
}
}
// Create sequence with multiple tracks
Sequence newSeq = new Sequence(in.getDivisionType(), in.getResolution());
for (ArrayList<MidiEvent> msgList : msgMap.values())
{
Track tr = newSeq.createTrack();
for (MidiEvent m1 : msgList)
tr.add(m1);
}
return newSeq;
}