| /* 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_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; |
| } |
| |
| /* |
| * 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; |
| } |
| |
| /* |
| * 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; |
| } |
| |
| /* |
| * 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; |
| } |
| |
| /* |
| * 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; |
| } |
| |
| /* |
| * 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 { |
| empty_init_module(module); |
| } |
| |
| return module; |
| } |