You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
NoiseTorch/c/ladspa/module.c

236 lines
6.7 KiB
C

/*
(c) Copyright 2021 github.com/lawl GPL3+
Free software by Richard W.E. Furse. Do with as you will. No
warranty.
*/
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "ladspa.h"
#include "utils.h"
#include "../ringbuf.h"
#include "../rnnoise/rnnoise.h"
#define SF_VAD 0
#define SF_INPUT 1
#define SF_OUTPUT 2
#define FRAMESIZE_NSAMPLES 480
#define FRAMESIZE_BYTES (480 * sizeof(float))
#define VAD_GRACE_PERIOD 20
typedef struct {
DenoiseState *st;
ringbuf_t in_buf;
ringbuf_t out_buf;
int32_t remaining_grace_period;
int init;
LADSPA_Data *m_pfVAD;
LADSPA_Data *m_pfInput;
LADSPA_Data *m_pfOutput;
} rnnoiseFilter;
static LADSPA_Handle
instantiateSimpleFilter(const LADSPA_Descriptor *Descriptor,
unsigned long SampleRate) {
rnnoiseFilter *psFilter;
psFilter = (rnnoiseFilter *)malloc(sizeof(rnnoiseFilter));
if (psFilter) {
psFilter->in_buf = ringbuf_new(FRAMESIZE_BYTES * 100);
psFilter->out_buf = ringbuf_new(FRAMESIZE_BYTES * 100);
psFilter->init = 0;
psFilter->remaining_grace_period = VAD_GRACE_PERIOD;
psFilter->st = rnnoise_create(NULL);
}
return psFilter;
}
static void activateSimpleFilter(LADSPA_Handle Instance) {
}
static void connectPortToSimpleFilter(LADSPA_Handle Instance,
unsigned long Port,
LADSPA_Data *DataLocation) {
rnnoiseFilter *psFilter;
psFilter = (rnnoiseFilter *)Instance;
switch (Port) {
case SF_VAD:
psFilter->m_pfVAD = DataLocation;
break;
case SF_INPUT:
psFilter->m_pfInput = DataLocation;
break;
case SF_OUTPUT:
psFilter->m_pfOutput = DataLocation;
break;
}
}
static void runFilter(LADSPA_Handle Instance, unsigned long n_samples) {
rnnoiseFilter *psFilter;
psFilter = (rnnoiseFilter *)Instance;
ringbuf_t in_buf = psFilter->in_buf;
ringbuf_t out_buf = psFilter->out_buf;
float *in, *out, vad_thresh;
in = psFilter->m_pfInput;
out = psFilter->m_pfOutput;
vad_thresh = *psFilter->m_pfVAD / 100;
for (int i = 0; i < n_samples; i++) {
in[i] = in[i] * 32767;
}
ringbuf_memcpy_into(in_buf, in, n_samples * sizeof(float));
const size_t n_frames = ringbuf_bytes_used(in_buf) / FRAMESIZE_BYTES;
float tmpin[n_frames * FRAMESIZE_NSAMPLES];
ringbuf_memcpy_from(tmpin, in_buf, FRAMESIZE_BYTES * n_frames);
for (int i = 0; i < n_frames; i++) {
float tmp[FRAMESIZE_NSAMPLES];
float vad_prob = rnnoise_process_frame(psFilter->st, tmp,
tmpin + (i * FRAMESIZE_NSAMPLES));
if (vad_prob > vad_thresh) {
psFilter->remaining_grace_period = VAD_GRACE_PERIOD;
}
if (psFilter->remaining_grace_period >= 0) {
psFilter->remaining_grace_period--;
} else {
for (int i = 0; i < FRAMESIZE_NSAMPLES; i++) {
tmp[i] = 0.f;
}
}
ringbuf_memcpy_into(out_buf, tmp, FRAMESIZE_BYTES);
}
int frames_avail = ringbuf_bytes_used(out_buf) / FRAMESIZE_BYTES;
int samples_avail = frames_avail * FRAMESIZE_NSAMPLES;
if (samples_avail < n_samples) {
int skip = n_samples - samples_avail;
for (int i = 0; i < skip; i++) {
out[i] = 0.f;
}
ringbuf_memcpy_from(out + skip, out_buf, samples_avail * sizeof(float));
} else {
ringbuf_memcpy_from(out, out_buf, n_samples * sizeof(float));
}
for (int i = 0; i < n_samples; i++) {
out[i] = out[i] / 32767;
}
}
static void cleanupFilter(LADSPA_Handle Instance) {
rnnoiseFilter *psFilter = (rnnoiseFilter *)Instance;
rnnoise_destroy(psFilter->st);
ringbuf_free(&(psFilter->in_buf));
ringbuf_free(&(psFilter->out_buf));
free(Instance);
}
static LADSPA_Descriptor *g_psDescriptor = NULL;
ON_LOAD_ROUTINE {
char **pcPortNames;
LADSPA_PortDescriptor *piPortDescriptors;
LADSPA_PortRangeHint *psPortRangeHints;
g_psDescriptor = (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor));
if (g_psDescriptor != NULL) {
g_psDescriptor->UniqueID = 16682994;
g_psDescriptor->Label = strdup("noisetorch");
g_psDescriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
g_psDescriptor->Name = strdup("NoiseTorch rnnoise ladspa module");
g_psDescriptor->Maker = strdup("lawl");
g_psDescriptor->Copyright = strdup("GPL3+");
g_psDescriptor->PortCount = 3;
piPortDescriptors =
(LADSPA_PortDescriptor *)calloc(3, sizeof(LADSPA_PortDescriptor));
g_psDescriptor->PortDescriptors =
(const LADSPA_PortDescriptor *)piPortDescriptors;
piPortDescriptors[SF_VAD] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
piPortDescriptors[SF_INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
piPortDescriptors[SF_OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
pcPortNames = (char **)calloc(3, sizeof(char *));
g_psDescriptor->PortNames = (const char **)pcPortNames;
pcPortNames[SF_VAD] = strdup("VAD %%");
pcPortNames[SF_INPUT] = strdup("Input");
pcPortNames[SF_OUTPUT] = strdup("Output");
psPortRangeHints =
((LADSPA_PortRangeHint *)calloc(3, sizeof(LADSPA_PortRangeHint)));
g_psDescriptor->PortRangeHints =
(const LADSPA_PortRangeHint *)psPortRangeHints;
psPortRangeHints[SF_VAD].HintDescriptor =
(LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_SAMPLE_RATE | LADSPA_HINT_LOGARITHMIC |
LADSPA_HINT_DEFAULT_440);
psPortRangeHints[SF_VAD].LowerBound = 0;
psPortRangeHints[SF_VAD].UpperBound = 95;
psPortRangeHints[SF_INPUT].HintDescriptor = 0;
psPortRangeHints[SF_OUTPUT].HintDescriptor = 0;
g_psDescriptor->instantiate = instantiateSimpleFilter;
g_psDescriptor->connect_port = connectPortToSimpleFilter;
g_psDescriptor->activate = activateSimpleFilter;
g_psDescriptor->run = runFilter;
g_psDescriptor->run_adding = NULL;
g_psDescriptor->set_run_adding_gain = NULL;
g_psDescriptor->deactivate = NULL;
g_psDescriptor->cleanup = cleanupFilter;
}
}
static void deleteDescriptor(LADSPA_Descriptor *psDescriptor) {
unsigned long lIndex;
if (psDescriptor) {
free((char *)psDescriptor->Label);
free((char *)psDescriptor->Name);
free((char *)psDescriptor->Maker);
free((char *)psDescriptor->Copyright);
free((LADSPA_PortDescriptor *)psDescriptor->PortDescriptors);
for (lIndex = 0; lIndex < psDescriptor->PortCount; lIndex++)
free((char *)(psDescriptor->PortNames[lIndex]));
free((char **)psDescriptor->PortNames);
free((LADSPA_PortRangeHint *)psDescriptor->PortRangeHints);
free(psDescriptor);
}
}
ON_UNLOAD_ROUTINE { deleteDescriptor(g_psDescriptor); }
const LADSPA_Descriptor *ladspa_descriptor(unsigned long Index) {
/* Return the requested descriptor or null if the index is out of
range. */
switch (Index) {
case 0:
return g_psDescriptor;
default:
return NULL;
}
}