MCP: metering changes from rodrigo, makes metering work correctly on the MC Pro ...
[ardour.git] / libs / surfaces / mackie / meter.cc
1 /*
2         Copyright (C) 2006,2007 John Anderson
3         Copyright (C) 2012 Paul Davis
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 #include <cmath>
21
22 #include "pbd/compose.h"
23 #include "ardour/debug.h"
24
25 #include "mackie_control_protocol.h"
26 #include "meter.h"
27 #include "surface.h"
28 #include "surface_port.h"
29 #include "control_group.h"
30
31 using namespace Mackie;
32 using namespace PBD;
33
34 Control*
35 Meter::factory (Surface& surface, int id, const char* name, Group& group)
36 {
37         Meter* m = new Meter (id, name, group);
38         surface.meters[id] = m;
39         surface.controls.push_back (m);
40         group.add (*m);
41         return m;
42 }
43
44 void 
45 Meter::update_transport_rolling(Surface& surface)
46 {
47         bool transport_is_rolling = (surface.mcp().get_transport_speed () != 0.0f);
48         
49         if (_transport_is_rolling == transport_is_rolling) {
50                 return;
51         }
52         if (transport_is_rolling) {
53                 MidiByteArray enable_msg;
54                 
55                 // sysex header
56                 enable_msg << surface.sysex_hdr();
57                 
58                 // code for Channel Meter Enable Message
59                 enable_msg << 0x20;
60                 
61                 // Channel identification
62                 enable_msg << id();
63                 
64                 // Enabling level meter on LCD, peak hold display on horizontal meter and signal LED
65                 enable_msg << 0x07;
66                 
67                 // sysex trailer
68                 enable_msg << MIDI::eox;
69                 
70                 surface.write (enable_msg);
71                 
72         } else {
73                 MidiByteArray disable_msg;
74                 
75                 // sysex header
76                 disable_msg << surface.sysex_hdr();
77                 
78                 // code for Channel Meter Enable Message
79                 disable_msg << 0x20;
80                 
81                 // Channel identification
82                 disable_msg << id();
83                 
84                 // Disabling level meter on LCD, peak hold display on horizontal meter and signal LED
85                 disable_msg << 0x00;
86                 
87                 // sysex trailer
88                 disable_msg << MIDI::eox;
89                 
90                 surface.write (disable_msg);            
91         }
92         _transport_is_rolling = transport_is_rolling;
93 }
94
95 void
96 Meter::send_update (Surface& surface, float dB)
97 {
98         float def = 0.0f; /* Meter deflection %age */
99
100         // DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Meter ID %1 dB %2\n", id(), dB));
101         
102         if (!_transport_is_rolling) {
103                 return;
104         }
105         
106         if (dB < -70.0f) {
107                 def = 0.0f;
108         } else if (dB < -60.0f) {
109                 def = (dB + 70.0f) * 0.25f;
110         } else if (dB < -50.0f) {
111                 def = (dB + 60.0f) * 0.5f + 2.5f;
112         } else if (dB < -40.0f) {
113                 def = (dB + 50.0f) * 0.75f + 7.5f;
114         } else if (dB < -30.0f) {
115                 def = (dB + 40.0f) * 1.5f + 15.0f;
116         } else if (dB < -20.0f) {
117                 def = (dB + 30.0f) * 2.0f + 30.0f;
118         } else if (dB < 6.0f) {
119                 def = (dB + 20.0f) * 2.5f + 50.0f;
120         } else {
121                 def = 115.0f;
122         }
123         
124         /* 115 is the deflection %age that would be
125            when dB=6.0. this is an arbitrary
126            endpoint for our scaling.
127         */
128
129         MidiByteArray msg;
130         
131         if (def > 100.0f) {
132                 if (!overload_on) {
133                         overload_on = true;
134                         surface.write (MidiByteArray (2, 0xd0, (id() << 4) | 0xe));
135                         
136                 }
137         } else {
138                 if (overload_on) {
139                         overload_on = false;
140                         surface.write (MidiByteArray (2, 0xd0, (id() << 4) | 0xf));
141                 }
142         }
143         
144         /* we can use up to 13 segments */
145
146         int segment = lrintf ((def/115.0) * 13.0);
147         
148         surface.write (MidiByteArray (2, 0xd0, (id()<<4) | segment));
149 }
150
151 MidiByteArray
152 Meter::zero ()
153 {
154         return MidiByteArray (2, 0xD0, (id()<<4 | 0));
155 }