FYI to all MIDI-hungry folks: I've gotten MIDI input to work perfectly with MacRuby (hooray!) I'm working on output today, and hopefully I'll have something workable up on github shortly.
As it turns out, I never could get performRubySelector to work the way I wanted, but I realized I wanted to use a different program flow for input anyway (pretty much just following rbcoremidi, with an array that gets filled with midi data and emptied whenever you query it.) ~Mike On Thu, May 28, 2009 at 1:57 PM, Mike Laurence <mklaure...@gmail.com> wrote: > I'll try and post what I was working on to Github, but it's fairly > incomplete, as I didn't want to get too far and then find out I > couldn't send messages to ruby the way I thought :-) > > This little MIDI project of mine was just to get my formerly-RubyCocoa > (and thus formerly Midiator / DL / rbcoremidi compatible) app working > in MacRuby, but the more I think about it, the more it feels like we > should do something about this fragmented ruby MIDI situation. Since > that's really a topic for the Ruby-MIDI forum, I posted my thoughts > over there: > http://groups.google.com/group/ruby-midi/browse_thread/thread/2cacf04770abf242 > > Let the firestorm begin! Or, maybe just a happy storm. That would be better. > > Mike > > On Thu, May 28, 2009 at 1:02 PM, Jeremy Voorhis <jvoor...@gmail.com> wrote: >> 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 >> <mattaimone...@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 <jvoor...@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 <mklaure...@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 >>>> > <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 >>>> > >>>> _______________________________________________ >>>> 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