1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
/*
Copyright (C) 2006 Paul Davis
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 2 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, write to the Free Software Foundation, Inc.,
675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <ardour/meter.h>
#include <algorithm>
#include <cmath>
#include <ardour/buffer_set.h>
#include <ardour/peak.h>
#include <ardour/dB.h>
#include <ardour/session.h>
namespace ARDOUR {
/** Get peaks from @a bufs
* Input acceptance is lenient - the first n audio buffers from @a bufs will
* be metered, where n was set by the last call to setup(), excess meters will
* be set to 0.
*/
void
PeakMeter::run (BufferSet& bufs, jack_nframes_t nframes, jack_nframes_t offset)
{
size_t meterable = std::min(bufs.count().get(DataType::AUDIO), _peak_power.size());
// Meter what we have
for (size_t n = 0; n < meterable; ++n) {
_peak_power[n] = compute_peak (bufs.get_audio(n).data(nframes, offset), nframes, _peak_power[n]);
}
// Zero any excess peaks
for (size_t n = meterable; n < _peak_power.size(); ++n) {
_peak_power[n] = 0;
}
}
void
PeakMeter::reset ()
{
for (size_t i = 0; i < _peak_power.size(); ++i) {
_peak_power[i] = 0;
}
}
void
PeakMeter::setup (const ChanCount& in)
{
uint32_t limit = in.get(DataType::AUDIO);
while (_peak_power.size() > limit) {
_peak_power.pop_back();
_visible_peak_power.pop_back();
}
while (_peak_power.size() < limit) {
_peak_power.push_back (0);
_visible_peak_power.push_back (0);
}
assert(_peak_power.size() == limit);
assert(_visible_peak_power.size() == limit);
}
/** To be driven by the Meter signal from IO.
* Caller MUST hold io_lock!
*/
void
PeakMeter::meter ()
{
assert(_visible_peak_power.size() == _peak_power.size());
const size_t limit = _peak_power.size();
for (size_t n = 0; n < limit; ++n) {
/* XXX we should use atomic exchange here */
/* grab peak since last read */
float new_peak = _peak_power[n];
_peak_power[n] = 0;
/* compute new visible value using falloff */
if (new_peak > 0.0) {
new_peak = coefficient_to_dB (new_peak);
} else {
new_peak = minus_infinity();
}
if (_session.meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
_visible_peak_power[n] = new_peak;
} else {
// do falloff
new_peak = _visible_peak_power[n] - _session.meter_falloff();
_visible_peak_power[n] = std::max (new_peak, -INFINITY);
}
}
}
} // namespace ARDOUR
|