-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #24 from kshoji/feature/add-inter-app-midi-support…
…-20240506 Add Inter-App MIDI support
- Loading branch information
Showing
5 changed files
with
1,020 additions
and
0 deletions.
There are no files selected for viewing
204 changes: 204 additions & 0 deletions
204
javax.sound.midi/src/jp/kshoji/javax/sound/midi/interapp/InterAppMidiDevice.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
package jp.kshoji.javax.sound.midi.interapp; | ||
|
||
import android.media.midi.MidiDeviceInfo; | ||
import android.media.midi.MidiInputPort; | ||
import android.media.midi.MidiOutputPort; | ||
import android.os.Build; | ||
import android.os.Bundle; | ||
import android.support.annotation.NonNull; | ||
import android.support.annotation.RequiresApi; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
import jp.kshoji.javax.sound.midi.MidiDevice; | ||
import jp.kshoji.javax.sound.midi.MidiUnavailableException; | ||
import jp.kshoji.javax.sound.midi.Receiver; | ||
import jp.kshoji.javax.sound.midi.Transmitter; | ||
|
||
/** | ||
* {@link jp.kshoji.javax.sound.midi.MidiDevice} implementation | ||
* | ||
* @author K.Shoji | ||
*/ | ||
public class InterAppMidiDevice implements MidiDevice { | ||
private final MidiDeviceInfo midiDeviceInfo; | ||
private final List<InterAppMidiReceiver> receivers = new ArrayList<>(); | ||
private final List<InterAppMidiTransmitter> transmitters = new ArrayList<>(); | ||
private boolean isOpened; | ||
|
||
/** | ||
* Constructor | ||
* | ||
* @param midiDevice the MIDI device | ||
*/ | ||
@RequiresApi(api = Build.VERSION_CODES.M) | ||
public InterAppMidiDevice(android.media.midi.MidiDevice midiDevice) { | ||
midiDeviceInfo = midiDevice.getInfo(); | ||
for (int i = 0; i < midiDeviceInfo.getInputPortCount(); i++) { | ||
// MidiInputPort: used for MIDI sending | ||
MidiInputPort midiInputPort = midiDevice.openInputPort(i); | ||
if (midiInputPort != null) { | ||
receivers.add(new InterAppMidiReceiver(midiInputPort)); | ||
} | ||
} | ||
|
||
for (int i = 0; i < midiDeviceInfo.getOutputPortCount(); i++) { | ||
// MidiOutputPort: used for MIDI receiving | ||
MidiOutputPort midiOutputPort = midiDevice.openOutputPort(i); | ||
if (midiOutputPort != null) { | ||
transmitters.add(new InterAppMidiTransmitter(midiOutputPort)); | ||
} | ||
} | ||
} | ||
|
||
@NonNull | ||
@Override | ||
public Info getDeviceInfo() { | ||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { | ||
Bundle properties = midiDeviceInfo.getProperties(); | ||
String name = properties.getString(MidiDeviceInfo.PROPERTY_NAME); | ||
if (name == null) { | ||
name = "(null)"; | ||
} | ||
String vendor = properties.getString(MidiDeviceInfo.PROPERTY_MANUFACTURER); | ||
if (vendor == null) { | ||
vendor = "(null)"; | ||
} | ||
String product = properties.getString(MidiDeviceInfo.PROPERTY_PRODUCT); | ||
if (product == null) { | ||
product = "(null)"; | ||
} | ||
String version = properties.getString(MidiDeviceInfo.PROPERTY_VERSION); | ||
if (version == null) { | ||
version = "(null)"; | ||
} | ||
return new MidiDevice.Info(name, vendor, product, version); | ||
} | ||
|
||
return new MidiDevice.Info("(null)", "(null)", "(null)", "(null)"); | ||
} | ||
|
||
@Override | ||
public void open() throws MidiUnavailableException { | ||
if (isOpened) { | ||
return; | ||
} | ||
|
||
synchronized (transmitters) { | ||
for (InterAppMidiTransmitter transmitter : transmitters) { | ||
if (transmitter != null) { | ||
transmitter.open(); | ||
} | ||
} | ||
} | ||
|
||
isOpened = true; | ||
} | ||
|
||
@Override | ||
public void close() { | ||
if (!isOpened) { | ||
return; | ||
} | ||
|
||
synchronized (transmitters) { | ||
for (InterAppMidiTransmitter transmitter : transmitters) { | ||
if (transmitter != null) { | ||
transmitter.close(); | ||
} | ||
} | ||
} | ||
|
||
synchronized (receivers) { | ||
for (InterAppMidiReceiver receiver : receivers) { | ||
if (receiver != null) { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||
receiver.onFlush(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
isOpened = false; | ||
} | ||
|
||
@Override | ||
public boolean isOpen() { | ||
return isOpened; | ||
} | ||
|
||
@Override | ||
public long getMicrosecondPosition() { | ||
return -1; | ||
} | ||
|
||
@Override | ||
public int getMaxReceivers() { | ||
return receivers.size(); | ||
} | ||
|
||
@Override | ||
public int getMaxTransmitters() { | ||
return transmitters.size(); | ||
} | ||
|
||
@NonNull | ||
@Override | ||
public Receiver getReceiver() throws MidiUnavailableException { | ||
synchronized (receivers) { | ||
for (InterAppMidiReceiver receiver : receivers) { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||
return receiver.getMidiReceiver(); | ||
} | ||
} | ||
} | ||
|
||
throw new MidiUnavailableException("Receiver not found"); | ||
} | ||
|
||
@NonNull | ||
@Override | ||
public List<Receiver> getReceivers() { | ||
final List<Receiver> result = new ArrayList<>(); | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||
synchronized (receivers) { | ||
for (InterAppMidiReceiver receiver : receivers) { | ||
if (receiver != null) { | ||
result.add(receiver.getMidiReceiver()); | ||
} | ||
} | ||
} | ||
} | ||
return Collections.unmodifiableList(result); | ||
} | ||
|
||
@NonNull | ||
@Override | ||
public Transmitter getTransmitter() throws MidiUnavailableException { | ||
synchronized (transmitters) { | ||
for (InterAppMidiTransmitter transmitter : transmitters) { | ||
if (transmitter != null) { | ||
return transmitter; | ||
} | ||
} | ||
} | ||
|
||
throw new MidiUnavailableException("Transmitter not found"); | ||
} | ||
|
||
@NonNull | ||
@Override | ||
public List<Transmitter> getTransmitters() { | ||
final List<Transmitter> result = new ArrayList<>(); | ||
synchronized (transmitters) { | ||
for (InterAppMidiTransmitter transmitter : transmitters) { | ||
if (transmitter != null) { | ||
result.add(transmitter); | ||
} | ||
} | ||
} | ||
return Collections.unmodifiableList(result); | ||
} | ||
} |
104 changes: 104 additions & 0 deletions
104
javax.sound.midi/src/jp/kshoji/javax/sound/midi/interapp/InterAppMidiReceiver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package jp.kshoji.javax.sound.midi.interapp; | ||
|
||
import android.media.midi.MidiInputPort; | ||
import android.media.midi.MidiReceiver; | ||
import android.os.Build; | ||
import android.support.annotation.NonNull; | ||
import android.support.annotation.RequiresApi; | ||
import android.util.Log; | ||
|
||
import java.io.IOException; | ||
import java.util.Arrays; | ||
|
||
import jp.kshoji.javax.sound.midi.MidiMessage; | ||
import jp.kshoji.javax.sound.midi.Receiver; | ||
|
||
/** | ||
* {@link jp.kshoji.javax.sound.midi.Receiver} implementation | ||
* | ||
* @author K.Shoji | ||
*/ | ||
@RequiresApi(api = Build.VERSION_CODES.M) | ||
public class InterAppMidiReceiver extends MidiReceiver { | ||
InterAppReceiver interAppReceiver; | ||
|
||
/** | ||
* Receiver used internally | ||
*/ | ||
private static class InterAppReceiver implements Receiver { | ||
MidiReceiver midiReceiver; | ||
|
||
/** | ||
* Constructor | ||
* | ||
* @param midiReceiver the MIDI Receiver | ||
*/ | ||
@RequiresApi(api = Build.VERSION_CODES.M) | ||
InterAppReceiver(MidiReceiver midiReceiver) { | ||
this.midiReceiver = midiReceiver; | ||
} | ||
|
||
@Override | ||
public void send(@NonNull MidiMessage message, long timeStamp) { | ||
try { | ||
byte[] midiMessage = message.getMessage(); | ||
if (midiMessage != null) { | ||
midiReceiver.onSend(midiMessage, 0, midiMessage.length, timeStamp); | ||
} | ||
} catch (IOException ignored) { | ||
} | ||
} | ||
|
||
private void send(byte[] midiMessage, long timeStamp) { | ||
try { | ||
if (midiMessage != null) { | ||
midiReceiver.onSend(midiMessage, 0, midiMessage.length, timeStamp); | ||
} | ||
} catch (IOException ignored) { | ||
} | ||
} | ||
|
||
@Override | ||
public void close() { | ||
} | ||
|
||
private void flush() { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||
try { | ||
midiReceiver.onFlush(); | ||
} catch (IOException ignored) { | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Constructor | ||
* | ||
* @param midiInputPort the MIDI input port | ||
*/ | ||
public InterAppMidiReceiver(MidiInputPort midiInputPort) { | ||
this.interAppReceiver = new InterAppReceiver(midiInputPort); | ||
} | ||
|
||
@Override | ||
public void onSend(byte[] midiMessage, int offset, int count, long timestamp) throws IOException { | ||
Log.i("InterAppMidiReceiver", "onSend message: " + Arrays.toString(midiMessage)); | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||
interAppReceiver.send(midiMessage, timestamp); | ||
} | ||
} | ||
|
||
@Override | ||
public void onFlush() { | ||
interAppReceiver.flush(); | ||
} | ||
|
||
/** | ||
* Obtains the Receiver instance | ||
* @return the Receiver instance | ||
*/ | ||
public Receiver getMidiReceiver() { | ||
return interAppReceiver; | ||
} | ||
} |
Oops, something went wrong.