experimental RMS-meter and peak-signal (vs peak-power) query
[ardour.git] / libs / ardour / kmeterdsp.cc
1 /*
2     Copyright (C) 2008-2011 Fons Adriaensen <fons@linuxaudio.org>
3                 Adopted for Ardour 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
21 #include <math.h>
22 #include "kmeterdsp.h"
23
24 float  Kmeterdsp::_omega;
25
26 Kmeterdsp::Kmeterdsp (void) :
27     _z1 (0),
28     _z2 (0),
29     _rms (0),
30     _flag (false)
31 {
32 }
33
34
35 Kmeterdsp::~Kmeterdsp (void)
36 {
37 }
38
39
40 void Kmeterdsp::process (float *p, int n)
41 {
42     // Called by JACK's process callback.
43     //
44     // p : pointer to sample buffer
45     // n : number of samples to process
46
47     float  s, t, z1, z2;
48
49     if (_flag) // Display thread has read the rms value.
50     {
51         _rms  = 0;
52         _flag = false;
53     }
54
55     // Get filter state.
56     z1 = _z1;
57     z2 = _z2;
58
59     // Process n samples. Find digital peak value for this
60     // period and perform filtering. The second filter is
61     // evaluated only every 4th sample - this is just an
62     // optimisation.
63     t = 0;
64     n /= 4;  // Loop is unrolled by 4.
65     while (n--)
66     {
67         s = *p++;
68         s *= s;
69         if (t < s) t = s;             // Update digital peak.
70         z1 += _omega * (s - z1);      // Update first filter.
71         s = *p++;
72         s *= s;
73         if (t < s) t = s;             // Update digital peak.
74         z1 += _omega * (s - z1);      // Update first filter.
75         s = *p++;
76         s *= s;
77         if (t < s) t = s;             // Update digital peak.
78         z1 += _omega * (s - z1);      // Update first filter.
79         s = *p++;
80         s *= s;
81         if (t < s) t = s;             // Update digital peak.
82         z1 += _omega * (s - z1);      // Update first filter.
83         z2 += 4 * _omega * (z1 - z2); // Update second filter.
84     }
85     t = sqrtf (t);
86
87     // Save filter state. The added constants avoid denormals.
88     _z1 = z1 + 1e-20f;
89     _z2 = z2 + 1e-20f;
90
91     // Adjust RMS value and update maximum since last read().
92     s = sqrtf (2 * z2);
93     if (s > _rms) _rms = s;
94 }
95
96
97 /* Returns highest _rms value since last call */
98 float Kmeterdsp::read ()
99 {
100     float rv= _rms;
101     _flag = true; // Resets _rms in next process().
102     return rv;
103 }
104
105 void Kmeterdsp::init (int fsamp)
106 {
107     _omega = 9.72f / fsamp; // ballistic filter coefficient
108 }
109
110 void Kmeterdsp::reset ()
111 {
112     _z1 = _z2 = _rms = 0.0;
113     _flag=false;
114 }
115
116 /* vi:set ts=8 sts=8 sw=8: */