Java Midi 定序器计时已关闭
Posted
技术标签:
【中文标题】Java Midi 定序器计时已关闭【英文标题】:Java Midi sequencer timing is off 【发布时间】:2020-08-31 12:29:30 【问题描述】:在过去的几天里,我一直在尝试用 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;
我的主要课程
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);
【问题讨论】:
【参考方案1】:您的代码看起来不错。
不定时的初始节拍通常是由于连接了 Midi 设备(在我使用外部 USB Midi 声卡时)。如果可以,请尝试使用其他 MidiDevice。
如果不能,解决方法是将创建的Sequence
的所有MidiEvents
移动4 个节拍,然后使用Sequencer.setLoopEndPoint(long tick)
和Sequencer.setLoopStartPoint(long tick)
使循环从新起点开始。
对于启动后的节奏变化,这是一个 JDK 错误。解决方法是在Sequencer.start()
之后立即调用Sequencer.setTempoInBPM()
。
【讨论】:
感谢您的回复,我设法通过将所有 midi 事件向前移动 100 个刻度来克服时间问题(似乎足够了)。我还设法通过调用sequencer.setTempoFactor()
来解决节奏问题,因为sequencer.setTempoInBPM()
对我不起作用。为了计算新的速度因子,我将 bpm 的新值除以 120(因为我的 midi 文件的基本速度为 120)。似乎工作正常。
好。如果您需要读取各种 Midi 文件,您需要通过在读取序列中搜索 Midi Set Tempo 元消息来获取速度。以上是关于Java Midi 定序器计时已关闭的主要内容,如果未能解决你的问题,请参考以下文章