startup assistant patch from tinman; cleanup fix backported from 2.X ; easy(ier)...
[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 PeakMeter::PeakMeter (Session& s, const XMLNode& node)
113         : Processor (s, node)
114 {
115 }
116
117 void
118 PeakMeter::reset ()
119 {
120         for (size_t i = 0; i < _peak_power.size(); ++i) {
121                 _peak_power[i] = 0.0f;
122         }
123 }
124
125 void
126 PeakMeter::reset_max ()
127 {
128         for (size_t i = 0; i < _max_peak_power.size(); ++i) {
129                 _max_peak_power[i] = -INFINITY;
130         }
131 }
132
133 bool
134 PeakMeter::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
135 {
136         out = in;
137         return true;
138 }
139
140 bool
141 PeakMeter::configure_io (ChanCount in, ChanCount out)
142 {
143         if (out != in) { // always 1:1
144                 return false;
145         }
146         
147         uint32_t limit = in.n_total();
148         
149         while (_peak_power.size() > limit) {
150                 _peak_power.pop_back();
151                 _visible_peak_power.pop_back();
152                 _max_peak_power.pop_back();
153         }
154
155         while (_peak_power.size() < limit) {
156                 _peak_power.push_back(0);
157                 _visible_peak_power.push_back(minus_infinity());
158                 _max_peak_power.push_back(minus_infinity());
159         }
160
161         assert(_peak_power.size() == limit);
162         assert(_visible_peak_power.size() == limit);
163         assert(_max_peak_power.size() == limit);
164
165         return Processor::configure_io (in, out);
166 }
167
168 /** To be driven by the Meter signal from IO.
169  * Caller MUST hold its own processor_lock to prevent reconfiguration
170  * of meter size during this call.
171  */
172
173 void
174 PeakMeter::meter ()
175 {
176         assert(_visible_peak_power.size() == _peak_power.size());
177
178         const size_t limit = _peak_power.size();
179
180         for (size_t n = 0; n < limit; ++n) {
181
182                 /* grab peak since last read */
183
184                 float new_peak = _peak_power[n]; /* XXX we should use atomic exchange from here ... */
185                 _peak_power[n] = 0;              /* ... to here */
186                 
187                 /* compute new visible value using falloff */
188
189                 if (new_peak > 0.0) {
190                         new_peak = coefficient_to_dB (new_peak);
191                 } else {
192                         new_peak = minus_infinity();
193                 }
194                 
195                 /* update max peak */
196                 
197                 _max_peak_power[n] = std::max (new_peak, _max_peak_power[n]);
198                 
199                 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
200                         _visible_peak_power[n] = new_peak;
201                 } else {
202                         // do falloff
203                         new_peak = _visible_peak_power[n] - (Config->get_meter_falloff() * 0.01f);
204                         _visible_peak_power[n] = std::max (new_peak, -INFINITY);
205                 }
206         }
207 }
208
209 XMLNode&
210 PeakMeter::state (bool full_state)
211 {
212         XMLNode& node (Processor::state (full_state));
213         node.add_property("type", "meter");
214         return node;
215 }
216