/* * Copyright (C) 2010-2011 David Robillard * Copyright (C) 2010-2016 Paul Davis * Copyright (C) 2014-2016 Robin Gareus * Copyright (C) 2016 Tim Mayberry * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "pbd/error.h" #include "ardour/speaker.h" #include "ardour/speakers.h" #include "pbd/i18n.h" using namespace ARDOUR; using namespace PBD; using namespace std; Speaker::Speaker (int i, const AngularVector& position) : id (i) { move (position); } Speaker::Speaker (Speaker const & o) : id (o.id) , _coords (o._coords) , _angles (o._angles) { } Speaker & Speaker::operator= (Speaker const & o) { if (&o == this) { return *this; } id = o.id; _coords = o._coords; _angles = o._angles; return *this; } void Speaker::move (const AngularVector& new_position) { _angles = new_position; _angles.cartesian (_coords); PositionChanged (); /* EMIT SIGNAL */ } Speakers::Speakers () { } Speakers::Speakers (const Speakers& s) : Stateful () { _speakers = s._speakers; } Speakers::~Speakers () { } Speakers& Speakers::operator= (const Speakers& s) { if (&s != this) { _speakers = s._speakers; } return *this; } void Speakers::dump_speakers (ostream& o) { for (vector::iterator i = _speakers.begin(); i != _speakers.end(); ++i) { o << "Speaker " << (*i).id << " @ " << (*i).coords().x << ", " << (*i).coords().y << ", " << (*i).coords().z << " azimuth " << (*i).angles().azi << " elevation " << (*i).angles().ele << " distance " << (*i).angles().length << endl; } } void Speakers::clear_speakers () { _speakers.clear (); update (); } int Speakers::add_speaker (const AngularVector& position) { int id = _speakers.size(); _speakers.push_back (Speaker (id, position)); update (); Changed (); return id; } void Speakers::remove_speaker (int id) { for (vector::iterator i = _speakers.begin(); i != _speakers.end(); ++i) { if (i->id == id) { i = _speakers.erase (i); update (); break; } } } void Speakers::move_speaker (int id, const AngularVector& new_position) { for (vector::iterator i = _speakers.begin(); i != _speakers.end(); ++i) { if ((*i).id == id) { (*i).move (new_position); update (); break; } } } void Speakers::setup_default_speakers (uint32_t n) { double o = 180.0; /* default assignment of speaker position for n speakers */ assert (n>0); switch (n) { case 1: add_speaker (AngularVector (o +0.0, 0.0)); break; case 2: add_speaker (AngularVector (o +60.0, 0.0)); add_speaker (AngularVector (o -60.0, 0.0)); break; case 3: add_speaker (AngularVector (o +60.0, 0.0)); add_speaker (AngularVector (o -60.0, 0.0)); add_speaker (AngularVector (o +180.0, 0.0)); break; case 4: /* 4.0 with regular spacing */ add_speaker (AngularVector (o +45.0, 0.0)); add_speaker (AngularVector (o -45.0, 0.0)); add_speaker (AngularVector (o +135.0, 0.0)); add_speaker (AngularVector (o -135.0, 0.0)); break; case 5: /* 5.0 with regular spacing */ add_speaker (AngularVector (o +72.0, 0.0)); add_speaker (AngularVector (o -72.0, 0.0)); add_speaker (AngularVector (o +0.0, 0.0)); add_speaker (AngularVector (o +144.0, 0.0)); add_speaker (AngularVector (o -144.0, 0.0)); break; case 6: /* 6.0 with regular spacing */ add_speaker (AngularVector (o +60.0, 0.0)); add_speaker (AngularVector (o -60.0, 0.0)); add_speaker (AngularVector (o +0.0, 0.0)); add_speaker (AngularVector (o +120.0, 0.0)); add_speaker (AngularVector (o -120.0, 0.0)); add_speaker (AngularVector (o +180.0, 0.0)); break; case 7: /* 7.0 with regular front spacing */ add_speaker (AngularVector (o +45.0, 0.0)); add_speaker (AngularVector (o -45.0, 0.0)); add_speaker (AngularVector (o +0.0, 0.0)); add_speaker (AngularVector (o +90.0, 0.0)); add_speaker (AngularVector (o -90.0, 0.0)); add_speaker (AngularVector (o +150.0, 0.0)); add_speaker (AngularVector (o -150.0, 0.0)); break; case 10: /* 5+4 with 45°/90° spacing */ add_speaker (AngularVector (o +45.0, 0.0)); add_speaker (AngularVector (o -45.0, 0.0)); add_speaker (AngularVector (o +0.0, 0.0)); add_speaker (AngularVector (o +135.0, 0.0)); add_speaker (AngularVector (o -135.0, 0.0)); add_speaker (AngularVector (o +45.0, 60.0)); add_speaker (AngularVector (o -45.0, 60.0)); add_speaker (AngularVector (o +135.0, 60.0)); add_speaker (AngularVector (o -135.0, 60.0)); add_speaker (AngularVector (o +0.0, 90.0)); break; default: { double degree_step = 360.0 / n; double deg; uint32_t i; /* even number of speakers? make sure the top two are either side of "top". otherwise, just start at the "top" (90.0 degrees) and rotate around */ if (n % 2) { deg = 360 + o + degree_step; } else { deg = 360 + o; } for (i = 0; i < n; ++i, deg -= degree_step) { add_speaker (AngularVector (fmod(deg, 360), 0.0)); } } } } XMLNode& Speakers::get_state () { XMLNode* node = new XMLNode (X_("Speakers")); for (vector::const_iterator i = _speakers.begin(); i != _speakers.end(); ++i) { XMLNode* speaker = new XMLNode (X_("Speaker")); speaker->set_property (X_("azimuth"), (*i).angles().azi); speaker->set_property (X_("elevation"), (*i).angles().ele); speaker->set_property (X_("distance"), (*i).angles().length); node->add_child_nocopy (*speaker); } return *node; } int Speakers::set_state (const XMLNode& node, int /*version*/) { XMLNodeConstIterator i; _speakers.clear (); for (i = node.children().begin(); i != node.children().end(); ++i) { if ((*i)->name() == X_("Speaker")) { double a, e, d; if (!(*i)->get_property (X_("azimuth"), a) || !(*i)->get_property (X_("elevation"), e) || !(*i)->get_property (X_("distance"), d)) { warning << _("Speaker information is missing - speaker ignored") << endmsg; continue; } add_speaker (AngularVector (a, e, d)); } } update (); return 0; }