mirror of
https://git.vladimir.cc/vladimir/wdsp.git
synced 2026-08-25 17:27:33 +00:00
first commit
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
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 "denoise_mixer.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct DenoiseMixer {
|
||||
float* residual_spectrum;
|
||||
float* denoised_spectrum;
|
||||
|
||||
uint32_t fft_size;
|
||||
uint32_t real_spectrum_size;
|
||||
uint32_t sample_rate;
|
||||
uint32_t hop;
|
||||
};
|
||||
|
||||
DenoiseMixer* denoise_mixer_initialize(uint32_t fft_size, uint32_t sample_rate,
|
||||
uint32_t hop) {
|
||||
DenoiseMixer* self = (DenoiseMixer*)calloc(1U, sizeof(DenoiseMixer));
|
||||
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 = hop;
|
||||
|
||||
self->residual_spectrum = (float*)calloc((self->fft_size), sizeof(float));
|
||||
self->denoised_spectrum = (float*)calloc((self->fft_size), sizeof(float));
|
||||
|
||||
if (!self->residual_spectrum || !self->denoised_spectrum) {
|
||||
denoise_mixer_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void denoise_mixer_free(DenoiseMixer* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
free(self->residual_spectrum);
|
||||
free(self->denoised_spectrum);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool denoise_mixer_run(DenoiseMixer* self, float* fft_spectrum,
|
||||
const float* gain_spectrum,
|
||||
DenoiseMixerParameters parameters) {
|
||||
|
||||
if (!fft_spectrum || !gain_spectrum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get denoised spectrum - Apply to both real and complex parts
|
||||
for (uint32_t k = 0U; k < self->fft_size; k++) {
|
||||
self->denoised_spectrum[k] = fft_spectrum[k] * gain_spectrum[k];
|
||||
}
|
||||
|
||||
// Get residual spectrum - Apply to both real and complex parts
|
||||
for (uint32_t k = 0U; k < self->fft_size; k++) {
|
||||
self->residual_spectrum[k] = fft_spectrum[k] - self->denoised_spectrum[k];
|
||||
}
|
||||
|
||||
// Mix denoised and residual - Now a simple toggle
|
||||
if (parameters.residual_listen) {
|
||||
for (uint32_t k = 0U; k < self->fft_size; k++) {
|
||||
fft_spectrum[k] = self->residual_spectrum[k];
|
||||
}
|
||||
} else {
|
||||
for (uint32_t k = 0U; k < self->fft_size; k++) {
|
||||
fft_spectrum[k] = self->denoised_spectrum[k];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
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 DENOISE_MIXER_H
|
||||
#define DENOISE_MIXER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct DenoiseMixerParameters {
|
||||
float noise_level;
|
||||
bool residual_listen;
|
||||
float whitening_amount;
|
||||
} DenoiseMixerParameters;
|
||||
|
||||
typedef struct DenoiseMixer DenoiseMixer;
|
||||
|
||||
DenoiseMixer* denoise_mixer_initialize(uint32_t fft_size, uint32_t sample_rate,
|
||||
uint32_t hop);
|
||||
void denoise_mixer_free(DenoiseMixer* self);
|
||||
bool denoise_mixer_run(DenoiseMixer* self, float* fft_spectrum,
|
||||
const float* gain_spectrum,
|
||||
DenoiseMixerParameters parameters);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -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
|
||||
*/
|
||||
|
||||
#include "general_utils.h"
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
float sanitize_denormal(float value) {
|
||||
if (!isnormal(value)) {
|
||||
value = 0.F;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
float from_db_to_coefficient(const float value_db) {
|
||||
return expf(value_db / 20.F * logf(10.F));
|
||||
}
|
||||
|
||||
float remap_percentage_log_like_unity(const float value) {
|
||||
return 1.F - expf(-3.F * (value));
|
||||
}
|
||||
|
||||
int get_next_divisible_two(int number) {
|
||||
int q = number / 2;
|
||||
int n1 = 2 * q;
|
||||
int n2 = (number * 2) > 0 ? (2 * (q + 1)) : (2 * (q - 1));
|
||||
if (abs(number - n1) < abs(number - n2)) {
|
||||
return n1;
|
||||
}
|
||||
|
||||
return n2;
|
||||
}
|
||||
|
||||
int get_next_power_two(int number) {
|
||||
return (int)roundf(powf(2.F, ceilf(log2f((float)number))));
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
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 GENERAL_UTILS_H
|
||||
#define GENERAL_UTILS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Compile-time validation
|
||||
_Static_assert(sizeof(float) >= 4, "float must be at least 32 bits");
|
||||
_Static_assert(sizeof(double) >= 8, "double must be at least 64 bits");
|
||||
|
||||
__attribute__((warn_unused_result)) float sanitize_denormal(float value);
|
||||
__attribute__((warn_unused_result)) float from_db_to_coefficient(
|
||||
float value_db);
|
||||
__attribute__((warn_unused_result)) float remap_percentage_log_like_unity(
|
||||
float value);
|
||||
__attribute__((warn_unused_result)) int get_next_divisible_two(int number);
|
||||
__attribute__((warn_unused_result)) int get_next_power_two(int number);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
shared_sources += files(
|
||||
'general_utils.c',
|
||||
'denoise_mixer.c',
|
||||
'spectral_features.c',
|
||||
'spectral_utils.c',
|
||||
'spectral_trailing_buffer.c',
|
||||
)
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
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_features.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct SpectralFeatures {
|
||||
float* power_spectrum;
|
||||
float* phase_spectrum;
|
||||
float* magnitude_spectrum;
|
||||
|
||||
uint32_t real_spectrum_size;
|
||||
};
|
||||
|
||||
SpectralFeatures* spectral_features_initialize(
|
||||
const uint32_t real_spectrum_size) {
|
||||
SpectralFeatures* self =
|
||||
(SpectralFeatures*)calloc(1U, sizeof(SpectralFeatures));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->real_spectrum_size = real_spectrum_size;
|
||||
|
||||
self->power_spectrum =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
self->phase_spectrum =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
self->magnitude_spectrum =
|
||||
(float*)calloc(self->real_spectrum_size, sizeof(float));
|
||||
|
||||
if (!self->power_spectrum || !self->phase_spectrum ||
|
||||
!self->magnitude_spectrum) {
|
||||
spectral_features_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void spectral_features_free(SpectralFeatures* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
free(self->power_spectrum);
|
||||
free(self->phase_spectrum);
|
||||
free(self->magnitude_spectrum);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
float* get_power_spectrum(SpectralFeatures* self) {
|
||||
return self->power_spectrum;
|
||||
}
|
||||
float* get_magnitude_spectrum(SpectralFeatures* self) {
|
||||
return self->magnitude_spectrum;
|
||||
}
|
||||
float* get_phase_spectrum(SpectralFeatures* self) {
|
||||
return self->phase_spectrum;
|
||||
}
|
||||
|
||||
static bool compute_power_spectrum(SpectralFeatures* self,
|
||||
const float* fft_spectrum,
|
||||
const uint32_t fft_spectrum_size) {
|
||||
if (!self || !fft_spectrum || !fft_spectrum_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t n = fft_spectrum_size;
|
||||
const uint32_t n2 = n / 2U;
|
||||
const bool is_even = (n % 2U == 0);
|
||||
|
||||
// DC bin
|
||||
self->power_spectrum[0] = fft_spectrum[0] * fft_spectrum[0];
|
||||
|
||||
// Complex bins
|
||||
for (uint32_t k = 1U; k < n2; k++) {
|
||||
float real = fft_spectrum[k];
|
||||
float imag = fft_spectrum[n - k];
|
||||
self->power_spectrum[k] = (real * real) + (imag * imag);
|
||||
}
|
||||
|
||||
// Nyquist bin
|
||||
if (is_even) {
|
||||
self->power_spectrum[n2] = fft_spectrum[n2] * fft_spectrum[n2];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool compute_magnitude_spectrum(SpectralFeatures* self,
|
||||
const float* fft_spectrum,
|
||||
const uint32_t fft_spectrum_size) {
|
||||
if (!self || !fft_spectrum || !fft_spectrum_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t n = fft_spectrum_size;
|
||||
const uint32_t n2 = n / 2U;
|
||||
const bool is_even = (n % 2U == 0);
|
||||
|
||||
// DC bin
|
||||
self->magnitude_spectrum[0] = fabsf(fft_spectrum[0]);
|
||||
|
||||
// Complex bins
|
||||
for (uint32_t k = 1U; k < n2; k++) {
|
||||
self->magnitude_spectrum[k] = hypotf(fft_spectrum[k], fft_spectrum[n - k]);
|
||||
}
|
||||
|
||||
// Nyquist bin
|
||||
if (is_even) {
|
||||
self->magnitude_spectrum[n2] = fabsf(fft_spectrum[n2]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool compute_phase_spectrum(SpectralFeatures* self,
|
||||
const float* fft_spectrum,
|
||||
const uint32_t fft_spectrum_size) {
|
||||
if (!self || !fft_spectrum || !fft_spectrum_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t n = fft_spectrum_size;
|
||||
const uint32_t n2 = n / 2U;
|
||||
const bool is_even = (n % 2U == 0);
|
||||
|
||||
// DC bin - purely real
|
||||
self->phase_spectrum[0] = atan2f(0.F, fft_spectrum[0]);
|
||||
|
||||
// Complex bins
|
||||
for (uint32_t k = 1U; k < n2; k++) {
|
||||
float real = fft_spectrum[k];
|
||||
float imag = fft_spectrum[n - k];
|
||||
self->phase_spectrum[k] = atan2f(imag, real);
|
||||
}
|
||||
|
||||
// Nyquist bin - purely real
|
||||
if (is_even) {
|
||||
self->phase_spectrum[n2] = atan2f(0.F, fft_spectrum[n2]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float* get_spectral_feature(SpectralFeatures* self, const float* fft_spectrum,
|
||||
uint32_t fft_spectrum_size, SpectrumType type) {
|
||||
if (!self || !fft_spectrum || fft_spectrum_size == 0U) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case POWER_SPECTRUM:
|
||||
compute_power_spectrum(self, fft_spectrum, fft_spectrum_size);
|
||||
return get_power_spectrum(self);
|
||||
break;
|
||||
case MAGNITUDE_SPECTRUM:
|
||||
compute_magnitude_spectrum(self, fft_spectrum, fft_spectrum_size);
|
||||
return get_magnitude_spectrum(self);
|
||||
break;
|
||||
case PHASE_SPECTRUM:
|
||||
compute_phase_spectrum(self, fft_spectrum, fft_spectrum_size);
|
||||
return get_phase_spectrum(self);
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
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_FEATURES_H
|
||||
#define SPECTRAL_FEATURES_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct SpectralFeatures SpectralFeatures;
|
||||
|
||||
typedef enum SpectrumType {
|
||||
POWER_SPECTRUM = 0,
|
||||
MAGNITUDE_SPECTRUM = 1,
|
||||
PHASE_SPECTRUM = 2,
|
||||
} SpectrumType;
|
||||
|
||||
SpectralFeatures* spectral_features_initialize(uint32_t real_spectrum_size);
|
||||
void spectral_features_free(SpectralFeatures* self);
|
||||
float* get_spectral_feature(SpectralFeatures* self, const float* fft_spectrum,
|
||||
uint32_t fft_spectrum_size, SpectrumType type);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
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_trailing_buffer.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct SpectralTrailingBuffer {
|
||||
uint32_t real_spectrum_size;
|
||||
uint32_t buffer_size;
|
||||
|
||||
float* buffer;
|
||||
};
|
||||
|
||||
SpectralTrailingBuffer* spectral_trailing_buffer_initialize(
|
||||
const uint32_t real_spectrum_size, const uint32_t buffer_size) {
|
||||
SpectralTrailingBuffer* self =
|
||||
(SpectralTrailingBuffer*)calloc(1U, sizeof(SpectralTrailingBuffer));
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->real_spectrum_size = real_spectrum_size;
|
||||
self->buffer_size = buffer_size;
|
||||
|
||||
self->buffer = (float*)calloc(
|
||||
((size_t)self->real_spectrum_size * (size_t)self->buffer_size),
|
||||
sizeof(float));
|
||||
|
||||
if (!self->buffer) {
|
||||
spectral_trailing_buffer_free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void spectral_trailing_buffer_free(SpectralTrailingBuffer* self) {
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
free(self->buffer);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool spectral_trailing_buffer_push_back(SpectralTrailingBuffer* self,
|
||||
const float* input_spectrum) {
|
||||
if (!input_spectrum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memmove(self->buffer, &self->buffer[self->real_spectrum_size],
|
||||
sizeof(float) * self->real_spectrum_size * (self->buffer_size - 1U));
|
||||
memcpy(&self->buffer[(size_t)self->real_spectrum_size *
|
||||
(size_t)(self->buffer_size - 1U)],
|
||||
input_spectrum, sizeof(float) * self->real_spectrum_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float* get_trailing_spectral_buffer(SpectralTrailingBuffer* self) {
|
||||
return self->buffer;
|
||||
}
|
||||
|
||||
uint32_t get_spectrum_buffer_size(SpectralTrailingBuffer* self) {
|
||||
return self->buffer_size;
|
||||
}
|
||||
|
||||
uint32_t get_spectrum_size(SpectralTrailingBuffer* self) {
|
||||
return self->real_spectrum_size;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
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_TRAILING_BUFFER_H
|
||||
#define SPECTRAL_TRAILING_BUFFER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct SpectralTrailingBuffer SpectralTrailingBuffer;
|
||||
|
||||
SpectralTrailingBuffer* spectral_trailing_buffer_initialize(
|
||||
uint32_t real_spectrum_size, uint32_t buffer_size);
|
||||
void spectral_trailing_buffer_free(SpectralTrailingBuffer* self);
|
||||
bool spectral_trailing_buffer_push_back(SpectralTrailingBuffer* self,
|
||||
const float* input_spectrum);
|
||||
float* get_trailing_spectral_buffer(SpectralTrailingBuffer* self);
|
||||
uint32_t get_spectrum_buffer_size(SpectralTrailingBuffer* self);
|
||||
uint32_t get_spectrum_size(SpectralTrailingBuffer* self);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
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_utils.h"
|
||||
#include "../configurations.h"
|
||||
#include "general_utils.h"
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static float blackman(const uint32_t bin_index, const uint32_t fft_size) {
|
||||
const float p = ((float)(bin_index)) / ((float)(fft_size));
|
||||
return sanitize_denormal(0.42F - (0.5F * cosf(2.F * M_PIf * p)) +
|
||||
(0.08F * cosf(4.F * M_PIf * p)));
|
||||
}
|
||||
|
||||
static float hanning(const uint32_t bin_index, const uint32_t fft_size) {
|
||||
const float p = ((float)(bin_index)) / ((float)(fft_size));
|
||||
return sanitize_denormal(0.5F - (0.5F * cosf(2.F * M_PIf * p)));
|
||||
}
|
||||
|
||||
static float hamming(const uint32_t bin_index, const uint32_t fft_size) {
|
||||
const float p = ((float)(bin_index)) / ((float)(fft_size));
|
||||
return sanitize_denormal(0.54F - (0.46F * cosf(2.F * M_PIf * p)));
|
||||
}
|
||||
|
||||
static float vorbis(const uint32_t bin_index, const uint32_t fft_size) {
|
||||
const float p = ((float)(bin_index)) / ((float)(fft_size));
|
||||
return sanitize_denormal(sinf(M_PIf / 2.F * powf(sinf(M_PIf * p), 2.F)));
|
||||
}
|
||||
|
||||
bool get_fft_window(float* window, const uint32_t fft_size,
|
||||
const WindowTypes window_type) {
|
||||
if (!window || !fft_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0; k < fft_size; k++) {
|
||||
switch (window_type) {
|
||||
case HANN_WINDOW:
|
||||
window[k] = hanning(k, fft_size);
|
||||
break;
|
||||
case HAMMING_WINDOW:
|
||||
window[k] = hamming(k, fft_size);
|
||||
break;
|
||||
case BLACKMAN_WINDOW:
|
||||
window[k] = blackman(k, fft_size);
|
||||
break;
|
||||
case VORBIS_WINDOW:
|
||||
window[k] = vorbis(k, fft_size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool initialize_spectrum_with_value(float* spectrum, uint32_t spectrum_size,
|
||||
const float value) {
|
||||
if (!spectrum || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0U; i < spectrum_size; i++) {
|
||||
spectrum[i] = value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float max_spectral_value(const float* spectrum,
|
||||
const uint32_t real_spectrum_size) {
|
||||
if (!spectrum || real_spectrum_size == 0U) {
|
||||
return 0.F;
|
||||
}
|
||||
|
||||
float max = spectrum[0];
|
||||
for (uint32_t k = 1U; k < real_spectrum_size; k++) {
|
||||
max = fmaxf(spectrum[k], max);
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
float min_spectral_value(const float* spectrum,
|
||||
const uint32_t real_spectrum_size) {
|
||||
if (!spectrum || real_spectrum_size == 0U) {
|
||||
return 0.F;
|
||||
}
|
||||
|
||||
float min = spectrum[0];
|
||||
for (uint32_t k = 1U; k < real_spectrum_size; k++) {
|
||||
min = fminf(spectrum[k], min);
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
bool min_spectrum_float(float* spectrum_one, const float* spectrum_two,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!spectrum_one || !spectrum_two || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0; k < spectrum_size; k++) {
|
||||
spectrum_one[k] = fminf(spectrum_one[k], spectrum_two[k]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool max_spectrum_float(float* spectrum_one, const float* spectrum_two,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!spectrum_one || !spectrum_two || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0; k < spectrum_size; k++) {
|
||||
spectrum_one[k] = fmaxf(spectrum_one[k], spectrum_two[k]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool min_spectrum_double(double* spectrum_one, const double* spectrum_two,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!spectrum_one || !spectrum_two || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0; k < spectrum_size; k++) {
|
||||
spectrum_one[k] = fmin(spectrum_one[k], spectrum_two[k]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool max_spectrum_double(double* spectrum_one, const double* spectrum_two,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!spectrum_one || !spectrum_two || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0; k < spectrum_size; k++) {
|
||||
spectrum_one[k] = fmax(spectrum_one[k], spectrum_two[k]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool direct_matrix_to_vector_spectral_convolution(const float* matrix_spectum,
|
||||
const float* spectrum,
|
||||
float* out_spectrum,
|
||||
uint32_t spectrum_size) {
|
||||
if (!matrix_spectum || !spectrum || !out_spectrum || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0U; i < spectrum_size; i++) {
|
||||
out_spectrum[i] = 0.F;
|
||||
for (uint32_t j = 0U; j < spectrum_size; j++) {
|
||||
out_spectrum[i] +=
|
||||
(matrix_spectum[(i * spectrum_size) + j] * spectrum[j]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float fft_bin_to_freq(const uint32_t bin_index, const uint32_t sample_rate,
|
||||
const uint32_t fft_size) {
|
||||
return (float)bin_index * ((float)sample_rate / (float)fft_size);
|
||||
}
|
||||
|
||||
uint32_t freq_to_fft_bin(const float freq, const uint32_t sample_rate,
|
||||
const uint32_t fft_size) {
|
||||
return (uint32_t)((freq / ((float)sample_rate / (float)fft_size)) + 0.5f);
|
||||
}
|
||||
|
||||
float spectral_flux(const float* spectrum, const float* previous_spectrum,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!spectrum || !previous_spectrum || spectrum_size == 0U) {
|
||||
return 0.F;
|
||||
}
|
||||
|
||||
float spectral_flux = 0.F;
|
||||
|
||||
for (uint32_t i = 0U; i < spectrum_size; i++) {
|
||||
const float temp = sqrtf(spectrum[i]) - sqrtf(previous_spectrum[i]);
|
||||
spectral_flux += (temp + fabsf(temp)) / 2.F;
|
||||
}
|
||||
return spectral_flux;
|
||||
}
|
||||
|
||||
bool get_rolling_mean_spectrum(float* averaged_spectrum,
|
||||
const float* current_spectrum,
|
||||
const uint32_t number_of_blocks,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!averaged_spectrum || !current_spectrum || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0U; k < spectrum_size; k++) {
|
||||
if (number_of_blocks <= 1U) {
|
||||
averaged_spectrum[k] = current_spectrum[k];
|
||||
} else {
|
||||
averaged_spectrum[k] += (current_spectrum[k] - averaged_spectrum[k]) /
|
||||
(float)number_of_blocks;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int min_max_comparator(const void* a, const void* b) {
|
||||
float x = *(const float*)a;
|
||||
float y = *(const float*)b;
|
||||
|
||||
return x >= y ? 1 : -1;
|
||||
}
|
||||
|
||||
static float find_median(const float* array, uint32_t array_size) {
|
||||
float median = 0.F;
|
||||
|
||||
if (array_size % 2 == 0) {
|
||||
// if number of elements are even
|
||||
median = (array[(array_size - 1U) / 2U] + array[array_size / 2U]) / 2.F;
|
||||
} else {
|
||||
// if number of elements are odd
|
||||
median = array[array_size / 2U];
|
||||
}
|
||||
|
||||
return median;
|
||||
}
|
||||
|
||||
bool get_rolling_median_spectrum(float* median_spectrum,
|
||||
const float* current_spectrum_buffer,
|
||||
const uint32_t number_of_blocks,
|
||||
const uint32_t spectrum_size) {
|
||||
if (!median_spectrum || !current_spectrum_buffer || spectrum_size == 0U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float tmp_buffer[number_of_blocks];
|
||||
|
||||
for (uint32_t i = 0U; i < spectrum_size; i++) {
|
||||
for (uint32_t j = 0U; j < number_of_blocks; j++) {
|
||||
tmp_buffer[j] = current_spectrum_buffer[(j * spectrum_size) + i];
|
||||
}
|
||||
|
||||
// Sorting array
|
||||
qsort(tmp_buffer, number_of_blocks, sizeof(float), min_max_comparator);
|
||||
|
||||
float median_of_buffer = find_median(tmp_buffer, number_of_blocks);
|
||||
|
||||
// Taking the max of the median
|
||||
if (median_of_buffer > median_spectrum[i]) {
|
||||
median_spectrum[i] = median_of_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
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_UTILS_H
|
||||
#define SPECTRAL_UTILS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum WindowTypes {
|
||||
HANN_WINDOW = 0,
|
||||
HAMMING_WINDOW = 1,
|
||||
BLACKMAN_WINDOW = 2,
|
||||
VORBIS_WINDOW = 3
|
||||
} WindowTypes;
|
||||
|
||||
bool get_fft_window(float* window, uint32_t fft_size, WindowTypes window_type);
|
||||
bool initialize_spectrum_with_value(float* spectrum, uint32_t spectrum_size,
|
||||
float value);
|
||||
bool direct_matrix_to_vector_spectral_convolution(const float* matrix_spectum,
|
||||
const float* spectrum,
|
||||
float* out_spectrum,
|
||||
uint32_t spectrum_size);
|
||||
float max_spectral_value(const float* spectrum, uint32_t real_spectrum_size);
|
||||
float min_spectral_value(const float* spectrum, uint32_t real_spectrum_size);
|
||||
|
||||
#define min_spectrum(spectrum_one, spectrum_two, spectrum_size) \
|
||||
_Generic((spectrum_one), \
|
||||
float*: min_spectrum_float, \
|
||||
double*: min_spectrum_double, \
|
||||
default: min_spectrum_float)(spectrum_one, spectrum_two, spectrum_size)
|
||||
|
||||
#define max_spectrum(spectrum_one, spectrum_two, spectrum_size) \
|
||||
_Generic((spectrum_one), \
|
||||
float*: max_spectrum_float, \
|
||||
double*: max_spectrum_double, \
|
||||
default: max_spectrum_float)(spectrum_one, spectrum_two, spectrum_size)
|
||||
|
||||
bool min_spectrum_float(float* spectrum_one, const float* spectrum_two,
|
||||
uint32_t spectrum_size);
|
||||
bool max_spectrum_float(float* spectrum_one, const float* spectrum_two,
|
||||
uint32_t spectrum_size);
|
||||
bool min_spectrum_double(double* spectrum_one, const double* spectrum_two,
|
||||
uint32_t spectrum_size);
|
||||
bool max_spectrum_double(double* spectrum_one, const double* spectrum_two,
|
||||
uint32_t spectrum_size);
|
||||
float fft_bin_to_freq(uint32_t bin_index, uint32_t sample_rate,
|
||||
uint32_t fft_size);
|
||||
uint32_t freq_to_fft_bin(float freq, uint32_t sample_rate, uint32_t fft_size);
|
||||
float spectral_flux(const float* spectrum, const float* previous_spectrum,
|
||||
uint32_t spectrum_size);
|
||||
bool get_rolling_mean_spectrum(float* averaged_spectrum,
|
||||
const float* current_spectrum,
|
||||
uint32_t number_of_blocks,
|
||||
uint32_t spectrum_size);
|
||||
bool get_rolling_median_spectrum(float* median_spectrum,
|
||||
const float* current_spectrum_buffer,
|
||||
uint32_t number_of_blocks,
|
||||
uint32_t spectrum_size);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
Reference in New Issue
Block a user