ardour
speakers.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 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 #include "pbd/error.h"
20 #include "pbd/convert.h"
21 #include "pbd/locale_guard.h"
22 
23 #include "ardour/speaker.h"
24 #include "ardour/speakers.h"
25 
26 #include "i18n.h"
27 
28 using namespace ARDOUR;
29 using namespace PBD;
30 using namespace std;
31 
33  : id (i)
34 {
35  move (position);
36 }
37 
39  : id (o.id)
40  , _coords (o._coords)
41  , _angles (o._angles)
42 {
43 
44 }
45 
46 Speaker &
48 {
49  if (&o == this) {
50  return *this;
51  }
52 
53  id = o.id;
54  _coords = o._coords;
55  _angles = o._angles;
56 
57  return *this;
58 }
59 
60 void
61 Speaker::move (const AngularVector& new_position)
62 {
63  _angles = new_position;
65 
66  PositionChanged (); /* EMIT SIGNAL */
67 }
68 
70 {
71 }
72 
74  : Stateful ()
75 {
76  _speakers = s._speakers;
77 }
78 
80 {
81 }
82 
83 Speakers&
85 {
86  if (&s != this) {
87  _speakers = s._speakers;
88  }
89  return *this;
90 }
91 
92 void
94 {
95  for (vector<Speaker>::iterator i = _speakers.begin(); i != _speakers.end(); ++i) {
96  o << "Speaker " << (*i).id << " @ "
97  << (*i).coords().x << ", " << (*i).coords().y << ", " << (*i).coords().z
98  << " azimuth " << (*i).angles().azi
99  << " elevation " << (*i).angles().ele
100  << " distance " << (*i).angles().length
101  << endl;
102  }
103 }
104 
105 void
107 {
108  _speakers.clear ();
109  update ();
110 }
111 
112 int
114 {
115  int id = _speakers.size();
116 
117  _speakers.push_back (Speaker (id, position));
118  update ();
119 
120  Changed ();
121 
122  return id;
123 }
124 
125 void
127 {
128  for (vector<Speaker>::iterator i = _speakers.begin(); i != _speakers.end(); ++i) {
129  if (i->id == id) {
130  i = _speakers.erase (i);
131  update ();
132  break;
133  }
134  }
135 }
136 
137 void
138 Speakers::move_speaker (int id, const AngularVector& new_position)
139 {
140  for (vector<Speaker>::iterator i = _speakers.begin(); i != _speakers.end(); ++i) {
141  if ((*i).id == id) {
142  (*i).move (new_position);
143  update ();
144  break;
145  }
146  }
147 }
148 
149 void
151 {
152  double o = 180.0;
153 
154  /* default assignment of speaker position for n speakers */
155 
156  assert (n>0);
157 
158  switch (n) {
159  case 1:
160  add_speaker (AngularVector (o +0.0, 0.0));
161  break;
162 
163  case 2:
164  add_speaker (AngularVector (o +60.0, 0.0));
165  add_speaker (AngularVector (o -60.0, 0.0));
166  break;
167 
168  case 3:
169  add_speaker (AngularVector (o +60.0, 0.0));
170  add_speaker (AngularVector (o -60.0, 0.0));
171  add_speaker (AngularVector (o +180.0, 0.0));
172  break;
173  case 4:
174  /* 4.0 with regular spacing */
175  add_speaker (AngularVector (o +45.0, 0.0));
176  add_speaker (AngularVector (o -45.0, 0.0));
177  add_speaker (AngularVector (o +135.0, 0.0));
178  add_speaker (AngularVector (o -135.0, 0.0));
179  break;
180  case 5:
181  /* 5.0 with regular spacing */
182  add_speaker (AngularVector (o +72.0, 0.0));
183  add_speaker (AngularVector (o -72.0, 0.0));
184  add_speaker (AngularVector (o +0.0, 0.0));
185  add_speaker (AngularVector (o +144.0, 0.0));
186  add_speaker (AngularVector (o -144.0, 0.0));
187  break;
188  case 6:
189  /* 6.0 with regular spacing */
190  add_speaker (AngularVector (o +60.0, 0.0));
191  add_speaker (AngularVector (o -60.0, 0.0));
192  add_speaker (AngularVector (o +0.0, 0.0));
193  add_speaker (AngularVector (o +120.0, 0.0));
194  add_speaker (AngularVector (o -120.0, 0.0));
195  add_speaker (AngularVector (o +180.0, 0.0));
196  break;
197  case 7:
198  /* 7.0 with regular front spacing */
199  add_speaker (AngularVector (o +45.0, 0.0));
200  add_speaker (AngularVector (o -45.0, 0.0));
201  add_speaker (AngularVector (o +0.0, 0.0));
202  add_speaker (AngularVector (o +90.0, 0.0));
203  add_speaker (AngularVector (o -90.0, 0.0));
204  add_speaker (AngularVector (o +150.0, 0.0));
205  add_speaker (AngularVector (o -150.0, 0.0));
206  break;
207  case 10:
208  /* 5+4 with 45°/90° spacing */
209  add_speaker (AngularVector (o +45.0, 0.0));
210  add_speaker (AngularVector (o -45.0, 0.0));
211  add_speaker (AngularVector (o +0.0, 0.0));
212  add_speaker (AngularVector (o +135.0, 0.0));
213  add_speaker (AngularVector (o -135.0, 0.0));
214  add_speaker (AngularVector (o +45.0, 60.0));
215  add_speaker (AngularVector (o -45.0, 60.0));
216  add_speaker (AngularVector (o +135.0, 60.0));
217  add_speaker (AngularVector (o -135.0, 60.0));
218  add_speaker (AngularVector (o +0.0, 90.0));
219  break;
220 
221  default:
222  {
223  double degree_step = 360.0 / n;
224  double deg;
225  uint32_t i;
226 
227  /* even number of speakers? make sure the top two are either side of "top".
228  otherwise, just start at the "top" (90.0 degrees) and rotate around
229  */
230 
231  if (n % 2) {
232  deg = 360 + o + degree_step;
233  } else {
234  deg = 360 + o;
235  }
236  for (i = 0; i < n; ++i, deg -= degree_step) {
237  add_speaker (AngularVector (fmod(deg, 360), 0.0));
238  }
239  }
240  }
241 }
242 
243 XMLNode&
245 {
246  XMLNode* node = new XMLNode (X_("Speakers"));
247  char buf[32];
248  LocaleGuard lg (X_("C"));
249 
250  for (vector<Speaker>::const_iterator i = _speakers.begin(); i != _speakers.end(); ++i) {
251  XMLNode* speaker = new XMLNode (X_("Speaker"));
252 
253  snprintf (buf, sizeof (buf), "%.12g", (*i).angles().azi);
254  speaker->add_property (X_("azimuth"), buf);
255  snprintf (buf, sizeof (buf), "%.12g", (*i).angles().ele);
256  speaker->add_property (X_("elevation"), buf);
257  snprintf (buf, sizeof (buf), "%.12g", (*i).angles().length);
258  speaker->add_property (X_("distance"), buf);
259 
260  node->add_child_nocopy (*speaker);
261  }
262 
263  return *node;
264 }
265 
266 int
267 Speakers::set_state (const XMLNode& node, int /*version*/)
268 {
270  const XMLProperty* prop;
271  double a, e, d;
272  LocaleGuard lg (X_("C"));
273  int n = 0;
274 
275  _speakers.clear ();
276 
277  for (i = node.children().begin(); i != node.children().end(); ++i, ++n) {
278  if ((*i)->name() == X_("Speaker")) {
279  if ((prop = (*i)->property (X_("azimuth"))) == 0) {
280  warning << _("Speaker information is missing azimuth - speaker ignored") << endmsg;
281  continue;
282  }
283  a = atof (prop->value());
284 
285  if ((prop = (*i)->property (X_("elevation"))) == 0) {
286  warning << _("Speaker information is missing elevation - speaker ignored") << endmsg;
287  continue;
288  }
289  e = atof (prop->value());
290 
291  if ((prop = (*i)->property (X_("distance"))) == 0) {
292  warning << _("Speaker information is missing distance - speaker ignored") << endmsg;
293  continue;
294  }
295  d = atof (prop->value());
296 
297  add_speaker (AngularVector (a, e, d));
298  }
299  }
300 
301  update ();
302 
303  return 0;
304 }
std::vector< Speaker > _speakers
Definition: speakers.h:60
const std::string & value() const
Definition: xml++.h:159
virtual ~Speakers()
Definition: speakers.cc:79
int set_state(const XMLNode &, int version)
Definition: speakers.cc:267
Definition: Beats.hpp:239
LIBPBD_API Transmitter warning
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
Speakers & operator=(const Speakers &)
Definition: speakers.cc:84
void cartesian(CartesianVector &c) const
Definition: cartesian.h:95
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
PBD::CartesianVector _coords
Definition: speaker.h:46
#define _(Text)
Definition: i18n.h:11
virtual void remove_speaker(int id)
Definition: speakers.cc:126
PBD::AngularVector _angles
Definition: speaker.h:47
#define X_(Text)
Definition: i18n.h:13
virtual int add_speaker(const PBD::AngularVector &)
Definition: speakers.cc:113
Definition: amp.h:29
const PBD::ID & id() const
Definition: stateful.h:68
XMLNode & get_state()
Definition: speakers.cc:244
PBD::Signal0< void > Changed
Definition: speakers.h:57
void move(const PBD::AngularVector &new_position)
Definition: speakers.cc:61
XMLProperty * add_property(const char *name, const std::string &value)
PBD::Signal0< void > PositionChanged
Definition: speaker.h:43
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
void setup_default_speakers(uint32_t nspeakers)
Definition: speakers.cc:150
Definition: xml++.h:95
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
Definition: region.cc:65
virtual void clear_speakers()
Definition: speakers.cc:106
Definition: debug.h:30
Speaker(int, const PBD::AngularVector &position)
Definition: speakers.cc:32
virtual void move_speaker(int id, const PBD::AngularVector &new_position)
Definition: speakers.cc:138
virtual void update()
Definition: speakers.h:62
Speaker & operator=(const Speaker &)
Definition: speakers.cc:47
XMLNodeList::const_iterator XMLNodeConstIterator
Definition: xml++.h:49
void dump_speakers(std::ostream &)
Definition: speakers.cc:93
double atof(const string &s)
Definition: convert.cc:158