Java MIDI 音序器同步模式

Java MIDI Sequencer SyncMode

嗨:我正在尝试将 MIDI 音序器实例同步到外部时钟。我做了:

S_p = MidiSystem.getSequencer(false);
D2 = MidiSystem.getMidiDevice(MidiSystem.getMidiDeviceInfo()[1]);
S_p.open();
D2.open();
R2=S_p.getReceiver();
T2=D2.getTransmitter();
T2.setReceiver(R2);

但是

for(int i=0;i<S_p.getMasterSyncModes().length;i++)
{System.out.println("Available modes are "+i+ " "+S_p.getMasterSyncModes()[i].toString());}

returns

 Available modes are 0 Internal Clock

这意味着这将毫无用处。

S_p.setMasterSyncMode(Sequencer.SyncMode.MIDI_SYNC);

我做错了什么? 当然,我已经确认消息从 D2 传出并进入另一个接收器自定义写入以通知 system.out,并且音序器正常播放,它似乎不支持 SyncModes 文档说它应该。特别是这个短语让我感到困惑(来自MIDI_SYNC:"This mode only applies as the master sync mode for sequencers that are also MIDI receivers."

音序器成为接收器是什么意思。我认为我的 getReceiver()

方法应该足够了

问候和感谢!

一次有很多问题!

1) 最重要的信息是 Java Sound 中的 Sequencer 是插件(服务提供商,SPI)。 Java 附带至少一个 Sequencer,但没有提及它确实支持所有可以想象的功能。特别是,getMasterSyncModes() 查询的存在表明并非每个 Sequencer 实现都支持所有同步模式。正如您所发现的,Oracle Java 中的默认 Sequencer 碰巧不支持除 Internal 之外的任何同步模式。需要明确的是:Java 规范并未说明 Sequencer 必须支持任何特定的同步模式。

2) 但是,可以以插件的形式添加带有外部同步的 Sequencer 自己的实现。

What's the meaning of the sequencer BEING a receiver?

3) 我认为这意味着为了同步到另一个主同步提供者,音序器必须能够接收 MIDI 同步消息,即也接收 MIDI 消息。我同意接收器和发射器的术语在 Java 声音中确实令人困惑。

What am I doing wrong?

4) 你没有做错任何事。您可以查询同步模式,如果 Sequencer 支持您想要的同步模式,它就会工作。但是很有可能,您找不到这样的 Sequencer 实现...

S_p = MidiSystem.getSequencer(false);

5) 如上所述,在 Java 声音中,音序器就像 MIDI 设备和合成器一样是插件。所以你的系统可能会提供多个 Sequencer。您可以查询 MidiSystem.getMidiDeviceInfo(),获取各种设备,并查看它们是否 instanceof Sequencer 以找到所有可用的 Sequencer。

但我认为主要的答案是:可能没有公开可用的支持外部同步的 Sequencer 实现。 可以在 OpenJDK 的 RealTimeSequencer 中激活并修复它...

为了子孙后代:

自制软件,为我工作,MIDI 时钟音序器。 (猜猜现在清楚它所说的关于音序器是接收器的内容):(假设接收器在不同的 MIDI 通道上侦听,并相应地创建轨道。在关闭时发送所有音符。Track_Master 来自我的实现,保持接收器正在收听的频道的轨道)

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.Sequence;

/**
 * @author claudio
 *
 */

public class MIDI_Clocked_Sequencer implements Receiver {

private Sequence S;
private int[] playheads;
private long counter=0;
private Receiver[] receivers;
private long counter_reset;

/**
 * @throws MidiUnavailableException 
 * 
 */
public MIDI_Clocked_Sequencer(Sequence S,long counter_reset,int[]  where_to_get_receivers) throws MidiUnavailableException {
    this.setSequence(S);
    this.counter_reset=counter_reset;
    playheads=new int[S.getTracks().length];
    receivers=new Receiver[where_to_get_receivers.length];
    for(int i=0;i<where_to_get_receivers.length;i++){
        this.receivers[i]=MidiSystem.getMidiDevice(MidiSystem.getMidiDeviceInfo()[where_to_get_receivers[i]]).getReceiver();
        MidiSystem.getMidiDevice(MidiSystem.getMidiDeviceInfo()[where_to_get_receivers[i]]).open();
    }
}

@Override
public void close() {
    for(int j=0;j<receivers.length;j++){
        try {
            receivers[j].send(new ShortMessage(ShortMessage.CONTROL_CHANGE+Track_Master.channel_map.get(Track_Master.gui_map.get(j)),123,0), 0);
        } catch (InvalidMidiDataException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }           
receivers[j].close();}
}

@Override
public void send(MidiMessage msg, long arg1) {
    Set<MidiMessage> message_buffer = new HashSet<MidiMessage>();
    if(msg.getMessage()[0]==-8){
        if(counter==counter_reset){counter=0;}
            for(int j=0;j<S.getTracks().length;j++){
                if(playheads[j]==S.getTracks()[j].size()){playheads[j]=0;};
                while(playheads[j]<S.getTracks()[j].size() &&   S.getTracks()[j].get(playheads[j]).getTick()==counter){
                message_buffer.add(S.getTracks()[j].get(playheads[j]).getMessage());
                playheads[j]=playheads[j]+1;
                }
            }
            for(Iterator<MidiMessage> it=message_buffer.iterator();it.hasNext();){
            MidiMessage f=it.next();
                for(int j=0;j<receivers.length;j++)
                {
                    receivers[j].send(f, -1);}
            }
            counter=counter+1;
      }
}

public Sequence getSequence() {
    return S;
}

public void setSequence(Sequence s) {
    this.S = s;
  }

}