You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

137 lines
4.2 KiB

/*
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 <http://www.gnu.org/licenses/>.
*/
#include "dspmath.h"
#include "errors.h"
#include "meter.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
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;
}