package moppydesk.outputs; import java.util.ArrayList; import java.util.Arrays; import javax.sound.midi.MidiDevice; import javax.sound.midi.MidiMessage; import javax.sound.midi.Receiver; import javax.sound.midi.ShortMessage; /** * Marshals data from the chosen input device to the (up to) 16 output receivers. * Receivers are defined in a size-16 array, one slot for each MIDI channel. Each received * message is routed to the appropriate receiver based on its channel. If a receiver * is not defined for the given channel's index in the array, the message is dropped. */ public class ReceiverMarshaller implements MoppyReceiver{ /** * Array of {@link MoppyReceiver} references, one for each channel. The same receiver * object can be assigned to multiple indexes if it is going to be handling multiple * channels of data. */ private final MoppyReceiver[] outputReceivers = new MoppyReceiver[16]; private final boolean[] receiverEnabled = new boolean[16]; /** * Creates a new ReceiverMarshaller with an empty array of {@link Receiver}s. * @param receivers */ public ReceiverMarshaller(){ //Nothing for now. } /** * Sets a channel's Receiver object. If a receiver is already assigned to this * channel, {@link Receiver#close()} will be called before it is removed and replaced * with the new {@link Receiver}. * @param MIDIChannel * @param channelReceiver */ public void setReceiver(int MIDIChannel, MoppyReceiver channelReceiver){ if (MIDIChannel < 1 || MIDIChannel > 16){ throw new IllegalArgumentException("Only channels 1-16 are supported by the ReceiverMarshaller!"); } if (outputReceivers[MIDIChannel-1] != null){ outputReceivers[MIDIChannel-1].close(); } outputReceivers[MIDIChannel-1] = channelReceiver; } //MrSolidSnake745: Adding functions to enable/disable receivers (essentially channels) for progrommatic control //WARNING: These are not user facing! If you disable a channel and forget to enable it, the user will have no way of correcting it without restarting Moppy! // To help mitigate this, I'm calling enableAll when connected public void enableReceiver(int ch) { if (outputReceivers[ch-1] != null) {receiverEnabled[ch-1] = true;} } public void enableAll() { Arrays.fill(receiverEnabled, true); } public void disableReceiver(int ch) { if (outputReceivers[ch-1] != null) {receiverEnabled[ch-1] = false;} } public void disableAll() { Arrays.fill(receiverEnabled, false); } /** * Closes all receivers, and removes them from the array (fills array with nulls). */ public void clearReceivers() { close(); } public void send(MidiMessage message, long timeStamp) { int ch = ((ShortMessage)message).getChannel(); if (outputReceivers[ch]!= null && receiverEnabled[ch]){ outputReceivers[ch].send(message, timeStamp); } } /** * Explicity closes all output receivers, and nulls the array. * This differs slightly from the use described in {@link MidiDevice} in that * the ReceiverMarshaller itself is not necessarily closed when this is called. * After being closed, new receivers can continue to be added to the ReceiverMarshaller. */ public void close() { disconnecting(); for (Receiver r: outputReceivers){ if (r!= null){ r.close(); } } Arrays.fill(outputReceivers, null); } private ArrayList<MoppyReceiver> getUniqueReceivers() { ArrayList<MoppyReceiver> uniqueReceivers = new ArrayList<>(); for (MoppyReceiver r: outputReceivers){ if (r!= null && !uniqueReceivers.contains(r)){ uniqueReceivers.add(r); } } return uniqueReceivers; } /** * Finds the unique set of receivers and calls the {@link MoppyReceiver#reset() } method. * We go through the trouble of finding unique receivers incase the reset is time-consuming. */ public void reset() { for (MoppyReceiver r : getUniqueReceivers()){ r.reset(); } } public void silence() { for (MoppyReceiver r : getUniqueReceivers()){ r.silence(); } } public void connecting() { enableAll(); for (MoppyReceiver r : getUniqueReceivers()){ r.connecting(); } } public void disconnecting() { for (MoppyReceiver r : getUniqueReceivers()){ r.disconnecting(); } } public void sequenceStarting() { for (MoppyReceiver r : getUniqueReceivers()){ r.sequenceStarting(); } } public void sequenceStopping() { for (MoppyReceiver r : getUniqueReceivers()){ r.sequenceStopping(); } } }