/* Calf Box, an open source musical instrument. Copyright (C) 2010-2011 Krzysztof Foltman This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "dspmath.h" #include "errors.h" #include "meter.h" #include #include #include static void clear_meter(struct cbox_meter *m) { for (int i = 0; i < 2; i++) { m->volume[i] = 0.f; m->peak[i] = 0.f; m->last_peak[i] = 0.f; } m->smpcounter = 0; } gboolean cbox_meter_attach(struct cbox_recorder *handler, struct cbox_recording_source *src, GError **error) { struct cbox_meter *m = handler->user_data; m->channels = src->channels; clear_meter(m); return TRUE; } void cbox_meter_record_block(struct cbox_recorder *handler, const float **buffers, uint32_t offset, uint32_t numsamples) { struct cbox_meter *m = handler->user_data; for (int c = 0; c < m->channels; c++) { float peak = m->peak[c]; float volume = m->volume[c]; for (uint32_t i = 0; i < numsamples; i++) { float s = buffers[c][i]; if (fabs(s) > peak) peak = fabs(s); volume += (s * s - volume) * 0.01; // XXXKF this is too simplistic, needs sample rate and proper time constant } m->peak[c] = peak; m->volume[c] = sanef(volume); } m->smpcounter += numsamples; if (m->smpcounter > m->srate) { for (int c = 0; c < m->channels; c++) { m->last_peak[c] = m->peak[c]; m->peak[c] = 0; } m->smpcounter = 0; } } gboolean cbox_meter_detach(struct cbox_recorder *handler, GError **error) { struct cbox_meter *m = handler->user_data; m->channels = 0; clear_meter(m); return TRUE; } void cbox_meter_destroy(struct cbox_recorder *handler) { struct cbox_meter *m = handler->user_data; free(m); } static gboolean cbox_meter_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error) { struct cbox_meter *m = ct->user_data; if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, "")) { return CBOX_OBJECT_DEFAULT_STATUS(&m->recorder, fb, error); } if (!strcmp(cmd->command, "/get_peak") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; float peak[2]; for (int c = 0; c < 2; c++) { float v = m->peak[c], w = m->last_peak[c]; if (v < w) v = w; peak[c] = v; } return cbox_execute_on(fb, NULL, "/peak", "ff", error, peak[0], peak[1]); } else if (!strcmp(cmd->command, "/get_rms") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; return cbox_execute_on(fb, NULL, "/rms", "ff", error, sqrt(m->volume[0]), sqrt(m->volume[1])); } else return cbox_object_default_process_cmd(ct, fb, cmd, error); } struct cbox_meter *cbox_meter_new(struct cbox_document *document, int srate) { struct cbox_meter *m = malloc(sizeof(struct cbox_meter)); CBOX_OBJECT_HEADER_INIT(&m->recorder, cbox_recorder, document); m->recorder.user_data = m; cbox_command_target_init(&m->recorder.cmd_target, cbox_meter_process_cmd, m); m->recorder.attach = cbox_meter_attach; m->recorder.detach = cbox_meter_detach; m->recorder.record_block = cbox_meter_record_block; m->recorder.destroy = cbox_meter_destroy; m->srate = srate; clear_meter(m); CBOX_OBJECT_REGISTER(&m->recorder); return m; }