first commit

This commit is contained in:
Uladzimir Karpenka
2026-06-01 15:58:45 +03:00
commit 89c8a0e2b5
313 changed files with 945364 additions and 0 deletions
@@ -0,0 +1,354 @@
/*
libspecbleach - A spectral processing library
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "adaptive_denoiser.h"
#include "shared/configurations.h"
#include "shared/gain_estimation/gain_estimators.h"
#include "shared/noise_estimation/adaptive_noise_estimator.h"
#include "shared/post_estimation/noise_floor_manager.h"
#include "shared/post_estimation/postfilter.h"
#include "shared/pre_estimation/critical_bands.h"
#include "shared/pre_estimation/noise_scaling_criterias.h"
#include "shared/pre_estimation/spectral_smoother.h"
#include "shared/utils/denoise_mixer.h"
#include "shared/utils/spectral_features.h"
#include "shared/utils/spectral_utils.h"
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
typedef struct SpectralAdaptiveDenoiser {
uint32_t fft_size;
uint32_t real_spectrum_size;
uint32_t sample_rate;
uint32_t hop;
float default_oversubtraction;
float default_undersubtraction;
AdaptiveDenoiserParameters parameters;
float* alpha;
float* beta;
float* gain_spectrum;
float* residual_spectrum;
float* denoised_spectrum;
float* noise_profile;
SpectrumType spectrum_type;
CriticalBandType band_type;
GainEstimationType gain_estimation_type;
TimeSmoothingType time_smoothing_type;
DenoiseMixer* mixer;
NoiseScalingCriterias* noise_scaling_criteria;
SpectralSmoother* spectrum_smoothing;
PostFilter* postfiltering;
AdaptiveNoiseEstimator* adaptive_estimator;
SpectralFeatures* spectral_features;
NoiseFloorManager* noise_floor_manager;
bool postfiltering_enabled;
bool whitening_enabled;
} SpectralAdaptiveDenoiser;
SpectralProcessorHandle spectral_adaptive_denoiser_initialize(
const uint32_t sample_rate, const uint32_t fft_size,
const uint32_t overlap_factor) {
if (sample_rate == 0 || fft_size == 0 || overlap_factor == 0) {
return NULL;
}
SpectralAdaptiveDenoiser* self =
(SpectralAdaptiveDenoiser*)calloc(1U, sizeof(SpectralAdaptiveDenoiser));
if (!self) {
return NULL;
}
self->fft_size = fft_size;
self->real_spectrum_size = (self->fft_size / 2U) + 1U;
self->sample_rate = sample_rate;
self->hop = self->fft_size / overlap_factor;
self->default_oversubtraction = DEFAULT_OVERSUBTRACTION;
self->default_undersubtraction = DEFAULT_UNDERSUBTRACTION;
self->spectrum_type = SPECTRAL_TYPE_SPEECH;
self->band_type = CRITICAL_BANDS_TYPE_SPEECH;
self->gain_estimation_type = GAIN_ESTIMATION_TYPE_SPEECH;
self->time_smoothing_type = TIME_SMOOTHING_TYPE_SPEECH;
self->postfiltering_enabled = POSTFILTER_ENABLED_SPEECH;
self->whitening_enabled = WHITENING_ENABLED_SPEECH;
self->gain_spectrum = (float*)calloc(self->fft_size, sizeof(float));
if (!self->gain_spectrum) {
spectral_adaptive_denoiser_free(self);
return NULL;
}
(void)initialize_spectrum_with_value(self->gain_spectrum, self->fft_size,
1.F);
self->alpha = (float*)calloc(self->real_spectrum_size, sizeof(float));
if (!self->alpha) {
spectral_adaptive_denoiser_free(self);
return NULL;
}
(void)initialize_spectrum_with_value(self->alpha, self->real_spectrum_size,
1.F);
self->beta = (float*)calloc(self->real_spectrum_size, sizeof(float));
if (!self->beta) {
spectral_adaptive_denoiser_free(self);
return NULL;
}
self->noise_profile = (float*)calloc(self->real_spectrum_size, sizeof(float));
if (!self->noise_profile) {
spectral_adaptive_denoiser_free(self);
return NULL;
}
self->adaptive_estimator = louizou_estimator_initialize(
self->real_spectrum_size, sample_rate, fft_size);
if (!self->adaptive_estimator) {
spectral_adaptive_denoiser_free(self);
return NULL;
}
self->residual_spectrum = (float*)calloc((self->fft_size), sizeof(float));
if (!self->residual_spectrum) {
spectral_adaptive_denoiser_free(self);
return NULL;
}
self->denoised_spectrum = (float*)calloc((self->fft_size), sizeof(float));
if (!self->denoised_spectrum) {
spectral_adaptive_denoiser_free(self);
return NULL;
}
if (self->postfiltering_enabled) {
self->postfiltering = postfilter_initialize(self->fft_size);
if (!self->postfiltering) {
spectral_adaptive_denoiser_free(self);
return NULL;
}
}
self->spectrum_smoothing =
spectral_smoothing_initialize(self->fft_size, self->time_smoothing_type);
if (!self->spectrum_smoothing) {
spectral_adaptive_denoiser_free(self);
return NULL;
}
self->noise_scaling_criteria = noise_scaling_criterias_initialize(
self->fft_size, self->band_type, self->sample_rate, self->spectrum_type);
if (!self->noise_scaling_criteria) {
spectral_adaptive_denoiser_free(self);
return NULL;
}
self->spectral_features =
spectral_features_initialize(self->real_spectrum_size);
if (!self->spectral_features) {
spectral_adaptive_denoiser_free(self);
return NULL;
}
self->mixer =
denoise_mixer_initialize(self->fft_size, self->sample_rate, self->hop);
if (!self->mixer) {
spectral_adaptive_denoiser_free(self);
return NULL;
}
self->noise_floor_manager = noise_floor_manager_initialize(
self->fft_size, self->sample_rate, self->hop);
if (!self->noise_floor_manager) {
spectral_adaptive_denoiser_free(self);
return NULL;
}
return self;
}
void spectral_adaptive_denoiser_free(SpectralProcessorHandle instance) {
SpectralAdaptiveDenoiser* self = (SpectralAdaptiveDenoiser*)instance;
if (!self) {
return;
}
if (self->adaptive_estimator) {
if (self->parameters.noise_estimation_method == SPP_MMSE_METHOD) {
spp_mmse_estimator_free(self->adaptive_estimator);
} else {
louizou_estimator_free(self->adaptive_estimator);
}
}
if (self->spectral_features) {
spectral_features_free(self->spectral_features);
}
if (self->noise_scaling_criteria) {
noise_scaling_criterias_free(self->noise_scaling_criteria);
}
if (self->spectrum_smoothing) {
spectral_smoothing_free(self->spectrum_smoothing);
}
if (self->postfiltering) {
postfilter_free(self->postfiltering);
}
if (self->mixer) {
denoise_mixer_free(self->mixer);
}
if (self->residual_spectrum) {
free(self->residual_spectrum);
}
if (self->noise_floor_manager) {
noise_floor_manager_free(self->noise_floor_manager);
}
if (self->denoised_spectrum) {
free(self->denoised_spectrum);
}
if (self->noise_profile) {
free(self->noise_profile);
}
if (self->gain_spectrum) {
free(self->gain_spectrum);
}
if (self->alpha) {
free(self->alpha);
}
if (self->beta) {
free(self->beta);
}
free(self);
}
bool load_adaptive_reduction_parameters(SpectralProcessorHandle instance,
AdaptiveDenoiserParameters parameters) {
if (!instance) {
return false;
}
SpectralAdaptiveDenoiser* self = (SpectralAdaptiveDenoiser*)instance;
// Check if noise estimation method has changed
bool method_changed = (self->parameters.noise_estimation_method !=
parameters.noise_estimation_method);
self->parameters = parameters;
// If method changed, reinitialize the adaptive estimator
if (method_changed && self->adaptive_estimator) {
louizou_estimator_free(self->adaptive_estimator);
self->adaptive_estimator = NULL;
// Initialize the appropriate estimator based on the method
if (self->parameters.noise_estimation_method == SPP_MMSE_METHOD) {
self->adaptive_estimator = spp_mmse_estimator_initialize(
self->real_spectrum_size, self->sample_rate, self->fft_size);
} else {
// Default to Louizou method
self->adaptive_estimator = louizou_estimator_initialize(
self->real_spectrum_size, self->sample_rate, self->fft_size);
}
if (!self->adaptive_estimator) {
return false;
}
}
return true;
}
bool spectral_adaptive_denoiser_run(SpectralProcessorHandle instance,
float* fft_spectrum) {
if (!fft_spectrum || !instance) {
return false;
}
SpectralAdaptiveDenoiser* self = (SpectralAdaptiveDenoiser*)instance;
float* reference_spectrum =
get_spectral_feature(self->spectral_features, fft_spectrum,
self->fft_size, self->spectrum_type);
// Estimate noise using the selected method
if (self->parameters.noise_estimation_method == SPP_MMSE_METHOD) {
spp_mmse_estimator_run(self->adaptive_estimator, reference_spectrum,
self->noise_profile);
} else {
// Default to Louizou method
louizou_estimator_run(self->adaptive_estimator, reference_spectrum,
self->noise_profile);
}
float whitening_factor =
self->whitening_enabled ? self->parameters.whitening_factor : 0.0f;
// Scale estimated noise profile for oversubtraction
NoiseScalingParameters oversubtraction_parameters = (NoiseScalingParameters){
.oversubtraction =
self->default_oversubtraction + self->parameters.noise_rescale,
.undersubtraction = self->parameters.reduction_amount,
.scaling_type = self->parameters.noise_scaling_type,
};
apply_noise_scaling_criteria(self->noise_scaling_criteria, reference_spectrum,
self->noise_profile, self->alpha, self->beta,
oversubtraction_parameters);
TimeSmoothingParameters spectral_smoothing_parameters =
(TimeSmoothingParameters){
.smoothing = self->parameters.smoothing_factor,
};
spectral_smoothing_run(self->spectrum_smoothing,
spectral_smoothing_parameters, reference_spectrum);
estimate_gains(self->real_spectrum_size, self->fft_size, reference_spectrum,
self->noise_profile, self->gain_spectrum, self->alpha,
self->beta, self->gain_estimation_type);
noise_floor_manager_apply(
self->noise_floor_manager, self->real_spectrum_size, self->fft_size,
self->gain_spectrum, self->noise_profile,
self->parameters.reduction_amount, whitening_factor);
if (self->postfiltering_enabled) {
PostFiltersParameters post_filter_parameters = (PostFiltersParameters){
.snr_threshold = self->parameters.post_filter_threshold,
.gain_floor = self->parameters.reduction_amount,
};
postfilter_apply(self->postfiltering, fft_spectrum, self->gain_spectrum,
post_filter_parameters);
}
DenoiseMixerParameters mixer_parameters = (DenoiseMixerParameters){
.noise_level = self->parameters.reduction_amount,
.residual_listen = self->parameters.residual_listen,
.whitening_amount = whitening_factor,
};
denoise_mixer_run(self->mixer, fft_spectrum, self->gain_spectrum,
mixer_parameters);
return true;
}
@@ -0,0 +1,54 @@
/*
libspecbleach - A spectral processing library
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef SPECTRAL_ADAPTIVE_DENOISER_H
#define SPECTRAL_ADAPTIVE_DENOISER_H
#include "shared/spectral_processor.h"
#include <stdbool.h>
#include <stdint.h>
#include "shared/noise_estimation/adaptive_noise_estimator.h"
typedef struct AdaptiveDenoiserParameters {
float reduction_amount;
int noise_scaling_type;
float noise_rescale;
float smoothing_factor;
float whitening_factor;
float post_filter_threshold;
bool residual_listen;
/* Method used for adaptive noise estimation.
* LOUIZOU_METHOD uses minimum statistics (default), SPP_MMSE_METHOD uses
* Speech Presence Probability with MMSE estimation for lower complexity
* and unbiased noise tracking. */
AdaptiveNoiseEstimationMethod noise_estimation_method;
} AdaptiveDenoiserParameters;
SpectralProcessorHandle spectral_adaptive_denoiser_initialize(
uint32_t sample_rate, uint32_t fft_size, uint32_t overlap_factor);
void spectral_adaptive_denoiser_free(SpectralProcessorHandle instance);
bool load_adaptive_reduction_parameters(SpectralProcessorHandle instance,
AdaptiveDenoiserParameters parameters);
bool spectral_adaptive_denoiser_run(SpectralProcessorHandle instance,
float* fft_spectrum);
#endif
@@ -0,0 +1,317 @@
/*
libspecbleach - A spectral processing library
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "spectral_denoiser.h"
#include "shared/configurations.h"
#include "shared/gain_estimation/gain_estimators.h"
#include "shared/noise_estimation/noise_estimator.h"
#include "shared/post_estimation/noise_floor_manager.h"
#include "shared/post_estimation/postfilter.h"
#include "shared/pre_estimation/critical_bands.h"
#include "shared/pre_estimation/noise_scaling_criterias.h"
#include "shared/pre_estimation/spectral_smoother.h"
#include "shared/utils/denoise_mixer.h"
#include "shared/utils/spectral_features.h"
#include "shared/utils/spectral_utils.h"
#include <float.h>
#include <stdlib.h>
#include <string.h>
typedef struct SbSpectralDenoiser {
uint32_t fft_size;
uint32_t real_spectrum_size;
uint32_t sample_rate;
uint32_t hop;
float default_oversubtraction;
float default_undersubtraction;
float* gain_spectrum;
float* alpha;
float* beta;
float* noise_spectrum;
SpectrumType spectrum_type;
CriticalBandType band_type;
DenoiserParameters denoise_parameters;
GainEstimationType gain_estimation_type;
TimeSmoothingType time_smoothing_type;
NoiseEstimatorType noise_estimator_type;
NoiseEstimator* noise_estimator;
PostFilter* postfiltering;
NoiseProfile* noise_profile;
SpectralFeatures* spectral_features;
DenoiseMixer* mixer;
NoiseScalingCriterias* noise_scaling_criteria;
SpectralSmoother* spectrum_smoothing;
NoiseFloorManager* noise_floor_manager;
bool postfiltering_enabled;
bool whitening_enabled;
} SbSpectralDenoiser;
SpectralProcessorHandle spectral_denoiser_initialize(
const uint32_t sample_rate, const uint32_t fft_size,
const uint32_t overlap_factor, NoiseProfile* noise_profile) {
if (!noise_profile || sample_rate == 0 || fft_size == 0 ||
overlap_factor == 0) {
return NULL;
}
SbSpectralDenoiser* self =
(SbSpectralDenoiser*)calloc(1U, sizeof(SbSpectralDenoiser));
if (!self) {
return NULL;
}
self->fft_size = fft_size;
self->real_spectrum_size = (self->fft_size / 2U) + 1U;
self->hop = self->fft_size / overlap_factor;
self->sample_rate = sample_rate;
self->spectrum_type = SPECTRAL_TYPE_GENERAL;
self->band_type = CRITICAL_BANDS_TYPE;
self->default_oversubtraction = DEFAULT_OVERSUBTRACTION;
self->default_undersubtraction = DEFAULT_UNDERSUBTRACTION;
self->gain_estimation_type = GAIN_ESTIMATION_TYPE;
self->time_smoothing_type = TIME_SMOOTHING_TYPE;
self->postfiltering_enabled = POSTFILTER_ENABLED_GENERAL;
self->whitening_enabled = WHITENING_ENABLED_GENERAL;
self->gain_spectrum = (float*)calloc(self->fft_size, sizeof(float));
if (!self->gain_spectrum) {
spectral_denoiser_free(self);
return NULL;
}
(void)initialize_spectrum_with_value(self->gain_spectrum, self->fft_size,
1.F);
self->alpha = (float*)calloc(self->real_spectrum_size, sizeof(float));
if (!self->alpha) {
spectral_denoiser_free(self);
return NULL;
}
(void)initialize_spectrum_with_value(self->alpha, self->real_spectrum_size,
1.F);
self->beta = (float*)calloc(self->real_spectrum_size, sizeof(float));
if (!self->beta) {
spectral_denoiser_free(self);
return NULL;
}
self->noise_profile = noise_profile;
self->noise_spectrum =
(float*)calloc(self->real_spectrum_size, sizeof(float));
if (!self->noise_spectrum) {
spectral_denoiser_free(self);
return NULL;
}
self->noise_estimator =
noise_estimation_initialize(self->fft_size, noise_profile);
if (!self->noise_estimator) {
spectral_denoiser_free(self);
return NULL;
}
self->spectral_features =
spectral_features_initialize(self->real_spectrum_size);
if (!self->spectral_features) {
spectral_denoiser_free(self);
return NULL;
}
if (self->postfiltering_enabled) {
self->postfiltering = postfilter_initialize(self->fft_size);
if (!self->postfiltering) {
spectral_denoiser_free(self);
return NULL;
}
}
self->spectrum_smoothing =
spectral_smoothing_initialize(self->fft_size, self->time_smoothing_type);
if (!self->spectrum_smoothing) {
spectral_denoiser_free(self);
return NULL;
}
self->noise_scaling_criteria = noise_scaling_criterias_initialize(
self->fft_size, self->band_type, self->sample_rate, self->spectrum_type);
if (!self->noise_scaling_criteria) {
spectral_denoiser_free(self);
return NULL;
}
self->mixer =
denoise_mixer_initialize(self->fft_size, self->sample_rate, self->hop);
if (!self->mixer) {
spectral_denoiser_free(self);
return NULL;
}
self->noise_floor_manager = noise_floor_manager_initialize(
self->fft_size, self->sample_rate, self->hop);
if (!self->noise_floor_manager) {
spectral_denoiser_free(self);
return NULL;
}
return self;
}
void spectral_denoiser_free(SpectralProcessorHandle instance) {
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
if (!self) {
return;
}
// Don't free noise profile used as reference here
if (self->noise_estimator) {
noise_estimation_free(self->noise_estimator);
}
if (self->spectral_features) {
spectral_features_free(self->spectral_features);
}
if (self->spectrum_smoothing) {
spectral_smoothing_free(self->spectrum_smoothing);
}
if (self->noise_scaling_criteria) {
noise_scaling_criterias_free(self->noise_scaling_criteria);
}
if (self->postfiltering) {
postfilter_free(self->postfiltering);
}
if (self->mixer) {
denoise_mixer_free(self->mixer);
}
if (self->gain_spectrum) {
free(self->gain_spectrum);
}
if (self->noise_floor_manager) {
noise_floor_manager_free(self->noise_floor_manager);
}
if (self->alpha) {
free(self->alpha);
}
if (self->beta) {
free(self->beta);
}
if (self->noise_spectrum) {
free(self->noise_spectrum);
}
free(self);
}
bool load_reduction_parameters(SpectralProcessorHandle instance,
DenoiserParameters parameters) {
if (!instance) {
return false;
}
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
self->denoise_parameters = parameters;
return true;
}
bool spectral_denoiser_run(SpectralProcessorHandle instance,
float* fft_spectrum) {
if (!fft_spectrum || !instance) {
return false;
}
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
float* reference_spectrum =
get_spectral_feature(self->spectral_features, fft_spectrum,
self->fft_size, self->spectrum_type);
if (self->denoise_parameters.learn_noise > 0) {
// Learn all modes simultaneously
for (int mode = ROLLING_MEAN; mode <= MAX; mode++) {
noise_estimation_run(self->noise_estimator, (NoiseEstimatorType)mode,
reference_spectrum);
}
} else if (is_noise_estimation_available(
self->noise_profile,
self->denoise_parameters.noise_reduction_mode)) {
memcpy(self->noise_spectrum,
get_noise_profile(self->noise_profile,
self->denoise_parameters.noise_reduction_mode),
self->real_spectrum_size * sizeof(float));
NoiseScalingParameters oversubtraction_parameters =
(NoiseScalingParameters){
.oversubtraction = (self->default_oversubtraction +
self->denoise_parameters.noise_rescale),
.undersubtraction = self->denoise_parameters.reduction_amount,
.scaling_type = self->denoise_parameters.noise_scaling_type,
};
float whitening_factor = self->whitening_enabled
? self->denoise_parameters.whitening_factor
: 0.0f;
apply_noise_scaling_criteria(
self->noise_scaling_criteria, reference_spectrum, self->noise_spectrum,
self->alpha, self->beta, oversubtraction_parameters);
TimeSmoothingParameters spectral_smoothing_parameters =
(TimeSmoothingParameters){
.smoothing = self->denoise_parameters.smoothing_factor,
};
spectral_smoothing_run(self->spectrum_smoothing,
spectral_smoothing_parameters, reference_spectrum);
estimate_gains(self->real_spectrum_size, self->fft_size, reference_spectrum,
self->noise_spectrum, self->gain_spectrum, self->alpha,
self->beta, self->gain_estimation_type);
noise_floor_manager_apply(
self->noise_floor_manager, self->real_spectrum_size, self->fft_size,
self->gain_spectrum, self->noise_spectrum,
self->denoise_parameters.reduction_amount, whitening_factor);
if (self->postfiltering_enabled) {
PostFiltersParameters post_filter_parameters = (PostFiltersParameters){
.snr_threshold = self->denoise_parameters.post_filter_threshold,
.gain_floor = self->denoise_parameters.reduction_amount,
};
postfilter_apply(self->postfiltering, fft_spectrum, self->gain_spectrum,
post_filter_parameters);
}
DenoiseMixerParameters mixer_parameters = (DenoiseMixerParameters){
.noise_level = self->denoise_parameters.reduction_amount,
.residual_listen = self->denoise_parameters.residual_listen,
.whitening_amount = whitening_factor,
};
denoise_mixer_run(self->mixer, fft_spectrum, self->gain_spectrum,
mixer_parameters);
}
return true;
}
@@ -0,0 +1,50 @@
/*
libspecbleach - A spectral processing library
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef SPECTRAL_DENOISER_H
#define SPECTRAL_DENOISER_H
#include "shared/noise_estimation/noise_profile.h"
#include "shared/spectral_processor.h"
#include <stdbool.h>
#include <stdint.h>
typedef struct DenoiserParameters {
float reduction_amount;
int noise_scaling_type;
float noise_rescale;
bool residual_listen;
int learn_noise;
int noise_reduction_mode;
float smoothing_factor;
float whitening_factor;
float post_filter_threshold;
} DenoiserParameters;
SpectralProcessorHandle spectral_denoiser_initialize(
uint32_t sample_rate, uint32_t fft_size, uint32_t overlap_factor,
NoiseProfile* noise_profile);
void spectral_denoiser_free(SpectralProcessorHandle instance);
bool load_reduction_parameters(SpectralProcessorHandle instance,
DenoiserParameters parameters);
bool spectral_denoiser_run(SpectralProcessorHandle instance,
float* fft_spectrum);
#endif
+6
View File
@@ -0,0 +1,6 @@
processors_sources = files(
'denoiser/spectral_denoiser.c',
'adaptivedenoiser/adaptive_denoiser.c',
'specbleach_adenoiser.c',
'specbleach_denoiser.c',
)
@@ -0,0 +1,137 @@
/*
libspecbleach - A spectral processing library
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "specbleach_adenoiser.h"
#include "adaptivedenoiser/adaptive_denoiser.h"
#include "shared/configurations.h"
#include "shared/stft/stft_processor.h"
#include "shared/utils/general_utils.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
typedef struct SbAdaptiveDenoiser {
uint32_t sample_rate;
AdaptiveDenoiserParameters denoise_parameters;
SpectralProcessorHandle adaptive_spectral_denoiser;
StftProcessor* stft_processor;
} SbAdaptiveDenoiser;
SpectralBleachHandle specbleach_adaptive_initialize(const uint32_t sample_rate,
float frame_size) {
SbAdaptiveDenoiser* self =
(SbAdaptiveDenoiser*)calloc(1U, sizeof(SbAdaptiveDenoiser));
if (!self) {
return NULL;
}
self->sample_rate = sample_rate;
self->stft_processor = stft_processor_initialize(
sample_rate, frame_size, OVERLAP_FACTOR_SPEECH,
PADDING_CONFIGURATION_SPEECH, ZEROPADDING_AMOUNT_SPEECH,
INPUT_WINDOW_TYPE_SPEECH, OUTPUT_WINDOW_TYPE_SPEECH);
if (!self->stft_processor) {
specbleach_adaptive_free(self);
return NULL;
}
const uint32_t fft_size = get_stft_fft_size(self->stft_processor);
self->adaptive_spectral_denoiser = spectral_adaptive_denoiser_initialize(
self->sample_rate, fft_size, OVERLAP_FACTOR_SPEECH);
if (!self->adaptive_spectral_denoiser) {
specbleach_adaptive_free(self);
return NULL;
}
return self;
}
void specbleach_adaptive_free(SpectralBleachHandle instance) {
SbAdaptiveDenoiser* self = (SbAdaptiveDenoiser*)instance;
if (!self) {
return;
}
if (self->adaptive_spectral_denoiser) {
spectral_adaptive_denoiser_free(self->adaptive_spectral_denoiser);
}
if (self->stft_processor) {
stft_processor_free(self->stft_processor);
}
free(self);
}
uint32_t specbleach_adaptive_get_latency(SpectralBleachHandle instance) {
SbAdaptiveDenoiser* self = (SbAdaptiveDenoiser*)instance;
return get_stft_latency(self->stft_processor);
}
bool specbleach_adaptive_process(SpectralBleachHandle instance,
const uint32_t number_of_samples,
const float* input, float* output) {
if (!instance || number_of_samples == 0 || !input || !output) {
return false;
}
SbAdaptiveDenoiser* self = (SbAdaptiveDenoiser*)instance;
stft_processor_run(self->stft_processor, number_of_samples, input, output,
&spectral_adaptive_denoiser_run,
self->adaptive_spectral_denoiser);
return true;
}
bool specbleach_adaptive_load_parameters(
SpectralBleachHandle instance,
SpectralBleachAdaptiveParameters parameters) {
if (!instance) {
return false;
}
SbAdaptiveDenoiser* self = (SbAdaptiveDenoiser*)instance;
// clang-format off
self->denoise_parameters = (AdaptiveDenoiserParameters){
.residual_listen = parameters.residual_listen,
.reduction_amount =
from_db_to_coefficient(parameters.reduction_amount * -1.F),
.noise_rescale = from_db_to_coefficient(parameters.noise_rescale),
.noise_scaling_type = parameters.noise_scaling_type,
.smoothing_factor = remap_percentage_log_like_unity(parameters.smoothing_factor / 100.F),
.whitening_factor = parameters.whitening_factor / 100.F,
.post_filter_threshold = from_db_to_coefficient(parameters.post_filter_threshold),
.noise_estimation_method = parameters.noise_estimation_method,
};
// clang-format on
load_adaptive_reduction_parameters(self->adaptive_spectral_denoiser,
self->denoise_parameters);
return true;
}
Binary file not shown.
@@ -0,0 +1,277 @@
/*
libspecbleach - A spectral processing library
Copyright 2022 Luciano Dato <lucianodato@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "specbleach_denoiser.h"
#include "denoiser/spectral_denoiser.h"
#include "shared/configurations.h"
#include "shared/noise_estimation/noise_profile.h"
#include "shared/stft/stft_processor.h"
#include "shared/utils/general_utils.h"
#include <stdlib.h>
#include <string.h>
typedef struct SbSpectralDenoiser {
uint32_t sample_rate;
DenoiserParameters denoise_parameters;
NoiseProfile* noise_profile;
SpectralProcessorHandle spectral_denoiser;
StftProcessor* stft_processor;
} SbSpectralDenoiser;
SpectralBleachHandle specbleach_initialize(const uint32_t sample_rate,
float frame_size) {
if (sample_rate < 4000 || sample_rate > 192000 || frame_size <= 0.0f) {
return NULL;
}
SbSpectralDenoiser* self =
(SbSpectralDenoiser*)calloc(1U, sizeof(SbSpectralDenoiser));
if (!self) {
return NULL;
}
self->sample_rate = sample_rate;
self->stft_processor = stft_processor_initialize(
sample_rate, frame_size, OVERLAP_FACTOR_GENERAL,
PADDING_CONFIGURATION_GENERAL, ZEROPADDING_AMOUNT_GENERAL,
INPUT_WINDOW_TYPE_GENERAL, OUTPUT_WINDOW_TYPE_GENERAL);
if (!self->stft_processor) {
specbleach_free(self);
return NULL;
}
const uint32_t fft_size = get_stft_fft_size(self->stft_processor);
const uint32_t real_spectrum_size =
get_stft_real_spectrum_size(self->stft_processor);
self->noise_profile = noise_profile_initialize(real_spectrum_size);
if (!self->noise_profile) {
specbleach_free(self);
return NULL;
}
self->spectral_denoiser = spectral_denoiser_initialize(
self->sample_rate, fft_size, OVERLAP_FACTOR_GENERAL, self->noise_profile);
if (!self->spectral_denoiser) {
specbleach_free(self);
return NULL;
}
return self;
}
void specbleach_free(SpectralBleachHandle instance) {
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
if (!self) {
return;
}
if (self->noise_profile) {
noise_profile_free(self->noise_profile);
}
if (self->spectral_denoiser) {
spectral_denoiser_free(self->spectral_denoiser);
}
if (self->stft_processor) {
stft_processor_free(self->stft_processor);
}
free(self);
}
uint32_t specbleach_get_latency(SpectralBleachHandle instance) {
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
if (!self || !self->stft_processor) {
return 0;
}
return get_stft_latency(self->stft_processor);
}
bool specbleach_process(SpectralBleachHandle instance,
const uint32_t number_of_samples, const float* input,
float* output) {
if (!instance || number_of_samples == 0 || !input || !output) {
return false;
}
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
stft_processor_run(self->stft_processor, number_of_samples, input, output,
&spectral_denoiser_run, self->spectral_denoiser);
return true;
}
uint32_t specbleach_get_noise_profile_size(SpectralBleachHandle instance) {
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
if (!self || !self->noise_profile) {
return 0;
}
return get_noise_profile_size(self->noise_profile);
}
uint32_t specbleach_get_noise_profile_blocks_averaged(
SpectralBleachHandle instance) {
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
if (!self || !self->noise_profile) {
return 0;
}
return get_noise_profile_blocks_averaged(
self->noise_profile, self->denoise_parameters.noise_reduction_mode);
}
float* specbleach_get_noise_profile(SpectralBleachHandle instance) {
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
if (!self || !self->noise_profile) {
return NULL;
}
return get_noise_profile(self->noise_profile,
self->denoise_parameters.noise_reduction_mode);
}
bool specbleach_load_noise_profile(SpectralBleachHandle instance,
const float* restored_profile,
const uint32_t profile_size,
const uint32_t averaged_blocks) {
if (!instance || !restored_profile) {
return false;
}
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
if (profile_size != get_noise_profile_size(self->noise_profile)) {
return false;
}
set_noise_profile(self->noise_profile,
self->denoise_parameters.noise_reduction_mode,
restored_profile, profile_size, averaged_blocks);
return true;
}
bool specbleach_load_noise_profile_for_mode(SpectralBleachHandle instance,
const float* restored_profile,
const uint32_t profile_size,
const uint32_t averaged_blocks,
const int mode) {
if (!instance || !restored_profile || mode < 1 || mode > 3) {
return false;
}
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
if (profile_size != get_noise_profile_size(self->noise_profile)) {
return false;
}
set_noise_profile(self->noise_profile, mode, restored_profile, profile_size,
averaged_blocks);
return true;
}
bool specbleach_reset_noise_profile(SpectralBleachHandle instance) {
if (!instance) {
return false;
}
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
reset_noise_profile(self->noise_profile);
return true;
}
bool specbleach_noise_profile_available(SpectralBleachHandle instance) {
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
return is_noise_estimation_available(
self->noise_profile, self->denoise_parameters.noise_reduction_mode);
}
uint32_t specbleach_get_noise_profile_blocks_averaged_for_mode(
SpectralBleachHandle instance, int mode) {
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
if (!self || mode < 1 || mode > 3) {
return 0;
}
return get_noise_profile_blocks_averaged(self->noise_profile, mode);
}
float* specbleach_get_noise_profile_for_mode(SpectralBleachHandle instance,
int mode) {
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
if (!self || mode < 1 || mode > 3) {
return NULL;
}
return get_noise_profile(self->noise_profile, mode);
}
bool specbleach_noise_profile_available_for_mode(SpectralBleachHandle instance,
int mode) {
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
if (!self || mode < 1 || mode > 3) {
return false;
}
return is_noise_estimation_available(self->noise_profile, mode);
}
bool specbleach_load_parameters(SpectralBleachHandle instance,
SpectralBleachDenoiserParameters parameters) {
if (!instance) {
return false;
}
SbSpectralDenoiser* self = (SbSpectralDenoiser*)instance;
// clang-format off
self->denoise_parameters = (DenoiserParameters){
.learn_noise = parameters.learn_noise,
.noise_reduction_mode = parameters.noise_reduction_mode,
.residual_listen = parameters.residual_listen,
.noise_scaling_type = parameters.noise_scaling_type,
.reduction_amount =
from_db_to_coefficient(parameters.reduction_amount * -1.F),
.noise_rescale = from_db_to_coefficient(parameters.noise_rescale),
.smoothing_factor = remap_percentage_log_like_unity(parameters.smoothing_factor / 100.F),
.whitening_factor = parameters.whitening_factor / 100.F,
.post_filter_threshold = from_db_to_coefficient(parameters.post_filter_threshold),
};
// clang-format on
load_reduction_parameters(self->spectral_denoiser, self->denoise_parameters);
return true;
}
Binary file not shown.