@@ -8075,6 +8075,70 @@ struct whisper_token_data whisper_full_get_token_data(struct whisper_context * c
80758075 return ctx->state ->result_all [i_segment].tokens [i_token];
80768076}
80778077
8078+ // map a token time (centiseconds) from the VAD-processed timeline back to the original
8079+ // audio. a token inside a speech segment is interpolated within that segment; a token that
8080+ // falls in the silence removed between two segments snaps to the nearer boundary, so it
8081+ // never ends up in the middle of a cut-out gap (which a single global interpolation over
8082+ // the whole mapping table would do).
8083+ static int64_t whisper_map_token_time_segment_aware (
8084+ int64_t t,
8085+ const std::vector<whisper_state::vad_segment_info> & segs) {
8086+ if (segs.empty ()) {
8087+ return t;
8088+ }
8089+ if (t <= segs.front ().vad_start ) {
8090+ return segs.front ().orig_start ;
8091+ }
8092+ if (t >= segs.back ().vad_end ) {
8093+ return segs.back ().orig_end ;
8094+ }
8095+ for (size_t i = 0 ; i < segs.size (); ++i) {
8096+ const auto & s = segs[i];
8097+ if (t >= s.vad_start && t <= s.vad_end ) {
8098+ const int64_t vd = s.vad_end - s.vad_start ;
8099+ const int64_t od = s.orig_end - s.orig_start ;
8100+ if (vd <= 0 ) {
8101+ return s.orig_start ;
8102+ }
8103+ return s.orig_start + (t - s.vad_start ) * od / vd;
8104+ }
8105+ if (i + 1 < segs.size () && t > s.vad_end && t < segs[i + 1 ].vad_start ) {
8106+ const int64_t mid = (s.vad_end + segs[i + 1 ].vad_start ) / 2 ;
8107+ return (t <= mid) ? s.orig_end : segs[i + 1 ].orig_start ;
8108+ }
8109+ }
8110+ return t;
8111+ }
8112+
8113+ int64_t whisper_full_get_token_t0_from_state (struct whisper_state * state, int i_segment, int i_token) {
8114+ const int64_t t0 = state->result_all [i_segment].tokens [i_token].t0 ;
8115+ if (!state->has_vad_segments || state->vad_segments .empty ()) {
8116+ return t0;
8117+ }
8118+ return whisper_map_token_time_segment_aware (t0, state->vad_segments );
8119+ }
8120+
8121+ int64_t whisper_full_get_token_t0 (struct whisper_context * ctx, int i_segment, int i_token) {
8122+ return whisper_full_get_token_t0_from_state (ctx->state , i_segment, i_token);
8123+ }
8124+
8125+ int64_t whisper_full_get_token_t1_from_state (struct whisper_state * state, int i_segment, int i_token) {
8126+ const int64_t t1 = state->result_all [i_segment].tokens [i_token].t1 ;
8127+ if (!state->has_vad_segments || state->vad_segments .empty ()) {
8128+ return t1;
8129+ }
8130+ const int64_t orig_t0 = whisper_full_get_token_t0_from_state (state, i_segment, i_token);
8131+ int64_t orig_t1 = whisper_map_token_time_segment_aware (t1, state->vad_segments );
8132+ if (orig_t1 < orig_t0 + 1 ) {
8133+ orig_t1 = orig_t0 + 1 ; // keep a strictly positive duration after snapping
8134+ }
8135+ return orig_t1;
8136+ }
8137+
8138+ int64_t whisper_full_get_token_t1 (struct whisper_context * ctx, int i_segment, int i_token) {
8139+ return whisper_full_get_token_t1_from_state (ctx->state , i_segment, i_token);
8140+ }
8141+
80788142float whisper_full_get_token_p_from_state (struct whisper_state * state, int i_segment, int i_token) {
80798143 return state->result_all [i_segment].tokens [i_token].p ;
80808144}
0 commit comments