/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <stdlib.h>
#include "cras_dsp_module.h"
#include "drc.h"
#include "dsp_util.h"
#include "eq.h"
#include "eq2.h"
/*
* empty module functions (for source and sink)
*/
static int empty_instantiate(struct dsp_module *module,
unsigned long sample_rate)
{
return 0;
}
static void empty_connect_port(struct dsp_module *module, unsigned long port,
float *data_location) {}
static int empty_get_delay(struct dsp_module *module)
{
return 0;
}
static void empty_run(struct dsp_module *module, unsigned long sample_count) {}
static void empty_deinstantiate(struct dsp_module *module) {}
static void empty_free_module(struct dsp_module *module)
{
free(module);
}
static int empty_get_properties(struct dsp_module *module) { return 0; }
static void empty_dump(struct dsp_module *module, struct dumper *d)
{
dumpf(d, "built-in module\n");
}
static void empty_init_module(struct dsp_module *module)
{
module->instantiate = &empty_instantiate;
module->connect_port = &empty_connect_port;
module->get_delay = &empty_get_delay;
module->run = &empty_run;
module->deinstantiate = &empty_deinstantiate;
module->free_module = &empty_free_module;
module->get_properties = &empty_get_properties;
module->dump = &empty_dump;
}
/*
* swap_lr module functions
*/
static int swap_lr_instantiate(struct dsp_module *module,
unsigned long sample_rate)
{
module->data = calloc(4, sizeof(float*));
return 0;
}
static void swap_lr_connect_port(struct dsp_module *module,
unsigned long port, float *data_location)
{
float **ports;
ports = (float **)module->data;
ports[port] = data_location;
}
static void swap_lr_run(struct dsp_module *module,
unsigned long sample_count)
{
size_t i;
float **ports = (float **)module->data;
/* This module runs dsp in-place, so ports[0] == ports[2],
* ports[1] == ports[3]. Here we swap data on two channels.
*/
for (i = 0; i < sample_count; i++) {
float temp = ports[0][i];
ports[2][i] = ports[1][i];
ports[3][i] = temp;
}
}
static void swap_lr_deinstantiate(struct dsp_module *module)
{
free(module->data);
}
static void swap_lr_init_module(struct dsp_module *module)
{
module->instantiate = &swap_lr_instantiate;
module->connect_port = &swap_lr_connect_port;
module->get_delay = &empty_get_delay;
module->run = &swap_lr_run;
module->deinstantiate = &swap_lr_deinstantiate;
module->free_module = &empty_free_module;
module->get_properties = &empty_get_properties;
}
/*
* invert_lr module functions
*/
static int invert_lr_instantiate(struct dsp_module *module,
unsigned long sample_rate)
{
module->data = calloc(4, sizeof(float*));
return 0;
}
static void invert_lr_connect_port(struct dsp_module *module,
unsigned long port, float *data_location)
{
float **ports;
ports = (float **)module->data;
ports[port] = data_location;
}
static void invert_lr_run(struct dsp_module *module,
unsigned long sample_count)
{
size_t i;
float **ports = (float **)module->data;
for (i = 0; i < sample_count; i++) {
ports[2][i] = -ports[0][i];
ports[3][i] = ports[1][i];
}
}
static void invert_lr_deinstantiate(struct dsp_module *module)
{
free(module->data);
}
static void invert_lr_init_module(struct dsp_module *module)
{
module->instantiate = &invert_lr_instantiate;
module->connect_port = &invert_lr_connect_port;
module->get_delay = &empty_get_delay;
module->run = &invert_lr_run;
module->deinstantiate = &invert_lr_deinstantiate;
module->free_module = &empty_free_module;
module->get_properties = &empty_get_properties;
}
/*
* mix_stereo module functions
*/
static int mix_stereo_instantiate(struct dsp_module *module,
unsigned long sample_rate)
{
module->data = calloc(4, sizeof(float*));
return 0;
}
static void mix_stereo_connect_port(struct dsp_module *module,
unsigned long port, float *data_location)
{
float **ports;
ports = (float **)module->data;
ports[port] = data_location;
}
static void mix_stereo_run(struct dsp_module *module,
unsigned long sample_count)
{
size_t i;
float tmp;
float **ports = (float **)module->data;
for (i = 0; i < sample_count; i++) {
tmp = ports[0][i] + ports[1][i];
ports[2][i] = tmp;
ports[3][i] = tmp;
}
}
static void mix_stereo_deinstantiate(struct dsp_module *module)
{
free(module->data);
}
static void mix_stereo_init_module(struct dsp_module *module)
{
module->instantiate = &mix_stereo_instantiate;
module->connect_port = &mix_stereo_connect_port;
module->get_delay = &empty_get_delay;
module->run = &mix_stereo_run;
module->deinstantiate = &mix_stereo_deinstantiate;
module->free_module = &empty_free_module;
module->get_properties = &empty_get_properties;
module->dump = &empty_dump;
}
/*
* eq module functions
*/
struct eq_data {
int sample_rate;
struct eq *eq; /* Initialized in the first call of eq_run() */
/* One port for input, one for output, and 4 parameters per eq */
float *ports[2 + MAX_BIQUADS_PER_EQ * 4];
};
static int eq_instantiate(struct dsp_module *module, unsigned long sample_rate)
{
struct eq_data *data;
module->data = calloc(1, sizeof(struct eq_data));
data = (struct eq_data *) module->data;
data->sample_rate = (int) sample_rate;
return 0;
}
static void eq_connect_port(struct dsp_module *module,
unsigned long port, float *data_location)
{
struct eq_data *data = (struct eq_data *) module->data;
data->ports[port] = data_location;
}
static void eq_run(struct dsp_module *module, unsigned long sample_count)
{
struct eq_data *data = (struct eq_data *) module->data;
if (!data->eq) {
float nyquist = data->sample_rate / 2;
int i;
data->eq = eq_new();
for (i = 2; i < 2 + MAX_BIQUADS_PER_EQ * 4; i += 4) {
if (!data->ports[i])
break;
int type = (int) *data->ports[i];
float freq = *data->ports[i+1];
float Q = *data->ports[i+2];
float gain = *data->ports[i+3];
eq_append_biquad(data->eq, type, freq / nyquist, Q,
gain);
}
}
if (data->ports[0] != data->ports[1])
memcpy(data->ports[1], data->ports[0],
sizeof(float) * sample_count);
eq_process(data->eq, data->ports[1], (int) sample_count);
}
static void eq_deinstantiate(struct dsp_module *module)
{
struct eq_data *data = (struct eq_data *) module->data;
if (data->eq)
eq_free(data->eq);
free(data);
}
static void eq_init_module(struct dsp_module *module)
{
module->instantiate = &eq_instantiate;
module->connect_port = &eq_connect_port;
module->get_delay = &empty_get_delay;
module->run = &eq_run;
module->deinstantiate = &eq_deinstantiate;
module->free_module = &empty_free_module;
module->get_properties = &empty_get_properties;
module->dump = &empty_dump;
}
/*
* eq2 module functions
*/
struct eq2_data {
int sample_rate;
struct eq2 *eq2; /* Initialized in the first call of eq2_run() */
/* Two ports for input, two for output, and 8 parameters per eq pair */
float *ports[4 + MAX_BIQUADS_PER_EQ2 * 8];
};
static int eq2_instantiate(struct dsp_module *module, unsigned long sample_rate)
{
struct eq2_data *data;
module->data = calloc(1, sizeof(struct eq2_data));
data = (struct eq2_data *) module->data;
data->sample_rate = (int) sample_rate;
return 0;
}
static void eq2_connect_port(struct dsp_module *module,
unsigned long port, float *data_location)
{
struct eq2_data *data = (struct eq2_data *) module->data;
data->ports[port] = data_location;
}
static void eq2_run(struct dsp_module *module, unsigned long sample_count)
{
struct eq2_data *data = (struct eq2_data *) module->data;
if (!data->eq2) {
float nyquist = data->sample_rate / 2;
int i, channel;
data->eq2 = eq2_new();
for (i = 4; i < 4 + MAX_BIQUADS_PER_EQ2 * 8; i += 8) {
if (!data->ports[i])
break;
for (channel = 0; channel < 2; channel++) {
int k = i + channel * 4;
int type = (int) *data->ports[k];
float freq = *data->ports[k+1];
float Q = *data->ports[k+2];
float gain = *data->ports[k+3];
eq2_append_biquad(data->eq2, channel, type,
freq / nyquist, Q, gain);
}
}
}
if (data->ports[0] != data->ports[2])
memcpy(data->ports[2], data->ports[0],
sizeof(float) * sample_count);
if (data->ports[3] != data->ports[1])
memcpy(data->ports[3], data->ports[1],
sizeof(float) * sample_count);
eq2_process(data->eq2, data->ports[2], data->ports[3],
(int) sample_count);
}
static void eq2_deinstantiate(struct dsp_module *module)
{
struct eq2_data *data = (struct eq2_data *) module->data;
if (data->eq2)
eq2_free(data->eq2);
free(data);
}
static void eq2_init_module(struct dsp_module *module)
{
module->instantiate = &eq2_instantiate;
module->connect_port = &eq2_connect_port;
module->get_delay = &empty_get_delay;
module->run = &eq2_run;
module->deinstantiate = &eq2_deinstantiate;
module->free_module = &empty_free_module;
module->get_properties = &empty_get_properties;
module->dump = &empty_dump;
}
/*
* drc module functions
*/
struct drc_data {
int sample_rate;
struct drc *drc; /* Initialized in the first call of drc_run() */
/* Two ports for input, two for output, one for disable_emphasis,
* and 8 parameters each band */
float *ports[4 + 1 + 8 * 3];
};
static int drc_instantiate(struct dsp_module *module, unsigned long sample_rate)
{
struct drc_data *data;
module->data = calloc(1, sizeof(struct drc_data));
data = (struct drc_data *) module->data;
data->sample_rate = (int) sample_rate;
return 0;
}
static void drc_connect_port(struct dsp_module *module,
unsigned long port, float *data_location)
{
struct drc_data *data = (struct drc_data *) module->data;
data->ports[port] = data_location;
}
static int drc_get_delay(struct dsp_module *module)
{
struct drc_data *data = (struct drc_data *) module->data;
return DRC_DEFAULT_PRE_DELAY * data->sample_rate;
}
static void drc_run(struct dsp_module *module, unsigned long sample_count)
{
struct drc_data *data = (struct drc_data *) module->data;
if (!data->drc) {
int i;
float nyquist = data->sample_rate / 2;
struct drc *drc = drc_new(data->sample_rate);
data->drc = drc;
drc->emphasis_disabled = (int) *data->ports[4];
for (i = 0; i < 3; i++) {
int k = 5 + i * 8;
float f = *data->ports[k];
float enable = *data->ports[k+1];
float threshold = *data->ports[k+2];
float knee = *data->ports[k+3];
float ratio = *data->ports[k+4];
float attack = *data->ports[k+5];
float release = *data->ports[k+6];
float boost = *data->ports[k+7];
drc_set_param(drc, i, PARAM_CROSSOVER_LOWER_FREQ,
f / nyquist);
drc_set_param(drc, i, PARAM_ENABLED, enable);
drc_set_param(drc, i, PARAM_THRESHOLD, threshold);
drc_set_param(drc, i, PARAM_KNEE, knee);
drc_set_param(drc, i, PARAM_RATIO, ratio);
drc_set_param(drc, i, PARAM_ATTACK, attack);
drc_set_param(drc, i, PARAM_RELEASE, release);
drc_set_param(drc, i, PARAM_POST_GAIN, boost);
}
drc_init(drc);
}
if (data->ports[0] != data->ports[2])
memcpy(data->ports[2], data->ports[0],
sizeof(float) * sample_count);
if (data->ports[1] != data->ports[3])
memcpy(data->ports[3], data->ports[1],
sizeof(float) * sample_count);
drc_process(data->drc, &data->ports[2], (int) sample_count);
}
static void drc_deinstantiate(struct dsp_module *module)
{
struct drc_data *data = (struct drc_data *) module->data;
if (data->drc)
drc_free(data->drc);
free(data);
}
static void drc_init_module(struct dsp_module *module)
{
module->instantiate = &drc_instantiate;
module->connect_port = &drc_connect_port;
module->get_delay = &drc_get_delay;
module->run = &drc_run;
module->deinstantiate = &drc_deinstantiate;
module->free_module = &empty_free_module;
module->get_properties = &empty_get_properties;
module->dump = &empty_dump;
}
/*
* builtin module dispatcher
*/
struct dsp_module *cras_dsp_module_load_builtin(struct plugin *plugin)
{
struct dsp_module *module;
if (strcmp(plugin->library, "builtin") != 0)
return NULL;
module = calloc(1, sizeof(struct dsp_module));
if (strcmp(plugin->label, "mix_stereo") == 0) {
mix_stereo_init_module(module);
} else if (strcmp(plugin->label, "invert_lr") == 0) {
invert_lr_init_module(module);
} else if (strcmp(plugin->label, "eq") == 0) {
eq_init_module(module);
} else if (strcmp(plugin->label, "eq2") == 0) {
eq2_init_module(module);
} else if (strcmp(plugin->label, "drc") == 0) {
drc_init_module(module);
} else if (strcmp(plugin->label, "swap_lr") == 0) {
swap_lr_init_module(module);
} else {
empty_init_module(module);
}
return module;
}