From 1a0f4ae55798dc8f894712bc79d34b684f0ed748 Mon Sep 17 00:00:00 2001 From: Kevin Lenzo Date: Sat, 15 Aug 2026 15:22:02 -0400 Subject: [PATCH] Document and test the forced-alignment variant-token contract ps_set_align_text() looks up each token with an exact dictionary lookup, so an explicit pronunciation variant such as "a(2)" is aligned with only that entry's phones, a base spelling such as "a" remains free to use any of its alternate pronunciations, and an unknown spelling such as "a(99)" is rejected. Document this on ps_set_align_text() and add tests for it. test_align_text_variant checks that an unknown variant returns -1 while a transcript of known base and variant spellings is accepted. test_align_variant_alt inspects the constructed alignment FSG: a base token contributes an alternate-pronunciation transition, while an explicit variant token does not. --- include/pocketsphinx/search.h | 3 +++ test/unit/CMakeLists.txt | 2 ++ test/unit/test_align_text_variant.c | 26 ++++++++++++++++++++ test/unit/test_align_variant_alt.c | 37 +++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+) create mode 100644 test/unit/test_align_text_variant.c create mode 100644 test/unit/test_align_variant_alt.c diff --git a/include/pocketsphinx/search.h b/include/pocketsphinx/search.h index 35cbff87b..6673e85b4 100644 --- a/include/pocketsphinx/search.h +++ b/include/pocketsphinx/search.h @@ -332,6 +332,9 @@ int ps_add_allphone_file(ps_decoder_t *ps, const char *name, const char *path); * * Decoding proceeds as normal, though only this word sequence will be * recognized, with silences and alternate pronunciations inserted. + * An explicit dictionary variant such as `a(2)` uses only that entry's + * pronunciation. A base spelling such as `a` may use any of its alternate + * pronunciations. An unknown spelling such as `a(99)` causes an error. * Word alignments are available with ps_seg_iter(). To obtain * phoneme or state segmentations, you must subsequently call * ps_set_alignment() and re-run decoding. It's tough son, but it's life. diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 4c0d08db7..9a20df728 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -6,6 +6,8 @@ target_include_directories(test_thread_utils PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) set(TESTS test_acmod test_acmod_grow + test_align_text_variant + test_align_variant_alt test_alignment test_allphone test_bitvec diff --git a/test/unit/test_align_text_variant.c b/test/unit/test_align_text_variant.c new file mode 100644 index 000000000..14b0e2e57 --- /dev/null +++ b/test/unit/test_align_text_variant.c @@ -0,0 +1,26 @@ +#include + +#include "test_macros.h" + +int +main(int argc, char *argv[]) +{ + ps_config_t *config; + ps_decoder_t *ps; + + (void)argc; + (void)argv; + TEST_ASSERT(config = + ps_config_parse_json( + NULL, + "hmm: \"" MODELDIR "/en-us/en-us\"," + "dict: \"" MODELDIR "/en-us/cmudict-en-us.dict\"")); + TEST_ASSERT(ps = ps_init(config)); + + TEST_EQUAL(-1, ps_set_align_text(ps, "a(99)")); + TEST_EQUAL(0, ps_set_align_text(ps, "a a(2) are are(2)")); + + ps_free(ps); + ps_config_free(config); + return 0; +} diff --git a/test/unit/test_align_variant_alt.c b/test/unit/test_align_variant_alt.c new file mode 100644 index 000000000..ad1a1a731 --- /dev/null +++ b/test/unit/test_align_variant_alt.c @@ -0,0 +1,37 @@ +#include + +#include "lm/fsg_model.h" +#include "test_macros.h" + +int +main(int argc, char *argv[]) +{ + fsg_model_t *fsg; + ps_config_t *config; + ps_decoder_t *ps; + int32 altwid; + + (void)argc; + (void)argv; + TEST_ASSERT(config = + ps_config_parse_json( + NULL, + "hmm: \"" MODELDIR "/en-us/en-us\"," + "dict: \"" MODELDIR "/en-us/cmudict-en-us.dict\"")); + TEST_ASSERT(ps = ps_init(config)); + + TEST_EQUAL(0, ps_set_align_text(ps, "a")); + TEST_ASSERT(fsg = ps_get_fsg(ps, "_align")); + TEST_ASSERT(fsg_model_has_alt(fsg)); + TEST_ASSERT((altwid = fsg_model_word_id(fsg, "a(2)")) >= 0); + TEST_ASSERT(fsg_model_is_alt(fsg, altwid)); + + TEST_EQUAL(0, ps_set_align_text(ps, "a(2)")); + TEST_ASSERT(fsg = ps_get_fsg(ps, "_align")); + TEST_ASSERT(fsg_model_word_id(fsg, "a(2)") >= 0); + TEST_ASSERT(!fsg_model_has_alt(fsg)); + + ps_free(ps); + ps_config_free(config); + return 0; +}