diff --git a/media/java/android/media/midi/package.html b/media/java/android/media/midi/package.html index 67df1b2fa3157..d9e38e20f9bad 100644 --- a/media/java/android/media/midi/package.html +++ b/media/java/android/media/midi/package.html @@ -267,6 +267,56 @@ raw MIDI data and can contain multiple messages or partial messages. It might contain System Real-Time messages, which can be interleaved inside other messages.

+

Using MIDI Over Bluetooth LE

+ +

MIDI devices can be connected to Android using Bluetooth LE.

+ +

Before using the device, the app must scan for available BTLE devices and then allow +the user to connect. +See the Android developer website for an +example +program.

+ +

Request Location Permission for BTLE

+ +

Applications that scan for Bluetooth devices must request permission in the +manifest file. This LOCATION permission is required because it may be possible to +guess the location of an Android device by seeing which BTLE devices are nearby.

+ +
+<uses-permission android:name="android.permission.BLUETOOTH"/>
+<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+
+ +

Apps must also request location permission from the user at run-time. +See the documentation for Activity.requestPermissions() for details and an example. +

+ +

Scan for MIDI Devices

+ +

The app will only want to see MIDI devices and not mice or other non-MIDI devices. +So construct a ScanFilter using the UUID for standard MIDI over BTLE.

+ +
+MIDI over BTLE UUID = "03B80E5A-EDE8-4B33-A751-6CE34EC4C700"
+
+ +

Open a MIDI Bluetooth Device

+ +

See the documentation for android.bluetooth.le.BluetoothLeScanner.startScan() +method for details. When the user selects a MIDI/BTLE device then you can open it +using the MidiManager.

+ +
+m.openBluetoothDevice(bluetoothDevice, callback, handler);
+
+ +

Once the MIDI/BTLE device has been opened by one app then it will also become available to other +apps using the +MIDI device discovery calls described above. +

+

Creating a MIDI Virtual Device Service

@@ -355,62 +405,17 @@ public class MidiSynthDeviceService extends MidiDeviceService { } -

Using MIDI Over Bluetooth LE

-

MIDI devices can be connected to Android using Bluetooth LE.

+

Using MIDI 2.0

-

Before using the device, the app must scan for available BTLE devices and then allow -the user to connect. -See the Android developer website for an -example -program.

- -

Request Location Permission for BTLE

- -

Applications that scan for Bluetooth devices must request permission in the -manifest file. This LOCATION permission is required because it may be possible to -guess the location of an Android device by seeing which BTLE devices are nearby.

- -
-<uses-permission android:name="android.permission.BLUETOOTH"/>
-<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
-<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
-
- -

Apps must also request location permission from the user at run-time. -See the documentation for Activity.requestPermissions() for details and an example. -

- -

Scan for MIDI Devices

- -

The app will only want to see MIDI devices and not mice or other non-MIDI devices. -So construct a ScanFilter using the UUID for standard MIDI over BTLE.

- -
-MIDI over BTLE UUID = "03B80E5A-EDE8-4B33-A751-6CE34EC4C700"
-
- -

Open a MIDI Bluetooth Device

- -

See the documentation for android.bluetooth.le.BluetoothLeScanner.startScan() -method for details. When the user selects a MIDI/BTLE device then you can open it -using the MidiManager.

- -
-m.openBluetoothDevice(bluetoothDevice, callback, handler);
-
- -

Once the MIDI/BTLE device has been opened by one app then it will also become available to other -apps using the -MIDI device discovery calls described above. -

- -

Using MIDI 2.0 over USB

- -

An app can use MIDI 2.0 over USB starting in Android T. MIDI 2.0 packets are embedded in +

An app can use MIDI 2.0 over USB starting in Android T. MIDI 2.0 packets are embedded in Universal MIDI Packets, or UMP for short. A MIDI 2.0 USB device should create two interfaces, one endpoint that accepts only MIDI 1.0 packets and one that accepts only UMP packets. -For more info about MIDI 2.0 and UMP, please read the MIDI 2.0 USB spec.

+For more info about MIDI 2.0 and UMP, please read the MIDI 2.0 and UMP spec. Starting from Android +V, apps can also open MIDI 2.0 virtual +devices.

MidiManager.getDevices() would simply return the 1.0 interface. This interface should work exactly the same as before. In order to use the new UMP interface, retrieve the device with the @@ -421,15 +426,15 @@ Collection<MidiDeviceInfo> universalDeviceInfos = midiManager.getDevices MidiManager.TRANSPORT_UNIVERSAL_MIDI_PACKETS); -

UMP Packets are always in multiple of 4 bytes. For each set of 4 bytes, they are sent in network -order. Compare the following NoteOn code snippet with the NoteOn code snippet above.

+

UMP packet sizes are always a multiple of 4 bytes. For each set of 4 bytes, they are sent in +network order. Compare the following NoteOn code snippet with the NoteOn code snippet above.

 byte[] buffer = new byte[32];
 int numBytes = 0;
 int channel = 3; // MIDI channels 1-16 are encoded as 0-15.
 int group = 0;
-buffer[numBytes++] = (byte)(0x20 + group); // MIDI 1.0 voice message
+buffer[numBytes++] = (byte)(0x20 + group); // MIDI 1.0 Channel Voice Message
 buffer[numBytes++] = (byte)(0x90 + (channel - 1)); // note on
 buffer[numBytes++] = (byte)60; // pitch is middle C
 buffer[numBytes++] = (byte)127; // max velocity
@@ -446,5 +451,108 @@ For a MidiDeviceInfo, you can query the defaultProtocol.

int defaultProtocol = info.getDefaultProtocol();
+

Creating a MIDI 2.0 Virtual Device Service

+ + +

Starting in Android V, an app can provide a MIDI 2.0 Service that can be used by other apps. +MIDI 2.0 packets are embedded in Universal MIDI Packets, or UMP for short. The service must be +guarded with permission "android.permission.BIND_MIDI_DEVICE_SERVICE".

+ +

Manifest Files

+ + +

An app declares that it will function as a MIDI server in the AndroidManifest.xml file. Unlike +MIDI 1.0 virtual devices, android.media.midi.MidiUmpDeviceService is used

+ +
+<service android:name="MidiEchoDeviceService"
+  android:permission="android.permission.BIND_MIDI_DEVICE_SERVICE">
+  <intent-filter>
+    <action android:name="android.media.midi.MidiUmpDeviceService" />
+  </intent-filter>
+  <meta-data android:name="android.media.midi.MidiUmpDeviceService"
+      android:resource="@xml/echo_device_info" />
+</service>
+
+ + +

The details of the resource in this example is stored in “res/xml/echo_device_info.xml +”. The port names that you declare in this file will be available from PortInfo.getName(). +Unlike MIDI 1.0, MIDI 2.0 ports are bidirectional. If you declare a port in this service, then it +automatically creates an input port and an output port with the same name. Clients can use those +two ports like the MIDI 1.0 ports.

+ +
+<devices>
+    <device manufacturer="MyCompany" product="MidiEcho">
+        <port name="port1" />
+    </device>
+</devices>
+
+ + +

Extend MidiUmpDeviceService

+ + +

You then define your server by extending android.media.midi.MidiUmpDeviceService.

+ +
+import android.media.midi.MidiDeviceStatus;
+import android.media.midi.MidiReceiver;
+import android.media.midi.MidiUmpDeviceService;
+
+public class MidiEchoDeviceService extends MidiUmpDeviceService {
+    private static final String TAG = "MidiEchoDeviceService";
+    // Other apps will write to this port.
+    private MidiReceiver mInputReceiver = new MyReceiver();
+    // This app will copy the data to this port.
+    private MidiReceiver mOutputReceiver;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+    }
+
+    @Override
+    // Declare the receivers associated with your input ports.
+    public List onGetInputPortReceivers() {
+        return new ArrayList(Collections.singletonList(mInputReceiver));
+    }
+
+    /**
+     * Sample receiver to echo from the input port to the output port.
+     * In this example, we are just echoing the data and not parsing it.
+     * You will probably want to convert the bytes to a packet and then interpret the packet.
+     * See the MIDI 2.0 spec at the MMA site. Packets are either 4, 8, 12 or 16 bytes.
+     */
+    class MyReceiver extends MidiReceiver {
+        @Override
+        public void onSend(byte[] data, int offset, int count, long timestamp)
+                throws IOException {
+            if (mOutputReceiver == null) {
+                mOutputReceiver = getOutputPortReceivers().get(0);
+            }
+            // Copy input to output.
+            mOutputReceiver.send(data, offset, count, timestamp);
+        }
+    }
+
+    /**
+     * This will get called when clients connect or disconnect.
+     * You can use it to figure out how many devices are connected.
+     */
+    @Override
+    public void onDeviceStatusChanged(MidiDeviceStatus status) {
+        // inputOpened = status.isInputPortOpen(0);
+        // outputOpenCount = status.getOutputPortOpenCount(0);
+    }
+}
+
+