Network MIDI on iOS - Part 1

 
This is an app I wrote to try out some ideas for networked MIDI on iPhone and iPad. It connects to a host computer running OS X Tiger or later (see the documentation for Apple's Audio MIDI Setup application), or any compatible RTP MIDI host such as rtpMIDI for Windows.
 
I will discuss the implementation details in further blog posts, as it introduces some useful concepts such as:
  • Composing outgoing MIDI data in response to user input
  • Processing incoming MIDI data in real time (with semaphores and lock free buffers)
  • Finding network services with Bonjour
For now, here's the source code.
Updated project for iOS 5.1 - 6 using ARC:

XCode 4.51 Project (MediaFire download)

Updated project for iOS 7 (should work back to iOS 5.1):


Please note you need to run this on a device rather than the simulator.

(Now seems to work OK on the iOS 7 simulator at least).

Network MIDI on iOS - Part 2

 

In this part, I will discuss finding and publishing network MIDI services using Bonjour, and creating the MIDI client using the CoreMIDI API. The source code for this project is available for download in
Part 1 of this article.

The network MIDI services in OS X and iOS can be discovered in the same way as any other Bonjour service. In the initialiser of the MIDIController class (see MIDIController.m) an instance of
NSNetServiceBrowser is created, and instructed to search for services of the type MIDINetworkBonjourServiceType i.e. @"_apple-midi._udp". By implementing the delegate protocol for this browser, a MIDIController instance can monitor available services of
this type on the network.

These services are exposed to the remainder of the application as a dictionary. In addition, various operations are provided to allow connection, disconnection etc. (see the section marked "Connection Management" in the implementation for details). The sample
application uses these methods to provide a simple UI to connect to any detected services. The settings page is displayed by flipping the main view. From here, we can select one or more of the remote MIDI services available on the current LAN.

 

Note that connections can also be made from the other end. By opening Audio MIDI Setup on a Mac on the same LAN, we can browse to the iPhone and initiate a connection from the computer. In this instance, the MIDIController instance will inform the UI that a
connection has been made via an NSNotification. If multiple connections are made to or from the same device, they are bridged in that:

  • All incoming data from the network is merged as if it was coming from a single device
  • Outgoing data from the device is sent to all network services
The settings view also allows the user to set the MIDI channel on which messages will be sent in response to actions from the main UI views. This is similarly the channel on which the app will listen for incoming MIDI commands.

The MIDIController initialiser also sets up the shared MIDINetworkSession instance, which acts as a bridge between the network services and the CoreMIDI API. A MIDI client, input port and output port are then created. The input port is connected to the source endpoint of the MIDINetworkSession instance. Note
that these endpoints are named from the perspective of the iOS application; the "source" endpoint is where data will be received from the network, and the "destination" endpoint is where the application will send data to the network.

To send data to the output port once a connection has been made, the app invokes the methods in the section marked Sending in the implementation file, namely:

-(void) allNotesOffOnChannel:(NSUInteger)channel;
-(void) sendChangeForController:(NSUInteger)controller onChannel:(NSUInteger)channel withValue:(NSUInteger)value;
-(void) sendNote:(NSUInteger)note on:(BOOL)on onChannel:(NSUInteger)channel withVelocity:(NSUInteger)velocity;
-(void) sendMMCCommand:(NSUInteger)command toDevice:(NSUInteger)device;

Internally, these use the writeMIDIPacket methods to construct a MIDIPacketList and send it via the output port created above to the MIDINetworkSession's destinationEndpoint. Care should be taken to construct the packet lists correctly, as sending garbage
data (for instance where the packet count is set too high) will typically result in disconnection by the remote service.
The sendChangeForController:onChannel:withValue: method is invoked in response to user input from the controller tab:

The sendNote:on:onChannel:withVelocity: method is invoked when the user presses the "keys" on the Notes tab:

The sendMMCCommand:toDevice: method is invoked in response to button presses on the MMC tab:

Please note that the MMC command output hasn't been tested as I don't have any devices that respond to this part of the MIDI protocol. Let me know via the comments if you have any problems.

The operation of the input port is described in Part 3 of this article.

Network MIDI on iOS - Part 3

 

In this part I will discuss how incoming MIDI is received into the application and subsequently processed. The source code for this project is available for download in
Part 1 of this article.

The MIDI controller class (see MIDIController.h) provides a formal protocol, MIDIReceivedDelegate, and a corresponding delegate property. This defines the following methods:

- (void) midiControllerUpdated:(Byte)controller onChannel:(Byte)channel toValue:(Byte)value;
- (void) midiNoteOnOff:(Byte)note onChannel:(Byte)channel withVelocity:(Byte)velocity on:(BOOL)on;

These methods encapsulate the complexity of receiving MIDI data - but how is this accomplished behind the scenes?

When we created the MIDI client in part 2 of this article, we also created a MIDI input port. This was passed a pointer to a callback function, MIDIInputReadProc. This callback function is called by the operating system when MIDI data is received at the port.
As a real time callback function which may be re-entrant when the system is under load, certain restrictions should be adhered to. In particular, this function should avoid:

  • Allocating and deallocating memory
  • Acquiring locks
  • Performing lengthy operations

The function walks the list of MIDI packets received as follows:

For each MIDI packet received:

  • The packet's length and data are written into a structured circular buffer (see MIDIPacketBuffer.h)
  • A Mach semaphore is incremented to signal the rest of the application that another packet is available for processing.

Note that the structured buffer in this example disregards the timestamp of the MIDI packet. This will be covered in a later example.

Another thread (see midiInputThreadProc) waits on this semaphore. If the semaphore is signalled, the length of the next MIDI packet is retrieved from the circular buffer, and then that amount of data is copied into a regular buffer.

This data is then parsed from this buffer. The following MIDI commands are identified in this example:

  • Control changes
  • Note on/off
Other commands are discarded. When a recognised command is received, Grand Central Dispatch is used to enqueue a block that will invoke the controller's delegate asynchronously on the main queue. The delegate will then respond to the invocation and perform any necessary UI updates etc.

By these means, the application decouples the processing of MIDI data from its receipt, and conforms with the requirements placed on it by the CoreMIDI port model

The Stereo Action Dimension的更多相关文章

  1. 强化学习_PolicyGradient(策略梯度)_代码解析

    使用策略梯度解决离散action space问题. 一.导入包,定义hyper parameter import gym import tensorflow as tf import numpy as ...

  2. Java基础之处理事件——使用动作Action(Sketcher 6 using Action objects)

    控制台程序. 动作Action是任何实现了javax.swing.Action接口的类的对象.这个接口声明了操作Action对象的方法,例如,存储与动作相关的属性.启用和禁用动作.Action接口扩展 ...

  3. 微软BI 之SSIS 系列 - 数据仓库中实现 Slowly Changing Dimension 缓慢渐变维度的三种方式

    开篇介绍 关于 Slowly Changing Dimension 缓慢渐变维度的理论概念请参看 数据仓库系列 - 缓慢渐变维度 (Slowly Changing Dimension) 常见的三种类型 ...

  4. 【论文笔记】Spatial Temporal Graph Convolutional Networks for Skeleton-Based Action Recognition

    Spatial Temporal Graph Convolutional Networks for Skeleton-Based Action Recognition 2018-01-28  15:4 ...

  5. [libGDX游戏开发教程]使用libGDX进行游戏开发(12)-Action动画

    前文章节列表:  使用libGDX进行游戏开发(11)-高级编程技巧   使用libGDX进行游戏开发(10)-音乐音效不求人,程序员也可以DIY   使用libGDX进行游戏开发(9)-场景过渡   ...

  6. redux-amrc:用更少的代码发起异步 action

    很多人说 Redux 代码多,开发效率低.其实 Redux 是可以灵活使用以及拓展的,经过充分定制的 Redux 其实写不了几行代码.今天先介绍一个很好用的 Redux 拓展-- redux-amrc ...

  7. 尝试asp.net mvc 基于controller action 方式权限控制方案可行性

    微软在推出mvc框架不久,短短几年里,版本更新之快,真是大快人心,微软在这种优秀的框架上做了大量的精力投入,是值得赞同的,毕竟程序员驾驭在这种框架上,能够强力的精化代码,代码层次也更加优雅,扩展较为方 ...

  8. ASP.NET Core 中文文档 第四章 MVC(4.1)Controllers, Actions 和 Action Results

    原文:Controllers, Actions, and Action Results 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:许登洋(Seay) Action 和 acti ...

  9. java中Action层、Service层和Dao层的功能区分

    Action/Service/DAO简介: Action是管理业务(Service)调度和管理跳转的. Service是管理具体的功能的. Action只负责管理,而Service负责实施. DAO只 ...

随机推荐

  1. [JWFD开源工作流]JWFD开源工作流官方下载内容更新

    在更新版的JWFD二次开发包中,我正在实现单线程的时钟控制器,动了下引擎的源代码,这个更新包主要是升级界面,内核代码,大家就不用升级了.. 代码提示: 请修改代码包中(org.jwfd.workflo ...

  2. JSON(3)Google解析Json库Gson

    本文参考 : http://www.cnblogs.com/chenlhuaf/archive/2011/05/01/gson_test.html 1.资料 官网: http://groups.goo ...

  3. Python3 学习第五弹:类与面向对象

    对于面向对象总是要提到,万物皆对象.好似博大精深的感觉. 接下来一起看看python的面向对象的例子 创建一个对象 class Person: type = 'person' def __init__ ...

  4. B/S 和 C/S

    B/S最大优势为客户端免维护,适用于用户群庞大,或客户需求经长发生变化的情况. C/S功能强大,可以减轻服务器端压力,如果用户的需求特别复杂,用C/S. 全面: Client/Server是建立在局域 ...

  5. 51nod1189 阶乘分数

    (x-n!)(y-n!)=n!2 ans=t[n]+1.t表示的是n!2的小于n!的约数个数.n!2=p1a1*p2a2*p3a3...t[n]=(a1+1)*(a2+1)...-1 /2; 2对于n ...

  6. [转] Qt 多线程学习

    Qt 多线程学习 转自:http://www.cnblogs.com/IT-BOY/p/3544220.html 最近的项目上用到了关于多线程的知识,自己也比较感兴趣,所以就拿了那本<C++ G ...

  7. laravel5 centos6.4下的配置体验

    1. 安装lmnp环境: nginx version: nginx/1.6.0. php 5.5.7 . centos6.42. laravel-v5.1.4 一键安装包,在使用composer 安装 ...

  8. Windows Store APP- C# to get IP Address

    using Windows.Networking.Connectivity; public String GetIPString() { String ipString = String.Empty; ...

  9. Excel学习笔记杂荟

    Excel学习 一.工具->选项 可以对整个excel里面的东西进行编辑,里面有隐藏行号,下拉档等选项,有文档作者信息. 隐藏网格等 二.单元格内容比较大可以右击单元格->设置单元格格式- ...

  10. 25个有用的jQuery日历和日期选取插件

    jQuery被认为是最好的JavaScript库,因为它简单易用.灵活,并有大量的插件.本文介绍25个非常不错的jQuery日历和日期选取插件,希望对各位有用. 1. Simple JQuery Da ...