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
Speaker(int i,const AngularVector & position)33 Speaker::Speaker (int i, const AngularVector& position)
34 : id (i)
35 {
36 move (position);
37 }
38
Speaker(Speaker const & o)39 Speaker::Speaker (Speaker const & o)
40 : id (o.id)
41 , _coords (o._coords)
42 , _angles (o._angles)
43 {
44
45 }
46
47 Speaker &
operator =(Speaker const & o)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
move(const AngularVector & new_position)62 Speaker::move (const AngularVector& new_position)
63 {
64 _angles = new_position;
65 _angles.cartesian (_coords);
66
67 PositionChanged (); /* EMIT SIGNAL */
68 }
69
Speakers()70 Speakers::Speakers ()
71 {
72 }
73
Speakers(const Speakers & s)74 Speakers::Speakers (const Speakers& s)
75 : Stateful ()
76 {
77 _speakers = s._speakers;
78 }
79
~Speakers()80 Speakers::~Speakers ()
81 {
82 }
83
84 Speakers&
operator =(const Speakers & s)85 Speakers::operator= (const Speakers& s)
86 {
87 if (&s != this) {
88 _speakers = s._speakers;
89 }
90 return *this;
91 }
92
93 void
dump_speakers(ostream & o)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
clear_speakers()107 Speakers::clear_speakers ()
108 {
109 _speakers.clear ();
110 update ();
111 }
112
113 int
add_speaker(const AngularVector & position)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
remove_speaker(int id)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
move_speaker(int id,const AngularVector & new_position)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
setup_default_speakers(uint32_t n)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&
get_state()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
set_state(const XMLNode & node,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 }
287