afd0f71719c0397046e5cf793e5ef86243cb6b2a
[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     // Get filter state.
50     z1 = _z1;
51     z2 = _z2;
52
53     // Process n samples. Find digital peak value for this
54     // period and perform filtering. The second filter is
55     // evaluated only every 4th sample - this is just an
56     // optimisation.
57     t = 0;
58     n /= 4;  // Loop is unrolled by 4.
59     while (n--)
60     {
61         s = *p++;
62         s *= s;
63         if (t < s) t = s;             // Update digital peak.
64         z1 += _omega * (s - z1);      // Update first filter.
65         s = *p++;
66         s *= s;
67         if (t < s) t = s;             // Update digital peak.
68         z1 += _omega * (s - z1);      // Update first filter.
69         s = *p++;
70         s *= s;
71         if (t < s) t = s;             // Update digital peak.
72         z1 += _omega * (s - z1);      // Update first filter.
73         s = *p++;
74         s *= s;
75         if (t < s) t = s;             // Update digital peak.
76         z1 += _omega * (s - z1);      // Update first filter.
77         z2 += 4 * _omega * (z1 - z2); // Update second filter.
78     }
79     t = sqrtf (t);
80
81     // Save filter state. The added constants avoid denormals.
82     _z1 = z1 + 1e-20f;
83     _z2 = z2 + 1e-20f;
84
85     s = sqrtf (2 * z2);
86
87     if (_flag) // Display thread has read the rms value.
88     {
89         _rms  = s;
90         _flag = false;
91     }
92     else
93     {
94         // Adjust RMS value and update maximum since last read().
95         if (s > _rms) _rms = s;
96     }
97 }
98
99
100 /* Returns highest _rms value since last call */
101 float Kmeterdsp::read ()
102 {
103     float rv= _rms;
104     _flag = true; // Resets _rms in next process().
105     return rv;
106 }
107
108 void Kmeterdsp::init (int fsamp)
109 {
110     _omega = 9.72f / fsamp; // ballistic filter coefficient
111 }
112
113 void Kmeterdsp::reset ()
114 {
115     _z1 = _z2 = _rms = 0.0;
116     _flag=false;
117 }
118
119 /* vi:set ts=8 sts=8 sw=8: */