JNI中的双数组

时间:2015-04-02 09:49:57

标签: android android-ndk java-native-interface

我尝试在Android上使用JNI实现两个音频文件的直接卷积。到目前为止,我已经这样做了:

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;}

在java方面:

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]);
}

结果数组(out)全为零。我不明白我做错了什么。有什么帮助吗?

2 个答案:

答案 0 :(得分:3)

您对JNI阵列的处理完全错误。首先,你没有理由在这里创建任何新阵列。传递下来的输入和输出,您要做的是将输入转换为C数组,在纯C中处理它们,然后将输出数组转换为Java数组。

其次,您不需要memcpys。调用getDoubleArrayElements可以帮到你。

第三,你需要通过setDoubleArrayRegion将值输出到输出中

第四,您需要清理内存使用情况。如果你不这样做,你会发生内存泄漏并最终死亡,因为它有256的限制(或者是512?我忘了太久了)Java对象被固定到C。

您的代码应该更像:

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;}

我会假设你的卷积数学是正确的,它让我开始记忆那些东西太晚了:)

答案 1 :(得分:0)

我弄明白了这个问题。我添加了文件大小作为参数,如下所示:

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;
}