Пример #1
0
int main (int argc, char *argv[])
{
    awgn_state_t noise_source;
    dc_restore_state_t dc_state;
    int i;
    int idum = 1234567;
    int16_t dirty;
    int16_t clean;
    int estimate;
    int min;
    int max;
    int dc_offset;

    dc_offset = 5000;
    awgn_init_dbm0(&noise_source, idum, -10.0);
    dc_restore_init(&dc_state);
    for (i = 0;  i < 100000;  i++)
    {
        dirty = awgn(&noise_source) + dc_offset;
        clean = dc_restore(&dc_state, dirty);
        if ((i % 1000) == 0)
        {
            printf("Sample %6d: %d (expect %d)\n",
                   i,
                   dc_restore_estimate(&dc_state),
                   dc_offset);
        }
    }
    /* We should have settled by now. Look at the variation we get */
    min = 99999;
    max = -99999;
    for (i = 0;  i < 100000;  i++)
    {
        dirty = awgn(&noise_source) + dc_offset;
        clean = dc_restore(&dc_state, dirty);
        estimate = dc_restore_estimate(&dc_state);
        if (estimate < min)
            min = estimate;
        if (estimate > max)
            max = estimate;
    }
    printf("Spread of DC estimate for an offset of %d was %d to %d\n", dc_offset, min, max);
    if (min < dc_offset - 50  ||  max > dc_offset + 50)
    {
        printf("Test failed.\n");
        exit(2);
    }
    printf("Test passed.\n");
    return  0;
}
Пример #2
0
static float calc_far_line_filter(one_way_line_model_state_t *s, float v)
{
    float sum;
    int j;
    int p;

    /* Add the sample in the filter buffer */
    p = s->far_buf_ptr;
    s->far_buf[p] = v;
    if (++p == s->far_filter_len)
        p = 0;
    s->far_buf_ptr = p;
    
    /* Apply the filter */
    sum = 0;
    for (j = 0;  j < s->far_filter_len;  j++)
    {
        sum += s->far_filter[j]*s->far_buf[p];
        if (++p >= s->far_filter_len)
            p = 0;
    }
    
    /* Add noise */
    sum += awgn(&s->far_noise);

    return sum;
}
Пример #3
0
static void complexify_tests(void)
{
    complexify_state_t *s;
    complexf_t cc;
    int16_t amp;
    int i;
    SNDFILE *outhandle;
    int outframes;
    int16_t out[40000];
    awgn_state_t noise1;

    if ((outhandle = sf_open_telephony_write(OUT_FILE_COMPLEXIFY, 2)) == NULL)
    {
        fprintf(stderr, "    Cannot create audio file '%s'\n", OUT_FILE_COMPLEXIFY);
        exit(2);
    }
    awgn_init_dbm0(&noise1, 1234567, -10.0f);
    s = complexify_init();
    for (i = 0;  i < 20000;  i++)
    {
        amp = awgn(&noise1);
        cc = complexify(s, amp);
        out[2*i] = cc.re;
        out[2*i + 1] = cc.im;
    }
    awgn_release(&noise1);
    complexify_free(s);
    outframes = sf_writef_short(outhandle, out, 20000);
    if (outframes != 20000)
    {
        fprintf(stderr, "    Error writing audio file\n");
        exit(2);
    }
    if (sf_close_telephony(outhandle))
    {
        fprintf(stderr, "    Cannot close audio file '%s'\n", OUT_FILE_COMPLEXIFY);
        exit(2);
    }
}
Пример #4
0
int main(int argc, char *argv[])
{
    int duration;
    int i;
    int j;
    int len;
    int sample;
    const char *s;
    char digit[2];
    char buf[MAX_BELL_MF_DIGITS + 1];
    int actual;
    int nplus;
    int nminus;
    float rrb;
    float rcfo;
    time_t now;
    bell_mf_rx_state_t *mf_state;
    awgn_state_t noise_source;

    time(&now);
    mf_state = bell_mf_rx_init(NULL, NULL, NULL);

    /* Test 1: Mitel's test 1 isn't really a test. Its a calibration step,
       which has no meaning here. */
    printf("Test 1: Calibration\n");
    printf("    Passed\n");

    /* Test 2: Decode check
       This is a sanity check, that all digits are reliably detected
       under ideal conditions.  Each possible digit is repeated 10 times,
       with 68ms bursts. The level of each tone is about 6dB down from clip */
    printf("Test 2: Decode check\n");
    my_mf_gen_init(0.0, -3, 0.0, -3, 68, 68);
    s = ALL_POSSIBLE_DIGITS;
    digit[1] = '\0';
    while (*s)
    {
        digit[0] = *s++;
        for (i = 0;  i < 10;  i++)
        {
            len = my_mf_generate(amp, digit);
            codec_munge(amp, len);
            bell_mf_rx(mf_state, amp, len);
            actual = bell_mf_rx_get(mf_state, buf, 128);
            if (actual != 1  ||  buf[0] != digit[0])
            {
                printf("    Sent     '%s'\n", digit);
                printf("    Received '%s' [%d]\n", buf, actual);
                printf("    Failed\n");
                exit(2);
            }
        }
    }
    printf("    Passed\n");

    /* Test 3: Recognition bandwidth and channel centre frequency check.
       Use all digits. Each digit types requires four tests to complete
       the check. Each section contains 40 pulses of 68ms duration,
       with an amplitude of -20dB from clip per frequency.

       Four sections covering the tests for one tone (1 digit) are:
       a. H frequency at 0% deviation from center, L frequency at +0.1%.
          L frequency is then increments in +01.% steps up to +4%. The
          number of tone bursts is noted and designated N+.
       b. H frequency at 0% deviation, L frequency at -0.1%. L frequency
          is then incremental in -0.1% steps, up to -4%. The number of
          tone bursts is noted and designated N-.
       c. The test in (a) is repeated with the L frequency at 0% and the
          H frequency varied up to +4%.
       d. The test in (b) is repeated with the L frequency and 0% and the
          H frequency varied to -4%.

       Receiver Recognition Bandwidth (RRB) is calculated as follows:
            RRB% = (N+ + N-)/10
       Receiver Center Frequency Offset (RCFO) is calculated as follows:
            RCFO% = X + (N+ - N-)/20

       Note that this test doesn't test what it says it is testing at all,
       and the results are quite inaccurate, if not a downright lie! However,
       it follows the Mitel procedure, so how can it be bad? :)

       The spec calls for +-1.5% +-10Hz of bandwidth.
    */
    printf("Test 3: Recognition bandwidth and channel centre frequency check\n");
    s = ALL_POSSIBLE_DIGITS;
    digit[1] = '\0';
    j = 0;
    while (*s)
    {
        digit[0] = *s++;
        for (nplus = 0, i = 1;  i <= 60;  i++)
        {
            my_mf_gen_init((float) i/1000.0, -17, 0.0, -17, 68, 68);
            len = my_mf_generate(amp, digit);
            codec_munge(amp, len);
            bell_mf_rx(mf_state, amp, len);
            nplus += bell_mf_rx_get(mf_state, buf, 128);
        }
        for (nminus = 0, i = -1;  i >= -60;  i--)
        {
            my_mf_gen_init((float) i/1000.0, -17, 0.0, -17, 68, 68);
            len = my_mf_generate(amp, digit);
            codec_munge(amp, len);
            bell_mf_rx(mf_state, amp, len);
            nminus += bell_mf_rx_get(mf_state, buf, 128);
        }
        rrb = (float) (nplus + nminus)/10.0;
        rcfo = (float) (nplus - nminus)/10.0;
        printf("    %c (low)  rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n",
               digit[0],
               rrb,
               rcfo,
               (float) nminus/10.0,
               (float) nplus/10.0);

        if (rrb < 3.0 + rcfo + (2.0*100.0*10.0/bell_mf_tones[j].f1)  ||  rrb >= 15.0 + rcfo)
        {
            printf("    Failed\n");
            exit(2);
        }

        for (nplus = 0, i = 1;  i <= 60;  i++)
        {
            my_mf_gen_init(0.0, -17, (float) i/1000.0, -17, 68, 68);
            len = my_mf_generate(amp, digit);
            codec_munge(amp, len);
            bell_mf_rx(mf_state, amp, len);
            nplus += bell_mf_rx_get(mf_state, buf, 128);
        }
        for (nminus = 0, i = -1;  i >= -60;  i--)
        {
            my_mf_gen_init(0.0, -17, (float) i/1000.0, -17, 68, 68);
            len = my_mf_generate(amp, digit);
            codec_munge(amp, len);
            bell_mf_rx(mf_state, amp, len);
            nminus += bell_mf_rx_get(mf_state, buf, 128);
        }
        rrb = (float) (nplus + nminus)/10.0;
        rcfo = (float) (nplus - nminus)/10.0;
        printf("    %c (high) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n",
               digit[0],
               rrb,
               rcfo,
               (float) nminus/10.0,
               (float) nplus/10.0);
        if (rrb < 3.0 + rcfo + (2.0*100.0*10.0/bell_mf_tones[j].f2)  ||  rrb >= 15.0 + rcfo)
        {
            printf("    Failed\n");
            exit(2);
        }
        j++;
    }
    printf("    Passed\n");

    /* Test 4: Acceptable amplitude ratio (twist).
       Twist all digits in both directions, and check the maximum twist
       we can accept. The way this is done is styled after the Mitel DTMF
       test, and has good and bad points. */

    printf("Test 4: Acceptable amplitude ratio (twist)\n");
    s = ALL_POSSIBLE_DIGITS;
    digit[1] = '\0';
    while (*s)
    {
        digit[0] = *s++;
        for (nplus = 0, i = -50;  i >= -250;  i--)
        {
            my_mf_gen_init(0.0, -5, 0.0, i/10, 68, 68);

            len = my_mf_generate(amp, digit);
            codec_munge(amp, len);
            bell_mf_rx(mf_state, amp, len);
            nplus += bell_mf_rx_get(mf_state, buf, 128);
        }
        printf("    %c normal twist  = %.2fdB\n", digit[0], (float) nplus/10.0);
        if (nplus < 60)
        {
            printf("    Failed\n");
            exit(2);
        }
        for (nminus = 0, i = -50;  i >= -250;  i--)
        {
            my_mf_gen_init(0.0, i/10, 0.0, -5, 68, 68);

            len = my_mf_generate(amp, digit);
            codec_munge(amp, len);
            bell_mf_rx(mf_state, amp, len);
            nminus += bell_mf_rx_get(mf_state, buf, 128);
        }
        printf("    %c reverse twist = %.2fdB\n", digit[0], (float) nminus/10.0);
        if (nminus < 60)
        {
            printf("    Failed\n");
            exit(2);
        }
    }
    printf("    Passed\n");

    /* Test 5: Dynamic range
       This test sends all possible digits, with gradually increasing
       amplitude. We determine the span over which we achieve reliable
       detection. The spec says we should detect between -14dBm and 0dBm,
       but the tones clip above -3dBm, so this cannot really work. */

    printf("Test 5: Dynamic range\n");
    for (nplus = nminus = -1000, i = -50;  i <= 3;  i++)
    {
        my_mf_gen_init(0.0, i, 0.0, i, 68, 68);
        for (j = 0;  j < 100;  j++)
        {
            len = my_mf_generate(amp, ALL_POSSIBLE_DIGITS);
            codec_munge(amp, len);
            bell_mf_rx(mf_state, amp, len);
            if (bell_mf_rx_get(mf_state, buf, 128) != 15)
                break;
            if (strcmp(buf, ALL_POSSIBLE_DIGITS) != 0)
                break;
        }
        if (j == 100)
        {
            if (nplus == -1000)
                nplus = i;
        }
        else
        {
            if (nplus != -1000  &&  nminus == -1000)
                nminus = i;
        }
    }
    printf("    Dynamic range = %ddB to %ddB\n", nplus, nminus - 1);
    if (nplus > -22  ||  nminus <= -3)
    {
        printf("    Failed\n");
        exit(2);
    }
    printf("    Passed\n");

    /* Test 6: Guard time
       This test sends all possible digits, with a gradually reducing
       duration. The spec defines a narrow range of tone duration
       times we can expect, so as long as we detect reliably at the
       specified minimum we should be OK. However, the spec also says
       we should detect on a minimum of 55ms of KP, or 30ms of other
       digits. */

    printf("Test 6: Guard time\n");
    for (i = 30;  i < 62;  i++)
    {
        my_mf_gen_init(0.0, -5, 0.0, -3, i, 68);
        for (j = 0;  j < 500;  j++)
        {
            len = my_mf_generate(amp, ALL_POSSIBLE_DIGITS);
            codec_munge(amp, len);
            bell_mf_rx(mf_state, amp, len);
            if (bell_mf_rx_get(mf_state, buf, 128) != 15)
                break;
            if (strcmp(buf, ALL_POSSIBLE_DIGITS) != 0)
                break;
        }
        if (j == 500)
            break;
    }
    printf("    Guard time = %dms\n", i);
    if (i > 61)
    {
        printf("    Failed\n");
        exit(2);
    }
    printf("    Passed\n");

    /* Test 7: Acceptable signal to noise ratio
       We send all possible digits at -6dBm from clip, mixed with AWGN.
       We gradually reduce the noise until we get clean detection. */

    printf("Test 7: Acceptable signal to noise ratio\n");
    my_mf_gen_init(0.0, -3, 0.0, -3, 68, 68);
    for (i = -10;  i > -50;  i--)
    {
        awgn_init_dbm0(&noise_source, 1234567, (float) i);
        for (j = 0;  j < 500;  j++)
        {
            len = my_mf_generate(amp, ALL_POSSIBLE_DIGITS);
            for (sample = 0;  sample < len;  sample++)
                amp[sample] = saturate(amp[sample] + awgn(&noise_source));
            codec_munge(amp, len);
            bell_mf_rx(mf_state, amp, len);
            if (bell_mf_rx_get(mf_state, buf, 128) != 15)
                break;
            if (strcmp(buf, ALL_POSSIBLE_DIGITS) != 0)
                break;
        }
        if (j == 500)
            break;
    }
    printf("    Acceptable S/N ratio is %ddB\n", -3 - i);
    if (-3 - i > 26)
    {
        printf("    Failed\n");
        exit(2);
    }
    bell_mf_rx_free(mf_state);
    printf("    Passed\n");

    /* The remainder of the Mitel tape is the talk-off test. This is
       meaningless for Bell MF. However the decoder's tolerance of
       out of band noise is significant. */
    /* TODO: add a OOB tolerance test. */

    /* Test the callback mode for delivering detected digits */

    printf("Test: Callback digit delivery mode.\n");
    callback_ok = false;
    callback_roll = 0;
    mf_state = bell_mf_rx_init(NULL, digit_delivery, (void *) 0x12345678);
    my_mf_gen_init(0.0, -10, 0.0, -10, 68, 68);
    for (i = 1;  i < 10;  i++)
    {
        len = 0;
        for (j = 0;  j < i;  j++)
            len += my_mf_generate(amp + len, ALL_POSSIBLE_DIGITS);
        bell_mf_rx(mf_state, amp, len);
        if (!callback_ok)
            break;
    }
    if (!callback_ok)
    {
        printf("    Failed\n");
        exit(2);
    }
    bell_mf_rx_free(mf_state);
    printf("    Passed\n");

    duration = time (NULL) - now;
    printf("Tests passed in %ds\n", duration);
    return 0;
}
Пример #5
0
static void test_both_ways_model(int line_model_no, int speech_test)
{
    both_ways_line_model_state_t *model;
    int16_t input1[BLOCK_LEN];
    int16_t input2[BLOCK_LEN];
    int16_t output1[BLOCK_LEN];
    int16_t output2[BLOCK_LEN];
    int16_t amp[2*BLOCK_LEN];
    SNDFILE *inhandle1;
    SNDFILE *inhandle2;
    SNDFILE *outhandle;
    int outframes;
    int samples;
    int i;
    int j;
    awgn_state_t noise1;
    awgn_state_t noise2;

    if ((model = both_ways_line_model_init(line_model_no,
                                           -50,
                                           -15.0f,
                                           -15.0f,
                                           line_model_no + 1,
                                           -35,
                                           -15.0f,
                                           -15.0f,
                                           channel_codec,
                                           rbs_pattern)) == NULL)
    {
        fprintf(stderr, "    Failed to create line model\n");
        exit(2);
    }

    awgn_init_dbm0(&noise1, 1234567, -10.0f);
    awgn_init_dbm0(&noise2, 1234567, -10.0f);

    if (speech_test)
    {
        if ((inhandle1 = sf_open_telephony_read(IN_FILE_NAME1, 1)) == NULL)
        {
            fprintf(stderr, "    Cannot open audio file '%s'\n", IN_FILE_NAME1);
            exit(2);
        }
        if ((inhandle2 = sf_open_telephony_read(IN_FILE_NAME2, 1)) == NULL)
        {
            fprintf(stderr, "    Cannot open audio file '%s'\n", IN_FILE_NAME2);
            exit(2);
        }
    }
    else
    {
        inhandle1 =
        inhandle2 = NULL;
    }
    if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME2, 2)) == NULL)
    {
        fprintf(stderr, "    Cannot create audio file '%s'\n", OUT_FILE_NAME2);
        exit(2);
    }
    for (i = 0;  i < 10000;  i++)
    {
        if (speech_test)
        {
            samples = sf_readf_short(inhandle1, input1, BLOCK_LEN);
            if (samples == 0)
                break;
            samples = sf_readf_short(inhandle2, input2, samples);
            if (samples == 0)
                break;
        }
        else
        {
            for (j = 0;  j < BLOCK_LEN;  j++)
            {
                input1[j] = awgn(&noise1);
                input2[j] = awgn(&noise2);
            }
            samples = BLOCK_LEN;
        }
        for (j = 0;  j < samples;  j++)
        {
            both_ways_line_model(model,
                                 &output1[j],
                                 &input1[j],
                                 &output2[j],
                                 &input2[j],
                                 1);
            amp[2*j] = output1[j];
            amp[2*j + 1] = output2[j];
        }
        outframes = sf_writef_short(outhandle, amp, samples);
        if (outframes != samples)
        {
            fprintf(stderr, "    Error writing audio file\n");
            exit(2);
        }
    }
    if (speech_test)
    {
        if (sf_close_telephony(inhandle1))
        {
            fprintf(stderr, "    Cannot close audio file '%s'\n", IN_FILE_NAME1);
            exit(2);
        }
        if (sf_close_telephony(inhandle2))
        {
            fprintf(stderr, "    Cannot close audio file '%s'\n", IN_FILE_NAME2);
            exit(2);
        }
    }
    if (sf_close_telephony(outhandle))
    {
        fprintf(stderr, "    Cannot close audio file '%s'\n", OUT_FILE_NAME2);
        exit(2);
    }
    both_ways_line_model_free(model);
}
Пример #6
0
static int power_meter_tests(void)
{
    awgn_state_t noise_source;
    power_meter_t meter;
    tone_gen_descriptor_t tone_desc;
    tone_gen_state_t gen;
    int i;
    int idum = 1234567;
    int16_t amp[1000];
    int len;
    int32_t level;

    power_meter_init(&meter, 7);
    printf("Testing with zero in the power register\n");
    printf("Power: expected %fdBm0, got %fdBm0\n", -90.169f, power_meter_current_dbm0(&meter));
    printf("Power: expected %fdBOv, got %fdBOv\n", -96.329f, power_meter_current_dbov(&meter));

    printf("Testing with a square wave 10dB from maximum\n");
    for (i = 0;  i < 1000;  i++)
    {
        amp[i] = (i & 1)  ?  10362  :  -10362;
        level = power_meter_update(&meter, amp[i]);
        //printf("%12d %fdBm0 %fdBov\n", level, power_meter_current_dbm0(&meter), power_meter_current_dbov(&meter));
    }
    printf("Level: expected %" PRId32 "/%" PRId32 ", got %" PRId32 "\n", power_meter_level_dbov(-10.0f), power_meter_level_dbm0(-10.0f + DBM0_MAX_POWER), level);
    printf("Power: expected %fdBm0, got %fdBm0\n", -10.0f + DBM0_MAX_POWER, power_meter_current_dbm0(&meter));
    printf("Power: expected %fdBOv, got %fdBOv\n", -10.0f, power_meter_current_dbov(&meter));
    if (level < power_meter_level_dbov(-10.0f)*0.99f
        ||
        level > power_meter_level_dbov(-10.0f)*1.01f)
    {
        printf("Test failed (level)\n");
        exit(2);
    }
    if (0.1f < fabsf(power_meter_current_dbm0(&meter) + 10.0f - DBM0_MAX_POWER))
    {
        printf("Test failed (dBm0)\n");
        exit(2);
    }
    if (0.1f < fabsf(power_meter_current_dbov(&meter) + 10.0))
    {
        printf("Test failed (dBOv)\n");
        exit(2);
    }

    printf("Testing with a sine wave tone 10dB from maximum\n");
    tone_gen_descriptor_init(&tone_desc,
                             1000,
                             -4,
                             0,
                             1,
                             1,
                             0,
                             0,
                             0,
                             true);
    tone_gen_init(&gen, &tone_desc);
    len = tone_gen(&gen, amp, 1000);
    for (i = 0;  i < len;  i++)
    {
        level = power_meter_update(&meter, amp[i]);
        //printf("%12d %fdBm0 %fdBov\n", level, power_meter_current_dbm0(&meter), power_meter_current_dbov(&meter));
    }
    printf("Level: expected %" PRId32 "/%" PRId32 ", got %" PRId32 "\n", power_meter_level_dbov(-10.0f), power_meter_level_dbm0(-10.0f + DBM0_MAX_POWER), level);
    printf("Power: expected %fdBm0, got %fdBm0\n", -10.0f + DBM0_MAX_POWER, power_meter_current_dbm0(&meter));
    printf("Power: expected %fdBOv, got %fdBOv\n", -10.0f, power_meter_current_dbov(&meter));
    if (level < power_meter_level_dbov(-10.0f)*0.95f
        ||
        level > power_meter_level_dbov(-10.0f)*1.05f)
    {
        printf("Test failed (level)\n");
        exit(2);
    }
    if (0.2f < fabsf(power_meter_current_dbm0(&meter) + 10.0f - DBM0_MAX_POWER))
    {
        printf("Test failed (dBm0)\n");
        exit(2);
    }
    if (0.2f < fabsf(power_meter_current_dbov(&meter) + 10.0))
    {
        printf("Test failed (dBOv)\n");
        exit(2);
    }

    printf("Testing with AWGN 10dB from maximum\n");
    awgn_init_dbov(&noise_source, idum, -10.0f);
    for (i = 0;  i < 1000;  i++)
        amp[i] = awgn(&noise_source);
    for (i = 0;  i < 1000;  i++)
    {
        level = power_meter_update(&meter, amp[i]);
        //printf("%12d %fdBm0 %fdBov\n", level, power_meter_current_dbm0(&meter), power_meter_current_dbov(&meter));
    }
    printf("Level: expected %" PRId32 "/%" PRId32 ", got %" PRId32 "\n", power_meter_level_dbov(-10.0f), power_meter_level_dbm0(-10.0f + DBM0_MAX_POWER), level);
    printf("Power: expected %fdBm0, got %fdBm0\n", -10.0f + DBM0_MAX_POWER, power_meter_current_dbm0(&meter));
    printf("Power: expected %fdBOv, got %fdBOv\n", -10.0f, power_meter_current_dbov(&meter));
    if (level < power_meter_level_dbov(-10.0f)*0.95f
        ||
        level > power_meter_level_dbov(-10.0f)*1.05f)
    {
        printf("Test failed (level)\n");
        exit(2);
    }
    if (0.2f < fabsf(power_meter_current_dbm0(&meter) + 10.0f - DBM0_MAX_POWER))
    {
        printf("Test failed (dBm0)\n");
        exit(2);
    }
    if (0.2f < fabsf(power_meter_current_dbov(&meter) + 10.0f))
    {
        printf("Test failed (dBOv)\n");
        exit(2);
    }
    return 0;
}
Пример #7
0
static int power_surge_detector_tests(void)
{
    SNDFILE *outhandle;
    power_surge_detector_state_t *sig;
    int i;
    int sample;
    int16_t amp[8000];
    int16_t amp_out[2*8000];
    awgn_state_t *awgnx;
    int32_t phase_rate;
    uint32_t phase_acc;
    int16_t phase_scale;
    float signal_power;
    int32_t signal_level;
    int signal_present;
    int prev_signal_present;
    int ok;
    int extremes[4];

    if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 2)) == NULL)
    {
        fprintf(stderr, "    Cannot create audio file '%s'\n", OUT_FILE_NAME);
        exit(2);
    }
    sig = power_surge_detector_init(NULL, -50.0f, 5.0f);
    prev_signal_present = false;

    phase_rate = dds_phase_rate(450.0f);
    phase_acc = 0;

    phase_scale = dds_scaling_dbm0(-33.0f);
    awgnx = awgn_init_dbm0(NULL, 1234567, -45.0f);

    extremes[0] = 8001;
    extremes[1] = -1;
    extremes[2] = 8001;
    extremes[3] = -1;
    for (sample = 0;  sample < 800000;  sample += 8000)
    {
        ok = 0;
        for (i = 0;  i < 8000;  i++)
        {
            amp[i] = awgn(awgnx);
            if (i < 4000)
                amp[i] += dds_mod(&phase_acc, phase_rate, phase_scale, 0);

            signal_level = power_surge_detector(sig, amp[i]);
            signal_present = (signal_level != 0);
            if (prev_signal_present != signal_present)
            {
                signal_power = power_surge_detector_current_dbm0(sig);
                if (signal_present)
                {
                    if (ok == 0  &&  i >= 0  &&  i < 25)
                        ok = 1;
                    if (extremes[0] > i)
                        extremes[0] = i;
                    if (extremes[1] < i)
                        extremes[1] = i;
                    printf("On at %f (%fdBm0)\n", (sample + i)/8000.0, signal_power);
                }
                else
                {
                    if (ok == 1  &&  i >= 4000 + 0  &&  i < 4000 + 35)
                        ok = 2;
                    if (extremes[2] > i)
                        extremes[2] = i;
                    if (extremes[3] < i)
                        extremes[3] = i;
                    printf("Off at %f (%fdBm0)\n", (sample + i)/8000.0, signal_power);
                }
                prev_signal_present = signal_present;
            }
            amp_out[2*i] = amp[i];
            amp_out[2*i + 1] = signal_present*5000;
        }
        sf_writef_short(outhandle, amp_out, 8000);
        if (ok != 2
            ||
            extremes[0] < 1
            ||
            extremes[1] > 30
            ||
            extremes[2] < 4001
            ||
            extremes[3] > 4030)
        {
            printf("    Surge not detected correctly (%d)\n", ok);
            exit(2);
        }
    }
    if (sf_close_telephony(outhandle))
    {
        fprintf(stderr, "    Cannot close audio file '%s'\n", OUT_FILE_NAME);
        exit(2);
    }
    printf("Min on %d, max on %d, min off %d, max off %d\n", extremes[0], extremes[1], extremes[2], extremes[3]);
    power_surge_detector_free(sig);
    awgn_free(awgnx);
    return 0;
}
Пример #8
0
int main(int argc, char **argv) {
  int i, j, k, nof_errors = 0, ret = SRSLTE_SUCCESS;
  float mse;
  cf_t *x[SRSLTE_MAX_LAYERS], *r[SRSLTE_MAX_PORTS], *y[SRSLTE_MAX_PORTS], *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
      *xr[SRSLTE_MAX_LAYERS];
  srslte_mimo_type_t type;
  
  parse_args(argc, argv);

  /* Check input ranges */
  if (nof_tx_ports > SRSLTE_MAX_PORTS || nof_rx_ports > SRSLTE_MAX_PORTS || nof_layers > SRSLTE_MAX_LAYERS) {
    fprintf(stderr, "Invalid number of layers or ports\n");
    exit(-1);
  }

  /* Parse MIMO Type */
  if (srslte_str2mimotype(mimo_type_name, &type)) {
    fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name);
    exit(-1);
  }

  /* Check scenario conditions are OK */
  switch (type) {
    case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
      nof_re = nof_layers*nof_symbols;
      break;
    case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
      nof_re = nof_symbols;
      break;
    case SRSLTE_MIMO_TYPE_CDD:
      nof_re = nof_symbols*nof_tx_ports/nof_layers;
      if (nof_rx_ports != 2 || nof_tx_ports != 2) {
        fprintf(stderr, "CDD nof_tx_ports=%d nof_rx_ports=%d is not currently supported\n", nof_tx_ports, nof_rx_ports);
        exit(-1);
      }
      break;
    default:
      nof_re = nof_symbols*nof_layers;
  }

  /* Allocate x and xr (received symbols) in memory for each layer */
  for (i = 0; i < nof_layers; i++) {
    /* Source data */
    x[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols);
    if (!x[i]) {
      perror("srslte_vec_malloc");
      exit(-1);
    }

    /* Sink data */
    xr[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols);
    if (!xr[i]) {
      perror("srslte_vec_malloc");
      exit(-1);
    }
  }

  /* Allocate y in memory for tx each port */
  for (i = 0; i < nof_tx_ports; i++) {
    y[i] = srslte_vec_malloc(sizeof(cf_t) * nof_re);
    if (!y[i]) {
      perror("srslte_vec_malloc");
      exit(-1);
    }
  }

  /* Allocate h in memory for each cross channel and layer */
  for (i = 0; i < nof_tx_ports; i++) {
    for (j = 0; j < nof_rx_ports; j++) {
      h[i][j] = srslte_vec_malloc(sizeof(cf_t) * nof_re);
      if (!h[i][j]) {
        perror("srslte_vec_malloc");
        exit(-1);
      }
    }
  }

  /* Allocate r */
  for (i = 0; i < nof_rx_ports; i++) {
    r[i] = srslte_vec_malloc(sizeof(cf_t) * nof_re);
    if (!r[i]) {
      perror("srslte_vec_malloc");
      exit(-1);
    }
  }

  /* Generate source random data */
  for (i = 0; i < nof_layers; i++) {
    for (j = 0; j < nof_symbols; j++) {
      x[i][j] = (2 * (rand() % 2) - 1 + (2 * (rand() % 2) - 1) * _Complex_I) / sqrt(2);
    }
  }

  /* Execute Precoding (Tx) */
  if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, codebook_idx, nof_symbols, scaling, type) < 0) {
    fprintf(stderr, "Error layer mapper encoder\n");
    exit(-1);
  }

  /* generate channel */
  populate_channel(type, h);

  /* pass signal through channel
   (we are in the frequency domain so it's a multiplication) */
  for (i = 0; i < nof_rx_ports; i++) {
    for (k = 0; k < nof_re; k++) {
      r[i][k] = (cf_t) (0.0 + 0.0 * _Complex_I);
      for (j = 0; j < nof_tx_ports; j++) {
        r[i][k] += y[j][k] * h[j][i][k];
      }
    }
  }

  awgn(r, (uint32_t) nof_re, snr_db);

  /* If CDD or Spatial muliplex choose decoder */
  if (strncmp(decoder_type_name, "zf", 16) == 0) {
    srslte_predecoding_set_mimo_decoder(SRSLTE_MIMO_DECODER_ZF);
  } else if (strncmp(decoder_type_name, "mmse", 16) == 0) {
    srslte_predecoding_set_mimo_decoder(SRSLTE_MIMO_DECODER_MMSE);
  } else {
    ret = SRSLTE_ERROR;
    goto quit;
  }


  /* predecoding / equalization */
  struct timeval t[3];
  gettimeofday(&t[1], NULL);
  srslte_predecoding_type(r, h, xr, NULL, nof_rx_ports, nof_tx_ports, nof_layers,
                          codebook_idx, nof_re, type, scaling, powf(10, -snr_db / 10));
  gettimeofday(&t[2], NULL);
  get_time_interval(t);

  /* check errors */
  mse = 0;
  for (i = 0; i < nof_layers; i++) {
    for (j = 0; j < nof_symbols; j++) {
      mse += cabsf(xr[i][j] - x[i][j]);

      if ((crealf(xr[i][j]) > 0) != (crealf(x[i][j]) > 0)) {
        nof_errors ++;
      }
      if ((cimagf(xr[i][j]) > 0) != (cimagf(x[i][j]) > 0)) {
        nof_errors ++;
      }
    }
  }
  printf("SNR: %5.1fdB;\tExecution time: %5ldus;\tMSE: %.6f;\tBER: %.6f\n", snr_db, t[0].tv_usec,
         mse / nof_layers / nof_symbols, (float) nof_errors / (4.0f * nof_re));
  if (mse / nof_layers / nof_symbols > MSE_THRESHOLD) {
    ret = SRSLTE_ERROR;
  } 

  quit:
  /* Free all data */
  for (i = 0; i < nof_layers; i++) {
    free(x[i]);
    free(xr[i]);
  }

  for (i = 0; i < nof_rx_ports; i++) {
    free(r[i]);
  }

  for (i = 0; i < nof_rx_ports; i++) {
    for (j = 0; j < nof_tx_ports; j++) {
      free(h[j][i]);
    }
  }

  exit(ret);
}
static int end_to_end_tests(void)
{
    ademco_contactid_receiver_state_t *receiver;
    ademco_contactid_sender_state_t *sender;
    logging_state_t *logging;
    codec_munge_state_t *munge;
    awgn_state_t noise_source;
    int16_t amp[SAMPLES_PER_CHUNK];
    int16_t sndfile_buf[2*SAMPLES_PER_CHUNK];
    int samples;
    int i;
    int j;

    printf("End to end tests\n");

    if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 2)) == NULL)
    {
        fprintf(stderr, "    Cannot open audio file '%s'\n", OUTPUT_FILE_NAME);
        exit(2);
    }

    if ((receiver = ademco_contactid_receiver_init(NULL, rx_callback, NULL)) == NULL)
        return -1;
    ademco_contactid_receiver_set_realtime_callback(receiver, rx_callback, receiver);

    logging = ademco_contactid_receiver_get_logging_state(receiver);
    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
    span_log_set_tag(logging, "Ademco-rx");

    if ((sender = ademco_contactid_sender_init(NULL, tx_callback, NULL)) == NULL)
        return -1;
    ademco_contactid_sender_set_realtime_callback(sender, tx_callback, sender);
    logging = ademco_contactid_sender_get_logging_state(sender);
    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
    span_log_set_tag(logging, "Ademco-tx");

    awgn_init_dbm0(&noise_source, 1234567, -50);
    munge = codec_munge_init(MUNGE_CODEC_ALAW, 0);

    sending_complete = FALSE;
    rx_callback_reported = FALSE;

    for (i = 0;  i < 1000;  i++)
    {
        samples = ademco_contactid_sender_tx(sender, amp, SAMPLES_PER_CHUNK);
        for (j = samples;  j < SAMPLES_PER_CHUNK;  j++)
            amp[j] = 0;
        for (j = 0;  j < SAMPLES_PER_CHUNK;  j++)
            sndfile_buf[2*j] = amp[j];
        /* There is no point in impairing this signal. It is just DTMF tones, which
           will work as wel as the DTMF detector beign used. */
        ademco_contactid_receiver_rx(receiver, amp, SAMPLES_PER_CHUNK);

        samples = ademco_contactid_receiver_tx(receiver, amp, SAMPLES_PER_CHUNK);
        for (j = samples;  j < SAMPLES_PER_CHUNK;  j++)
            amp[j] = 0;
        
        /* We add AWGN and codec impairments to the signal, to stress the tone detector. */
        codec_munge(munge, amp, SAMPLES_PER_CHUNK);
        for (j = 0;  j < SAMPLES_PER_CHUNK;  j++)
        {
            sndfile_buf[2*j + 1] = amp[j];
            /* Add noise to the tones */
            amp[j] += awgn(&noise_source);
        }
        codec_munge(munge, amp, SAMPLES_PER_CHUNK);
        ademco_contactid_sender_rx(sender, amp, SAMPLES_PER_CHUNK);

        sf_writef_short(outhandle, sndfile_buf, SAMPLES_PER_CHUNK);
    }
    if (!rx_callback_reported)
    {
        fprintf(stderr, "    Report not received\n");
        return -1;
    }

    if (sf_close_telephony(outhandle))
    {
        fprintf(stderr, "    Cannot close audio file '%s'\n", OUTPUT_FILE_NAME);
        return -1;
    }
    printf("    Passed\n");
    return 0;
}
Пример #10
0
static int periodogram_tests(void)
{
    int i;
    int j;
    int k;
    int len;
    complexf_t coeffs[PG_WINDOW/2];
    complexf_t camp[BLOCK_LEN];
    complexf_t last_result;
    complexf_t result;
    complexf_t phase_offset;
    float freq_error;
    float pg_scale;
    float level;
    float scale1;
    float scale2;
    int32_t phase_rate1;
    int32_t phase_rate2;
    uint32_t phase_acc1;
    uint32_t phase_acc2;
    awgn_state_t noise_source_re;
    awgn_state_t noise_source_im;

    phase_rate1 = DEC_RATIO*dds_phase_ratef(FREQ1 - 5.0f);
    phase_rate2 = DEC_RATIO*dds_phase_ratef(FREQ2);
    phase_acc1 = 0;
    phase_acc2 = 0;
    len = periodogram_generate_coeffs(coeffs, FREQ1, DEC_SAMPLE_RATE, PG_WINDOW);
    if (len != PG_WINDOW/2)
    {
        printf("Test failed\n");
        return -1;
    }
    pg_scale = periodogram_generate_phase_offset(&phase_offset, FREQ1, DEC_SAMPLE_RATE, PG_WINDOW);
    scale1 = dds_scaling_dbm0f(-6.0f);
    scale2 = dds_scaling_dbm0f(-6.0f);

    for (k = -50;  k < 0;  k++)
    {
        printf("Setting noise to %ddBm0\n", k);
        awgn_init_dbm0(&noise_source_re, 1234567, (float) k);
        awgn_init_dbm0(&noise_source_im, 7654321, (float) k);
        last_result = complex_setf(0.0f, 0.0f);
        for (i = 0;  i < 100;  i++)
        {
            for (j = 0;  j < PG_WINDOW;  j++)
            {
                result = dds_complexf(&phase_acc1, phase_rate1);
                camp[j].re = result.re*scale1;
                camp[j].im = result.im*scale1;
                result = dds_complexf(&phase_acc2, phase_rate2);
                camp[j].re += result.re*scale2;
                camp[j].im += result.im*scale2;
                camp[j].re += awgn(&noise_source_re);
                camp[j].im += awgn(&noise_source_im);
            }
            result = periodogram(coeffs, camp, PG_WINDOW);
            level = sqrtf(result.re*result.re + result.im*result.im);
            freq_error = periodogram_freq_error(&phase_offset, pg_scale, &last_result, &result);
            last_result = result;
            if (i == 0)
                continue;

            printf("Signal level = %.5f, freq error = %.5f\n", level, freq_error);
            if (level < scale1*0.8f  ||  level > scale1*1.2f)
            {
                printf("Test failed - %ddBm0 of noise, signal is %f (%f)\n", k, level, scale1);
                return -1;
            }
            if (freq_error < -10.0f  ||  freq_error > 10.0f)
            {
                printf("Test failed - %ddBm0 of noise, %fHz error\n", k, freq_error);
                return -1;
            }
        }
    }
    return 0;
}
Пример #11
0
int main(int argc, char *argv[])
{
    int16_t silence[SAMPLES_PER_CHUNK];
    int16_t t30_amp[2][SAMPLES_PER_CHUNK];
    int16_t t38_amp[2][SAMPLES_PER_CHUNK];
    int16_t t38_amp_hist_a[8][SAMPLES_PER_CHUNK];
    int16_t t38_amp_hist_b[8][SAMPLES_PER_CHUNK];
    int16_t out_amp[SAMPLES_PER_CHUNK*4];
    int16_t *fax_rx_buf[2];
    int16_t *fax_tx_buf[2];
    int16_t *t38_gateway_rx_buf[2];
    int16_t *t38_gateway_tx_buf[2];
    int t30_len[2];
    int t38_len[2];
    int hist_ptr;
    int log_audio;
    int msg_len;
    uint8_t msg[1024];
    int outframes;
    SNDFILE *wave_handle;
    SNDFILE *input_wave_handle;
    int use_ecm;
    int use_tep;
    int feedback_audio;
    int use_transmit_on_idle;
    int t38_version;
    const char *input_tiff_file_name;
    const char *decode_file_name;
    int i;
    int j;
    int seq_no;
    int g1050_model_no;
    int g1050_speed_pattern_no;
    int t38_transport;
    double tx_when;
    double rx_when;
    int supported_modems;
    int remove_fill_bits;
    int opt;
    int start_page;
    int end_page;
    int drop_frame;
    int drop_frame_rate;
    float signal_scaling;
    int signal_level;
    int noise_level;
    int code_to_look_up;
    int scan_line_time;
    t38_stats_t t38_stats;
    t30_stats_t t30_stats;
    logging_state_t *logging;
    int expected_pages;
    char *page_header_info;
    char *page_header_tz;
    const char *tag;
    char buf[132 + 1];
#if defined(ENABLE_GUI)
    int use_gui;
#endif

#if defined(ENABLE_GUI)
    use_gui = FALSE;
#endif
    log_audio = FALSE;
    use_ecm = FALSE;
    t38_version = 1;
    input_tiff_file_name = INPUT_TIFF_FILE_NAME;
    t38_simulate_incrementing_repeats = FALSE;
    g1050_model_no = 0;
    g1050_speed_pattern_no = 1;
    remove_fill_bits = FALSE;
    use_tep = FALSE;
    feedback_audio = FALSE;
    use_transmit_on_idle = TRUE;
    supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17;
    page_header_info = NULL;
    page_header_tz = NULL;
    drop_frame = 0;
    drop_frame_rate = 0;
    start_page = -1;
    end_page = -1;
    signal_level = 0;
    noise_level = -99;
    scan_line_time = 0;
    decode_file_name = NULL;
    code_to_look_up = -1;
    t38_transport = T38_TRANSPORT_UDPTL;
    while ((opt = getopt(argc, argv, "c:d:D:efFgH:i:Ilm:M:n:p:s:tT:u:v:z:")) != -1)
    {
        switch (opt)
        {
        case 'c':
            code_to_look_up = atoi(optarg);
            break;
        case 'd':
            decode_file_name = optarg;
            break;
        case 'D':
            drop_frame_rate =
            drop_frame = atoi(optarg);
            break;
        case 'e':
            use_ecm = TRUE;
            break;
        case 'f':
            feedback_audio = TRUE;
            break;
        case 'F':
            remove_fill_bits = TRUE;
            break;
        case 'g':
#if defined(ENABLE_GUI)
            use_gui = TRUE;
#else
            fprintf(stderr, "Graphical monitoring not available\n");
            exit(2);
#endif
            break;
        case 'H':
            page_header_info = optarg;
            break;
        case 'i':
            input_tiff_file_name = optarg;
            break;
        case 'I':
            t38_simulate_incrementing_repeats = TRUE;
            break;
        case 'l':
            log_audio = TRUE;
            break;
        case 'm':
            supported_modems = atoi(optarg);
            break;
        case 'M':
            g1050_model_no = optarg[0] - 'A' + 1;
            break;
        case 'n':
            noise_level = atoi(optarg);
            break;
        case 'p':
            for (i = 0;  i < 2;  i++)
            {
                switch (optarg[i])
                {
                case 'A':
                    mode[i] = AUDIO_FAX;
                    break;
                case 'G':
                    mode[i] = T38_GATEWAY_FAX;
                    break;
                case 'T':
                    mode[i] = T38_TERMINAL_FAX;
                    break;
                default:
                    fprintf(stderr, "Unknown FAX path element %c\n", optarg[i]);
                    exit(2);
                }
            }
            if ((mode[0] == AUDIO_FAX  &&  mode[1] != AUDIO_FAX)
                ||
                (mode[0] != AUDIO_FAX  &&  mode[1] == AUDIO_FAX))
            {
                fprintf(stderr, "Invalid FAX path %s\n", optarg);
                exit(2);
            }
            break;
        case 's':
            g1050_speed_pattern_no = atoi(optarg);
            break;
#if 0
        case 's':
            signal_level = atoi(optarg);
            break;
#endif
        case 'S':
            scan_line_time = atoi(optarg);
            break;
        case 't':
            use_tep = TRUE;
            break;
        case 'T':
            start_page = 0;
            end_page = atoi(optarg);
            break;
        case 'u':
            if (strcasecmp(optarg, "udptl") == 0)
                t38_transport = T38_TRANSPORT_UDPTL;
            else if (strcasecmp(optarg, "rtp") == 0)
                t38_transport = T38_TRANSPORT_RTP;
            else if (strcasecmp(optarg, "tcp") == 0)
                t38_transport = T38_TRANSPORT_TCP;
            else if (strcasecmp(optarg, "tcp-tpkt") == 0)
                t38_transport = T38_TRANSPORT_TCP_TPKT;
            else
            {
                fprintf(stderr, "Unknown T.38 transport mode\n");
                exit(2);
            }
            break;
        case 'v':
            t38_version = atoi(optarg);
            break;
        case 'z':
            page_header_tz = optarg;
            break;
        default:
            //usage();
            exit(2);
            break;
        }
    }

    if (code_to_look_up >= 0)
    {
        printf("Result code %d is %s\n", code_to_look_up, t30_completion_code_to_str(code_to_look_up));
        exit(0);
    }

    printf("Using T.38 version %d\n", t38_version);
    if (use_ecm)
        printf("Using ECM\n");

    wave_handle = NULL;
    if (log_audio)
    {
        if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 4)) == NULL)
        {
            fprintf(stderr, "    Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
            exit(2);
        }
    }
    memset(silence, 0, sizeof(silence));
 
    srand48(0x1234567);
    /* Set up the nodes */
    input_wave_handle = NULL;
    if (mode[0] == T38_TERMINAL_FAX)
    {
    }
    else
    {
        if (decode_file_name)
        {
            if ((input_wave_handle = sf_open_telephony_read(decode_file_name, 1)) == NULL)
            {
                fprintf(stderr, "    Cannot open audio file '%s'\n", decode_file_name);
                exit(2);
            }
        }
    }

    for (i = 0;  i < 2;  i++)
    {
        tag = (i == 0)  ?  "A"  :  "B";

        memset(&expected_rx_info[i], 0, sizeof(expected_rx_info[i]));
        if (mode[i] == T38_TERMINAL_FAX)
        {
            if ((t38_state[i] = t38_terminal_init(NULL, (i == 0), tx_packet_handler, (void *) (intptr_t) i)) == NULL)
            {
                fprintf(stderr, "Cannot start the T.38 terminal instance\n");
                exit(2);
            }
            t30_state[i] = t38_terminal_get_t30_state(t38_state[i]);
            t38_core_state[i] = t38_terminal_get_t38_core_state(t38_state[i]);

            logging = t38_terminal_get_logging_state(t38_state[i]);
            span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
            span_log_set_tag(logging, tag);

            logging = t38_core_get_logging_state(t38_core_state[i]);
            span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
            span_log_set_tag(logging, tag);

            logging = t30_get_logging_state(t30_state[i]);
            span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
            span_log_set_tag(logging, tag);
        }
        else
        {
            if ((fax_state[i] = fax_init(NULL, (i == 0))) == NULL)
            {
                fprintf(stderr, "Cannot start FAX instance\n");
                exit(2);
            }
            t30_state[i] = fax_get_t30_state(fax_state[i]);

            logging = fax_get_logging_state(fax_state[i]);
            span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
            span_log_set_tag(logging, tag);

            logging = fax_modems_get_logging_state(&fax_state[i]->modems);
            span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
            span_log_set_tag(logging, tag);

            logging = t30_get_logging_state(t30_state[i]);
            span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
            span_log_set_tag(logging, tag);

            if (mode[i] == T38_GATEWAY_FAX)
            {
                if ((t38_gateway_state[i] = t38_gateway_init(NULL, tx_packet_handler, (void *) (intptr_t) i)) == NULL)
                {
                    fprintf(stderr, "Cannot start the T.38 gateway instancel\n");
                    exit(2);
                }
                t38_core_state[i] = t38_gateway_get_t38_core_state(t38_gateway_state[i]);

                logging = t38_gateway_get_logging_state(t38_gateway_state[i]);
                span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
                span_log_set_tag(logging, tag);

                logging = fax_modems_get_logging_state(&t38_gateway_state[i]->audio.modems);
                span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
                span_log_set_tag(logging, tag);

                logging = t38_core_get_logging_state(t38_core_state[i]);
                span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
                span_log_set_tag(logging, tag);

                fax_rx_buf[i] = t38_amp[i];
                fax_tx_buf[i] = t30_amp[i];
                t38_gateway_rx_buf[i] = t30_amp[i];
                t38_gateway_tx_buf[i] = t38_amp[i];
            }
            else
            {
                fax_rx_buf[i] = t30_amp[i];
                fax_tx_buf[i] = t30_amp[i ^ 1];
                t38_gateway_rx_buf[i] = NULL;
                t38_gateway_tx_buf[i] = NULL;
            }
            awgn_state[i] = NULL;
            signal_scaling = 1.0f;
            if (noise_level > -99)
            {
                awgn_state[i] = awgn_init_dbm0(NULL, 1234567, noise_level);
                signal_scaling = powf(10.0f, signal_level/20.0f);
                printf("Signal scaling %f\n", signal_scaling);
            }
        }
        set_t30_callbacks(t30_state[i], i);
    }
    /* Set up the channels */
    for (i = 0;  i < 2;  i++)
    {
        if ((g1050_path[i] = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL)
        {
            fprintf(stderr, "Failed to start IP network path model\n");
            exit(2);
        }
        memset(audio_buffer[2*i], 0, SAMPLES_PER_CHUNK*sizeof(int16_t));
        memset(audio_buffer[2*i + 1], 0, SAMPLES_PER_CHUNK*sizeof(int16_t));
        memset(t30_amp[i], 0, sizeof(t30_amp[i]));
        memset(t38_amp[i], 0, sizeof(t38_amp[i]));
    }
    memset(t38_amp_hist_a, 0, sizeof(t38_amp_hist_a));
    memset(t38_amp_hist_b, 0, sizeof(t38_amp_hist_b));

    for (i = 0;  i < 2;  i++)
    {
        j = i + 1;
        sprintf(buf, "%d%d%d%d%d%d%d%d", j, j, j, j, j, j, j, j);
        t30_set_tx_ident(t30_state[i], buf);
        strcpy(expected_rx_info[i ^ 1].ident, buf);
        sprintf(buf, "Sub-address %d", j);
        t30_set_tx_sub_address(t30_state[i], buf);
        //strcpy(expected_rx_info[i ^ 1].sub_address, buf);
        sprintf(buf, "Sender ID %d", j);
        t30_set_tx_sender_ident(t30_state[i], buf);
        //strcpy(expected_rx_info[i ^ 1].sender_ident, buf);
        sprintf(buf, "Password %d", j);
        t30_set_tx_password(t30_state[i], buf);
        //strcpy(expected_rx_info[i ^ 1].password, buf);
        sprintf(buf, "Polled sub-add %d", j);
        t30_set_tx_polled_sub_address(t30_state[i], buf);
        //strcpy(expected_rx_info[i ^ 1].polled_sub_address, buf);
        sprintf(buf, "Select poll add %d", j);
        t30_set_tx_selective_polling_address(t30_state[i], buf);
        //strcpy(expected_rx_info[i ^ 1].selective_polling_address, buf);
        t30_set_tx_page_header_info(t30_state[i], page_header_info);
        if (page_header_tz)
            t30_set_tx_page_header_tz(t30_state[i], page_header_tz);

        if ((i & 1) == 1)
        {
            t30_set_tx_nsf(t30_state[i], (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
            expected_rx_info[i ^ 1].nsf = (uint8_t *) "\x50\x00\x00\x00Spandsp\x00";
            expected_rx_info[i ^ 1].nsf_len = 12;
        }

        t30_set_supported_modems(t30_state[i], supported_modems);
        t30_set_supported_t30_features(t30_state[i],
                                       T30_SUPPORT_IDENTIFICATION
                                     | T30_SUPPORT_SELECTIVE_POLLING
                                     | T30_SUPPORT_SUB_ADDRESSING);
        t30_set_supported_image_sizes(t30_state[i],
                                      T30_SUPPORT_US_LETTER_LENGTH
                                    | T30_SUPPORT_US_LEGAL_LENGTH
                                    | T30_SUPPORT_UNLIMITED_LENGTH
                                    | T30_SUPPORT_215MM_WIDTH
                                    | T30_SUPPORT_255MM_WIDTH
                                    | T30_SUPPORT_303MM_WIDTH);
        t30_set_supported_resolutions(t30_state[i],
                                      T30_SUPPORT_STANDARD_RESOLUTION
                                    | T30_SUPPORT_FINE_RESOLUTION
                                    | T30_SUPPORT_SUPERFINE_RESOLUTION
                                    | T30_SUPPORT_R8_RESOLUTION
                                    | T30_SUPPORT_R16_RESOLUTION
                                    | T30_SUPPORT_300_300_RESOLUTION
                                    | T30_SUPPORT_400_400_RESOLUTION
                                    | T30_SUPPORT_600_600_RESOLUTION
                                    | T30_SUPPORT_1200_1200_RESOLUTION
                                    | T30_SUPPORT_300_600_RESOLUTION
                                    | T30_SUPPORT_400_800_RESOLUTION
                                    | T30_SUPPORT_600_1200_RESOLUTION);
        t30_set_ecm_capability(t30_state[i], use_ecm);
        if (use_ecm)
        {
            t30_set_supported_compressions(t30_state[i],
                                           T30_SUPPORT_T4_1D_COMPRESSION
                                         | T30_SUPPORT_T4_2D_COMPRESSION
                                         | T30_SUPPORT_T6_COMPRESSION
                                         | T30_SUPPORT_T81_COMPRESSION
                                         | T30_SUPPORT_T85_COMPRESSION
                                         | T30_SUPPORT_T85_L0_COMPRESSION);
        }
        else
        {
            t30_set_supported_compressions(t30_state[i],
                                           T30_SUPPORT_T4_1D_COMPRESSION
                                         | T30_SUPPORT_T4_2D_COMPRESSION);
        }
        t30_set_minimum_scan_line_time(t30_state[i], scan_line_time);

        if (mode[i] == T38_GATEWAY_FAX)
        {
            t38_gateway_set_transmit_on_idle(t38_gateway_state[i], use_transmit_on_idle);
            t38_gateway_set_supported_modems(t38_gateway_state[i], supported_modems);
            //t38_gateway_set_nsx_suppression(t38_state[i], NULL, 0, NULL, 0);
            t38_gateway_set_fill_bit_removal(t38_gateway_state[i], remove_fill_bits);
            t38_gateway_set_real_time_frame_handler(t38_gateway_state[i], real_time_gateway_frame_handler, (void *) (intptr_t) i);
            t38_gateway_set_ecm_capability(t38_gateway_state[i], use_ecm);
        }
        if (mode[i] != AUDIO_FAX)
        {
            t38_set_t38_version(t38_core_state[i], t38_version);
        }

        if (mode[i] == T38_TERMINAL_FAX)
        {
            //t30_set_iaf_mode(t30_state[i], T30_IAF_MODE_NO_FILL_BITS);
            switch (t38_transport)
            {
            case T38_TRANSPORT_UDPTL:
            case T38_TRANSPORT_RTP:
                t38_terminal_set_fill_bit_removal(t38_state[i], remove_fill_bits);
                t38_terminal_set_tep_mode(t38_state[i], use_tep);
                break;
            case T38_TRANSPORT_TCP:
            case T38_TRANSPORT_TCP_TPKT:
                t38_terminal_set_fill_bit_removal(t38_state[i], TRUE);
                t38_terminal_set_config(t38_state[i], T38_TERMINAL_OPTION_NO_PACING | T38_TERMINAL_OPTION_NO_INDICATORS);
                t38_terminal_set_tep_mode(t38_state[i], FALSE);
                break;
            }
        }
        else
        {
            fax_set_transmit_on_idle(fax_state[i], use_transmit_on_idle);
            fax_set_tep_mode(fax_state[i], use_tep);
        }
    }

    t30_set_tx_file(t30_state[0], input_tiff_file_name, start_page, end_page);
    t30_set_rx_file(t30_state[1], OUTPUT_TIFF_FILE_NAME, -1);

#if defined(ENABLE_GUI)
    if (use_gui)
        start_media_monitor();
#endif
    hist_ptr = 0;
    for (;;)
    {
        memset(out_amp, 0, sizeof(out_amp));

        for (i = 0;  i < 2;  i++)
        {
            /* Update T.30 timing */
            logging = t30_get_logging_state(t30_state[i]);
            span_log_bump_samples(logging, SAMPLES_PER_CHUNK);

            if (mode[i] == T38_TERMINAL_FAX)
            {
                /* Update T.38 termination timing */
                logging = t38_terminal_get_logging_state(t38_state[i]);
                span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
                logging = t38_core_get_logging_state(t38_core_state[i]);
                span_log_bump_samples(logging, SAMPLES_PER_CHUNK);

                completed[i] = t38_terminal_send_timeout(t38_state[i], SAMPLES_PER_CHUNK);
            }
            else
            {
                /* Update audio FAX timing */
                logging = fax_get_logging_state(fax_state[i]);
                span_log_bump_samples(logging, SAMPLES_PER_CHUNK);

                fax_rx(fax_state[i], fax_rx_buf[i], SAMPLES_PER_CHUNK);
                if (!t30_call_active(t30_state[i]))
                {
                    completed[i] = TRUE;
                    continue;
                }

                if (i == 0  &&  input_wave_handle)
                {
                    t30_len[i] = sf_readf_short(input_wave_handle, fax_tx_buf[i], SAMPLES_PER_CHUNK);
                    if (t30_len[i] == 0)
                        break;
                }
                else
                {
                    t30_len[i] = fax_tx(fax_state[i], fax_tx_buf[i], SAMPLES_PER_CHUNK);
                    if (!use_transmit_on_idle)
                    {
                        /* The receive side always expects a full block of samples, but the
                           transmit side may not be sending any when it doesn't need to. We
                           may need to pad with some silence. */
                        if (t30_len[i] < SAMPLES_PER_CHUNK)
                        {
                            memset(t30_amp[i] + t30_len[i], 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len[i]));
                            t30_len[i] = SAMPLES_PER_CHUNK;
                        }
                    }
                    if (awgn_state[i])
                    {
                        for (j = 0;  j < t30_len[i];  j++)
                            fax_tx_buf[i][j] = ((int16_t) (fax_tx_buf[i][j]*signal_scaling)) + awgn(awgn_state[i]);
                    }
                }
                if (log_audio)
                {
                    for (j = 0;  j < t30_len[i];  j++)
                        out_amp[4*j + 2*i] = t30_amp[i][j];
                }
                if (feedback_audio)
                {
                    for (j = 0;  j < t30_len[i];  j++)
                        t30_amp[i][j] += t38_amp_hist_a[hist_ptr][j] >> 1;
                    memcpy(t38_amp_hist_a[hist_ptr], t38_amp[i], sizeof(int16_t)*SAMPLES_PER_CHUNK);
                }

                if (mode[i] == T38_GATEWAY_FAX)
                {
                    /* Update T.38 gateway timing */
                    logging = t38_gateway_get_logging_state(t38_gateway_state[i]);
                    span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
                    logging = t38_core_get_logging_state(t38_core_state[i]);
                    span_log_bump_samples(logging, SAMPLES_PER_CHUNK);

                    if (drop_frame_rate  &&  --drop_frame == 0)
                    {
                        drop_frame = drop_frame_rate;
                        if (t38_gateway_rx_fillin(t38_gateway_state[i], SAMPLES_PER_CHUNK))
                            break;
                    }
                    else
                    {
                        if (t38_gateway_rx(t38_gateway_state[i], t38_gateway_rx_buf[i], SAMPLES_PER_CHUNK))
                            break;
                    }

                    t38_len[i] = t38_gateway_tx(t38_gateway_state[i], t38_gateway_tx_buf[i], SAMPLES_PER_CHUNK);
                    if (!use_transmit_on_idle)
                    {
                        if (t38_len[i] < SAMPLES_PER_CHUNK)
                        {
                            memset(t38_amp[i] + t38_len[i], 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t38_len[i]));
                            t38_len[i] = SAMPLES_PER_CHUNK;
                        }
                    }
                    if (feedback_audio)
                    {
                        for (j = 0;  j < t30_len[i];  j++)
                            t30_amp[i][j] += t38_amp_hist_a[hist_ptr][j] >> 1;
                        memcpy(t38_amp_hist_a[hist_ptr], t38_amp[i], sizeof(int16_t)*SAMPLES_PER_CHUNK);
                    }

                    if (log_audio)
                    {
                        for (j = 0;  j < t38_len[i];  j++)
                            out_amp[4*j + 2*i + 1] = t38_amp[i][j];
                    }
                }
            }
            if (mode[i] != AUDIO_FAX)
            {
                while ((msg_len = g1050_get(g1050_path[i], msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
                {
#if defined(ENABLE_GUI)
                    if (use_gui)
                        media_monitor_rx(seq_no, tx_when, rx_when);
#endif
                   t38_core_rx_ifp_packet(t38_core_state[i ^ 1], msg, msg_len, seq_no);
                }
            }
        }
        if (log_audio)
        {
            outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK);
            if (outframes != SAMPLES_PER_CHUNK)
                break;
        }

        when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE;

        if (completed[0]  &&  completed[1])
            break;
#if defined(ENABLE_GUI)
        if (use_gui)
            media_monitor_update_display();
#endif
        if (++hist_ptr > 3)
            hist_ptr = 0;
    }
Пример #12
0
static int test_a_tone_set(int fwd)
{
    int i;
    int j;
    int len;
    int sample;
    const char *s;
    char digit;
    int actual;
    int nplus;
    int nminus;
    float rrb;
    float rcfo;
    int16_t amp[100000];
    r2_mf_rx_state_t mf_state;
    awgn_state_t noise_source;
    const mf_digit_tones_t *tone;

    if (fwd)
        tone = &r2_mf_fwd_tones[0];
    else
        tone = &r2_mf_back_tones[0];
    r2_mf_rx_init(&mf_state, fwd);

    /* Test 1: Mitel's test 1 isn't really a test. Its a calibration step,
       which has no meaning here. */

    printf ("Test 1: Calibration\n");
    printf ("    Passed\n");

    /* Test 2: Decode check
       This is a sanity check, that all digits are reliably detected
       under ideal conditions.  Each possible digit is repeated 10 times,
       with 68ms bursts. The level of each tone is about 6dB down from clip */

    printf ("Test 2: Decode check\n");
    my_mf_gen_init(0.0, -3, 0.0, -3, 68, fwd);
    s = r2_mf_tone_codes;
    while (*s)
    {
        digit = *s++;
        for (i = 0;  i < 10;  i++)
        {
            len = my_mf_generate(amp, digit);
            codec_munge (amp, len);
            actual = r2_mf_rx(&mf_state, amp, len);
            if (actual != digit)
            {
                printf ("    Sent     '%c'\n", digit);
                printf ("    Received 0x%X\n", actual);
                printf ("    Failed\n");
                exit (2);
            }
        }
    }
    printf ("    Passed\n");

    /* Test 3: Recognition bandwidth and channel centre frequency check.
       Use all digits. Each digit types requires four tests to complete
       the check. Each section contains 40 pulses of 68ms duration,
       with an amplitude of -20dB from clip per frequency.

       Four sections covering the tests for one tone (1 digit) are:
       a. H frequency at 0% deviation from center, L frequency at +0.1%.
          L frequency is then increments in +01.% steps up to +4%. The
          number of tone bursts is noted and designated N+.
       b. H frequency at 0% deviation, L frequency at -0.1%. L frequency
          is then incremental in -0.1% steps, up to -4%. The number of
          tone bursts is noted and designated N-.
       c. The test in (a) is repeated with the L frequency at 0% and the
          H frequency varied up to +4%.
       d. The test in (b) is repeated with the L frequency and 0% and the
          H frequency varied to -4%.

       Receiver Recognition Bandwidth (RRB) is calculated as follows:
            RRB% = (N+ + N-)/10
       Receiver Center Frequency Offset (RCFO) is calculated as follows:
            RCFO% = X + (N+ - N-)/20
            
       Note that this test doesn't test what it says it is testing at all,
       and the results are quite inaccurate, if not a downright lie! However,
       it follows the Mitel procedure, so how can it be bad? :)
       
       The spec calls for +-4 +-10Hz (ie +-14Hz) of bandwidth. */

    printf ("Test 3: Recognition bandwidth and channel centre frequency check\n");
    s = r2_mf_tone_codes;
    j = 0;
    while (*s)
    {
        digit = *s++;
        for (nplus = 0, i = 1;  i <= 60;  i++)
        {
            my_mf_gen_init((float) i/1000.0, -17, 0.0, -17, 68, fwd);
            len = my_mf_generate(amp, digit);
            codec_munge(amp, len);
            if (r2_mf_rx(&mf_state, amp, len) == digit)
                nplus++;
        }
        for (nminus = 0, i = -1;  i >= -60;  i--)
        {
            my_mf_gen_init((float) i/1000.0, -17, 0.0, -17, 68, fwd);
            len = my_mf_generate(amp, digit);
            codec_munge(amp, len);
            if (r2_mf_rx(&mf_state, amp, len) == digit)
                nminus++;
        }
        rrb = (float) (nplus + nminus)/10.0;
        rcfo = (float) (nplus - nminus)/10.0;
        printf ("    %c (low)  rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n",
                digit,
                rrb,
                rcfo,
                (float) nminus/10.0,
                (float) nplus/10.0);

        if (rrb < rcfo + (2.0*100.0*14.0/r2_mf_fwd_tones[j].f1)  ||  rrb >= 15.0 + rcfo)
        {
            printf ("    Failed\n");
            exit (2);
        }

        for (nplus = 0, i = 1;  i <= 60;  i++)
        {
            my_mf_gen_init(0.0, -17, (float) i/1000.0, -17, 68, fwd);
            len = my_mf_generate(amp, digit);
            codec_munge(amp, len);
            if (r2_mf_rx(&mf_state, amp, len) == digit)
                nplus++;
        }
        for (nminus = 0, i = -1;  i >= -60;  i--)
        {
            my_mf_gen_init(0.0, -17, (float) i/1000.0, -17, 68, fwd);
            len = my_mf_generate(amp, digit);
            codec_munge(amp, len);
            if (r2_mf_rx(&mf_state, amp, len) == digit)
                nminus++;
        }
        rrb = (float) (nplus + nminus)/10.0;
        rcfo = (float) (nplus - nminus)/10.0;
        printf ("    %c (high) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n",
                digit,
                rrb,
                rcfo,
                (float) nminus/10.0,
                (float) nplus/10.0);
        if (rrb < rcfo + (2.0*100.0*14.0/r2_mf_fwd_tones[j].f2)  ||  rrb >= 15.0 + rcfo)
        {
            printf ("    Failed\n");
            exit (2);
        }
        j++;
    }
    printf ("    Passed\n");

    /* Test 4: Acceptable amplitude ratio (twist).
       Twist all digits in both directions, and check the maximum twist
       we can accept. The way this is done is styled after the Mitel DTMF
       test, and has good and bad points. */

    printf ("Test 4: Acceptable amplitude ratio (twist)\n");
    s = r2_mf_tone_codes;
    while (*s)
    {
        digit = *s++;
        for (nplus = 0, i = -50;  i >= -250;  i--)
        {
            my_mf_gen_init(0.0, -5, 0.0, i/10, 68, fwd);

            len = my_mf_generate(amp, digit);
            codec_munge (amp, len);
            if (r2_mf_rx(&mf_state, amp, len) == digit)
                nplus++;
        }
        printf ("    %c normal twist  = %.2fdB\n", digit, (float) nplus/10.0);
        if (nplus < 70)
        {
            printf ("    Failed\n");
            exit (2);
        }
        for (nminus = 0, i = -50;  i >= -250;  i--)
        {
            my_mf_gen_init(0.0, i/10, 0.0, -5, 68, fwd);

            len = my_mf_generate(amp, digit);
            codec_munge(amp, len);
            if (r2_mf_rx(&mf_state, amp, len) == digit)
                nminus++;
        }
        printf ("    %c reverse twist = %.2fdB\n", digit, (float) nminus/10.0);
        if (nminus < 70)
        {
            printf ("    Failed\n");
            exit (2);
        }
    }
    printf ("    Passed\n");

    /* Test 5: Dynamic range
       This test sends all possible digits, with gradually increasing 
       amplitude. We determine the span over which we achieve reliable
       detection. */
       
    printf ("Test 5: Dynamic range\n");
    for (nplus = nminus = -1000, i = -50;  i <= 3;  i++)
    {
        s = r2_mf_tone_codes;
        while (*s)
        {
            digit = *s++;
            my_mf_gen_init(0.0, i, 0.0, i, 68, fwd);
            for (j = 0;  j < 100;  j++)
            {
                len = my_mf_generate(amp, digit);
                codec_munge(amp, len);
                if (r2_mf_rx(&mf_state, amp, len) != digit)
                    break;
            }
            if (j < 100)
                break;
        }
        if (j == 100)
        {
            if (nplus == -1000)
                nplus = i;
        }
        else
        {
            if (nplus != -1000  &&  nminus == -1000)
                nminus = i;
        }
    }
    printf ("    Dynamic range = %ddB to %ddB\n", nplus, nminus - 1);
    if (nplus > -35  ||  nminus <= -5)
    {
        printf("    Failed\n");
        exit(2);
    }
    printf ("    Passed\n");

    /* Test 6: Guard time
       This test sends all possible digits, with a gradually reducing 
       duration. */

    printf ("Test 6: Guard time\n");
    for (i = 30;  i < 62;  i++)
    {
        s = r2_mf_tone_codes;
        j = 0;
        while (*s)
        {
            digit = *s++;
            my_mf_gen_init(0.0, -5, 0.0, -3, i, fwd);
            for (j = 0;  j < 500;  j++)
            {
                len = my_mf_generate(amp, digit);
                codec_munge(amp, len);
                if (r2_mf_rx(&mf_state, amp, len) != digit)
                    break;
            }
            if (j < 500)
                break;
        }
        if (j == 500)
            break;
    }
    printf ("    Guard time = %dms\n", i);
    if (i > 61)
    {
        printf("    Failed\n");
        exit(2);
    }
    printf ("    Passed\n");

    /* Test 7: Acceptable signal to noise ratio
       We send all possible digits at -6dBm from clip, mixed with AWGN.
       We gradually reduce the noise until we get clean detection. */

    printf ("Test 7: Acceptable signal to noise ratio\n");
    my_mf_gen_init(0.0, -3, 0.0, -3, 68, fwd);
    for (i = -3;  i > -50;  i--)
    {
        s = r2_mf_tone_codes;
        while (*s)
        {
            digit = *s++;
            awgn_init_dbm0(&noise_source, 1234567, (float) i);
            for (j = 0;  j < 500;  j++)
            {
                len = my_mf_generate(amp, digit);
                for (sample = 0;  sample < len;  sample++)
                    amp[sample] = saturate(amp[sample] + awgn(&noise_source));
                codec_munge(amp, len);
                if (r2_mf_rx(&mf_state, amp, len) != digit)
                    break;
            }
            if (j < 500)
                break;
        }
        if (j == 500)
            break;
    }
    printf("    Acceptable S/N ratio is %ddB\n", -3 - i);
    if (-3 - i > 26)
    {
        printf("    Failed\n");
        exit(2);
    }
    printf("    Passed\n");

    /* The remainder of the Mitel tape is the talk-off test. This is
       meaningless for R2 MF. However the decoder's tolerance of
       out of band noise is significant. */
    /* TODO: add a OOB tolerance test. */
    
    return 0;
}
Пример #13
0
int main(int argc, char *argv[])
{
    echo_can_state_t *ctx;
    awgn_state_t local_noise_source;
    awgn_state_t far_noise_source;
    int i;
    int clean;
    int residue;
    int16_t rx;
    int16_t tx;
    int j;
    int k;
    tone_gen_descriptor_t tone_desc;
    tone_gen_state_t tone_state;
    int16_t local_sound[40000];
    int local_max;
    int local_cur;
    int16_t hoth_noise;
    //int16_t far_sound[SAMPLE_RATE];
    //int16_t result_sound[64000];
    //int32_t coeffs[200][128];
    //int coeff_index;
    int far_cur;
    int result_cur;
    //int far_tx;
    AFfilehandle resulthandle;
    AFfilesetup filesetup;
    AFfilesetup filesetup2;
    //int outframes;
    time_t now;
    int tone_burst_step;
    level_measurement_device_t *power_meter_1;
    level_measurement_device_t *power_meter_2;
    float pp1;
    float pp2;
    int model_number;
    int use_gui;

    power_meter_1 = NULL;
    power_meter_2 = NULL;
    /* Check which tests we should run */
    if (argc < 2)
        fprintf(stderr, "Usage: echo tests <list of test numbers>\n");
    test_list = 0;
    model_number = 0;
    use_gui = FALSE;
    for (i = 1;  i < argc;  i++)
    {
        if (strcasecmp(argv[i], "2a") == 0)
            test_list |= PERFORM_TEST_2A;
        else if (strcasecmp(argv[i], "2b") == 0)
            test_list |= PERFORM_TEST_2B;
        else if (strcasecmp(argv[i], "2c") == 0)
            test_list |= PERFORM_TEST_2C;
        else if (strcasecmp(argv[i], "3a") == 0)
            test_list |= PERFORM_TEST_3A;
        else if (strcasecmp(argv[i], "3b") == 0)
            test_list |= PERFORM_TEST_3B;
        else if (strcasecmp(argv[i], "3c") == 0)
            test_list |= PERFORM_TEST_3C;
        else if (strcasecmp(argv[i], "4") == 0)
            test_list |= PERFORM_TEST_4;
        else if (strcasecmp(argv[i], "5") == 0)
            test_list |= PERFORM_TEST_5;
        else if (strcasecmp(argv[i], "6") == 0)
            test_list |= PERFORM_TEST_6;
        else if (strcasecmp(argv[i], "7") == 0)
            test_list |= PERFORM_TEST_7;
        else if (strcasecmp(argv[i], "8") == 0)
            test_list |= PERFORM_TEST_8;
        else if (strcasecmp(argv[i], "9") == 0)
            test_list |= PERFORM_TEST_9;
        else if (strcasecmp(argv[i], "10a") == 0)
            test_list |= PERFORM_TEST_10A;
        else if (strcasecmp(argv[i], "10b") == 0)
            test_list |= PERFORM_TEST_10B;
        else if (strcasecmp(argv[i], "10c") == 0)
            test_list |= PERFORM_TEST_10C;
        else if (strcasecmp(argv[i], "11") == 0)
            test_list |= PERFORM_TEST_11;
        else if (strcasecmp(argv[i], "12") == 0)
            test_list |= PERFORM_TEST_12;
        else if (strcasecmp(argv[i], "13") == 0)
            test_list |= PERFORM_TEST_13;
        else if (strcasecmp(argv[i], "14") == 0)
            test_list |= PERFORM_TEST_14;
        else if (strcasecmp(argv[i], "15") == 0)
            test_list |= PERFORM_TEST_15;
        else if (strcmp(argv[i], "-m") == 0)
        {
            if (++i < argc)
                model_number = atoi(argv[i]);
        }
        else if (strcmp(argv[i], "-g") == 0)
        {
            use_gui = TRUE;
        }
        else
        {
            fprintf(stderr, "Unknown test '%s' specified\n", argv[i]);
            exit(2);
        }
    }
    if (test_list == 0)
    {
        fprintf(stderr, "No tests have been selected\n");
        exit(2);
    }
    time(&now);
    tone_burst_step = 0;
    ctx = echo_can_create(TEST_EC_TAPS, 0);
    awgn_init_dbm0(&far_noise_source, 7162534, -50.0f);

    signal_load(&local_css, "sound_c1_8k.wav");
    signal_load(&far_css, "sound_c3_8k.wav");

    filesetup = afNewFileSetup();
    if (filesetup == AF_NULL_FILESETUP)
    {
        fprintf(stderr, "    Failed to create file setup\n");
        exit(2);
    }
    afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
    afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE);
    afInitFileFormat(filesetup, AF_FILE_WAVE);
    afInitChannels(filesetup, AF_DEFAULT_TRACK, 6);

    filesetup2 = afNewFileSetup();
    if (filesetup2 == AF_NULL_FILESETUP)
    {
        fprintf(stderr, "    Failed to create file setup\n");
        exit(2);
    }
    afInitSampleFormat(filesetup2, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
    afInitRate(filesetup2, AF_DEFAULT_TRACK, (float) SAMPLE_RATE);
    afInitFileFormat(filesetup2, AF_FILE_WAVE);
    afInitChannels(filesetup2, AF_DEFAULT_TRACK, 1);

    resulthandle = afOpenFile("result_sound.wav", "w", filesetup);
    if (resulthandle == AF_NULL_FILEHANDLE)
    {
        fprintf(stderr, "    Failed to open result file\n");
        exit(2);
    }

    residuehandle = afOpenFile("residue_sound.wav", "w", filesetup2);
    if (residuehandle == AF_NULL_FILEHANDLE)
    {
        fprintf(stderr, "    Failed to open residue file\n");
        exit(2);
    }
    local_cur = 0;
    far_cur = 0;
    result_cur = 0;
    if (channel_model_create(model_number))
    {
        fprintf(stderr, "    Failed to create line model\n");
        exit(2);
    }
#if defined(ENABLE_GUI)
    if (use_gui)
    {
        start_echo_can_monitor(TEST_EC_TAPS);
        echo_can_monitor_line_model_update(line_model.coeffs, line_model.taps);
    }
#endif
    power_meter_1 = level_measurement_device_create(0);
    power_meter_2 = level_measurement_device_create(0);

    level_measurement_device(power_meter_1, 0);

#if 0
    echo_can_flush(ctx);
    /* Converge the canceller */
    signal_restart(&local_css);
    for (i = 0;  i < 800*2;  i++)
    {
        clean = echo_can_update(ctx, 0, 0);
        put_residue(clean);
    }
    for (i = 0;  i < SAMPLE_RATE*5;  i++)
    {
        tx = signal_amp(&local_css);
        channel_model(&tx, &rx, tx, 0);
        clean = echo_can_update(ctx, tx, rx);
        put_residue(clean);
    }
    echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP | ECHO_CAN_USE_CNG);
    for (i = 0;  i < SAMPLE_RATE*5;  i++)
    {
        tx = signal_amp(&local_css);
        channel_model(&tx, &rx, tx, 0);
        clean = echo_can_update(ctx, tx, rx);
        put_residue(clean);
    }
    echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
    
    for (i = 0;  i < SAMPLE_RATE*10;  i++)
    {
        tx = signal_amp(&local_css);
#if 0
        if ((i/10000)%10 == 9)
        {
            /* Inject a burst of far sound */
            if (far_cur >= far_max)
            {
                far_max = afReadFrames(farhandle, AF_DEFAULT_TRACK, far_sound, SAMPLE_RATE);
                if (far_max < 0)
                {
                    fprintf(stderr, "    Error reading far sound\n");
                    exit(2);
                }
                if (far_max == 0)
                    break;
                far_cur = 0;
            }
            far_tx = far_sound[far_cur++];
        }
        else
        {
            far_tx = 0;
        }
#else
        far_sound[0] = 0;
        far_tx = 0;
#endif
        channel_model(&tx, &rx, tx, far_tx);
        //rx += awgn(&far_noise_source);
        //tx += awgn(&far_noise_source);
        clean = echo_can_update(ctx, tx, rx);

#if defined(XYZZY)
        if (i%SAMPLE_RATE == 0)
        {
            if (coeff_index < 200)
            {
                for (j = 0;  j < ctx->taps;  j++)
                    coeffs[coeff_index][j] = ctx->fir_taps32[j];
                coeff_index++;
            }
        }
#endif
        result_sound[result_cur++] = tx;
        result_sound[result_cur++] = rx;
        result_sound[result_cur++] = clean - far_tx;
        //result_sound[result_cur++] = ctx->tx_power[2];
        //result_sound[result_cur++] = ctx->tx_power[1];
        result_sound[result_cur++] = (ctx->tx_power[1] > 64)  ?  SAMPLE_RATE  :  -SAMPLE_RATE;
        //result_sound[result_cur++] = ctx->tap_set*SAMPLE_RATE;
        //result_sound[result_cur++] = (ctx->nonupdate_dwell > 0)  ?  SAMPLE_RATE  :  -SAMPLE_RATE;
        //result_sound[result_cur++] = ctx->latest_correction >> 8;
        //result_sound[result_cur++] = level_measurement_device(tx)/(16.0*65536.0);
        //result_sound[result_cur++] = level_measurement_device(tx)/4096.0;
        result_sound[result_cur++] = (ctx->tx_power[1] > ctx->rx_power[0])  ?  SAMPLE_RATE  :  -SAMPLE_RATE;
        //result_sound[result_cur++] = (ctx->tx_power[1] > ctx->rx_power[0])  ?  SAMPLE_RATE  :  -SAMPLE_RATE;
        //result_sound[result_cur++] = (ctx->narrowband_score)*5; //  ?  SAMPLE_RATE  :  -SAMPLE_RATE;
        //result_sound[result_cur++] = ctx->tap_rotate_counter*10;
        result_sound[result_cur++] = ctx->vad;
        
        put_residue(clean - far_tx);
        if (result_cur >= 6*SAMPLE_RATE)
        {
            outframes = afWriteFrames(resulthandle,
                                      AF_DEFAULT_TRACK,
                                      result_sound,
                                      result_cur/6);
            if (outframes != result_cur/6)
            {
                fprintf(stderr, "    Error writing result sound\n");
                exit(2);
            }
            result_cur = 0;
        }
    }
    if (result_cur > 0)
    {
        outframes = afWriteFrames(resulthandle,
                                  AF_DEFAULT_TRACK,
                                  result_sound,
                                  result_cur/6);
        if (outframes != result_cur/4)
        {
            fprintf(stderr, "    Error writing result sound\n");
            exit(2);
        }
    }
#endif

    /* Test 1 - Steady state residual and returned echo level test */
    /* This functionality has been merged with test 2 in newer versions of G.168,
       so test 1 no longer exists. */

    /* Test 2 - Convergence and steady state residual and returned echo level test */
    if ((test_list & PERFORM_TEST_2A))
    {
        printf("Performing test 2A - Convergence with NLP enabled\n");
        /* Test 2A - Convergence with NLP enabled */
        echo_can_flush(ctx);
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP);
        /* Converge the canceller */
        signal_restart(&local_css);
        for (i = 0;  i < 800*2;  i++)
        {
            clean = echo_can_update(ctx, 0, 0);
            put_residue(clean);
        }
        for (i = 0;  i < SAMPLE_RATE*50;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            pp1 = level_measurement_device(power_meter_1, rx);
            pp2 = level_measurement_device(power_meter_2, clean);
            residue = 100.0*pp1/pp2;
            put_residue(residue);
#if defined(ENABLE_GUI)
            if (use_gui)
                echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
#endif
        }
#if defined(ENABLE_GUI)
        if (use_gui)
            echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
#endif
    }

    if ((test_list & PERFORM_TEST_2B))
    {
        printf("Performing test 2B - Convergence with NLP disabled\n");
        /* Test 2B - Convergence with NLP disabled */
        echo_can_flush(ctx);
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
        /* Converge a canceller */
        signal_restart(&local_css);
        for (i = 0;  i < 800*2;  i++)
        {
            clean = echo_can_update(ctx, 0, 0);
            put_residue(clean);
        }
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
#if defined(ENABLE_GUI)
            if (use_gui)
                echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
#endif
        }
#if defined(ENABLE_GUI)
        if (use_gui)
            echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
#endif
    }

    if ((test_list & PERFORM_TEST_2C))
    {
        printf("Performing test 2C - Convergence with background noise present\n");
        /* Test 2C - Convergence with background noise present */
        echo_can_flush(ctx);
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
        /* Converge a canceller */
        signal_restart(&local_css);
        for (i = 0;  i < 800*2;  i++)
        {
            clean = echo_can_update(ctx, 0, 0);
            put_residue(clean);
        }
        /* TODO: This uses a crude approx. to Hoth noise. We need the real thing. */
        awgn_init_dbm0(&far_noise_source, 7162534, -40.0f);
        hoth_noise = 0;
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            hoth_noise = hoth_noise*0.625 + awgn(&far_noise_source)*0.375;
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, hoth_noise);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        /* Now freeze adaption, and measure the echo. */
        echo_can_adaption_mode(ctx, 0);
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
#if defined(ENABLE_GUI)
        if (use_gui)
            echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
#endif
    }

    /* Test 3 - Performance under double talk conditions */
    if ((test_list & PERFORM_TEST_3A))
    {
        printf("Performing test 3A - Double talk test with low cancelled-end levels\n");
        /* Test 3A - Double talk test with low cancelled-end levels */
        echo_can_flush(ctx);
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
        signal_restart(&local_css);
        signal_restart(&far_css);
        /* Apply double talk, with a weak far end signal */
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            tx = signal_amp(&local_css);
            rx = signal_amp(&far_css)/20;
            channel_model(&tx, &rx, tx, rx);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean - rx);
        }
        /* Now freeze adaption. */
        echo_can_adaption_mode(ctx, 0);
        for (i = 0;  i < 800*5;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        /* Now measure the echo */
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
#if defined(ENABLE_GUI)
        if (use_gui)
            echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
#endif
    }

    if ((test_list & PERFORM_TEST_3B))
    {
        printf("Performing test 3B - Double talk test with high cancelled-end levels\n");
        /* Test 3B - Double talk test with high cancelled-end levels */
        echo_can_flush(ctx);
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
        signal_restart(&local_css);
        signal_restart(&far_css);
        /* Converge the canceller */
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        /* Apply double talk */
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            tx = signal_amp(&local_css);
            rx = signal_amp(&far_css);
            channel_model(&tx, &rx, tx, rx);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean - rx);
        }
        /* Now freeze adaption. */
        echo_can_adaption_mode(ctx, 0);
        for (i = 0;  i < 800*5;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        /* Now measure the echo */
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
#if defined(ENABLE_GUI)
        if (use_gui)
            echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
#endif
    }

    if ((test_list & PERFORM_TEST_3C))
    {
        printf("Performing test 3C - Double talk test with simulated conversation\n");
        /* Test 3C - Double talk test with simulated conversation */
        echo_can_flush(ctx);
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
        signal_restart(&local_css);
        signal_restart(&far_css);
        /* Apply double talk */
        for (i = 0;  i < 800*56;  i++)
        {
            tx = signal_amp(&local_css);
            rx = signal_amp(&far_css);
            channel_model(&tx, &rx, tx, rx);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean - rx);
        }
        /* Stop the far signal */
        for (i = 0;  i < 800*14;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        /* Continue measuring the resulting echo */
        for (i = 0;  i < 800*50;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        /* Reapply double talk */
        signal_restart(&far_css);
        for (i = 0;  i < 800*56;  i++)
        {
            tx = signal_amp(&local_css);
            rx = signal_amp(&far_css);
            channel_model(&tx, &rx, tx, rx);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean - rx);
        }
        /* Now the far signal only */
        for (i = 0;  i < 800*56;  i++)
        {
            tx = 0;
            rx = signal_amp(&far_css);
            channel_model(&tx, &rx, 0, rx);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean - rx);
        }
#if defined(ENABLE_GUI)
        if (use_gui)
            echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
#endif
    }

    if ((test_list & PERFORM_TEST_4))
    {
        printf("Performing test 4 - Leak rate test\n");
        /* Test 4 - Leak rate test */
        echo_can_flush(ctx);
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
        /* Converge a canceller */
        signal_restart(&local_css);
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        /* Put 2 minutes of silence through it */
        for (i = 0;  i < SAMPLE_RATE*120;  i++)
        {
            clean = echo_can_update(ctx, 0, 0);
            put_residue(clean);
        }
        /* Now freeze it, and check if it is still well adapted. */
        echo_can_adaption_mode(ctx, 0);
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
#if defined(ENABLE_GUI)
        if (use_gui)
            echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
#endif
    }

    if ((test_list & PERFORM_TEST_5))
    {
        printf("Performing test 5 - Infinite return loss convergence test\n");
        /* Test 5 - Infinite return loss convergence test */
        echo_can_flush(ctx);
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
        /* Converge the canceller */
        signal_restart(&local_css);
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        /* Now stop echoing, and see we don't do anything unpleasant as the
           echo path is open looped. */
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            tx = signal_amp(&local_css);
            rx = 0;
            tx = codec_munge(tx);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
#if defined(ENABLE_GUI)
        if (use_gui)
            echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
#endif
    }

    if ((test_list & PERFORM_TEST_6))
    {
        printf("Performing test 6 - Non-divergence on narrow-band signals\n");
        /* Test 6 - Non-divergence on narrow-band signals */
        echo_can_flush(ctx);
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
        /* Converge the canceller */
        signal_restart(&local_css);
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        /* Now put 5s bursts of a list of tones through the converged canceller, and check
           that bothing unpleasant happens. */
        for (k = 0;  tones_6_4_2_7[k][0];  k++)
        {
            make_tone_gen_descriptor(&tone_desc,
                                     tones_6_4_2_7[k][0],
                                     -11,
                                     tones_6_4_2_7[k][1],
                                     -9,
                                     1,
                                     0,
                                     0,
                                     0,
                                     1);
            tone_gen_init(&tone_state, &tone_desc);
            j = 0;
            for (i = 0;  i < 5;  i++)
            {
                local_max = tone_gen(&tone_state, local_sound, SAMPLE_RATE);
                for (j = 0;  j < SAMPLE_RATE;  j++)
                {
                    tx = local_sound[j];
                    channel_model(&tx, &rx, tx, 0);
                    clean = echo_can_update(ctx, tx, rx);
                    put_residue(clean);
                }
#if defined(ENABLE_GUI)
                if (use_gui)
                {
                    echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
                    echo_can_monitor_update_display();
                    usleep(100000);
                }
#endif
            }
        }
#if defined(ENABLE_GUI)
        if (use_gui)
            echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
#endif
    }

    if ((test_list & PERFORM_TEST_7))
    {
        printf("Performing test 7 - Stability\n");
        /* Test 7 - Stability */
        /* Put tones through an unconverged canceller, and check nothing unpleasant
           happens. */
        echo_can_flush(ctx);
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
        make_tone_gen_descriptor(&tone_desc,
                                 tones_6_4_2_7[0][0],
                                 -11,
                                 tones_6_4_2_7[0][1],
                                 -9,
                                 1,
                                 0,
                                 0,
                                 0,
                                 1);
        tone_gen_init(&tone_state, &tone_desc);
        j = 0;
        for (i = 0;  i < 120;  i++)
        {
            local_max = tone_gen(&tone_state, local_sound, SAMPLE_RATE);
            for (j = 0;  j < SAMPLE_RATE;  j++)
            {
                tx = local_sound[j];
                channel_model(&tx, &rx, tx, 0);
                clean = echo_can_update(ctx, tx, rx);
                put_residue(clean);
            }
#if defined(ENABLE_GUI)
            if (use_gui)
            {
                echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
                echo_can_monitor_update_display();
                usleep(100000);
            }
#endif
        }
#if defined(ENABLE_GUI)
        if (use_gui)
            echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
#endif
    }

    if ((test_list & PERFORM_TEST_8))
    {
        printf("Performing test 8 - Non-convergence on No 5, 6, and 7 in-band signalling\n");
        /* Test 8 - Non-convergence on No 5, 6, and 7 in-band signalling */
        fprintf(stderr, "Test 8 not yet implemented\n");
    }

    if ((test_list & PERFORM_TEST_9))
    {
        printf("Performing test 9 - Comfort noise test\n");
        /* Test 9 - Comfort noise test */
        /* Test 9 part 1 - matching */
        echo_can_flush(ctx);
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
        /* Converge the canceller */
        signal_restart(&local_css);
        for (i = 0;  i < SAMPLE_RATE*5;  i++)
        {
            tx = signal_amp(&local_css);
            channel_model(&tx, &rx, tx, 0);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP | ECHO_CAN_USE_CNG);
        awgn_init_dbm0(&far_noise_source, 7162534, -45.0f);
        for (i = 0;  i < SAMPLE_RATE*30;  i++)
        {
            tx = 0;
            rx = awgn(&far_noise_source);
            channel_model(&tx, &rx, tx, rx);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        awgn_init_dbm0(&local_noise_source, 1234567, -10.0f);
        for (i = 0;  i < SAMPLE_RATE*2;  i++)
        {
            tx = awgn(&local_noise_source);
            rx = awgn(&far_noise_source);
            channel_model(&tx, &rx, tx, rx);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }

        /* Test 9 part 2 - adjust down */
        awgn_init_dbm0(&far_noise_source, 7162534, -55.0f);
        for (i = 0;  i < SAMPLE_RATE*10;  i++)
        {
            tx = 0;
            rx = awgn(&far_noise_source);
            channel_model(&tx, &rx, tx, rx);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
        for (i = 0;  i < SAMPLE_RATE*2;  i++)
        {
            tx = awgn(&local_noise_source);
            rx = awgn(&far_noise_source);
            channel_model(&tx, &rx, tx, rx);
            clean = echo_can_update(ctx, tx, rx);
            put_residue(clean);
        }
#if defined(ENABLE_GUI)
        if (use_gui)
            echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS);
#endif
    }

    /* Test 10 - FAX test during call establishment phase */
    if ((test_list & PERFORM_TEST_10A))
    {
        printf("Performing test 10A - Canceller operation on the calling station side\n");
        /* Test 10A - Canceller operation on the calling station side */
        fprintf(stderr, "Test 10A not yet implemented\n");
    }

    if ((test_list & PERFORM_TEST_10B))
    {
        printf("Performing test 10B - Canceller operation on the called station side\n");
        /* Test 10B - Canceller operation on the called station side */
        fprintf(stderr, "Test 10B not yet implemented\n");
    }

    if ((test_list & PERFORM_TEST_10C))
    {
        printf("Performing test 10C - Canceller operation on the calling station side during page\n"
               "transmission and page breaks (for further study)\n");
        /* Test 10C - Canceller operation on the calling station side during page
                      transmission and page breaks (for further study) */
        fprintf(stderr, "Test 10C not yet implemented\n");
    }

    if ((test_list & PERFORM_TEST_11))
    {
        printf("Performing test 11 - Tandem echo canceller test (for further study)\n");
        /* Test 11 - Tandem echo canceller test (for further study) */
        fprintf(stderr, "Test 11 not yet implemented\n");
    }

    if ((test_list & PERFORM_TEST_12))
    {
        printf("Performing test 12 - Residual acoustic echo test (for further study)\n");
        /* Test 12 - Residual acoustic echo test (for further study) */
        fprintf(stderr, "Test 12 not yet implemented\n");
    }

    if ((test_list & PERFORM_TEST_13))
    {
        printf("Performing test 13 - Performance with ITU-T low-bit rate coders in echo path (Optional, under study)\n");
        /* Test 13 - Performance with ITU-T low-bit rate coders in echo path
                     (Optional, under study) */
        fprintf(stderr, "Test 13 not yet implemented\n");
    }

    if ((test_list & PERFORM_TEST_14))
    {
        printf("Performing test 14 - Performance with V-series low-speed data modems\n");
        /* Test 14 - Performance with V-series low-speed data modems */
        fprintf(stderr, "Test 14 not yet implemented\n");
    }

    if ((test_list & PERFORM_TEST_15))
    {
        printf("Performing test 15 - PCM offset test (Optional)\n");
        /* Test 15 - PCM offset test (Optional) */
        fprintf(stderr, "Test 15 not yet implemented\n");
    }

    echo_can_free(ctx);

    signal_free(&local_css);
    signal_free(&far_css);

    if (afCloseFile(resulthandle) != 0)
    {
        fprintf(stderr, "    Cannot close speech file '%s'\n", "result_sound.wav");
        exit(2);
    }
    if (afCloseFile(residuehandle) != 0)
    {
        fprintf(stderr, "    Cannot close speech file '%s'\n", "residue_sound.wav");
        exit(2);
    }
    afFreeFileSetup(filesetup);
    afFreeFileSetup(filesetup2);

#if defined(XYZZY)
    for (j = 0;  j < ctx->taps;  j++)
    {
        for (i = 0;  i < coeff_index;  i++)
            fprintf(stderr, "%d ", coeffs[i][j]);
        fprintf(stderr, "\n");
    }
#endif
    printf("Run time %lds\n", time(NULL) - now);
    
#if defined(ENABLE_GUI)
    if (use_gui)
        echo_can_monitor_wait_to_end();
#endif

    if (power_meter_1)
        level_measurement_device_release(power_meter_1);
    if (power_meter_2)
        level_measurement_device_release(power_meter_2);

    printf("Tests passed.\n");
    return  0;
}
Пример #14
0
int main(int argc, char *argv[])
{
    int i;
    int j;
    int clip_high;
    int clip_low;
    int total_samples;
    int idum = 1234567;
    int16_t value;
    double total;
    double x;
    double p;
    double o;
    double error;
    int bins[65536];
    awgn_state_t noise_source;

    /* Generate noise at several RMS levels between -50dBm and 0dBm. Noise is
       generated for a large number of samples (1,000,000), and the RMS value
       of the noise is calculated along the way. If the resulting level is
       close to the requested RMS level, at least the scaling of the noise
       should be Ok. At high level some clipping may distort the result a
       little. */
    for (j = -50;  j <= 0;  j += 5)
    {
        clip_high = 0;
        clip_low = 0;
        total = 0.0;
        awgn_init_dbm0(&noise_source, idum, (float) j);
        total_samples = 1000000;
        for (i = 0;  i < total_samples;  i++)
        {
            value = awgn(&noise_source);
            if (value == 32767)
                clip_high++;
            else if (value == -32768)
                clip_low++;
            total += ((double) value)*((double) value);
        }
        error = 100.0*(1.0 - sqrt(total/total_samples)/noise_source.rms);
        printf("RMS = %.3f (expected %d) %.2f%% error [clipped samples %d+%d]\n",
               10.0*log10((total/total_samples)/(32768.0*32768.0) + 1.0e-10) + DBM0_MAX_POWER,
               j,
               error,
               clip_low,
               clip_high);
        /* We don't check the result at 0dBm0, as there will definitely be a lot of error due to clipping */
        if (j < 0  &&  fabs(error) > 0.2)
        {
            printf("Test failed.\n");
            exit(2);
        }
    }
    /* Now look at the statistical spread of the results, by collecting data in
       bins from a large number of samples. Use a fairly high noise level, but
       low enough to avoid significant clipping. Use the Gaussian model to
       predict the real probability, and present the results for graphing. */
    memset(bins, 0, sizeof(bins));
    clip_high = 0;
    clip_low = 0;
    awgn_init_dbm0(&noise_source, idum, -15);
    total_samples = 10000000;
    for (i = 0;  i < total_samples;  i++)
    {
        value = awgn(&noise_source);
        if (value == 32767)
            clip_high++;
        else if (value == -32768)
            clip_low++;
        bins[value + 32768]++;
    }
    o = noise_source.rms;
    for (i = 0;  i < 65536 - 10;  i++)
    {
        x = i - 32768;
        /* Find the real probability for this bin */
        p = (1.0/(o*sqrt(2.0*M_PI)))*exp(-(x*x)/(2.0*o*o));
        /* Now do a little smoothing on the real data to get a reasonably
           steady answer */
        x = 0;
        for (j = 0;  j < 10;  j++)
            x += bins[i + j];
        x /= 10.0;
        x /= total_samples;
        /* Now send it out for graphing. */
        printf("%6d %.7f %.7f\n", i - 32768, x, p);
    }
    
    printf("Tests passed.\n");
    return  0;
}
Пример #15
0
int main(int argc, char *argv[])
{
    SNDFILE *wave_handle;
    SNDFILE *input_wave_handle;
    int i;
    int j;
    int k;
    struct machine_s *mc;
    int outframes;
    char buf[128 + 1];
    int16_t silence[SAMPLES_PER_CHUNK];
    int16_t out_amp[2*SAMPLES_PER_CHUNK];
    int alldone;
    const char *input_tiff_file_name;
    const char *input_audio_file_name;
    int log_audio;
    int use_ecm;
    int use_tep;
    int use_transmit_on_idle;
#if defined(WITH_SPANDSP_INTERNALS)
    int use_line_hits;
#endif
    int polled_mode;
    int reverse_flow;
    int use_page_limits;
    int supported_modems;
    int signal_level;
    int noise_level;
    float signal_scaling;
    time_t start_time;
    time_t end_time;
    int scan_line_time;
    char *page_header_info;
    int opt;
    t30_state_t *t30;
    logging_state_t *logging;

    log_audio = false;
    input_tiff_file_name = INPUT_TIFF_FILE_NAME;
    input_audio_file_name = NULL;
    use_ecm = false;
#if defined(WITH_SPANDSP_INTERNALS)
    use_line_hits = false;
#endif
    use_tep = false;
    polled_mode = false;
    page_header_info = NULL;
    reverse_flow = false;
    use_transmit_on_idle = true;
    use_receiver_not_ready = false;
    use_page_limits = false;
    signal_level = 0;
    noise_level = -99;
    scan_line_time = 0;
    supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17;
    while ((opt = getopt(argc, argv, "ehH:i:I:lm:n:prRs:S:tTw:")) != -1)
    {
        switch (opt)
        {
        case 'e':
            use_ecm = true;
            break;
#if defined(WITH_SPANDSP_INTERNALS)
        case 'h':
            use_line_hits = true;
            break;
#endif
        case 'H':
            page_header_info = optarg;
            break;
        case 'i':
            input_tiff_file_name = optarg;
            break;
        case 'I':
            input_audio_file_name = optarg;
            break;
        case 'l':
            log_audio = true;
            break;
        case 'm':
            supported_modems = atoi(optarg);
            break;
        case 'n':
            noise_level = atoi(optarg);
            break;
        case 'p':
            polled_mode = true;
            break;
        case 'r':
            reverse_flow = true;
            break;
        case 'R':
            use_receiver_not_ready = true;
            break;
        case 's':
            signal_level = atoi(optarg);
            break;
        case 'S':
            scan_line_time = atoi(optarg);
            break;
        case 't':
            use_tep = true;
            break;
        case 'T':
            use_page_limits = true;
            break;
        case 'w':
            t30_state_to_wreck = atoi(optarg);
            break;
        default:
            //usage();
            exit(2);
            break;
        }
    }

    input_wave_handle = NULL;
    if (input_audio_file_name)
    {
        if ((input_wave_handle = sf_open_telephony_read(input_audio_file_name, 1)) == NULL)
        {
            fprintf(stderr, "    Cannot open audio file '%s'\n", input_audio_file_name);
            exit(2);
        }
    }

    wave_handle = NULL;
    if (log_audio)
    {
        if ((wave_handle = sf_open_telephony_write(OUTPUT_FILE_NAME_WAVE, 2)) == NULL)
        {
            fprintf(stderr, "    Cannot create audio file '%s'\n", OUTPUT_FILE_NAME_WAVE);
            exit(2);
        }
    }

    memset(silence, 0, sizeof(silence));
    for (j = 0;  j < FAX_MACHINES;  j++)
    {
        machines[j].chan = j;
        mc = &machines[j];

        i = mc->chan + 1;
        sprintf(buf, "%d%d%d%d%d%d%d%d", i, i, i, i, i, i, i, i);
        if (reverse_flow)
            mc->fax = fax_init(NULL, (mc->chan & 1)  ?  true  :  false);
        else
            mc->fax = fax_init(NULL, (mc->chan & 1)  ?  false  :  true);
        mc->awgn = NULL;
        signal_scaling = 1.0f;
        if (noise_level > -99)
        {
            mc->awgn = awgn_init_dbm0(NULL, 1234567, noise_level);
            signal_scaling = powf(10.0f, signal_level/20.0f);
            printf("Signal scaling %f\n", signal_scaling);
        }
        fax_set_transmit_on_idle(mc->fax, use_transmit_on_idle);
        fax_set_tep_mode(mc->fax, use_tep);
        t30 = fax_get_t30_state(mc->fax);
        t30_set_tx_ident(t30, buf);
        t30_set_tx_sub_address(t30, "Sub-address");
        t30_set_tx_sender_ident(t30, "Sender ID");
        t30_set_tx_password(t30, "Password");
        t30_set_tx_polled_sub_address(t30, "Polled sub-address");
        t30_set_tx_selective_polling_address(t30, "Selective polling address");
        t30_set_tx_page_header_info(t30, page_header_info);
        t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
        t30_set_ecm_capability(t30, use_ecm);
        t30_set_supported_t30_features(t30,
                                       T30_SUPPORT_IDENTIFICATION
                                     | T30_SUPPORT_SELECTIVE_POLLING
                                     | T30_SUPPORT_SUB_ADDRESSING);

        if ((mc->chan & 1))
            t30_set_minimum_scan_line_time(t30, scan_line_time);
        t30_set_supported_image_sizes(t30,
                                      T30_SUPPORT_US_LETTER_LENGTH
                                    | T30_SUPPORT_US_LEGAL_LENGTH
                                    | T30_SUPPORT_UNLIMITED_LENGTH
                                    | T30_SUPPORT_215MM_WIDTH
                                    | T30_SUPPORT_255MM_WIDTH
                                    | T30_SUPPORT_303MM_WIDTH);
        t30_set_supported_resolutions(t30,
                                      T30_SUPPORT_STANDARD_RESOLUTION
                                    | T30_SUPPORT_FINE_RESOLUTION
                                    | T30_SUPPORT_SUPERFINE_RESOLUTION
                                    | T30_SUPPORT_R8_RESOLUTION
                                    | T30_SUPPORT_R16_RESOLUTION
                                    | T30_SUPPORT_300_300_RESOLUTION
                                    | T30_SUPPORT_400_400_RESOLUTION
                                    | T30_SUPPORT_600_600_RESOLUTION
                                    | T30_SUPPORT_1200_1200_RESOLUTION
                                    | T30_SUPPORT_300_600_RESOLUTION
                                    | T30_SUPPORT_400_800_RESOLUTION
                                    | T30_SUPPORT_600_1200_RESOLUTION);
        t30_set_supported_modems(t30, supported_modems);
        if (use_ecm)
#if defined(SPANDSP_SUPPORT_T85)
            t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION | T30_SUPPORT_T85_COMPRESSION);
#else
            t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
#endif
        if ((mc->chan & 1))
        {
            if (polled_mode)
            {
                if (use_page_limits)
                    t30_set_tx_file(t30, input_tiff_file_name, 3, 6);
                else
                    t30_set_tx_file(t30, input_tiff_file_name, -1, -1);
            }
            else
            {
                sprintf(buf, "fax_tests_%d.tif", (mc->chan + 1)/2);
                t30_set_rx_file(t30, buf, -1);
                t30_set_rx_encoding(t30, T4_COMPRESSION_ITU_T6);
            }
        }
        else
        {
            if (polled_mode)
            {
                sprintf(buf, "fax_tests_%d.tif", (mc->chan + 1)/2);
                t30_set_rx_file(t30, buf, -1);
                t30_set_rx_encoding(t30, T4_COMPRESSION_ITU_T6);
            }
            else
            {
                if (use_page_limits)
                    t30_set_tx_file(t30, input_tiff_file_name, 3, 6);
                else
                    t30_set_tx_file(t30, input_tiff_file_name, -1, -1);
            }
        }
        t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) mc->chan + 'A');
        t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) mc->chan + 'A');
        t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) mc->chan + 'A');
        t30_set_real_time_frame_handler(t30, real_time_frame_handler, (void *) (intptr_t) mc->chan + 'A');
        t30_set_document_handler(t30, document_handler, (void *) (intptr_t) mc->chan + 'A');
        sprintf(mc->tag, "FAX-%d", j + 1);

        logging = t30_get_logging_state(t30);
        span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
        span_log_set_tag(logging, mc->tag);
        if ((j & 1))
        {
            span_log_set_level(&t30->t4.rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
            span_log_set_tag(&t30->t4.rx.logging, mc->tag);
        }
        else
        {
            span_log_set_level(&t30->t4.tx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
            span_log_set_tag(&t30->t4.tx.logging, mc->tag);
        }
        logging = fax_get_logging_state(mc->fax);
        span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
        span_log_set_tag(logging, mc->tag);

        memset(mc->amp, 0, sizeof(mc->amp));
        mc->total_audio_time = 0;
        mc->done = false;
    }
    time(&start_time);
    for (;;)
    {
        alldone = true;
        for (j = 0;  j < FAX_MACHINES;  j++)
        {
            mc = &machines[j];

            if ((j & 1) == 0  &&  input_audio_file_name)
            {
                mc->len = sf_readf_short(input_wave_handle, mc->amp, SAMPLES_PER_CHUNK);
                if (mc->len == 0)
                    break;
            }
            else
            {
                mc->len = fax_tx(mc->fax, mc->amp, SAMPLES_PER_CHUNK);
                if (mc->awgn)
                {
                    for (k = 0;  k < mc->len;  k++)
                        mc->amp[k] = ((int16_t) (mc->amp[k]*signal_scaling)) + awgn(mc->awgn);
                }
            }
            mc->total_audio_time += SAMPLES_PER_CHUNK;
            if (!use_transmit_on_idle)
            {
                /* The receive side always expects a full block of samples, but the
                   transmit side may not be sending any when it doesn't need to. We
                   may need to pad with some silence. */
                if (mc->len < SAMPLES_PER_CHUNK)
                {
                    memset(mc->amp + mc->len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - mc->len));
                    mc->len = SAMPLES_PER_CHUNK;
                }
            }
            t30 = fax_get_t30_state(mc->fax);
            logging = t30_get_logging_state(t30);
            span_log_bump_samples(logging, mc->len);
            logging = fax_get_logging_state(mc->fax);
            span_log_bump_samples(logging, mc->len);

            if (log_audio)
            {
                for (k = 0;  k < mc->len;  k++)
                    out_amp[2*k + j] = mc->amp[k];
            }
            if (machines[j ^ 1].len < SAMPLES_PER_CHUNK)
                memset(machines[j ^ 1].amp + machines[j ^ 1].len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - machines[j ^ 1].len));
            t30 = fax_get_t30_state(mc->fax);
#if defined(WITH_SPANDSP_INTERNALS)
            if (use_line_hits)
            {
                /* TODO: This applies very crude line hits. improve it */
                if (t30->state == 22)
                {
                    if (++mc->error_delay == 100)
                    {
                        fprintf(stderr, "HIT %d!\n", j);
                        mc->error_delay = 0;
                        for (k = 0;  k < 5;  k++)
                            mc->amp[k] = 0;
                    }
                }
            }
            if (t30->state == t30_state_to_wreck)
                memset(machines[j ^ 1].amp, 0, sizeof(int16_t)*SAMPLES_PER_CHUNK);
#endif
            if (fax_rx(mc->fax, machines[j ^ 1].amp, SAMPLES_PER_CHUNK))
                break;
            if (!mc->done)
                alldone = false;
        }

        if (log_audio)
        {
            outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK);
            if (outframes != SAMPLES_PER_CHUNK)
                break;
        }

        if (alldone  ||  j < FAX_MACHINES)
            break;
    }
    time(&end_time);
    for (j = 0;  j < FAX_MACHINES;  j++)
    {
        mc = &machines[j];
        fax_release(mc->fax);
    }
    if (log_audio)
    {
        if (sf_close(wave_handle))
        {
            fprintf(stderr, "    Cannot close audio file '%s'\n", OUTPUT_FILE_NAME_WAVE);
            exit(2);
        }
    }
    if (input_audio_file_name)
    {
        if (sf_close(input_wave_handle))
        {
            fprintf(stderr, "    Cannot close audio file '%s'\n", input_audio_file_name);
            exit(2);
        }
    }
    printf("Total audio time = %ds (wall time %ds)\n", machines[0].total_audio_time/8000, (int) (end_time - start_time));
    return 0;
}
Пример #16
0
static void test_one_way_model(int line_model_no, int speech_test)
{
    one_way_line_model_state_t *model;
    int16_t input1[BLOCK_LEN];
    int16_t output1[BLOCK_LEN];
    int16_t amp[2*BLOCK_LEN];
    AFfilehandle inhandle1;
    AFfilehandle outhandle;
    AFfilesetup filesetup;
    int outframes;
    int samples;
    int i;
    int j;
    awgn_state_t noise1;
    
    if ((model = one_way_line_model_init(line_model_no, -50, MUNGE_CODEC_ALAW)) == NULL)
    {
        fprintf(stderr, "    Failed to create line model\n");
        exit(2);
    }
    
    awgn_init_dbm0(&noise1, 1234567, -10.0f);

    if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP)
    {
        fprintf(stderr, "    Failed to create file setup\n");
        exit(2);
    }
    afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
    afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE);
    afInitFileFormat(filesetup, AF_FILE_WAVE);
    afInitChannels(filesetup, AF_DEFAULT_TRACK, 1);

    if ((inhandle1 = afOpenFile(IN_FILE_NAME1, "r", NULL)) == AF_NULL_FILEHANDLE)
    {
        fprintf(stderr, "    Cannot open wave file '%s'\n", IN_FILE_NAME1);
        exit(2);
    }
    if ((outhandle = afOpenFile(OUT_FILE_NAME1, "w", filesetup)) == AF_NULL_FILEHANDLE)
    {
        fprintf(stderr, "    Cannot create wave file '%s'\n", OUT_FILE_NAME1);
        exit(2);
    }
    for (i = 0;  i < 10000;  i++)
    {
        if (speech_test)
        {
            samples = afReadFrames(inhandle1,
                                   AF_DEFAULT_TRACK,
                                   input1,
                                   BLOCK_LEN);
            if (samples == 0)
                break;
        }
        else
        {
            for (j = 0;  j < BLOCK_LEN;  j++)
                input1[j] = awgn(&noise1);
            samples = BLOCK_LEN;
        }
        for (j = 0;  j < samples;  j++)
        {
            one_way_line_model(model, 
                               &output1[j],
                               &input1[j],
                               1);
            amp[j] = output1[j];
        }
        outframes = afWriteFrames(outhandle,
                                  AF_DEFAULT_TRACK,
                                  amp,
                                  samples);
        if (outframes != samples)
        {
            fprintf(stderr, "    Error writing wave file\n");
            exit(2);
        }
    }
    if (afCloseFile(inhandle1))
    {
        fprintf(stderr, "    Cannot close wave file '%s'\n", IN_FILE_NAME1);
        exit(2);
    }
    if (afCloseFile(outhandle))
    {
        fprintf(stderr, "    Cannot close wave file '%s'\n", OUT_FILE_NAME1);
        exit(2);
    }
    afFreeFileSetup(filesetup);
    one_way_line_model_release(model);
}