2 * Implementation of various helpers for the plugin interface.
4 * Copyright (C) 2001-2010 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
23 #include <calf/giface.h>
24 #include <calf/utils.h>
27 using namespace calf_utils
;
28 using namespace calf_plugins
;
30 static const char automation_key_prefix
[] = "automation_v1_";
32 void automation_range::send_configure(const plugin_metadata_iface
*metadata
, uint32_t from_controller
, send_configure_iface
*sci
)
34 std::stringstream ss1
, ss2
;
35 ss1
<< automation_key_prefix
<< from_controller
<< "_to_" << metadata
->get_param_props(param_no
)->short_name
;
36 ss2
<< min_value
<< " " << max_value
;
37 sci
->send_configure(ss1
.str().c_str(), ss2
.str().c_str());
40 automation_range
*automation_range::new_from_configure(const plugin_metadata_iface
*metadata
, const char *key
, const char *value
, uint32_t &from_controller
)
42 if (0 != strncmp(key
, automation_key_prefix
, sizeof(automation_key_prefix
) - 1))
44 key
+= sizeof(automation_key_prefix
) - 1;
45 const char *totoken
= strstr(key
, "_to_");
48 string
from_ctl(key
, totoken
- key
);
49 for (size_t i
= 0; i
< from_ctl
.length(); i
++)
51 if (!isdigit(from_ctl
[i
]))
54 from_controller
= (uint32_t)atoi(from_ctl
.c_str());
57 size_t pcount
= metadata
->get_param_count();
58 for (size_t i
= 0; i
< pcount
; ++i
) {
59 const parameter_properties
*props
= metadata
->get_param_props(i
);
60 if (!strcmp(key
, props
->short_name
))
62 std::stringstream
ss(value
);
65 return new automation_range(minv
, maxv
, i
);
72 float parameter_properties::from_01(double value01
) const
74 double value
= dsp::clip(value01
, 0., 1.);
75 switch(flags
& PF_SCALEMASK
)
77 case PF_SCALE_DEFAULT
:
81 value
= min
+ (max
- min
) * value01
;
84 value
= min
+ (max
- min
) * value01
* value01
;
87 value
= min
* pow(double(max
/ min
), value01
);
90 if (value01
< 0.00001)
93 float rmin
= std::max(1.0f
/ 1024.0f
, min
);
94 value
= rmin
* pow(double(max
/ rmin
), value01
);
97 case PF_SCALE_LOG_INF
:
99 if (value01
> (step
- 1.0) / step
)
100 value
= FAKE_INFINITY
;
102 value
= min
* pow(double(max
/ min
), value01
* step
/ (step
- 1.0));
105 switch(flags
& PF_TYPEMASK
)
112 value
= (int)(value
+ 0.5);
114 value
= (int)(value
- 0.5);
120 double parameter_properties::to_01(float value
) const
122 switch(flags
& PF_SCALEMASK
)
124 case PF_SCALE_DEFAULT
:
125 case PF_SCALE_LINEAR
:
128 return double(value
- min
) / (max
- min
);
130 return sqrt(double(value
- min
) / (max
- min
));
133 return log((double)value
) / log((double)max
/ min
);
134 case PF_SCALE_LOG_INF
:
135 if (IS_FAKE_INFINITY(value
))
139 return (step
- 1.0) * log((double)value
) / (step
* log((double)max
/ min
));
141 if (value
< 1.0 / 1024.0) // new bottom limit - 60 dB
143 double rmin
= std::max(1.0f
/ 1024.0f
, min
);
145 return log((double)value
) / log(max
/ rmin
);
149 float parameter_properties::get_increment() const
151 float increment
= 0.01;
153 increment
= 1.0 / (step
- 1);
155 if (step
> 0 && step
< 1)
158 if ((flags
& PF_TYPEMASK
) != PF_FLOAT
)
159 increment
= 1.0 / (max
- min
);
163 int parameter_properties::get_char_count() const
165 if ((flags
& PF_SCALEMASK
) == PF_SCALE_PERC
)
167 if ((flags
& PF_SCALEMASK
) == PF_SCALE_GAIN
) {
170 sprintf(buf
, "%0.0f dB", 6.0 * log(min
) / log(2));
172 sprintf(buf
, "%0.0f dB", 6.0 * log(max
) / log(2));
173 len
= std::max(len
, strlen(buf
)) + 2;
176 return std::max(to_string(min
).length(), std::max(to_string(max
).length(), to_string(min
+ (max
-min
) * 0.987654).length()));
179 std::string
parameter_properties::to_string(float value
) const
182 if ((flags
& PF_SCALEMASK
) == PF_SCALE_PERC
) {
183 sprintf(buf
, "%0.f%%", 100.0 * value
);
186 if ((flags
& PF_SCALEMASK
) == PF_SCALE_GAIN
) {
187 if (value
< 1.0 / 1024.0) // new bottom limit - 60 dB
188 return "-inf dB"; // XXXKF change to utf-8 infinity
189 sprintf(buf
, "%0.1f dB", dsp::amp2dB(value
));
192 switch(flags
& PF_TYPEMASK
)
202 if ((flags
& PF_SCALEMASK
) == PF_SCALE_LOG_INF
&& IS_FAKE_INFINITY(value
))
203 sprintf(buf
, "+inf"); // XXXKF change to utf-8 infinity
205 sprintf(buf
, "%g", value
);
207 switch(flags
& PF_UNITMASK
) {
208 case PF_UNIT_DB
: return string(buf
) + " dB";
209 case PF_UNIT_HZ
: return string(buf
) + " Hz";
210 case PF_UNIT_SEC
: return string(buf
) + " s";
211 case PF_UNIT_MSEC
: return string(buf
) + " ms";
212 case PF_UNIT_CENTS
: return string(buf
) + " ct";
213 case PF_UNIT_SEMITONES
: return string(buf
) + "#";
214 case PF_UNIT_BPM
: return string(buf
) + " bpm";
215 case PF_UNIT_RPM
: return string(buf
) + " rpm";
216 case PF_UNIT_DEG
: return string(buf
) + " deg";
219 static const char *notes
= "C C#D D#E F F#G G#A A#B ";
220 int note
= (int)value
;
221 if (note
< 0 || note
> 127)
223 return string(notes
+ 2 * (note
% 12), 2) + i2s(note
/ 12 - 2);
230 float parameter_properties::string_to_value(const char* string
) const
232 float value
= atof(string
);
233 if ((flags
& PF_SCALEMASK
) == PF_SCALE_PERC
) {
234 return value
/ 100.0;
236 if ((flags
& PF_SCALEMASK
) == PF_SCALE_GAIN
) {
237 return dsp::dB2amp(value
);
242 ////////////////////////////////////////////////////////////////////////
244 void calf_plugins::plugin_ctl_iface::clear_preset() {
245 int param_count
= get_metadata_iface()->get_param_count();
246 for (int i
= 0; i
< param_count
; i
++)
248 const parameter_properties
&pp
= *get_metadata_iface()->get_param_props(i
);
249 set_param_value(i
, pp
.def_value
);
251 const char *const *vars
= get_metadata_iface()->get_configure_vars();
254 for (int i
= 0; vars
[i
]; i
++)
255 configure(vars
[i
], NULL
);
259 const char *calf_plugins::load_gui_xml(const std::string
&plugin_id
)
262 return strdup(calf_utils::load_file((std::string(PKGLIBDIR
) + "/gui-" + plugin_id
+ ".xml").c_str()).c_str());
264 catch(file_exception e
)
270 bool calf_plugins::get_freq_gridline(int subindex
, float &pos
, bool &vertical
, std::string
&legend
, cairo_iface
*context
, bool use_frequencies
, float res
, float ofs
)
274 static const double dash
[] = {2.0};
281 if (subindex
== 9) legend
= "100 Hz";
282 if (subindex
== 18) legend
= "1 kHz";
283 if (subindex
== 27) legend
= "10 kHz";
285 float freq
= subindex_to_freq(subindex
);
286 pos
= log(freq
/ 20.0) / log(1000);
288 if (!legend
.empty()) {
289 context
->set_source_rgba(0, 0, 0, 0.1);
290 context
->set_dash(dash
, 0);
292 context
->set_source_rgba(0, 0, 0, 0.1);
293 context
->set_dash(dash
, 1);
304 float gain
= 64.0 / (1 << subindex
);
305 pos
= dB_grid(gain
, res
, ofs
);
310 if (!(subindex
& 1)) {
311 std::stringstream ss
;
312 ss
<< (36 - 6 * subindex
) << " dB";
315 if (!legend
.empty() and subindex
!= 6) {
316 context
->set_source_rgba(0, 0, 0, 0.1);
317 context
->set_dash(dash
, 0);
318 } else if (subindex
!= 6) {
319 context
->set_source_rgba(0, 0, 0, 0.1);
320 context
->set_dash(dash
, 1);
322 context
->set_dash(dash
, 0);
328 void calf_plugins::set_channel_color(cairo_iface
*context
, int channel
, float alpha
)
331 context
->set_source_rgba(0.25, 0.10, 0.0, alpha
);
333 context
->set_source_rgba(0.05, 0.25, 0.0, alpha
);
335 void calf_plugins::set_channel_dash(cairo_iface
*context
, int channel
)
337 double dash
[] = {8,2};
362 context
->set_dash(dash
, length
);
364 ////////////////////////////////////////////////////////////////////////
366 bool frequency_response_line_graph::get_graph(int index
, int subindex
, int phase
, float *data
, int points
, cairo_iface
*context
, int *mode
) const
368 if (phase
or subindex
)
370 return ::get_graph(*this, subindex
, data
, points
);
372 bool frequency_response_line_graph::get_gridline(int index
, int subindex
, int phase
, float &pos
, bool &vertical
, std::string
&legend
, cairo_iface
*context
) const
376 return get_freq_gridline(subindex
, pos
, vertical
, legend
, context
, true);
378 bool frequency_response_line_graph::get_layers(int index
, int generation
, unsigned int &layers
) const
380 redraw_graph
= redraw_graph
|| !generation
;
381 layers
= (generation
? LG_NONE
: LG_CACHE_GRID
) | (redraw_graph
? LG_CACHE_GRAPH
: LG_NONE
);
382 bool r
= redraw_graph
;
383 redraw_graph
= false;
386 std::string
frequency_response_line_graph::get_crosshair_label(int x
, int y
, int sx
, int sy
, cairo_iface
*context
) const
388 std::stringstream ss
;
389 float freq
= exp((float(x
) / float(sx
)) * log(1000)) * 20.0;
390 ss
<< int(freq
) << " Hz";
396 ////////////////////////////////////////////////////////////////////////
398 calf_plugins::plugin_registry
&calf_plugins::plugin_registry::instance()
400 static calf_plugins::plugin_registry registry
;
404 const plugin_metadata_iface
*calf_plugins::plugin_registry::get_by_uri(const char *plugin_uri
)
406 static const char prefix
[] = "http://calf.sourceforge.net/plugins/";
407 if (strncmp(plugin_uri
, prefix
, sizeof(prefix
) - 1))
409 const char *label
= plugin_uri
+ sizeof(prefix
) - 1;
410 for (unsigned int i
= 0; i
< plugins
.size(); i
++)
412 if (!strcmp(plugins
[i
]->get_plugin_info().label
, label
))
418 const plugin_metadata_iface
*calf_plugins::plugin_registry::get_by_id(const char *id
, bool case_sensitive
)
420 typedef int (*comparator
)(const char *, const char *);
421 comparator comp
= case_sensitive
? strcmp
: strcasecmp
;
422 for (unsigned int i
= 0; i
< plugins
.size(); i
++)
424 if (!comp(plugins
[i
]->get_id(), id
))
430 ////////////////////////////////////////////////////////////////////////
432 bool calf_plugins::parse_table_key(const char *key
, const char *prefix
, bool &is_rows
, int &row
, int &column
)
437 if (0 != strncmp(key
, prefix
, strlen(prefix
)))
440 key
+= strlen(prefix
);
442 if (!strcmp(key
, "rows"))
448 const char *comma
= strchr(key
, ',');
451 row
= atoi(string(key
, comma
- key
).c_str());
452 column
= atoi(comma
+ 1);
456 printf("Unknown key %s under prefix %s", key
, prefix
);
461 ////////////////////////////////////////////////////////////////////////
463 const char *mod_mapping_names
[] = { "0..1", "-1..1", "-1..0", "x^2", "2x^2-1", "ASqr", "ASqrBip", "Para", NULL
};
465 mod_matrix_metadata::mod_matrix_metadata(unsigned int _rows
, const char **_src_names
, const char **_dest_names
)
466 : mod_src_names(_src_names
)
467 , mod_dest_names(_dest_names
)
470 table_column_info tci
[6] = {
471 { "Source", TCT_ENUM
, 0, 0, 0, mod_src_names
},
472 { "Mapping", TCT_ENUM
, 0, 0, 0, mod_mapping_names
},
473 { "Modulator", TCT_ENUM
, 0, 0, 0, mod_src_names
},
474 { "Amount", TCT_FLOAT
, 0, 1, 1, NULL
},
475 { "Destination", TCT_ENUM
, 0, 0, 0, mod_dest_names
},
478 assert(sizeof(table_columns
) == sizeof(tci
));
479 memcpy(table_columns
, tci
, sizeof(table_columns
));
482 const table_column_info
*mod_matrix_metadata::get_table_columns() const
484 return table_columns
;
487 uint32_t mod_matrix_metadata::get_table_rows() const
492 ////////////////////////////////////////////////////////////////////////
496 table_via_configure::table_via_configure()
501 table_via_configure::~table_via_configure()