NO-OP: whitespace/comments
[ardour.git] / libs / ardour / speakers.cc
1 /*
2  * Copyright (C) 2010-2011 David Robillard <d@drobilla.net>
3  * Copyright (C) 2010-2016 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2014-2016 Robin Gareus <robin@gareus.org>
5  * Copyright (C) 2016 Tim Mayberry <mojofunk@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "pbd/error.h"
23
24 #include "ardour/speaker.h"
25 #include "ardour/speakers.h"
26
27 #include "pbd/i18n.h"
28
29 using namespace ARDOUR;
30 using namespace PBD;
31 using namespace std;
32
33 Speaker::Speaker (int i, const AngularVector& position)
34         : id (i)
35 {
36         move (position);
37 }
38
39 Speaker::Speaker (Speaker const & o)
40         : id (o.id)
41         , _coords (o._coords)
42         , _angles (o._angles)
43 {
44
45 }
46
47 Speaker &
48 Speaker::operator= (Speaker const & o)
49 {
50         if (&o == this) {
51                 return *this;
52         }
53
54         id = o.id;
55         _coords = o._coords;
56         _angles = o._angles;
57
58         return *this;
59 }
60
61 void
62 Speaker::move (const AngularVector& new_position)
63 {
64         _angles = new_position;
65         _angles.cartesian (_coords);
66
67         PositionChanged (); /* EMIT SIGNAL */
68 }
69
70 Speakers::Speakers ()
71 {
72 }
73
74 Speakers::Speakers (const Speakers& s)
75         : Stateful ()
76 {
77         _speakers = s._speakers;
78 }
79
80 Speakers::~Speakers ()
81 {
82 }
83
84 Speakers&
85 Speakers::operator= (const Speakers& s)
86 {
87         if (&s != this) {
88                 _speakers = s._speakers;
89         }
90         return *this;
91 }
92
93 void
94 Speakers::dump_speakers (ostream& o)
95 {
96         for (vector<Speaker>::iterator i = _speakers.begin(); i != _speakers.end(); ++i) {
97                 o << "Speaker " << (*i).id << " @ "
98                   << (*i).coords().x << ", " << (*i).coords().y << ", " << (*i).coords().z
99                   << " azimuth " << (*i).angles().azi
100                   << " elevation " << (*i).angles().ele
101                   << " distance " << (*i).angles().length
102                   << endl;
103         }
104 }
105
106 void
107 Speakers::clear_speakers ()
108 {
109         _speakers.clear ();
110         update ();
111 }
112
113 int
114 Speakers::add_speaker (const AngularVector& position)
115 {
116         int id = _speakers.size();
117
118         _speakers.push_back (Speaker (id, position));
119         update ();
120
121         Changed ();
122
123         return id;
124 }
125
126 void
127 Speakers::remove_speaker (int id)
128 {
129         for (vector<Speaker>::iterator i = _speakers.begin(); i != _speakers.end(); ++i) {
130                 if (i->id == id) {
131                         i = _speakers.erase (i);
132                         update ();
133                         break;
134                 }
135         }
136 }
137
138 void
139 Speakers::move_speaker (int id, const AngularVector& new_position)
140 {
141         for (vector<Speaker>::iterator i = _speakers.begin(); i != _speakers.end(); ++i) {
142                 if ((*i).id == id) {
143                         (*i).move (new_position);
144                         update ();
145                         break;
146                 }
147         }
148 }
149
150 void
151 Speakers::setup_default_speakers (uint32_t n)
152 {
153         double o = 180.0;
154
155         /* default assignment of speaker position for n speakers */
156
157         assert (n>0);
158
159         switch (n) {
160         case 1:
161                 add_speaker (AngularVector (o   +0.0, 0.0));
162                 break;
163
164         case 2:
165                 add_speaker (AngularVector (o  +60.0, 0.0));
166                 add_speaker (AngularVector (o  -60.0, 0.0));
167                 break;
168
169         case 3:
170                 add_speaker (AngularVector (o  +60.0, 0.0));
171                 add_speaker (AngularVector (o  -60.0, 0.0));
172                 add_speaker (AngularVector (o +180.0, 0.0));
173                 break;
174         case 4:
175                 /* 4.0 with regular spacing */
176                 add_speaker (AngularVector (o  +45.0, 0.0));
177                 add_speaker (AngularVector (o  -45.0, 0.0));
178                 add_speaker (AngularVector (o +135.0, 0.0));
179                 add_speaker (AngularVector (o -135.0, 0.0));
180                 break;
181         case 5:
182                 /* 5.0 with regular spacing */
183                 add_speaker (AngularVector (o  +72.0, 0.0));
184                 add_speaker (AngularVector (o  -72.0, 0.0));
185                 add_speaker (AngularVector (o   +0.0, 0.0));
186                 add_speaker (AngularVector (o +144.0, 0.0));
187                 add_speaker (AngularVector (o -144.0, 0.0));
188                 break;
189         case 6:
190                 /* 6.0 with regular spacing */
191                 add_speaker (AngularVector (o  +60.0, 0.0));
192                 add_speaker (AngularVector (o  -60.0, 0.0));
193                 add_speaker (AngularVector (o   +0.0, 0.0));
194                 add_speaker (AngularVector (o +120.0, 0.0));
195                 add_speaker (AngularVector (o -120.0, 0.0));
196                 add_speaker (AngularVector (o +180.0, 0.0));
197                 break;
198         case 7:
199                 /* 7.0 with regular front spacing */
200                 add_speaker (AngularVector (o  +45.0, 0.0));
201                 add_speaker (AngularVector (o  -45.0, 0.0));
202                 add_speaker (AngularVector (o   +0.0, 0.0));
203                 add_speaker (AngularVector (o  +90.0, 0.0));
204                 add_speaker (AngularVector (o  -90.0, 0.0));
205                 add_speaker (AngularVector (o +150.0, 0.0));
206                 add_speaker (AngularVector (o -150.0, 0.0));
207                 break;
208         case 10:
209                 /* 5+4 with 45°/90° spacing */
210                 add_speaker (AngularVector (o  +45.0, 0.0));
211                 add_speaker (AngularVector (o  -45.0, 0.0));
212                 add_speaker (AngularVector (o   +0.0, 0.0));
213                 add_speaker (AngularVector (o +135.0, 0.0));
214                 add_speaker (AngularVector (o -135.0, 0.0));
215                 add_speaker (AngularVector (o  +45.0, 60.0));
216                 add_speaker (AngularVector (o  -45.0, 60.0));
217                 add_speaker (AngularVector (o +135.0, 60.0));
218                 add_speaker (AngularVector (o -135.0, 60.0));
219                 add_speaker (AngularVector (o   +0.0, 90.0));
220                 break;
221
222         default:
223         {
224                 double degree_step = 360.0 / n;
225                 double deg;
226                 uint32_t i;
227
228                 /* even number of speakers? make sure the top two are either side of "top".
229                    otherwise, just start at the "top" (90.0 degrees) and rotate around
230                 */
231
232                 if (n % 2) {
233                         deg = 360 + o + degree_step;
234                 } else {
235                         deg = 360 + o;
236                 }
237                 for (i = 0; i < n; ++i, deg -= degree_step) {
238                         add_speaker (AngularVector (fmod(deg, 360), 0.0));
239                 }
240         }
241         }
242 }
243
244 XMLNode&
245 Speakers::get_state ()
246 {
247         XMLNode* node = new XMLNode (X_("Speakers"));
248
249         for (vector<Speaker>::const_iterator i = _speakers.begin(); i != _speakers.end(); ++i) {
250                 XMLNode* speaker = new XMLNode (X_("Speaker"));
251
252                 speaker->set_property (X_("azimuth"), (*i).angles().azi);
253                 speaker->set_property (X_("elevation"), (*i).angles().ele);
254                 speaker->set_property (X_("distance"), (*i).angles().length);
255
256                 node->add_child_nocopy (*speaker);
257         }
258
259         return *node;
260 }
261
262 int
263 Speakers::set_state (const XMLNode& node, int /*version*/)
264 {
265         XMLNodeConstIterator i;
266
267         _speakers.clear ();
268
269         for (i = node.children().begin(); i != node.children().end(); ++i) {
270                 if ((*i)->name() == X_("Speaker")) {
271                         double a, e, d;
272                         if (!(*i)->get_property (X_("azimuth"), a) ||
273                             !(*i)->get_property (X_("elevation"), e) ||
274                             !(*i)->get_property (X_("distance"), d)) {
275                                 warning << _("Speaker information is missing - speaker ignored") << endmsg;
276                                 continue;
277                         }
278
279                         add_speaker (AngularVector (a, e, d));
280                 }
281         }
282
283         update ();
284
285         return 0;
286 }