【问题标题】:Java MIDI Sequencer SyncModeJava MIDI 音序器同步模式
【发布时间】:2015-10-27 02:24:15
【问题描述】:

嗨:我正在尝试将 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());}

返回

 Available modes are 0 Internal Clock

这意味着这将毫无用处。

S_p.setMasterSyncMode(Sequencer.SyncMode.MIDI_SYNC);

我做错了什么? 当然,我已经确认消息从 D2 出来并进入另一个定制的接收器,以通知 system.out,并且音序器正常播放,只是似乎它不支持 SyncModes 文档说它应该。特别是这句话让我感到困惑(来自MIDI_SYNC:“这种模式仅适用于同时也是 MIDI 接收器的音序器的主同步模式。”

音序器作为接收器是什么意思。我认为我的 getReceiver() 方法应该足够了

问候和感谢!

【问题讨论】:

    标签: java midi javax.sound.midi


    【解决方案1】:

    为了后代:

    自制,为我工作,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;
      }
    
    }
    

    【讨论】:

      【解决方案2】:

      同时提出许多问题!

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

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

      音序器成为接收器是什么意思?

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

      我做错了什么?

      4) 你没有做错任何事。您可以查询同步模式,如果 Sequencer 支持您所追求的同步模式,它将起作用。但很可能,你不会找到这样的 Sequencer 实现......

      S_p = MidiSystem.getSequencer(false);

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

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

      【讨论】:

      • 弗洛里安:感谢您提供非常完整的答案。今天我终于结束了依靠内部时钟的测试,决定绝对不行。 PS:你是英雄!!!!您的鼠标键盘是我开始涉足此类事物时遇到的第一批软件之一!谢谢!!!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多