mirror of
https://github.com/k2-fsa/sherpa-onnx.git
synced 2026-11-10 13:04:05 +08:00
102 lines
3.5 KiB
C++
102 lines
3.5 KiB
C++
// cxx-api-examples/online-speech-enhancement-voxlock-with-voice-sample-cxx-api.cc
|
|
//
|
|
// Copyright (c) 2026 Xiaomi Corporation
|
|
//
|
|
// VoxLock is a target-speaker voice isolation model. It keeps the voice of
|
|
// one speaker, e.g., the caller in a phone call, and removes the other
|
|
// voices.
|
|
//
|
|
// The model is from https://github.com/arbazsiddiqui/voxlock
|
|
//
|
|
// This example provides a voice sample of the speaker to keep, so VoxLock
|
|
// isolates that speaker from the first sample. The voice sample must have at
|
|
// least 3 seconds of the speaker's voice; from a longer file, VoxLock uses
|
|
// the loudest 3 seconds within its first 30 seconds. See
|
|
// ./online-speech-enhancement-voxlock-cxx-api.cc if you don't have a voice
|
|
// sample.
|
|
//
|
|
// We assume you have pre-downloaded the model from
|
|
// https://github.com/k2-fsa/sherpa-onnx/releases/tag/speech-enhancement-models
|
|
//
|
|
// An example command to download:
|
|
// clang-format off
|
|
/*
|
|
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/speech-enhancement-models/sherpa-onnx-voxlock-int8.tar.bz2
|
|
tar xvf sherpa-onnx-voxlock-int8.tar.bz2
|
|
*/
|
|
// clang-format on
|
|
|
|
#include <algorithm>
|
|
#include <chrono> // NOLINT
|
|
#include <cstdio>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "sherpa-onnx/c-api/cxx-api.h"
|
|
|
|
int32_t main() {
|
|
using namespace sherpa_onnx::cxx; // NOLINT
|
|
|
|
OnlineSpeechDenoiserConfig config;
|
|
std::string enroll_model = "./sherpa-onnx-voxlock-int8/enroll.onnx";
|
|
std::string chunk_model = "./sherpa-onnx-voxlock-int8/chunk_int8.onnx";
|
|
std::string voice_sample =
|
|
"./sherpa-onnx-voxlock-int8/test_wavs/en-voice-sample-f.wav";
|
|
std::string wav_filename =
|
|
"./sherpa-onnx-voxlock-int8/test_wavs/en-combined.wav";
|
|
std::string out_wave_filename =
|
|
"./voxlock-enhanced-online-with-voice-sample-16k.wav";
|
|
config.model.voxlock.enroll_model = enroll_model;
|
|
config.model.voxlock.chunk_model = chunk_model;
|
|
config.model.voxlock.voice_sample = voice_sample;
|
|
|
|
auto sd = OnlineSpeechDenoiser::Create(config);
|
|
if (!sd.Get()) {
|
|
std::cerr << "Please check your config\n";
|
|
return -1;
|
|
}
|
|
|
|
Wave wave = ReadWave(wav_filename);
|
|
if (wave.samples.empty()) {
|
|
std::cerr << "Failed to read: '" << wav_filename << "'\n";
|
|
return -1;
|
|
}
|
|
|
|
std::vector<float> samples;
|
|
auto frame_shift = sd.GetFrameShiftInSamples();
|
|
|
|
std::cout << "Started\n";
|
|
const auto begin = std::chrono::steady_clock::now();
|
|
|
|
for (int32_t start = 0; start < static_cast<int32_t>(wave.samples.size());
|
|
start += frame_shift) {
|
|
int32_t n = std::min<int32_t>(frame_shift, wave.samples.size() - start);
|
|
auto denoised = sd.Run(wave.samples.data() + start, n, wave.sample_rate);
|
|
samples.insert(samples.end(), denoised.samples.begin(),
|
|
denoised.samples.end());
|
|
}
|
|
|
|
auto tail = sd.Flush();
|
|
samples.insert(samples.end(), tail.samples.begin(), tail.samples.end());
|
|
|
|
const auto end = std::chrono::steady_clock::now();
|
|
std::cout << "Done\n";
|
|
|
|
WriteWave(out_wave_filename, {samples, sd.GetSampleRate()});
|
|
|
|
const float elapsed_seconds =
|
|
std::chrono::duration_cast<std::chrono::milliseconds>(end - begin)
|
|
.count() /
|
|
1000.;
|
|
float duration = wave.samples.size() / static_cast<float>(wave.sample_rate);
|
|
float rtf = elapsed_seconds / duration;
|
|
|
|
std::cout << "Saved to " << out_wave_filename << "\n";
|
|
printf("Duration: %.3fs\n", duration);
|
|
printf("Elapsed seconds: %.3fs\n", elapsed_seconds);
|
|
printf("(Real time factor) RTF = %.3f / %.3f = %.3f\n", elapsed_seconds,
|
|
duration, rtf);
|
|
return 0;
|
|
}
|