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 <[email protected]> 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 > <[email protected]> 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 >> [email protected] >> http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel >> > _______________________________________________ > MacRuby-devel mailing list > [email protected] > http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel > _______________________________________________ MacRuby-devel mailing list [email protected] http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
