/* 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 #include "cras_dsp_module.h" #include "drc.h" #include "dsp_util.h" #include "dcblock.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; } /* * dcblock module functions */ struct dcblock_data { struct dcblock *dcblockl; struct dcblock *dcblockr; unsigned long sample_rate; /* One port for input, one for output, and 1 parameter */ float *ports[5]; }; static int dcblock_instantiate(struct dsp_module *module, unsigned long sample_rate) { struct dcblock_data *data; module->data = calloc(1, sizeof(struct dcblock_data)); data = (struct dcblock_data *)module->data; data->sample_rate = sample_rate; return 0; } static void dcblock_connect_port(struct dsp_module *module, unsigned long port, float *data_location) { struct dcblock_data *data = (struct dcblock_data *)module->data; data->ports[port] = data_location; } static void dcblock_run(struct dsp_module *module, unsigned long sample_count) { struct dcblock_data *data = (struct dcblock_data *)module->data; if (!data->dcblockl) data->dcblockl = dcblock_new(*data->ports[4], data->sample_rate); if (!data->dcblockr) data->dcblockr = dcblock_new(*data->ports[4], data->sample_rate); 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); dcblock_process(data->dcblockl, data->ports[2], (int)sample_count); dcblock_process(data->dcblockr, data->ports[3], (int)sample_count); } static void dcblock_deinstantiate(struct dsp_module *module) { struct dcblock_data *data = (struct dcblock_data *)module->data; if (data->dcblockl) dcblock_free(data->dcblockl); if (data->dcblockr) dcblock_free(data->dcblockr); free(data); } static void dcblock_init_module(struct dsp_module *module) { module->instantiate = &dcblock_instantiate; module->connect_port = &dcblock_connect_port; module->get_delay = &empty_get_delay; module->run = &dcblock_run; module->deinstantiate = &dcblock_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; } /* * sink module functions */ struct sink_data { struct ext_dsp_module *ext_module; float *ports[MAX_EXT_DSP_PORTS]; }; static int sink_instantiate(struct dsp_module *module, unsigned long sample_rate) { module->data = (struct sink_data *)calloc(1, sizeof(struct sink_data)); return 0; } static void sink_deinstantiate(struct dsp_module *module) { struct sink_data *data = (struct sink_data *)module->data; free(data); } static void sink_connect_port(struct dsp_module *module, unsigned long port, float *data_location) { struct sink_data *data = (struct sink_data *)module->data; data->ports[port] = data_location; } static void sink_run(struct dsp_module *module, unsigned long sample_count) { struct sink_data *data = (struct sink_data *)module->data; if (!data->ext_module) return; data->ext_module->run(data->ext_module, sample_count); } static void sink_init_module(struct dsp_module *module) { module->instantiate = &sink_instantiate; module->connect_port = &sink_connect_port; module->get_delay = &empty_get_delay; module->run = &sink_run; module->deinstantiate = &sink_deinstantiate; module->free_module = &empty_free_module; module->get_properties = &empty_get_properties; module->dump = &empty_dump; } void cras_dsp_module_set_sink_ext_module(struct dsp_module *module, struct ext_dsp_module *ext_module) { struct sink_data *data = (struct sink_data *)module->data; int i; data->ext_module = ext_module; if (data->ext_module == NULL) return; for (i = 0; i < MAX_EXT_DSP_PORTS; i++) ext_module->ports[i] = data->ports[i]; } /* * 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, "dcblock") == 0) { dcblock_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 if (strcmp(plugin->label, "sink") == 0) { sink_init_module(module); } else { empty_init_module(module); } return module; }