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 <lsansone...@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