mirror of
https://github.com/libretro/RetroArch
synced 2025-02-28 22:13:51 +00:00
Cleanups
This commit is contained in:
parent
d6809537b0
commit
e45cd48547
@ -60,6 +60,7 @@ static void echo_process(void *data, struct dspfilter_output *output,
|
|||||||
|
|
||||||
for (i = 0; i < input->frames; i++, out += 2)
|
for (i = 0; i < input->frames; i++, out += 2)
|
||||||
{
|
{
|
||||||
|
float left, right;
|
||||||
float echo_left = 0.0f;
|
float echo_left = 0.0f;
|
||||||
float echo_right = 0.0f;
|
float echo_right = 0.0f;
|
||||||
|
|
||||||
@ -72,8 +73,8 @@ static void echo_process(void *data, struct dspfilter_output *output,
|
|||||||
echo_left *= echo->amp;
|
echo_left *= echo->amp;
|
||||||
echo_right *= echo->amp;
|
echo_right *= echo->amp;
|
||||||
|
|
||||||
float left = out[0] + echo_left;
|
left = out[0] + echo_left;
|
||||||
float right = out[1] + echo_right;
|
right = out[1] + echo_right;
|
||||||
|
|
||||||
for (c = 0; c < echo->num_channels; c++)
|
for (c = 0; c < echo->num_channels; c++)
|
||||||
{
|
{
|
||||||
@ -94,22 +95,21 @@ static void echo_process(void *data, struct dspfilter_output *output,
|
|||||||
static void *echo_init(const struct dspfilter_info *info,
|
static void *echo_init(const struct dspfilter_info *info,
|
||||||
const struct dspfilter_config *config, void *userdata)
|
const struct dspfilter_config *config, void *userdata)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i, channels;
|
||||||
struct echo_data *echo = (struct echo_data*)calloc(1, sizeof(*echo));
|
|
||||||
if (!echo)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
float *delay = NULL, *feedback = NULL;
|
float *delay = NULL, *feedback = NULL;
|
||||||
unsigned num_delay = 0, num_feedback = 0;
|
unsigned num_delay = 0, num_feedback = 0;
|
||||||
|
|
||||||
static const float default_delay[] = { 200.0f };
|
static const float default_delay[] = { 200.0f };
|
||||||
static const float default_feedback[] = { 0.5f };
|
static const float default_feedback[] = { 0.5f };
|
||||||
|
struct echo_data *echo = (struct echo_data*)calloc(1, sizeof(*echo));
|
||||||
|
if (!echo)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
config->get_float_array(userdata, "delay", &delay, &num_delay, default_delay, 1);
|
config->get_float_array(userdata, "delay", &delay, &num_delay, default_delay, 1);
|
||||||
config->get_float_array(userdata, "feedback", &feedback, &num_feedback, default_feedback, 1);
|
config->get_float_array(userdata, "feedback", &feedback, &num_feedback, default_feedback, 1);
|
||||||
config->get_float(userdata, "amp", &echo->amp, 0.2f);
|
config->get_float(userdata, "amp", &echo->amp, 0.2f);
|
||||||
|
|
||||||
unsigned channels = num_feedback = num_delay = min(num_delay, num_feedback);
|
channels = num_feedback = num_delay = min(num_delay, num_feedback);
|
||||||
|
|
||||||
echo->channels = (struct echo_channel*)calloc(channels, sizeof(*echo->channels));
|
echo->channels = (struct echo_channel*)calloc(channels, sizeof(*echo->channels));
|
||||||
if (!echo->channels)
|
if (!echo->channels)
|
||||||
|
@ -12,12 +12,14 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
#include "dspfilter.h"
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <retro_inline.h>
|
#include <retro_inline.h>
|
||||||
|
#include <filters.h>
|
||||||
|
|
||||||
|
#include "dspfilter.h"
|
||||||
|
|
||||||
#include "fft/fft.c"
|
#include "fft/fft.c"
|
||||||
|
|
||||||
@ -45,7 +47,7 @@ struct eq_data
|
|||||||
struct eq_gain
|
struct eq_gain
|
||||||
{
|
{
|
||||||
float freq;
|
float freq;
|
||||||
float gain; // Linear.
|
float gain; /* Linear. */
|
||||||
};
|
};
|
||||||
|
|
||||||
static void eq_free(void *data)
|
static void eq_free(void *data)
|
||||||
@ -80,6 +82,7 @@ static void eq_process(void *data, struct dspfilter_output *output,
|
|||||||
while (input_frames)
|
while (input_frames)
|
||||||
{
|
{
|
||||||
unsigned write_avail = eq->block_size - eq->block_ptr;
|
unsigned write_avail = eq->block_size - eq->block_ptr;
|
||||||
|
|
||||||
if (input_frames < write_avail)
|
if (input_frames < write_avail)
|
||||||
write_avail = input_frames;
|
write_avail = input_frames;
|
||||||
|
|
||||||
@ -135,8 +138,8 @@ static void generate_response(fft_complex_t *response,
|
|||||||
float start_freq = 0.0f;
|
float start_freq = 0.0f;
|
||||||
float start_gain = 1.0f;
|
float start_gain = 1.0f;
|
||||||
|
|
||||||
float end_freq = 1.0f;
|
float end_freq = 1.0f;
|
||||||
float end_gain = 1.0f;
|
float end_gain = 1.0f;
|
||||||
|
|
||||||
if (num_gains)
|
if (num_gains)
|
||||||
{
|
{
|
||||||
@ -149,6 +152,8 @@ static void generate_response(fft_complex_t *response,
|
|||||||
// Create a response by linear interpolation between known frequency sample points.
|
// Create a response by linear interpolation between known frequency sample points.
|
||||||
for (i = 0; i <= samples; i++)
|
for (i = 0; i <= samples; i++)
|
||||||
{
|
{
|
||||||
|
float gain;
|
||||||
|
float lerp = 0.5f;
|
||||||
float freq = (float)i / samples;
|
float freq = (float)i / samples;
|
||||||
|
|
||||||
while (freq >= end_freq)
|
while (freq >= end_freq)
|
||||||
@ -173,11 +178,10 @@ static void generate_response(fft_complex_t *response,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float lerp = 0.5f;
|
/* Edge case where i == samples. */
|
||||||
// Edge case where i == samples.
|
|
||||||
if (end_freq > start_freq)
|
if (end_freq > start_freq)
|
||||||
lerp = (freq - start_freq) / (end_freq - start_freq);
|
lerp = (freq - start_freq) / (end_freq - start_freq);
|
||||||
float gain = (1.0f - lerp) * start_gain + lerp * end_gain;
|
gain = (1.0f - lerp) * start_gain + lerp * end_gain;
|
||||||
|
|
||||||
response[i].real = gain;
|
response[i].real = gain;
|
||||||
response[i].imag = 0.0f;
|
response[i].imag = 0.0f;
|
||||||
@ -186,58 +190,25 @@ static void generate_response(fft_complex_t *response,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modified Bessel function of first order.
|
|
||||||
// Check Wiki for mathematical definition ...
|
|
||||||
static INLINE double kaiser_besseli0(double x)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
double sum = 0.0;
|
|
||||||
|
|
||||||
double factorial = 1.0;
|
|
||||||
double factorial_mult = 0.0;
|
|
||||||
double x_pow = 1.0;
|
|
||||||
double two_div_pow = 1.0;
|
|
||||||
double x_sqr = x * x;
|
|
||||||
|
|
||||||
// Approximate. This is an infinite sum.
|
|
||||||
// Luckily, it converges rather fast.
|
|
||||||
for (i = 0; i < 18; i++)
|
|
||||||
{
|
|
||||||
sum += x_pow * two_div_pow / (factorial * factorial);
|
|
||||||
|
|
||||||
factorial_mult += 1.0;
|
|
||||||
x_pow *= x_sqr;
|
|
||||||
two_div_pow *= 0.25;
|
|
||||||
factorial *= factorial_mult;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE double kaiser_window(double index, double beta)
|
|
||||||
{
|
|
||||||
return kaiser_besseli0(beta * sqrt(1 - index * index));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void create_filter(struct eq_data *eq, unsigned size_log2,
|
static void create_filter(struct eq_data *eq, unsigned size_log2,
|
||||||
struct eq_gain *gains, unsigned num_gains, double beta, const char *filter_path)
|
struct eq_gain *gains, unsigned num_gains, double beta, const char *filter_path)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int half_block_size = eq->block_size >> 1;
|
int half_block_size = eq->block_size >> 1;
|
||||||
double window_mod = 1.0 / kaiser_window(0.0, beta);
|
double window_mod = 1.0 / kaiser_window_function(0.0, beta);
|
||||||
|
|
||||||
fft_t *fft = fft_new(size_log2);
|
fft_t *fft = fft_new(size_log2);
|
||||||
float *time_filter = (float*)calloc(eq->block_size * 2 + 1, sizeof(*time_filter));
|
float *time_filter = (float*)calloc(eq->block_size * 2 + 1, sizeof(*time_filter));
|
||||||
if (!fft || !time_filter)
|
if (!fft || !time_filter)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
// Make sure bands are in correct order.
|
/* Make sure bands are in correct order. */
|
||||||
qsort(gains, num_gains, sizeof(*gains), gains_cmp);
|
qsort(gains, num_gains, sizeof(*gains), gains_cmp);
|
||||||
|
|
||||||
// Compute desired filter response.
|
/* Compute desired filter response. */
|
||||||
generate_response(eq->filter, gains, num_gains, half_block_size);
|
generate_response(eq->filter, gains, num_gains, half_block_size);
|
||||||
|
|
||||||
// Get equivalent time-domain filter.
|
/* Get equivalent time-domain filter. */
|
||||||
fft_process_inverse(fft, time_filter, eq->filter, 1);
|
fft_process_inverse(fft, time_filter, eq->filter, 1);
|
||||||
|
|
||||||
// ifftshift() to create the correct linear phase filter.
|
// ifftshift() to create the correct linear phase filter.
|
||||||
@ -250,16 +221,16 @@ static void create_filter(struct eq_data *eq, unsigned size_log2,
|
|||||||
time_filter[i] = tmp;
|
time_filter[i] = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply a window to smooth out the frequency repsonse.
|
/* Apply a window to smooth out the frequency repsonse. */
|
||||||
for (i = 0; i < (int)eq->block_size; i++)
|
for (i = 0; i < (int)eq->block_size; i++)
|
||||||
{
|
{
|
||||||
// Kaiser window.
|
/* Kaiser window. */
|
||||||
double phase = (double)i / eq->block_size;
|
double phase = (double)i / eq->block_size;
|
||||||
phase = 2.0 * (phase - 0.5);
|
phase = 2.0 * (phase - 0.5);
|
||||||
time_filter[i] *= window_mod * kaiser_window(phase, beta);
|
time_filter[i] *= window_mod * kaiser_window_function(phase, beta);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debugging.
|
/* Debugging. */
|
||||||
if (filter_path)
|
if (filter_path)
|
||||||
{
|
{
|
||||||
FILE *file = fopen(filter_path, "w");
|
FILE *file = fopen(filter_path, "w");
|
||||||
@ -271,9 +242,10 @@ static void create_filter(struct eq_data *eq, unsigned size_log2,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Padded FFT to create our FFT filter.
|
/* Padded FFT to create our FFT filter.
|
||||||
// Make our even-length filter odd by discarding the first coefficient.
|
* Make our even-length filter odd by discarding the first coefficient.
|
||||||
// For some interesting reason, this allows us to design an odd-length linear phase filter.
|
* For some interesting reason, this allows us to design an odd-length linear phase filter.
|
||||||
|
*/
|
||||||
fft_process_forward(eq->fft, eq->filter, time_filter + 1, 1);
|
fft_process_forward(eq->fft, eq->filter, time_filter + 1, 1);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
@ -284,28 +256,27 @@ end:
|
|||||||
static void *eq_init(const struct dspfilter_info *info,
|
static void *eq_init(const struct dspfilter_info *info,
|
||||||
const struct dspfilter_config *config, void *userdata)
|
const struct dspfilter_config *config, void *userdata)
|
||||||
{
|
{
|
||||||
unsigned i;
|
float *frequencies, *gain;
|
||||||
|
unsigned num_freq, num_gain, i, size;
|
||||||
|
int size_log2;
|
||||||
|
float beta;
|
||||||
|
struct eq_gain *gains = NULL;
|
||||||
|
char *filter_path = NULL;
|
||||||
|
const float default_freq[] = { 0.0f, info->input_rate };
|
||||||
|
const float default_gain[] = { 0.0f, 0.0f };
|
||||||
struct eq_data *eq = (struct eq_data*)calloc(1, sizeof(*eq));
|
struct eq_data *eq = (struct eq_data*)calloc(1, sizeof(*eq));
|
||||||
if (!eq)
|
if (!eq)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
const float default_freq[] = { 0.0f, info->input_rate };
|
|
||||||
const float default_gain[] = { 0.0f, 0.0f };
|
|
||||||
|
|
||||||
float beta;
|
|
||||||
config->get_float(userdata, "window_beta", &beta, 4.0f);
|
config->get_float(userdata, "window_beta", &beta, 4.0f);
|
||||||
|
|
||||||
int size_log2;
|
|
||||||
config->get_int(userdata, "block_size_log2", &size_log2, 8);
|
config->get_int(userdata, "block_size_log2", &size_log2, 8);
|
||||||
unsigned size = 1 << size_log2;
|
size = 1 << size_log2;
|
||||||
|
|
||||||
struct eq_gain *gains = NULL;
|
|
||||||
float *frequencies, *gain;
|
|
||||||
unsigned num_freq, num_gain;
|
|
||||||
config->get_float_array(userdata, "frequencies", &frequencies, &num_freq, default_freq, 2);
|
config->get_float_array(userdata, "frequencies", &frequencies, &num_freq, default_freq, 2);
|
||||||
config->get_float_array(userdata, "gains", &gain, &num_gain, default_gain, 2);
|
config->get_float_array(userdata, "gains", &gain, &num_gain, default_gain, 2);
|
||||||
|
|
||||||
char *filter_path = NULL;
|
|
||||||
if (!config->get_string(userdata, "impulse_response_output", &filter_path, ""))
|
if (!config->get_string(userdata, "impulse_response_output", &filter_path, ""))
|
||||||
{
|
{
|
||||||
config->free(filter_path);
|
config->free(filter_path);
|
||||||
@ -333,8 +304,9 @@ static void *eq_init(const struct dspfilter_info *info,
|
|||||||
eq->fftblock = (fft_complex_t*)calloc(2 * size, sizeof(*eq->fftblock));
|
eq->fftblock = (fft_complex_t*)calloc(2 * size, sizeof(*eq->fftblock));
|
||||||
eq->filter = (fft_complex_t*)calloc(2 * size, sizeof(*eq->filter));
|
eq->filter = (fft_complex_t*)calloc(2 * size, sizeof(*eq->filter));
|
||||||
|
|
||||||
// Use an FFT which is twice the block size with zero-padding
|
/* Use an FFT which is twice the block size with zero-padding
|
||||||
// to make circular convolution => proper convolution.
|
* to make circular convolution => proper convolution.
|
||||||
|
*/
|
||||||
eq->fft = fft_new(size_log2 + 1);
|
eq->fft = fft_new(size_log2 + 1);
|
||||||
|
|
||||||
if (!eq->fft || !eq->fftblock || !eq->save || !eq->block || !eq->filter)
|
if (!eq->fft || !eq->fftblock || !eq->save || !eq->block || !eq->filter)
|
||||||
|
@ -53,12 +53,12 @@ static void phaser_process(void *data, struct dspfilter_output *output,
|
|||||||
{
|
{
|
||||||
unsigned i, c;
|
unsigned i, c;
|
||||||
int s;
|
int s;
|
||||||
float m[2], tmp[2];
|
float m[2], tmp[2], *out;
|
||||||
struct phaser_data *ph = (struct phaser_data*)data;
|
struct phaser_data *ph = (struct phaser_data*)data;
|
||||||
|
|
||||||
output->samples = input->samples;
|
output->samples = input->samples;
|
||||||
output->frames = input->frames;
|
output->frames = input->frames;
|
||||||
float *out = output->samples;
|
out = output->samples;
|
||||||
|
|
||||||
for (i = 0; i < input->frames; i++, out += 2)
|
for (i = 0; i < input->frames; i++, out += 2)
|
||||||
{
|
{
|
||||||
@ -95,12 +95,11 @@ static void phaser_process(void *data, struct dspfilter_output *output,
|
|||||||
static void *phaser_init(const struct dspfilter_info *info,
|
static void *phaser_init(const struct dspfilter_info *info,
|
||||||
const struct dspfilter_config *config, void *userdata)
|
const struct dspfilter_config *config, void *userdata)
|
||||||
{
|
{
|
||||||
|
float lfo_freq, lfo_start_phase;
|
||||||
struct phaser_data *ph = (struct phaser_data*)calloc(1, sizeof(*ph));
|
struct phaser_data *ph = (struct phaser_data*)calloc(1, sizeof(*ph));
|
||||||
if (!ph)
|
if (!ph)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
float lfo_freq, lfo_start_phase;
|
|
||||||
|
|
||||||
config->get_float(userdata, "lfo_freq", &lfo_freq, 0.4f);
|
config->get_float(userdata, "lfo_freq", &lfo_freq, 0.4f);
|
||||||
config->get_float(userdata, "lfo_start_phase", &lfo_start_phase, 0.0f);
|
config->get_float(userdata, "lfo_start_phase", &lfo_start_phase, 0.0f);
|
||||||
config->get_float(userdata, "feedback", &ph->fb, 0.0f);
|
config->get_float(userdata, "feedback", &ph->fb, 0.0f);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user