Home | History | Annotate | Download | only in audioquality
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 // Wrapper to the native phone test signal processing library, which
     18 // exposes an interface suitable for calling via JNI.
     19 
     20 #include <stdlib.h>
     21 #include <jni.h>
     22 
     23 #include "GenerateSinusoid.h"
     24 #include "MeasureRms.h"
     25 #include "GlitchTest.h"
     26 #include "OverflowCheck.h"
     27 #include "CompareSpectra.h"
     28 #include "LinearityTest.h"
     29 
     30 typedef short *shortPtr;
     31 
     32 extern "C" {
     33     JNIEXPORT jshortArray JNICALL
     34         Java_com_android_cts_verifier_audioquality_Native_generateSinusoid(
     35             JNIEnv *env, jobject obj,
     36             jfloat freq, jfloat duration,
     37             jfloat sampleRate, jfloat amplitude, jfloat ramp);
     38     JNIEXPORT jfloatArray JNICALL
     39         Java_com_android_cts_verifier_audioquality_Native_measureRms(
     40             JNIEnv *env, jobject obj,
     41             jshortArray jpcm, jfloat sampleRate, jfloat onsetThresh);
     42     JNIEXPORT jfloatArray JNICALL
     43         Java_com_android_cts_verifier_audioquality_Native_glitchTest(
     44             JNIEnv *env, jobject obj,
     45             jfloat sampleRate, jfloat stimFreq, jfloat onsetThresh,
     46             jfloat dbSnrThresh, jshortArray jpcm);
     47     JNIEXPORT jfloatArray JNICALL
     48         Java_com_android_cts_verifier_audioquality_Native_overflowCheck(
     49             JNIEnv *env, jobject obj,
     50             jshortArray jpcm, jfloat sampleRate);
     51     JNIEXPORT jfloatArray JNICALL
     52         Java_com_android_cts_verifier_audioquality_Native_compareSpectra(
     53             JNIEnv *env, jobject obj,
     54             jshortArray jpcm, jshortArray jrefPcm, jfloat sampleRate);
     55     JNIEXPORT jfloat JNICALL
     56         Java_com_android_cts_verifier_audioquality_Native_linearityTest(
     57             JNIEnv *env, jobject obj,
     58             jobjectArray jpcms,
     59             jfloat sampleRate, jfloat dbStepSize, jint referenceStim);
     60 
     61     JNIEXPORT jfloat JNICALL
     62         Java_com_android_cts_verifier_audioquality_Native_linearityTestRms(
     63             JNIEnv *env, jobject obj,
     64             jobjectArray jpcms,
     65             jfloat sampleRate, jfloat dbStepSize);
     66 };
     67 
     68 /* Returns an array of sinusoidal samples.
     69    If the arguments are invalid, returns an empty array. */
     70 JNIEXPORT jshortArray JNICALL
     71     Java_com_android_cts_verifier_audioquality_Native_generateSinusoid(
     72         JNIEnv *env, jobject obj,
     73         jfloat freq, jfloat duration,
     74         jfloat sampleRate, jfloat amplitude, jfloat ramp) {
     75     short *wave = NULL;
     76     int numSamples = 0;
     77 
     78     generateSinusoid(freq, duration, sampleRate, amplitude, ramp,
     79             &numSamples, &wave);
     80 
     81     jshortArray ja;
     82     if (!numSamples) {
     83         ja = env->NewShortArray(0);
     84     } else {
     85         ja = env->NewShortArray(numSamples);
     86         env->SetShortArrayRegion(ja, 0, numSamples, wave);
     87         delete[] wave;
     88     }
     89     return ja;
     90 }
     91 
     92 /* Returns an array of four floats.
     93    ret[0] = RMS
     94    ret[1] = standard deviation of the RMS
     95    ret[2] = non-silent region duration
     96    ret[3] = mean value
     97 */
     98 JNIEXPORT jfloatArray JNICALL
     99     Java_com_android_cts_verifier_audioquality_Native_measureRms(
    100         JNIEnv *env, jobject obj,
    101         jshortArray jpcm, jfloat sampleRate, jfloat onsetThresh) {
    102     float ret[4];
    103     ret[0] = ret[1] = ret[2] = ret[3] = -1.0;
    104     int numSamples = env->GetArrayLength(jpcm);
    105     short *pcm = new short[numSamples];
    106     env->GetShortArrayRegion(jpcm, 0, numSamples, pcm);
    107 
    108     measureRms(pcm, numSamples, sampleRate, onsetThresh, ret, ret + 1,
    109             ret + 3, ret + 2);
    110 
    111     jfloatArray ja = env->NewFloatArray(4);
    112     env->SetFloatArrayRegion(ja, 0, 4, ret);
    113     return ja;
    114 }
    115 
    116 /* Returns an array of three floats.
    117    ret[0] = #bad frames
    118    ret[1] = error code
    119    ret[2] = duration
    120    Error code = 1 for success,
    121                -1 if initialization failed,
    122                -2 if insufficient samples
    123                -3 if tone signal onset not found
    124                -4 if tone signal end not found
    125 */
    126 JNIEXPORT jfloatArray JNICALL
    127     Java_com_android_cts_verifier_audioquality_Native_glitchTest(
    128         JNIEnv *env, jobject obj,
    129         jfloat sampleRate, jfloat stimFreq, jfloat onsetThresh,
    130         jfloat dbSnrThresh, jshortArray jpcm) {
    131     float ret[3];
    132     int numSamples = env->GetArrayLength(jpcm);
    133     short *pcm = new short[numSamples];
    134     env->GetShortArrayRegion(jpcm, 0, numSamples, pcm);
    135 
    136     GlitchTest gt;
    137     gt.init(sampleRate, stimFreq, onsetThresh, dbSnrThresh);
    138     float duration = -1.0;
    139     int badFrames = -1;
    140     int success = gt.checkToneSnr(pcm, numSamples, &duration, &badFrames);
    141     ret[0] = badFrames;
    142     ret[1] = success;
    143     ret[2] = duration;
    144     jfloatArray ja = env->NewFloatArray(3);
    145     env->SetFloatArrayRegion(ja, 0, 3, ret);
    146     return ja;
    147 }
    148 
    149 /* Returns an array of seven floats.
    150    ret[0] = num deltas
    151    ret[1] = error code
    152    ret[2] = duration
    153    ret[3] = onset
    154    ret[4] = offset
    155    ret[5] = max peak
    156    ret[6] = min peak
    157    Error code = 1 for success, -1 for failure. */
    158 JNIEXPORT jfloatArray JNICALL
    159     Java_com_android_cts_verifier_audioquality_Native_overflowCheck(
    160         JNIEnv *env, jobject obj,
    161         jshortArray jpcm, jfloat sampleRate) {
    162     float ret[7];
    163     int numSamples = env->GetArrayLength(jpcm);
    164     short *pcm = new short[numSamples];
    165     env->GetShortArrayRegion(jpcm, 0, numSamples, pcm);
    166 
    167     float duration = -1.0;
    168     int numDeltas = -1, onset = -1, offset = -1;
    169     int maxPeak = 0, minPeak = 0;
    170     int success = overflowCheck(pcm, numSamples, sampleRate,
    171             &duration, &numDeltas, &onset, &offset, &maxPeak, &minPeak);
    172     ret[0] = numDeltas;
    173     ret[1] = success ? 1 : -1;
    174     ret[2] = duration;
    175     ret[3] = onset;
    176     ret[4] = offset;
    177     ret[5] = maxPeak;
    178     ret[6] = minPeak;
    179     jfloatArray ja = env->NewFloatArray(7);
    180     env->SetFloatArrayRegion(ja, 0, 7, ret);
    181     return ja;
    182 }
    183 
    184 /* Returns an array of three floats.
    185    ret[0] = max deviation,
    186    ret[1] = error code,
    187    ret[2] = rms deviation.
    188    Error code = 1 for success, -1 for failure. */
    189 JNIEXPORT jfloatArray JNICALL
    190     Java_com_android_cts_verifier_audioquality_Native_compareSpectra(
    191         JNIEnv *env, jobject obj,
    192         jshortArray jpcm, jshortArray jrefPcm, jfloat sampleRate) {
    193     float ret[3];
    194     int numSamples = env->GetArrayLength(jpcm);
    195     short *pcm = new short[numSamples];
    196     env->GetShortArrayRegion(jpcm, 0, numSamples, pcm);
    197     int nRefSamples = env->GetArrayLength(jrefPcm);
    198     short *refPcm = new short[nRefSamples];
    199     env->GetShortArrayRegion(jrefPcm, 0, nRefSamples, refPcm);
    200 
    201     float maxDeviation = -1.0, rmsDeviation = -1.0;
    202     int success = compareSpectra(pcm, numSamples, refPcm, nRefSamples,
    203             sampleRate, &maxDeviation, &rmsDeviation);
    204     ret[1] = success ? 1 : -1;
    205 
    206     ret[0] = maxDeviation;
    207     ret[2] = rmsDeviation;
    208     jfloatArray ja = env->NewFloatArray(3);
    209     env->SetFloatArrayRegion(ja, 0, 3, ret);
    210     return ja;
    211 }
    212 
    213 /* Return maximum deviation from linearity in dB.
    214    On failure returns:
    215       -1.0 The input signals or sample counts are missing.
    216       -2.0 The number of input signals is < 2.
    217       -3.0 The specified sample rate is <= 4000.0
    218       -4.0 The dB step size for the increase in stimulus level is <= 0.0
    219       -5.0 The specified reverence stimulus number is out of range.
    220       -6.0 One or more of the stimuli is too short in duration.
    221 */
    222 JNIEXPORT jfloat JNICALL
    223     Java_com_android_cts_verifier_audioquality_Native_linearityTest(
    224         JNIEnv *env, jobject obj,
    225         jobjectArray jpcms,
    226         jfloat sampleRate, jfloat dbStepSize, jint referenceStim) {
    227     int numSignals = env->GetArrayLength(jpcms);
    228     int *sampleCounts = new int[numSignals];
    229     short **pcms = new shortPtr[numSignals];
    230     jshortArray ja;
    231     for (int i = 0; i < numSignals; i++) {
    232         ja = (jshortArray) env->GetObjectArrayElement(jpcms, i);
    233         sampleCounts[i] = env->GetArrayLength(ja);
    234         pcms[i] = new short[sampleCounts[i]];
    235         env->GetShortArrayRegion(ja, 0, sampleCounts[i], pcms[i]);
    236     }
    237 
    238     float maxDeviation = -1.0;
    239     int ret = linearityTest(pcms, sampleCounts, numSignals,
    240             sampleRate, dbStepSize, referenceStim, &maxDeviation);
    241     delete[] sampleCounts;
    242     for (int i = 0; i < numSignals; i++) {
    243         delete[] pcms[i];
    244     }
    245     delete[] pcms;
    246     if (ret < 1) return ret;
    247 
    248     return maxDeviation;
    249 }
    250 
    251 
    252 /* Return maximum deviation from linearity in dB.
    253    On failure returns:
    254       -1.0 The input signals or sample counts are missing.
    255       -2.0 The number of input signals is < 2.
    256       -3.0 The specified sample rate is <= 4000.0
    257       -4.0 The dB step size for the increase in stimulus level is <= 0.0
    258       -6.0 One or more of the stimuli is too short in duration.
    259 */
    260 JNIEXPORT jfloat JNICALL
    261     Java_com_android_cts_verifier_audioquality_Native_linearityTestRms(
    262         JNIEnv *env, jobject obj,
    263         jobjectArray jpcms,
    264         jfloat sampleRate, jfloat dbStepSize) {
    265     int numSignals = env->GetArrayLength(jpcms);
    266     int *sampleCounts = new int[numSignals];
    267     short **pcms = new shortPtr[numSignals];
    268     jshortArray ja;
    269     for (int i = 0; i < numSignals; i++) {
    270         ja = (jshortArray) env->GetObjectArrayElement(jpcms, i);
    271         sampleCounts[i] = env->GetArrayLength(ja);
    272         pcms[i] = new short[sampleCounts[i]];
    273         env->GetShortArrayRegion(ja, 0, sampleCounts[i], pcms[i]);
    274     }
    275 
    276     float maxDeviation = -1.0;
    277     int ret = linearityTestRms(pcms, sampleCounts, numSignals,
    278             sampleRate, dbStepSize, &maxDeviation);
    279     delete[] sampleCounts;
    280     for (int i = 0; i < numSignals; i++) {
    281         delete[] pcms[i];
    282     }
    283     delete[] pcms;
    284     if (ret < 1) return ret;
    285 
    286     return maxDeviation;
    287 }
    288