package jp.kshoji.javax.sound.midi;
import android.content.Context;
import android.support.annotation.NonNull;
import java.util.HashMap;
import java.util.Map;
import jp.kshoji.blemidi.central.BleMidiCentralProvider;
import jp.kshoji.blemidi.device.MidiInputDevice;
import jp.kshoji.blemidi.device.MidiOutputDevice;
import jp.kshoji.blemidi.listener.OnMidiDeviceAttachedListener;
import jp.kshoji.blemidi.listener.OnMidiDeviceDetachedListener;
import jp.kshoji.blemidi.peripheral.BleMidiPeripheralProvider;
import jp.kshoji.blemidi.util.BleUtils;
import jp.kshoji.javax.sound.midi.ble.BleMidiDevice;
/**
* {@link jp.kshoji.javax.sound.midi.MidiSystem} initializer for BLE MIDI
*
* @author K.Shoji
*/
public final class BleMidiSystem implements OnMidiDeviceAttachedListener, OnMidiDeviceDetachedListener {
private static BleMidiPeripheralProvider peripheralProvider;
private static BleMidiCentralProvider centralProvider;
private static final Map<String, BleMidiDevice> midiDeviceMap = new HashMap<>();
private final Context context;
/**
* Constructor
*
* @param context the context
*/
public BleMidiSystem(@NonNull Context context) {
this.context = context.getApplicationContext();
}
/**
* Initializes {@link jp.kshoji.javax.sound.midi.MidiSystem}
*/
public void initialize() {
if (BleUtils.isBleSupported(context)) {
if (BleUtils.isBlePeripheralSupported(context)) {
peripheralProvider = new BleMidiPeripheralProvider(context);
peripheralProvider.setOnMidiDeviceAttachedListener(this);
}
centralProvider = new BleMidiCentralProvider(context);
centralProvider.setOnMidiDeviceAttachedListener(this);
}
}
/**
* Terminates {@link jp.kshoji.javax.sound.midi.MidiSystem}
*/
public void terminate() {
stopAdvertising();
stopScanDevice();
if (centralProvider != null) {
centralProvider.terminate();
centralProvider = null;
}
if (peripheralProvider != null) {
peripheralProvider.terminate();
peripheralProvider = null;
}
synchronized (midiDeviceMap) {
for (BleMidiDevice bleMidiDevice : midiDeviceMap.values()) {
bleMidiDevice.close();
}
midiDeviceMap.clear();
}
}
/**
* Start to scan BLE MIDI devices
*/
public void startScanDevice() {
if (centralProvider != null) {
centralProvider.startScanDevice(0);
}
}
/**
* Stop to scan BLE MIDI devices
*/
public void stopScanDevice() {
if (centralProvider != null) {
centralProvider.stopScanDevice();
}
}
/**
* Starts BLE MIDI advertising
*/
public void startAdvertising() {
if (peripheralProvider != null) {
peripheralProvider.startAdvertising();
}
}
/**
* Stops BLE MIDI advertising
*/
public void stopAdvertising() {
if (peripheralProvider != null) {
peripheralProvider.stopAdvertising();
}
}
@Override
public void onMidiInputDeviceAttached(@NonNull MidiInputDevice midiInputDevice) {
synchronized (midiDeviceMap) {
BleMidiDevice existingDevice = midiDeviceMap.get(midiInputDevice.getDeviceAddress());
if (existingDevice != null) {
existingDevice.setMidiInputDevice(midiInputDevice);
MidiSystem.addMidiDevice(existingDevice);
} else {
BleMidiDevice midiDevice = new BleMidiDevice(midiInputDevice, null);
midiDeviceMap.put(midiInputDevice.getDeviceAddress(), midiDevice);
MidiSystem.addMidiDevice(midiDevice);
}
}
}
@Override
public void onMidiOutputDeviceAttached(@NonNull MidiOutputDevice midiOutputDevice) {
synchronized (midiDeviceMap) {
BleMidiDevice existingDevice = midiDeviceMap.get(midiOutputDevice.getDeviceAddress());
if (existingDevice != null) {
existingDevice.setMidiOutputDevice(midiOutputDevice);
MidiSystem.addMidiDevice(existingDevice);
} else {
BleMidiDevice midiDevice = new BleMidiDevice(null, midiOutputDevice);
midiDeviceMap.put(midiOutputDevice.getDeviceAddress(), midiDevice);
MidiSystem.addMidiDevice(midiDevice);
}
}
}
@Override
public void onMidiInputDeviceDetached(@NonNull MidiInputDevice midiInputDevice) {
synchronized (midiDeviceMap) {
BleMidiDevice existingDevice = midiDeviceMap.get(midiInputDevice.getDeviceAddress());
if (existingDevice != null) {
existingDevice.setMidiInputDevice(null);
if (existingDevice.getMidiOutputDevice() == null) {
// both of devices are disconnected
midiDeviceMap.remove(midiInputDevice.getDeviceAddress());
MidiSystem.removeMidiDevice(existingDevice);
}
}
}
}
@Override
public void onMidiOutputDeviceDetached(@NonNull MidiOutputDevice midiOutputDevice) {
synchronized (midiDeviceMap) {
BleMidiDevice existingDevice = midiDeviceMap.get(midiOutputDevice.getDeviceAddress());
if (existingDevice != null) {
existingDevice.setMidiOutputDevice(null);
if (existingDevice.getMidiInputDevice() == null) {
// both of devices are disconnected
midiDeviceMap.remove(midiOutputDevice.getDeviceAddress());
MidiSystem.removeMidiDevice(existingDevice);
}
}
}
}
}