I’m unsure on the camera stream, basic types will probably come first.
Note that you don’t have to use the GCD singleton code — I simply used it in the GameCenter test because I needed to attach the addon as a delegate to the GKGameCenterViewController from inside the exported Lua function, this was the cleanest way I could think to have access to the specific instance of the addon. This made the code more complex than I liked.
The singleton pattern is helpful if you need to manipulate/access the singular instance of your addon in exported Lua functions.
Ok, works fine anyhow. Was thinking of removing it, since I haven’t read about GCD yet, but then I got use for it in the facebook share function, since I call presentViewController and need the CodeaViewController.
I like the new API. My biggest issue was trying to call an objective c method from within a c function. What I have done feels like a bit of a hack, so if there is a more elegant way then I would love to learn it.
I didn’t use @Simeon’s singleton pattern for a couple of reasons:
Just to see if I could; and
The extra singleton code obfuscates the learning process a bit and could be intimidating for 1st time Xcoders. I wanted to show how simple it is to add functionality using this new protocol.
I’ve updated the audio add on so that you can control the volume of the player from your Lua code and that works great. So getting values from Lua to Objective C is all good but I’m having problems going the other way.
I’m trying to provide a dB meter as part of this audio add on. To that end I need to read an integer from my add on method within the draw loop. I’m using the Cider dial control (which looks great) like this:
function draw()
dial.val = peakPowerForPlayer() or 0
end
The app crashes (the old EXC_BAD_ACCESS) as soon as the mp3 starts playing. Any ideas what I am doing wrong? I think the issue is that I am not returning a valid integer in peakPowerForPlayer(). The associated Objective C method getPower seems to work ok.
The relevant code is shown below.
- (int)getPower
{
if ([self.player isPlaying])
{
// Refresh the average and peak power values for all channels of our audio player.
[self.player updateMeters];
// A floating-point representation, in decibels, of a given audio
// channel’s current peak power.
// A return value of 0 dB indicates full scale, or maximum power;
// a return value of -160 dB indicates
// minimum power (that is, near silence).
//
// If the signal provided to the audio player exceeds ±full scale,
// then the return value may exceed 0
// (that is, it may enter the positive range). For simplicity we will
// only return the power from channel 0.
float power = [self.player peakPowerForChannel: 0];
// Our dial is expecting a value between 0 and 100.
if (power >= 0)
return 100;
else
{
power += 160.0f; // power is now a +ve float between 0 and 160
power = (power / 160.0f) * 100.0f; // change to a percentage
return (int)power;
}
}
else
return 0;
}
// C Functions
static int peakPowerForPlayer(struct lua_State *state)
{
return [audioAddOnInstance getPower];
}
```
@Reefwing unfortunately interfacing with Lua is a bit complicated.
Your function:
static int peakPowerForPlayer(struct lua_State *state)
{
return [audioAddOnInstance getPower];
}
```
Should not be returning a value directly — the returned value from *all* exported Lua functions is how many values that function should return in Lua.
For example, if you return 0 from that function, you are telling Lua that peakPowerForPlayer returns 0 values. If you return 2, you are telling Lua to expect 2 values on the stack when the function returns.
To actually return values, you need to push them onto the Lua stack and then return the number of values you pushed on. So this should work:
static int peakPowerForPlayer(struct lua_State *state)
{
//Push the integer on the stack
lua_pushinteger(state, [audioAddOnInstance getPower]);
return 1; //Our function returns 1 value
}
```
The following functions are available in Codea once the audio add on is registered:
playMusic()
stopMusic()
getVolume() -- returns an integer between 0 and 100
setVolume(setting) -- expects setting to be between 0 and 100
peakPowerForChannel(channel)
averagePowerForChannel(channel)
I used the Cider dial and donut for the left and right dB level meters, and the Cider slider for the volume control. So you will need to include these as a dependency. Thanks to @Mark for his work on these, they look great. You may have to tweak the position of the controls, for some reason they moved when I exported them from Codea into Xcode.
Feel free to expand/modify or otherwise use the code. The meters would look better with a slow animation to zero when the mp3 is stopped. Passing in an mp3 name to play is another obvious extension.