diff --git a/src/fsg_search.c b/src/fsg_search.c index d4db17c5..12318f6e 100644 --- a/src/fsg_search.c +++ b/src/fsg_search.c @@ -243,6 +243,13 @@ fsg_search_init(const char *name, fsgs->bestpath = TRUE; #endif + /* Forced alignment must use the Viterbi backtrace, not the lattice + * bestpath: the latter's segmentation can give phones durations too + * short for their HMMs, corrupting the state alignment. The align + * CLI already disables bestpath; do the same for the _align search. */ + if (name != NULL && strcmp(name, PS_DEFAULT_ALIGN_SEARCH) == 0) + fsgs->bestpath = FALSE; + if (fsg_search_reinit(ps_search_base(fsgs), ps_search_dict(fsgs), ps_search_dict2pid(fsgs)) < 0) diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 4c0d08db..93710419 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -7,6 +7,7 @@ set(TESTS test_acmod test_acmod_grow test_alignment + test_align_bestpath test_allphone test_bitvec test_config diff --git a/test/unit/test_align_bestpath.c b/test/unit/test_align_bestpath.c new file mode 100644 index 00000000..7964c29e --- /dev/null +++ b/test/unit/test_align_bestpath.c @@ -0,0 +1,68 @@ +/* -*- c-basic-offset: 4 -*- */ +#include +#include + +#include + +#include "test_macros.h" + +#define ALIGN_TEXT "feels like these days go on forever" + +static void +capture_error(void *user_data, err_lvl_t level, const char *fmt, ...) +{ + char message[1024]; + va_list args; + + va_start(args, fmt); + vsnprintf(message, sizeof(message), fmt, args); + va_end(args); + if (strstr(message, "impossible duration") != NULL) + *(int *)user_data = TRUE; + (void)level; +} + +static int +decode_wav(ps_decoder_t *ps) +{ + FILE *rawfh; + long nsamp; + + TEST_ASSERT(rawfh = fopen(DATADIR "/forever/input_2_16k.wav", "rb")); + TEST_EQUAL(0, fseek(rawfh, 44, SEEK_SET)); + nsamp = ps_decode_raw(ps, rawfh, -1); + fclose(rawfh); + TEST_ASSERT(nsamp > 0); + return 0; +} + +int +main(int argc, char *argv[]) +{ + ps_config_t *config; + ps_decoder_t *ps; + int impossible_duration = FALSE; + + (void)argc; + (void)argv; + TEST_ASSERT(config = + ps_config_parse_json( + NULL, + "hmm: \"" MODELDIR "/en-us/en-us\"," + "lm: \"" MODELDIR "/en-us/en-us.lm.bin\"," + "dict: \"" MODELDIR "/en-us/cmudict-en-us.dict\"")); + TEST_ASSERT(ps_config_bool(config, "bestpath")); + TEST_ASSERT(ps = ps_init(config)); + err_set_callback(capture_error, &impossible_duration); + + TEST_EQUAL(0, ps_set_align_text(ps, ALIGN_TEXT)); + decode_wav(ps); + TEST_EQUAL(0, ps_set_alignment(ps, NULL)); + decode_wav(ps); + + err_set_callback(err_logfp_cb, NULL); + TEST_ASSERT(impossible_duration == FALSE); + ps_free(ps); + ps_config_free(config); + return 0; +}