DPDFNet C API

This page describes how to use DPDFNet with the C API of sherpa-onnx.

See C API for how to build sherpa-onnx.

Offline speech enhancement

sherpa-onnx contains a ready-to-build example named speech-enhancement-dpdfnet-c-api.c.

cd /tmp
git clone https://github.com/k2-fsa/sherpa-onnx
cd sherpa-onnx

wget https://github.com/k2-fsa/sherpa-onnx/releases/download/speech-enhancement-models/dpdfnet2.onnx
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/speech-enhancement-models/inp_16k.wav

# All 8, 16, and 48 kHz models are available from the same release.
# See the DPDFNet model page linked below for all download commands.

mkdir build
cd build

cmake \
  -DSHERPA_ONNX_ENABLE_C_API=ON \
  -DBUILD_SHARED_LIBS=ON \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_INSTALL_PREFIX=./install \
  ..

make -j2 install
cd ..

gcc -o speech-enhancement-dpdfnet-c-api \
  ./c-api-examples/speech-enhancement-dpdfnet-c-api.c \
  -I ./build/install/include \
  -L ./build/install/lib \
  -l sherpa-onnx-c-api \
  -l onnxruntime

export LD_LIBRARY_PATH=$PWD/build/install/lib:$LD_LIBRARY_PATH
export DYLD_LIBRARY_PATH=$PWD/build/install/lib:$DYLD_LIBRARY_PATH

./speech-enhancement-dpdfnet-c-api

The example source is available at

The core offline configuration is shown below:

#include <stdio.h>
#include <string.h>

#include "sherpa-onnx/c-api/c-api.h"

int32_t main() {
  SherpaOnnxOfflineSpeechDenoiserConfig config;
  memset(&config, 0, sizeof(config));

  config.model.dpdfnet.model = "./dpdfnet2.onnx";
  config.model.dpdfnet.attenuation_limit_db = 12.0f;
  config.model.num_threads = 1;
  config.model.debug = 0;
  config.model.provider = "cpu";

  const SherpaOnnxOfflineSpeechDenoiser *sd =
      SherpaOnnxCreateOfflineSpeechDenoiser(&config);
  if (sd == NULL) {
    fprintf(stderr, "Failed to create offline speech denoiser\n");
    return -1;
  }

  const SherpaOnnxWave *wave = SherpaOnnxReadWave("./inp_16k.wav");
  if (wave == NULL) {
    SherpaOnnxDestroyOfflineSpeechDenoiser(sd);
    fprintf(stderr, "Failed to read input wave\n");
    return -1;
  }
  const SherpaOnnxDenoisedAudio *denoised =
      SherpaOnnxOfflineSpeechDenoiserRun(
          sd, wave->samples, wave->num_samples, wave->sample_rate);

  SherpaOnnxWriteWave(
      denoised->samples, denoised->n, denoised->sample_rate,
      "./enhanced.wav");

  SherpaOnnxDestroyDenoisedAudio(denoised);
  SherpaOnnxFreeWave(wave);
  SherpaOnnxDestroyOfflineSpeechDenoiser(sd);
  return 0;
}

attenuation_limit_db belongs to SherpaOnnxOfflineSpeechDenoiserDpdfNetModelConfig. It defaults to 0 when the configuration is zero-initialized. A positive value limits offline suppression; finite values must be in [0, 100], and infinity disables the limit. Invalid values cause SherpaOnnxCreateOfflineSpeechDenoiser() to return NULL. See Offline attenuation limit for details.

Streaming speech enhancement

DPDFNet is also available through the streaming denoiser API:

  • SherpaOnnxOnlineSpeechDenoiserConfig

  • SherpaOnnxCreateOnlineSpeechDenoiser()

  • SherpaOnnxOnlineSpeechDenoiserRun()

  • SherpaOnnxOnlineSpeechDenoiserFlush()

  • SherpaOnnxOnlineSpeechDenoiserReset()

The online API supports all official DPDFNet exports listed in DPDFNet: two 8 kHz models, four 16 kHz models, and two 48 kHz models.

The following example processes a wave file frame by frame and writes the streaming output to enhanced-streaming.wav:

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sherpa-onnx/c-api/c-api.h"

static int32_t AppendSamples(float **buffer, int32_t *size,
                             int32_t *capacity, const float *samples,
                             int32_t n) {
  if (*size + n > *capacity) {
    int32_t new_capacity = *capacity == 0 ? n : *capacity * 2;
    while (new_capacity < *size + n) {
      new_capacity *= 2;
    }

    float *new_buffer =
        (float *)realloc(*buffer, new_capacity * sizeof(float));
    if (new_buffer == NULL) {
      return 0;
    }

    *buffer = new_buffer;
    *capacity = new_capacity;
  }

  memcpy(*buffer + *size, samples, n * sizeof(float));
  *size += n;
  return 1;
}

int32_t main() {
  SherpaOnnxOnlineSpeechDenoiserConfig config;
  memset(&config, 0, sizeof(config));

  config.model.dpdfnet.model = "./dpdfnet2.onnx";
  config.model.num_threads = 1;
  config.model.debug = 0;
  config.model.provider = "cpu";

  const SherpaOnnxOnlineSpeechDenoiser *sd =
      SherpaOnnxCreateOnlineSpeechDenoiser(&config);
  if (sd == NULL) {
    fprintf(stderr, "Failed to create online speech denoiser\n");
    return -1;
  }

  const SherpaOnnxWave *wave = SherpaOnnxReadWave("./inp_16k.wav");
  if (wave == NULL) {
    SherpaOnnxDestroyOnlineSpeechDenoiser(sd);
    fprintf(stderr, "Failed to read input wave\n");
    return -1;
  }

  const int32_t frame_shift =
      SherpaOnnxOnlineSpeechDenoiserGetFrameShiftInSamples(sd);

  float *enhanced = NULL;
  int32_t num_enhanced = 0;
  int32_t capacity = 0;

  for (int32_t start = 0; start < wave->num_samples; start += frame_shift) {
    int32_t n = wave->num_samples - start;
    if (n > frame_shift) {
      n = frame_shift;
    }

    const SherpaOnnxDenoisedAudio *chunk =
        SherpaOnnxOnlineSpeechDenoiserRun(
            sd, wave->samples + start, n, wave->sample_rate);
    if (chunk == NULL) {
      continue;
    }

    if (!AppendSamples(&enhanced, &num_enhanced, &capacity,
                       chunk->samples, chunk->n)) {
      fprintf(stderr, "Failed to grow output buffer\n");
      SherpaOnnxDestroyDenoisedAudio(chunk);
      SherpaOnnxFreeWave(wave);
      SherpaOnnxDestroyOnlineSpeechDenoiser(sd);
      free(enhanced);
      return -1;
    }

    SherpaOnnxDestroyDenoisedAudio(chunk);
  }

  const SherpaOnnxDenoisedAudio *tail =
      SherpaOnnxOnlineSpeechDenoiserFlush(sd);
  if (tail != NULL) {
    AppendSamples(&enhanced, &num_enhanced, &capacity,
                  tail->samples, tail->n);
    SherpaOnnxDestroyDenoisedAudio(tail);
  }

  SherpaOnnxWriteWave(
      enhanced, num_enhanced,
      SherpaOnnxOnlineSpeechDenoiserGetSampleRate(sd),
      "./enhanced-streaming.wav");

  free(enhanced);
  SherpaOnnxFreeWave(wave);
  SherpaOnnxDestroyOnlineSpeechDenoiser(sd);
  return 0;
}

Note

SherpaOnnxOnlineSpeechDenoiserRun() can return NULL until enough input audio has been buffered. Call SherpaOnnxOnlineSpeechDenoiserFlush() at the end of the stream to retrieve the final tail samples and reset the denoiser state. The offline attenuation_limit_db field is not applied in streaming mode.