1 /*
2 Copyright (C) 2008-2011 Fons Adriaensen <fons@linuxaudio.org>
3 Copyright (C) 2013 by Robin Gareus <robin@gareus.org>
4
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 2 of the License, or
8 (at your option) any later version.
9
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.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <math.h>
21 #include "kmeterdsp.h"
22
23 namespace LV2M {
24
25 float Kmeterdsp::_omega;
26 int Kmeterdsp::_hold;
27 float Kmeterdsp::_fsamp;
28
29
Kmeterdsp(void)30 Kmeterdsp::Kmeterdsp (void) :
31 _z1 (0),
32 _z2 (0),
33 _rms (0),
34 _peak (0),
35 _cnt (0),
36 _fpp (0),
37 _fall (0),
38 _flag (false)
39 {
40 }
41
42
~Kmeterdsp(void)43 Kmeterdsp::~Kmeterdsp (void)
44 {
45 }
46
init(float fsamp)47 void Kmeterdsp::init (float fsamp)
48 {
49 const float hold = 0.5f;
50 _fsamp = fsamp;
51
52 _hold = (int)(hold * fsamp + 0.5f); // number of samples to hold peak
53 _omega = 9.72f / fsamp; // ballistic filter coefficient
54 }
55
process(float * p,int n)56 void Kmeterdsp::process (float *p, int n)
57 {
58 // Called by JACK's process callback.
59 //
60 // p : pointer to sample buffer
61 // n : number of samples to process
62
63 float s, t, z1, z2;
64
65 if (_fpp != n) {
66 const float fall = 15.0f;
67 const float tme = (float) n / _fsamp; // period time in seconds
68 _fall = powf (10.0f, -0.05f * fall * tme); // per period fallback multiplier
69 _fpp = n;
70 }
71
72 t = 0;
73 // Get filter state.
74 z1 = _z1 > 50 ? 50 : (_z1 < 0 ? 0 : _z1);
75 z2 = _z2 > 50 ? 50 : (_z2 < 0 ? 0 : _z2);
76
77 // Perform filtering. The second filter is evaluated
78 // only every 4th sample - this is just an optimisation.
79 n /= 4; // Loop is unrolled by 4.
80 while (n--)
81 {
82 s = *p++;
83 s *= s;
84 if (t < s) t = s; // Update digital peak.
85 z1 += _omega * (s - z1); // Update first filter.
86 s = *p++;
87 s *= s;
88 if (t < s) t = s; // Update digital peak.
89 z1 += _omega * (s - z1); // Update first filter.
90 s = *p++;
91 s *= s;
92 if (t < s) t = s; // Update digital peak.
93 z1 += _omega * (s - z1); // Update first filter.
94 s = *p++;
95 s *= s;
96 if (t < s) t = s; // Update digital peak.
97 z1 += _omega * (s - z1); // Update first filter.
98 z2 += 4 * _omega * (z1 - z2); // Update second filter.
99 }
100
101 if (isnan(z1)) z1 = 0;
102 if (isnan(z2)) z2 = 0;
103 if (!isfinite(t)) t = 0;
104
105 // Save filter state. The added constants avoid denormals.
106 _z1 = z1 + 1e-20f;
107 _z2 = z2 + 1e-20f;
108
109 s = sqrtf (2.0f * z2);
110 t = sqrtf (t);
111
112 if (_flag) // Display thread has read the rms value.
113 {
114 _rms = s;
115 _flag = false;
116 }
117 else
118 {
119 // Adjust RMS value and update maximum since last read().
120 if (s > _rms) _rms = s;
121 }
122
123 // Digital peak hold and fallback.
124 if (t >= _peak)
125 {
126 // If higher than current value, update and set hold counter.
127 _peak = t;
128 _cnt = _hold;
129 }
130 else if (_cnt > 0)
131 {
132 // else decrement counter if not zero,
133 _cnt-=_fpp;
134 }
135 else
136 {
137 _peak *= _fall; // else let the peak value fall back,
138 _peak += 1e-10f; // and avoid denormals.
139 }
140 }
141
142 /* Returns highest _rms value since last call */
read()143 float Kmeterdsp::read ()
144 {
145 float rv= _rms;
146 _flag = true; // Resets _rms in next process().
147 return rv;
148 }
149
read(float & rms,float & peak)150 void Kmeterdsp::read (float &rms, float &peak)
151 {
152 rms = _rms;
153 peak = _peak;
154 _flag = true; // Resets _rms in next process().
155 }
156
reset()157 void Kmeterdsp::reset ()
158 {
159 _z1 = _z2 = _rms = _peak = .0f;
160 _cnt = 0;
161 _flag = false;
162 }
163
164 } /* end namespace */
165 /* vi:set ts=8 sts=8 sw=4: */
166