Skip to content
Merged
12 changes: 2 additions & 10 deletions examples/denoiser_demo.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ static void print_usage(const char* prog_name) {
fprintf(stderr, " --smoothing <val> Smoothing factor (default: 0.0)\n");
fprintf(stderr,
" --masking-depth <val> Masking depth (0.0-1.0, default: 0.5)\n");
fprintf(stderr,
" --masking-elasticity <val> Masking elasticity (0.0-1.0, default: "
"0.1)\n");
fprintf(stderr,
" --learn-avg <val> Learn average mode (0-3, default: 3)\n");
fprintf(stderr, " --adaptive Enable adaptive noise estimation\n");
Expand Down Expand Up @@ -99,15 +96,13 @@ int main(int argc, char** argv) {
.reduction_amount = 20.F,
.smoothing_factor = 0.F,
.whitening_factor = 50.F,
.masking_depth = 0.5F,
.masking_elasticity = 0.1F};
.masking_depth = 0.5F};

static struct option long_options[] = {
{"reduction", required_argument, 0, 'r'},
{"whitening", required_argument, 0, 'w'},
{"smoothing", required_argument, 0, 's'},
{"masking-depth", required_argument, 0, 'd'},
{"masking-elasticity", required_argument, 0, 'e'},
{"steering-response", required_argument, 0, 'l'},
{"adaptive", no_argument, 0, 'a'},
{"noise-method", required_argument, 0, 'm'},
Expand All @@ -119,7 +114,7 @@ int main(int argc, char** argv) {
float frame_size_ms = FRAME_SIZE;
uint32_t learn_frames = NOISE_FRAMES;
int opt;
while ((opt = getopt_long(argc, argv, "r:w:s:d:e:l:am:f:n:", long_options,
while ((opt = getopt_long(argc, argv, "r:w:s:d:l:am:f:n:", long_options,
NULL)) != -1) {
switch (opt) {
case 'r':
Expand All @@ -134,9 +129,6 @@ int main(int argc, char** argv) {
case 'd':
parameters.masking_depth = (float)atof(optarg);
break;
case 'e':
parameters.masking_elasticity = (float)atof(optarg);
break;
case 'l':
parameters.aggressiveness = (float)atof(optarg);
break;
Expand Down
5 changes: 0 additions & 5 deletions include/specbleach_2d_denoiser.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,6 @@ typedef struct SpectralBleach2DDenoiserParameters {
*/
float nlm_masking_protection;

/**
Range: 0.0 (Pure masking) to 1.0 (Bypass protection).
*/
float masking_elasticity;

/** Sets the suppression aggressiveness (0-100%).
* Controls the SNR-dependent oversubtraction factor.
*/
Expand Down
3 changes: 1 addition & 2 deletions include/specbleach_denoiser.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ typedef struct SpectralBleachDenoiserParameters {
int noise_estimation_method;

/** Masking Veto depth (0.0 - 1.0) */
float masking_depth; // 0.0 - 1.0: Depth of signal energy preservation
float masking_elasticity; // 0.0 - 1.0: Tolerance for model inaccuracies
float masking_depth; // 0.0 - 1.0: Depth of signal energy preservation

/** Suppression aggressiveness (0.0 - 1.0) */
float suppression_strength; // 0.0 - 1.0: Berouti oversubtraction factor
Expand Down
34 changes: 11 additions & 23 deletions src/processors/denoiser/spectral_denoiser.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ typedef struct SbSpectralDenoiser {
float* beta;
float* noise_spectrum;
float* manual_noise_floor;
float* noisy_reference;

TonalReducer* tonal_reducer;

Expand Down Expand Up @@ -115,10 +114,7 @@ SpectralProcessorHandle spectral_denoiser_initialize(

self->manual_noise_floor =
(float*)calloc(self->real_spectrum_size, sizeof(float));
self->noisy_reference =
(float*)calloc(self->real_spectrum_size, sizeof(float));

if (!self->manual_noise_floor || !self->noisy_reference) {
if (!self->manual_noise_floor) {
spectral_denoiser_free(self);
return NULL;
}
Expand All @@ -144,8 +140,8 @@ SpectralProcessorHandle spectral_denoiser_initialize(
return NULL;
}

self->spectrum_smoothing =
spectral_smoothing_initialize(self->fft_size, self->time_smoothing_type);
self->spectrum_smoothing = spectral_smoothing_initialize(
self->fft_size, self->sample_rate, self->time_smoothing_type);
if (!self->spectrum_smoothing) {
spectral_denoiser_free(self);
return NULL;
Expand All @@ -159,10 +155,11 @@ SpectralProcessorHandle spectral_denoiser_initialize(
self->denoise_parameters.tonal_reduction = 0.0f;

self->masking_veto = masking_veto_initialize(
self->fft_size, self->sample_rate, self->band_type, self->spectrum_type);
self->suppression_engine =
suppression_engine_initialize(self->real_spectrum_size, self->sample_rate,
self->band_type, self->spectrum_type);
self->fft_size, self->sample_rate, CRITICAL_BANDS_TYPE_1D,
self->spectrum_type, false, USE_TEMPORAL_MASKING_1D_DEFAULT);
self->suppression_engine = suppression_engine_initialize(
self->real_spectrum_size, self->sample_rate, self->band_type,
self->spectrum_type, true, USE_TEMPORAL_MASKING_1D_DEFAULT);

if (!self->noise_floor_manager || !self->masking_veto ||
!self->suppression_engine) {
Expand Down Expand Up @@ -219,9 +216,7 @@ void spectral_denoiser_free(SpectralProcessorHandle instance) {
if (self->manual_noise_floor) {
free(self->manual_noise_floor);
}
if (self->noisy_reference) {
free(self->noisy_reference);
}

if (self->tonal_reducer) {
tonal_reducer_free(self->tonal_reducer);
}
Expand Down Expand Up @@ -296,11 +291,6 @@ bool spectral_denoiser_run(SpectralProcessorHandle instance,

// 3. Denoising Stage: Calculate gains and apply psychoacoustic constraints

// Preservation of 'noisy' reference before temporal smoothing for Veto
// comparison
memcpy(self->noisy_reference, reference_spectrum,
self->real_spectrum_size * sizeof(float));

// 3.1. Calculate SNR-dependent oversubtraction factors (Alpha/Beta)
SuppressionParameters suppression_params = {
.type = SUPPRESSION_BEROUTI_PER_BIN,
Expand All @@ -326,10 +316,8 @@ bool spectral_denoiser_run(SpectralProcessorHandle instance,

// 3.4. Apply Structural Veto to rescue transients and moderate artifacts
masking_veto_apply(self->masking_veto, reference_spectrum,
self->noisy_reference, self->noise_spectrum, self->alpha,
MASKING_VETO_ALPHA_FLOOR,
self->denoise_parameters.masking_depth,
self->denoise_parameters.masking_elasticity);
self->noise_spectrum, NULL, self->alpha,
self->denoise_parameters.masking_depth);

// 3.5. Final Gain Calculation
calculate_gains(self->real_spectrum_size, self->fft_size, reference_spectrum,
Expand Down
1 change: 0 additions & 1 deletion src/processors/denoiser/spectral_denoiser.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ typedef struct DenoiserParameters {
int adaptive_noise;
int noise_estimation_method; /**< 0=SPP-MMSE, 1=Brandt, 2=Martin MS */
float masking_depth;
float masking_elasticity;
float suppression_strength;
float aggressiveness; /**< -1.0 (Median/Min) to 1.0 (Max), 0.0 (Mean) */
float tonal_reduction; /**< 0.0 to 1.0 (Phase 3) */
Expand Down
32 changes: 11 additions & 21 deletions src/processors/denoiser2d/spectral_2d_denoiser.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ typedef struct Spectral2DDenoiser {
SbSpectralCircularBuffer* circular_buffer;
uint32_t layer_fft;
uint32_t layer_noise;
uint32_t layer_magnitude;

SpectrumType spectrum_type;
GainCalculationType gain_calculation_type;
Expand Down Expand Up @@ -167,13 +166,10 @@ SpectralProcessorHandle spectral_2d_denoiser_initialize(

self->layer_fft =
spectral_circular_buffer_add_layer(self->circular_buffer, self->fft_size);
self->layer_magnitude = spectral_circular_buffer_add_layer(
self->circular_buffer, self->real_spectrum_size);
self->layer_noise = spectral_circular_buffer_add_layer(
self->circular_buffer, self->real_spectrum_size);

if (self->layer_fft == 0xFFFFFFFF || self->layer_magnitude == 0xFFFFFFFF ||
self->layer_noise == 0xFFFFFFFF) {
if (self->layer_fft == 0xFFFFFFFF || self->layer_noise == 0xFFFFFFFF) {
spectral_2d_denoiser_free(self);
return NULL;
}
Expand Down Expand Up @@ -216,21 +212,21 @@ SpectralProcessorHandle spectral_2d_denoiser_initialize(
return NULL;
}

self->masking_veto =
masking_veto_initialize(self->fft_size, self->sample_rate,
CRITICAL_BANDS_TYPE_2D, self->spectrum_type);
self->masking_veto = masking_veto_initialize(
self->fft_size, self->sample_rate, CRITICAL_BANDS_TYPE_2D,
self->spectrum_type, false, USE_TEMPORAL_MASKING_2D_DEFAULT);
self->suppression_engine = suppression_engine_initialize(
self->real_spectrum_size, self->sample_rate, CRITICAL_BANDS_TYPE_2D,
self->spectrum_type);
self->spectrum_type, true, USE_TEMPORAL_MASKING_2D_DEFAULT);

if (!self->masking_veto || !self->suppression_engine) {
spectral_2d_denoiser_free(self);
return NULL;
}

// Initialize noise floor manager
self->noise_floor_manager =
noise_floor_manager_initialize(fft_size, sample_rate, self->hop);

if (!self->noise_floor_manager) {
spectral_2d_denoiser_free(self);
return NULL;
Expand Down Expand Up @@ -362,13 +358,10 @@ bool spectral_2d_denoiser_run(SpectralProcessorHandle instance,
// 2.1 Align internal state and output to the delayed frame (temporal
// plumbing)
float* delayed_noise = NULL;
float* delayed_magnitude_spectrum = NULL;

// 2.1.1 Push current spectra to circular buffer
spectral_circular_buffer_push(self->circular_buffer, self->layer_fft,
fft_spectrum);
spectral_circular_buffer_push(self->circular_buffer, self->layer_magnitude,
reference_spectrum);
spectral_circular_buffer_push(self->circular_buffer, self->layer_noise,
self->noise_spectrum);

Expand All @@ -381,9 +374,6 @@ bool spectral_2d_denoiser_run(SpectralProcessorHandle instance,
delayed_noise = spectral_circular_buffer_retrieve(
self->circular_buffer, self->layer_noise, delay_frames);

delayed_magnitude_spectrum = spectral_circular_buffer_retrieve(
self->circular_buffer, self->layer_magnitude, delay_frames);

// 2.1.3 Align output to the delayed frame by default (Passthrough)
memcpy(fft_spectrum, delayed_spectrum, self->fft_size * sizeof(float));

Expand Down Expand Up @@ -421,11 +411,11 @@ bool spectral_2d_denoiser_run(SpectralProcessorHandle instance,

// 3.3.4 Apply psychoacoustic veto to preserve transients and moderate
// artifacts
masking_veto_apply(self->masking_veto, smoothed_magnitude,
delayed_magnitude_spectrum, delayed_noise, self->alpha,
MASKING_VETO_ALPHA_FLOOR,
self->parameters.nlm_masking_protection,
self->parameters.masking_elasticity);
// We pass the CURRENT spectrum (fft_spectrum) as the lookahead for the
// DELAYED frame being processed.
masking_veto_apply(self->masking_veto, smoothed_magnitude, delayed_noise,
fft_spectrum, self->alpha,
self->parameters.nlm_masking_protection);

// 3.3.5 Final Gain Calculation
calculate_gains(self->real_spectrum_size, self->fft_size,
Expand Down
1 change: 0 additions & 1 deletion src/processors/denoiser2d/spectral_2d_denoiser.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ typedef struct Denoiser2DParameters {
int adaptive_noise; /**< Adaptive noise mode: 0=disabled, 1=enabled */
int noise_estimation_method; /**< 0=SPP-MMSE, 1=Brandt, 2=Martin MS */
float nlm_masking_protection; /**< Masking protection depth (0.0 to 1.0) */
float masking_elasticity; /**< Masking elasticity (0.0 to 1.0) */
float suppression_strength; /**< Suppression aggressiveness (0.0 to 1.0) */
float aggressiveness; /**< -1.0 (Median/Min) to 1.0 (Max), 0.0 (Mean) */
float tonal_reduction; /**< 0.0 to 1.0 (Phase 3) */
Expand Down
1 change: 0 additions & 1 deletion src/processors/specbleach_2d_denoiser.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,6 @@ bool specbleach_2d_load_parameters(
.adaptive_noise = parameters.adaptive_noise,
.noise_estimation_method = parameters.noise_estimation_method,
.nlm_masking_protection = parameters.nlm_masking_protection,
.masking_elasticity = parameters.masking_elasticity,
.suppression_strength = parameters.suppression_strength / 100.F,
.aggressiveness = parameters.aggressiveness,
.tonal_reduction =
Expand Down
1 change: 0 additions & 1 deletion src/processors/specbleach_denoiser.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@ bool specbleach_load_parameters(SpectralBleachHandle instance,
.adaptive_noise = parameters.adaptive_noise,
.noise_estimation_method = parameters.noise_estimation_method,
.masking_depth = parameters.masking_depth,
.masking_elasticity = parameters.masking_elasticity,
.suppression_strength = parameters.suppression_strength / 100.F,
.aggressiveness = parameters.aggressiveness,
.tonal_reduction =
Expand Down
58 changes: 42 additions & 16 deletions src/shared/configurations.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,25 +58,42 @@ _Static_assert(sizeof(uint32_t) == 4, "uint32_t must be exactly 32 bits");
#define REFERENCE_LEVEL (90.F)
#define SINE_AMPLITUDE (1.F)

// Masking Thresholds
#define BIAS false
#define HIGH_FREQ_BIAS 20.F
#if BIAS
// clang-format off
#define relative_thresholds \
(float[25]){-16.F, -17.F, -18.F, -19.F, -20.F, -21.F, -22.F, -23.F, -24.F, \
-25.F, -25.F, -25.F, -25.F, -25.F, -25.F, -24.F, -23.F, -22.F, \
-19.F, -18.F, -18.F, -18.F, -18.F, -18.F, -18.F}
// clang-format on
#endif
// Johnston Psychoacoustic Model (1988)
#define DB_FS_TO_SPL_REF 96.0F // 0dBFS -> 96dB SPL reference level
#define POWER_LAW_EXPONENT (0.6F) // Johnston power-law integration exponent

// Default Additivity Exponents
#define SPECTRAL_ADDITIVITY_EXPONENT_STANDARD (1.0F) // Pure Johnston
#define SPECTRAL_ADDITIVITY_EXPONENT_PEAQ (0.4F) // Advanced precision

// Schroeder spreading function constants
#define S_MIN_UPWARD (5.0F) // Minimum upward spreading slope (dB/Bark)
#define S_MAX_UPWARD (15.0F) // Maximum upward spreading slope (dB/Bark)
#define S_DOWNWARD (25.0F) // Constant downward spreading slope (dB/Bark)

// Threshold Offsets (NMT = Noise-Masking-Tone, TMN = Tone-Masking-Noise)
#define NMT_OFFSET_DB (6.0F) // Standard offset for NMT
#define TMN_OFFSET_BASE (14.5F) // Base offset for TMN (Bark-dependent)

// Johnston SFM (Spectral Flatness Measure) constants
#define SFM_MIN_DB (-60.0F) // Minimum expected SFM (highly tonal)
#define SFM_MAX_DB (0.0F) // Maximum expected SFM (random noise)
// Temporal Masking Constants
#define FORWARD_MASKING_TAU_LOW_MS (0.100F) // 100ms decay for low frequencies
#define FORWARD_MASKING_TAU_HIGH_MS (0.025F) // 25ms decay for high frequencies
#define BACKWARD_MASKING_TAU_MS (0.010F) // 10ms decay for pre-masking

// Schroeder Slope Adaptation Constants
#define S_LEVEL_REF_DB 40.0F // Reference level for slope adaptation (dB SPL)
#define S_SLOPE_FACTOR 0.2F // Slope broadening factor per dB

// Veto Parameters
#define MASKING_VETO_ALPHA_FLOOR \
(0.2F) // Set to 0.0 for full preservation, or 1.0 for standard reduction.
#define MASKING_VETO_SMOOTHING 0.5F // Stabilization alpha for clean signal
#define MASKING_VETO_NMR_RANGE 20.0F // NMR range for protection mapping (dB)

// Gain Estimators
#define GSS_EXPONENT \
2.0F // 2 Power Subtraction / 1 Magnitude Subtraxtion / 0.5 Spectral
2.0F // 2 Power Subtraction / 1 Magnitude Subtraction / 0.5 Spectral
// Subtraction

// Oversubtraction criteria
Expand All @@ -92,7 +109,6 @@ _Static_assert(sizeof(uint32_t) == 4, "uint32_t must be exactly 32 bits");
#define ESTIMATOR_SILENCE_THRESHOLD (1e-10F) // Roughly -100dB in power

// Martin (2001) Constants
#define MARTIN_WINDOW_LEN 96 // Total window length (frames)
#define MARTIN_SUBWIN_COUNT 8 // Number of sub-windows
#define MARTIN_SUBWIN_LEN 12 // Sub-window length (96/8)
#define MARTIN_BIAS_CORR 1.5F // Conservative bias correction for min tracking
Expand All @@ -116,7 +132,8 @@ _Static_assert(sizeof(uint32_t) == 4, "uint32_t must be exactly 32 bits");
(1e-6F) // Precision for bias correction calc
#define BRANDT_ESTIMATOR_MIN_HISTORY_FRAMES \
5U // Minimum frames for history-based tracking
#define BRANDT_ESTIMATOR_MIN_DURATION_MS 0.1F // Safety floor for duration calcs
#define BRANDT_ESTIMATOR_MIN_DURATION_MS \
(0.1F) // Safety floor for duration calcs

// Tonal Detector Constants
#define PEAK_THRESHOLD 1.41f // ~3dB above neighbor background
Expand All @@ -132,6 +149,9 @@ _Static_assert(sizeof(uint32_t) == 4, "uint32_t must be exactly 32 bits");
// Transient Detector Constants
#define UPPER_LIMIT (5.F)
#define DEFAULT_TRANSIENT_THRESHOLD (2.F)
#define MIN_INNOVATION_ENERGY 1e-10F // ~ -100dB floor for transient trigger
#define ONSET_RATIO_SENSITIVITY 0.25F // Innovation required for full weight
#define TRANSIENT_SMOOTH_ALPHA 0.8F // Reference smoothing alpha

// Noise Estimator Constants
#define MIN_NUMBER_OF_WINDOWS_NOISE_AVERAGED 5
Expand Down Expand Up @@ -170,6 +190,9 @@ _Static_assert(sizeof(uint32_t) == 4, "uint32_t must be exactly 32 bits");
#define CRITICAL_BANDS_TYPE_1D BARK_SCALE
#define GAIN_ESTIMATION_TYPE_1D WIENER

// Masking Veto defaults
#define USE_TEMPORAL_MASKING_1D_DEFAULT true

/* ------------------------------------------------------------------ */
/* ------------------- 2D Denoiser configurations ------------------- */
/* ------------------------------------------------------------------ */
Expand All @@ -190,4 +213,7 @@ _Static_assert(sizeof(uint32_t) == 4, "uint32_t must be exactly 32 bits");
#define CRITICAL_BANDS_TYPE_2D BARK_SCALE
#define GAIN_ESTIMATION_TYPE_2D WIENER

// Masking Veto defaults
#define USE_TEMPORAL_MASKING_2D_DEFAULT true

#endif // MODULES_CONFIGURATIONS_H
Loading