0

Hi: I'm trying to get an instance of the MIDI Sequencer sync to an external clock. I did:

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

but

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

which means this will be useless.

S_p.setMasterSyncMode(Sequencer.SyncMode.MIDI_SYNC);

What am I doing wrong ? Of course I have confirmation of messages going out of D2 and into another receiver custom written to notify to system.out, and sequencer plays normally, it just appears that it doesn't support the SyncModes docs say it should. Specifically this phrase confuses me (from MIDI_SYNC: "This mode only applies as the master sync mode for sequencers that are also MIDI receivers."

What's the meaning of the sequencer BEING a receiver. I thought it should be enough with my approach of getReceiver()

Regards and thanks !

cladelpino
  • 337
  • 3
  • 14

2 Answers2

1

For the future generations:

Homebrew, works-for-me, MIDI-clocked-sequencer. (Guess it's now clear what it says about the sequencer BEING a receiver): (ASSUMES that receivers listen on different MIDI channels, and tracks are created accordingly. Sends all notes off at closing. Track_Master is from my implementation, keeps track of the channel the receiver is listening)

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

}
cladelpino
  • 337
  • 3
  • 14
0

Many questions at once!

1) The most important information is that Sequencers in Java Sound are plugins (service providers, SPI). Java ships with at least one Sequencer, but there is no mention that it does support all features imaginable. In particular, the existence of the getMasterSyncModes() query is an indication for the fact that not every Sequencer implementation will support all sync modes. And as you have found out, the default Sequencer in Oracle's Java happens to not support any sync modes except Internal. To be clear about it: the Java specification does not say that a Sequencer must support any particular sync mode.

2) It is, however, possible to add an own implementation of Sequencer with external sync in form of a plugin.

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

3) I assume what is meant is that in order to sync to another master sync provider, a Sequencer must be able to receive the MIDI Sync messages, i.e. also receive MIDI messages. I agree that the terminology of Receiver and Transmitter is indeed confusing in Java Sound.

What am I doing wrong?

4) You're not doing anything wrong. You can query the sync modes, and if the Sequencer supports the sync mode you're after, it'll work. But chances are, you won't find such a Sequencer implementation...

S_p = MidiSystem.getSequencer(false);

5) As said above, in Java Sound, Sequencers are plugins just like MIDI devices and Synthesizers. So your system might provide multiple Sequencers. You can query MidiSystem.getMidiDeviceInfo(), get the various devices, and see if they are instanceof Sequencer to find all available Sequencers.

But I think the main answer is: there is probably no implementation of Sequencer publicly available which supports external synchronization. It is possible to get active and fix it in OpenJDK's RealTimeSequencer...

Florian
  • 1,095
  • 9
  • 14
  • Florian: Thanks for that very complete answer. Today I finally ended my tests on relying on the internal clock, decided it's definitely no-go. PS: you're a hero !!!! your Mouse Keyboard was one of the first pieces of software I met when I started my path into these kind of things ! Thanks !!! – cladelpino Nov 02 '15 at 04:35