Browse Source

Include previous audio context in streaming Silero inference

master
evgeny 1 week ago
parent
commit
50e276cb94
  1. 20
      lib/silero_vad.c
  2. 5
      lib/silero_vad.h

20
lib/silero_vad.c

@ -13,6 +13,9 @@
/* Число float-элементов рекуррентного состояния модели: 2 * 1 * 128 */
#define SILERO_VAD_STATE_COUNT 256
/* ONNX-вход: 64 отсчёта предыдущего окна + 512 новых отсчётов @16кГц. */
#define SILERO_VAD_CONTEXT_SAMPLES 64
#define SILERO_VAD_INPUT_SAMPLES (SILERO_VAD_CONTEXT_SAMPLES + SILERO_VAD_WINDOW_SAMPLES)
struct silero_vad {
const OrtApi* ort;
@ -20,6 +23,7 @@ struct silero_vad {
OrtSession* session;
OrtMemoryInfo* mem_info;
float state[SILERO_VAD_STATE_COUNT]; /* рекуррентное состояние между вызовами */
float context[SILERO_VAD_CONTEXT_SAMPLES]; /* звуковой контекст предыдущего окна */
uint8_t* model_data; /* байты .onnx, загруженные в память (для file-версии) */
size_t model_len;
};
@ -124,7 +128,8 @@ static silero_vad_t* silero_vad_create_from_bytes(const uint8_t* data, size_t le
ort->ReleaseSessionOptions(opts);
DEBUG_INFO(DEBUG_CATEGORY_VAD, "silero_vad_create(%s): ok bytes=%zu", label, len);
DEBUG_INFO(DEBUG_CATEGORY_VAD, "silero_vad_create(%s): ok bytes=%zu window=%d context=%d input=%d", label, len,
SILERO_VAD_WINDOW_SAMPLES, SILERO_VAD_CONTEXT_SAMPLES, SILERO_VAD_INPUT_SAMPLES);
return vad;
fail:
@ -168,7 +173,8 @@ void silero_vad_destroy(silero_vad_t* vad) {
void silero_vad_reset(silero_vad_t* vad) {
if (!vad) return;
memset(vad->state, 0, sizeof(vad->state));
DEBUG_DEBUG(DEBUG_CATEGORY_VAD, "silero_vad_reset");
memset(vad->context, 0, sizeof(vad->context));
DEBUG_DEBUG(DEBUG_CATEGORY_VAD, "silero_vad_reset: recurrent state and audio context cleared");
}
int silero_vad_process(silero_vad_t* vad, const float* samples, float* prob) {
@ -183,12 +189,13 @@ int silero_vad_process(silero_vad_t* vad, const float* samples, float* prob) {
const char* output_names[2];
const OrtValue* inputs[3];
OrtValue* outputs[2];
int64_t shape_input[2] = {1, SILERO_VAD_WINDOW_SAMPLES};
int64_t shape_input[2] = {1, SILERO_VAD_INPUT_SAMPLES};
int64_t shape_state[3] = {2, 1, 128};
int64_t shape_prob[2] = {1, 1};
int64_t sr_value = SILERO_VAD_SAMPLE_RATE;
float prob_local = 0.0f;
float next_state[SILERO_VAD_STATE_COUNT];
float input[SILERO_VAD_INPUT_SAMPLES];
int rc = -1;
if (!vad || !samples || !prob) {
@ -196,9 +203,11 @@ int silero_vad_process(silero_vad_t* vad, const float* samples, float* prob) {
return -1;
}
ort = vad->ort;
memcpy(input, vad->context, sizeof(vad->context));
memcpy(input + SILERO_VAD_CONTEXT_SAMPLES, samples, SILERO_VAD_WINDOW_SAMPLES * sizeof(float));
status = ort->CreateTensorWithDataAsOrtValue(vad->mem_info, (void*)samples,
SILERO_VAD_WINDOW_SAMPLES * sizeof(float), shape_input, 2,
status = ort->CreateTensorWithDataAsOrtValue(vad->mem_info, input,
sizeof(input), shape_input, 2,
ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, &in_input);
if (status) { vad_report_ort_error(ort, status, "input tensor"); return -1; }
@ -241,6 +250,7 @@ int silero_vad_process(silero_vad_t* vad, const float* samples, float* prob) {
}
memcpy(vad->state, next_state, sizeof(next_state));
memcpy(vad->context, input + SILERO_VAD_INPUT_SAMPLES - SILERO_VAD_CONTEXT_SAMPLES, sizeof(vad->context));
*prob = prob_local;
rc = 0;

5
lib/silero_vad.h

@ -4,7 +4,8 @@
* Запускает официальную стриминговую модель silero_vad.onnx (v5, ~2.3 МБ),
* которая по окну аудио возвращает вероятность наличия речи [0..1].
* Рекуррентное состояние (GRU) хранится внутри объекта и переносится между
* вызовами, поэтому детектор работает в потоковом (real-time) режиме.
* вызовами. Обёртка также хранит 64 последних отсчёта аудио и добавляет их
* перед новым окном: ONNX получает 576 отсчётов, публичный API принимает 512.
*
* Требования к входному аудио:
* - частота дискретизации 16 кГц (модель поддерживает только 16k);
@ -54,7 +55,7 @@ silero_vad_t* silero_vad_create_default(void);
/* Освободить детектор. NULL безопасен. */
void silero_vad_destroy(silero_vad_t* vad);
/* Сбросить рекуррентное состояние (начало нового аудиопотока / после длительной тишины). */
/* Сбросить рекуррентное состояние и звуковой контекст (начало нового потока / разрыв захвата). */
void silero_vad_reset(silero_vad_t* vad);
/**

Loading…
Cancel
Save