提供通过USB,蓝牙LE和虚拟(应用程序间)传输使用标准MIDI事件协议发送和接收消息的类。

一、概要

Android MIDI包允许用户:

1、将MIDI键盘连接到Android以播放合成器或驱动音乐应用程序。

2、将可选的MIDI控制器连接到Android。

3、从Android驱动外部MIDI合成器。

4、从Android驱动外部外设,灯光,显示控制等。

5、从游戏或音乐制作应用程序动态生成音乐。

6、在一个应用程序中生成MIDI消息并将其发送到第二个应用程序。

7、使用以外设模式运行的Android设备作为连接到笔记本电脑的多点触控控制器。

一)、API功能包括:

1、枚举当前可用的设备。 信息包括名称,供应商,能力等。

2、在MIDI设备插入或拔出时提供通知。

3、支持单个或多个短1-3字节MIDI消息的高效传输。

4、支持SysEx等任意长度数据的传输。

5、时间戳以避免抖动。

6、支持创建可连接到其他设备的虚拟MIDI设备。 一个例子可能是一个可由合成应用程序控制的合成器应用程序。

7、支持设备的直接连接或“修补”以降低延迟。

二)、传输支持

API是“传输不可知论”。 但目前有几种运输支持:

1、USB

2、软件路由

3、BTLE

二、Android MIDI术语

一)、术语

设备是具有零个或多个InputPorts和OutputPorts的具有MIDI能力的对象。

InputPort有16个通道,可以从OutputPort或应用程序接收MIDI消息。

OutputPort有16个通道,可以将MIDI信息发送到InputPort或应用程序。

MidiService是一个集中的过程,可以跟踪所有设备和经纪人之间的沟通。

MidiManager是应用程序或设备管理器调用与MidiService进行通信的类。

三、编写MIDI应用程序

一)、在清单中声明功能

需要MIDI API的应用程序应声明在AndroidManifest.xml文件中。 那么对于不支持MIDI API的旧设备,该应用不会出现在Play商店中。

<uses-feature android:name="android.software.midi" android:required="true"/>

二)、检查功能支持

应用程序还可以在运行时检查平台上是否支持MIDI功能。 当您直接在设备上安装应用程序时,这在开发过程中特别有用。

if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI)) {// do MIDI stuff
}

三)、MidiManager

访问MIDI包的主要类是通过MidiManager。

MidiManager m = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);

四)、获取已插入实体的列表

当应用程序启动时,它可以获得所有可用MIDI设备的列表。 该信息可以呈现给用户,允许他们选择一个设备。

MidiDeviceInfo[] infos = m.getDevices();

五)、通知MIDI设备HotPlug事件

例如,当插入或拔出键盘时,应用程序可以请求通知。

m.registerDeviceCallback(new MidiManager.DeviceCallback() {public void onDeviceAdded( MidiDeviceInfo info ) {...}public void onDeviceRemoved( MidiDeviceInfo info ) {...}});

六)、设备和端口信息

您可以查询输入和输出端口的数量。

int numInputs = info.getInputPortCount();
int numOutputs = info.getOutputPortCount();

注意,“输入”和“输出”是从设备的角度出发的。 因此,合成器将具有接收消息的“输入”端口。 键盘将有一个“输出”端口发送消息。

MidiDeviceInfo有一组属性。

Bundle properties = info.getProperties();
String manufacturer = properties.getString(MidiDeviceInfo.PROPERTY_MANUFACTURER);

其他资源包括PROPERTY_PRODUCT,PROPERTY_NAME,PROPERTY_SERIAL_NUMBER

您可以从PortInfo对象获取端口的名称和类型。 类型将是TYPE_INPUT或TYPE_OUTPUT。

MidiDeviceInfo.PortInfo[] portInfos = info.getPorts();
String portName = portInfos[0].getName();
if (portInfos[0].getType() == MidiDeviceInfo.PortInfo.TYPE_INPUT) {...
}

七)、打开MIDI设备

要访问MIDI设备,您需要先打开它。 open是异步的,所以你需要提供一个回调来完成。 如果要在特定线程上发生回调,可以指定可选的处理程序。

m.openDevice(info, new MidiManager.OnDeviceOpenedListener() {@Overridepublic void onDeviceOpened(MidiDevice device) {if (device == null) {Log.e(TAG, "could not open device " + info);} else {...}}, new Handler(Looper.getMainLooper()));

八)、打开MIDI输入端口

如果要将信息发送到MIDI设备,则需要打开具有独占访问权限的“输入”端口。

MidiInputPort inputPort = device.openInputPort(index);

九)、发送一个NoteOn

MIDI消息作为字节数组发送。 在这里我们编码一个注释消息。

byte[] buffer = new byte[32];
int numBytes = 0;
int channel = 3; // MIDI channels 1-16 are encoded as 0-15.
buffer[numBytes++] = (byte)(0x90 + (channel - 1)); // note on
buffer[numBytes++] = (byte)60; // pitch is middle C
buffer[numBytes++] = (byte)127; // max velocity
int offset = 0;
// post is non-blocking
inputPort.send(buffer, offset, numBytes);

有时可以方便地发送带有时间戳的MIDI信息。 通过调度将来的事件,我们可以掩盖调度抖动。 Android MIDI时间戳基于单调纳秒系统定时器。 这与其他音频和输入定时器一致。

在这里,我们将来发送一个时间戳为2秒的消息。

final long NANOS_PER_SECOND = 1000000000L;
long now = System.nanoTime();
long future = now + (2 * NANOS_PER_SECOND);
inputPort.send(buffer, offset, numBytes, future);

如果要取消以后安排的事件,请调用flush()。

inputPort.flush(); // discard events

如果缓冲区中有任何MIDI NoteOff消息,那么它们将被丢弃,您可能会收到卡纸。 所以我们建议在进行冲水后发送“所有音符关闭”。

十)、接收一个Note

要从设备接收MIDI数据,您需要扩展MidiReceiver。 然后将您的接收机连接到设备的输出端口。

class MyReceiver extends MidiReceiver {public void onSend(byte[] data, int offset,int count, long timestamp) throws IOException {// parse MIDI or whatever}
}
MidiOutputPort outputPort = device.openOutputPort(index);
outputPort.connect(new MyReceiver());

到达的数据不会以任何特定的方式进行验证或对齐。 它是原始的MIDI数据,可以包含多个消息或部分消息。 它可能包含系统实时消息,可以在其他消息中进行交织。

四、创建MIDI虚拟设备服务

一个应用程序可以提供可由其他应用程序使用的MIDI服务。 例如,应用程序可以提供其他应用程序可以发送消息的自定义合成器。 该服务必须通过“android.permission.BIND_MIDI_DEVICE_SERVICE”的许可进行保护。

一)、清单文件

一个应用程序声明它将在AndroidManifest.xml文件中用作MIDI服务器。

<service android:name="MySynthDeviceService"android:permission="android.permission.BIND_MIDI_DEVICE_SERVICE"><intent-filter><action android:name="android.media.midi.MidiDeviceService" /></intent-filter><meta-data android:name="android.media.midi.MidiDeviceService"android:resource="@xml/synth_device_info" />
</service>

此示例中的资源的详细信息存储在“res / xml / synth_device_info.xml”中。 您在此文件中声明的端口名称将可从PortInfo.getName()获得。

<devices><device manufacturer="MyCompany" product="MidiSynthBasic"><input-port name="input" /></device>
</devices>

二)、扩展MidiDeviceService

然后,通过扩展android.media.midi.MidiDeviceService来定义服务器。 假设你有一个扩展MidiReceiver的MySynthEngine类。

import android.media.midi.MidiDeviceService;
import android.media.midi.MidiDeviceStatus;
import android.media.midi.MidiReceiver;public class MidiSynthDeviceService extends MidiDeviceService {private static final String TAG = "MidiSynthDeviceService";private MySynthEngine mSynthEngine = new MySynthEngine();private boolean synthStarted = false;@Overridepublic void onCreate() {super.onCreate();}@Overridepublic void onDestroy() {mSynthEngine.stop();super.onDestroy();}@Override// Declare the receivers associated with your input ports.public MidiReceiver[] onGetInputPortReceivers() {return new MidiReceiver[] { mSynthEngine };}/*** This will get called when clients connect or disconnect.* You can use it to turn on your synth only when needed.*/@Overridepublic void onDeviceStatusChanged(MidiDeviceStatus status) {if (status.isInputPortOpen(0) && !synthStarted) {mSynthEngine.start();synthStarted = true;} else if (!status.isInputPortOpen(0) && synthStarted){mSynthEngine.stop();synthStarted = false;}}
}

五、在蓝牙LE上使用MIDI

MIDI设备可以使用蓝牙LE连接到Android。

在使用设备之前,应用程序必须扫描可用的BTLE设备,然后允许用户连接。 将提供一个示例程序,以便在Android开发者网站上查找。

一)、请求BTLE的位置许可

扫描蓝牙设备的应用程序必须在清单文件中请求许可。 需要此LOCATION权限,因为可能会通过查看附近的BTLE设备来猜测Android设备的位置。

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

应用程序还必须在运行时请求用户的位置许可。 有关详细信息和示例,请参阅Activity.requestPermissions()的文档。

二)、扫描MIDI设备

该应用程序只想看到MIDI设备,而不是鼠标或其他非MIDI设备。 因此,使用UUID构建一个ScanFilter,用于基于BTLE的标准MIDI。

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

三)、打开一个MIDI蓝牙设备

有关详细信息,请参阅android.bluetooth.le.BluetoothLeScanner.startScan()方法的文档。 当用户选择MIDI / BTLE设备时,您可以使用MidiManager打开它。

m.openBluetoothDevice(bluetoothDevice, callback, handler);

一旦MIDI / BTLE设备被一个应用程序打开,那么也可以使用上述MIDI设备发现调用对其他应用程序使用。

接口

MidiManager.OnDeviceOpenedListener

用于接收openDevice(MidiDeviceInfo,MidiManager.OnDeviceOpenedListener,Handler)和openBluetoothDevice(BluetoothDevice,MidiManager.OnDeviceOpenedListener,Handler)的结果的侦听器类

MidiDevice

此类用于从MIDI设备发送和接收数据此类的实例由openDevice(MidiDeviceInfo,MidiManager.OnDeviceOpenedListener,Handler)创建。

MidiDevice.MidiConnection

该类表示一个设备的输出端口和另一个设备的输入端口之间的连接。

MidiDeviceInfo

该课程包含描述MIDI设备的信息。

MidiDeviceInfo.PortInfo

包含有关输入或输出端口的信息。

MidiDeviceService

实现虚拟MIDI设备的服务。

MidiDeviceStatus

这是描述MIDI设备端口的当前状态的不可变类。

MidiInputPort

该类用于将数据发送到MIDI设备上的端口

MidiManager

这个类是MIDI服务的公共应用程序界面。

MidiManager.DeviceCallback

用于客户端接收MIDI设备的Callback类添加和删除通知

MidiOutputPort

此类用于从MIDI设备上的端口接收数据

MidiReceiver

用于向MIDI设备发送和接收数据的接口。

MidiSender

由设备提供的接口,可以将MIDI接收器连接到MIDI设备。

Android音视频API(android.media.midi):概览相关推荐

  1. Android音视频API - MediaCodec/MediaMuxer/MediaStore/MediaController等

    AudioTrack播放音频PCM.[Android] 混音器AudioMixer. MediaPlayer/MediaRecorder, AudioTrack/AudioRecorder, Medi ...

  2. android 音视频 教程,Android移动端音视频的快速开发教程(九)

    4.6. 私聊函数 4.6.1. 更改当前的聊天模式 INT ChangeChatMode(INT ChatMode); 功能:更改本身的聊天模式(默认为公聊模式) 返回值:0表示成功,不然为出错代码 ...

  3. Android音视频入门及架构介绍

    一.多媒体基础 音视频格式 一个视频文件的格式由封装格式+音频码流格式+视频码流格式+字幕流组成. 如下为一个视频文件的信息,是asf封装的wmav2音频+mpeg4视频. 常用的视频格式 MPEG系 ...

  4. 推荐几个堪称教科书级别的 Android 音视频入门项目

    公众号回复:OpenGL,领取学习资源大礼包 在 直播 中有提到几个不错的开源项目,这里再重点推荐一下: 目前,市面上关于音视频学习的相关书籍并不多,而且即使看了书籍学了理论,最终还是要回归到代码上来 ...

  5. Android音视频编辑库,Android音视频处理.pdf

    Android音视频处理 Android 视频处理 沈青海 admin@3 Copyright 2008-2009 Farsight. All rights reserved. 频处理 } Media ...

  6. Android音视频 - 学习路线概览

    PS 我们上一个系列 - OpenGL ES 暂告一段落,如果你对相机滤镜感兴趣,可以参看之前的文章. 从本篇开始呢,开始记录Android音视频的相关知识. 学习路线概览 Android音视频的基础 ...

  7. Android音视频开发基础(七):视频采集-系统API基础

    前言 在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了<Android 音视频从入门到提高 - 任务列表>.本文是Android音视 ...

  8. Android音视频开发基础(六):学习MediaCodec API,完成视频H.264的解码

    前言 在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了<Android 音视频从入门到提高 - 任务列表>.本文是Android音视 ...

  9. android音视频指南-支持的媒体格式

    android音视频指南-支持的媒体格式 本文描述了Android平台提供的媒体编解码器.容器和网络协议支持. 作为应用程序开发人员,您可以使用任何可以在任何Android设备上使用的媒体编解码器,包 ...

最新文章

  1. python绝对值编程_Python-abs vs fabs
  2. c++如何获取文件时间_Linux下如何删除长时间不使用的旧文件?
  3. python programming training(三):搜索算法
  4. OpneCV3——使用SURF、SVM、BOW对图像进行分类
  5. 后端数据操作超时_数据分析在知乎商业质量保障中的初步实践
  6. oracle节点1关闭节点2的集群,[Oracle] Oracle两个节点分裂,识别不到对方节点的状态...
  7. 全网最简单明了的MySQL连接Eclipse方法(JDBC详细安装方式及简单操作)2020新版
  8. C#的两种类据类型:值类型和引用类型
  9. Linux vim编写编译运行一个.c文件(centeos 8 HelloWorld.c)
  10. 解决vue2.0路由 TypeError: Cannot read property ‘matched‘ of undefined 的错误问题
  11. linux开启权限继承,linux的一个权限问题(权限继承)
  12. 7个示例科普CPU CACHE(zz)
  13. 中兴网络设备交换机路由器查看日志命令方法
  14. photoshop7.0绿色迷你免安装版
  15. 时间序列可预测性度量
  16. php 月份英文缩写,php如何实现月份转换
  17. gazebo中视觉仿真怎么使用自定义贴图的问题
  18. 【懒懒的Python学习笔记八】
  19. Redis Java客户端的选择
  20. 新能源硫酸钠溶液除镍钴锰分离树脂技术

热门文章

  1. 万象物语老显示服务器繁忙,万象物语敌方状态简析 细数麻烦的异常状态
  2. scratch魔法星空 电子学会图形化编程scratch等级考试二级真题和答案解析2022年3月
  3. 在html中加下划线
  4. 高性能网页开发的14条军规
  5. SQL SERVER 查询作业(Job)基本信息及执行情况的sql
  6. 《ありがとう》中文名《感谢》
  7. 银联商户号变更及证书更新
  8. 【Web技术】624- redux、mobx、concent 状态管理方案对比
  9. non-Boost Asio 笔记: UDP UART SocketCAN Multicast UDS
  10. [人机界面]昆仑通态TPC7022Ex的工程环境搭建与工程的下载步骤详析