Skip to content

Commit 778c507

Browse files
authored
refactor(vad): store duration constants in ms instead of hops (#1200)
## Description `kMinSpeechDuration`, `kMinSilenceDuration` and `kSpeechPad` were stored as hop counts with trailing comments hinting the ms equivalent. The unit implicitly depended on `kHopLengthMs`, and the comments would rot the moment someone changed it. Rename to `*Ms` to match the `kWindowSizeMs` / `kHopLengthMs` convention and convert to hops at the use site via `/ kHopLengthMs`. Now `kHopLengthMs` changes propagate automatically and the source-of-truth unit is explicit in the name. ### Introduces a breaking change? - [ ] Yes - [x] No ### Type of change - [ ] Bug fix (change which fixes an issue) - [ ] New feature (change which adds functionality) - [ ] Documentation update (improves or adds clarity to existing documentation) - [x] Other (chores, tests, code style improvements etc.) ### Tested on - [ ] iOS - [ ] Android ### Testing instructions Refactor only — values are unchanged (`250 / 10 = 25`, `100 / 10 = 10`, `30 / 10 = 3`). Existing VAD behavior should be identical. ### Screenshots ### Related issues Closes #1172 ### Checklist - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have updated the documentation accordingly - [x] My changes generate no new warnings ### Additional notes Per discussion in the issue, picked option 2 (ms-based source of truth) over the rename-with-`Hops`-suffix option because it survives changes to `kHopLengthMs`.
1 parent d488d1b commit 778c507

2 files changed

Lines changed: 9 additions & 8 deletions

File tree

‎packages/react-native-executorch/common/rnexecutorch/models/voice_activity_detection/Constants.h‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ inline constexpr auto kPaddedWindowSize = std::bit_ceil(kWindowSize); // 512
2121
inline constexpr size_t kModelInputMin = 100;
2222
inline constexpr size_t kModelInputMax = 1000;
2323
inline constexpr auto kSpeechThreshold = 0.6f;
24-
inline constexpr size_t kMinSpeechDuration = 25; // 250 ms
25-
inline constexpr size_t kMinSilenceDuration = 10; // 100 ms
26-
inline constexpr size_t kSpeechPad = 3; // 30 ms
24+
inline constexpr size_t kMinSpeechDurationMs = 250;
25+
inline constexpr size_t kMinSilenceDurationMs = 100;
26+
inline constexpr size_t kSpeechPadMs = 30;
2727
inline constexpr size_t kStreamBufferMaxSize = 10 * kSampleRate; // 10s
2828
inline constexpr size_t kStreamBufferMinReserve =
2929
1 * kSampleRate; // 1s of audio

‎packages/react-native-executorch/common/rnexecutorch/models/voice_activity_detection/VoiceActivityDetection.cpp‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ VoiceActivityDetection::postprocess(const std::vector<float> &scores,
209209
if (score >= threshold) {
210210
if (potentialStart == -1) {
211211
potentialStart = i;
212-
} else if (i - potentialStart >= kMinSpeechDuration) {
212+
} else if (i - potentialStart >= kMinSpeechDurationMs / kHopLengthMs) {
213213
triggered = true;
214214
startSegment = potentialStart;
215215
potentialStart = -1;
@@ -221,7 +221,7 @@ VoiceActivityDetection::postprocess(const std::vector<float> &scores,
221221
if (score < threshold) {
222222
if (potentialEnd == -1) {
223223
potentialEnd = i;
224-
} else if (i - potentialEnd >= kMinSilenceDuration) {
224+
} else if (i - potentialEnd >= kMinSilenceDurationMs / kHopLengthMs) {
225225
triggered = false;
226226
endSegment = potentialEnd;
227227
speechSegments.emplace_back(startSegment, endSegment);
@@ -237,11 +237,12 @@ VoiceActivityDetection::postprocess(const std::vector<float> &scores,
237237
speechSegments.emplace_back(startSegment, endSegment);
238238
}
239239

240+
constexpr size_t kSpeechPadHops = kSpeechPadMs / kHopLengthMs;
240241
for (auto &[start, end] : speechSegments) {
241-
// std::max(start-kSpeedchPad, 0) might be underflow that is why we use ?
242+
// std::max(start-kSpeechPadHops, 0) might be underflow that is why we use ?
242243
// operator.
243-
start = (start > kSpeechPad ? start - kSpeechPad : 0) * kHopLength;
244-
end = std::min(end + kSpeechPad, scores.size()) * kHopLength;
244+
start = (start > kSpeechPadHops ? start - kSpeechPadHops : 0) * kHopLength;
245+
end = std::min(end + kSpeechPadHops, scores.size()) * kHopLength;
245246
}
246247

247248
// Merge tightly placed segments according to the max allowed gap parameter.

0 commit comments

Comments
 (0)