packages feed

silero-vad-0.1.0.0: cbits/silero/model.c

#include "model.h"

// 16khz sample rate can only have a window size of 512 in the v5 model.
#define STATE_LENGTH 2 * 1 * 128
#define STATE_BYTES STATE_LENGTH * sizeof(float)

#define CONTEXT_LENGTH 64
#define CONTEXT_BYTES CONTEXT_LENGTH * sizeof(float)

#define BUFFER_LENGTH WINDOW_LENGTH + CONTEXT_LENGTH
#define BUFFER_BYTES WINDOW_BYTES + CONTEXT_BYTES

// Log level: Error
#define ORT_LOGGING_LEVEL 3

const int64_t sr_shape[] = {1};
const int64_t state_shape[] = {2, 1, 128};

const char *input_names[] = {"input", "state", "sr"};
const char *output_names[] = {"output", "stateN"};

int64_t get_window_length() { return WINDOW_LENGTH; }
int64_t get_sample_rate() { return SAMPLE_RATE; }

struct SileroModel *load_model(OrtApiBase *(*ortGetApiBase)(),
                               const void *model_path) {
  struct SileroModel *model = malloc(sizeof(struct SileroModel));
  model->api = ortGetApiBase()->GetApi(ORT_API_VERSION);
  (void)model->api->CreateEnv(ORT_LOGGING_LEVEL, "silero-vad-hs", &model->env);
  (void)model->api->CreateSessionOptions(&model->session_options);
  (void)model->api->SetIntraOpNumThreads(model->session_options, 1);
  (void)model->api->SetInterOpNumThreads(model->session_options, 1);
  (void)model->api->SetSessionGraphOptimizationLevel(model->session_options,
                                                     ORT_ENABLE_ALL);
  (void)model->api->CreateSession(model->env, model_path,
                                  model->session_options, &model->session);
  (void)model->api->CreateCpuMemoryInfo(OrtArenaAllocator, OrtMemTypeCPU,
                                        &model->memory_info);
  model->state = calloc(STATE_LENGTH, STATE_BYTES);
  model->buffer = calloc(BUFFER_LENGTH, BUFFER_BYTES);
  model->context = calloc(CONTEXT_LENGTH, CONTEXT_BYTES);
  model->input_shape[0] = 1;
  model->is_first_run = true;
  return model;
}

void release_model(struct SileroModel *model) {
  model->api->ReleaseEnv(model->env);
  model->api->ReleaseSessionOptions(model->session_options);
  model->api->ReleaseSession(model->session);
  model->api->ReleaseMemoryInfo(model->memory_info);
  free(model->state);
  free(model->buffer);
  free(model->context);
  free(model);
}

void reset_model(struct SileroModel *model) {
  memset(model->state, 0.0f, STATE_BYTES);
  memset(model->buffer, 0.0f, BUFFER_BYTES);
  memset(model->context, 0.0f, CONTEXT_BYTES);
  model->is_first_run = true;
}

float detect_speech(struct SileroModel *model, const float *samples) {
  // Add context from previous run.
  if (model->is_first_run) {
    model->is_first_run = false;
    model->input_shape[1] = WINDOW_LENGTH;
    memcpy(model->buffer, samples, WINDOW_BYTES);
  } else {
    model->input_shape[1] = BUFFER_LENGTH;
    memcpy(model->buffer, model->context, CONTEXT_BYTES);
    memcpy(model->buffer + CONTEXT_LENGTH, samples, WINDOW_BYTES);
  }
  // Save context for next run.
  memcpy(model->context, samples + WINDOW_LENGTH - CONTEXT_LENGTH,
         CONTEXT_BYTES);

  // Input tensor (containing the pcm data).
  OrtValue *input_tensor = NULL;
  (void)model->api->CreateTensorWithDataAsOrtValue(
      model->memory_info, model->buffer, model->input_shape[1] * sizeof(float),
      model->input_shape, sizeof(model->input_shape) / sizeof(int64_t),
      ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, &input_tensor);
  // State tensor.
  OrtValue *state_tensor = NULL;
  (void)model->api->CreateTensorWithDataAsOrtValue(
      model->memory_info, model->state, STATE_BYTES, state_shape,
      sizeof(state_shape) / sizeof(int64_t),
      ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, &state_tensor);

  // Sample-rate tensor (assumes 16khz).
  int64_t sample_rate[] = {SAMPLE_RATE};
  OrtValue *sr_tensor = NULL;
  (void)model->api->CreateTensorWithDataAsOrtValue(
      model->memory_info, sample_rate, sizeof(int64_t), sr_shape,
      sizeof(sr_shape) / sizeof(int64_t), ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64,
      &sr_tensor);

  // Run inference.
  const OrtValue *input_tensors[] = {input_tensor, state_tensor, sr_tensor};
  OrtValue *output_tensors[] = {NULL, NULL};
  (void)model->api->Run(model->session, NULL, input_names, input_tensors,
                        sizeof(input_tensors) / sizeof(OrtValue *),
                        output_names, sizeof(output_names) / sizeof(char *),
                        output_tensors);

  float *probabilities = NULL;
  float *state_n = NULL;

  (void)model->api->GetTensorMutableData(output_tensors[0],
                                         (void **)&probabilities);
  (void)model->api->GetTensorMutableData(output_tensors[1], (void **)&state_n);

  memcpy(model->state, state_n, STATE_BYTES);

  model->api->ReleaseValue(output_tensors[0]);
  model->api->ReleaseValue(output_tensors[1]);
  model->api->ReleaseValue(input_tensor);
  model->api->ReleaseValue(state_tensor);
  model->api->ReleaseValue(sr_tensor);

  return probabilities[0];
}