lv2plugin.hpp
1 /****************************************************************************
2 
3  lv2plugin.hpp - support file for writing LV2 plugins in C++
4 
5  Copyright (C) 2006-2007 Lars Luthman <lars.luthman@gmail.com>
6  Modified by Dave Robillard, 2008
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., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA
21 
22 ****************************************************************************/
23 
24 #ifndef LV2PLUGIN_HPP
25 #define LV2PLUGIN_HPP
26 
27 #include <cstdarg>
28 
29 #include <cstring>
30 #include <string>
31 #include <vector>
32 
33 #include <lv2.h>
34 #include <lv2_uri_map.h>
35 #include <lv2_saverestore.h>
36 #include <lv2_event.h>
37 #include <lv2_contexts.h>
38 #include <lv2types.hpp>
39 
40 
73 namespace LV2 {
74 
75 
79  class DescList : public std::vector<LV2_Descriptor> {
80  public:
81  ~DescList();
82  };
83 
84 
88  DescList& get_lv2_descriptors();
89 
90 
131  template <class Derived,
132  class Ext1 = End, class Ext2 = End, class Ext3 = End,
133  class Ext4 = End, class Ext5 = End, class Ext6 = End,
134  class Ext7 = End, class Ext8 = End, class Ext9 = End>
135  class Plugin : public MixinTree<Derived,
136  Ext1, Ext2, Ext3, Ext4, Ext5,
137  Ext6, Ext7, Ext8, Ext9> {
138  public:
139 
146  Plugin(uint32_t ports)
147  : m_ports(ports, 0),
148  m_ok(true) {
149  m_features = s_features;
150  m_bundle_path = s_bundle_path;
151  s_features = 0;
152  s_bundle_path = 0;
153  if (m_features) {
154  FeatureHandlerMap hmap;
155  Derived::map_feature_handlers(hmap);
156  for (const Feature* const* iter = m_features; *iter != 0; ++iter) {
157  FeatureHandlerMap::iterator miter;
158  miter = hmap.find((*iter)->URI);
159  if (miter != hmap.end())
160  miter->second(static_cast<Derived*>(this), (*iter)->data);
161  }
162  }
163  }
164 
174  void connect_port(uint32_t port, void* data_location) {
175  m_ports[port] = data_location;
176  }
177 
181  void activate() { }
182 
193  void run(uint32_t sample_count) { }
194 
199  void deactivate() { }
200 
213  static unsigned register_class(const std::string& uri) {
214  LV2_Descriptor desc;
215  std::memset(&desc, 0, sizeof(LV2_Descriptor));
216  char* c_uri = new char[uri.size() + 1];
217  std::memcpy(c_uri, uri.c_str(), uri.size() + 1);
218  desc.URI = c_uri;
219  desc.instantiate = &Derived::_create_plugin_instance;
220  desc.connect_port = &Derived::_connect_port;
221  desc.activate = &Derived::_activate;
222  desc.run = &Derived::_run;
223  desc.deactivate = &Derived::_deactivate;
224  desc.cleanup = &Derived::_delete_plugin_instance;
225  desc.extension_data = &Derived::extension_data;
226  get_lv2_descriptors().push_back(desc);
227  return get_lv2_descriptors().size() - 1;
228  }
229 
238  bool check_ok() {
239  return m_ok && MixinTree<Derived,
240  Ext1, Ext2, Ext3, Ext4, Ext5,
241  Ext6, Ext7, Ext8, Ext9>::check_ok();
242  }
243 
244  protected:
245 
257  template <typename T> T*& p(uint32_t port) {
258  return reinterpret_cast<T*&>(m_ports[port]);
259  }
260 
264  float*& p(uint32_t port) {
265  return reinterpret_cast<float*&>(m_ports[port]);
266  }
267 
271  const char* bundle_path() const {
272  return m_bundle_path;
273  }
274 
283  void set_ok(bool ok) {
284  m_ok = ok;
285  }
286 
290  std::vector<void*> m_ports;
291 
292  private:
293 
297  static void _connect_port(LV2_Handle instance, uint32_t port,
298  void* data_location) {
299  reinterpret_cast<Derived*>(instance)->connect_port(port, data_location);
300  }
301 
305  static void _activate(LV2_Handle instance) {
306  reinterpret_cast<Derived*>(instance)->activate();
307  }
308 
312  static void _run(LV2_Handle instance, uint32_t sample_count) {
313  reinterpret_cast<Derived*>(instance)->run(sample_count);
314  }
315 
319  static void _deactivate(LV2_Handle instance) {
320  reinterpret_cast<Derived*>(instance)->deactivate();
321  }
322 
327  static LV2_Handle _create_plugin_instance(const LV2_Descriptor* descriptor,
328  double sample_rate,
329  const char* bundle_path,
330  const Feature* const*
331  features) {
332 
333  // copy some data to static variables so the subclasses don't have to
334  // bother with it
335  s_features = features;
336  s_bundle_path = bundle_path;
337 
338  Derived* t = new Derived(sample_rate);
339  if (t->check_ok())
340  return reinterpret_cast<LV2_Handle>(t);
341  delete t;
342  return 0;
343  }
344 
349  static void _delete_plugin_instance(LV2_Handle instance) {
350  delete reinterpret_cast<Derived*>(instance);
351  }
352 
353 
354  private:
355 
360  LV2::Feature const* const* m_features;
361 
366  char const* m_bundle_path;
367 
372  static LV2::Feature const* const* s_features;
373 
378  static char const* s_bundle_path;
379 
385  bool m_ok;
386 
387  };
388 
389 
390  // The static variables need to be initialised.
391  template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
392  class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
393  LV2::Feature const* const*
394  Plugin<Derived, Ext1, Ext2, Ext3, Ext4,
395  Ext5, Ext6, Ext7, Ext8, Ext9>::s_features = 0;
396 
397  template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
398  class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
399  char const*
400  Plugin<Derived, Ext1, Ext2, Ext3, Ext4,
401  Ext5, Ext6, Ext7, Ext8, Ext9>::s_bundle_path = 0;
402 
403 
429  template <bool Required = true>
430  struct FixedBufSize {
431 
436  template <class Derived> struct I : Extension<Required> {
437 
439  I() : m_buffer_size(0) { }
440 
442  static void map_feature_handlers(FeatureHandlerMap& hmap) {
443  hmap["http://tapas.affenbande.org/lv2/ext/fixed-buffersize"] =
445  }
446 
448  static void handle_feature(void* instance, void* data) {
449  Derived* d = reinterpret_cast<Derived*>(instance);
450  I<Derived>* fe = static_cast<I<Derived>*>(d);
451  fe->m_buffer_size = *reinterpret_cast<uint32_t*>(data);
452  fe->m_ok = true;
453  }
454 
455  protected:
456 
460  uint32_t get_buffer_size() const { return m_buffer_size; }
461 
462  uint32_t m_buffer_size;
463 
464  };
465 
466  };
467 
476  template <bool Required = true>
477  struct FixedP2BufSize {
478 
483  template <class Derived> struct I : Extension<Required> {
484 
486  I() : m_buffer_size(0) { }
487 
489  static void map_feature_handlers(FeatureHandlerMap& hmap) {
490  hmap["http://tapas.affenbande.org/lv2/ext/power-of-two-buffersize"] =
492  }
493 
495  static void handle_feature(void* instance, void* data) {
496  Derived* d = reinterpret_cast<Derived*>(instance);
497  I<Derived>* fe = static_cast<I<Derived>*>(d);
498  fe->m_buffer_size = *reinterpret_cast<uint32_t*>(data);
499  fe->m_ok = true;
500  }
501 
502  protected:
503 
507  uint32_t get_buffer_size() const { return m_buffer_size; }
508 
509  uint32_t m_buffer_size;
510 
511  };
512 
513  };
514 
515 
522  template <bool Required = true>
523  struct SaveRestore {
524 
529  template <class Derived> struct I : Extension<Required> {
530 
532  I() { }
533 
535  static void map_feature_handlers(FeatureHandlerMap& hmap) {
536  hmap[LV2_SAVERESTORE_URI] = &I<Derived>::handle_feature;
537  }
538 
540  static void handle_feature(void* instance, void* data) {
541  Derived* d = reinterpret_cast<Derived*>(instance);
542  I<Derived>* fe = static_cast<I<Derived>*>(d);
543  fe->m_ok = true;
544  }
545 
547  static const void* extension_data(const char* uri) {
548  if (!std::strcmp(uri, LV2_SAVERESTORE_URI)) {
549  static LV2SR_Descriptor srdesc = { &I<Derived>::_save,
551  return &srdesc;
552  }
553  return 0;
554  }
555 
568  char* save(const char* directory, LV2SR_File*** files) { return 0; }
569 
576  char* restore(const LV2SR_File** files) { return 0; }
577 
578  protected:
579 
582  static char* _save(LV2_Handle h,
583  const char* directory, LV2SR_File*** files) {
584  return reinterpret_cast<Derived*>(h)->save(directory, files);
585  }
586 
589  static char* _restore(LV2_Handle h, const LV2SR_File** files) {
590  return reinterpret_cast<Derived*>(h)->restore(files);
591  }
592 
593  };
594  };
595 
596 
603  template <bool Required = true>
604  struct EventRef {
605 
610  template <class Derived> struct I : Extension<Required> {
611 
613  I() : m_callback_data(0), m_ref_func(0), m_unref_func(0) { }
614 
616  static void map_feature_handlers(FeatureHandlerMap& hmap) {
617  hmap[LV2_EVENT_URI] = &I<Derived>::handle_feature;
618  }
619 
621  static void handle_feature(void* instance, void* data) {
622  Derived* d = reinterpret_cast<Derived*>(instance);
623  I<Derived>* fe = static_cast<I<Derived>*>(d);
624  LV2_Event_Feature* ef = reinterpret_cast<LV2_Event_Feature*>(data);
625  fe->m_callback_data = ef->callback_data;
626  fe->m_ref_func = ef->lv2_event_ref;
627  fe->m_unref_func = ef->lv2_event_unref;
628  fe->m_ok = true;
629  }
630 
631  protected:
632 
642  uint32_t event_ref(LV2_Event* event) {
643  return m_ref_func(m_callback_data, event);
644  }
645 
650  uint32_t event_unref(LV2_Event* event) {
651  return m_unref_func(m_callback_data, event);
652  }
653 
654  LV2_Event_Callback_Data m_callback_data;
655  uint32_t (*m_ref_func)(LV2_Event_Callback_Data, LV2_Event*);
656  uint32_t (*m_unref_func)(LV2_Event_Callback_Data, LV2_Event*);
657 
658  };
659 
660  };
661 
662 
670  template <bool Required = true>
671  struct MsgContext {
672 
677  template <class Derived> struct I : Extension<Required> {
678 
680  I() { }
681 
683  static void map_feature_handlers(FeatureHandlerMap& hmap) {
684  hmap[LV2_CONTEXT_MESSAGE] = &I<Derived>::handle_feature;
685  }
686 
688  static void handle_feature(void* instance, void* data) {
689  Derived* d = reinterpret_cast<Derived*>(instance);
690  I<Derived>* fe = static_cast<I<Derived>*>(d);
691  fe->m_ok = true;
692  }
693 
695  static const void* extension_data(const char* uri) {
696  if (!std::strcmp(uri, LV2_CONTEXT_MESSAGE)) {
697  static LV2_Blocking_Context desc = { &I<Derived>::_blocking_run,
699  return &desc;
700  }
701  return 0;
702  }
703 
708  bool blocking_run(uint8_t* outputs_written) { return false; }
709 
710  protected:
711 
714  static bool _blocking_run(LV2_Handle h, uint8_t* outputs_written) {
715  return reinterpret_cast<Derived*>(h)->blocking_run(outputs_written);
716  }
717 
720  static void _connect_port(LV2_Handle h, uint32_t port, void* buffer) {
721  reinterpret_cast<Derived*>(h)->connect_port(port, buffer);
722  }
723 
724  };
725  };
726 
727 
728 }
729 
730 
731 #endif