4

I'm trying to make a standalone FFT extension for ruby in C, based on this recipe

I've noted several methods for passing different values between ruby and c. However im fairly new to both ruby and C and can't work out how to copy an array from a VALUE ruby object into a C array.

The compilation error: SimpleFFT.c:47: error: subscripted value is neither array nor pointer

And the code:

#include "ruby.h"
#include "fft.c" // the c file I wish to wrap in ruby

VALUE SimpleFFT = Qnil;
void Init_simplefft();
VALUE method_rfft(VALUE self, VALUE anObject);

void Init_simplefft() {
    SimpleFFT = rb_define_module("SimpleFFT");
    rb_define_method(SimpleFFT, "rfft", method_rfft, 1);
}

VALUE method_rfft(VALUE self, VALUE inputArr) {
    int N = RARRAY_LEN(inputArr); // this works :)

    // the FFT function takes an array of real and imaginary paired values
    double (*x)[2] = malloc(2 * N * sizeof(double)); 
    // and requires as an argument another such array (empty) for the transformed output
    double (*X)[2] = malloc(2 * N * sizeof(double));

    for(i=0; i<N; i++) {
        x[i][0]=NUM2DBL(inputArr[i]); // ***THIS LINE CAUSES THE ERROR***
        x[i][1]=0;  // setting all the imaginary values to zero for simplicity
    }

    fft(N, x, X); // the target function call

    // this bit should work in principle, dunno if it's optimal
    VALUE outputArr = rb_ary_new();
    for(i=0; i<N; i++){
        rb_ary_push(outputArr, DBL2NUM(X[i][0]));
    }

    free(x);
    free(X);

    return outputArr;
}

Thanks in advance :)

2 Answers 2

4

You can't subscript inputArr because it's a VALUE rather than a C array. Ie, it's a scalar type. To access a particular index, use

rb_ary_entry(inputArr, i)

As an aside, you might want to verify first that it's an array:

Check_Type(rarray, T_ARRAY);
2
  • thanks for the tip :). I answered myself without refreshing, oops! Is there any reason accessing the array entry might be better or worse than popping off values?
    – Nat
    Commented Dec 24, 2010 at 2:24
  • @Nat I don't know how Ruby implements its push/pop mechanism vs random access. If one scheme involves shuffling content or reallocating memory, then that would be less efficient. Sadly, I'm not sure which it is without digging through the Ruby source code... However, you could profile your application if you are really concerned with performance. Commented Dec 24, 2010 at 2:45
2

looks like answering the question (and double checking my sources) helped me work out the answer.

replacing:

    rb_ary_push(outputArr, DBL2NUM(X[i][0]));

with:

    x[i][0]=NUM2DBL(rb_ary_pop(inputArr));

seemed to do the trick :)

I'm still wonder if this is the most efficient way of doing things, but it works.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.