1 /* Calf DSP Library utility application.
2 * DSSI GUI application.
3 * Copyright (C) 2007 Krzysztof Foltman
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
25 #include <calf/giface.h>
27 #include <calf/main_win.h>
28 #include <calf/lv2_data_access.h>
29 #include <calf/lv2_string_port.h>
30 #include <calf/lv2_ui.h>
31 #include <calf/lv2_uri_map.h>
32 #include <calf/preset_gui.h>
33 #include <calf/utils.h>
34 #include <calf/lv2helpers.h>
38 using namespace calf_plugins
;
39 using namespace calf_utils
;
41 struct LV2_Calf_Descriptor
{
42 plugin_ctl_iface
*(*get_pci
)(LV2_Handle Instance
);
45 struct plugin_proxy
: public plugin_ctl_iface
, public plugin_metadata_proxy
47 LV2UI_Write_Function write_function
;
48 LV2UI_Controller controller
;
54 /// Instance pointer - usually NULL unless the host supports instance-access extension
55 plugin_ctl_iface
*instance
;
57 LV2_Handle instance_handle
;
58 LV2_Extension_Data_Feature
*data_access
;
59 LV2_URI_Map_Feature
*uri_map
;
60 map
<string
, int> params_by_name
;
61 uint32_t string_port_uri
;
63 plugin_proxy(plugin_metadata_iface
*md
)
64 : plugin_metadata_proxy(md
)
68 instance_handle
= NULL
;
71 param_count
= get_param_count();
72 params
= new float[param_count
];
74 for (int i
= 0; i
< param_count
; i
++)
76 parameter_properties
*pp
= get_param_props(i
);
77 params_by_name
[pp
->short_name
] = i
;
78 if ((pp
->flags
& PF_TYPEMASK
) < PF_STRING
)
79 params
[i
] = pp
->def_value
;
83 void setup(LV2UI_Write_Function wfn
, LV2UI_Controller ctl
)
89 virtual float get_param_value(int param_no
) {
90 if (param_no
< 0 || param_no
>= param_count
)
92 return params
[param_no
];
95 virtual void set_param_value(int param_no
, float value
) {
96 if (param_no
< 0 || param_no
>= param_count
)
98 if ((get_param_props(param_no
)->flags
& PF_TYPEMASK
) >= PF_STRING
)
103 params
[param_no
] = value
;
105 scope_assign
<bool> _a_(send
, false);
106 write_function(controller
, param_no
+ get_param_port_offset(), sizeof(float), 0, ¶ms
[param_no
]);
110 virtual bool activate_preset(int bank
, int program
)
115 virtual line_graph_iface
*get_line_graph_iface() {
117 return instance
->get_line_graph_iface();
121 virtual char *configure(const char *key
, const char *value
)
125 map
<string
, int>::iterator i
= params_by_name
.find(key
);
126 if (i
== params_by_name
.end())
128 fprintf(stderr
, "ERROR: configure called for unknown key %s\n", key
);
132 LV2_String_Data data
;
133 data
.data
= (char *)value
;
134 data
.len
= strlen(value
);
135 data
.storage
= -1; // host doesn't need that
140 if (string_port_uri
) {
141 write_function(controller
, idx
+ get_param_port_offset(), sizeof(LV2_String_Data
), string_port_uri
, &data
);
147 virtual float get_level(unsigned int port
) { return 0.f
; }
148 virtual void execute(int command_no
) { assert(0); }
149 void send_configures(send_configure_iface
*sci
) {
150 fprintf(stderr
, "TODO: send_configures (non-control port configuration dump) not implemented in LV2 GUIs\n");
152 void resolve_instance() {
153 fprintf(stderr
, "CALF DEBUG: instance %p data %p\n", instance_handle
, data_access
);
154 if (instance_handle
&& data_access
)
156 LV2_Calf_Descriptor
*calf
= (LV2_Calf_Descriptor
*)(*data_access
->data_access
)("http://foltman.com/ns/calf-plugin-instance");
157 fprintf(stderr
, "CALF DEBUG: calf %p cpi %p\n", calf
, calf
? calf
->get_pci
: NULL
);
158 if (calf
&& calf
->get_pci
)
159 instance
= calf
->get_pci(instance_handle
);
162 uint32_t map_uri(const char *mapURI
, const char *keyURI
)
166 return uri_map
->uri_to_id(uri_map
->callback_data
, mapURI
, keyURI
);
175 static gboolean
plugin_on_idle(void *data
)
177 plugin_gui
*self
= (plugin_gui
*)data
;
182 LV2UI_Handle
gui_instantiate(const struct _LV2UI_Descriptor
* descriptor
,
183 const char* plugin_uri
,
184 const char* bundle_path
,
185 LV2UI_Write_Function write_function
,
186 LV2UI_Controller controller
,
187 LV2UI_Widget
* widget
,
188 const LV2_Feature
* const* features
)
190 vector
<plugin_metadata_iface
*> plugins
;
191 get_all_plugins(plugins
);
192 const char *label
= plugin_uri
+ sizeof("http://calf.sourceforge.net/plugins/") - 1;
193 plugin_proxy
*proxy
= NULL
;
194 for (unsigned int i
= 0; i
< plugins
.size(); i
++)
196 if (!strcmp(plugins
[i
]->get_plugin_info().label
, label
))
198 proxy
= new plugin_proxy(plugins
[i
]);
204 for (int i
= 0; features
[i
]; i
++)
206 if (!strcmp(features
[i
]->URI
, "http://lv2plug.in/ns/ext/instance-access"))
207 proxy
->instance_handle
= features
[i
]->data
;
208 else if (!strcmp(features
[i
]->URI
, "http://lv2plug.in/ns/ext/data-access"))
209 proxy
->data_access
= (LV2_Extension_Data_Feature
*)features
[i
]->data
;
210 else if (!strcmp(features
[i
]->URI
, LV2_URI_MAP_URI
))
212 proxy
->uri_map
= (LV2_URI_Map_Feature
*)features
[i
]->data
;
213 proxy
->string_port_uri
= proxy
->map_uri("http://lv2plug.in/ns/extensions/ui",
214 LV2_STRING_PORT_URI
);
217 proxy
->resolve_instance();
218 scope_assign
<bool> _a_(proxy
->send
, false);
219 proxy
->setup(write_function
, controller
);
221 main_window
*main
= new main_window
;
223 main
->conditions
.insert("directlink");
224 main
->conditions
.insert("lv2gui");
225 plugin_gui_window
*window
= new plugin_gui_window(main
);
226 plugin_gui
*gui
= new plugin_gui(window
);
227 const char *xml
= proxy
->get_gui_xml();
229 *(GtkWidget
**)(widget
) = gui
->create_from_xml(proxy
, xml
);
231 if (*(GtkWidget
**)(widget
))
232 proxy
->source_id
= g_timeout_add_full(G_PRIORITY_LOW
, 1000/30, plugin_on_idle
, gui
, NULL
); // 30 fps should be enough for everybody
234 return (LV2UI_Handle
)gui
;
237 void gui_cleanup(LV2UI_Handle handle
)
239 plugin_gui
*gui
= (plugin_gui
*)handle
;
240 plugin_proxy
*proxy
= dynamic_cast<plugin_proxy
*>(gui
->plugin
);
241 if (proxy
->source_id
)
242 g_source_remove(proxy
->source_id
);
246 void gui_port_event(LV2UI_Handle handle
, uint32_t port
, uint32_t buffer_size
, uint32_t format
, const void *buffer
)
248 plugin_gui
*gui
= (plugin_gui
*)handle
;
249 plugin_proxy
*proxy
= dynamic_cast<plugin_proxy
*>(gui
->plugin
);
251 float v
= *(float *)buffer
;
252 port
-= gui
->plugin
->get_param_port_offset();
253 if (port
>= (uint32_t)gui
->plugin
->get_param_count())
255 if ((gui
->plugin
->get_param_props(port
)->flags
& PF_TYPEMASK
) == PF_STRING
)
257 scope_assign
<bool> _a_(proxy
->send
, false);
258 gui
->plugin
->configure(gui
->plugin
->get_param_props(port
)->short_name
, ((LV2_String_Data
*)buffer
)->data
);
261 if (fabs(gui
->plugin
->get_param_value(port
) - v
) < 0.00001)
264 scope_assign
<bool> _a_(proxy
->send
, false);
265 gui
->set_param_value(port
, v
);
269 const void *gui_extension(const char *uri
)
274 namespace calf_plugins
{
276 // this function is normally implemented in preset_gui.cpp, but we're not using that file
277 void activate_preset(GtkAction
*action
, activate_preset_params
*params
)
281 // so is this function
282 void store_preset(GtkWindow
*toplevel
, plugin_gui
*gui
)
288 ///////////////////////////////////////////////////////////////////////////////////////
290 class small_plugin_gui
: public uri_map_access
293 LV2UI_Write_Function write_function
;
294 LV2UI_Controller controller
;
295 GtkWidget
**widget_ptr
;
297 void write(int port
, const void *data
, uint32_t size
, uint32_t format
)
299 (*write_function
)(controller
, port
, size
, format
, &data
);
302 virtual void use_feature(const char *URI
, void *feature
) {
305 virtual void parse_features(const LV2_Feature
* const*features
) {
307 for(;*features
;features
++)
308 use_feature((*features
)->URI
, (*features
)->data
);
312 virtual GtkWidget
*create_widget()=0;
314 virtual void init(const char* plugin_uri
, const char* bundle_path
,
315 LV2UI_Write_Function write_function
, LV2UI_Controller controller
,
316 LV2UI_Widget
* widget
, const LV2_Feature
* const*features
)
318 this->write_function
= write_function
;
319 this->controller
= controller
;
320 widget_ptr
= (GtkWidget
**)widget
;
321 parse_features(features
);
322 *widget_ptr
= create_widget();
325 virtual ~small_plugin_gui() {}
328 class msg_read_gui
: public message_mixin
<small_plugin_gui
>
331 uint32_t set_float_msg
, float_type
;
333 static void bang(GtkWidget
*widget
, msg_read_gui
*gui
)
344 data
.selector
= gui
->set_float_msg
;
345 data
.serial_no
= 1337;
348 data
.data_type
= gui
->float_type
;
349 data
.data_value
= atof(gtk_entry_get_text(GTK_ENTRY(gui
->editor
)));
351 gui
->write(0, &data
, sizeof(data
), gui
->message_event_type
);
353 virtual void map_uris()
355 message_mixin
<small_plugin_gui
>::map_uris();
356 set_float_msg
= map_uri("http://lv2plug.in/ns/dev/msg", "http://foltman.com/garbage/setFloat");
357 float_type
= map_uri("http://lv2plug.in/ns/dev/types", "http://lv2plug.in/ns/dev/types#float");
359 virtual GtkWidget
*create_widget()
361 editor
= gtk_entry_new();
362 GtkWidget
*button
= gtk_button_new_with_label("Bang!");
363 GtkWidget
*vbox
= gtk_vbox_new(false, 10);
364 gtk_box_pack_start(GTK_BOX(vbox
), editor
, true, true, 5);
365 gtk_box_pack_start(GTK_BOX(vbox
), button
, true, true, 5);
366 GtkWidget
*frame
= gtk_frame_new("GUI");
367 gtk_container_add(GTK_CONTAINER(frame
), vbox
);
368 gtk_widget_queue_resize(frame
);
369 gtk_signal_connect( GTK_OBJECT(button
), "clicked", G_CALLBACK(bang
), this);
374 LV2UI_Handle
sgui_instantiate(const struct _LV2UI_Descriptor
* descriptor
,
375 const char* plugin_uri
,
376 const char* bundle_path
,
377 LV2UI_Write_Function write_function
,
378 LV2UI_Controller controller
,
379 LV2UI_Widget
* widget
,
380 const LV2_Feature
* const* features
)
382 small_plugin_gui
*gui
= NULL
;
383 if (!strcmp(plugin_uri
, "http://calf.sourceforge.net/small_plugins/msgread_e"))
384 gui
= new msg_read_gui
;
387 gui
->init(plugin_uri
, bundle_path
, write_function
, controller
, widget
, features
);
391 void sgui_cleanup(LV2UI_Handle handle
)
393 small_plugin_gui
*gui
= (small_plugin_gui
*)handle
;
397 void sgui_port_event(LV2UI_Handle handle
, uint32_t port
, uint32_t buffer_size
, uint32_t format
, const void *buffer
)
401 const void *sgui_extension(const char *uri
)
406 ///////////////////////////////////////////////////////////////////////////////////////
408 const LV2UI_Descriptor
* lv2ui_descriptor(uint32_t index
)
410 static LV2UI_Descriptor gui
, sgui
;
411 gui
.URI
= "http://calf.sourceforge.net/plugins/gui/gtk2-gui";
412 gui
.instantiate
= gui_instantiate
;
413 gui
.cleanup
= gui_cleanup
;
414 gui
.port_event
= gui_port_event
;
415 gui
.extension_data
= gui_extension
;
416 sgui
.URI
= "http://calf.sourceforge.net/small_plugins/gui/gtk2-gui";
417 sgui
.instantiate
= sgui_instantiate
;
418 sgui
.cleanup
= sgui_cleanup
;
419 sgui
.port_event
= sgui_port_event
;
420 sgui
.extension_data
= sgui_extension
;