RubyInline - passing pointer from one function to another

M

Marcin Lewandowski

Hi,

I'm trying to write ruby interface to JACK audio library. I've chosen
RubyInline due it's simplicity. What I want to achieve is to have ruby
code like this:

client = JACK::Client.new "my_name"
puts client.get_sample_rate

To achieve that I need to pass pointer to variable of jack_client_t*
from libjack from one function to another. What I tried to do is
available at http://pastebin.com/m3b6ee0c9 but as you can expect it
doesn't work.

How can I do that? Is there any way to save pointer in instance of
ruby class e.g. in the same way as I can access strings?

Thanks in advance,

m.
 
B

Brian Candler

Marcin said:
I'm trying to write ruby interface to JACK audio library. I've chosen
RubyInline due it's simplicity.

I'm afraid I'm not answering your question, but have you looked at FFI?
This is designed to do exactly what you want, namely, calling an
existing C library from Ruby.
 
E

Eric Hodel

I'm trying to write ruby interface to JACK audio library. I've chosen
RubyInline due it's simplicity. What I want to achieve is to have ruby
code like this:

client = JACK::Client.new "my_name"
puts client.get_sample_rate

To achieve that I need to pass pointer to variable of jack_client_t*
from libjack from one function to another. What I tried to do is
available at http://pastebin.com/m3b6ee0c9 but as you can expect it
doesn't work.

How can I do that? Is there any way to save pointer in instance of
ruby class e.g. in the same way as I can access strings?

You'll need to use the Ruby/C API for this, namely Data_Wrap_Struct
and Data_Get_Struct. Passing around the pointer as an instance
variable (without even using INT2FIX/FIX2INT) can only lead to memory
leaks and segfaults.

If you're using RubyInline, place everything in the same inline block
per class. Use private as a method afterward:

class JACK::Client
inline do |builder|
builder.c <<-C
/* define connect */
C
end

private :connect
end

There are several strategies to wrapping C libraries in a class so
they are initialized properly.

This uses ::allocate:

http://github.com/drbrain/ffmpeg-rb/blob/master/lib/ffmpeg/fifo.rb

This uses ::new:

http://github.com/drbrain/ffmpeg-rb/blob/master/lib/ffmpeg/frame_buffer.rb

This uses a custom method ::for_decoder:

http://github.com/drbrain/ffmpeg-rb/blob/master/lib/ffmpeg/codec.rb

Also, your extension doesn't make much use of RubyInline's
helpfulness. RubyInline will automatically perform input and output
casts for you. Connect should be a class method written like:

builder.c_singleton <<-C
static VALUE connect(char *name) {
jack_client_t *client;

client = jack_client_new(name);

if (client == 0)
rb_raise(rb_eRuntimeError, "cannot connect to JACK server");

/* guessing at free function */
return Data_Wrap_Struct(self, NULL, jack_client_close, client);
}
C

With jack_get_sample_rate bound like:

builder.c <<-C
static jack_nframes_t sample_rate() { /* rubyish method name */
jack_client_t *client;

Data_Get_Struct(self, jack_client_t, client);

return jack_get_sample_rate(client);
}
C

and a type converter:

builder.alias_type_converter 'unsigned long', 'jack_nframes_t'
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top