c846145ebcd8910e7af22565ecb6c946f48fb3fc
[ardour.git] / libs / surfaces / osc / osc_cue_observer.cc
1 /*
2     Copyright (C) 2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "boost/lambda/lambda.hpp"
21
22 #include "ardour/track.h"
23 #include "ardour/dB.h"
24 #include "ardour/meter.h"
25
26 #include "osc.h"
27 #include "osc_cue_observer.h"
28
29 #include "pbd/i18n.h"
30
31 using namespace std;
32 using namespace PBD;
33 using namespace ARDOUR;
34 using namespace ArdourSurface;
35
36 OSCCueObserver::OSCCueObserver (boost::shared_ptr<Stripable> s, std::vector<boost::shared_ptr<ARDOUR::Stripable> >& snds, lo_address a)
37         : sends (snds)
38         , _strip (s)
39         , tick_enable (false)
40 {
41         addr = lo_address_new (lo_address_get_hostname(a) , lo_address_get_port(a));
42
43         _strip->PropertyChanged.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCCueObserver::name_changed, this, boost::lambda::_1, 0), OSC::instance());
44         name_changed (ARDOUR::Properties::name, 0);
45
46         _strip->mute_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, bind (&OSCCueObserver::send_change_message, this, X_("/cue/mute"), 0, _strip->mute_control()), OSC::instance());
47         send_change_message ("/cue/mute", 0, _strip->mute_control());
48
49         gain_timeout.push_back (0);
50         _strip->gain_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, bind (&OSCCueObserver::send_gain_message, this, 0, _strip->gain_control()), OSC::instance());
51         send_gain_message (0, _strip->gain_control());
52
53         send_init ();
54
55         tick_enable = true;
56         tick ();
57 }
58
59 OSCCueObserver::~OSCCueObserver ()
60 {
61
62         strip_connections.drop_connections ();
63         send_end ();
64         // all strip buttons should be off and faders 0 and etc.
65         text_with_id ("/cue/name", 0, " ");
66         clear_strip ("/cue/mute", 0);
67         clear_strip ("/cue/fader", 0);
68         clear_strip ("/cue/signal", 0);
69
70         lo_address_free (addr);
71 }
72
73 void
74 OSCCueObserver::tick ()
75 {
76         if (!tick_enable) {
77                 return;
78         }
79         float now_meter;
80         if (_strip->peak_meter()) {
81                 now_meter = _strip->peak_meter()->meter_level(0, MeterMCP);
82         } else {
83                 now_meter = -193;
84         }
85         if (now_meter < -120) now_meter = -193;
86         if (_last_meter != now_meter) {
87                 string path = "/cue/signal";
88                 lo_message msg = lo_message_new ();
89                 float signal;
90                 if (now_meter < -40) {
91                         signal = 0;
92                 } else {
93                         signal = 1;
94                 }
95                 lo_message_add_float (msg, signal);
96                 lo_send_message (addr, path.c_str(), msg);
97                 lo_message_free (msg);
98         }
99         _last_meter = now_meter;
100
101         for (uint32_t i = 0; i < gain_timeout.size(); i++) {
102                 if (gain_timeout[i]) {
103                         if (gain_timeout[i] == 1) {
104                                 name_changed (ARDOUR::Properties::name, i);
105                         }
106                         gain_timeout[i]--;
107                 }
108         }
109
110 }
111
112 void
113 OSCCueObserver::send_init()
114 {
115         for (uint32_t i = 0; i < sends.size(); i++) {
116                 boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (sends[i]);
117                 boost::shared_ptr<Send> send = r->internal_send_for (boost::dynamic_pointer_cast<Route> (_strip));
118                 if (r) {
119                         r->processors_changed.connect  (send_connections, MISSING_INVALIDATOR, boost::bind (&OSCCueObserver::send_restart, this), OSC::instance());
120                 }
121
122                 if (send) {
123                         // send name
124                         if (r) {
125                                 sends[i]->PropertyChanged.connect (send_connections, MISSING_INVALIDATOR, boost::bind (&OSCCueObserver::name_changed, this, boost::lambda::_1, i + 1), OSC::instance());
126                                 name_changed (ARDOUR::Properties::name, i + 1);
127                         }
128                                 
129
130                         if (send->gain_control()) {
131                                 gain_timeout.push_back (0);
132                                 send->gain_control()->Changed.connect (send_connections, MISSING_INVALIDATOR, boost::bind (&OSCCueObserver::send_gain_message, this, i + 1, send->gain_control()), OSC::instance());
133                                 send_gain_message (i + 1, send->gain_control());
134                         }
135                         
136                         boost::shared_ptr<Processor> proc = boost::dynamic_pointer_cast<Processor> (send);
137                                 proc->ActiveChanged.connect (send_connections, MISSING_INVALIDATOR, boost::bind (&OSCCueObserver::send_enabled_message, this, X_("/cue/send_enable"), i + 1, proc->enabled()), OSC::instance());
138                                 send_enabled_message (X_("/cue/send/enable"), i + 1, proc->enabled());
139                 }
140         }
141
142 }
143
144 void
145 OSCCueObserver::send_end ()
146 {
147         send_connections.drop_connections ();
148         for (uint32_t i = 1; i <= sends.size(); i++) {
149                 clear_strip (string_compose ("/cue/send/fader/%1", i), 0);
150                 clear_strip (string_compose ("/cue/send/enable/%1", i), 0);
151                 text_with_id ("/cue/send/name", i, " ");
152         }
153 }
154
155 void
156 OSCCueObserver::send_restart ()
157 {
158         tick_enable = false;
159         send_end();
160         send_init();
161         tick_enable = true;
162 }
163
164 void
165 OSCCueObserver::name_changed (const PBD::PropertyChange& what_changed, uint32_t id)
166 {
167         if (!what_changed.contains (ARDOUR::Properties::name)) {
168             return;
169         }
170
171         if (!_strip) {
172                 return;
173         }
174         if (id) {
175                 text_with_id ("/cue/send/name", id, sends[id - 1]->name());
176         } else {
177                 text_with_id ("/cue/name", 0, _strip->name());
178         }
179 }
180
181 void
182 OSCCueObserver::send_change_message (string path, uint32_t id, boost::shared_ptr<Controllable> controllable)
183 {
184         lo_message msg = lo_message_new ();
185
186         if (id) {
187                 path = string_compose("%1/%2", path, id);
188         }
189         float val = controllable->get_value();
190         lo_message_add_float (msg, (float) controllable->internal_to_interface (val));
191
192         lo_send_message (addr, path.c_str(), msg);
193         lo_message_free (msg);
194 }
195
196 void
197 OSCCueObserver::text_with_id (string path, uint32_t id, string val)
198 {
199         lo_message msg = lo_message_new ();
200         if (id) {
201                 path = string_compose("%1/%2", path, id);
202         }
203
204         lo_message_add_string (msg, val.c_str());
205
206         lo_send_message (addr, path.c_str(), msg);
207         lo_message_free (msg);
208 }
209
210 void
211 OSCCueObserver::send_gain_message (uint32_t id,  boost::shared_ptr<Controllable> controllable)
212 {
213         string path = "/cue";
214         if (id) {
215                 path = "/cue/send";
216         }
217
218         text_with_id (string_compose ("%1/name", path), id, string_compose ("%1%2%3", std::fixed, std::setprecision(2), accurate_coefficient_to_dB (controllable->get_value())));
219         path = string_compose ("%1/fader", path);
220         if (id) {
221                 path = string_compose ("%1/%2", path, id);
222         }
223         lo_message msg = lo_message_new ();
224         lo_message_add_float (msg, gain_to_slider_position (controllable->get_value()));
225         gain_timeout[id] = 8;
226
227         lo_send_message (addr, path.c_str(), msg);
228         lo_message_free (msg);
229 }
230
231 void
232 OSCCueObserver::send_enabled_message (std::string path, uint32_t id, bool enabled)
233 {
234         lo_message msg = lo_message_new ();
235
236         if (id) {
237                 path = string_compose("%1/%2", path, id);
238         }
239         lo_message_add_float (msg, (float) enabled);
240
241         lo_send_message (addr, path.c_str(), msg);
242         lo_message_free (msg);
243         
244 }
245
246 void
247 OSCCueObserver::clear_strip (string path, float val)
248 {
249         lo_message msg = lo_message_new ();
250         lo_message_add_float (msg, val);
251
252         lo_send_message (addr, path.c_str(), msg);
253         lo_message_free (msg);
254
255 }
256