0

I have been working with the book Practical Ruby Gems. It gave me the code below, which I wrote in:

require 'dl/import'
class LiveMIDI
ON = 0x90
OFF = 0x80
PC = 0xC0
  def initialize
    open
  end
  def noteon(channel, note, velocity=64)
    message(ON | channel, note, velocity)
  end
  def noteoff(channel, note, velocity=64)
    message(OFF | channel, note, velocity)
  end
  def programchange(channel, preset)
    message(PC | channel, preset)
  end
  module C
    extend DL::Importer
    dlload '/System/Library/Frameworks/CoreMIDI.framework/Versions/Current/CoreMIDI'
    extern "int MIDIClientCreate(void *, void *, void *, void *)"
    extern "int MIDIClientDispose(void *)"
    extern "int MIDIGetNumberOfDestinations()"
    extern "void * MIDIGetDestination(int)"
    extern "int MIDIOutputPortCreate(void *, void *, void *)"
    extern "void * MIDIPacketListInit(void *)"
    extern "void * MIDIPacketListAdd(void *, int, void *, int, int, int, void *)"
    extern "int MIDISend(void *, void *, void *)"
  end
  module CF
    extend DL::Importer
    dlload '/System/Library/Frameworks/CoreFoundation.framework/Versions/Current/CoreFoundation'
    extern "void * CFStringCreateWithCString (void *, char *, int)"
  end
  def open
    client_name = CF.CFStringCreateWithCString(nil, "RubyMIDI", 0)
    @client = DL::PtrData.new(nil)
    C.mIDIClientCreate(client_name, nil, nil, @client.ref);

    port_name = CF.cFStringCreateWithCString(nil, "Output", 0)
    @outport = DL::PtrData.new(nil)
    C.mIDIOutputPortCreate(@client, port_name, @outport.ref);

    num = C.mIDIGetNumberOfDestinations()
    raise NoMIDIDestinations if num < 1
    @destination = C.mIDIGetDestination(0)
  end

  def close
    C.mIDIClientDispose(@client)
  end

  def message(*args)
    format = "C" * args.size
    bytes = args.pack(format).to_ptr
    packet_list = DL.malloc(256)
    packet_ptr  = C.mIDIPacketListInit(packet_list)
    # Pass in two 32 bit 0s for the 64 bit time
    packet_ptr  = C.mIDIPacketListAdd(packet_list, 256, packet_ptr, 0, 0, args.size, bytes)
    C.mIDISend(@outport, @destination, packet_list)
  end
end

When I try to run it, I get the following error, which I don't understand, I've never worked with DL before.:

livemidi.rb:36:in `open': undefined method `cFStringCreateWithCString' for LiveMIDI::CF:Module (NoMethodError)
    from livemidi.rb:7:in `initialize'
    from livemidi.rb:63:in `new'
    from livemidi.rb:63:in `<main>'

Why is this??? I am using Ruby 1.9.3, on Mac OS X Can you help me fix this bug?

Bobby Tables
  • 1,154
  • 4
  • 15
  • 25
  • Should be obvious, there is no method called `CFStringCreateWithCString`. –  May 02 '12 at 23:34

2 Answers2

0

If you search the Apple Developer Documentation you will find a method called CFStringCreateWithCString. The method signature for CFStringCreateWithCString is different than what you define. The correct method definition is.

CFStringRef CFStringCreateWithCString (
   CFAllocatorRef alloc,
   const char *cStr,
   CFStringEncoding encoding
);

That means you should change.

extern "void * CFStringCreateWithCString (void *, char *, int)"

To.

extern "CFStringRef CFStringCreateWithCString(CFAllocatorRef, const char*, CFStringEncoding)"
0

Your trouble appears to be that you're calling cFStringCreateWithCString, but the function is called CFStringCreateWithCString — capitalization is important.

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • Line 36 does call `CFStringCreateWithCString` though. –  May 03 '12 at 01:40
  • @dunsmoreb: The error clearly shows the lowercase version, so he must have pasted a different version of the code than the error came from. The uppercase version does in fact exist — I have run the code and confirmed this. – Chuck May 03 '12 at 02:08