hanaa
hanaa

Reputation: 405

Double Arrays in JNI

I tried implementing direct convolution of two audio files using JNI on Android.. So far, I ve done this:

JNIEXPORT jint JNICALL Java_com_example_directconv_MainActivity_convolve (JNIEnv * env, jobject obj, jdoubleArray signal1, jdoubleArray signal2, jdoubleArray output)

{

jdouble *sig1, *sig2, *out;

//  jboolean     isCopy1, isCopy2, isCopy3;
int i,j;
jsize n,m;

sig1=(*env)->NewDoubleArray(env,n);
sig2=(*env)->NewDoubleArray(env,m);
out=(*env)->NewDoubleArray(env,m);


n=(*env)->GetArrayLength(env, sig1);
m=(*env)->GetArrayLength(env,sig2);

sig1=(*env)->GetDoubleArrayElements(env, signal1,NULL);
sig2=(*env)->GetDoubleArrayElements(env, signal2,NULL);
out=(*env)->GetDoubleArrayElements(env, output, NULL);

if (sig1 != NULL || sig2!=NULL) {

    memcpy(signal1,sig1,n);
    memcpy(signal2,sig2,m);

    (*env)->ReleaseDoubleArrayElements(env,signal1,sig1,JNI_ABORT);
    (*env)->ReleaseDoubleArrayElements(env,signal2,sig2,JNI_ABORT);
}


for(i=0; i<n;i++)
{
    out[i]=0;
    for(j=0;j<m;j++)
    {
        out[i]+=sig1[i-j]*sig2[j];
    }
}

(*env)->ReleaseDoubleArrayElements(env,output,out,0);


return 1;}

And on the java side:

public class MainActivity extends Activity {

static
{
    System.loadLibrary("DirectConv");
}
File externalDir1=Environment.getExternalStorageDirectory();
File externalDir2=Environment.getExternalStorageDirectory();
File f1=new File(externalDir1.getAbsolutePath()+"/Test"+File.separator+"wav2.wav");
File f2=new File(externalDir2.getAbsolutePath()+"/Test"+File.separator+"wav2.wav");
int res;
public native int convolve(double[]signal1, double[]signal2, double[]output);
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
try {

        //---------------------------------------------read files
        double[]raw1=read(f1);
        double[]raw2=read(f2);
        double[]out=new double[raw1.length];
        res=convolve(raw1,raw2,out);
        for(int i=0;i<out.length;i++)
        Log.i("out", "out   "+ out[i]);
}

The resulting array (out) is all zeros. I don't see what I did wrong. Any help?

Upvotes: 0

Views: 3339

Answers (2)

hanaa
hanaa

Reputation: 405

I figured out the problem. I added files sizes as parameters like this:

JNIEXPORT jint JNICALL Java_com_example_directconv_MainActivity_convolve (JNIEnv * env, jobject obj, jdoubleArray signal1, jdoubleArray signal2, jdoubleArray output, jint size1, jint size2)
{
jdouble *sig1, *sig2, *out;
int i,j,k;
jint n,m;

n=size1;
m=size2;

sig1=(*env)->GetDoubleArrayElements(env, signal1,NULL);
sig2=(*env)->GetDoubleArrayElements(env, signal2,NULL);
out=(*env)->GetDoubleArrayElements(env,output,NULL);


for(i=0; i<n;i++)
{
    out[i]=0;

    for(j=0;j<m;j++)
    {
        if(i-j>=0)

        out[i]+=sig1[i-j]*sig2[j];
    }
}

(*env)->SetDoubleArrayRegion(env, output, 0, n, out);
(*env)->ReleaseDoubleArrayElements(env,signal1,sig1,JNI_ABORT);
(*env)->ReleaseDoubleArrayElements(env,signal2,sig2,JNI_ABORT);

return 1;
}

Upvotes: 0

Gabe Sechan
Gabe Sechan

Reputation: 93668

Your handling of JNI arrays is all wrong. First off, there's no reason for you to be creating any new arrays here. YOur inputs and outputs are passed down, what you want to do is convert the inputs to C arrays, work on them in pure C, then convert your output array to a Java array.

Secondly, you don't need the memcpys. Calling getDoubleArrayElements does it for you.

Third, you need to put the values in out back into output via setDoubleArrayRegion

Fourth, you need to clean up your memory usage. If you don't, you're going to memory leak and eventually die as there's a limit of 256 (or is it 512? Been too long I forget) Java objects pinned to C.

Your code should look more like:

JNIEXPORT jint JNICALL Java_com_example_directconv_MainActivity_convolve (JNIEnv * env, jobject obj, jdoubleArray signal1, jdoubleArray signal2, jdoubleArray output)

{

double *sig1, *sig2, *out;

int i,j;
jsize n,m;


n=(*env)->GetArrayLength(env, sig1);
m=(*env)->GetArrayLength(env,sig2);

sig1=(*env)->GetDoubleArrayElements(env, signal1,NULL);
sig2=(*env)->GetDoubleArrayElements(env, signal2,NULL);

for(i=0; i<n;i++)
{
    out[i]=0;
    for(j=0;j<m;j++)
    {
        out[i]+=sig1[i-j]*sig2[j];
    }
}

(*env)->SetDoubleArrayRegion(env, output, 0, n, out);

(*env)->ReleaseDoubleArrayElements(env,signal1,sig1,JNI_ABORT);
(*env)->ReleaseDoubleArrayElements(env,signal2,sig2,JNI_ABORT);

return 1;}

I'm going to assume your convolution math is right, its way too late for me to start remembering that stuff :)

Upvotes: 4

Related Questions