int main(int argc, char *argv[]) { cmd_ln_t *config; ps_decoder_t *ps; FILE *rawfh; char const *hyp; char const *uttid; int32 score; TEST_ASSERT(config = cmd_ln_init(NULL, ps_args(), TRUE, "-hmm", DATADIR "/an4_ci_cont", "-lm", MODELDIR "/lm/en/turtle.DMP", "-dict", MODELDIR "/lm/en/turtle.dic", "-mllr", DATADIR "/mllr_matrices", "-samprate", "16000", NULL)); TEST_ASSERT(ps = ps_init(config)); TEST_ASSERT(rawfh = fopen(DATADIR "/goforward.raw", "rb")); ps_decode_raw(ps, rawfh, "goforward", -1); fclose(rawfh); hyp = ps_get_hyp(ps, &score, &uttid); printf("FWDFLAT (%s): %s (%d)\n", uttid, hyp, score); ps_free(ps); cmd_ln_free_r(config); return 0; }
std::tuple<std::string, double> TwitchStreamChunk::process(std::string body){ int pos = _uri.find_last_of('/'); std::string fileName = _uri.substr(pos + 1); std::ofstream file(fileName); file << body; file.flush(); file.close(); std::stringstream cmd; std::string audioFile = boost::filesystem::unique_path().native(); audioFile.append(".wav"); cmd << "ffmpeg -i " << fileName << " -vn -ac 1 " << audioFile << " > /dev/null 2>&1"; system(cmd.str().c_str()); FILE *aFile = fopen(audioFile.c_str(), "r"); ps_decode_raw(getDecoder(), aFile, -1); fclose(aFile); auto logarithm = ps_get_logmath(getDecoder()); int confidence = 1; const char * result = ps_get_hyp(getDecoder(), &confidence); double tmp = logmath_exp(logarithm, confidence); std::remove(fileName.c_str()); std::remove(audioFile.c_str()); return std::make_tuple(result == nullptr ? "" : std::string(result), tmp); }
int main(int argc, char *argv[]) { ps_decoder_t *ps; cmd_ln_t *config; FILE *fh; char const *hyp, *uttid; int16 buf[512]; int rv; int32 score; //int i; config = cmd_ln_init(NULL, ps_args(), TRUE, "-hmm", MODELDIR "/hmm/en_US/hub4wsj_sc_8k", "-lm", MODELDIR "/lm/en/turtle.DMP", "-dict", MODELDIR "/lm/en/turtle.dic", NULL); if (config == NULL) return 1; ps = ps_init(config); if (ps == NULL) return 1; fh = fopen("goforward.raw", "rb"); if (fh == NULL) { perror("Failed to open goforward.raw"); return 1; } rv = ps_decode_raw(ps, fh, "goforward", -1); if (rv < 0) return 1; hyp = ps_get_hyp(ps, &score, &uttid); if (hyp == NULL) return 1; printf("Recognized: %s\n", hyp); fseek(fh, 0, SEEK_SET); rv = ps_start_utt(ps, "goforward"); if (rv < 0) return 1; while (!feof(fh)) { size_t nsamp; nsamp = fread(buf, 2, 512, fh); rv = ps_process_raw(ps, buf, nsamp, FALSE, FALSE); } rv = ps_end_utt(ps); if (rv < 0) return 1; hyp = ps_get_hyp(ps, &score, &uttid); if (hyp == NULL) return 1; printf("Recognized: %s\n", hyp); fclose(fh); ps_free(ps); return 0; }
int main(int argc, char *argv[]) { ps_decoder_t *ps; cmd_ln_t *config; FILE *fh; const char *filename = "goforward.raw"; const char *word = "goforward"; char const *hyp, *uttid; int rv; int32 score; /* setup the sphinx config */ config = cmd_ln_init(NULL, ps_args(), TRUE, "-hmm", MODELDIR "/hmm/en_US/hub4wsj_sc_8k", "-lm", MODELDIR "/lm/en/turtle.DMP", "-dict", MODELDIR "/lm/en/turtle.dic", NULL); if(config == NULL) { EXIT_ERROR; } /* initialize the config */ ps = ps_init(config); if(ps == NULL) { EXIT_ERROR; } /* open the audio file (stream?) */ fh = fopen(filename, "rb"); if(fh == NULL) { perror(filename); exit(1); } /* decode the file */ rv = ps_decode_raw(ps, fh, word, -1); if(rv < 0) { EXIT_ERROR; } /* get hypothesis */ hyp = ps_get_hyp(ps, &score, &uttid); if(hyp == NULL) { EXIT_ERROR; } printf("Recognized: %s; score: %d; uttid: %s\n", hyp, score, uttid); /* clean up */ fclose(fh); ps_free(ps); return 0; }
int main(int argc, char *argv[]) { ps_decoder_t *ps; ps_nbest_t *nbest; cmd_ln_t *config; FILE *rawfh; char const *hyp; int32 score, n; TEST_ASSERT(config = cmd_ln_init(NULL, ps_args(), TRUE, "-hmm", MODELDIR "/en-us/en-us", "-lm", MODELDIR "/en-us/en-us.lm.bin", "-dict", MODELDIR "/en-us/cmudict-en-us.dict", "-fwdtree", "yes", "-fwdflat", "yes", "-bestpath", "yes", "-input_endian", "little", "-samprate", "16000", NULL)); TEST_ASSERT(ps = ps_init(config)); TEST_ASSERT(rawfh = fopen(DATADIR "/goforward.raw", "rb")); ps_decode_raw(ps, rawfh, -1); fclose(rawfh); hyp = ps_get_hyp(ps, &score); printf("BESTPATH: %s (%d)\n", hyp, score); for (n = 1, nbest = ps_nbest(ps); nbest && n < 10; nbest = ps_nbest_next(nbest), n++) { ps_seg_t *seg; hyp = ps_nbest_hyp(nbest, &score); printf("NBEST %d: %s (%d)\n", n, hyp, score); for (seg = ps_nbest_seg(nbest); seg; seg = ps_seg_next(seg)) { char const *word; int sf, ef; word = ps_seg_word(seg); ps_seg_frames(seg, &sf, &ef); printf("%s %d %d\n", word, sf, ef); } } if (nbest) ps_nbest_free(nbest); ps_free(ps); cmd_ln_free_r(config); return 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; }
static int process_ctl_line(ps_decoder_t *ps, cmd_ln_t *config, char const *file, char const *uttid, int32 sf, int32 ef) { FILE *infh; char const *cepdir, *cepext; char *infile; if (ef != -1 && ef < sf) { E_ERROR("End frame %d is < start frame %d\n", ef, sf); return -1; } cepdir = cmd_ln_str_r(config, "-cepdir"); cepext = cmd_ln_str_r(config, "-cepext"); /* Build input filename. */ infile = string_join(cepdir ? cepdir : "", "/", file, cepext ? cepext : "", NULL); if (uttid == NULL) uttid = file; if ((infh = fopen(infile, "rb")) == NULL) { E_ERROR_SYSTEM("Failed to open %s", infile); ckd_free(infile); return -1; } /* Build output directories. */ if (cmd_ln_boolean_r(config, "-build_outdirs")) build_outdirs(config, uttid); if (cmd_ln_boolean_r(config, "-senin")) { /* start and end frames not supported. */ ps_decode_senscr(ps, infh, uttid); } else if (cmd_ln_boolean_r(config, "-adcin")) { if (ef != -1) { ef = (int32)((ef - sf) * (cmd_ln_float32_r(config, "-samprate") / cmd_ln_int32_r(config, "-frate")) + (cmd_ln_float32_r(config, "-samprate") * cmd_ln_float32_r(config, "-wlen"))); } sf = (int32)(sf * (cmd_ln_float32_r(config, "-samprate") / cmd_ln_int32_r(config, "-frate"))); fseek(infh, cmd_ln_int32_r(config, "-adchdr") + sf * sizeof(int16), SEEK_SET); ps_decode_raw(ps, infh, uttid, ef); } else { mfcc_t **mfcs; int nfr; if (NULL == (mfcs = read_mfc_file(infh, sf, ef, &nfr, cmd_ln_int32_r(config, "-ceplen")))) { E_ERROR("Failed to read MFCC from the file '%s'\n", infile); fclose(infh); ckd_free(infile); return -1; } ps_start_utt(ps, uttid); ps_process_cep(ps, mfcs, nfr, FALSE, TRUE); ps_end_utt(ps); ckd_free_2d(mfcs); } fclose(infh); ckd_free(infile); return 0; }
int main(int argc, char *argv[]) { ps_decoder_t *ps; cmd_ln_t *config; acmod_t *acmod; fsg_search_t *fsgs; jsgf_t *jsgf; jsgf_rule_t *rule; fsg_model_t *fsg; ps_seg_t *seg; ps_lattice_t *dag; FILE *rawfh; char const *hyp, *uttid; int32 score, prob; clock_t c; int i; TEST_ASSERT(config = cmd_ln_init(NULL, ps_args(), TRUE, "-hmm", MODELDIR "/hmm/en_US/hub4wsj_sc_8k", "-dict", MODELDIR "/lm/en/turtle.dic", "-input_endian", "little", "-samprate", "16000", NULL)); TEST_ASSERT(ps = ps_init(config)); jsgf = jsgf_parse_file(DATADIR "/goforward.gram", NULL); TEST_ASSERT(jsgf); rule = jsgf_get_rule(jsgf, "<goforward.move2>"); TEST_ASSERT(rule); fsg = jsgf_build_fsg(jsgf, rule, ps->lmath, 7.5); TEST_ASSERT(fsg); fsg_model_write(fsg, stdout); ps_set_fsg(ps, "<goforward.move2>", fsg); ps_set_search(ps, "<goforward.move2>"); acmod = ps->acmod; fsgs = (fsg_search_t *) fsg_search_init(fsg, config, acmod, ps->dict, ps->d2p); setbuf(stdout, NULL); c = clock(); for (i = 0; i < 5; ++i) { int16 buf[2048]; size_t nread; int16 const *bptr; int nfr; int is_final; TEST_ASSERT(rawfh = fopen(DATADIR "/goforward.raw", "rb")); TEST_EQUAL(0, acmod_start_utt(acmod)); fsg_search_start(ps_search_base(fsgs)); is_final = FALSE; while (!feof(rawfh)) { nread = fread(buf, sizeof(*buf), 2048, rawfh); bptr = buf; while ((nfr = acmod_process_raw(acmod, &bptr, &nread, FALSE)) > 0) { while (acmod->n_feat_frame > 0) { fsg_search_step(ps_search_base(fsgs), acmod->output_frame); acmod_advance(acmod); } } hyp = fsg_search_hyp(ps_search_base(fsgs), &score, &is_final); printf("FSG: %s (%d) frame %d final %s\n", hyp, score, acmod->output_frame, is_final ? "FINAL" : ""); TEST_EQUAL (is_final, (acmod->output_frame > 170)); } fsg_search_finish(ps_search_base(fsgs)); hyp = fsg_search_hyp(ps_search_base(fsgs), &score, NULL); printf("FSG: %s (%d)\n", hyp, score); TEST_ASSERT(acmod_end_utt(acmod) >= 0); fclose(rawfh); } TEST_EQUAL(0, strcmp("go forward ten meters", fsg_search_hyp(ps_search_base(fsgs), &score, NULL))); ps->search = (ps_search_t *)fsgs; for (seg = ps_seg_iter(ps, &score); seg; seg = ps_seg_next(seg)) { char const *word; int sf, ef; word = ps_seg_word(seg); ps_seg_frames(seg, &sf, &ef); printf("%s %d %d\n", word, sf, ef); } c = clock() - c; printf("5 * fsg search in %.2f sec\n", (double)c / CLOCKS_PER_SEC); dag = ps_get_lattice(ps); ps_lattice_write(dag, "test_jsgf.lat"); jsgf_grammar_free(jsgf); fsg_search_free(ps_search_base(fsgs)); ps_free(ps); cmd_ln_free_r(config); TEST_ASSERT(config = cmd_ln_init(NULL, ps_args(), TRUE, "-hmm", MODELDIR "/hmm/en_US/hub4wsj_sc_8k", "-dict", MODELDIR "/lm/en/turtle.dic", "-jsgf", DATADIR "/goforward.gram", "-input_endian", "little", "-samprate", "16000", NULL)); TEST_ASSERT(ps = ps_init(config)); 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 (%d, %d)\n", uttid, hyp, score, prob); TEST_EQUAL(0, strcmp("go forward ten meters", hyp)); ps_free(ps); fclose(rawfh); cmd_ln_free_r(config); TEST_ASSERT(config = cmd_ln_init(NULL, ps_args(), TRUE, "-hmm", MODELDIR "/hmm/en_US/hub4wsj_sc_8k", "-dict", MODELDIR "/lm/en/turtle.dic", "-jsgf", DATADIR "/goforward.gram", "-toprule", "goforward.move2", "-input_endian", "little", "-samprate", "16000", NULL)); TEST_ASSERT(ps = ps_init(config)); 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 (%d, %d)\n", uttid, hyp, score, prob); TEST_EQUAL(0, strcmp("go forward ten meters", hyp)); ps_free(ps); cmd_ln_free_r(config); fclose(rawfh); TEST_ASSERT(config = cmd_ln_init(NULL, ps_args(), TRUE, "-hmm", MODELDIR "/hmm/en_US/hub4wsj_sc_8k", "-dict", MODELDIR "/lm/en/turtle.dic", "-jsgf", DATADIR "/defective.gram", NULL)); TEST_ASSERT(NULL == ps_init(config)); cmd_ln_free_r(config); return 0; }
int main(int argc, char** argv) { int i; int rv; FILE* fh; char const *hyp, *uttid; int32 score; ps_decoder_t *ps; cmd_ln_t *config; ps_lattice_t* dag; config = cmd_ln_init(NULL, ps_args(), TRUE, "-hmm", "./hmm/zh_broadcastnews_ptm256_8000", "-lm", "./lm/syllables.lm.DMP", "-dict", "./lm/syllables_sorted.dic", NULL); if (config == NULL) return 1; ps = ps_init(config); if (ps == NULL) return 1; fh = fopen(argv[1], "rb"); if (fh == NULL) { perror("Failed to open audio file."); return 1; } rv = ps_decode_raw(ps, fh, "test", -1); if (rv < 0) return 1; hyp = ps_get_hyp(ps, &score, &uttid); if (hyp == NULL) return 1; printf("Recognized: %s\n", hyp); inverted_index_t* index = inverted_index_init("./syllable.lst"); if (index == NULL) { exit(1); } dag = ps_get_lattice(ps); if (dag == NULL) { perror("No lattice"); return 1; } /* printf("# Total number of words: %d\n", index->n_word); for(i = 0; i < index->n_word; i++) { printf("%3d: %s\n", i+1, index->word_list[i]); }*/ float32 ascale = cmd_ln_float32_r(config, "-ascale"); printf("ascale: %f\n", ascale); //printf("%d: %s\n", inverted_index_get_wid(index, "ba"), "ba"); //printf("%d: %s\n", inverted_index_get_wid(index, "bia"), "bia"); inverted_index_addhits(index, "test", dag, 1.0/ascale); inverted_index_write(index, "./index"); inverted_index_free(index); index = inverted_index_read("./index"); inverted_index_write(index, "./index2"); char* query[] = {"jin", "tian", "jie", "mu"}; result_list_t* rl; inverted_index_search(index, ps_get_lmset(ps), 1.0/ascale, query, 4, &rl); inverted_index_free(index); return 0; }
int main(int argc, char* argv[]) { ps_decoder_t *ps; cmd_ln_t *config; FILE *fh; int rv; char const *hyp, *uttid; int32 score; int16 buf[512]; /* *config = cmd_ln_init(NULL, ps_args(), TRUE, * "-hmm", MODELDIR "/hmm/en_US/hub4wsj_sc_8k", * "-lm", MODELDIR "/lm/en/turtle.DMP", * "-dict", MODELDIR "/lm/en/turtle.dic", * NULL); */ config = cmd_ln_parse_file_r(NULL, ps_args(), "commands.gram", FALSE); if ( config == NULL ) return 1; ps = ps_init(config); if ( ps == NULL ) return 1; // Audio file for test fh = fopen("goforward.raw", "rb"); if ( fh == NULL ) { perror("Failed to open file"); return 1; } // Decoding rv = ps_decode_raw(ps, fh, "goforward", -1); if ( rv < 0 ) return 1; // Hypothesis hyp = ps_get_hyp(ps, &score, &uttid); if ( hyp == NULL ) return 1; printf("Recognized: %s (%d %s)\n", hyp, score, uttid); /* Do it again, from block memory fseek(fh, 0, SEEK_SET); while ( !feof(fh) ) { size_t nsamp; nsamp = fread(buf, 2, 512, fh); rv = ps_process_raw(ps, buf, nsamp, FALSE, FALSE); } // End of the utterance rv = ps_end_utt(ps); if ( rv < 0 ) return 1; // Retrieving hypothesis hyp = ps_get_hyp(ps, &score, &uttid); if ( hyp == NULL ) return 1; printf("Recognized: %s (%d %s)\n", hyp, score, uttid);*/ // Cleaning up fclose(fh); ps_free(ps); return 0; }
int main(int argc, char *argv[]) { ps_decoder_t *ps; cmd_ln_t *config; FILE *fh; char const *hyp, *uttid; int16 buf[512]; int rv; int32 score; config = cmd_ln_init(NULL, ps_args(), TRUE, "-hmm", MODELDIR "/hmm/en_US/hub4wsj_sc_8k", "-dict", MODELDIR2 "/en.id001.a.dic", "-lm", MODELDIR2 "/en.id001.arpabo", NULL); if (config == NULL) return 1; ps = ps_init(config); if (ps == NULL) return 1; fh = fopen("/Users/kicoolzhang/Documents/1.mov", "rb"); if (fh == NULL) { perror("Failed to open goforward.raw"); return 1; } rv = ps_decode_raw(ps, fh, NULL, -1); if (rv < 0) return 1; printf("[K]Decoded No. of samples of audio: %d\n", rv); hyp = ps_get_hyp(ps, &score, &uttid); if (hyp == NULL) return 1; printf("Recognized: %s\n", hyp); fseek(fh, 0, SEEK_SET); rv = ps_start_utt(ps, NULL); if (rv < 0) return 1; while (!feof(fh)) { rv = ps_start_utt(ps, NULL); if (rv < 0) return 1; printf("ready:\n"); size_t nsamp; nsamp = fread(buf, 2, 512, fh); printf("read:\n"); //我们将每次从文件中读取512大小的样本,使用ps_process_raw()把它们放到解码器中: rv = ps_process_raw(ps, buf, nsamp, FALSE, FALSE); printf("process:\n"); } //我们需要使用ps_end_utt()去标记说话的结尾处: rv = ps_end_utt(ps); if (rv < 0) return 1; //以相同精确的方式运行来检索假设的字符串: hyp = ps_get_hyp(ps, &score, &uttid); if (hyp == NULL) return 1; printf("Recognized: %s\n", hyp); fclose(fh); ps_free(ps); return 0; }