obs-filters: Add RTX denoiser
This adds RTX denoiser filter to be used with RTX GPUs. (from Nvidia Audio Effects SDK)master
parent
a609554b89
commit
54892b27db
|
@ -28,9 +28,26 @@ if(NOT LIBRNNOISE_FOUND)
|
|||
set(LIBRNNOISE_FOUND TRUE)
|
||||
endif()
|
||||
|
||||
if(LIBSPEEXDSP_FOUND OR LIBRNNOISE_FOUND)
|
||||
if (WIN32)
|
||||
if(DISABLE_NVAFX)
|
||||
message(STATUS "NVidia Audio FX support disabled")
|
||||
set(LIBNVAFX_FOUND FALSE)
|
||||
else()
|
||||
message(STATUS "NVidia Audio FX support enabled; requires redist to be installed by end-user")
|
||||
add_definitions(-DLIBNVAFX_ENABLED)
|
||||
set(LIBNVAFX_FOUND TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(LIBSPEEXDSP_FOUND OR LIBRNNOISE_FOUND OR LIBNVAFX_FOUND)
|
||||
set(obs-filters_NOISEREDUCTION_SOURCES
|
||||
noise-suppress-filter.c)
|
||||
if(LIBNVAFX_FOUND)
|
||||
set(obs-filters_NOISEREDUCTION_HEADERS
|
||||
nvafx-load.h)
|
||||
else()
|
||||
set(obs-filters_NOISEREDUCTION_HEADERS)
|
||||
endif()
|
||||
set(obs-filters_NOISEREDUCTION_LIBRARIES
|
||||
${LIBSPEEXDSP_LIBRARIES} ${LIBRNNOISE_LIBRARIES})
|
||||
set(NOISEREDUCTION_ENABLED TRUE)
|
||||
|
@ -83,7 +100,8 @@ add_library(obs-filters MODULE
|
|||
${rnnoise_SOURCES}
|
||||
${obs-filters_SOURCES}
|
||||
${obs-filters_config_HEADERS}
|
||||
${obs-filters_NOISEREDUCTION_SOURCES})
|
||||
${obs-filters_NOISEREDUCTION_SOURCES}
|
||||
${obs-filters_NOISEREDUCTION_HEADERS})
|
||||
target_link_libraries(obs-filters
|
||||
libobs
|
||||
${obs-filters_PLATFORM_DEPS}
|
||||
|
|
|
@ -69,9 +69,11 @@ ScaleFiltering.Bicubic="Bicubic"
|
|||
ScaleFiltering.Lanczos="Lanczos"
|
||||
ScaleFiltering.Area="Area"
|
||||
NoiseSuppress.SuppressLevel="Suppression Level"
|
||||
NoiseSuppress.Intensity="Suppression Intensity"
|
||||
NoiseSuppress.Method="Method"
|
||||
NoiseSuppress.Method.Speex="Speex (lower CPU usage)"
|
||||
NoiseSuppress.Method.RNNoise="RNNoise (higher quality)"
|
||||
NoiseSuppress.Method.nvafx="NVIDIA Noise Removal (highest quality, requires RTX GPU)"
|
||||
Saturation="Saturation"
|
||||
HueShift="Hue Shift"
|
||||
Amount="Amount"
|
||||
|
|
|
@ -16,6 +16,11 @@
|
|||
#include <media-io/audio-resampler.h>
|
||||
#endif
|
||||
|
||||
bool nvafx_loaded = false;
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
#include "nvafx-load.h"
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
|
||||
#define do_log(level, format, ...) \
|
||||
|
@ -34,15 +39,19 @@
|
|||
/* -------------------------------------------------------- */
|
||||
|
||||
#define S_SUPPRESS_LEVEL "suppress_level"
|
||||
#define S_NVAFX_INTENSITY "intensity"
|
||||
#define S_METHOD "method"
|
||||
#define S_METHOD_SPEEX "speex"
|
||||
#define S_METHOD_RNN "rnnoise"
|
||||
#define S_METHOD_NVAFX "nvafx"
|
||||
|
||||
#define MT_ obs_module_text
|
||||
#define TEXT_SUPPRESS_LEVEL MT_("NoiseSuppress.SuppressLevel")
|
||||
#define TEXT_NVAFX_INTENSITY MT_("NoiseSuppress.Intensity")
|
||||
#define TEXT_METHOD MT_("NoiseSuppress.Method")
|
||||
#define TEXT_METHOD_SPEEX MT_("NoiseSuppress.Method.Speex")
|
||||
#define TEXT_METHOD_RNN MT_("NoiseSuppress.Method.RNNoise")
|
||||
#define TEXT_METHOD_NVAFX MT_("NoiseSuppress.Method.nvafx")
|
||||
|
||||
#define MAX_PREPROC_CHANNELS 8
|
||||
|
||||
|
@ -50,6 +59,11 @@
|
|||
#define RNNOISE_SAMPLE_RATE 48000
|
||||
#define RNNOISE_FRAME_SIZE 480
|
||||
|
||||
/* nvafx constants, these can't be changed */
|
||||
#define NVAFX_SAMPLE_RATE 48000
|
||||
#define NVAFX_FRAME_SIZE \
|
||||
480 /* the sdk does not explicitly set this as a constant though it relies on it*/
|
||||
|
||||
/* If the following constant changes, RNNoise breaks */
|
||||
#define BUFFER_SIZE_MSEC 10
|
||||
|
||||
|
@ -70,6 +84,8 @@ struct noise_suppress_data {
|
|||
struct circlebuf output_buffers[MAX_PREPROC_CHANNELS];
|
||||
|
||||
bool use_rnnoise;
|
||||
bool use_nvafx;
|
||||
bool nvafx_enabled;
|
||||
|
||||
#ifdef LIBSPEEXDSP_ENABLED
|
||||
/* Speex preprocessor state */
|
||||
|
@ -85,6 +101,20 @@ struct noise_suppress_data {
|
|||
audio_resampler_t *rnn_resampler_back;
|
||||
#endif
|
||||
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
/* NVAFX handle, one per audio channel */
|
||||
NvAFX_Handle handle[MAX_PREPROC_CHANNELS];
|
||||
|
||||
uint32_t sample_rate;
|
||||
float intensity_ratio;
|
||||
unsigned int num_samples_per_frame, num_channels;
|
||||
const char *sdk_path;
|
||||
const char *model;
|
||||
|
||||
/* Resampler */
|
||||
audio_resampler_t *nvafx_resampler;
|
||||
audio_resampler_t *nvafx_resampler_back;
|
||||
#endif
|
||||
/* PCM buffers */
|
||||
float *copy_buffers[MAX_PREPROC_CHANNELS];
|
||||
#ifdef LIBSPEEXDSP_ENABLED
|
||||
|
@ -93,6 +123,9 @@ struct noise_suppress_data {
|
|||
#ifdef LIBRNNOISE_ENABLED
|
||||
float *rnn_segment_buffers[MAX_PREPROC_CHANNELS];
|
||||
#endif
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
float *nvafx_segment_buffers[MAX_PREPROC_CHANNELS];
|
||||
#endif
|
||||
|
||||
/* output data */
|
||||
struct obs_audio_data output_audio;
|
||||
|
@ -125,6 +158,14 @@ static void noise_suppress_destroy(void *data)
|
|||
#endif
|
||||
#ifdef LIBRNNOISE_ENABLED
|
||||
rnnoise_destroy(ng->rnn_states[i]);
|
||||
#endif
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
if (ng->handle[0]) {
|
||||
if (NvAFX_DestroyEffect(ng->handle[i]) !=
|
||||
NVAFX_STATUS_SUCCESS) {
|
||||
do_log(LOG_ERROR, "NvAFX_Release() failed");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
circlebuf_free(&ng->input_buffers[i]);
|
||||
circlebuf_free(&ng->output_buffers[i]);
|
||||
|
@ -141,6 +182,15 @@ static void noise_suppress_destroy(void *data)
|
|||
audio_resampler_destroy(ng->rnn_resampler_back);
|
||||
}
|
||||
#endif
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
bfree(ng->nvafx_segment_buffers[0]);
|
||||
|
||||
if (ng->nvafx_resampler) {
|
||||
audio_resampler_destroy(ng->nvafx_resampler);
|
||||
audio_resampler_destroy(ng->nvafx_resampler_back);
|
||||
}
|
||||
bfree(ng->model);
|
||||
#endif
|
||||
|
||||
bfree(ng->copy_buffers[0]);
|
||||
circlebuf_free(&ng->info_buffer);
|
||||
|
@ -158,6 +208,80 @@ static inline void alloc_channel(struct noise_suppress_data *ng,
|
|||
#endif
|
||||
#ifdef LIBRNNOISE_ENABLED
|
||||
ng->rnn_states[channel] = rnnoise_create(NULL);
|
||||
#endif
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
int err;
|
||||
if (!ng->handle[0] && ng->use_nvafx && nvafx_loaded) {
|
||||
ng->sample_rate = NVAFX_SAMPLE_RATE;
|
||||
|
||||
for (int i = 0; i < MAX_PREPROC_CHANNELS; i++) {
|
||||
err = NvAFX_CreateEffect(NVAFX_EFFECT_DENOISER,
|
||||
&ng->handle[i]);
|
||||
if (err != NVAFX_STATUS_SUCCESS) {
|
||||
do_log(LOG_ERROR,
|
||||
"NvAFX_CreateEffect() failed, error %i",
|
||||
err);
|
||||
ng->use_nvafx = false;
|
||||
}
|
||||
err = NvAFX_SetU32(ng->handle[i],
|
||||
NVAFX_PARAM_DENOISER_SAMPLE_RATE,
|
||||
ng->sample_rate);
|
||||
if (err != NVAFX_STATUS_SUCCESS) {
|
||||
do_log(LOG_ERROR,
|
||||
"NvAFX_SetU32(Sample Rate: %d) failed, error %i",
|
||||
ng->sample_rate, err);
|
||||
ng->use_nvafx = false;
|
||||
}
|
||||
err = NvAFX_SetString(ng->handle[i],
|
||||
NVAFX_PARAM_DENOISER_MODEL_PATH,
|
||||
ng->model);
|
||||
if (err != NVAFX_STATUS_SUCCESS) {
|
||||
do_log(LOG_ERROR,
|
||||
"NvAFX_SetString() failed, error %i",
|
||||
err);
|
||||
ng->use_nvafx = false;
|
||||
}
|
||||
err = NvAFX_Load(ng->handle[i]);
|
||||
if (err != NVAFX_STATUS_SUCCESS) {
|
||||
do_log(LOG_ERROR,
|
||||
"NvAFX_Load() failed with error %i",
|
||||
err);
|
||||
ng->use_nvafx = false;
|
||||
}
|
||||
}
|
||||
if (ng->use_nvafx) {
|
||||
err = NvAFX_GetU32(ng->handle[0],
|
||||
NVAFX_PARAM_DENOISER_NUM_CHANNELS,
|
||||
&ng->num_channels);
|
||||
if (err != NVAFX_STATUS_SUCCESS) {
|
||||
do_log(LOG_ERROR,
|
||||
"NvAFX_GetU32() failed to get the number of channels, error %i",
|
||||
err);
|
||||
ng->use_nvafx = false;
|
||||
}
|
||||
if (ng->num_channels != 1) {
|
||||
do_log(LOG_ERROR,
|
||||
"The number of channels is not 1 in the sdk any more ==> update code");
|
||||
ng->use_nvafx = false;
|
||||
}
|
||||
NvAFX_Status err = NvAFX_GetU32(
|
||||
ng->handle[0],
|
||||
NVAFX_PARAM_DENOISER_NUM_SAMPLES_PER_FRAME,
|
||||
&ng->num_samples_per_frame);
|
||||
if (err != NVAFX_STATUS_SUCCESS) {
|
||||
do_log(LOG_ERROR,
|
||||
"NvAFX_GetU32() failed to get the number of samples per frame, error %i",
|
||||
err);
|
||||
ng->use_nvafx = false;
|
||||
}
|
||||
if (ng->num_samples_per_frame != NVAFX_FRAME_SIZE) {
|
||||
do_log(LOG_ERROR,
|
||||
"The number of samples per frame has changed from 480 (= 10 ms) ==> update code");
|
||||
ng->use_nvafx = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
circlebuf_reserve(&ng->input_buffers[channel], frames * sizeof(float));
|
||||
circlebuf_reserve(&ng->output_buffers[channel], frames * sizeof(float));
|
||||
|
@ -200,8 +324,14 @@ static void noise_suppress_update(void *data, obs_data_t *s)
|
|||
ng->latency = 1000000000LL / (1000 / BUFFER_SIZE_MSEC);
|
||||
ng->use_rnnoise = strcmp(method, S_METHOD_RNN) == 0;
|
||||
|
||||
ng->use_nvafx = ng->nvafx_enabled &&
|
||||
strcmp(method, S_METHOD_NVAFX) == 0;
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
ng->intensity_ratio = (float)obs_data_get_double(s, S_NVAFX_INTENSITY);
|
||||
#endif
|
||||
/* Process 10 millisecond segments to keep latency low */
|
||||
/* Also RNNoise only supports buffers of this exact size. */
|
||||
/* At 48kHz, NVAFX processes 480 samples which corresponds to 10 ms.*/
|
||||
ng->frames = frames;
|
||||
ng->channels = channels;
|
||||
|
||||
|
@ -209,10 +339,15 @@ static void noise_suppress_update(void *data, obs_data_t *s)
|
|||
#if defined(LIBSPEEXDSP_ENABLED)
|
||||
if (ng->spx_states[0])
|
||||
return;
|
||||
#else
|
||||
#endif
|
||||
#ifdef LIBRNNOISE_ENABLED
|
||||
if (ng->rnn_states[0])
|
||||
return;
|
||||
#endif
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
if (ng->handle[0])
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* One speex/rnnoise state for each channel (limit 2) */
|
||||
ng->copy_buffers[0] = bmalloc(frames * channels * sizeof(float));
|
||||
|
@ -223,6 +358,10 @@ static void noise_suppress_update(void *data, obs_data_t *s)
|
|||
#ifdef LIBRNNOISE_ENABLED
|
||||
ng->rnn_segment_buffers[0] =
|
||||
bmalloc(RNNOISE_FRAME_SIZE * channels * sizeof(float));
|
||||
#endif
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
ng->nvafx_segment_buffers[0] =
|
||||
bmalloc(NVAFX_FRAME_SIZE * channels * sizeof(float));
|
||||
#endif
|
||||
for (size_t c = 1; c < channels; ++c) {
|
||||
ng->copy_buffers[c] = ng->copy_buffers[c - 1] + frames;
|
||||
|
@ -233,6 +372,10 @@ static void noise_suppress_update(void *data, obs_data_t *s)
|
|||
#ifdef LIBRNNOISE_ENABLED
|
||||
ng->rnn_segment_buffers[c] =
|
||||
ng->rnn_segment_buffers[c - 1] + RNNOISE_FRAME_SIZE;
|
||||
#endif
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
ng->nvafx_segment_buffers[c] =
|
||||
ng->nvafx_segment_buffers[c - 1] + NVAFX_FRAME_SIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -257,14 +400,102 @@ static void noise_suppress_update(void *data, obs_data_t *s)
|
|||
ng->rnn_resampler_back = audio_resampler_create(&src, &dst);
|
||||
}
|
||||
#endif
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
if (sample_rate == NVAFX_SAMPLE_RATE) {
|
||||
ng->nvafx_resampler = NULL;
|
||||
ng->nvafx_resampler_back = NULL;
|
||||
} else {
|
||||
struct resample_info src, dst;
|
||||
src.samples_per_sec = sample_rate;
|
||||
src.format = AUDIO_FORMAT_FLOAT_PLANAR;
|
||||
src.speakers = convert_speaker_layout((uint8_t)channels);
|
||||
|
||||
dst.samples_per_sec = NVAFX_SAMPLE_RATE;
|
||||
dst.format = AUDIO_FORMAT_FLOAT_PLANAR;
|
||||
dst.speakers = convert_speaker_layout((uint8_t)channels);
|
||||
|
||||
ng->nvafx_resampler = audio_resampler_create(&dst, &src);
|
||||
ng->nvafx_resampler_back = audio_resampler_create(&src, &dst);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4706)
|
||||
#endif
|
||||
bool load_nvafx(void)
|
||||
{
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
if (!load_lib()) {
|
||||
blog(LOG_INFO,
|
||||
"[noise suppress: Nvidia RTX denoiser disabled, redistributable not found]");
|
||||
return false;
|
||||
} else {
|
||||
blog(LOG_INFO, "[noise suppress: Nvidia RTX denoiser enabled]");
|
||||
}
|
||||
|
||||
#define LOAD_SYM_FROM_LIB(sym, lib, dll) \
|
||||
if (!(sym = (sym##_t)GetProcAddress(lib, #sym))) { \
|
||||
DWORD err = GetLastError(); \
|
||||
printf("[noise suppress: Couldn't load " #sym " from " dll \
|
||||
": %lu (0x%lx)]", \
|
||||
err, err); \
|
||||
goto unload_everything; \
|
||||
}
|
||||
|
||||
#define LOAD_SYM(sym) LOAD_SYM_FROM_LIB(sym, nv_audiofx, "NVAudioEffects.dll")
|
||||
LOAD_SYM(NvAFX_GetEffectList);
|
||||
LOAD_SYM(NvAFX_CreateEffect);
|
||||
LOAD_SYM(NvAFX_DestroyEffect);
|
||||
LOAD_SYM(NvAFX_SetU32);
|
||||
LOAD_SYM(NvAFX_SetString);
|
||||
LOAD_SYM(NvAFX_SetFloat);
|
||||
LOAD_SYM(NvAFX_GetU32);
|
||||
LOAD_SYM(NvAFX_GetString);
|
||||
LOAD_SYM(NvAFX_GetFloat);
|
||||
LOAD_SYM(NvAFX_Load);
|
||||
LOAD_SYM(NvAFX_Run);
|
||||
#undef LOAD_SYM
|
||||
nvafx_loaded = true;
|
||||
return true;
|
||||
|
||||
unload_everything:
|
||||
release_lib();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
static void *noise_suppress_create(obs_data_t *settings, obs_source_t *filter)
|
||||
{
|
||||
struct noise_suppress_data *ng =
|
||||
bzalloc(sizeof(struct noise_suppress_data));
|
||||
|
||||
ng->context = filter;
|
||||
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
char sdk_path[MAX_PATH];
|
||||
|
||||
if (!nvafx_get_sdk_path(sdk_path)) {
|
||||
ng->nvafx_enabled = false;
|
||||
do_log(LOG_ERROR, "NVAFX redist is not installed.");
|
||||
} else {
|
||||
const char *file = "\\models\\denoiser_48k.trtpkg";
|
||||
size_t size = strlen(sdk_path) + strlen(file) + 1;
|
||||
char *buffer = (char *)bmalloc(size);
|
||||
|
||||
ng->sdk_path = sdk_path;
|
||||
strcpy(buffer, sdk_path);
|
||||
strcat(buffer, file);
|
||||
ng->model = buffer;
|
||||
ng->nvafx_enabled = true;
|
||||
|
||||
info("NVAFX SDK redist path was found here %s", ng->sdk_path);
|
||||
}
|
||||
#endif
|
||||
noise_suppress_update(ng, settings);
|
||||
return ng;
|
||||
}
|
||||
|
@ -381,6 +612,101 @@ static inline void process_rnnoise(struct noise_suppress_data *ng)
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline void process_nvafx(struct noise_suppress_data *ng)
|
||||
{
|
||||
if (nvafx_loaded) {
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
for (int i = 0; i < MAX_PREPROC_CHANNELS; i++) {
|
||||
if (NvAFX_SetFloat(ng->handle[i],
|
||||
NVAFX_PARAM_DENOISER_INTENSITY_RATIO,
|
||||
ng->intensity_ratio) !=
|
||||
NVAFX_STATUS_SUCCESS) {
|
||||
do_log(LOG_ERROR,
|
||||
"NvAFX_SetFloat(Intensity Ratio: %d) failed",
|
||||
ng->intensity_ratio);
|
||||
ng->use_nvafx = false;
|
||||
}
|
||||
}
|
||||
/* Resample if necessary */
|
||||
if (ng->nvafx_resampler) {
|
||||
float *output[MAX_PREPROC_CHANNELS];
|
||||
uint32_t out_frames;
|
||||
uint64_t ts_offset;
|
||||
audio_resampler_resample(
|
||||
ng->nvafx_resampler, (uint8_t **)output,
|
||||
&out_frames, &ts_offset,
|
||||
(const uint8_t **)ng->copy_buffers,
|
||||
(uint32_t)ng->frames);
|
||||
|
||||
for (size_t i = 0; i < ng->channels; i++) {
|
||||
for (ssize_t j = 0, k = (ssize_t)out_frames -
|
||||
NVAFX_FRAME_SIZE;
|
||||
j < NVAFX_FRAME_SIZE; ++j, ++k) {
|
||||
if (k >= 0) {
|
||||
ng->nvafx_segment_buffers[i][j] =
|
||||
output[i][k];
|
||||
} else {
|
||||
ng->nvafx_segment_buffers[i][j] =
|
||||
0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < ng->channels; i++) {
|
||||
for (size_t j = 0; j < NVAFX_FRAME_SIZE; ++j) {
|
||||
ng->nvafx_segment_buffers[i][j] =
|
||||
ng->copy_buffers[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Execute */
|
||||
for (size_t i = 0; i < ng->channels; i++) {
|
||||
NvAFX_Status err = NvAFX_Run(
|
||||
ng->handle[i], &ng->nvafx_segment_buffers[i],
|
||||
&ng->nvafx_segment_buffers[i],
|
||||
ng->num_samples_per_frame, ng->num_channels);
|
||||
if (err != NVAFX_STATUS_SUCCESS)
|
||||
do_log(LOG_ERROR, "NvAFX_Run() failed");
|
||||
}
|
||||
|
||||
/* Revert signal level adjustment, resample back if necessary */
|
||||
if (ng->nvafx_resampler) {
|
||||
float *output[MAX_PREPROC_CHANNELS];
|
||||
uint32_t out_frames;
|
||||
uint64_t ts_offset;
|
||||
audio_resampler_resample(
|
||||
ng->nvafx_resampler_back, (uint8_t **)output,
|
||||
&out_frames, &ts_offset,
|
||||
(const uint8_t **)ng->nvafx_segment_buffers,
|
||||
NVAFX_FRAME_SIZE);
|
||||
|
||||
for (size_t i = 0; i < ng->channels; i++) {
|
||||
for (ssize_t j = 0, k = (ssize_t)out_frames -
|
||||
ng->frames;
|
||||
j < (ssize_t)ng->frames; ++j, ++k) {
|
||||
if (k >= 0) {
|
||||
ng->copy_buffers[i][j] =
|
||||
output[i][k];
|
||||
} else {
|
||||
ng->copy_buffers[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < ng->channels; i++) {
|
||||
for (size_t j = 0; j < NVAFX_FRAME_SIZE; ++j) {
|
||||
ng->copy_buffers[i][j] =
|
||||
ng->nvafx_segment_buffers[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(ng);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline void process(struct noise_suppress_data *ng)
|
||||
{
|
||||
/* Pop from input circlebuf */
|
||||
|
@ -390,6 +716,10 @@ static inline void process(struct noise_suppress_data *ng)
|
|||
|
||||
if (ng->use_rnnoise) {
|
||||
process_rnnoise(ng);
|
||||
} else if (ng->use_nvafx) {
|
||||
if (nvafx_loaded) {
|
||||
process_nvafx(ng);
|
||||
}
|
||||
} else {
|
||||
process_speexdsp(ng);
|
||||
}
|
||||
|
@ -431,7 +761,8 @@ noise_suppress_filter_audio(void *data, struct obs_audio_data *audio)
|
|||
#ifdef LIBSPEEXDSP_ENABLED
|
||||
if (!ng->spx_states[0])
|
||||
return audio;
|
||||
#else
|
||||
#endif
|
||||
#ifdef LIBRNNOISE_ENABLED
|
||||
if (!ng->rnn_states[0])
|
||||
return audio;
|
||||
#endif
|
||||
|
@ -502,10 +833,14 @@ static bool noise_suppress_method_modified(obs_properties_t *props,
|
|||
{
|
||||
obs_property_t *p_suppress_level =
|
||||
obs_properties_get(props, S_SUPPRESS_LEVEL);
|
||||
obs_property_t *p_navfx_intensity =
|
||||
obs_properties_get(props, S_NVAFX_INTENSITY);
|
||||
const char *method = obs_data_get_string(settings, S_METHOD);
|
||||
bool enable_level = strcmp(method, S_METHOD_SPEEX) == 0;
|
||||
bool enable_intensity = strcmp(method, S_METHOD_NVAFX) == 0;
|
||||
|
||||
obs_property_set_visible(p_suppress_level, enable_level);
|
||||
obs_property_set_visible(p_navfx_intensity, enable_intensity);
|
||||
|
||||
UNUSED_PARAMETER(property);
|
||||
return true;
|
||||
|
@ -534,6 +869,7 @@ static void noise_suppress_defaults_v2(obs_data_t *s)
|
|||
static obs_properties_t *noise_suppress_properties(void *data)
|
||||
{
|
||||
obs_properties_t *ppts = obs_properties_create();
|
||||
struct noise_suppress_data *ng = (struct noise_suppress_data *)data;
|
||||
|
||||
#if defined(LIBRNNOISE_ENABLED) && defined(LIBSPEEXDSP_ENABLED)
|
||||
obs_property_t *method = obs_properties_add_list(
|
||||
|
@ -541,7 +877,11 @@ static obs_properties_t *noise_suppress_properties(void *data)
|
|||
OBS_COMBO_FORMAT_STRING);
|
||||
obs_property_list_add_string(method, TEXT_METHOD_SPEEX, S_METHOD_SPEEX);
|
||||
obs_property_list_add_string(method, TEXT_METHOD_RNN, S_METHOD_RNN);
|
||||
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
if (ng->nvafx_enabled)
|
||||
obs_property_list_add_string(method, TEXT_METHOD_NVAFX,
|
||||
S_METHOD_NVAFX);
|
||||
#endif
|
||||
obs_property_set_modified_callback(method,
|
||||
noise_suppress_method_modified);
|
||||
#endif
|
||||
|
@ -554,6 +894,15 @@ static obs_properties_t *noise_suppress_properties(void *data)
|
|||
#endif
|
||||
|
||||
UNUSED_PARAMETER(data);
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
obs_property_t *nvafx_slider = obs_properties_add_float_slider(
|
||||
ppts, S_NVAFX_INTENSITY, TEXT_NVAFX_INTENSITY, 0.0f, 1.0f,
|
||||
0.01f);
|
||||
if (!nvafx_loaded) {
|
||||
obs_property_list_item_disable(method, 2, true);
|
||||
}
|
||||
|
||||
#endif
|
||||
return ppts;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <util/platform.h>
|
||||
|
||||
#define NVAFX_API __declspec(dllexport)
|
||||
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
static HMODULE nv_audiofx = NULL;
|
||||
|
||||
/** Denoiser Effect */
|
||||
#define NVAFX_EFFECT_DENOISER "denoiser"
|
||||
|
||||
/** Parameter selectors */
|
||||
|
||||
/** Denoiser parameters. @ref NvAFX_ParameterSelector */
|
||||
/** Denoiser filter model path (char*) */
|
||||
#define NVAFX_PARAM_DENOISER_MODEL_PATH "denoiser_model_path"
|
||||
/** Denoiser sample rate (unsigned int). Currently supported sample rate(s): 48000 */
|
||||
#define NVAFX_PARAM_DENOISER_SAMPLE_RATE "sample_rate"
|
||||
/** Denoiser number of samples per frame (unsigned int). This is immutable parameter */
|
||||
#define NVAFX_PARAM_DENOISER_NUM_SAMPLES_PER_FRAME "num_samples_per_frame"
|
||||
/** Denoiser number of channels in I/O (unsigned int). This is immutable parameter */
|
||||
#define NVAFX_PARAM_DENOISER_NUM_CHANNELS "num_channels"
|
||||
/** Denoiser noise suppression factor (float) */
|
||||
#define NVAFX_PARAM_DENOISER_INTENSITY_RATIO "intensity_ratio"
|
||||
|
||||
typedef enum {
|
||||
/** Success */
|
||||
NVAFX_STATUS_SUCCESS = 0,
|
||||
/** Failure */
|
||||
NVAFX_STATUS_FAILED = 1,
|
||||
/** Handle invalid */
|
||||
NVAFX_STATUS_INVALID_HANDLE = 2,
|
||||
/** Parameter value invalid */
|
||||
NVAFX_STATUS_INVALID_PARAM = 3,
|
||||
/** Parameter value immutable */
|
||||
NVAFX_STATUS_IMMUTABLE_PARAM = 4,
|
||||
/** Insufficient data to process */
|
||||
NVAFX_STATUS_INSUFFICIENT_DATA = 5,
|
||||
/** Effect not supported */
|
||||
NVAFX_STATUS_EFFECT_NOT_AVAILABLE = 6,
|
||||
/** Given buffer length too small to hold requested data */
|
||||
NVAFX_STATUS_OUTPUT_BUFFER_TOO_SMALL = 7,
|
||||
/** Model file could not be loaded */
|
||||
NVAFX_STATUS_MODEL_LOAD_FAILED = 8,
|
||||
|
||||
/** (32 bit SDK only) COM server was not registered, please see user manual for details */
|
||||
NVAFX_STATUS_32_SERVER_NOT_REGISTERED = 9,
|
||||
/** (32 bit SDK only) COM operation failed */
|
||||
NVAFX_STATUS_32_COM_ERROR = 10,
|
||||
/** GPU supported. The SDK requires Turing and above GPU with Tensor cores */
|
||||
NVAFX_STATUS_GPU_UNSUPPORTED = 11,
|
||||
} NvAFX_Status;
|
||||
|
||||
typedef const char *NvAFX_EffectSelector;
|
||||
typedef const char *NvAFX_ParameterSelector;
|
||||
typedef void *NvAFX_Handle;
|
||||
|
||||
typedef NvAFX_Status
|
||||
NVAFX_API (*NvAFX_GetEffectList_t)(int *num_effects,
|
||||
NvAFX_EffectSelector *effects[]);
|
||||
typedef NvAFX_Status
|
||||
NVAFX_API (*NvAFX_CreateEffect_t)(NvAFX_EffectSelector code,
|
||||
NvAFX_Handle *effect);
|
||||
typedef NvAFX_Status NVAFX_API (*NvAFX_DestroyEffect_t)(NvAFX_Handle effect);
|
||||
typedef NvAFX_Status
|
||||
NVAFX_API (*NvAFX_SetU32_t)(NvAFX_Handle effect,
|
||||
NvAFX_ParameterSelector param_name,
|
||||
unsigned int val);
|
||||
typedef NvAFX_Status
|
||||
NVAFX_API (*NvAFX_SetString_t)(NvAFX_Handle effect,
|
||||
NvAFX_ParameterSelector param_name,
|
||||
const char *val);
|
||||
typedef NvAFX_Status NVAFX_API (*NvAFX_SetFloat_t)(
|
||||
NvAFX_Handle effect, NvAFX_ParameterSelector param_name, float val);
|
||||
typedef NvAFX_Status
|
||||
NVAFX_API (*NvAFX_GetU32_t)(NvAFX_Handle effect,
|
||||
NvAFX_ParameterSelector param_name,
|
||||
unsigned int *val);
|
||||
typedef NvAFX_Status
|
||||
NVAFX_API (*NvAFX_GetString_t)(NvAFX_Handle effect,
|
||||
NvAFX_ParameterSelector param_name,
|
||||
char *val, int max_length);
|
||||
typedef NvAFX_Status NVAFX_API (*NvAFX_GetFloat_t)(
|
||||
NvAFX_Handle effect, NvAFX_ParameterSelector param_name, float *val);
|
||||
typedef NvAFX_Status NVAFX_API (*NvAFX_Load_t)(NvAFX_Handle effect);
|
||||
typedef NvAFX_Status NVAFX_API (*NvAFX_Run_t)(NvAFX_Handle effect,
|
||||
const float **input,
|
||||
float **output,
|
||||
unsigned num_samples,
|
||||
unsigned num_channels);
|
||||
|
||||
static NvAFX_GetEffectList_t NvAFX_GetEffectList = NULL;
|
||||
static NvAFX_CreateEffect_t NvAFX_CreateEffect = NULL;
|
||||
static NvAFX_DestroyEffect_t NvAFX_DestroyEffect = NULL;
|
||||
static NvAFX_SetU32_t NvAFX_SetU32 = NULL;
|
||||
static NvAFX_SetString_t NvAFX_SetString = NULL;
|
||||
static NvAFX_SetFloat_t NvAFX_SetFloat = NULL;
|
||||
static NvAFX_GetU32_t NvAFX_GetU32 = NULL;
|
||||
static NvAFX_GetString_t NvAFX_GetString = NULL;
|
||||
static NvAFX_GetFloat_t NvAFX_GetFloat = NULL;
|
||||
static NvAFX_Load_t NvAFX_Load = NULL;
|
||||
static NvAFX_Run_t NvAFX_Run = NULL;
|
||||
|
||||
void release_lib(void)
|
||||
{
|
||||
NvAFX_GetEffectList = NULL;
|
||||
NvAFX_CreateEffect = NULL;
|
||||
NvAFX_DestroyEffect = NULL;
|
||||
NvAFX_SetU32 = NULL;
|
||||
NvAFX_SetString = NULL;
|
||||
NvAFX_SetFloat = NULL;
|
||||
NvAFX_GetU32 = NULL;
|
||||
NvAFX_GetString = NULL;
|
||||
NvAFX_GetFloat = NULL;
|
||||
NvAFX_Load = NULL;
|
||||
NvAFX_Run = NULL;
|
||||
if (nv_audiofx) {
|
||||
FreeLibrary(nv_audiofx);
|
||||
nv_audiofx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool nvafx_get_sdk_path(char buffer[MAX_PATH])
|
||||
{
|
||||
char value[MAX_PATH];
|
||||
PVOID pvData = value;
|
||||
DWORD BufferSize = 8192;
|
||||
LPDWORD pcbData;
|
||||
LSTATUS status = RegGetValue(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"),
|
||||
TEXT("NVAFX_SDK_DIR"), RRF_RT_REG_SZ, NULL, pvData,
|
||||
&BufferSize);
|
||||
|
||||
if (status != ERROR_SUCCESS)
|
||||
return false;
|
||||
else if (!os_wcs_to_utf8((wchar_t *)pvData, 0, buffer, MAX_PATH))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool load_lib(void)
|
||||
{
|
||||
char buffer[MAX_PATH];
|
||||
if (!nvafx_get_sdk_path(buffer))
|
||||
return false;
|
||||
|
||||
size_t length = strlen(buffer);
|
||||
wchar_t path[MAX_PATH];
|
||||
|
||||
if (!os_utf8_to_wcs(buffer, 0, path, length + 1))
|
||||
return false;
|
||||
SetDllDirectory(path);
|
||||
nv_audiofx = LoadLibrary(L"NVAudioEffects.dll");
|
||||
SetDllDirectory(NULL);
|
||||
|
||||
return !!nv_audiofx;
|
||||
}
|
||||
#endif
|
|
@ -28,6 +28,8 @@ extern struct obs_source_info async_delay_filter;
|
|||
#if NOISEREDUCTION_ENABLED
|
||||
extern struct obs_source_info noise_suppress_filter;
|
||||
extern struct obs_source_info noise_suppress_filter_v2;
|
||||
extern bool load_nvafx();
|
||||
extern void release_lib();
|
||||
#endif
|
||||
extern struct obs_source_info invert_polarity_filter;
|
||||
extern struct obs_source_info noise_gate_filter;
|
||||
|
@ -57,6 +59,14 @@ bool obs_module_load(void)
|
|||
obs_register_source(&chroma_key_filter_v2);
|
||||
obs_register_source(&async_delay_filter);
|
||||
#if NOISEREDUCTION_ENABLED
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
/* load nvidia audio fx dll */
|
||||
if (!load_nvafx()) {
|
||||
printf("[noise suppress: Unable to load NVAudioEffects.dll.]");
|
||||
} else {
|
||||
printf("[noise suppress: NVAudioEffects.dll loaded.]");
|
||||
}
|
||||
#endif
|
||||
obs_register_source(&noise_suppress_filter);
|
||||
obs_register_source(&noise_suppress_filter_v2);
|
||||
#endif
|
||||
|
@ -69,3 +79,10 @@ bool obs_module_load(void)
|
|||
obs_register_source(&luma_key_filter_v2);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef LIBNVAFX_ENABLED
|
||||
void obs_module_unload(void)
|
||||
{
|
||||
release_lib();
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue