To register and login, use your Google, Twitter, Facebook, LinkedIn, or OpenID credentials.

This is allowing us to stop most spam registrations. We've deleted most of the spam accounts that got through, and we're closely watching for more.

iOS: Is it possible to receive PdBase delegate methods on a thread other than the main thread?

alexanderalexander Posts: 6
edited September 2012 in Pd Everywhere

Hey everybody,

I'm sending MIDI out of my LibPd application, but since PdBase's delegate methods are called on the main thread, I'm experiencing some lag with the MIDI output when there is too much going on in the UI.

I'm wondering, is possible to receive the PdBase delegate methods (receiveFloat:, receiveBangFromSource:, etc.) on a separate thread? If not, would immediately handing these messages off to another thread after being received help? Any other possible solutions?

Many thanks, Alexander

Answers

  • reakinatorreakinator Posts: 301

    You can currently only receive the PdReceiverDelegate methods on the main thread, if you wanted to receive them from the audio thread you'd have to manually override libpd's c callback hooks. However, for almost all cases it is a bad idea to handle pd messages from the audio thread (which is why PdBase doesn't support it).

    What is it that you are trying to do with the MIDI, and why is your UI getting bogged down? I'm sure if there is a good use case, we can figure out how to do it. But you're going to have to lighten up whatever it is you are doing on the main thread anyway, in order to have a responsive app.

    cheers, Rich

  • Hey Rich, thanks for the reply.

    I'm creating MIDI Note and MIDI CC messages in my main view controller, and sending them over CoreMidi (to other applications, external gear, or over a network). These messages are affected by LibPd.

    Just to be clear, the UI does not get bogged down, it is only the MIDI output that suffers. And the MIDI output only suffers when I present or dismiss a Popover, or scroll a Table View. (It's an iPad app, and the Popover and Table View are used for settings.)

    I'm sure there is an obvious answer for this, but just in case, why is it a bad idea to handle pd messages from the audio thread?

  • reakinatorreakinator Posts: 301

    Ok, we're looking into the possibilities to make this work. Don't yet know if we need to allow for specifying a custom runloop (and thereby thread), or expose some other functionality that'll allow the user to customize where they receive the callbacks. Would you mind posting a snippet of what your callback looks like, that contains your calls to Core Midi?

    I was also thinking whether it would be possible to take advantage of pd's built in midi send objects, like [noteout] or [ctlout], and even pd's built in Core Midi support, but I don't think this supports sending over a network.

    About handling messages on the audio thread: the main reason is that messages from pd are normally used to update the UI, which can almost always only be done on the main thread. If you call a UIKit method from the background, you either get undefined results or a crash. But almost just as important is that we want to do as little as possible from the audio thread so it has the maximum amount of time to process what it has to in real-time. This is why we write all of the messages to a circular buffer and deliver them on a different thread (currently hard coded to be the main thread via [NSRunLoop mainRunLoop]).

  • Awesome, thanks Rich. Here's a stripped down version of the callback. It accepts a float from Pd and sends a MIDI Note on message.

    - (void)receiveFloat:(float)received fromSource:(NSString *)source  {   
         if ([source isEqualToString:@"noteFromPd"]) {   
           const UInt8 noteOn[]  = { 0x90, (UInt8)received, 64 }; //{header, note, velocity}
           [_midiDestination sendQueuedMidi:noteOn size:sizeof(noteOn) atTime:mach_absolute_time()];        
         }
    }
    

    _midiDestination is an instance of Pete Goodliffe's PGMidiDestination (http://goodliffe.blogspot.com/2011/02/pgmidi-updated.html)

    Also, does LibPd for iOS already contain built-in Core Midi support, or were you referring to Pd on OS X?

    And with regards to Pd's built in Core Midi network support, if you were referring to Pd on OS X, I believe it does support sending over a network. I simply create a Network Session in Audio MIDI setup, and it is included in the available Output devices in Pd's MIDI settings.

    Thanks again, Alexander

  • reakinatorreakinator Posts: 301

    Hey, it's just a first pass at one approach, but there is a branch up on github where I've enabled polling from a secondary thread of the user's choosing, you can find the relevant commit here. Basically, you have to call [PdBase setAutoPollsMessages:NO] and then [PdBase pollMessages] however you see fit. I'll try to throw up an example that does this tonight after I get off work..

    If anyone has comments, suggestions, or ideas, we're open to other possibilities to enable this too. We probably won't go for something too intricate though, like a utility class, since this is a pretty special and advanced use case.

  • reakinatorreakinator Posts: 301
    edited October 2012

    Just pushed the example to the following branch: https://github.com/libpd/pd-for-ios/tree/background_polling

    Look at pd-for-ios/test/BackgroundPollingTest. In the RootViewController, pd messages are being pulled via grand central dispatch, using the 'default' background queue.

    cheers, Rich

  • alexanderalexander Posts: 6
    edited October 2012

    YESSS! Great solution! I just integrated the changes into my application and so far so good! Thanks so much, Rich :]

    To get your backgroundPollingTest example to build, I had to @synthesize the audioController and dispatchTimer properties. Was this missing in your code, or is there a global in Xcode (or something else) you can set to not write these?

    Lastly, is it safe to send messages to Pd from any thread? And is it safe to send to Pd from multiple threads at the same time?

  • reakinatorreakinator Posts: 301

    Great, glad it's a working solution. Although note that Peter and I have been discussing the possibility of integrating Core Midi directly into libpd, so we don't know if this newly exposed functionality will be useful - maybe though, because there are alternatives to MIDI like OSC as well. So, for the moment the pollMessages changes will stay in the background_polling branches.

    About the example I made, it's using a feature from LLVM 4.0 (Xcode 4.4+) for default property synthesis - sort of habit from my last day job. I should add in the explicit @synthesis if the test stays.. thanks letting me know, however.

    Lastly, is it safe to send messages to Pd from any thread? And is it safe to send to Pd from multiple threads at the same time?

    libpd itself provides no thread safety, but the language wrappers do (PdBase.m uses @synchronize blocks). This includes everything in the wrapper API's, except the newly added pollMessages method, which will possibly get it too, if it stays.

  • pbrinkmannpbrinkmann Posts: 685 ✭✭

    Quick update: We've revisited the matter of background polling in the context of the recently added MIDI support in ObjC. Support for background polling is now in the master branch, but the API is different now.

    There's a new method, setDelegate:pollingEnabled, that takes an additional boolean parameter that indicates whether you want PdBase to install the default poll timer for you. If you don't have PdBase install the timer, then you will need to call [PdBase receiveMessages] yourself. Of course, the old setDelegate method is still there and it still installs a timer, like it did before.

    There's a matching set of new methods for setting MIDI delegates and polling the MIDI message queue.

Sign In or Register to comment.