reload alpha1-6 Pannable XML state so that panning of existing sessions should work...
[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
189         node->add_child_nocopy (pan_azimuth_control->get_state());
190         node->add_child_nocopy (pan_width_control->get_state());
191         node->add_child_nocopy (pan_elevation_control->get_state());
192         node->add_child_nocopy (pan_frontback_control->get_state());
193         node->add_child_nocopy (pan_lfe_control->get_state());
194
195         node->add_child_nocopy (get_automation_xml_state ());
196
197         return *node;
198 }
199
200 int
201 Pannable::set_state (const XMLNode& root, int version)
202 {
203         if (root.name() != X_("Pannable")) {
204                 warning << string_compose (_("Pannable given XML data for %1 - ignored"), root.name()) << endmsg;
205                 return -1;
206         }
207
208         const XMLNodeList& nlist (root.children());
209         XMLNodeConstIterator niter;
210
211         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
212                 if ((*niter)->name() == Controllable::xml_node_name) {
213                         const XMLProperty* prop = (*niter)->property (X_("name"));
214
215                         if (!prop) {
216                                 continue;
217                         }
218
219                         if (prop->value() == pan_azimuth_control->name()) {
220                                 pan_azimuth_control->set_state (**niter, version);
221                         } else if (prop->value() == pan_width_control->name()) {
222                                 pan_width_control->set_state (**niter, version);
223                         } else if (prop->value() == pan_elevation_control->name()) {
224                                 pan_elevation_control->set_state (**niter, version);
225                         } else if (prop->value() == pan_frontback_control->name()) {
226                                 pan_frontback_control->set_state (**niter, version);
227                         } else if (prop->value() == pan_lfe_control->name()) {
228                                 pan_lfe_control->set_state (**niter, version);
229                         }
230
231                 } else if ((*niter)->name() == Automatable::xml_node_name) {
232                         set_automation_xml_state (**niter, PanAzimuthAutomation);
233
234                 } else {
235                         const XMLProperty* prop;
236
237                         /* old school (alpha1-6) XML info */
238
239                         if ((*niter)->name() == pan_azimuth_control->name()) {
240                                 prop = (*niter)->property (X_("value"));
241                                 if (prop) {
242                                         pan_azimuth_control->set_value (atof (prop->value()));
243                                 }
244                         } else if ((*niter)->name() == pan_width_control->name()) {
245                                 prop = (*niter)->property (X_("value"));
246                                 if (prop) {
247                                         pan_width_control->set_value (atof (prop->value()));
248                                 }
249                         } else if ((*niter)->name() == pan_elevation_control->name()) {
250                                 prop = (*niter)->property (X_("value"));
251                                 if (prop) {
252                                         pan_elevation_control->set_value (atof (prop->value()));
253                                 }
254                         } else if ((*niter)->name() == pan_frontback_control->name()) {
255                                 prop = (*niter)->property (X_("value"));
256                                 if (prop) {
257                                         pan_frontback_control->set_value (atof (prop->value()));
258                                 }
259                         } else if ((*niter)->name() == pan_lfe_control->name()) {
260                                 prop = (*niter)->property (X_("value"));
261                                 if (prop) {
262                                         pan_lfe_control->set_value (atof (prop->value()));
263                                 }
264                         }
265                 }
266         }
267
268         _has_state = true;
269
270         return 0;
271 }
272
273 string
274 Pannable::value_as_string (boost::shared_ptr<AutomationControl> ac) const
275 {
276         boost::shared_ptr<Panner> p = panner ();
277
278         if (p) {
279                 return p->value_as_string (ac);
280         }
281
282         return Automatable::value_as_string (ac);
283 }