SpectMorph
smproperty.hh
1 // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl-2.1.html
2 
3 #ifndef SPECTMORPH_PROPERTY_HH
4 #define SPECTMORPH_PROPERTY_HH
5 
6 #include "smmath.hh"
7 #include "smutils.hh"
8 #include "smoutfile.hh"
9 #include "sminfile.hh"
10 #include "smsignal.hh"
11 
12 #include <functional>
13 #include <memory>
14 #include <string>
15 
16 namespace SpectMorph
17 {
18 
19 class EnumInfo;
20 class ModulationList;
21 class ModulationData;
22 class MorphOperator;
23 
24 class Property : public SignalReceiver
25 {
26 protected:
27  std::unique_ptr<ModulationList> m_modulation_list;
28  MorphOperator *m_op;
29  std::string m_identifier;
30  double m_modulation_range_ui = 1;
31 public:
32  Property (MorphOperator *op, const std::string& identifier);
33  virtual ~Property();
34 
35  MorphOperator *op() { return m_op; }
36  std::string identifier() { return m_identifier; }
37 
38  enum class Type { BOOL, INT, ENUM, FLOAT };
39  enum class Scale { NONE, LINEAR, LOG };
40 
41  virtual Type type() = 0;
42 
43  virtual int min() = 0;
44  virtual int max() = 0;
45  virtual int get() = 0;
46  virtual void set (int v) = 0;
47 
48  virtual std::string label() = 0;
49  virtual std::string value_label() = 0;
50 
51  virtual std::string get_edit_str() { return "<none>"; }
52  virtual void set_edit_str (const std::string& s) {}
53 
54  virtual void save (OutFile& out_file) = 0;
55  virtual bool load (InFile& in_file) = 0;
56 
57  Signal<> signal_value_changed;
58  Signal<> signal_modulation_changed;
59 
60  /* specific types */
61  bool get_bool() { return get() != 0; }
62  void set_bool (bool b) { set (b ? 1 : 0); }
63 
64  virtual float get_float() const { return 0; }
65  virtual void set_float (float f) {}
66 
67  virtual const EnumInfo *enum_info() const { return nullptr; }
68 
69  ModulationList *modulation_list() { return m_modulation_list.get(); }
70 
71  void set_modulation_data (ModulationData *mod_data);
72 
73  void set_modulation_range_ui (double range_ui) { m_modulation_range_ui = range_ui; }
74  double modulation_range_ui() const { return m_modulation_range_ui; }
75 
76  struct Range
77  {
78  double min_value;
79  double max_value;
80 
81  Range (double min_value, double max_value) :
82  min_value (min_value),
83  max_value (max_value)
84  {
85  }
86  double
87  clamp (double value) const
88  {
89  return sm_clamp (value, min_value, max_value);
90  }
91  };
92  virtual Range float_range() { return Range (min(), max()); }
93  virtual Scale float_scale() { return Scale::NONE; }
94 };
95 
96 class IntProperty : public Property
97 {
98  int *m_value;
99  int m_min_value;
100  int m_max_value;
101  std::string m_label;
102  std::string m_format;
103 public:
104  Type type() override { return Type::INT; }
105  int min() override { return m_min_value; }
106  int max() override { return m_max_value; }
107  int get() override { return *m_value; }
108 
109  IntProperty (MorphOperator *op, int *value, const std::string& identifier, const std::string& label, const std::string& format,
110  int def, int mn, int mx) :
111  Property (op, identifier),
112  m_value (value),
113  m_min_value (mn),
114  m_max_value (mx),
115  m_label (label),
116  m_format (format)
117  {
118  *value = def;
119  }
120  std::string
121  label() override
122  {
123  return m_label;
124  }
125  std::string
126  value_label() override
127  {
128  return string_locale_printf (m_format.c_str(), *m_value);
129  }
130  std::string
131  get_edit_str() override
132  {
133  return string_locale_printf ("%d", get());
134  }
135  void
136  set_edit_str (const std::string& s) override
137  {
138  set (atoi (s.c_str()));
139  }
140  void
141  set (int v) override
142  {
143  *m_value = std::clamp (v, min(), max());
144  signal_value_changed();
145  }
146  void
147  save (OutFile& out_file) override
148  {
149  out_file.write_int (m_identifier, *m_value);
150  }
151  bool
152  load (InFile& in_file) override
153  {
154  if (in_file.event() == InFile::INT)
155  {
156  if (in_file.event_name() == m_identifier)
157  {
158  *m_value = in_file.event_int();
159  return true;
160  }
161  }
162  return false;
163  }
164 };
165 
166 class IntVecProperty : public Property
167 {
168  int *m_value;
169  std::vector<int> m_valid_values;
170  std::string m_label;
171  std::string m_format;
172 public:
173  Type type() { return Type::INT; }
174  int min() { return 0; }
175  int max() { return m_valid_values.size() - 1; }
176  int
177  get()
178  {
179  for (size_t i = 0; i < m_valid_values.size(); i++)
180  if (*m_value == m_valid_values[i])
181  return i;
182 
183  // should never happen
184  return 0;
185  }
186  void
187  set (int v)
188  {
189  *m_value = m_valid_values[std::clamp (v, min(), max())];
190  signal_value_changed();
191  }
192  std::string label() { return m_label; }
193 
194  std::string
195  value_label()
196  {
197  return string_locale_printf (m_format.c_str(), *m_value);
198  }
199  std::string
200  get_edit_str()
201  {
202  return string_locale_printf ("%d", *m_value);
203  }
204  void
205  set_edit_str (const std::string& s)
206  {
207  int i = atoi (s.c_str());
208  size_t best_idx = 0;
209  for (size_t idx = 0; idx < m_valid_values.size(); idx++)
210  {
211  if (std::abs (m_valid_values[idx] - i) < std::abs (m_valid_values[best_idx] - i))
212  best_idx = idx;
213  }
214  set (best_idx);
215  }
216  IntVecProperty (MorphOperator *op, int *value, const std::string& identifier, const std::string& label, const std::string& format,
217  int def, const std::vector<int>& valid_values) :
218  Property (op, identifier),
219  m_value (value),
220  m_valid_values (valid_values),
221  m_label (label),
222  m_format (format)
223  {
224  *value = def;
225  }
226  void
227  save (OutFile& out_file)
228  {
229  out_file.write_int (m_identifier, *m_value);
230  }
231  bool
232  load (InFile& in_file)
233  {
234  if (in_file.event() == InFile::INT)
235  {
236  if (in_file.event_name() == m_identifier)
237  {
238  *m_value = in_file.event_int();
239  return true;
240  }
241  }
242  return false;
243  }
244 };
245 
246 class BoolProperty : public Property
247 {
248  bool *m_value;
249  std::string m_label;
250 public:
251  Type type() { return Type::BOOL; }
252  int min() { return 0; }
253  int max() { return 1; }
254  int get() { return *m_value; }
255 
256  BoolProperty (MorphOperator *op, bool *value, const std::string& identifier, const std::string& label, bool def) :
257  Property (op, identifier),
258  m_value (value),
259  m_label (label)
260  {
261  *value = def;
262  }
263  std::string label() { return m_label; }
264 
265  std::string
266  value_label()
267  {
268  return "";
269  }
270 
271  void
272  set (int v)
273  {
274  *m_value = v ? true : false;
275  signal_value_changed();
276  }
277  void
278  save (OutFile& out_file)
279  {
280  out_file.write_bool (m_identifier, *m_value);
281  }
282  bool
283  load (InFile& in_file)
284  {
285  if (in_file.event() == InFile::BOOL)
286  {
287  if (in_file.event_name() == m_identifier)
288  {
289  *m_value = in_file.event_bool();
290  return true;
291  }
292  }
293  return false;
294  }
295 };
296 
297 class EnumInfo
298 {
299 public:
300  struct Item
301  {
302  int value;
303  std::string text;
304  };
305  EnumInfo (const std::vector<Item>& items) :
306  m_items (items)
307  {
308  }
309 
310  const std::vector<Item>
311  items() const
312  {
313  return m_items;
314  }
315 private:
316  std::vector<Item> m_items;
317 };
318 
319 class EnumProperty : public Property
320 {
321  std::string m_label;
322  EnumInfo m_enum_info;
323  std::function<int()> m_read_func;
324  std::function<void(int)> m_write_func;
325  int m_min_value;
326  int m_max_value;
327 public:
329  const std::string& identifier,
330  const std::string& label,
331  int def,
332  const EnumInfo& ei,
333  std::function<int()> read_func,
334  std::function<void(int)> write_func) :
335  Property (op, identifier),
336  m_label (label),
337  m_enum_info (ei),
338  m_read_func (read_func),
339  m_write_func (write_func)
340  {
341  m_write_func (def);
342 
343  g_return_if_fail (ei.items().size());
344  m_min_value = ei.items()[0].value;
345  m_max_value = ei.items()[0].value;
346  for (auto item : ei.items())
347  {
348  m_min_value = std::min (item.value, m_min_value);
349  m_max_value = std::max (item.value, m_max_value);
350  }
351  }
352  Type type() { return Type::ENUM; }
353  int min() { return m_min_value; }
354  int max() { return m_max_value; }
355  int get() { return m_read_func(); }
356  void set (int v)
357  {
358  m_write_func (v);
359  signal_value_changed();
360  }
361  std::string label() { return m_label; }
362  std::string value_label() { return "-"; }
363  virtual const EnumInfo *enum_info() const { return &m_enum_info; }
364  void
365  save (OutFile& out_file)
366  {
367  out_file.write_int (m_identifier, m_read_func());
368  }
369  bool
370  load (InFile& in_file)
371  {
372  if (in_file.event() == InFile::INT)
373  {
374  if (in_file.event_name() == m_identifier)
375  {
376  m_write_func (in_file.event_int());
377  return true;
378  }
379  }
380  return false;
381  }
382 };
383 
384 class FloatProperty : public Property
385 {
386 protected:
387  float *m_value;
388  const Range m_range;
389  const Scale m_scale;
390  std::string m_label;
391  std::string m_format;
392  std::function<std::string (float)> m_custom_formatter;
393 public:
395  float *value,
396  const Range& range,
397  Scale scale,
398  const std::string& identifier,
399  const std::string& label,
400  const std::string& format) :
401  Property (op, identifier),
402  m_value (value),
403  m_range (range),
404  m_scale (scale),
405  m_label (label),
406  m_format (format)
407  {
408  }
409  Type type() override { return Type::FLOAT; }
410  int min() override { return 0; }
411  int max() override { return 1000; }
412  int get() override { return lrint (value2ui (*m_value) * 1000); }
413 
414  void
415  set (int v) override
416  {
417  *m_value = m_range.clamp (ui2value (v / 1000.));
418  signal_value_changed();
419  }
420 
421  float
422  get_float() const override
423  {
424  return *m_value;
425  }
426  void
427  set_float (float f) override
428  {
429  *m_value = m_range.clamp (f);
430  signal_value_changed();
431  }
432  std::string
433  get_edit_str() override
434  {
435  return string_locale_printf ("%.3f", get_float());
436  }
437  void
438  set_edit_str (const std::string& s) override
439  {
440  set_float (sm_atof_any (s.c_str()));
441  }
442  Range
443  float_range() override
444  {
445  return m_range;
446  }
447  Scale
448  float_scale() override
449  {
450  return m_scale;
451  }
452 
453  virtual double value2ui (double value) = 0;
454  virtual double ui2value (double ui) = 0;
455 
456  std::string
457  label() override
458  {
459  return m_label;
460  }
461  std::string
462  value_label() override
463  {
464  if (m_custom_formatter)
465  return m_custom_formatter (*m_value);
466  else
467  return string_locale_printf (m_format.c_str(), *m_value);
468  }
469 
470  void
471  set_custom_formatter (const std::function<std::string (float)>& formatter)
472  {
473  m_custom_formatter = formatter;
474  }
475  void
476  save (OutFile& out_file) override
477  {
478  out_file.write_float (m_identifier, *m_value);
479  }
480  bool
481  load (InFile& in_file) override
482  {
483  if (in_file.event() == InFile::FLOAT)
484  {
485  if (in_file.event_name() == m_identifier)
486  {
487  *m_value = in_file.event_float();
488  return true;
489  }
490  }
491  return false;
492  }
493 };
494 
496 {
497 public:
499  float *value,
500  const std::string& identifier,
501  const std::string& label,
502  const std::string& format,
503  float def_value,
504  float min_value,
505  float max_value) :
506  FloatProperty (op, value, { min_value, max_value }, Scale::LOG, identifier, label, format)
507  {
508  *value = def_value;
509  }
510 
511  double
512  value2ui (double v)
513  {
514  return (log (v) - log (m_range.min_value)) / (log (m_range.max_value) - log (m_range.min_value));
515  }
516  double
517  ui2value (double ui)
518  {
519  return exp (ui * (log (m_range.max_value) - log (m_range.min_value)) + log (m_range.min_value));
520  }
521 };
522 
524 {
525 public:
527  float *value,
528  const std::string& identifier,
529  const std::string& label,
530  const std::string& format,
531  float def_value,
532  double min_value,
533  double max_value) :
534  FloatProperty (op, value, { min_value, max_value }, Scale::LINEAR, identifier, label, format)
535  {
536  *value = def_value;
537  }
538  double
539  value2ui (double v)
540  {
541  return (v - m_range.min_value) / (m_range.max_value - m_range.min_value);
542  }
543  double
544  ui2value (double ui)
545  {
546  return ui * (m_range.max_value - m_range.min_value) + m_range.min_value;
547  }
548 };
549 
551 {
552  double m_slope;
553 public:
555  float *value,
556  const std::string& identifier,
557  const std::string& label,
558  const std::string& format,
559  float def_value,
560  float min_value,
561  float max_value,
562  double slope) :
563  FloatProperty (op, value, { min_value, max_value }, /* FIXME: FILTER */ Scale::NONE, identifier, label, format),
564  m_slope (slope)
565  {
566  *value = def_value;
567  }
568  double
569  value2ui (double v)
570  {
571  return sm_xparam_inv ((v - m_range.min_value) / (m_range.max_value - m_range.min_value), m_slope);
572  }
573  double
574  ui2value (double ui)
575  {
576  return sm_xparam (ui, m_slope) * (m_range.max_value - m_range.min_value) + m_range.min_value;
577  }
578 };
579 
580 }
581 
582 #endif
Definition: smproperty.hh:247
Definition: smproperty.hh:298
Definition: smproperty.hh:320
Definition: smproperty.hh:385
Class to read SpectMorph binary data.
Definition: sminfile.hh:27
Event event()
Definition: sminfile.cc:69
float event_float()
Definition: sminfile.cc:380
int event_int()
Definition: sminfile.cc:391
std::string event_name()
Definition: sminfile.cc:369
bool event_bool()
Definition: sminfile.cc:402
Definition: smproperty.hh:97
Definition: smproperty.hh:167
Definition: smproperty.hh:524
Definition: smproperty.hh:496
Definition: smmodulationlist.hh:17
Definition: smmodulationlist.hh:41
Definition: smmorphoperator.hh:27
Definition: smoutfile.hh:19
Definition: smproperty.hh:25
Definition: smsignal.hh:35
Definition: smsignal.hh:150
Definition: smproperty.hh:551
Definition: smproperty.hh:301
Definition: smproperty.hh:77