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

Share These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Facebook
  • Twitter
  • LinkedIn
  • email
  • DZone
  • Slashdot
  • Reddit
  • Google Bookmarks
  • Digg
  • StumbleUpon
  • del.icio.us
This entry was posted in Core MIDI. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

20 Comments

  1. kyzouik
    Posted August 5, 2016 at 5:45 am | Permalink

    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,

    • Gene De Lisa
      Posted August 5, 2016 at 7:37 am | Permalink

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

      • kyzouik
        Posted August 11, 2016 at 8:29 am | Permalink

        Yes, as a beginner, this very difficult ! Everything i found is minimum on middle level !

  2. Ruslan
    Posted September 10, 2016 at 7:25 pm | Permalink

    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.

    • Gene De Lisa
      Posted September 13, 2016 at 8:00 am | Permalink

      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. Posted September 24, 2016 at 11:27 am | Permalink

    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.

    • Gene De Lisa
      Posted September 25, 2016 at 9:07 am | Permalink

      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?

      • Posted September 25, 2016 at 11:02 am | Permalink

        • Posted March 13, 2017 at 6:30 pm | Permalink

          The code I posted above is broken with the latest version of XCode/Swift. See below for the updated code.

  4. Posted September 25, 2016 at 11:34 am | Permalink

    BTW Thank-you for all of the code you have posted! It was very helpful in getting me started with Swift and Core MIDI on Apple’s platforms.

  5. Christoph Schifferli
    Posted November 25, 2016 at 10:40 am | Permalink

    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.

    • Gene De Lisa
      Posted November 27, 2016 at 8:32 am | Permalink

      send me a link to your repo and I check your code.

  6. Sebastian Sygulla
    Posted December 10, 2016 at 4:05 pm | Permalink

    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!

  7. Posted February 24, 2017 at 4:43 pm | Permalink

    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”.

    • Posted March 13, 2017 at 6:38 pm | Permalink

      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.

  8. Posted March 13, 2017 at 6:27 pm | Permalink

    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.

    • Jens
      Posted June 26, 2017 at 6:20 am | Permalink

      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.

  9. Jens
    Posted June 27, 2017 at 6:44 am | Permalink

    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

    // ...

  10. Jens
    Posted June 27, 2017 at 6:44 am | Permalink

    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

    // ...

    • Jens
      Posted June 27, 2017 at 6:51 am | Permalink

      … 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!

Post a Comment

Your email is never published nor shared.

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">