Category

Swift 3 Core MIDI

Swift Language

Swift 3 Core MIDI

The Swift 3 betas bring many changes. Here’s an update for Core MIDI based on Swift 3 beta 3.

Introduction

Table of Contents

There aren’t a great number of changes specifically to Core MIDI; it’s just as awful as it’s always been.
Much of what you need to deal with is renamification[sic]. Some of the language types and function signatures have been changed.

Some Changes

Table of Contents

Here is a comparison of MIDIReadBlock which is passed to a virtual destination at creation. As you see, nothing horrible (besides MIDIPacketList still living).

Notifications have been updated.

Still some inconsistencies remain. Compare NotificationCenter.default with MIDINetworkSession.default().

Enums have been renamed. Many enums started with an uppercase character, some didn’t. They all start with lower case characters now.

C Pointers are still there and still a pain. Some members on the Swift side have been renamed, e.g. memory is not pointee.

Beta 6 changes

Table of Contents

First a change that’s not just CoreMIDI, but every iOS app. In your Application delegate the commonly used “set up” function has a new signature.

The signatures of many Core MIDI items have been changed. There is a new UnsafeMutableRawPointer type.

Casting Core Foundation types must be explicit now.

For example, the CFString first formal parameter of MIDIClientCreateWithBlock or the CFURL in MusicSequenceFileCreate.

Pointers

You should probably read this document from the evolution docs.

Here are some examples.

Speaking of MIDINotification, you will need to “cast” MIDINotification to other types. You can’t do it with UnsafeMutablePointer anymore. Instead there is a new way:

added to: label to withUnsafeMutablePointer.

sizeof has been morphed into MemoryLayout.

Summary

Table of Contents

Core MIDI still works. There have been no improvements. You will have to change some names and signatures to get back to where you were.

A final note: if you are using a sound font, Core Audio is less forgiving with sound fonts that have problems, like MusesCore’s General User sound font. (Their Fluid R3 works just fine).

Resources

Table of Contents

23 thoughts on “Swift 3 Core MIDI”

  1. Hi Gene,

    thanks a lot for your useful article, i’m new in midi development. What do you think about to create a basic article about the basics of Core MIDI ?

    best,

    1. That’s probably a good idea since that info is so scattered across the net and much of it is out of date.

  2. Hi Gene! Can you help me?

    I make my own midi player.Player plays notes to AVAudioEngine (I send individual notes in handle(_:) function to AVAudioUnitSampler for each track). This your Github project is really helpful for me! I use this code (setup midi and start music player). But I have one serious question. What about timing? In this your examples everything is great and very useful, but MIDI plays not in sync… Notes plays very uneven. How I can fix it? I heed your help.

    Best Regards,
    Ruslan.

    1. I have no timing issues when using MusicPlayer on the device.

      You will have timing issues if you are using a network connection through a router (e.g. sending MIDI from iPhone to macBook or vice versa)
      For that use an Ad Hoc connection.

  3. In your GitHub code you have this comment when creating MetaEvents:
    //FIXME: produces junk. But when inline it’s fine.
    What do you mean by “when inline”?

    When I used code based on yours to create a MetaEvent in Swift 3 it crashed with an illegal memory access error. Eventually I had to create an UnsafeMutableRawPointer and then use event = eventPtr.bindMemory(to: MIDIMetaEvent.self, capacity: 1) to interpret it as a MetaEvent. That worked.

    1. This works:

      internal func addTrackName(track:MusicTrack, name:String) {

      The code tagged with FIXME doesn’t.

      I’ll try your suggestion for the FIXME.

      Could you post a bit of your code?

  4. Hello Gene,

    thanks for your good examples, most of which I got to work. Would not have know how to start without them.

    Are you willing to help solve my practical problem, for a fee, of course.

    I did not manage to send MIDI program change messages from my iOS app over a CoreMIDI compliant interface attached interface. The app successfully finds the attached destinations, creates a client, port etc. but the messages disappear somewhere.

    I know the hardware interface works. I ran a commercial iOS app, and the MIDI messages successfully get to the destination on the MacBook which is connected to the same MIDI device.

    Thanks. Hope you will encourage me to feed your kitten.

    Christoph. Binningen, Switzerland.

  5. Hello Gene,

    thanks for your example codes- they are a great help and resource for developing midi iOS App.
    Now i’m desperately trying to parse SysEx Data from MidiRawData but didn’t manage to write a working code for iOS with Swift3
    Perhaps you can help me with a code snippet – i searched everywhere, but didn’t find any useful clues.
    I think it can be done with “Mirror(reflecting: data)” like you recommended in another post about parsing MIDIMetaEvents, but i didnt manage to do it…

    Here’s my code snippet so far:

    switch eventType
    case kMusicEventType_MIDIRawData:
    var raw = eventData?.bindMemory(to: MIDIRawData.self, capacity: 2)
    let length = raw!.pointee.length
    var data = raw!.pointee.data
    now i don’t know what to do with “data”. I only can extract one UInt8 , but “length” tells me, there are 30 bytes or more…

    I would be very thankful if you could help me!

  6. Gene, anything in my code between a less than sign and a subsequent greater than sign (html tag) is escaping the syntax highlighting and disappearing. I must be formatting my crayon tags incorrectly. It worked before but something must have been updated in the crayon plug in for WordPress. I hat to be a pain but please delete everything from today (again) and I will read up on the correct tags to use other than “pre” and “/pre”.

    1. Thanks Gene. I had to change all the “less than” symbols to ampersand lt semicolon and the “greater than” symbols to ampersand gt semicolon to get them and their contents through the Crayon parser.

  7. In particular using a variable assigned to $0.pointee causes the MetaEvent to be changed into a Sequence event. I’m not sure how this happens.

    1. I”ve tried that code too, just for fun, but it”s not working. The results will be random data with that for some certain reasons…
      The memory management of the SWIFT language is extremely opaque and complicated and we mostly do not even know, what”s really happening under the hood… We just cannot do things like we would do it in C or C++ or even Objective-C. ^^ Mostly this will produce undefined results In Swift.

      In another thread here you can find ‘my” solution for the Meta, SysEx and MIDIUserEvent problem. It currently works, but I will certainly NOT quarantee this for a lifetime.

  8. Hello Gene!

    I discovered some random crashes with your CoreMIDI code examples at GitHub.
    I think, you should consider using an OperationQueue in all critical operations inside the MIDI callbacks. Especially if excessive processing of MIDI events is done or user interfaces are accessed or such…

    It must be applied to all callbacks that are passed to *MIDIDestinationCreateWithBlock()* functions, after the MIDIPacket is deciphered and forwarded to any other processing.

    i.e.:


    // return as fast as even possible , because these MIDI message callbacks is a critical system process

    case 0x80: // NOTE ON

    OperationQueue.main.addOperation(
    {
    self.delegate.messageMIDINoteOn(timestamp: timestamp, noteNumber: d1, velocity: d2, channel: channel)
    })
    break

    case 0x90: // NOTE OFF

    OperationQueue.main.addOperation(
    {
    self.delegate.messageMIDINoteOff(timestamp: timestamp, noteNumber: d1, velocity: d2, channel: channel)
    })
    break

    // ...

  9. Hello Gene!

    I discovered some random crashes with your CoreMIDI code examples at GitHub.
    I think, you should consider using an OperationQueue in all critical operations inside the MIDI callbacks. Especially if excessive processing of MIDI events is done or user interfaces are accessed or such…

    It must be applied to all callbacks that are passed to *MIDIDestinationCreateWithBlock()* functions, after the MIDIPacket is deciphered and forwarded to any other processing.

    i.e.:


    // return as fast as even possible , because these MIDI message callbacks is a critical system process

    case 0x80: // NOTE ON

    OperationQueue.main.addOperation(
    {
    self.delegate.messageMIDINoteOn(timestamp: timestamp, noteNumber: d1, velocity: d2, channel: channel)
    })
    break

    case 0x90: // NOTE OFF

    OperationQueue.main.addOperation(
    {
    self.delegate.messageMIDINoteOff(timestamp: timestamp, noteNumber: d1, velocity: d2, channel: channel)
    })
    break

    // ...

    1. … sorry, I wrote this from my mind and I obviously mismatched the ON/OFF status bytes. ^^
      But it should be clear what I mean.

      Regards!

  10. Hello Gene!

    Iam so thankful to you and what you’ve build!
    I am an Austrian student and I am working on an iOS and Android App within my team, we want to make a opensource App for managing notes within an app.
    So we want to provide an MIDI Feature for Live Situations…
    I am pretty new into ios Development…. So this brings me to my question.

    How can I make a Control Change?
    I know that the HEX Valu is 0x B0, and there is a controllerNumber from 0 – 127 and also a controllerValue…but how can I create and start the command when the User tap on a Button?

    I would be very thankful if you could help me!

    1. Trigger it via the usual target/action pattern.

      1. Dear Gene,

        How do i get the value for variable track? And which value is needed for data1 and data2 when i want to send a Control Change for LSB?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.