Das Timing des Java Midi-Sequenzers ist deaktiviert
In den letzten Tagen habe ich versucht, ein Metronom in Java zum Üben zu codieren. Ich habe einen einfachen 4/4-Midi-Beat gemacht, den das Programm mit der Bibliothek javax.sound.midi spielt .
Mein Hauptproblem ist, dass der Sequenzer die erste Off-Time zu spielen scheint. Wenn ich die Sequenz auf Schleife setze, tritt dies nur in der ersten Schleife auf. Nebenbei bemerkt, wenn ich die BPM des Tracks ändere, wird sie nach der ersten Schleife zurückgesetzt.
Außerdem habe ich mehrere MIDI-Dateien ausprobiert, nur für den Fall, dass ein Problem mit der von mir erstellten MIDI-Datei aufgetreten ist, aber alle meine Tests die gleichen Ergebnisse erzielt haben.
Hier ist mein Code für die MIDI-Wiedergabe:
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;
}
}
Meine Hauptklasse
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);
}
}
}
Antworten
Ihr Code sieht in Ordnung aus.
Der anfängliche Takt, der außerhalb des Timings liegt, ist normalerweise auf das angeschlossene Midi-Gerät zurückzuführen (in meinem Fall, wenn ich meine externe USB-Midi-Soundkarte verwende). Versuchen Sie es mit einem anderen MidiDevice, wenn Sie können.
Wenn Sie dies nicht können, besteht die Problemumgehung darin, alle von beispielsweise 4 Schlägen MidiEventserstellten zu verschieben und dann die Schleife am neuen Startpunkt zu Sequenceverwenden Sequencer.setLoopEndPoint(long tick)und Sequencer.setLoopStartPoint(long tick)zu starten.
Bei der Tempowechsel nach dem Start handelt es sich um einen JDK-Fehler. Die Problemumgehung besteht darin, Sequencer.setTempoInBPM()direkt danach anzurufen Sequencer.start().