0

嗨:我正在尝试将 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() 方法应该足够了

问候和感谢!

4

2 回答 2

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;
  }

}
于 2015-11-02T04:40:01.240 回答
0

一次有很多问题!

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

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

定序器作为接收器是什么意思?

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

我究竟做错了什么?

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

S_p = MidiSystem.getSequencer(false);

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

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

于 2015-10-27T19:52:06.907 回答