Re-fix compile failure with --no-nls (#3111).
[ardour.git] / libs / ardour / pannable.cc
1 /*
2     Copyright (C) 2011 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 "pbd/error.h"
21 #include "pbd/convert.h"
22 #include "pbd/compose.h"
23
24 #include "ardour/debug.h"
25 #include "ardour/automation_control.h"
26 #include "ardour/automation_list.h"
27 #include "ardour/pannable.h"
28 #include "ardour/panner.h"
29 #include "ardour/pan_controllable.h"
30 #include "ardour/session.h"
31
32 #include "i18n.h"
33
34 using namespace std;
35 using namespace PBD;
36 using namespace ARDOUR;
37
38 Pannable::Pannable (Session& s)
39         : Automatable (s)
40         , SessionHandleRef (s)
41         , pan_azimuth_control (new PanControllable (s, "", this, PanAzimuthAutomation))
42         , pan_elevation_control (new PanControllable (s, "", this, PanElevationAutomation))
43         , pan_width_control (new PanControllable (s, "", this, PanWidthAutomation))
44         , pan_frontback_control (new PanControllable (s, "", this, PanFrontBackAutomation))
45         , pan_lfe_control (new PanControllable (s, "", this, PanLFEAutomation))
46         , _auto_state (Off)
47         , _auto_style (Absolute)
48         , _has_state (false)
49         , _responding_to_control_auto_state_change (0)
50 {
51         add_control (pan_azimuth_control);
52         add_control (pan_elevation_control);
53         add_control (pan_width_control);
54         add_control (pan_frontback_control);
55         add_control (pan_lfe_control);
56
57         /* all controls change state together */
58
59         pan_azimuth_control->alist()->automation_state_changed.connect_same_thread (*this, boost::bind (&Pannable::control_auto_state_changed, this, _1));
60         pan_elevation_control->alist()->automation_state_changed.connect_same_thread (*this, boost::bind (&Pannable::control_auto_state_changed, this, _1));
61         pan_width_control->alist()->automation_state_changed.connect_same_thread (*this, boost::bind (&Pannable::control_auto_state_changed, this, _1));
62         pan_frontback_control->alist()->automation_state_changed.connect_same_thread (*this, boost::bind (&Pannable::control_auto_state_changed, this, _1));
63         pan_lfe_control->alist()->automation_state_changed.connect_same_thread (*this, boost::bind (&Pannable::control_auto_state_changed, this, _1));
64
65         pan_azimuth_control->Changed.connect_same_thread (*this, boost::bind (&Pannable::value_changed, this));
66         pan_elevation_control->Changed.connect_same_thread (*this, boost::bind (&Pannable::value_changed, this));
67         pan_width_control->Changed.connect_same_thread (*this, boost::bind (&Pannable::value_changed, this));
68         pan_frontback_control->Changed.connect_same_thread (*this, boost::bind (&Pannable::value_changed, this));
69         pan_lfe_control->Changed.connect_same_thread (*this, boost::bind (&Pannable::value_changed, this));
70 }
71
72 Pannable::~Pannable ()
73 {
74         DEBUG_TRACE (DEBUG::Destruction, string_compose ("pannable @ %1 destructor\n", this));
75 }
76
77 void
78 Pannable::control_auto_state_changed (AutoState new_state)
79 {
80         if (_responding_to_control_auto_state_change) {
81                 return;
82         }
83
84         _responding_to_control_auto_state_change++;
85
86         pan_azimuth_control->set_automation_state (new_state);
87         pan_width_control->set_automation_state (new_state);
88         pan_elevation_control->set_automation_state (new_state);
89         pan_frontback_control->set_automation_state (new_state);
90         pan_lfe_control->set_automation_state (new_state);
91
92         _responding_to_control_auto_state_change--;
93
94         _auto_state = new_state;
95         automation_state_changed (new_state);  /* EMIT SIGNAL */
96 }
97
98 void
99 Pannable::set_panner (boost::shared_ptr<Panner> p)
100 {
101         _panner = p;
102 }
103
104 void
105 Pannable::value_changed ()
106 {
107         _session.set_dirty ();
108 }
109
110 void
111 Pannable::set_automation_state (AutoState state)
112 {
113         if (state != _auto_state) {
114                 _auto_state = state;
115
116                 const Controls& c (controls());
117         
118                 for (Controls::const_iterator ci = c.begin(); ci != c.end(); ++ci) {
119                         boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl>(ci->second);
120                         if (ac) {
121                                 ac->alist()->set_automation_state (state);
122                         }
123                 }
124                 
125                 session().set_dirty ();
126                 automation_state_changed (_auto_state);
127         }
128 }
129
130 void
131 Pannable::set_automation_style (AutoStyle style)
132 {
133         if (style != _auto_style) {
134                 _auto_style = style;
135
136                 const Controls& c (controls());
137                 
138                 for (Controls::const_iterator ci = c.begin(); ci != c.end(); ++ci) {
139                         boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl>(ci->second);
140                         if (ac) {
141                                 ac->alist()->set_automation_style (style);
142                         }
143                 }
144                 
145                 session().set_dirty ();
146                 automation_style_changed ();
147         }
148 }
149
150 void
151 Pannable::start_touch (double when)
152 {
153         const Controls& c (controls());
154         
155         for (Controls::const_iterator ci = c.begin(); ci != c.end(); ++ci) {
156                 boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl>(ci->second);
157                 if (ac) {
158                         ac->alist()->start_touch (when);
159                 }
160         }
161         g_atomic_int_set (&_touching, 1);
162 }
163
164 void
165 Pannable::stop_touch (bool mark, double when)
166 {
167         const Controls& c (controls());
168         
169         for (Controls::const_iterator ci = c.begin(); ci != c.end(); ++ci) {
170                 boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl>(ci->second);
171                 if (ac) {
172                         ac->alist()->stop_touch (mark, when);
173                 }
174         }
175         g_atomic_int_set (&_touching, 0);
176 }
177
178 XMLNode&
179 Pannable::get_state ()
180 {
181         return state (true);
182 }
183
184 XMLNode&
185 Pannable::state (bool full)
186 {
187         XMLNode* node = new XMLNode (X_("Pannable"));
188         XMLNode* control_node;
189         char buf[32];
190
191         control_node = new XMLNode (X_("azimuth"));
192         snprintf (buf, sizeof(buf), "%.12g", pan_azimuth_control->get_value());
193         control_node->add_property (X_("value"), buf);
194         node->add_child_nocopy (*control_node);
195         
196         control_node = new XMLNode (X_("width"));
197         snprintf (buf, sizeof(buf), "%.12g", pan_width_control->get_value());
198         control_node->add_property (X_("value"), buf);
199         node->add_child_nocopy (*control_node);
200
201         control_node = new XMLNode (X_("elevation"));
202         snprintf (buf, sizeof(buf), "%.12g", pan_elevation_control->get_value());
203         control_node->add_property (X_("value"), buf);
204         node->add_child_nocopy (*control_node);
205
206         control_node = new XMLNode (X_("frontback"));
207         snprintf (buf, sizeof(buf), "%.12g", pan_frontback_control->get_value());
208         control_node->add_property (X_("value"), buf);
209         node->add_child_nocopy (*control_node);
210
211         control_node = new XMLNode (X_("lfe"));
212         snprintf (buf, sizeof(buf), "%.12g", pan_lfe_control->get_value());
213         control_node->add_property (X_("value"), buf);
214         node->add_child_nocopy (*control_node);
215         
216         node->add_child_nocopy (get_automation_xml_state ());
217
218      return *node;
219 }
220
221 int
222 Pannable::set_state (const XMLNode& root, int /*version - not used*/)
223 {
224         if (root.name() != X_("Pannable")) {
225                 warning << string_compose (_("Pannable given XML data for %1 - ignored"), root.name()) << endmsg;
226                 return -1;
227         }
228         
229         XMLNodeList nlist;
230         XMLNodeConstIterator niter;
231         const XMLProperty *prop;
232
233         nlist = root.children();
234
235         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
236                 if ((*niter)->name() == X_("azimuth")) {
237                         prop = (*niter)->property (X_("value"));
238                         if (prop) {
239                                 pan_azimuth_control->set_value (atof (prop->value()));
240                         }
241                 } else if ((*niter)->name() == X_("width")) {
242                         prop = (*niter)->property (X_("value"));
243                         if (prop) {
244                                 pan_width_control->set_value (atof (prop->value()));
245                         }
246                 } else if ((*niter)->name() == X_("elevation")) {
247                         prop = (*niter)->property (X_("value"));
248                         if (prop) {
249                                 pan_elevation_control->set_value (atof (prop->value()));
250                         }
251                 } else if ((*niter)->name() == X_("azimuth")) {
252                         prop = (*niter)->property (X_("value"));
253                         if (prop) {
254                                 pan_frontback_control->set_value (atof (prop->value()));
255                         }
256                 } else if ((*niter)->name() == X_("lfe")) {
257                         prop = (*niter)->property (X_("value"));
258                         if (prop) {
259                                 pan_lfe_control->set_value (atof (prop->value()));
260                         }
261                 } else if ((*niter)->name() == Automatable::xml_node_name) {
262                         set_automation_xml_state (**niter, PanAzimuthAutomation);
263                 }
264         }
265         
266         _has_state = true;
267
268         return 0;
269 }
270
271 string 
272 Pannable::value_as_string (boost::shared_ptr<AutomationControl> ac) const
273 {
274         boost::shared_ptr<Panner> p = panner ();
275
276         if (p) {
277                 return p->value_as_string (ac);
278         } 
279
280         return Automatable::value_as_string (ac);
281 }