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