Working with Audio in Xamarin with Superpowered Audio Engine
Xamarin is a popular cross-platform mobile app development platform that helps developers create iOS, Android, Mac and Windows apps in C#.
Because Xamarin is written C# and Superpowered is written in C++, a Xamarin developer would need to create a binding to the Superpowered Audio libraries.
One of the developers in the Superpowered Dev community, Bryon Baker, has done just that, and moreover, has open-sourced his implementation. Bryon writes:
The Xamarin Spectrum Analyser is a small project that demonstrates how to bind C# managed code with the SuperpoweredSDK. It is not an attempt to provide a binding of the complete SDK, but rather demonstrates all of what you need to bind any of the SuperpoweredSDK class library to Xamarin.
The single notable missing binding is the binding to SuperpoweredIOSAudioOutput. This is a complex binding that I did not need it for my initial implementation; I plan to build this later (or will happily accept contributions :-).
The X-Code and Xamarin projects give you everything you need to extend the binding and enjoy the awesomeness of SuperpoweredSDK with cross-platform code!
The source code can be found here: https://firstname.lastname@example.org/bryonbaker/xamarin-spectrum-analyser.git
If you have any questions please feel free to contact me.
Calling the C and C++ class library
In order to bind to Superpowered you need to wrap up the C++ code in a way that enables it to be called from managed code. The information on how to do this is actually hard to find but basically there are two things working against you here:
1. C++ uses mangled names which means you need to create a map file to find the code you want to call.
2. You cannot create C++ objects from C#.
To work around this you reimplement each C++ method as a simple C function. The impact of this is that you need to pass object references into functions that need to call instance methods. For example, the following two functions are part of the reimplementation of the SuperpoweredBandpassFilterbank class:
extern "C" SuperpoweredBandpassFilterbank* SuperpoweredBandpassFilterbank_Create(int numBands, float frequencies, float widths, unsigned int samplerate); // constructor extern "C" void SuperpoweredBandpassFilterbank_SetSamplerate( SuperpoweredBandpassFilterbank *pObject, unsigned int sampleRate ); // instance method
There are two things going on here:
- extern "C" ensures that the function uses standard cdecl and does not mangle the function name.
- The C++ object wrapper needs to pass the object reference in and out in order to construct the object and then call its methods.
WARNING: IT IS CRITICAL THAT YOU DO NOT ALLOW AN EXCEPTION TO PASS FROM UNMANAGED CODE TO MANAGED CODE. It is for this reason that the catch(...) is used and instead a diagnostic message is written to stderr. I think a good enhancement would be to add a result code to the C functions that can be tested in C# and then a call to get the error details.
As I said, I have not bound SuperpoweredIOSAudioOutput yet - but have demonstrated what is required by binding to the SuperpoweredFrequencies demo. From an X-Code perspectiveyou do not need to do anything except make sure it is built into the library - the heavy lifting for this is done in C#. The Xamarin utility Objective Sharpie is used t parse the Objective-C headers and create an ApiDefinition.cs and StructsAndEnums.cs class files. If you take the time to learn the notation I suggest writing them yourself.
Building the X-Code Project
To build the X-Code project you need to use the command line and run "make." This will create the libSuperpoweredXCodeWrapperSDK.a library that is needed for the Xaramin solution.
In the Xamarin Solution there are a couple of parts to the binding. To call the C or C++ code in SuperpoweredSDK you need to use pInvoke. To call Objective-C you need to use a C# binding. The solution therefore contains three projects:
- Project 1: SuperpoweredSDKXamarinWrapper - demonstrates how to wrap the C and C++ Superpowered library.
- Project 2: SuperpoweredSDKBinding - demonstrates how to bind to the SuperpoweredFrequencies demo in Objective-C (this is where the binding to SuperpoweredIOSAudioOutput will go).
- Project 3: XamarinSpectrumAnalyser - the project that demonstrates the implementation of the binding.
The code here is pretty self explanatory and the only thing worth noting is this is where we convert our "flattened" C++ code back into classes. Here I have basically reimplemented the original C++ interface in C# so you can use SuperpoweredBandpassFilterbank as per the current documentation.
Thanks to Bryon's heavy-lifting, the source code can be found here: https://email@example.com/bryonbaker/xamarin-spectrum-analyser.git.