1 /* 2 * Copyright (C) 2006-2017 Paul Davis <paul@linuxaudiosystems.com> 3 * Copyright (C) 2008-2009 David Robillard <d@drobilla.net> 4 * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net> 5 * Copyright (C) 2014 Ben Loftis <ben@harrisonconsoles.com> 6 * Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License along 19 * with this program; if not, write to the Free Software Foundation, Inc., 20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 */ 22 23 #ifndef __pbd_controllable_h__ 24 #define __pbd_controllable_h__ 25 26 #include <string> 27 #include <set> 28 29 #include "pbd/libpbd_visibility.h" 30 #include "pbd/signals.h" 31 #include <glibmm/threads.h> 32 33 #include <boost/enable_shared_from_this.hpp> 34 35 #include "pbd/statefuldestructible.h" 36 37 class XMLNode; 38 39 namespace PBD { 40 41 /** This is a pure virtual class to represent a scalar control. 42 * 43 * Note that it contains no storage/state for the controllable thing that it 44 * represents. Derived classes must provide set_value()/get_value() methods, 45 * which will involve (somehow) an actual location to store the value. 46 * 47 * In essence, this is an interface, not a class. 48 * 49 * Without overriding upper() and lower(), a derived class will function 50 * as a control whose value can range between 0 and 1.0. 51 * 52 * 53 54 * We express Controllable values in one of three ways: 55 * 1. `user' --- as presented to the user (e.g. dB, Hz, etc.) 56 * 2. `interface' --- as used in some cases for the UI representation 57 * (in order to make controls behave logarithmically). 58 * 3. `internal' --- as passed to a processor, track, plugin, or whatever. 59 * 60 * Note that in some cases user and internal may be the same 61 * (and interface different) e.g. frequency, which is presented 62 * to the user and passed to the processor in linear terms, but 63 * which needs log scaling in the interface. 64 * 65 * In other cases, user and interface may be the same (and internal different) 66 * e.g. gain, which is presented to the user in log terms (dB) 67 * but passed to the processor as a linear quantity. 68 */ 69 class LIBPBD_API Controllable : public PBD::StatefulDestructible, public boost::enable_shared_from_this<Controllable> 70 { 71 public: 72 enum Flag { 73 Toggle = 0x01, 74 GainLike = 0x02, 75 RealTime = 0x04, 76 NotAutomatable = 0x08, 77 InlineControl = 0x10, 78 HiddenControl = 0x20, 79 }; 80 81 Controllable (const std::string& name, Flag f = Flag (0)); 82 83 /** Within an application, various Controllables might be considered to 84 * be "grouped" in a way that implies that setting 1 of them also 85 * modifies others in the group. 86 */ 87 enum GroupControlDisposition { 88 InverseGroup, /**< set all controls in the same "group" as this one */ 89 NoGroup, /**< set only this control */ 90 UseGroup, /**< use group settings to decide which group controls are altered */ 91 ForGroup /**< this setting is being done *for* the group (i.e. UseGroup was set in the callchain somewhere). */ 92 }; 93 94 /** Set `internal' value 95 * 96 * All derived classes must implement this. 97 * 98 * Basic derived classes will ignore \p group_override 99 * but more sophisticated children, notably those that 100 * proxy the value setting logic via an object that is aware of group 101 * relationships between this control and others, will find it useful. 102 * 103 * @param value raw numeric value to set 104 * @param group_override if and how to propagate value to grouped controls 105 */ 106 virtual void set_value (double value, GroupControlDisposition group_override) = 0; 107 108 /** Get `internal' value 109 * @return raw value as used for the plugin/processor control port 110 */ 111 virtual double get_value (void) const = 0; 112 113 /** This is used when saving state. By default it just calls 114 * get_value(), but a class with more complex semantics might override 115 * this to save some value that differs from what get_value() would 116 * return. 117 */ get_save_value()118 virtual double get_save_value () const { return get_value(); } 119 120 /** Conversions between `internal', 'interface', and 'user' values */ 121 virtual double internal_to_interface (double i, bool rotary = false) const { 122 /* by default, the interface range is just a linear 123 * interpolation between lower and upper values */ 124 return (i-lower())/(upper() - lower()); 125 } 126 127 virtual double interface_to_internal (double i, bool rotary = false) const { 128 return lower() + i*(upper() - lower()); 129 } 130 131 /** Get and Set `interface' value (typically, fraction of knob travel) */ 132 virtual float get_interface(bool rotary=false) const { return (internal_to_interface(get_value(), rotary)); } 133 134 virtual void set_interface (float fraction, bool rotary=false, GroupControlDisposition gcd = NoGroup); 135 get_user_string()136 virtual std::string get_user_string() const { return std::string(); } 137 138 PBD::Signal0<void> LearningFinished; 139 140 static PBD::Signal1<bool, boost::weak_ptr<PBD::Controllable> > StartLearning; 141 static PBD::Signal1<void, boost::weak_ptr<PBD::Controllable> > StopLearning; 142 143 static PBD::Signal1<void, boost::weak_ptr<PBD::Controllable> > GUIFocusChanged; 144 static PBD::Signal1<void, boost::weak_ptr<PBD::Controllable> > ControlTouched; 145 146 PBD::Signal2<void,bool,PBD::Controllable::GroupControlDisposition> Changed; 147 148 int set_state (const XMLNode&, int version); 149 virtual XMLNode& get_state (); 150 name()151 std::string name() const { return _name; } 152 touching()153 bool touching () const { return _touching; } 154 PBD::Signal0<void> TouchChanged; 155 is_toggle()156 bool is_toggle() const { return _flags & Toggle; } is_gain_like()157 bool is_gain_like() const { return _flags & GainLike; } 158 lower()159 virtual double lower() const { return 0.0; } upper()160 virtual double upper() const { return 1.0; } normal()161 virtual double normal() const { return 0.0; } //the default value 162 flags()163 Flag flags() const { return _flags; } 164 void set_flags (Flag f); 165 166 void set_flag (Flag f); ///< _flags |= f; 167 void clear_flag (Flag f); ///< _flags &= ~f; 168 169 static boost::shared_ptr<Controllable> by_id (const PBD::ID&); 170 static void dump_registry (); 171 172 static const std::string xml_node_name; 173 174 protected: set_touching(bool yn)175 void set_touching (bool yn) { 176 if (_touching == yn) { return; } 177 _touching = yn; 178 TouchChanged (); /* EMIT SIGNAL */ 179 } 180 181 private: 182 std::string _name; 183 std::string _units; 184 Flag _flags; 185 bool _touching; 186 187 typedef std::set<PBD::Controllable*> Controllables; 188 189 static ScopedConnectionList registry_connections; 190 static Glib::Threads::RWLock registry_lock; 191 static Controllables registry; 192 193 static void add (Controllable&); 194 static void remove (Controllable*); 195 }; 196 197 } 198 199 #endif /* __pbd_controllable_h__ */ 200