Skip to content

Commit ceee17c

Browse files
committed
Fix ef boundary handling in state_align_search
prune_hmms used nf > ef[i] to gate frame advancement, where ef[i] is the exclusive end frame (start + duration). This allowed a phone to advance to ef[i] and be scored there, one frame past its window. phone_transition used hmm_frame(hmm) != nf to decide whether to fire, which meant only phones advanced by prune_hmms could transition. Phones stopped at the ef boundary had hmm_frame == frame_idx rather than nf, so the check silently suppressed transitions. In practice this meant the last phone of a word could not enter the first phone of the following word, causing two-pass alignment to fail to reach the final state. Change the prune gate to nf >= ef[i] so a phone's last active frame is ef[i]-1. Change the transition condition to hmm_frame(hmm) < frame_idx so any phone active this frame can fire, whether or not it was advanced by prune.
1 parent 850a642 commit ceee17c

1 file changed

Lines changed: 17 additions & 6 deletions

File tree

src/state_align_search.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,12 @@ prune_hmms(state_align_search_t *sas, int frame_idx)
9494
hmm_t *hmm = sas->hmms + i;
9595
if (hmm_frame(hmm) < frame_idx)
9696
continue;
97-
/* Enforce alignment constraint: due to non-emitting states,
98-
* previous phone's HMM remains active in first frame of its
99-
* successor. */
100-
if (nf > sas->ef[i])
97+
/* ef[i] is the exclusive end frame (= start + duration).
98+
* Once nf reaches ef[i] the phone has used its full window;
99+
* stop advancing so it is not scored in the next frame.
100+
* phone_transition is allowed to fire at this last active
101+
* frame via the complementary check in phone_transition. */
102+
if (nf >= sas->ef[i])
101103
continue;
102104
hmm_frame(hmm) = nf;
103105
}
@@ -114,7 +116,13 @@ phone_transition(state_align_search_t *sas, int frame_idx)
114116
int32 newphone_score;
115117

116118
hmm = sas->hmms + i;
117-
if (hmm_frame(hmm) != nf)
119+
/* Allow transition from phones that were active this frame,
120+
* whether they were advanced to nf (normal case) or left at
121+
* frame_idx by prune_hmms because they hit their ef boundary.
122+
* The original check (hmm_frame != nf) silently blocked
123+
* cross-word transitions when the phone was evaluated at
124+
* exactly its last allowed frame. */
125+
if (hmm_frame(hmm) < frame_idx)
118126
continue;
119127
/* Enforce alignment constraint for initial state of each phone. */
120128
if (nf < sas->sf[i + 1])
@@ -123,9 +131,12 @@ phone_transition(state_align_search_t *sas, int frame_idx)
123131
newphone_score = hmm_out_score(hmm);
124132
nhmm = hmm + 1;
125133
if (hmm_frame(nhmm) < frame_idx) {
134+
/* Successor is inactive: enter it fresh with the new frame. */
126135
hmm_enter(nhmm, newphone_score, hmm_out_history(hmm), nf);
127136
continue;
128137
}
138+
/* Successor is already active: update score/history only (Viterbi
139+
* competition), never bump its hmm_frame to a later value. */
129140
if (newphone_score BETTER_THAN hmm_in_score(nhmm)) {
130141
hmm_in_score(nhmm) = newphone_score;
131142
hmm_in_history(nhmm) = hmm_out_history(hmm);
@@ -461,7 +472,7 @@ state_align_search_init(const char *name,
461472
++i, itor = ps_alignment_iter_next(itor)) {
462473
ps_alignment_entry_t *ent = ps_alignment_iter_get(itor);
463474
int min_nframes;
464-
475+
465476
hmm_init(sas->hmmctx, &sas->hmms[i], FALSE,
466477
ent->id.pid.ssid, ent->id.pid.tmatid);
467478
/* Can't align less than the number of frames in an HMM! */

0 commit comments

Comments
 (0)