예제 #1
0
static int
acmod_process_full_raw(acmod_t *acmod,
                       int16 const **inout_raw,
                       size_t *inout_n_samps)
{
    int32 nfr, ntail;
    mfcc_t **cepptr;

    /* Write to logging file if any. */
    if (acmod->rawfh)
        fwrite(*inout_raw, 2, *inout_n_samps, acmod->rawfh);
    /* Resize mfc_buf to fit. */
    if (fe_process_frames(acmod->fe, NULL, inout_n_samps, NULL, &nfr) < 0)
        return -1;
    if (acmod->n_mfc_alloc < nfr + 1) {
        ckd_free_2d(acmod->mfc_buf);
        acmod->mfc_buf = ckd_calloc_2d(nfr + 1, fe_get_output_size(acmod->fe),
                                       sizeof(**acmod->mfc_buf));
        acmod->n_mfc_alloc = nfr + 1;
    }
    acmod->n_mfc_frame = 0;
    acmod->mfc_outidx = 0;
    fe_start_utt(acmod->fe);
    if (fe_process_frames(acmod->fe, inout_raw, inout_n_samps,
                          acmod->mfc_buf, &nfr) < 0)
        return -1;
    fe_end_utt(acmod->fe, acmod->mfc_buf[nfr], &ntail);
    nfr += ntail;

    cepptr = acmod->mfc_buf;
    nfr = acmod_process_full_cep(acmod, &cepptr, &nfr);
    acmod->n_mfc_frame = 0;
    return nfr;
}
예제 #2
0
/**
 * Process PCM audio from a filehandle.  Assume that wtf->infh is
 * positioned just after the file header.
 */
static int
decode_pcm(sphinx_wave2feat_t *wtf)
{
    size_t nsamp;
    int32 n, nfr, nchans, whichchan;
    uint32 nfloat;

    nchans = cmd_ln_int32_r(wtf->config, "-nchans");
    whichchan = cmd_ln_int32_r(wtf->config, "-whichchan");
    fe_start_utt(wtf->fe);
    nfloat = 0;
    while ((nsamp = fread(wtf->audio, 2, wtf->blocksize, wtf->infh)) != 0) {
        size_t nvec;
        int16 const *inspeech;

        /* Byteswap stuff here if necessary. */
        if (wtf->byteswap) {
            for (n = 0; n < nsamp; ++n)
                SWAP_INT16(wtf->audio + n);
        }

        /* Mix or pick channels. */
        if (nchans > 1)
            nsamp = mixnpick_channels(wtf->audio, nsamp, nchans, whichchan);
            
        inspeech = wtf->audio;
        nvec = wtf->featsize;
        /* Consume all samples. */
        while (nsamp) {
            nfr = nvec;
            fe_process_frames(wtf->fe, &inspeech, &nsamp, wtf->feat, &nfr, NULL);
            if (nfr) {
                if ((n = (*wtf->ot->output_frames)(wtf, wtf->feat, nfr)) < 0)
                    return -1;
                nfloat += n;
            }
        }
        inspeech = wtf->audio;
    }
    /* Now process any leftover audio frames. */
    fe_end_utt(wtf->fe, wtf->feat[0], &nfr);
    if (nfr) {
        if ((n = (*wtf->ot->output_frames)(wtf, wtf->feat, nfr)) < 0)
            return -1;
        nfloat += n;
    }

    if (fclose(wtf->infh) == EOF)
        E_ERROR_SYSTEM("Failed to close input file");
    wtf->infh = NULL;
    return nfloat;
}
예제 #3
0
/**
 * Process PCM audio from a libsndfile file.  FIXME: looks a lot like
 * decode_pcm!  Also needs stereo support (as does decode_pcm).
 */
static int
decode_sndfile(sphinx_wave2feat_t *wtf)
{
    size_t nsamp;
    int32 nfr, nchans, whichchan;
    int nfloat, n;

    nchans = cmd_ln_int32_r(wtf->config, "-nchans");
    whichchan = cmd_ln_int32_r(wtf->config, "-whichchan");
    fe_start_utt(wtf->fe);
    nfloat = 0;
    while ((nsamp = sf_read_short(wtf->insfh,
                                  wtf->audio,
                                  wtf->blocksize)) != 0) {
        int16 const *inspeech;
        size_t nvec;

        /* Mix or pick channels. */
        if (nchans > 1)
            nsamp = mixnpick_channels(wtf->audio, nsamp, nchans, whichchan);

        inspeech = wtf->audio;
        nvec = wtf->featsize;
        /* Consume all samples. */
        while (nsamp) {
            nfr = nvec;
            fe_process_frames(wtf->fe, &inspeech, &nsamp, wtf->feat, &nfr, NULL);
            if (nfr) {
                if ((n = (*wtf->ot->output_frames)(wtf, wtf->feat, nfr)) < 0)
                    return -1;
                nfloat += n;
            }
        }
        inspeech = wtf->audio;
    }
    /* Now process any leftover audio frames. */
    fe_end_utt(wtf->fe, wtf->feat[0], &nfr);
    if (nfr) {
        if ((n = (*wtf->ot->output_frames)(wtf, wtf->feat, nfr)) < 0)
            return -1;
        nfloat += n;
    }

    sf_close(wtf->insfh);
    wtf->insfh = NULL;
    return nfloat;
}
예제 #4
0
파일: acmod.c 프로젝트: JonGBowen/GoodVibes
int
acmod_end_utt(acmod_t *acmod)
{
    int32 nfr = 0;

    acmod->state = ACMOD_ENDED;
    if (acmod->n_mfc_frame < acmod->n_mfc_alloc) {
        int inptr;
        /* Where to start writing them (circular buffer) */
        inptr = (acmod->mfc_outidx + acmod->n_mfc_frame) % acmod->n_mfc_alloc;
        /* nfr is always either zero or one. */
        fe_end_utt(acmod->fe, acmod->mfc_buf[inptr], &nfr);
        acmod->n_mfc_frame += nfr;
        
        /* Process whatever's left, and any leadout or update stats if needed. */
        if (nfr)
            nfr = acmod_process_mfcbuf(acmod);
        else
            feat_update_stats(acmod->fcb);
    }
    if (acmod->mfcfh) {
        long outlen;
        int32 rv;
        outlen = (ftell(acmod->mfcfh) - 4) / 4;
        if (!WORDS_BIGENDIAN)
            SWAP_INT32(&outlen);
        /* Try to seek and write */
        if ((rv = fseek(acmod->mfcfh, 0, SEEK_SET)) == 0) {
            fwrite(&outlen, 4, 1, acmod->mfcfh);
        }
        fclose(acmod->mfcfh);
        acmod->mfcfh = NULL;
    }
    if (acmod->rawfh) {
        fclose(acmod->rawfh);
        acmod->rawfh = NULL;
    }

    if (acmod->senfh) {
        fclose(acmod->senfh);
        acmod->senfh = NULL;
    }

    return nfr;
}
예제 #5
0
파일: live2.c 프로젝트: wdebeaum/cabot
int
ld_utt_proc_raw_impl(live_decoder_t *decoder,
		     int16 *samples,
		     int32 num_samples,
		     int32 begin_utt,
		     int32 end_utt)
{
  float32 dummy_frame[MAX_CEP_LEN];
  float32 **frames = 0;
  int32 num_frames = 0;
  int32 num_features = 0;
	
  num_frames = fe_process_utt(decoder->fe, samples, num_samples, &frames);
	
  if (end_utt) {
    fe_end_utt(decoder->fe, dummy_frame);
  }
	
  if (num_frames > 0) {
    num_features = feat_s2mfc2feat_block(kbcore_fcb(decoder->kbcore),
					 frames,
					 num_frames,
					 begin_utt,
					 end_utt,
					 decoder->features);
  }
	
  if (num_features > 0) {
    utt_decode_block(decoder->features, 
		     num_features, 
		     &decoder->frame_num, 
		     &decoder->kb, 
		     decoder->max_wpf, 
		     decoder->max_histpf, 
		     decoder->max_hmmpf, 
		     decoder->phones_skip, 
		     decoder->hmm_log);
  }
	
  if (frames) {
    ckd_free_2d((void **)frames);
  }
	
  return 0;
}
예제 #6
0
void
segment_audio()
{
    FILE *file;
    int16 pcm_buf[BLOCKSIZE];
    mfcc_t **cep_buf;
    int16 voiced_buf = NULL;
    int32 voiced_nsamps, out_frameidx, uttstart = 0;
    char file_name[1024];
    uint8 cur_vad_state, vad_state, writing;
    int uttno, uttlen, sample_rate;
    int32 nframes, nframes_tmp;
    int16 frame_size, frame_shift, frame_rate;
    size_t k;

    sample_rate = (int) cmd_ln_float32_r(config, "-samprate");
    frame_rate = cmd_ln_int32_r(config, "-frate");
    frame_size =
        (int32) (cmd_ln_float32_r(config, "-wlen") * sample_rate + 0.5);
    frame_shift =
        (int32) (sample_rate / cmd_ln_int32_r(config, "-frate") + 0.5);
    nframes = (BLOCKSIZE - frame_size) / frame_shift;
    cep_buf =
        (mfcc_t **) ckd_calloc_2d(nframes, fe_get_output_size(fe),
                                  sizeof(mfcc_t));

    uttno = 0;
    uttlen = 0;
    cur_vad_state = 0;
    voiced_nsamps = 0;
    writing = 0;
    file = NULL;
    fe_start_stream(fe);
    fe_start_utt(fe);
    while ((k = read_audio(pcm_buf, BLOCKSIZE)) > 0) {
        int16 const *pcm_buf_tmp;
        pcm_buf_tmp = &pcm_buf[0];
        while (k) {
            nframes_tmp = nframes;
            fe_process_frames_ext(fe, &pcm_buf_tmp, &k, cep_buf,
                                  &nframes_tmp, voiced_buf,
                                  &voiced_nsamps, &out_frameidx);
            if (out_frameidx > 0) {
        	uttstart = out_frameidx;
            }
            vad_state = fe_get_vad_state(fe);
            if (!cur_vad_state && vad_state) {
                /* silence->speech transition, time to start new file */
                uttno++;
                if (!singlefile) {
                    sprintf(file_name, "%s%04d.raw", infile_path, uttno);
                    if ((file = fopen(file_name, "wb")) == NULL)
                          E_FATAL_SYSTEM("Failed to open '%s' for writing",
                                         file_name);
                } else {
                    sprintf(file_name, "%s.raw", infile_path);
                    if ((file = fopen(file_name, "ab")) == NULL)
                          E_FATAL_SYSTEM("Failed to open '%s' for writing",
                                         file_name);
		}
		writing = 1;
            }

            if (writing && file && voiced_nsamps > 0) {
                fwrite(voiced_buf, sizeof(int16), voiced_nsamps, file);
                uttlen += voiced_nsamps;
            }

            if (cur_vad_state && !vad_state) {
                /* speech -> silence transition, time to finish file */
                fclose(file);
	        printf("Utterance %04d: file %s start %.1f sec length %d samples ( %.2f sec )\n",
    		       uttno,
    		       file_name,
    	    	       ((double) uttstart) / frame_rate,
            	        uttlen,
            	       ((double) uttlen) / sample_rate);
                fflush(stdout);
                fe_end_utt(fe, cep_buf[0], &nframes_tmp);
                writing = 0;
                uttlen = 0;
                voiced_nsamps = 0;
                fe_start_utt(fe);
            }
            cur_vad_state = vad_state;
        }
    }

    if (writing) {
        fclose(file);
	printf("Utterance %04d: file %s start %.1f sec length %d samples ( %.2f sec )\n",
    	        uttno,
    		file_name,
    	    	((double) uttstart) / frame_rate,
            	uttlen,
                ((double) uttlen) / sample_rate);
        fflush(stdout);
    }
    fe_end_utt(fe, cep_buf[0], &nframes);
    ckd_free_2d(cep_buf);
}
예제 #7
0
int
ps_decoder_test(cmd_ln_t *config, char const *sname, char const *expected)
{
    ps_decoder_t *ps;
    mfcc_t **cepbuf;
    FILE *rawfh;
    int16 *buf;
    int16 const *bptr;
    size_t nread;
    size_t nsamps;
    int32 nfr, i, score, prob;
    char const *hyp;
    char const *uttid;
    double n_speech, n_cpu, n_wall;
    ps_seg_t *seg;

    TEST_ASSERT(ps = ps_init(config));
    /* Test it first with pocketsphinx_decode_raw() */
    TEST_ASSERT(rawfh = fopen(DATADIR "/goforward.raw", "rb"));
    ps_decode_raw(ps, rawfh, "goforward", -1);
    hyp = ps_get_hyp(ps, &score, &uttid);
    prob = ps_get_prob(ps, &uttid);
    printf("%s (%s): %s (%d, %d)\n", sname, uttid, hyp, score, prob);
    TEST_EQUAL(0, strcmp(hyp, expected));
    TEST_ASSERT(prob <= 0);
    ps_get_utt_time(ps, &n_speech, &n_cpu, &n_wall);
    printf("%.2f seconds speech, %.2f seconds CPU, %.2f seconds wall\n",
           n_speech, n_cpu, n_wall);
    printf("%.2f xRT (CPU), %.2f xRT (elapsed)\n",
           n_cpu / n_speech, n_wall / n_speech);

    /* Test it with ps_process_raw() */
    clearerr(rawfh);
    fseek(rawfh, 0, SEEK_END);
    nsamps = ftell(rawfh) / sizeof(*buf);
    fseek(rawfh, 0, SEEK_SET);
    TEST_EQUAL(0, ps_start_utt(ps, NULL));
    nsamps = 2048;
    buf = ckd_calloc(nsamps, sizeof(*buf));
    while (!feof(rawfh)) {
        nread = fread(buf, sizeof(*buf), nsamps, rawfh);
        ps_process_raw(ps, buf, nread, FALSE, FALSE);
    }
    TEST_EQUAL(0, ps_end_utt(ps));
    hyp = ps_get_hyp(ps, &score, &uttid);
    prob = ps_get_prob(ps, &uttid);
    printf("%s (%s): %s (%d, %d)\n", sname, uttid, hyp, score, prob);
    TEST_EQUAL(0, strcmp(uttid, "000000000"));
    TEST_EQUAL(0, strcmp(hyp, expected));
    ps_get_utt_time(ps, &n_speech, &n_cpu, &n_wall);
    printf("%.2f seconds speech, %.2f seconds CPU, %.2f seconds wall\n",
           n_speech, n_cpu, n_wall);
    printf("%.2f xRT (CPU), %.2f xRT (elapsed)\n",
           n_cpu / n_speech, n_wall / n_speech);

    /* Now read the whole file and produce an MFCC buffer. */
    clearerr(rawfh);
    fseek(rawfh, 0, SEEK_END);
    nsamps = ftell(rawfh) / sizeof(*buf);
    fseek(rawfh, 0, SEEK_SET);
    bptr = buf = ckd_realloc(buf, nsamps * sizeof(*buf));
    TEST_EQUAL(nsamps, fread(buf, sizeof(*buf), nsamps, rawfh));
    fe_process_frames(ps->acmod->fe, &bptr, &nsamps, NULL, &nfr);
    cepbuf = ckd_calloc_2d(nfr + 1,
                   fe_get_output_size(ps->acmod->fe),
                   sizeof(**cepbuf));
    fe_start_utt(ps->acmod->fe);
    fe_process_frames(ps->acmod->fe, &bptr, &nsamps, cepbuf, &nfr);
    fe_end_utt(ps->acmod->fe, cepbuf[nfr], &i);

    /* Decode it with process_cep() */
    TEST_EQUAL(0, ps_start_utt(ps, NULL));
    for (i = 0; i < nfr; ++i) {
        ps_process_cep(ps, cepbuf + i, 1, FALSE, FALSE);
    }
    TEST_EQUAL(0, ps_end_utt(ps));
    hyp = ps_get_hyp(ps, &score, &uttid);
    prob = ps_get_prob(ps, &uttid);
    printf("%s (%s): %s (%d, %d)\n", sname, uttid, hyp, score, prob);
    TEST_EQUAL(0, strcmp(uttid, "000000001"));
    TEST_EQUAL(0, strcmp(hyp, expected));
    TEST_ASSERT(prob <= 0);
    for (seg = ps_seg_iter(ps, &score); seg;
         seg = ps_seg_next(seg)) {
        char const *word;
        int sf, ef;
        int32 post, lscr, ascr, lback;

        word = ps_seg_word(seg);
        ps_seg_frames(seg, &sf, &ef);
        post = ps_seg_prob(seg, &ascr, &lscr, &lback);
        printf("%s (%d:%d) P(w|o) = %f ascr = %d lscr = %d lback = %d\n", word, sf, ef,
               logmath_exp(ps_get_logmath(ps), post), ascr, lscr, lback);
        TEST_ASSERT(post <= 2); // Due to numerical errors with float it sometimes could go out of 0
    }

    ps_get_utt_time(ps, &n_speech, &n_cpu, &n_wall);
    printf("%.2f seconds speech, %.2f seconds CPU, %.2f seconds wall\n",
           n_speech, n_cpu, n_wall);
    printf("%.2f xRT (CPU), %.2f xRT (elapsed)\n",
           n_cpu / n_speech, n_wall / n_speech);
    ps_get_all_time(ps, &n_speech, &n_cpu, &n_wall);
    printf("TOTAL: %.2f seconds speech, %.2f seconds CPU, %.2f seconds wall\n",
           n_speech, n_cpu, n_wall);
    printf("TOTAL: %.2f xRT (CPU), %.2f xRT (elapsed)\n",
           n_cpu / n_speech, n_wall / n_speech);

    fclose(rawfh);
    ps_free(ps);
    cmd_ln_free_r(config);
    ckd_free_2d(cepbuf);
    ckd_free(buf);

    return 0;
}
예제 #8
0
int
main(int argc, char *argv[])
{
    acmod_t *acmod;
    logmath_t *lmath;
    cmd_ln_t *config;
    FILE *rawfh;
    int16 *buf;
    int16 const *bptr;
    mfcc_t **cepbuf, **cptr;
    size_t nread, nsamps;
    int nfr;
    int frame_counter;
    int bestsen1[270];

    lmath = logmath_init(1.0001, 0, 0);
    config = cmd_ln_init(NULL, ps_args(), TRUE,
                 "-featparams", MODELDIR "/hmm/en_US/hub4wsj_sc_8k/feat.params",
                 "-mdef", MODELDIR "/hmm/en_US/hub4wsj_sc_8k/mdef",
                 "-mean", MODELDIR "/hmm/en_US/hub4wsj_sc_8k/means",
                 "-var", MODELDIR "/hmm/en_US/hub4wsj_sc_8k/variances",
                 "-tmat", MODELDIR "/hmm/en_US/hub4wsj_sc_8k/transition_matrices",
                 "-sendump", MODELDIR "/hmm/en_US/hub4wsj_sc_8k/sendump",
                 "-compallsen", "true",
                 "-cmn", "prior",
                 "-tmatfloor", "0.0001",
                 "-mixwfloor", "0.001",
                 "-varfloor", "0.0001",
                 "-mmap", "no",
                 "-topn", "4",
                 "-ds", "1",
                 "-input_endian", "little",
                 "-samprate", "16000", NULL);
    TEST_ASSERT(config);
    TEST_ASSERT(acmod = acmod_init(config, lmath, NULL, NULL));
    cmn_prior_set(acmod->fcb->cmn_struct, prior);

    nsamps = 2048;
    frame_counter = 0;
    buf = ckd_calloc(nsamps, sizeof(*buf));
    TEST_ASSERT(rawfh = fopen(DATADIR "/goforward.raw", "rb"));
    TEST_EQUAL(0, acmod_start_utt(acmod));
    E_INFO("Incremental(2048):\n");
    while (!feof(rawfh)) {
        nread = fread(buf, sizeof(*buf), nsamps, rawfh);
        bptr = buf;
        while ((nfr = acmod_process_raw(acmod, &bptr, &nread, FALSE)) > 0 || nread > 0) {
            int16 const *senscr;
            int16 best_score;
            int frame_idx = -1, best_senid;
            while (acmod->n_feat_frame > 0) {
                senscr = acmod_score(acmod, &frame_idx);
                acmod_advance(acmod);
                best_score = acmod_best_score(acmod, &best_senid);
                E_INFO("Frame %d best senone %d score %d\n",
                       frame_idx, best_senid, best_score);
                TEST_EQUAL(frame_counter, frame_idx);
                if (frame_counter < 190)
                    bestsen1[frame_counter] = best_score;
                ++frame_counter;
                frame_idx = -1;
            }
        }
    }
    TEST_EQUAL(0, acmod_end_utt(acmod));
    nread = 0;
    {
        int16 const *senscr;
        int16 best_score;
        int frame_idx = -1, best_senid;
        while (acmod->n_feat_frame > 0) {
            senscr = acmod_score(acmod, &frame_idx);
            acmod_advance(acmod);
            best_score = acmod_best_score(acmod, &best_senid);
            E_INFO("Frame %d best senone %d score %d\n",
                   frame_idx, best_senid, best_score);
            if (frame_counter < 190)
                bestsen1[frame_counter] = best_score;
            TEST_EQUAL(frame_counter, frame_idx);
            ++frame_counter;
            frame_idx = -1;
        }
    }

    /* Now try to process the whole thing at once. */
    E_INFO("Whole utterance:\n");
    cmn_prior_set(acmod->fcb->cmn_struct, prior);
    nsamps = ftell(rawfh) / sizeof(*buf);
    clearerr(rawfh);
    fseek(rawfh, 0, SEEK_SET);
    buf = ckd_realloc(buf, nsamps * sizeof(*buf));
    TEST_EQUAL(nsamps, fread(buf, sizeof(*buf), nsamps, rawfh));
    bptr = buf;
    TEST_EQUAL(0, acmod_start_utt(acmod));
    acmod_process_raw(acmod, &bptr, &nsamps, TRUE);
    TEST_EQUAL(0, acmod_end_utt(acmod));
    {
        int16 const *senscr;
        int16 best_score;
        int frame_idx = -1, best_senid;
        frame_counter = 0;
        while (acmod->n_feat_frame > 0) {
            senscr = acmod_score(acmod, &frame_idx);
            acmod_advance(acmod);
            best_score = acmod_best_score(acmod, &best_senid);
            E_INFO("Frame %d best senone %d score %d\n",
               frame_idx, best_senid, best_score);
            if (frame_counter < 190)
                TEST_EQUAL_LOG(best_score, bestsen1[frame_counter]);
            TEST_EQUAL(frame_counter, frame_idx);
            ++frame_counter;
            frame_idx = -1;
        }
    }

    /* Now process MFCCs and make sure we get the same results. */
    cepbuf = ckd_calloc_2d(frame_counter,
                   fe_get_output_size(acmod->fe),
                   sizeof(**cepbuf));
    fe_start_utt(acmod->fe);
    nsamps = ftell(rawfh) / sizeof(*buf);
    bptr = buf;
    nfr = frame_counter;
    fe_process_frames(acmod->fe, &bptr, &nsamps, cepbuf, &nfr);
    fe_end_utt(acmod->fe, cepbuf[frame_counter-1], &nfr);

    E_INFO("Incremental(MFCC):\n");
    cmn_prior_set(acmod->fcb->cmn_struct, prior);
    TEST_EQUAL(0, acmod_start_utt(acmod));
    cptr = cepbuf;
    nfr = frame_counter;
    frame_counter = 0;
    while ((acmod_process_cep(acmod, &cptr, &nfr, FALSE)) > 0) {
        int16 const *senscr;
        int16 best_score;
        int frame_idx = -1, best_senid;
        while (acmod->n_feat_frame > 0) {
            senscr = acmod_score(acmod, &frame_idx);
            acmod_advance(acmod);
            best_score = acmod_best_score(acmod, &best_senid);
            E_INFO("Frame %d best senone %d score %d\n",
                   frame_idx, best_senid, best_score);
            TEST_EQUAL(frame_counter, frame_idx);
            if (frame_counter < 190)
                TEST_EQUAL_LOG(best_score, bestsen1[frame_counter]);
            ++frame_counter;
            frame_idx = -1;
        }
    }
    TEST_EQUAL(0, acmod_end_utt(acmod));
    nfr = 0;
    acmod_process_cep(acmod, &cptr, &nfr, FALSE);
    {
        int16 const *senscr;
        int16 best_score;
        int frame_idx = -1, best_senid;
        while (acmod->n_feat_frame > 0) {
            senscr = acmod_score(acmod, &frame_idx);
            acmod_advance(acmod);
            best_score = acmod_best_score(acmod, &best_senid);
            E_INFO("Frame %d best senone %d score %d\n",
                   frame_idx, best_senid, best_score);
            TEST_EQUAL(frame_counter, frame_idx);
            if (frame_counter < 190)
                TEST_EQUAL_LOG(best_score, bestsen1[frame_counter]);
            ++frame_counter;
            frame_idx = -1;
        }
    }

    /* Note that we have to process the whole thing again because
     * !#@$@ s2mfc2feat modifies its argument (not for long) */
    fe_start_utt(acmod->fe);
    nsamps = ftell(rawfh) / sizeof(*buf);
    bptr = buf;
    nfr = frame_counter;
    fe_process_frames(acmod->fe, &bptr, &nsamps, cepbuf, &nfr);
    fe_end_utt(acmod->fe, cepbuf[frame_counter-1], &nfr);

    E_INFO("Whole utterance (MFCC):\n");
    cmn_prior_set(acmod->fcb->cmn_struct, prior);
    TEST_EQUAL(0, acmod_start_utt(acmod));
    cptr = cepbuf;
    nfr = frame_counter;
    acmod_process_cep(acmod, &cptr, &nfr, TRUE);
    TEST_EQUAL(0, acmod_end_utt(acmod));
    {
        int16 const *senscr;
        int16 best_score;
        int frame_idx = -1, best_senid;
        frame_counter = 0;
        while (acmod->n_feat_frame > 0) {
            senscr = acmod_score(acmod, &frame_idx);
            acmod_advance(acmod);
            best_score = acmod_best_score(acmod, &best_senid);
            E_INFO("Frame %d best senone %d score %d\n",
                   frame_idx, best_senid, best_score);
            if (frame_counter < 190)
                TEST_EQUAL_LOG(best_score, bestsen1[frame_counter]);
            TEST_EQUAL(frame_counter, frame_idx);
            ++frame_counter;
            frame_idx = -1;
        }
    }

    E_INFO("Rewound (MFCC):\n");
    TEST_EQUAL(0, acmod_rewind(acmod));
    {
        int16 const *senscr;
        int16 best_score;
        int frame_idx = -1, best_senid;
        frame_counter = 0;
        while (acmod->n_feat_frame > 0) {
            senscr = acmod_score(acmod, &frame_idx);
            acmod_advance(acmod);
            best_score = acmod_best_score(acmod, &best_senid);
            E_INFO("Frame %d best senone %d score %d\n",
                   frame_idx, best_senid, best_score);
            if (frame_counter < 190)
                TEST_EQUAL_LOG(best_score, bestsen1[frame_counter]);
            TEST_EQUAL(frame_counter, frame_idx);
            ++frame_counter;
            frame_idx = -1;
        }
    }

    /* Clean up, go home. */
    ckd_free_2d(cepbuf);
    fclose(rawfh);
    ckd_free(buf);
    acmod_free(acmod);
    logmath_free(lmath);
    cmd_ln_free_r(config);
    return 0;
}
예제 #9
0
파일: test_fe.c 프로젝트: 006/ios_lab
int
main(int argc, char *argv[])
{
	static const arg_t fe_args[] = {
		waveform_to_cepstral_command_line_macro(),
		{ NULL, 0, NULL, NULL }
	};
	FILE *raw;
	cmd_ln_t *config;
	fe_t *fe;
	int16 buf[1024];
	int16 const *inptr;
	int32 frame_shift, frame_size;
	mfcc_t **cepbuf1, **cepbuf2, **cptr;
	int32 nfr, i;
	size_t nsamp;

	TEST_ASSERT(config = cmd_ln_parse_r(NULL, fe_args, argc, argv, FALSE));
	TEST_ASSERT(fe = fe_init_auto_r(config));

	TEST_EQUAL(fe_get_output_size(fe), DEFAULT_NUM_CEPSTRA);

	fe_get_input_size(fe, &frame_shift, &frame_size);
	TEST_EQUAL(frame_shift, DEFAULT_FRAME_SHIFT);
	TEST_EQUAL(frame_size, (int)(DEFAULT_WINDOW_LENGTH*DEFAULT_SAMPLING_RATE));

	TEST_ASSERT(raw = fopen(TESTDATADIR "/chan3.raw", "rb"));

	TEST_EQUAL(0, fe_start_utt(fe));
	TEST_EQUAL(1024, fread(buf, sizeof(int16), 1024, raw));

	nsamp = 1024;
	TEST_ASSERT(fe_process_frames(fe, NULL, &nsamp, NULL, &nfr) >= 0);
	TEST_EQUAL(1024, nsamp);
	TEST_EQUAL(4, nfr);

	cepbuf1 = ckd_calloc_2d(5, DEFAULT_NUM_CEPSTRA, sizeof(**cepbuf1));
	inptr = &buf[0];
	nfr = 1;

	printf("frame_size %d frame_shift %d\n", frame_size, frame_shift);
	/* Process the first frame. */
	TEST_ASSERT(fe_process_frames(fe, &inptr, &nsamp, &cepbuf1[0], &nfr) >= 0);
	printf("inptr %d nsamp %d nfr %d\n", inptr - buf, nsamp, nfr);
	TEST_EQUAL(nfr, 1);

	/* Note that this next one won't actually consume any frames
	 * of input, because it already got sufficient overflow
	 * samples last time around.  This is implementation-dependent
	 * so we shouldn't actually test for it. */
	TEST_ASSERT(fe_process_frames(fe, &inptr, &nsamp, &cepbuf1[1], &nfr) >= 0);
	printf("inptr %d nsamp %d nfr %d\n", inptr - buf, nsamp, nfr);
	TEST_EQUAL(nfr, 1);

	TEST_ASSERT(fe_process_frames(fe, &inptr, &nsamp, &cepbuf1[2], &nfr) >= 0);
	printf("inptr %d nsamp %d nfr %d\n", inptr - buf, nsamp, nfr);
	TEST_EQUAL(nfr, 1);

	TEST_ASSERT(fe_process_frames(fe, &inptr, &nsamp, &cepbuf1[3], &nfr) >= 0);
	printf("inptr %d nsamp %d nfr %d\n", inptr - buf, nsamp, nfr);
	TEST_EQUAL(nfr, 1);

	TEST_ASSERT(fe_end_utt(fe, cepbuf1[4], &nfr) >= 0);
	printf("nfr %d\n", nfr);
	TEST_EQUAL(nfr, 1);

	/* What we *should* test is that the output we get by
	 * processing one frame at a time is exactly the same as what
	 * we get from doing them all at once.  So let's do that */
	cepbuf2 = ckd_calloc_2d(5, DEFAULT_NUM_CEPSTRA, sizeof(**cepbuf2));
	inptr = &buf[0];
	nfr = 5;
	nsamp = 1024;
	TEST_EQUAL(0, fe_start_utt(fe));
	TEST_ASSERT(fe_process_frames(fe, &inptr, &nsamp, cepbuf2, &nfr) >= 0);
	printf("nfr %d\n", nfr);
	TEST_EQUAL(nfr, 4);
	nfr = 1;
	TEST_ASSERT(fe_end_utt(fe, cepbuf2[4], &nfr) >= 0);
	printf("nfr %d\n", nfr);
	TEST_EQUAL(nfr, 1);

	for (i = 0; i < 5; ++i) {
		int j;
		printf("%d: ", i);
		for (j = 0; j < DEFAULT_NUM_CEPSTRA; ++j) {
			printf("%.2f,%.2f ",
			       MFCC2FLOAT(cepbuf1[i][j]),
			       MFCC2FLOAT(cepbuf2[i][j]));
			TEST_EQUAL_FLOAT(cepbuf1[i][j], cepbuf2[i][j]);
		}
		printf("\n");
	}

	/* Now, also test to make sure that even if we feed data in
	 * little tiny bits we can still make things work. */
	memset(cepbuf2[0], 0, 5 * DEFAULT_NUM_CEPSTRA * sizeof(**cepbuf2));
	inptr = &buf[0];
	cptr = &cepbuf2[0];
	nfr = 5;
	i = 5;
	nsamp = 256;
	TEST_EQUAL(0, fe_start_utt(fe));
	TEST_ASSERT(fe_process_frames(fe, &inptr, &nsamp, cptr, &i) >= 0);
	printf("inptr %d nsamp %d nfr %d\n", inptr - buf, nsamp, i);
	cptr += i;
	nfr -= i;
	i = nfr;
	nsamp = 256;
	TEST_ASSERT(fe_process_frames(fe, &inptr, &nsamp, cptr, &i) >= 0);
	printf("inptr %d nsamp %d nfr %d\n", inptr - buf, nsamp, i);
	cptr += i;
	nfr -= i;
	i = nfr;
	nsamp = 256;
	TEST_ASSERT(fe_process_frames(fe, &inptr, &nsamp, cptr, &i) >= 0);
	printf("inptr %d nsamp %d nfr %d\n", inptr - buf, nsamp, i);
	cptr += i;
	nfr -= i;
	i = nfr;
	nsamp = 256;
	TEST_ASSERT(fe_process_frames(fe, &inptr, &nsamp, cptr, &i) >= 0);
	printf("inptr %d nsamp %d nfr %d\n", inptr - buf, nsamp, i);
	cptr += i;
	nfr -= i;
	TEST_ASSERT(fe_end_utt(fe, *cptr, &nfr) >= 0);
	printf("nfr %d\n", nfr);
	TEST_EQUAL(nfr, 1);

	for (i = 0; i < 5; ++i) {
		int j;
		printf("%d: ", i);
		for (j = 0; j < DEFAULT_NUM_CEPSTRA; ++j) {
			printf("%.2f,%.2f ",
			       MFCC2FLOAT(cepbuf1[i][j]),
			       MFCC2FLOAT(cepbuf2[i][j]));
			TEST_EQUAL_FLOAT(cepbuf1[i][j], cepbuf2[i][j]);
		}
		printf("\n");
	}

	/* And now, finally, test fe_process_utt() */
	inptr = &buf[0];
	i = 0;
	TEST_EQUAL(0, fe_start_utt(fe));
	TEST_ASSERT(fe_process_utt(fe, inptr, 256, &cptr, &nfr) >= 0);
	printf("i %d nfr %d\n", i, nfr);
	if (nfr)
		memcpy(cepbuf2[i], cptr[0], nfr * DEFAULT_NUM_CEPSTRA * sizeof(**cptr));
	ckd_free_2d(cptr);
	i += nfr;
	inptr += 256;
	TEST_ASSERT(fe_process_utt(fe, inptr, 256, &cptr, &nfr) >= 0);
	printf("i %d nfr %d\n", i, nfr);
	if (nfr)
		memcpy(cepbuf2[i], cptr[0], nfr * DEFAULT_NUM_CEPSTRA * sizeof(**cptr));
	ckd_free_2d(cptr);
	i += nfr;
	inptr += 256;
	TEST_ASSERT(fe_process_utt(fe, inptr, 256, &cptr, &nfr) >= 0);
	printf("i %d nfr %d\n", i, nfr);
	if (nfr)
		memcpy(cepbuf2[i], cptr[0], nfr * DEFAULT_NUM_CEPSTRA * sizeof(**cptr));
	ckd_free_2d(cptr);
	i += nfr;
	inptr += 256;
	TEST_ASSERT(fe_process_utt(fe, inptr, 256, &cptr, &nfr) >= 0);
	printf("i %d nfr %d\n", i, nfr);
	if (nfr)
		memcpy(cepbuf2[i], cptr[0], nfr * DEFAULT_NUM_CEPSTRA * sizeof(**cptr));
	ckd_free_2d(cptr);
	i += nfr;
	inptr += 256;
	TEST_ASSERT(fe_end_utt(fe, cepbuf2[i], &nfr) >= 0);
	printf("i %d nfr %d\n", i, nfr);
	TEST_EQUAL(nfr, 1);

	for (i = 0; i < 5; ++i) {
		int j;
		printf("%d: ", i);
		for (j = 0; j < DEFAULT_NUM_CEPSTRA; ++j) {
			printf("%.2f,%.2f ",
			       MFCC2FLOAT(cepbuf1[i][j]),
			       MFCC2FLOAT(cepbuf2[i][j]));
			TEST_EQUAL_FLOAT(cepbuf1[i][j], cepbuf2[i][j]);
		}
		printf("\n");
	}

	ckd_free_2d(cepbuf1);
	ckd_free_2d(cepbuf2);
	fclose(raw);
	fe_free(fe);

	return 0;
}
int32 live_utt_decode_block (int16 *samples, int32 nsamples, 
		      int32 live_endutt, partialhyp_t **ohyp)
{
    static int32 live_begin_new_utt = 1;
    static int32 frmno;
    float32 **live_feat;
    int32   live_nfr, live_nfeatvec;
    int32   nwds;
    /* int32   id;  */  /* unreferenced variable */
    /* glist_t hyp;  */  /* unreferenced variable */
    /* gnode_t *gn;  */  /* unreferenced variable */
    /* hyp_t   *h;  */  /* unreferenced variable */
    /* dict_t  *dict;  */  /* unreferenced variable */
    float32 **mfcbuf;

    if (live_begin_new_utt){
        fe_start_utt(fe);
	utt_begin (kb);
	frmno = 0;
	kb->nfr = 0;
        kb->utt_hmm_eval = 0;
        kb->utt_sen_eval = 0;
        kb->utt_gau_eval = 0;
        live_begin_new_utt = 0;
    }

    sample_blk++;

    /* 10.jan.01 RAH, fe_process_utt now requires ***mfcbuf and it allocates the memory internally) */
    mfcbuf = NULL;

    live_nfr = fe_process_utt(fe, samples, nsamples, &mfcbuf); /*  */
    if (live_endutt) 		/* RAH, It seems that we shouldn't throw out this data */
        fe_end_utt(fe,dummyframe); /* Flush out the fe */

    /* Compute feature vectors */
    live_nfeatvec = feat_s2mfc2feat_block(kbcore_fcb(kbcore), mfcbuf,
                                         live_nfr, live_begin_new_utt,
					 live_endutt, &live_feat);
    E_INFO ("live_nfeatvec: %ld\n",live_nfeatvec);


    /* decode the block */
    if (sample_blk<=START_BLOCK) 
      single_utt_decode_block (live_feat, live_nfeatvec, &frmno, kb, 
			       maxwpf, maxhistpf, maxhmmpf, ptranskip, hmmdumpfp);
    else 
      utt_decode_block (live_feat, live_nfeatvec, &frmno, kb, 
			maxwpf, maxhistpf, maxhmmpf, ptranskip, hmmdumpfp);

    /* Pull out partial hypothesis */
    nwds =  live_get_partialhyp(live_endutt);
    *ohyp = parthyp;

    /* Clean up */
    if (live_endutt) {
	live_begin_new_utt = 1;
	kb->tot_fr += kb->nfr;
	utt_end(kb);
    }
    else {
	live_begin_new_utt = 0;
    }

    /* I'm starting to think that fe_process_utt should not be allocating its memory,
       that or it should allocate some max and just keep on going, this idea of constantly allocating freeing
       memory seems dangerous to me.*/
    ckd_free_2d((void **) mfcbuf); /* RAH, this must be freed since fe_process_utt allocates it */


    return(nwds);
}
예제 #11
0
파일: live.c 프로젝트: wdebeaum/cabot
int32 live_utt_decode_block (int16 *samples, int32 nsamples, 
			     int32 live_endutt, partialhyp_t **ohyp)
{
    static int32 live_begin_new_utt = 1;
    static int32 frmno;
    static float32 ***live_feat = NULL;
    
    int32   live_nfr, live_nfeatvec;
    int32   nwds =0;
    float32 **mfcbuf;
    /*    int i,j;*/
    /* 2004/08/27 L Galescu <*****@*****.**> -- added raw audio file saving */
    static char uttfn[1024];
    static FILE *rawfp = NULL;
    int16 block_peak_amplitude;

    if(live_feat==NULL)
        live_feat = feat_array_alloc (kbcore_fcb(kbcore), LIVEBUFBLOCKSIZE);
    
    if (live_begin_new_utt){
        fe_start_utt(fe);
        utt_begin (kb);
        frmno = 0;
        kb->nfr = 0;
        kb->utt_hmm_eval = 0;
        kb->utt_sen_eval = 0;
        kb->utt_gau_eval = 0;
        live_begin_new_utt = 0;
        sprintf(uttfn, "%s/%s.raw", cmd_ln_str("-outrawdir"), kb->uttid);
        rawfp = fopen(uttfn, "wb");
    }
    /* 10.jan.01 RAH, fe_process_utt now requires ***mfcbuf and it allocates the memory internally) */
    mfcbuf = NULL;

    /* LG 20080613 */
    block_peak_amplitude = get_peak_amplitude(samples, nsamples);
    if (block_peak_amplitude > peak_amplitude)
      peak_amplitude = block_peak_amplitude;
    E_INFO("segment peak %d\n",peak_amplitude);

    live_nfr = fe_process_utt(fe, samples, nsamples, &mfcbuf); /**/
    if (rawfp != NULL) {
      fwrite(samples, sizeof(int16), nsamples, rawfp);
      if (live_endutt)
	  fclose(rawfp);
    }

    if (live_endutt) {
        /* RAH, It seems that we shouldn't throw out this data */
        fe_end_utt(fe,dummyframe); /* Flush out the fe */
    }
#if 0
    E_INFO("Number frame after fe_process_utt %d\n",live_nfr);
    for(i=0;i<live_nfr;i++){
      printf("%d ",i);
      for(j=0;j<13;j++){
        printf("%f ",mfcbuf[i][j]);
        fflush(stdout);
      }
      printf("\n");
      fflush(stdout);
    }
#endif
    /* lgalescu 2004/08/22 -- i am under the impression that 
     * feat_s2mfc2feat_block() needs to be called at the end of utt 
     * even if no frames need processing
     */
    /* lgalescu 2004/10/13 -- rescinded the above */
    if(live_nfr>0){
      /* Compute feature vectors */
      live_nfeatvec = feat_s2mfc2feat_block(kbcore_fcb(kbcore), mfcbuf,
					    live_nfr, live_begin_new_utt,
					    live_endutt, live_feat);

#if 0   
    E_INFO ("live_nfeatvec: %ld\n",live_nfeatvec);
#endif
#if 0
      E_INFO("Current frame number %d, Number of frames %d, Number frame after feat_s2mfcfeat_block %d\n",frmno,live_nfr,live_nfeatvec);
      
      for(i=0;i<live_nfeatvec;i++){
        printf("%d\n",i);
        printf("Cep: ");
        fflush(stdout);
        for(j=0;j<13;j++){
	  printf("%f ",live_feat[i][0][j]);
	  fflush(stdout);
        }
        printf("\n");
        fflush(stdout);
        printf("Del: ");
        fflush(stdout);
        for(j=13;j<26;j++){
	  printf("%f ",live_feat[i][0][j]);
	  fflush(stdout); 
        }
        printf("\n");
        fflush(stdout);
        printf("Acc: ");
        fflush(stdout);
        for(j=26;j<39;j++){
	  printf("%f ",live_feat[i][0][j]);
	  fflush(stdout);
        }
        printf("\n");
        fflush(stdout);
        
      }
#endif
    
      /* decode the block */
      utt_decode_block (live_feat, live_nfeatvec, &frmno, kb, 
			maxwpf, maxhistpf, maxhmmpf, ptranskip, hmmdumpfp);

      /* lgalescu 2004/08/21
       * moved the following block out of the previous if(){} because we need 
       * the output even when no feature computation has to be done.
       */
      /* lgalescu 2004/10/13 -- rescinded */

      /* Pull out partial hypothesis */
      nwds =  live_get_partialhyp(live_endutt);
      *ohyp = parthyp;
      parthyplen = nwds;
    }

    /* Clean up */
    if (live_endutt) {
      live_begin_new_utt = 1;
      kb->tot_fr += kb->nfr;
      utt_end(kb);
    }
    else {
      live_begin_new_utt = 0;
    }
    
    /* I'm starting to think that fe_process_utt should not be allocating its 
     * memory, that or it should allocate some max and just keep on going, 
     * this idea of constantly allocating freeing memory seems dangerous to me.
     */
    /* 20040318 ARCHAN : It sounds extremely dangerous to me and I will 
     * eliminate it sometime. 
     */
    /* lgalescu: i second that! the memory issue needs to be investigated: after a run on linux, i noticed some 1.6M of memory having "disappeared"! */

    if(live_nfr>0){
      ckd_free_2d((void **) mfcbuf); /* RAH, this must be freed since fe_process_utt allocates it */
    }

    return(parthyplen);
}
예제 #12
0
void
ld_process_raw_impl(live_decoder_t * _decoder,
                    int16 * samples, int32 num_samples, int32 end_utt)
{
    float32 dummy_frame[MAX_CEP_LEN];
    float32 **frames = 0;
    int32 num_frames = 0;
    int32 num_features = 0;
    int32 begin_utt = _decoder->num_frames_entered == 0;
    int32 return_value;
    int i;

    assert(_decoder != NULL);

    if (begin_utt) {
        fe_start_utt(_decoder->fe);
    }

    if (_decoder->swap) {
        for (i = 0; i < num_samples; i++) {
            SWAP_INT16(samples + i);
        }
    }

    return_value =
        fe_process_utt(_decoder->fe, samples, num_samples, &frames,
                       &num_frames);

    if (end_utt) {
        return_value = fe_end_utt(_decoder->fe, dummy_frame, &num_frames);
        if (num_frames != 0) {
            /* ARCHAN: If num_frames !=0, assign this last ending frame to
               frames again.  The computation will then be correct.  Should
               clean up the finite state logic in fe_interface layer. 
             */
            frames =
                (float32 **) ckd_calloc_2d(1, _decoder->fe->NUM_CEPSTRA,
                                           sizeof(float32));
            memcpy(frames[0], dummy_frame,
                   _decoder->fe->NUM_CEPSTRA * sizeof(float32));
        }
    }

    if (FE_ZERO_ENERGY_ERROR == return_value) {
        E_WARN("Zero energy frame(s). Consider using dither\n");
    }

    if (num_frames > 0) {
        num_features = feat_s2mfc2feat_block(kbcore_fcb(_decoder->kbcore),
                                             frames,
                                             num_frames,
                                             begin_utt,
                                             end_utt, _decoder->features);
        _decoder->num_frames_entered += num_frames;
    }

    if (num_features > 0) {
        utt_decode_block(_decoder->features,
                         num_features,
                         &_decoder->num_frames_decoded, &_decoder->kb);
    }

    if (frames != NULL) {
        ckd_free_2d((void **) frames);
    }
}
예제 #13
0
int main (int32 argc, char *argv[])
{
    char line[4096], filename[4096], idspec[4096], *uttid, *result;
    int32 sf, ef, sps, adcin, nf;
    int16 adbuf[4096];
    int32 i, k;
    float32 **mfcbuf;
    CDCN_type *cdcn;
    param_t param;
    fe_t *fe = NULL;


    fbs_init (argc, argv);
    /* Assume that cdcn_init is part of the above fbs_init() */
    cdcn = uttproc_get_cdcn_ptr();

    adcin = query_adc_input();
    assert (adcin);	/* Limited to processing audio input files (not cep) */
    sps = query_sampling_rate();

    fe_init_params(&param);
    param.SAMPLING_RATE = (float)sps;

    if ((fe = fe_init (&param)) == NULL)
    {
        E_ERROR("fe_init() failed to initialize\n");
        exit (-1);
    }
    mfcbuf = (float32 **) ckd_calloc_2d (8192, 13, sizeof(float32));

    /* Process "control file" input through stdin */
    while (fgets (line, sizeof(line), stdin) != NULL) {
        if (uttproc_parse_ctlfile_entry (line, filename, &sf, &ef, idspec) < 0)
            continue;
        assert ((sf < 0) && (ef < 0));	/* Processing entire input file */

        uttid = build_uttid (idspec);

        uttproc_begin_utt (uttid);

        /* Convert raw data file to cepstra */
        if (uttfile_open (filename) < 0) {
            E_ERROR("uttfile_open(%s) failed\n", filename);
            continue;
        }
        fe_start_utt(fe);
        nf = 0;
        while ((k = adc_file_read (adbuf, 4096)) >= 0) {
            if (fe_process_utt (fe, adbuf, k, mfcbuf+nf, &k) == FE_ZERO_ENERGY_ERROR) {
                E_WARN("Frames with zero energy. Consider using dither\n");
            }
            nf += k;
            /* WARNING!! No check for mfcbuf overflow */
        }
        fe_end_utt(fe, mfcbuf[nf], &k);
        fe_close(fe);
        uttfile_close ();

        if (nf <= 0) {
            E_ERROR("Empty utterance\n");
            continue;
        } else
            E_INFO("%d frames\n", nf);

        /* Update CDCN module */
        cdcn_converged_update (mfcbuf, /* cepstra buffer */
                               nf, /* Number of frames */
                               cdcn, /* The CDCN wrapper */
                               1 /* One iteration */
                              );

        /* CDCN */
        for (i = 0; i < nf; i++)
            cdcn_norm (mfcbuf[i], cdcn);

        /* Process normalized cepstra */
        uttproc_cepdata (mfcbuf, nf, 1);
        uttproc_end_utt ();
        uttproc_result (&k, &result, 1);
        printf ("\n");
        fflush (stdout);

    }

    ckd_free_2d((void **)mfcbuf);

    fbs_end ();
    return 0;
}