I'd love to do it in FFI, but getting this far in C was a lot of work! ... so here's another crackpot idea of mine. Another project I have been following is the Pure Language <http://code.google.com/p/pure-lang>. It aims to be a simple, interpreted functional language based on term-rewriting, and also has an LLVM JIT compiler. Using LLVM, they support a literal syntax for declaring foreign functions. To assist in creating wrappers for libraries, they created a tool called pure-gen that parses C header files and dumps out a .pure file containing FFI declarations. The tool is written in Haskell using a module called Language.C, but I wonder if we could bootstrap something similar by wrapping up Clang's libparse. They've managed to create wrappers for gsl, gtk+ and some other libraries by starting with the generated FFI decls, and adding some syntactic sugar and abstraction within Pure as appropriate. Implementing such a tool is probably going to take a lot of effort, but the benefits are pretty clear – especially since generated wrappers might be usable in JRuby and MRI. I also don't know how much this overlaps with BridgeSupport, but I just wanted to put the idea out there. Best, Jeremy On Thu, May 28, 2009 at 10:38 AM, Matt Aimonetti <mattaimonetti@gmail.com> wrote:
I second what Jeremy said. A nice Midi wrapper would be great. Jeremy, regarding your MusicPlayer lib, the other option is to port it to FFI and therefore making it JRuby and MacRuby compatible.
- Matt
On Thu, May 28, 2009 at 10:32 AM, Jeremy Voorhis <jvoorhis@gmail.com> wrote:
Mike,
Is your code available anywhere, e.g. on github? I haven't looked at the PyObjC code myself, but I'd be interested in having really decent CoreMIDI support available in MacRuby.
Btw, when C extensions are supported, simple apps will be able to use my MusicPlayer lib at http://github.com/jvoorhis/music_player/tree/master, which wraps much of the MusicPlayer/MusicSequence api in AudioToolbox.framework. It's short on documentation, but it's easy to get up and running on MRI 1.8.x or 1.9.1.
Best,
Jeremy
On Wed, May 27, 2009 at 11:25 PM, Mike Laurence <mklaurence@gmail.com> wrote:
Hmmm... I'm doing several things different, perhaps one or more of them are impossible :-)
Basically, I'm trying to get MIDI support into Ruby via the PYMIDI obj-c library, which is really just a wrapper around CoreMIDI. One way I had thought of: create an additional obj-c class (MidiReceiver) which processes incoming packets for a given MIDI source and then call methods such as "note", "controlChange", "clockTick", etc. This MidiReceiver class can then be overridden by a custom ruby class that contains those same methods.
Here is a quick version of the MidiReceiver class (with only the clockTick method for simplicity):
------------- MidiReceiver --------------
#import <MacRuby/MacRuby.h> #include <CoreMIDI/CoreMIDI.h>
@interface MidiReceiver : NSObject
- (void) processMIDIPacket: (MIDIPacket*) packet; - (void) clockTick;
@end
@implementation MidiReceiver
- (void) processMIDIPacket: (MIDIPacket*) packet { if (packet->length > 0) {
int statusByte = packet->data[0]; int status = statusByte >= 0xf0 ? statusByte : statusByte >> 4 << 4;
switch (status) { case 0x90: // Note on, etc... case 0xf8: // Clock tick [self performRubySelector:@selector(clockTick)]; break; } } }
- (void) clockTick { }
@end
--------------------------------------------------------
Then, I have a ruby subclass of MidiReceiver that overrides clockTick, etc.:
class LiveMidiReceiver < MidiReceiver def clockTick puts "tick!" end end
And then, in my Ruby ApplicationController, I'm finding the MIDI source and adding an instance of LiveMidiReceiver as a MIDI receiver:
@src = PYMIDIManager.sharedInstance.realSources.find{ |s| s.displayName == 'KONTROL49 PORT A' } receiver = LiveMidiReceiver.new @src.addReceiver(receiver)
The LiveMidiReceiver instance, upon receiving a midi packet, is called properly up to the point of the performRubySelector, but thereafter it launches into the debugger with EXC_BAD_ACCESS messages or other unsightly stack dumps.
---
An even *better* interface would be to have the "clockTick" and other calls be performable on an arbitrary ruby object without having to subclass MidiReceiver (e.g., have MidiReceiver send "clockTick", etc. to a delegate object which has been created solely in Ruby). I tried that and it gave me similar results, although strangely it only crashed the first time on a clean build - thereafter I saw no crashes, but still no confirmation of ruby method calls either.
To test that, I just added a delegate object to MidiReceiver, and then I changed the clockTick recipient from self to delegate:
[delegate performRubySelector:@selector(clockTick)];
Then set receiver.delegate = self in my ApplicationController. I'll bet I need some more hooks than that, although it sure would be nice to send ruby messages from obj-c willy-nilly :-)
---
I hope I'm making some sense here! I greatly appreciate any info that you can send my way. Hopefully when I get this all figured out I can write a nice, fat blog post about it :-)
Regards, Mike Laurence
On Wed, May 27, 2009 at 8:18 PM, Laurent Sansonetti <lsansonetti@apple.com> wrote:
Hi Mike,
On May 26, 2009, at 5:45 PM, Mike Laurence wrote:
Hello,
I'm trying to get some obj-c code to talk back to my ruby. After encountering some "EXC_BAD_ACCESS" messages and scouring the web, I've concluded that I'm probably supposed to use performRubySelector instead of just expecting selectors to work when overridden by ruby subclasses, etc.
What is the preferred way to get this to work? I looked through some of Elysium's old code (which used performRubySelector), but I'm having trouble wrapping my head around how you're supposed to use the MacRuby sharedRuntime to get things to happen. If someone could give me a quick example of how to call arbitrary ruby methods, I would highly appreciate it.
Of course, if I'm completely off base and there's some other way to call ruby code, please let me know!
Calling Ruby from Objective-C can be problematic, depending if you want to call a pure Ruby method or a Ruby method that overrides an Objective-C one. If you want to dispatch the method by yourself (and if it's a Ruby method that overrides a specialized Objective-C method), you may want to be very careful about the types of the arguments you are passing to, as well as the return value.
In any case, using performRubySelector: is better because arguments will be converted from Objective-C objects (id) into the expected type, and the return value will be converted into an Objective-C object. Also, performRubySelector: can deal with Ruby methods that have optional or splat arguments.
$ cat t.m #import <Foundation/Foundation.h> #import <MacRuby/MacRuby.h>
@interface Foo : NSObject @end
@implementation Foo - (int)aMethodReturningInt { return 123; } @end
int main(void) { [[MacRuby sharedRuntime] evaluateString:@"class X; def foo(x=1, *a); p x, a; end; end"]; Class k = NSClassFromString(@"X"); id o = [k new];
[o performRubySelector:@selector(foo)]; [o performRubySelector:@selector(foo:) withArguments:@"1", NULL]; [o performRubySelector:@selector(foo:) withArguments:@"1", @"2", @"3", NULL];
[[MacRuby sharedRuntime] evaluateString:@"class Bar < Foo; def aMethodReturningInt; 42; end; end"]; k = NSClassFromString(@"Bar"); o = [k new];
NSLog(@"%d", [(Foo *)o aMethodReturningInt]); NSLog(@"%@", [o performRubySelector:@selector(aMethodReturningInt)]);
return 0; } $ gcc t.m -o t -framework Foundation -framework MacRuby -fobjc-gc $ ./t 1 [] "1" [] "1" ["2", "3"] 2009-05-27 18:16:36.092 t[11922:10b] 42 2009-05-27 18:16:36.095 t[11922:10b] 42 $
If you still have problems, it would be easier if you could paste some code, this way I can try to help you more.
HTH, Laurent _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel