001/*
002 * Title:        CoreMIDI4J
003 * Description:  Core MIDI Device Provider for Java on OS X
004 * Copyright:    Copyright (c) 2015-2016
005 * Company:      x.factory Librarians
006 *
007 * @author Derek Cook
008 * 
009 * CoreMIDI4J is an open source Service Provider Interface for supporting external MIDI devices on MAC OS X
010 * 
011 * CREDITS - This library uses principles established by OSXMIDI4J, but converted so it operates at the JNI level with no additional libraries required
012 * 
013 */
014
015package uk.co.xfactorylibrarians.coremidi4j;
016
017import javax.sound.midi.MidiDevice;
018import javax.sound.midi.MidiDeviceReceiver;
019import javax.sound.midi.MidiMessage;
020import java.util.concurrent.atomic.AtomicBoolean;
021
022/**
023 * CoreMidiReceiver - used to receive data from the application and send it to the connected device.
024 *
025 */
026
027public class CoreMidiReceiver implements MidiDeviceReceiver {
028
029  private final CoreMidiDestination device;
030  private final AtomicBoolean closed = new AtomicBoolean(false);
031
032
033  /**
034   * CoreMidiReceiver constructor
035   * 
036   * @param device      The MIDI device that contains the information required to send MIDI data via OSX core MIDI
037   */
038
039  CoreMidiReceiver(final CoreMidiDestination device) {
040
041    this.device = device;
042
043  }
044
045  /** 
046   * Sends a MIDI message
047   * 
048   * @see javax.sound.midi.Receiver#send(javax.sound.midi.MidiMessage, long)
049   * 
050   */
051
052  @Override
053  public void send(MidiMessage message, long timeStamp) {
054
055    if ( closed.get() == true ) {
056
057      throw new IllegalStateException("Can't call send() with a closed receiver");
058
059    }
060
061    if ( device.isOpen() == false ) {
062
063      throw new IllegalStateException("Can't call send with a receiver attached to a device that is not open: " + device);
064
065    }
066
067    try {
068
069      // Convert from Java-oriented port-relative microsecends to CoreMIDI-oriented boot-relative microseconds,
070      // and from signed Java semantics of -1 meaning now to unsigned CoreMIDI semantics of 0 meaning now.
071      final long coreTimestamp = (timeStamp == -1) ? 0 : timeStamp + device.getStartTime();
072
073      CoreMidiDeviceProvider.getOutputPort().send(((CoreMidiDeviceInfo)device.getDeviceInfo()).getEndPointReference(), message, coreTimestamp);
074
075    } catch (CoreMidiException e) {
076
077      e.printStackTrace();
078
079    }
080
081  }
082
083  /** 
084   * Closes the MIDI Receiver
085   * 
086   * @see javax.sound.midi.Receiver#close()
087   * 
088   */
089
090  @Override
091  public void close() {
092
093    if ( closed.compareAndSet(false, true) == true ) {
094
095      device.receiverClosed(this);
096
097    }
098
099  }
100
101  /**
102   * Gets the MIDI Device that this receiver is attached to
103   * 
104   * @return the MIDI Device that this receiver is attached to
105   * 
106   */
107
108  @Override
109  public MidiDevice getMidiDevice() {
110
111    return device;
112
113  }
114
115}