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
137 lines
4.2 KiB
3 years ago
|
/*
|
||
|
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;
|
||
|
}
|