mirror of
https://github.com/k2-fsa/sherpa-onnx.git
synced 2026-11-10 21:11:03 +08:00
Add C-API SetVoiceSample for VoxLock PCM enroll (#4151)
This commit is contained in:
1 parent
935e5ded3d
commit
111617b114
13 files changed
+225
-11
No files matched your search
@@ -3078,6 +3078,24 @@ int32_t SherpaOnnxOfflineSpeechDenoiserGetSampleRate(
|
||||
return sd->impl->GetSampleRate();
|
||||
}
|
||||
|
||||
int32_t SherpaOnnxOfflineSpeechDenoiserSetVoiceSample(
|
||||
const SherpaOnnxOfflineSpeechDenoiser *sd, const float *samples, int32_t n,
|
||||
int32_t sample_rate) {
|
||||
if (sd == nullptr || sd->impl == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
if (samples == nullptr && n > 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
return sd->impl->SetVoiceSample(samples, n, sample_rate) ? 0 : -1;
|
||||
} catch (const std::exception &e) {
|
||||
SHERPA_ONNX_LOGE("Failed to set voice sample: %s", e.what());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const SherpaOnnxDenoisedAudio *SherpaOnnxOfflineSpeechDenoiserRun(
|
||||
const SherpaOnnxOfflineSpeechDenoiser *sd, const float *samples, int32_t n,
|
||||
int32_t sample_rate) {
|
||||
@@ -3352,6 +3370,24 @@ void SherpaOnnxOnlineSpeechDenoiserReset(
|
||||
sd->impl->Reset();
|
||||
}
|
||||
|
||||
int32_t SherpaOnnxOnlineSpeechDenoiserSetVoiceSample(
|
||||
const SherpaOnnxOnlineSpeechDenoiser *sd, const float *samples, int32_t n,
|
||||
int32_t sample_rate) {
|
||||
if (sd == nullptr || sd->impl == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
if (samples == nullptr && n > 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
return sd->impl->SetVoiceSample(samples, n, sample_rate) ? 0 : -1;
|
||||
} catch (const std::exception &e) {
|
||||
SHERPA_ONNX_LOGE("Failed to set voice sample: %s", e.what());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#if SHERPA_ONNX_ENABLE_SPEAKER_DIARIZATION == 1
|
||||
|
||||
struct SherpaOnnxOfflineSpeakerDiarization {
|
||||
|
||||
@@ -4372,6 +4372,23 @@ SHERPA_ONNX_API void SherpaOnnxDestroyOfflineSpeechDenoiser(
|
||||
SHERPA_ONNX_API int32_t SherpaOnnxOfflineSpeechDenoiserGetSampleRate(
|
||||
const SherpaOnnxOfflineSpeechDenoiser *sd);
|
||||
|
||||
/**
|
||||
* @brief Set a PCM voice sample for VoxLock.
|
||||
*
|
||||
* After resampling to the model rate, it keeps the loudest 3 seconds
|
||||
* within the first 30 seconds. Returns -1 if the clip is shorter than
|
||||
* 3 seconds after resampling; the previous voice sample is left unchanged.
|
||||
*
|
||||
* @param sd A pointer returned by SherpaOnnxCreateOfflineSpeechDenoiser().
|
||||
* @param samples Input mono PCM samples normalized to [-1, 1].
|
||||
* @param n Number of input samples.
|
||||
* @param sample_rate Input sample rate in Hz.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
SHERPA_ONNX_API int32_t SherpaOnnxOfflineSpeechDenoiserSetVoiceSample(
|
||||
const SherpaOnnxOfflineSpeechDenoiser *sd, const float *samples, int32_t n,
|
||||
int32_t sample_rate);
|
||||
|
||||
/**
|
||||
* @brief Denoised audio returned by offline or online speech enhancement APIs.
|
||||
*
|
||||
@@ -4511,6 +4528,22 @@ SherpaOnnxOnlineSpeechDenoiserFlush(const SherpaOnnxOnlineSpeechDenoiser *sd);
|
||||
SHERPA_ONNX_API void SherpaOnnxOnlineSpeechDenoiserReset(
|
||||
const SherpaOnnxOnlineSpeechDenoiser *sd);
|
||||
|
||||
/**
|
||||
* @brief Set a PCM voice sample for VoxLock.
|
||||
*
|
||||
* See SherpaOnnxOfflineSpeechDenoiserSetVoiceSample(). On success the
|
||||
* denoiser is reset so it uses the new clip.
|
||||
*
|
||||
* @param sd A pointer returned by SherpaOnnxCreateOnlineSpeechDenoiser().
|
||||
* @param samples Input mono PCM samples normalized to [-1, 1].
|
||||
* @param n Number of input samples.
|
||||
* @param sample_rate Input sample rate in Hz.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
SHERPA_ONNX_API int32_t SherpaOnnxOnlineSpeechDenoiserSetVoiceSample(
|
||||
const SherpaOnnxOnlineSpeechDenoiser *sd, const float *samples, int32_t n,
|
||||
int32_t sample_rate);
|
||||
|
||||
// =========================================================================
|
||||
// Source separation
|
||||
// =========================================================================
|
||||
|
||||
@@ -876,6 +876,15 @@ int32_t OfflineSpeechDenoiser::GetSampleRate() const {
|
||||
return SherpaOnnxOfflineSpeechDenoiserGetSampleRate(p_);
|
||||
}
|
||||
|
||||
bool OfflineSpeechDenoiser::SetVoiceSample(const float *samples, int32_t n,
|
||||
int32_t sample_rate) const {
|
||||
if (!p_) {
|
||||
return false;
|
||||
}
|
||||
return SherpaOnnxOfflineSpeechDenoiserSetVoiceSample(p_, samples, n,
|
||||
sample_rate) == 0;
|
||||
}
|
||||
|
||||
OnlineSpeechDenoiser OnlineSpeechDenoiser::Create(
|
||||
const OnlineSpeechDenoiserConfig &config) {
|
||||
struct SherpaOnnxOnlineSpeechDenoiserConfig c;
|
||||
@@ -925,6 +934,15 @@ void OnlineSpeechDenoiser::Reset() const {
|
||||
SherpaOnnxOnlineSpeechDenoiserReset(p_);
|
||||
}
|
||||
|
||||
bool OnlineSpeechDenoiser::SetVoiceSample(const float *samples, int32_t n,
|
||||
int32_t sample_rate) const {
|
||||
if (!p_) {
|
||||
return false;
|
||||
}
|
||||
return SherpaOnnxOnlineSpeechDenoiserSetVoiceSample(p_, samples, n,
|
||||
sample_rate) == 0;
|
||||
}
|
||||
|
||||
int32_t OnlineSpeechDenoiser::GetSampleRate() const {
|
||||
return SherpaOnnxOnlineSpeechDenoiserGetSampleRate(p_);
|
||||
}
|
||||
|
||||
@@ -1360,6 +1360,10 @@ class SHERPA_ONNX_API OfflineSpeechDenoiser
|
||||
/** @brief Return the expected input sample rate. */
|
||||
int32_t GetSampleRate() const;
|
||||
|
||||
/** @brief Set a PCM voice sample for VoxLock. */
|
||||
bool SetVoiceSample(const float *samples, int32_t n,
|
||||
int32_t sample_rate) const;
|
||||
|
||||
private:
|
||||
explicit OfflineSpeechDenoiser(const SherpaOnnxOfflineSpeechDenoiser *p);
|
||||
};
|
||||
@@ -1389,6 +1393,10 @@ class SHERPA_ONNX_API OnlineSpeechDenoiser
|
||||
/** @brief Reset the denoiser for a new stream. */
|
||||
void Reset() const;
|
||||
|
||||
/** @brief Set a PCM voice sample for VoxLock. */
|
||||
bool SetVoiceSample(const float *samples, int32_t n,
|
||||
int32_t sample_rate) const;
|
||||
|
||||
/** @brief Return the expected input sample rate. */
|
||||
int32_t GetSampleRate() const;
|
||||
|
||||
|
||||
@@ -26,6 +26,11 @@ class OfflineSpeechDenoiserImpl {
|
||||
int32_t sample_rate) const = 0;
|
||||
|
||||
virtual int32_t GetSampleRate() const = 0;
|
||||
|
||||
virtual bool SetVoiceSample(const float * /*samples*/, int32_t /*n*/,
|
||||
int32_t /*sample_rate*/) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sherpa_onnx
|
||||
|
||||
@@ -88,6 +88,18 @@ class OfflineSpeechDenoiserVoxLockImpl : public OfflineSpeechDenoiserImpl {
|
||||
return model_.GetMetaData().sample_rate;
|
||||
}
|
||||
|
||||
bool SetVoiceSample(const float *samples, int32_t n,
|
||||
int32_t sample_rate) override {
|
||||
const auto &meta = model_.GetMetaData();
|
||||
auto prepared = PrepareVoxLockVoiceSampleFromPcm(
|
||||
samples, n, sample_rate, meta.sample_rate, meta.voice_sample_seconds);
|
||||
if (prepared.empty()) {
|
||||
return false;
|
||||
}
|
||||
voice_sample_ = std::move(prepared);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void Init(const OfflineSpeechDenoiserConfig &config) {
|
||||
const auto &meta = model_.GetMetaData();
|
||||
|
||||
@@ -53,6 +53,14 @@ int32_t OfflineSpeechDenoiser::GetSampleRate() const {
|
||||
return impl_->GetSampleRate();
|
||||
}
|
||||
|
||||
bool OfflineSpeechDenoiser::SetVoiceSample(const float *samples, int32_t n,
|
||||
int32_t sample_rate) {
|
||||
if (!impl_) {
|
||||
return false;
|
||||
}
|
||||
return impl_->SetVoiceSample(samples, n, sample_rate);
|
||||
}
|
||||
|
||||
#if __ANDROID_API__ >= 9
|
||||
template OfflineSpeechDenoiser::OfflineSpeechDenoiser(
|
||||
AAssetManager *mgr, const OfflineSpeechDenoiserConfig &config);
|
||||
|
||||
@@ -52,6 +52,19 @@ class OfflineSpeechDenoiser {
|
||||
*/
|
||||
int32_t GetSampleRate() const;
|
||||
|
||||
/*
|
||||
* Set a PCM voice sample for VoxLock.
|
||||
*
|
||||
* @param samples 1-D array of audio samples. Each sample is in the
|
||||
* range [-1, 1].
|
||||
* @param n Number of samples
|
||||
* @param sample_rate Sample rate of the input samples
|
||||
* @return Return true on success. Return false if this is not a VoxLock
|
||||
* denoiser or if the clip is shorter than 3 seconds after
|
||||
* resampling.
|
||||
*/
|
||||
bool SetVoiceSample(const float *samples, int32_t n, int32_t sample_rate);
|
||||
|
||||
private:
|
||||
std::unique_ptr<OfflineSpeechDenoiserImpl> impl_;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,11 @@ class OnlineSpeechDenoiserImpl {
|
||||
virtual void Reset() = 0;
|
||||
virtual int32_t GetSampleRate() const = 0;
|
||||
virtual int32_t GetFrameShiftInSamples() const = 0;
|
||||
|
||||
virtual bool SetVoiceSample(const float * /*samples*/, int32_t /*n*/,
|
||||
int32_t /*sample_rate*/) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sherpa_onnx
|
||||
|
||||
@@ -132,17 +132,7 @@ class OnlineSpeechDenoiserVoxLockImpl : public OnlineSpeechDenoiserImpl {
|
||||
}
|
||||
|
||||
void Reset() override {
|
||||
resampler_.reset();
|
||||
input_sample_rate_ = -1;
|
||||
total_input_samples_ = 0;
|
||||
total_output_samples_ = 0;
|
||||
|
||||
voiced_.clear();
|
||||
energy_.clear();
|
||||
rest_.clear();
|
||||
recent_.clear();
|
||||
after_.clear();
|
||||
num_to_skip_ = 0;
|
||||
ClearState();
|
||||
|
||||
if (voice_sample_.empty()) {
|
||||
stream_.reset();
|
||||
@@ -162,7 +152,38 @@ class OnlineSpeechDenoiserVoxLockImpl : public OnlineSpeechDenoiserImpl {
|
||||
return model_.GetMetaData().hop_length;
|
||||
}
|
||||
|
||||
bool SetVoiceSample(const float *samples, int32_t n,
|
||||
int32_t sample_rate) override {
|
||||
const auto &meta = model_.GetMetaData();
|
||||
auto prepared = PrepareVoxLockVoiceSampleFromPcm(
|
||||
samples, n, sample_rate, meta.sample_rate, meta.voice_sample_seconds);
|
||||
if (prepared.empty()) {
|
||||
return false;
|
||||
}
|
||||
auto stream = std::make_unique<SpeechDenoiserVoxLockStream>(
|
||||
&model_, prepared.data(), prepared.size());
|
||||
voice_sample_ = std::move(prepared);
|
||||
ClearState();
|
||||
stream_ = std::move(stream);
|
||||
num_faded_ = fade_length_;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void ClearState() {
|
||||
resampler_.reset();
|
||||
input_sample_rate_ = -1;
|
||||
total_input_samples_ = 0;
|
||||
total_output_samples_ = 0;
|
||||
|
||||
voiced_.clear();
|
||||
energy_.clear();
|
||||
rest_.clear();
|
||||
recent_.clear();
|
||||
after_.clear();
|
||||
num_to_skip_ = 0;
|
||||
}
|
||||
|
||||
void Init(const OnlineSpeechDenoiserConfig &config) {
|
||||
const auto &meta = model_.GetMetaData();
|
||||
const auto &filename = config.model.voxlock.voice_sample;
|
||||
|
||||
@@ -62,6 +62,14 @@ int32_t OnlineSpeechDenoiser::GetFrameShiftInSamples() const {
|
||||
return impl_->GetFrameShiftInSamples();
|
||||
}
|
||||
|
||||
bool OnlineSpeechDenoiser::SetVoiceSample(const float *samples, int32_t n,
|
||||
int32_t sample_rate) {
|
||||
if (!impl_) {
|
||||
return false;
|
||||
}
|
||||
return impl_->SetVoiceSample(samples, n, sample_rate);
|
||||
}
|
||||
|
||||
#if __ANDROID_API__ >= 9
|
||||
template OnlineSpeechDenoiser::OnlineSpeechDenoiser(
|
||||
AAssetManager *mgr, const OnlineSpeechDenoiserConfig &config);
|
||||
|
||||
@@ -49,6 +49,14 @@ class OnlineSpeechDenoiser {
|
||||
int32_t GetSampleRate() const;
|
||||
int32_t GetFrameShiftInSamples() const;
|
||||
|
||||
/*
|
||||
* Set a PCM voice sample for VoxLock.
|
||||
*
|
||||
* See OfflineSpeechDenoiser::SetVoiceSample. On success the denoiser is
|
||||
* reset so it uses the new clip.
|
||||
*/
|
||||
bool SetVoiceSample(const float *samples, int32_t n, int32_t sample_rate);
|
||||
|
||||
private:
|
||||
std::unique_ptr<OnlineSpeechDenoiserImpl> impl_;
|
||||
};
|
||||
|
||||
@@ -131,6 +131,45 @@ inline std::vector<float> PrepareVoxLockVoiceSample(
|
||||
kVoxLockMaxVoiceSampleSeconds);
|
||||
}
|
||||
|
||||
// Resample PCM to sample_rate and return exactly `seconds` seconds of it.
|
||||
// Return an empty vector if it is shorter than `seconds` seconds.
|
||||
inline std::vector<float> PrepareVoxLockVoiceSampleFromPcm(
|
||||
const float *samples, int32_t n, int32_t in_sample_rate,
|
||||
int32_t sample_rate, int32_t seconds) {
|
||||
if (samples == nullptr || n <= 0 || in_sample_rate <= 0 || sample_rate <= 0 ||
|
||||
seconds <= 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<float> resampled;
|
||||
if (in_sample_rate == sample_rate) {
|
||||
resampled.assign(samples, samples + n);
|
||||
} else {
|
||||
CreateVoxLockResampler(in_sample_rate, sample_rate)
|
||||
->Resample(samples, n, true, &resampled);
|
||||
}
|
||||
|
||||
const int32_t rn = static_cast<int32_t>(resampled.size());
|
||||
if (rn < seconds * sample_rate) {
|
||||
SHERPA_ONNX_LOGE(
|
||||
"The voxlock voice sample is %.3f seconds long, shorter than %d "
|
||||
"seconds.",
|
||||
static_cast<float>(rn) / sample_rate, seconds);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (rn > seconds * sample_rate) {
|
||||
SHERPA_ONNX_LOGE(
|
||||
"The voxlock voice sample is %.3f seconds long. Use its loudest "
|
||||
"%d seconds within its first %d seconds.",
|
||||
static_cast<float>(rn) / sample_rate, seconds,
|
||||
kVoxLockMaxVoiceSampleSeconds);
|
||||
}
|
||||
|
||||
return SelectVoxLockVoiceSample(resampled.data(), rn, sample_rate, seconds,
|
||||
kVoxLockMaxVoiceSampleSeconds);
|
||||
}
|
||||
|
||||
// Read a voice sample from a wave file and return exactly `seconds` seconds
|
||||
// of it. Return an empty vector if it cannot be read or is too short.
|
||||
inline std::vector<float> ReadVoxLockVoiceSample(const std::string &filename,
|
||||
|
||||
Reference in new issue
Block a user