Merge pull request #1 from atsampson/master
[calfbox.git] / meter.c
blob7f40c6abedad06e32e27df719fe5d4f25d300dff
1 /*
2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2011 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "dspmath.h"
20 #include "errors.h"
21 #include "meter.h"
22 #include <math.h>
23 #include <stdlib.h>
24 #include <string.h>
26 static void clear_meter(struct cbox_meter *m)
28 for (int i = 0; i < 2; i++)
30 m->volume[i] = 0.f;
31 m->peak[i] = 0.f;
32 m->last_peak[i] = 0.f;
34 m->smpcounter = 0;
37 gboolean cbox_meter_attach(struct cbox_recorder *handler, struct cbox_recording_source *src, GError **error)
39 struct cbox_meter *m = handler->user_data;
40 m->channels = src->channels;
41 clear_meter(m);
42 return TRUE;
45 void cbox_meter_record_block(struct cbox_recorder *handler, const float **buffers, uint32_t numsamples)
47 struct cbox_meter *m = handler->user_data;
48 for (int c = 0; c < m->channels; c++)
50 float peak = m->peak[c];
51 float volume = m->volume[c];
52 for (int i = 0; i < numsamples; i++)
54 float s = buffers[c][i];
55 if (fabs(s) > peak)
56 peak = fabs(s);
57 volume += (s * s - volume) * 0.01; // XXXKF this is too simplistic, needs sample rate and proper time constant
59 m->peak[c] = peak;
60 m->volume[c] = sanef(volume);
62 m->smpcounter += numsamples;
63 if (m->smpcounter > m->srate)
65 for (int c = 0; c < m->channels; c++)
67 m->last_peak[c] = m->peak[c];
68 m->peak[c] = 0;
70 m->smpcounter = 0;
74 gboolean cbox_meter_detach(struct cbox_recorder *handler, GError **error)
76 struct cbox_meter *m = handler->user_data;
77 m->channels = 0;
78 clear_meter(m);
79 return TRUE;
82 void cbox_meter_destroy(struct cbox_recorder *handler)
84 struct cbox_meter *m = handler->user_data;
85 free(m);
88 static gboolean cbox_meter_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
90 struct cbox_meter *m = ct->user_data;
91 if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
93 return CBOX_OBJECT_DEFAULT_STATUS(&m->recorder, fb, error);
95 if (!strcmp(cmd->command, "/get_peak") && !strcmp(cmd->arg_types, ""))
97 if (!cbox_check_fb_channel(fb, cmd->command, error))
98 return FALSE;
100 float peak[2];
101 for (int c = 0; c < 2; c++)
103 float v = m->peak[c], w = m->last_peak[c];
104 if (v < w)
105 v = w;
106 peak[c] = v;
109 return cbox_execute_on(fb, NULL, "/peak", "ff", error, peak[0], peak[1]);
111 else
112 if (!strcmp(cmd->command, "/get_rms") && !strcmp(cmd->arg_types, ""))
114 if (!cbox_check_fb_channel(fb, cmd->command, error))
115 return FALSE;
117 return cbox_execute_on(fb, NULL, "/rms", "ff", error, sqrt(m->volume[0]), sqrt(m->volume[1]));
119 else
120 return cbox_object_default_process_cmd(ct, fb, cmd, error);
123 struct cbox_meter *cbox_meter_new(struct cbox_document *document, int srate)
125 struct cbox_meter *m = malloc(sizeof(struct cbox_meter));
126 CBOX_OBJECT_HEADER_INIT(&m->recorder, cbox_recorder, document);
127 m->recorder.user_data = m;
128 cbox_command_target_init(&m->recorder.cmd_target, cbox_meter_process_cmd, m);
129 m->recorder.attach = cbox_meter_attach;
130 m->recorder.detach = cbox_meter_detach;
131 m->recorder.record_block = cbox_meter_record_block;
132 m->recorder.destroy = cbox_meter_destroy;
133 m->srate = srate;
134 clear_meter(m);
135 CBOX_OBJECT_REGISTER(&m->recorder);
136 return m;