Java Midi 音序器定时关闭
Java Midi sequencer timing is off
在过去的几天里,我一直在尝试编写 Java 中的节拍器进行练习。我制作了一个简单的 4/4 midi 节拍,该程序使用 javax.sound.midi 库进行播放。
我的主要问题是音序器似乎在关闭时间播放第一拍。如果我将序列设置为循环,这只会在第一个循环中发生。附带说明一下,如果我更改曲目的 bpm,它会在第一个循环后重置。
此外,我尝试了多个 midi 文件以防万一我创建的 midi 文件出现问题但我的所有测试都同样的结果。
这是我处理 MIDI 播放的代码:
public class MidiHandler
{
private Sequencer sequencer;
private Sequence seq;
private float newTempoFactor;
public MidiHandler()
{
try
{
sequencer = MidiSystem.getSequencer();
if (sequencer == null)
{
System.err.println("Sequencer not supported");
}
sequencer.open();
}
catch (MidiUnavailableException ex)
{
Logger.getLogger(MidiHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void setAudioTrack(String filePath)
{
try
{
seq= MidiSystem.getSequence(new File(filePath));
sequencer.setSequence(seq);
}
catch (InvalidMidiDataException | IOException ex)
{
Logger.getLogger(MidiHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void playTrack(float bpm) throws InterruptedException
{
try
{
seq=editEvents();//editEvents() method pushes all midi events 100 ticks forward
sequencer.setSequence(seq);
}
catch (InvalidMidiDataException ex)
{
Logger.getLogger(MidiHandler.class.getName()).log(Level.SEVERE, null, ex);
}
sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
sequencer.start();
//sequencer.setTempoInBPM(bpm);
newTempoFactor=bpm/120;
sequencer.setTempoFactor(newTempoFactor);//Default tempo is 120bpm --> Tempo factor =1
sequencer.setLoopStartPoint(100);//Shift the loop start/end by 100 ticks
sequencer.setLoopEndPoint(seq.getTickLength());
}
public Sequence editEvents()
{
Sequence seq= this.seq;
try
{
seq = MidiSystem.getSequence(new File("res//myTrack.mid"));
for (Track track : seq.getTracks())
{
for (int i=0; i < track.size(); i++)
{
MidiEvent event = track.get(i);
event.setTick(event.getTick()+100);
}
}
}
catch (InvalidMidiDataException | IOException ex)
{
Logger.getLogger(MidiHandler.class.getName()).log(Level.SEVERE, null, ex);
}
return seq;
}
}
我的主要class
public class main
{
public static void main(String[] args)
{
try
{
MidiHandler mh = new MidiHandler();
mh.setAudioTrack("res//myTrack.mid");
mh.playTrack(120f);
}
catch (SecurityException | InterruptedException ex)
{
Logger.getLogger(main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
您的代码看起来没问题。
off-timing 的初始节拍通常是由于连接了 Midi 设备(在我使用外部 USB Midi 声卡的情况下)。如果可以,请尝试使用不同的 MidiDevice。
如果不能,解决方法是将创建的 Sequence
的所有 MidiEvents
移动 4 拍,然后使用 Sequencer.setLoopEndPoint(long tick)
和 Sequencer.setLoopStartPoint(long tick)
使循环从新的起点开始。
对于开始后的速度变化,这是一个 JDK 错误。解决方法是在 Sequencer.start()
.
之后立即调用 Sequencer.setTempoInBPM()
在过去的几天里,我一直在尝试编写 Java 中的节拍器进行练习。我制作了一个简单的 4/4 midi 节拍,该程序使用 javax.sound.midi 库进行播放。
我的主要问题是音序器似乎在关闭时间播放第一拍。如果我将序列设置为循环,这只会在第一个循环中发生。附带说明一下,如果我更改曲目的 bpm,它会在第一个循环后重置。
此外,我尝试了多个 midi 文件以防万一我创建的 midi 文件出现问题但我的所有测试都同样的结果。
这是我处理 MIDI 播放的代码:
public class MidiHandler
{
private Sequencer sequencer;
private Sequence seq;
private float newTempoFactor;
public MidiHandler()
{
try
{
sequencer = MidiSystem.getSequencer();
if (sequencer == null)
{
System.err.println("Sequencer not supported");
}
sequencer.open();
}
catch (MidiUnavailableException ex)
{
Logger.getLogger(MidiHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void setAudioTrack(String filePath)
{
try
{
seq= MidiSystem.getSequence(new File(filePath));
sequencer.setSequence(seq);
}
catch (InvalidMidiDataException | IOException ex)
{
Logger.getLogger(MidiHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void playTrack(float bpm) throws InterruptedException
{
try
{
seq=editEvents();//editEvents() method pushes all midi events 100 ticks forward
sequencer.setSequence(seq);
}
catch (InvalidMidiDataException ex)
{
Logger.getLogger(MidiHandler.class.getName()).log(Level.SEVERE, null, ex);
}
sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
sequencer.start();
//sequencer.setTempoInBPM(bpm);
newTempoFactor=bpm/120;
sequencer.setTempoFactor(newTempoFactor);//Default tempo is 120bpm --> Tempo factor =1
sequencer.setLoopStartPoint(100);//Shift the loop start/end by 100 ticks
sequencer.setLoopEndPoint(seq.getTickLength());
}
public Sequence editEvents()
{
Sequence seq= this.seq;
try
{
seq = MidiSystem.getSequence(new File("res//myTrack.mid"));
for (Track track : seq.getTracks())
{
for (int i=0; i < track.size(); i++)
{
MidiEvent event = track.get(i);
event.setTick(event.getTick()+100);
}
}
}
catch (InvalidMidiDataException | IOException ex)
{
Logger.getLogger(MidiHandler.class.getName()).log(Level.SEVERE, null, ex);
}
return seq;
}
}
我的主要class
public class main
{
public static void main(String[] args)
{
try
{
MidiHandler mh = new MidiHandler();
mh.setAudioTrack("res//myTrack.mid");
mh.playTrack(120f);
}
catch (SecurityException | InterruptedException ex)
{
Logger.getLogger(main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
您的代码看起来没问题。
off-timing 的初始节拍通常是由于连接了 Midi 设备(在我使用外部 USB Midi 声卡的情况下)。如果可以,请尝试使用不同的 MidiDevice。
如果不能,解决方法是将创建的 Sequence
的所有 MidiEvents
移动 4 拍,然后使用 Sequencer.setLoopEndPoint(long tick)
和 Sequencer.setLoopStartPoint(long tick)
使循环从新的起点开始。
对于开始后的速度变化,这是一个 JDK 错误。解决方法是在 Sequencer.start()
.
Sequencer.setTempoInBPM()