[MacRuby-devel] Using performRubySelector

Matt Aimonetti mattaimonetti at gmail.com
Thu May 28 10:38:55 PDT 2009


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 at 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 at 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 at 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 at lists.macosforge.org
> >> http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
> >>
> > _______________________________________________
> > MacRuby-devel mailing list
> > MacRuby-devel at lists.macosforge.org
> > http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
> >
> _______________________________________________
> MacRuby-devel mailing list
> MacRuby-devel at lists.macosforge.org
> http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-devel/attachments/20090528/8ac45ece/attachment-0001.html>


More information about the MacRuby-devel mailing list