My Project 1.0.5
lv2gui.hpp
1/****************************************************************************
2
3 lv2gui.hpp - Wrapper library to make it easier to write LV2 GUIs in C++
4
5 Copyright (C) 2006-2008 Lars Luthman <lars.luthman@gmail.com>
6 Modified by Dave Robillard, 2008 (URI map mixin)
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 3 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
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301 USA
22
23****************************************************************************/
24
25#ifndef LV2GUI_HPP
26#define LV2GUI_HPP
27
28#include <cstdlib>
29#include <cstring>
30#include <map>
31
32#include <gtkmm/box.h>
33#include <gtkmm/main.h>
34#include <gtkmm/widget.h>
35
36#include <lv2_ui.h>
37#include <lv2_ui_presets.h>
38#include <lv2_uri_map.h>
39#include <lv2_event_helpers.h>
40#include <lv2_osc.h>
41#include <lv2types.hpp>
42
43
44namespace LV2 {
45
46
49 typedef std::vector<LV2UI_Descriptor*> GUIDescList;
50
51
55 GUIDescList& get_lv2g2g_descriptors();
56
57
104 template <bool Required = true>
106
111 template <class Derived> struct I : public Extension<Required> {
112
114 static void map_feature_handlers(FeatureHandlerMap& hmap) {
115 hmap["http://ll-plugins.nongnu.org/lv2/dev/ui#noUserResize"] =
117 }
118
120 static void handle_feature(void* instance, void* data) {
121 Derived* d = reinterpret_cast<Derived*>(instance);
122 I<Derived>* e = static_cast<I<Derived>*>(d);
123 e->m_ok = true;
124 }
125
126 };
127
128 };
129
130
140 template <bool Required = true>
141 struct FixedSize {
142
147 template <class Derived> struct I : public Extension<Required> {
148
150 static void map_feature_handlers(FeatureHandlerMap& hmap) {
151 hmap["http://ll-plugins.nongnu.org/lv2/dev/ui#fixedSize"] =
153 }
154
156 static void handle_feature(void* instance, void* data) {
157 Derived* d = reinterpret_cast<Derived*>(instance);
158 I<Derived>* e = static_cast<I<Derived>*>(d);
159 e->m_ok = true;
160 }
161
162 };
163
164 };
165
166
175 template <bool Required = true>
176 struct Presets {
177
182 template <class Derived> struct I : public Extension<Required> {
183
185 I() : m_hdesc(0), m_host_support(false) { }
186
188 static void map_feature_handlers(FeatureHandlerMap& hmap) {
189 hmap[LV2_UI_PRESETS_URI] = &I<Derived>::handle_feature;
190 }
191
193 static void handle_feature(void* instance, void* data) {
194 Derived* d = reinterpret_cast<Derived*>(instance);
195 I<Derived>* e = static_cast<I<Derived>*>(d);
196 e->m_hdesc = static_cast<LV2UI_Presets_Feature*>(data);
197 e->m_ok = (e->m_hdesc != 0);
198 e->m_host_support = (e->m_hdesc != 0);
199 }
200
201
207 void preset_added(uint32_t number,
208 char const* name) {
209
210 }
211
216 void preset_removed(uint32_t number) {
217
218 }
219
224
225 }
226
233 void current_preset_changed(uint32_t number) {
234
235 }
236
240 static void const* extension_data(char const* uri) {
241 static LV2UI_Presets_GDesc desc = { &_preset_added,
242 &_preset_removed,
243 &_presets_cleared,
244 &_current_preset_changed };
245 if (!std::strcmp(uri, LV2_UI_PRESETS_URI))
246 return &desc;
247 return 0;
248 }
249
250 protected:
251
254 void change_preset(uint32_t preset) {
255 if (m_hdesc)
256 m_hdesc->change_preset(static_cast<Derived*>(this)->controller(),
257 preset);
258 }
259
263 void save_preset(uint32_t preset, char const* name) {
264 if (m_hdesc)
265 m_hdesc->save_preset(static_cast<Derived*>(this)->controller(),
266 preset, name);
267 }
268
272 return m_host_support;
273 }
274
275 private:
276
277 static void _preset_added(LV2UI_Handle gui,
278 uint32_t number,
279 char const* name) {
280 static_cast<Derived*>(gui)->preset_added(number, name);
281 }
282
283 static void _preset_removed(LV2UI_Handle gui,
284 uint32_t number) {
285 static_cast<Derived*>(gui)->preset_removed(number);
286 }
287
288 static void _presets_cleared(LV2UI_Handle gui) {
289 static_cast<Derived*>(gui)->presets_cleared();
290 }
291
292 static void _current_preset_changed(LV2UI_Handle gui,
293 uint32_t number) {
294 static_cast<Derived*>(gui)->current_preset_changed(number);
295 }
296
297
298 LV2UI_Presets_Feature* m_hdesc;
299 bool m_host_support;
300
301 };
302
303 };
304
305
312 template <bool Required = true>
313 struct WriteMIDI {
314
315 enum {
316 EVENT_BUFFER_SIZE = 4
317 };
318
323 template <class Derived> struct I : Extension<Required> {
324
326 I() : m_midi_type(0) {
327 m_buffer = lv2_event_buffer_new(sizeof(LV2_Event) + EVENT_BUFFER_SIZE,
328 0);
329 }
330
332 bool check_ok() {
333 Derived* d = static_cast<Derived*>(this);
334 m_midi_type = d->
335 uri_to_id(LV2_EVENT_URI, "http://lv2plug.in/ns/ext/midi#MidiEvent");
336 m_event_buffer_format = d->
337 uri_to_id(LV2_UI_URI, "http://lv2plug.in/ns/extensions/ui#Events");
338 return !Required || (m_midi_type && m_event_buffer_format);
339 }
340
341 protected:
342
353 bool write_midi(uint32_t port, uint32_t size, const uint8_t* data) {
354 if (m_midi_type == 0)
355 return false;
356 LV2_Event_Buffer* buffer;
357 if (size <= 4)
358 buffer = m_buffer;
359 else
360 buffer = lv2_event_buffer_new(sizeof(LV2_Event) + size, 0);
361 lv2_event_buffer_reset(m_buffer, 0, m_buffer->data);
362 LV2_Event_Iterator iter;
363 lv2_event_begin(&iter, m_buffer);
364 lv2_event_write(&iter, 0, 0, m_midi_type, size, data);
365 static_cast<Derived*>(this)->
366 write(port, m_buffer->header_size + m_buffer->capacity,
367 m_event_buffer_format, m_buffer);
368 if (size > 4)
369 std::free(buffer);
370 return true;
371 }
372
373 uint32_t m_midi_type;
374 uint32_t m_event_buffer_format;
375 LV2_Event_Buffer* m_buffer;
376
377 };
378
379 };
380
381
391 template <bool Required = true>
392 struct WriteOSC {
393
398 template <class Derived> struct I : Extension<Required> {
399
400 I() : m_osc_type(0) {
401 m_buffer = lv2_event_buffer_new(sizeof(LV2_Event) + 256, 0);
402 }
403
404 bool check_ok() {
405 Derived* d = static_cast<Derived*>(this);
406 m_osc_type = d->
407 uri_to_id(LV2_EVENT_URI, "http://lv2plug.in/ns/ext/osc#OscEvent");
408 m_event_buffer_format = d->
409 uri_to_id(LV2_UI_URI, "http://lv2plug.in/ns/extensions/ui#Events");
410 return !Required || (m_osc_type && m_event_buffer_format);
411 }
412
413 protected:
414
415 bool write_osc(uint32_t port, const char* path, const char* types, ...) {
416 if (m_osc_type == 0)
417 return false;
418 // XXX handle all sizes here - this is dangerous
419 lv2_event_buffer_reset(m_buffer, 0, m_buffer->data);
420 LV2_Event_Iterator iter;
421 lv2_event_begin(&iter, m_buffer);
422 va_list ap;
423 va_start(ap, types);
424 uint32_t size = lv2_osc_event_vsize(path, types, ap);
425 va_end(ap);
426 if (!size)
427 return false;
428 va_start(ap, types);
429 bool success = lv2_osc_buffer_vappend(&iter, 0, 0, m_osc_type,
430 path, types, size, ap);
431 va_end(ap);
432 if (success) {
433 static_cast<Derived*>(this)->
434 write(port, m_buffer->header_size + m_buffer->capacity,
435 m_event_buffer_format, m_buffer);
436 return true;
437 }
438 return false;
439 }
440
441 uint32_t m_osc_type;
442 uint32_t m_event_buffer_format;
443 LV2_Event_Buffer* m_buffer;
444
445 };
446
447 };
448
449
466 template<class Derived, class Ext1 = End, class Ext2 = End, class Ext3 = End,
467 class Ext4 = End, class Ext5 = End, class Ext6 = End,
468 class Ext7 = End, class Ext8 = End, class Ext9 = End>
469 class GUI : public Gtk::HBox, public MixinTree<Derived,
470 Ext1, Ext2, Ext3, Ext4,
471 Ext5, Ext6, Ext7, Ext8, Ext9> {
472 public:
473
477 inline GUI() {
478 m_ctrl = s_ctrl;
479 m_wfunc = s_wfunc;
480 m_features = s_features;
481 m_bundle_path = s_bundle_path;
482 s_ctrl = 0;
483 s_wfunc = 0;
484 s_features = 0;
485 s_bundle_path = 0;
486 if (m_features) {
487 FeatureHandlerMap hmap;
488 Derived::map_feature_handlers(hmap);
489 for (const Feature* const* iter = m_features; *iter != 0; ++iter) {
490 FeatureHandlerMap::iterator miter;
491 miter = hmap.find((*iter)->URI);
492 if (miter != hmap.end())
493 miter->second(static_cast<Derived*>(this), (*iter)->data);
494 }
495 }
496 }
497
500 inline void port_event(uint32_t port, uint32_t buffer_size,
501 uint32_t format, void const* buffer) { }
502
504 static int register_class(char const* uri) {
505 LV2UI_Descriptor* desc = new LV2UI_Descriptor;
506 std::memset(desc, 0, sizeof(LV2UI_Descriptor));
507 desc->URI = strdup(uri);
508 desc->instantiate = &Derived::create_ui_instance;
509 desc->cleanup = &Derived::delete_ui_instance;
510 desc->port_event = &Derived::_port_event;
511 desc->extension_data = &Derived::extension_data;
512 get_lv2g2g_descriptors().push_back(desc);
513 return get_lv2g2g_descriptors().size() - 1;
514 }
515
516 protected:
517
522 inline void write(uint32_t port, uint32_t buffer_size,
523 uint32_t format, void const* buffer) {
524 (*m_wfunc)(m_ctrl, port, buffer_size, format, buffer);
525 }
526
528 inline void write_control(uint32_t port, float value) {
529 write(port, sizeof(float), 0, &value);
530 }
531
534 inline LV2::Feature const* const* features() {
535 return m_features;
536 }
537
539 inline char const* bundle_path() const {
540 return m_bundle_path;
541 }
542
543 public:
547 inline void* controller() {
548 return m_ctrl;
549 }
550
551
552 private:
553
554 // This is quite ugly but needed to allow these mixins to call
555 // protected functions in the GUI class, which we want.
556 friend class WriteMIDI<true>::I<Derived>;
557 friend class WriteMIDI<false>::I<Derived>;
558 friend class WriteOSC<true>::I<Derived>;
559 friend class WriteOSC<false>::I<Derived>;
560
565 static LV2UI_Handle create_ui_instance(struct _LV2UI_Descriptor const*
566 descriptor,
567 char const* plugin_uri,
568 char const* bundle_path,
569 LV2UI_Write_Function write_func,
570 LV2UI_Controller ctrl,
571 LV2UI_Widget* widget,
572 Feature const* const* features) {
573
574 // copy some data to static variables so the subclasses don't have to
575 // bother with it - this is threadsafe since hosts are not allowed
576 // to instantiate the same plugin concurrently
577 s_ctrl = ctrl;
578 s_wfunc = write_func;
579 s_features = features;
580 s_bundle_path = bundle_path;
581
582 // this is needed to initialise gtkmm stuff in case we're running in
583 // a Gtk+ or PyGtk host or some other language
584 Gtk::Main::init_gtkmm_internals();
585
586 // create the GUI object
587 Derived* t = new Derived(plugin_uri);
588 *widget = static_cast<Gtk::Widget*>(t)->gobj();
589
590 // check that everything is OK
591 if (t->check_ok())
592 return reinterpret_cast<LV2UI_Handle>(t);
593 delete t;
594 return 0;
595 }
596
597
602 static void delete_ui_instance(LV2UI_Handle instance) {
603 delete static_cast<Derived*>(instance);
604 }
605
606
610 static void _port_event(LV2UI_Handle instance, uint32_t port,
611 uint32_t buffer_size, uint32_t format,
612 void const* buffer) {
613 static_cast<Derived*>(instance)->port_event(port, buffer_size,
614 format, buffer);
615 }
616
617
618 void* m_ctrl;
619 LV2UI_Write_Function m_wfunc;
620 LV2::Feature const* const* m_features;
621 char const* m_bundle_path;
622
623 static void* s_ctrl;
624 static LV2UI_Write_Function s_wfunc;
625 static LV2::Feature const* const* s_features;
626 static char const* s_bundle_path;
627
628 };
629
630
631 /* Yes, static variables are messy. */
632 template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
633 class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
634 void* GUI<Derived, Ext1, Ext2, Ext3, Ext4,
635 Ext5, Ext6, Ext7, Ext8, Ext9>::s_ctrl = 0;
636
637 template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
638 class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
639 LV2UI_Write_Function GUI<Derived, Ext1, Ext2, Ext3, Ext4,
640 Ext5, Ext6, Ext7, Ext8, Ext9>::s_wfunc = 0;
641
642 template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
643 class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
644 LV2::Feature const* const* GUI<Derived, Ext1, Ext2, Ext3, Ext4,
645 Ext5, Ext6, Ext7, Ext8, Ext9>::s_features = 0;
646
647 template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
648 class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
649 char const* GUI<Derived, Ext1, Ext2, Ext3, Ext4,
650 Ext5, Ext6, Ext7, Ext8, Ext9>::s_bundle_path = 0;
651
652
653}
654
655
656#endif
Definition lv2gui.hpp:471
static int register_class(char const *uri)
Definition lv2gui.hpp:504
void write_control(uint32_t port, float value)
Definition lv2gui.hpp:528
LV2::Feature const *const * features()
Definition lv2gui.hpp:534
void * controller()
Definition lv2gui.hpp:547
void port_event(uint32_t port, uint32_t buffer_size, uint32_t format, void const *buffer)
Definition lv2gui.hpp:500
void write(uint32_t port, uint32_t buffer_size, uint32_t format, void const *buffer)
Definition lv2gui.hpp:522
char const * bundle_path() const
Definition lv2gui.hpp:539
Definition lv2gui.hpp:147
Definition lv2gui.hpp:141
Definition lv2gui.hpp:111
Definition lv2gui.hpp:105
Definition lv2gui.hpp:182
void preset_removed(uint32_t number)
Definition lv2gui.hpp:216
void change_preset(uint32_t preset)
Definition lv2gui.hpp:254
void save_preset(uint32_t preset, char const *name)
Definition lv2gui.hpp:263
bool host_supports_presets() const
Definition lv2gui.hpp:271
void preset_added(uint32_t number, char const *name)
Definition lv2gui.hpp:207
void presets_cleared()
Definition lv2gui.hpp:223
void current_preset_changed(uint32_t number)
Definition lv2gui.hpp:233
Definition lv2gui.hpp:176
Definition lv2gui.hpp:323
bool write_midi(uint32_t port, uint32_t size, const uint8_t *data)
Definition lv2gui.hpp:353
Definition lv2gui.hpp:313
Definition lv2gui.hpp:398