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