This commit is contained in:
twinaphex 2015-09-13 06:40:29 +02:00
parent d6809537b0
commit e45cd48547
3 changed files with 48 additions and 77 deletions

View File

@ -60,6 +60,7 @@ static void echo_process(void *data, struct dspfilter_output *output,
for (i = 0; i < input->frames; i++, out += 2)
{
float left, right;
float echo_left = 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_right *= echo->amp;
float left = out[0] + echo_left;
float right = out[1] + echo_right;
left = out[0] + echo_left;
right = out[1] + echo_right;
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,
const struct dspfilter_config *config, void *userdata)
{
unsigned i;
struct echo_data *echo = (struct echo_data*)calloc(1, sizeof(*echo));
if (!echo)
return NULL;
unsigned i, channels;
float *delay = NULL, *feedback = NULL;
unsigned num_delay = 0, num_feedback = 0;
static const float default_delay[] = { 200.0f };
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, "feedback", &feedback, &num_feedback, default_feedback, 1);
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));
if (!echo->channels)

View File

@ -12,12 +12,14 @@
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "dspfilter.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <retro_inline.h>
#include <filters.h>
#include "dspfilter.h"
#include "fft/fft.c"
@ -45,7 +47,7 @@ struct eq_data
struct eq_gain
{
float freq;
float gain; // Linear.
float gain; /* Linear. */
};
static void eq_free(void *data)
@ -80,6 +82,7 @@ static void eq_process(void *data, struct dspfilter_output *output,
while (input_frames)
{
unsigned write_avail = eq->block_size - eq->block_ptr;
if (input_frames < write_avail)
write_avail = input_frames;
@ -135,8 +138,8 @@ static void generate_response(fft_complex_t *response,
float start_freq = 0.0f;
float start_gain = 1.0f;
float end_freq = 1.0f;
float end_gain = 1.0f;
float end_freq = 1.0f;
float end_gain = 1.0f;
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.
for (i = 0; i <= samples; i++)
{
float gain;
float lerp = 0.5f;
float freq = (float)i / samples;
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)
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].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,
struct eq_gain *gains, unsigned num_gains, double beta, const char *filter_path)
{
int i;
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);
float *time_filter = (float*)calloc(eq->block_size * 2 + 1, sizeof(*time_filter));
if (!fft || !time_filter)
goto end;
// Make sure bands are in correct order.
/* Make sure bands are in correct order. */
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);
// Get equivalent time-domain filter.
/* Get equivalent time-domain filter. */
fft_process_inverse(fft, time_filter, eq->filter, 1);
// 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;
}
// 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++)
{
// Kaiser window.
/* Kaiser window. */
double phase = (double)i / eq->block_size;
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)
{
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.
// 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.
/* Padded FFT to create our FFT filter.
* 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.
*/
fft_process_forward(eq->fft, eq->filter, time_filter + 1, 1);
end:
@ -284,28 +256,27 @@ end:
static void *eq_init(const struct dspfilter_info *info,
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));
if (!eq)
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);
int size_log2;
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, "gains", &gain, &num_gain, default_gain, 2);
char *filter_path = NULL;
if (!config->get_string(userdata, "impulse_response_output", &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->filter = (fft_complex_t*)calloc(2 * size, sizeof(*eq->filter));
// Use an FFT which is twice the block size with zero-padding
// to make circular convolution => proper convolution.
/* Use an FFT which is twice the block size with zero-padding
* to make circular convolution => proper convolution.
*/
eq->fft = fft_new(size_log2 + 1);
if (!eq->fft || !eq->fftblock || !eq->save || !eq->block || !eq->filter)

View File

@ -53,12 +53,12 @@ static void phaser_process(void *data, struct dspfilter_output *output,
{
unsigned i, c;
int s;
float m[2], tmp[2];
float m[2], tmp[2], *out;
struct phaser_data *ph = (struct phaser_data*)data;
output->samples = input->samples;
output->frames = input->frames;
float *out = output->samples;
out = output->samples;
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,
const struct dspfilter_config *config, void *userdata)
{
float lfo_freq, lfo_start_phase;
struct phaser_data *ph = (struct phaser_data*)calloc(1, sizeof(*ph));
if (!ph)
return NULL;
float lfo_freq, lfo_start_phase;
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, "feedback", &ph->fb, 0.0f);