/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
// Wrapper to the native phone test signal processing library, which
// exposes an interface suitable for calling via JNI.
#include <stdlib.h>
#include <jni.h>
#include "GenerateSinusoid.h"
#include "MeasureRms.h"
#include "GlitchTest.h"
#include "OverflowCheck.h"
#include "CompareSpectra.h"
#include "LinearityTest.h"
typedef short *shortPtr;
extern "C" {
JNIEXPORT jshortArray JNICALL
Java_com_android_cts_verifier_audioquality_Native_generateSinusoid(
JNIEnv *env, jobject obj,
jfloat freq, jfloat duration,
jfloat sampleRate, jfloat amplitude, jfloat ramp);
JNIEXPORT jfloatArray JNICALL
Java_com_android_cts_verifier_audioquality_Native_measureRms(
JNIEnv *env, jobject obj,
jshortArray jpcm, jfloat sampleRate, jfloat onsetThresh);
JNIEXPORT jfloatArray JNICALL
Java_com_android_cts_verifier_audioquality_Native_glitchTest(
JNIEnv *env, jobject obj,
jfloat sampleRate, jfloat stimFreq, jfloat onsetThresh,
jfloat dbSnrThresh, jshortArray jpcm);
JNIEXPORT jfloatArray JNICALL
Java_com_android_cts_verifier_audioquality_Native_overflowCheck(
JNIEnv *env, jobject obj,
jshortArray jpcm, jfloat sampleRate);
JNIEXPORT jfloatArray JNICALL
Java_com_android_cts_verifier_audioquality_Native_compareSpectra(
JNIEnv *env, jobject obj,
jshortArray jpcm, jshortArray jrefPcm, jfloat sampleRate);
JNIEXPORT jfloat JNICALL
Java_com_android_cts_verifier_audioquality_Native_linearityTest(
JNIEnv *env, jobject obj,
jobjectArray jpcms,
jfloat sampleRate, jfloat dbStepSize, jint referenceStim);
};
/* Returns an array of sinusoidal samples.
If the arguments are invalid, returns an empty array. */
JNIEXPORT jshortArray JNICALL
Java_com_android_cts_verifier_audioquality_Native_generateSinusoid(
JNIEnv *env, jobject obj,
jfloat freq, jfloat duration,
jfloat sampleRate, jfloat amplitude, jfloat ramp) {
short *wave = NULL;
int numSamples = 0;
generateSinusoid(freq, duration, sampleRate, amplitude, ramp,
&numSamples, &wave);
jshortArray ja;
if (!numSamples) {
ja = env->NewShortArray(0);
} else {
ja = env->NewShortArray(numSamples);
env->SetShortArrayRegion(ja, 0, numSamples, wave);
delete[] wave;
}
return ja;
}
/* Returns an array of four floats.
ret[0] = RMS
ret[1] = standard deviation of the RMS
ret[2] = non-silent region duration
ret[3] = mean value
*/
JNIEXPORT jfloatArray JNICALL
Java_com_android_cts_verifier_audioquality_Native_measureRms(
JNIEnv *env, jobject obj,
jshortArray jpcm, jfloat sampleRate, jfloat onsetThresh) {
float ret[4];
ret[0] = ret[1] = ret[2] = ret[3] = -1.0;
int numSamples = env->GetArrayLength(jpcm);
short *pcm = new short[numSamples];
env->GetShortArrayRegion(jpcm, 0, numSamples, pcm);
measureRms(pcm, numSamples, sampleRate, onsetThresh, ret, ret + 1,
ret + 3, ret + 2);
jfloatArray ja = env->NewFloatArray(4);
env->SetFloatArrayRegion(ja, 0, 4, ret);
return ja;
}
/* Returns an array of three floats.
ret[0] = #bad frames
ret[1] = error code
ret[2] = duration
Error code = 1 for success,
-1 if initialization failed,
-2 if insufficient samples
-3 if tone signal onset not found
-4 if tone signal end not found
*/
JNIEXPORT jfloatArray JNICALL
Java_com_android_cts_verifier_audioquality_Native_glitchTest(
JNIEnv *env, jobject obj,
jfloat sampleRate, jfloat stimFreq, jfloat onsetThresh,
jfloat dbSnrThresh, jshortArray jpcm) {
float ret[3];
int numSamples = env->GetArrayLength(jpcm);
short *pcm = new short[numSamples];
env->GetShortArrayRegion(jpcm, 0, numSamples, pcm);
GlitchTest gt;
gt.init(sampleRate, stimFreq, onsetThresh, dbSnrThresh);
float duration = -1.0;
int badFrames = -1;
int success = gt.checkToneSnr(pcm, numSamples, &duration, &badFrames);
ret[0] = badFrames;
ret[1] = success;
ret[2] = duration;
jfloatArray ja = env->NewFloatArray(3);
env->SetFloatArrayRegion(ja, 0, 3, ret);
return ja;
}
/* Returns an array of seven floats.
ret[0] = num deltas
ret[1] = error code
ret[2] = duration
ret[3] = onset
ret[4] = offset
ret[5] = max peak
ret[6] = min peak
Error code = 1 for success, -1 for failure. */
JNIEXPORT jfloatArray JNICALL
Java_com_android_cts_verifier_audioquality_Native_overflowCheck(
JNIEnv *env, jobject obj,
jshortArray jpcm, jfloat sampleRate) {
float ret[7];
int numSamples = env->GetArrayLength(jpcm);
short *pcm = new short[numSamples];
env->GetShortArrayRegion(jpcm, 0, numSamples, pcm);
float duration = -1.0;
int numDeltas = -1, onset = -1, offset = -1;
int maxPeak = 0, minPeak = 0;
int success = overflowCheck(pcm, numSamples, sampleRate,
&duration, &numDeltas, &onset, &offset, &maxPeak, &minPeak);
ret[0] = numDeltas;
ret[1] = success ? 1 : -1;
ret[2] = duration;
ret[3] = onset;
ret[4] = offset;
ret[5] = maxPeak;
ret[6] = minPeak;
jfloatArray ja = env->NewFloatArray(7);
env->SetFloatArrayRegion(ja, 0, 7, ret);
return ja;
}
/* Returns an array of three floats.
ret[0] = max deviation,
ret[1] = error code,
ret[2] = rms deviation.
Error code = 1 for success, -1 for failure. */
JNIEXPORT jfloatArray JNICALL
Java_com_android_cts_verifier_audioquality_Native_compareSpectra(
JNIEnv *env, jobject obj,
jshortArray jpcm, jshortArray jrefPcm, jfloat sampleRate) {
float ret[3];
int numSamples = env->GetArrayLength(jpcm);
short *pcm = new short[numSamples];
env->GetShortArrayRegion(jpcm, 0, numSamples, pcm);
int nRefSamples = env->GetArrayLength(jrefPcm);
short *refPcm = new short[nRefSamples];
env->GetShortArrayRegion(jrefPcm, 0, nRefSamples, refPcm);
float maxDeviation = -1.0, rmsDeviation = -1.0;
int success = compareSpectra(pcm, numSamples, refPcm, nRefSamples,
sampleRate, &maxDeviation, &rmsDeviation);
ret[1] = success ? 1 : -1;
ret[0] = maxDeviation;
ret[2] = rmsDeviation;
jfloatArray ja = env->NewFloatArray(3);
env->SetFloatArrayRegion(ja, 0, 3, ret);
return ja;
}
/* Return maximum deviation from linearity in dB.
On failure returns:
-1.0 The input signals or sample counts are missing.
-2.0 The number of input signals is < 2.
-3.0 The specified sample rate is <= 4000.0
-4.0 The dB step size for the increase in stimulus level is <= 0.0
-5.0 The specified reverence stimulus number is out of range.
-6.0 One or more of the stimuli is too short in duration.
*/
JNIEXPORT jfloat JNICALL
Java_com_android_cts_verifier_audioquality_Native_linearityTest(
JNIEnv *env, jobject obj,
jobjectArray jpcms,
jfloat sampleRate, jfloat dbStepSize, jint referenceStim) {
int numSignals = env->GetArrayLength(jpcms);
int *sampleCounts = new int[numSignals];
short **pcms = new shortPtr[numSignals];
jshortArray ja;
for (int i = 0; i < numSignals; i++) {
ja = (jshortArray) env->GetObjectArrayElement(jpcms, i);
sampleCounts[i] = env->GetArrayLength(ja);
pcms[i] = new short[sampleCounts[i]];
env->GetShortArrayRegion(ja, 0, sampleCounts[i], pcms[i]);
}
float maxDeviation = -1.0;
int ret = linearityTest(pcms, sampleCounts, numSignals,
sampleRate, dbStepSize, referenceStim, &maxDeviation);
delete[] sampleCounts;
for (int i = 0; i < numSignals; i++) {
delete[] pcms[i];
}
delete[] pcms;
if (ret < 1) return ret;
return maxDeviation;
}