Monday 27 August 2012

Embedding Pure Data into a Unity iOS App

UPDATE: I wrote a sample project here.  It uses the most up-to-date version of libPd as of 03/08/2013.

So you're making a Unity-based iOS game, and you want to use Pure Data as your audio engine? Great! Let me show you how it's done.  Before starting, I suggest you read and understand this post on embedding libPd into an iOS app.

 

Step one: Create a wrapper for PdBase


The first thing you'll have to do is create a native wrapper for PdBase.  As mentioned in my previous post, PdBase is the main interface between your application and libPd.  So essentially what you're doing here, is creating a way to send messages to PdBase, which in turn sends messages to your Pure Data patches.  You can find my example wrapper here, however be warned that this is just a proof-of-concept, it is not fully tested, nor production ready code.  I'll explain how these wrapper functions work with an example:

This function is used to send a symbol to a receiver in your Pd patch.  That means it needs to know two things, the symbol you're sending, and, the name of the receiver.  However, you'll notice the function takes four arguments.  That's because both symbols and receivers are strings of characters, and the most reliable way for our native c code to know when a string sent from Unity ends, is to just tell it the length. In other words, symLength is the length of the symbol string in bytes, and recLength is the length of the receiver string in bytes.  The reason we do it this way is because a c string is simply a pointer to the memory location of the first character of the string, whereas a Unity string is an object that contains the string and more.

The first thing you do with each of these strings is convert them into NSStrings, because that's what PdBase expects.  To do so, initialize a new NSString object with the data sent from Unity, and make sure to specify the string is encoded as NSUTF16LittleEndianStringEncoding because that's the encoding that Unity uses.

Next, you call the appropriate PdBase function with our newly created strings, and release those strings because you're done with them.

Step two: Create an interface in Unity


Now that you've wrapped all the PdBase functions you're going to use, it's time to interface with your wrapper from Unity.  My example interface can be seen here.  There isn't much to explain, this code can be used more or less as-is, but I have a few notes to mention.
First, lists of arguments are sent as one long string separated by colons.  For example, "arg1:arg2:arg3".
Second, I append %f to float arguments which are part of a list.  This is so our native interface can differentiate between float and string arguments.  I did this while debugging a particular issue, but I'm fairly sure it's unnecessary.
Finally, you'll notice when passing that when I pass the length of a string to the native code, I multiply it by two.  This is because our C code is interested in the number of bytes a string is, not the number of characters, and since Unity strings are UTF-16 encoded, every character is made up of two bytes.

Step three: Embed Pd into an iOS App


When you build a Unity project for iOS, Unity creates a new XCode project with your game embedded in it.  At this point you'll embed Pd into your project, the process of which is described in this post.  Secondly, you'll want to add your PdBase wrapper, the first file we created, to this project.

Step four: Dance Party!


At this point you should have a Unity project and libPd embedded into a single application running on your iOS device.  Try calling the functions from your Unity-to-native-code-interface and see if your patches react.  If they do, great!  Otherwise, leave a note in the comments so we can deduce what went wrong.

4 comments:

  1. Thank you very much for this guide - it has managed to get me to the furthest point I have managed yet - a build deployed to the device and I can see pd print messages in the log - the only problem is that I don't hear any sound! I am using the latset unity (4.3). Any help you can give would be greatly appreciated - thanks - neil.

    ReplyDelete
    Replies
    1. I haven't tried with Unity 4.3 yet, but I'll setup a project and see if I run into any outstanding issues

      Delete
    2. Have you tried the sample project linked at the top of the post?

      Delete
  2. It fails to link due to a missing libiphone-lib.a (I tried copying one from a my project generated by unity 4.3 but then I just get a bunch of missing symbols). thanks for your help!

    ReplyDelete