0675e14cef1dd2fa03ecce9915cb37e66407dbc6
[ardour.git] / libs / ardour / meter.cc
1 /*
2     Copyright (C) 2006 Paul Davis 
3     
4     This program is free software; you can redistribute it and/or modify it
5     under the terms of the GNU General Public License as published by the Free
6     Software Foundation; either version 2 of the License, or (at your option)
7     any later version.
8     
9     This program is distributed in the hope that it will be useful, but WITHOUT
10     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12     for more details.
13     
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include "ardour/meter.h"
20 #include <algorithm>
21 #include <cmath>
22 #include "ardour/buffer_set.h"
23 #include "ardour/peak.h"
24 #include "ardour/dB.h"
25 #include "ardour/session.h"
26 #include "ardour/midi_buffer.h"
27 #include "ardour/audio_buffer.h"
28 #include "ardour/runtime_functions.h"
29
30 using namespace std;
31
32 using namespace ARDOUR;
33
34 sigc::signal<void> Metering::Meter;
35 Glib::StaticMutex  Metering::m_meter_signal_lock;
36
37 sigc::connection
38 Metering::connect (sigc::slot<void> the_slot)
39 {
40         // SignalProcessor::Meter is emitted from another thread so the
41         // Meter signal must be protected.
42         Glib::Mutex::Lock guard (m_meter_signal_lock);
43         return Meter.connect (the_slot);
44 }
45
46 void
47 Metering::disconnect (sigc::connection& c)
48 {
49         Glib::Mutex::Lock guard (m_meter_signal_lock);
50         c.disconnect ();
51 }
52
53 /**
54     Update the meters.
55
56     The meter signal lock is taken to prevent modification of the 
57     Meter signal while updating the meters, taking the meter signal
58     lock prior to taking the io_lock ensures that all IO will remain 
59     valid while metering.
60 */   
61 void
62 Metering::update_meters()
63 {
64         Glib::Mutex::Lock guard (m_meter_signal_lock);
65         Meter(); /* EMIT SIGNAL */
66 }
67
68 /** Get peaks from @a bufs
69  * Input acceptance is lenient - the first n buffers from @a bufs will
70  * be metered, where n was set by the last call to setup(), excess meters will
71  * be set to 0.
72  */
73 void
74 PeakMeter::run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
75 {
76         const uint32_t n_audio = min(_configured_input.n_audio(), bufs.count().n_audio());
77         const uint32_t n_midi  = min(_configured_input.n_midi(), bufs.count().n_midi());
78         
79         uint32_t n = 0;
80         
81         // Meter MIDI in to the first n_midi peaks
82         for (uint32_t i = 0; i < n_midi; ++i, ++n) {
83                 float val = 0.0f;
84                 for (MidiBuffer::iterator e = bufs.get_midi(i).begin(); e != bufs.get_midi(i).end(); ++e) {
85                         const Evoral::MIDIEvent<nframes_t> ev(*e, false);
86                         if (ev.is_note_on()) {
87                                 const float this_vel = log(ev.buffer()[2] / 127.0 * (M_E*M_E-M_E) + M_E) - 1.0;
88                                 if (this_vel > val) {
89                                         val = this_vel;
90                                 }
91                         } else {
92                                 val += 1.0 / bufs.get_midi(n).capacity();
93                                 if (val > 1.0) {
94                                         val = 1.0;
95                                 }
96                         }
97                 }
98                 _peak_power[n] = val;
99         }
100
101         // Meter audio in to the rest of the peaks
102         for (uint32_t i = 0; i < n_audio; ++i, ++n) {
103                 _peak_power[n] = compute_peak (bufs.get_audio(i).data(), nframes, _peak_power[n]); 
104         }
105
106         // Zero any excess peaks
107         for (uint32_t i = n; i < _peak_power.size(); ++i) {
108                 _peak_power[i] = 0.0f;
109         }
110 }
111
112 void
113 PeakMeter::reset ()
114 {
115         for (size_t i = 0; i < _peak_power.size(); ++i) {
116                 _peak_power[i] = 0.0f;
117         }
118 }
119
120 void
121 PeakMeter::reset_max ()
122 {
123         for (size_t i = 0; i < _max_peak_power.size(); ++i) {
124                 _max_peak_power[i] = -INFINITY;
125         }
126 }
127
128 bool
129 PeakMeter::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
130 {
131         out = in;
132         return true;
133 }
134
135 bool
136 PeakMeter::configure_io (ChanCount in, ChanCount out)
137 {
138         if (out != in) { // always 1:1
139                 return false;
140         }
141         
142         uint32_t limit = in.n_total();
143         
144         while (_peak_power.size() > limit) {
145                 _peak_power.pop_back();
146                 _visible_peak_power.pop_back();
147                 _max_peak_power.pop_back();
148         }
149
150         while (_peak_power.size() < limit) {
151                 _peak_power.push_back(0);
152                 _visible_peak_power.push_back(minus_infinity());
153                 _max_peak_power.push_back(minus_infinity());
154         }
155
156         assert(_peak_power.size() == limit);
157         assert(_visible_peak_power.size() == limit);
158         assert(_max_peak_power.size() == limit);
159
160         return Processor::configure_io (in, out);
161 }
162
163 /** To be driven by the Meter signal from IO.
164  * Caller MUST hold its own processor_lock to prevent reconfiguration
165  * of meter size during this call.
166  */
167
168 void
169 PeakMeter::meter ()
170 {
171         assert(_visible_peak_power.size() == _peak_power.size());
172
173         const size_t limit = _peak_power.size();
174
175         for (size_t n = 0; n < limit; ++n) {
176
177                 /* grab peak since last read */
178
179                 float new_peak = _peak_power[n]; /* XXX we should use atomic exchange from here ... */
180                 _peak_power[n] = 0;              /* ... to here */
181                 
182                 /* compute new visible value using falloff */
183
184                 if (new_peak > 0.0) {
185                         new_peak = coefficient_to_dB (new_peak);
186                 } else {
187                         new_peak = minus_infinity();
188                 }
189                 
190                 /* update max peak */
191                 
192                 _max_peak_power[n] = std::max (new_peak, _max_peak_power[n]);
193                 
194                 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
195                         _visible_peak_power[n] = new_peak;
196                 } else {
197                         // do falloff
198                         new_peak = _visible_peak_power[n] - (Config->get_meter_falloff() * 0.01f);
199                         _visible_peak_power[n] = std::max (new_peak, -INFINITY);
200                 }
201         }
202 }
203
204 XMLNode&
205 PeakMeter::state (bool full_state)
206 {
207         XMLNode& node (Processor::state (full_state));
208         node.add_property("type", "meter");
209         return node;
210 }
211