1 /*************************************************************************/
2 /* ladspa++ - A C++ wrapper for ladspa */
3 /* Copyright (C) 2014-2018 */
4 /* Johannes Lorenz */
5 /* https://github.com/JohannesLorenz/ */
6 /* */
7 /* This program is free software; you can redistribute it and/or modify */
8 /* it under the terms of the GNU General Public License as published by */
9 /* the Free Software Foundation; either version 3 of the License, or (at */
10 /* your option) any later version. */
11 /* This program is distributed in the hope that it will be useful, but */
12 /* WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
14 /* General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU General Public License */
17 /* along with this program; if not, write to the Free Software */
18 /* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA */
19 /*************************************************************************/
20
test(T expected)21 #include <tuple>
22 #include <array>
23 #include <cassert>
24 #include <cstdint>
25
26 #include "ladspa.h"
27
28 namespace ladspa
29 {
30
31 #ifndef DOXYGEN_SHOULD_SKIP_THIS
32
33 namespace helpers
34 {
35
36 /*
37 * sequences
38 */
39
40 //! default criterium argument, which accepts all numbers
41 template<int>
42 struct criterium_true {
43 static constexpr bool value = true;
44 };
45
46 //! the resulting sequence type to test for
47 template<int ...Seq>
48 struct full_seq
49 {
50 };
51
52 namespace seq_helpers
53 {
54
55 template<int Start, int I, template<int> class Criterium, int ...Seq>
56 struct _seq_recurse;
57
58 //! @a cond is true => spawn @a I into seq and recurse
59 template<int Start, int I, template<int> class Criterium, bool cond, int ...Seq>
60 struct _seq_check
61 {
62 using type = typename _seq_recurse<Start, I, Criterium, I, Seq...>::type;
63 };
64
65 //! @a cond is false => skip @a I in sequence and recurse
66 template<int Start, int I, template<int> class Criterium, int ...Seq>
67 struct _seq_check<Start, I, Criterium, false, Seq...>
68 {
69 using type = typename _seq_recurse<Start, I, Criterium, Seq...>::type;
70 };
71
72 //! counting down, we have not reached the @a Start -> evaluate @a Criterium
73 template<int Start, int I, template<int> class Criterium, int ...Seq>
74 struct _seq
75 {
76 using type = typename _seq_check<Start, I, Criterium, Criterium<I>::value, Seq...>::type;
77 };
78
79 //! counting down, we have reached the @a Start
80 template<int Start, template<int> class Criterium, int ...Seq>
81 struct _seq<Start, Start, Criterium, Seq...>
82 {
83 using type = full_seq<Seq...>;
84 };
85
86 //! sequence recursion, just decrements @a I
87 template<int Start, int I, template<int> class Criterium, int ...Seq>
88 struct _seq_recurse
89 {
90 using type = typename _seq<Start, I-1, Criterium, Seq...>::type;
91 };
92
93 } // namespace seq_helpers
94
95 //! creates maths like range, i.e. [Start, N]
96 template<int N, int Start = 1, template<int> class Criterium = criterium_true>
97 using math_seq = typename seq_helpers::_seq<Start-1, N, Criterium>::type;
98
99 //! creates C like range, i.e. [Start-1, N-1]. Criterium is *not* counted for i-1
100 template<int N, int Start = 0, template<int> class Criterium = criterium_true>
101 using seq = math_seq<N-1, Start, Criterium>;
102
103 template<class ...Args> static void do_nothing(Args...) {}
104
105 /*
106 * avoiding instantiations
107 */
108 template<typename ...> class falsify : std::false_type { };
109 template<typename T, T Arg> class falsify_id : std::false_type { };
110 template<typename ...Args>
111 class dont_instantiate_me {
112 static_assert(falsify<Args...>::value, "This should not be instantiated.");
113 };
114 template<typename T, T Arg>
115 class dont_instantiate_me_id {
116 static_assert(falsify_id<T, Arg>::value, "This should not be instantiated.");
117 };
118
119 /*
120 * accessing helpers
121 */
122 //! a quick fix since array's data() member is not constexpr
123 template<class T, std::size_t N>
124 constexpr const T* get_data(const std::array<T, N>& a)
125 {
126 return &a.front();
127 }
128
129 template<class EnumClass>
130 constexpr std::size_t enum_size() { return (std::size_t)EnumClass::size; }
131
132 //! checks whether class @a T has a ctor with two arguments
133 //! @note: if we need multiple of those, inherit from a base class
134 // Source: [1]
135 template <typename T>
136 class has_ctor_1_args
137 {
138 struct any
139 {
140 template<
141 typename U, typename Sfinae =
142 typename std::enable_if< false ==
143 std::is_same<U,T>::value, U >::type
144 >
145 operator U() const;
146 };
147
148 template <typename U>
149 static int32_t sfinae( decltype( U( any( ) ) ) * );
150 template <typename U>
151 static int8_t sfinae( ... );
152
153 public:
154 static constexpr bool value =
155 sizeof( sfinae<T>( nullptr ) ) == sizeof( int32_t );
156 };
157
158 template <class T, template<class > class HaveClass>
159 using en_if_has = typename std::enable_if<HaveClass<T>::value>::type;
160
161 template <class T, template<class > class HaveClass>
162 using en_if_doesnt_have = typename std::enable_if<!HaveClass<T>::value>::type;
163
164 /*
165 * misc
166 */
167 template<class T> struct identity {};
168
169 //! if @a Type is the nth integer in @a Others, returns n
170 template <std::size_t Type, std::size_t... Others>
171 struct id_in_list;
172
173 template <std::size_t Type>
174 struct id_in_list<Type>
175 {
176 static constexpr std::size_t value = -1;
177 };
178
179 template <std::size_t Type, std::size_t ... Others>
180 struct id_in_list<Type, Type, Others...>
181 {
182 static constexpr std::size_t value = 0;
183 };
184
185 template <std::size_t Type, std::size_t First, std::size_t ... Others>
186 struct id_in_list<Type, First, Others...>
187 {
188 static constexpr std::size_t value
189 = id_in_list<Type, Others...>::value + 1;
190 };
191
192 } // namespace helpers
193
194 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
195
196 //! A struct describing ladspa++'s version
197 struct version_t
198 {
199 char major;
200 char minor;
201 char patch;
202 };
203
204 //! This object can be used to receive the current ladspa++ version
205 constexpr static version_t version = { 1, 0, 0 };
206
207 typedef unsigned long port_size_t;
208 typedef unsigned long sample_size_t;
209 typedef unsigned long sample_rate_t;
210 typedef unsigned long plugin_index_t;
211 typedef LADSPA_Data data;
212
213 /**
214 * @brief A simple, type safe implementation of a bitmask.
215 *
216 * Its purpose is to be dependent on a class T, which means that bitmasks from
217 * different contexts can not be put into one operator.
218 */
219 template<class T>
220 class bitmask
221 {
222 int bits;
223 public:
224 // member functions
225 constexpr int get_bits() const { return bits; }
226 constexpr bool is(const bitmask<T> property) const {
227 return bits & property.bits;
228 }
229 constexpr bitmask(int _bits = 0) : bits(_bits) {}
230
231 // related functions
232 friend constexpr bitmask<T> operator|
233 (const bitmask<T>& l, const bitmask<T>& r)
234 {
235 return bitmask<T>(l.bits|r.bits);
236 }
237 };
238
239 /**
240 * @brief Struct containing bits for ladspa properties.
241 *
242 * The bits specify optional properties of the plugin.
243 */
244 struct properties
245 {
246 typedef bitmask<properties> m;
247 static constexpr m realtime = LADSPA_PROPERTY_REALTIME;
248 static constexpr m inplace_broken = LADSPA_PROPERTY_INPLACE_BROKEN;
249 static constexpr m hard_rt_capable = LADSPA_PROPERTY_HARD_RT_CAPABLE;
250 };
251
252 /**
253 * @brief Struct containing bits for ladspa's port types.
254 *
255 * The bits describe the basic communication type of a port.
256 */
257 struct port_types
258 {
259 typedef bitmask<port_types> m;
260 // ladspa forbids input + output
261 static constexpr m input = LADSPA_PORT_INPUT;
262 static constexpr m output = LADSPA_PORT_OUTPUT;
263 // ladspa forbids audio + control
264 static constexpr m control = LADSPA_PORT_CONTROL;
265 static constexpr m audio = LADSPA_PORT_AUDIO;
266 };
267
268 /**
269 * @brief Struct containing bits for ladspa's port hints.
270 *
271 * The bits give hints about the port's data range.
272 */
273 struct port_hints
274 {
275 typedef bitmask<port_hints> m;
276 static constexpr m bounded_below = LADSPA_HINT_BOUNDED_BELOW;
277 static constexpr m bounded_above = LADSPA_HINT_BOUNDED_ABOVE;
278 static constexpr m toggled = LADSPA_HINT_TOGGLED;
279 static constexpr m sample_rate = LADSPA_HINT_SAMPLE_RATE;
280 static constexpr m logarithmic = LADSPA_HINT_LOGARITHMIC;
281 static constexpr m integer = LADSPA_HINT_INTEGER;
282
283 static constexpr m default_mask = LADSPA_HINT_DEFAULT_MASK;
284 static constexpr m default_none = LADSPA_HINT_DEFAULT_NONE;
285 static constexpr m default_minimum = LADSPA_HINT_DEFAULT_MINIMUM;
286 static constexpr m default_low = LADSPA_HINT_DEFAULT_MIDDLE;
287 static constexpr m default_high = LADSPA_HINT_DEFAULT_HIGH;
288 static constexpr m default_maximum = LADSPA_HINT_DEFAULT_MAXIMUM;
289 static constexpr m default_0 = LADSPA_HINT_DEFAULT_0;
290 static constexpr m default_1 = LADSPA_HINT_DEFAULT_1;
291 static constexpr m default_100 = LADSPA_HINT_DEFAULT_100;
292 static constexpr m default_440 = LADSPA_HINT_DEFAULT_440;
293 };
294
295 /**
296 * @brief Class to access a whole buffer of @a T, like std::vector<T>.
297 *
298 * Can be hard copied, this will be cheap.
299 * The class can contain a size information, or not.
300 */
301 template<class T>
302 class buffer_template
303 {
304 T* _data;
305 //! this is overhead for multiple equal-sized buffers
306 //! however, this overhead is not much
307 std::size_t _size;
308 public:
309 buffer_template() {}
310 buffer_template(T* _in_data, std::size_t _in_size)
311 : _data(_in_data), _size(_in_size) {}
312
313 void assign(T* _in_data) { _data = _in_data; }
314 void set_size(std::size_t _in_size) { _size = _in_size; }
315
316 // void set_size(std::size_t _in_size) const { return _size; }
317 std::size_t size() const { return _size; }
318
319 T& operator[](std::size_t n) { return _data[n]; }
320 const T& operator[](std::size_t n) const { return _data[n]; }
321
322 T* begin() { return _data; }
323 const T* begin() const { return _data; }
324 T* end() { return _data + size(); }
325 const T* end() const { return _data + size(); }
326 T* data() { return begin(); }
327 const T* data() const { return begin(); }
328 };
329
330 //! A class that behaves like a reference to @a T.
331 template<class T>
332 class pointer_template
333 {
334 T* _data;
335 public:
336 pointer_template() {}
337 pointer_template(T* _in_data)
338 : _data(_in_data) {}
339 pointer_template(T* _in_data, int )
340 : pointer_template(_in_data) {}
341
342 void assign(T* _in_data) { _data = _in_data; }
343 void set_size(std::size_t _in_size) const {}
344
345 operator const T&() const { return *_data; }
346 operator T&() { return *_data; }
347 };
348
349 //! Class for mutable buffers (like out ports)
350 typedef buffer_template<data> buffer;
351 //! Class for const buffers (like in ports)
352 typedef buffer_template<const data> const_buffer;
353 //! Class for mutable single values (like in ports)
354 typedef pointer_template<data> pointer;
355 //! Class for const single values (like out ports)
356 typedef pointer_template<const data> const_pointer;
357
358 //! A class which describes a port.
359 struct port_info_t
360 {
361 //! A class which describes the numeric range for a port's values
362 struct range_hint_t
363 {
364 bitmask<port_hints> descriptor;
365 data lower_bound;
366 data upper_bound;
367 };
368
369 enum class type
370 {
371 name,
372 descriptor,
373 range_hint
374 };
375
376 const char* name; //!< Name of the port. Should be short.
377 const char* desription; //!< A short description about what it does
378 bitmask<port_types> descriptor; //!< Information about the port type
379 range_hint_t hint; //!< Information about numeric range
380
381 constexpr bool is_final() const { return (name == nullptr); }
382
383 #ifndef DOXYGEN_SHOULD_SKIP_THIS
384 //! This class is used in combination with the get() functions
385 template<type I> struct type_id {};
386
387 // get function overloads
388 constexpr const char* get(type_id<type::name>) const { return name; }
389 constexpr LADSPA_PortDescriptor get(type_id<type::descriptor>) const {
390 return descriptor.get_bits();
391 }
392 constexpr LADSPA_PortRangeHint get(type_id<type::range_hint>) const {
393 return { hint.descriptor.get_bits(),
394 hint.lower_bound,
395 hint.upper_bound };
396 }
397 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
398 /*
399 * Predefined, common types
400 */
401
402 // constexpr const static port_info_t audio_input,
403 // audio_output;
404
405
406 /* constexpr const static port_info_t audio_input = {
407 "Input", "Effect's audio input (mono).",
408 port_types::input | port_types::audio, {0} };
409 constexpr const static port_info_t audio_output = {
410 "Output", "Effect's audio output (mono).",
411 port_types::output | port_types::audio, {0} };*/
412 };
413
414 //! A list of very common ports
415 namespace port_info_common
416 {
417 constexpr static port_info_t audio_input = {
418 "Input", "Effect's audio input (mono).",
419 port_types::input | port_types::audio, {0,0,0} };
420 constexpr static port_info_t audio_input_l = {
421 "Input (L)", "Effect's audio input (left).",
422 port_types::input | port_types::audio, {0,0,0} };
423 constexpr static port_info_t audio_input_r = {
424 "Input (R)", "Effect's audio input (right).",
425 port_types::input | port_types::audio, {0,0,0} };
426
427 constexpr static port_info_t audio_output = {
428 "Output", "Effect's audio output (mono).",
429 port_types::output | port_types::audio, {0,0,0} };
430 constexpr static port_info_t audio_output_l = {
431 "Output (L)", "Effect's audio output (mono).",
432 port_types::output | port_types::audio, {0,0,0} };
433 constexpr static port_info_t audio_output_r = {
434 "Output (R)", "Effect's audio output (right).",
435 port_types::output | port_types::audio, {0,0,0} };
436
437 // more ports can be added on request...
438
439 //! port marking the end, recognized via the nullptr
440 constexpr static port_info_t final_port = { nullptr,
441 "Final port (internal use only).", 0, {0,0,0} };
442 }
443
444 #ifndef DOXYGEN_SHOULD_SKIP_THIS
445 /*
446 * Return value specialisations for port_array_t
447 */
448 template<class contained_type, const bitmask<port_types>* bm, class Enable = void>
449 struct return_value_base_type
450 {
451 typedef buffer_template<contained_type> type;
452 };
453
454 template<class contained_type, const bitmask<port_types>* bm>
455 struct return_value_base_type
456 <contained_type, bm,
457 typename std::enable_if<bm->is(port_types::control)>::type>
458 {
459 typedef pointer_template<contained_type> type;
460 };
461
462 template<class base_type,
463 const bitmask<port_types>* bm,
464 class Enable = void>
465 struct return_value_access_type
466 {
467 typedef const base_type type;
468 };
469
470 template<class base_type,
471 const bitmask<port_types>* bm>
472 struct return_value_access_type
473 <base_type, bm,
474 typename std::enable_if<bm->is(port_types::output)>::type>
475 {
476 typedef base_type type;
477 };
478
479 template<class PortNamesT, const port_info_t* PortDesArray>
480 class port_array_t;
481
482 template<class port_array_t_t, typename port_array_t_t::port_names_t ...PortIndexes>
483 class port_ptrs
484 {
485 helpers::dont_instantiate_me<port_array_t_t> s;
486 };
487 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
488
489 /**
490 * @brief The result of dereferencing a multi_iterator.
491 *
492 * This class holds multiple pointers to the elements of multiple vectors.
493 * The position of these different pointers is always equal.
494 * From outside, there a no pointers, but references.
495 */
496 template<class PortNamesT, const port_info_t* PortDesArray,
497 typename port_array_t<PortNamesT, PortDesArray>::port_names_t ...PortIndexes>
498 class port_ptrs<port_array_t<PortNamesT, PortDesArray>, PortIndexes...>
499 {
500 class type_helpers
501 {
502 template<const bitmask<port_types>* bm>
503 using t1 = typename return_value_access_type<data, bm>::type;
504
505 public:
506 template<std::size_t PortName>
507 class type_at_port
508 {
509 static constexpr auto arr_elem = PortDesArray[PortName];
510 static constexpr auto descr = arr_elem.descriptor;
511 public:
512 typedef t1<&descr> type; // data or const data
513 };
514
515 template<std::size_t ...Is>
516 struct _storage_t
517 {
518 typedef typename std::tuple
519 <typename type_at_port<Is>::type*...> type;
520 };
521 };
522 public:
523 template<int PortName>
524 using type_at = typename type_helpers::template type_at_port<PortName>::type;
525
526 private:
527 typedef typename type_helpers::template _storage_t<(int)PortIndexes...>::type
528 storage_t;
529
530 storage_t pointers; //!< valid if we are not at the end()
531
532 typedef port_array_t<PortNamesT, PortDesArray> port_array_t_t;
533
534 template<std::size_t id>
535 type_at<id>*& get_ptr() {
536 return std::get<helpers::id_in_list<id, (std::size_t)PortIndexes...>::value>(port_ptrs::pointers);
537 }
538
539 template<typename port_array_t_t::port_names_t id>
540 type_at<(std::size_t)id>*& get_ptr() {
541 return get_ptr<(std::size_t)id>();
542 }
543
544 template<std::size_t id>
545 type_at<id>& get() {
546 return *get_ptr<id>();
547 }
548
549 public:
550 port_ptrs(const port_array_t_t& port_array_t)
551 : pointers(port_array_t.template get<PortIndexes>().begin()...) {}
552 port_ptrs() {}
553
554 void operator++()
555 {
556 helpers::do_nothing(++(get_ptr<PortIndexes>())...);
557 }
558
559 template<typename port_array_t_t::port_names_t id>
560 type_at<(std::size_t)id>& get() {
561 return get<(std::size_t)id>();
562 }
563 };
564
565 /**
566 * @brief An iterator over a port array container.
567 *
568 * This class holds multiple pointers to the elements of multiple vectors.
569 * The position of these different pointers is always equal.
570 */
571 template<class port_array_t, typename port_array_t::port_names_t ...PortIndexes>
572 class multi_iterator
573 {
574 private:
575 typedef multi_iterator<port_array_t, PortIndexes...> m_type;
576
577 port_ptrs<port_array_t, PortIndexes...> _port_ptrs;
578 std::size_t position; //!< valid if we are not at the end()
579 const sample_size_t sample_count; //! note: this parameter could be obsolete, or useful...
580
581 public:
582 bool operator!=(const m_type& other)
583 {
584 return position != other.position;
585 }
586
587 m_type& operator++()
588 {
589 ++position;
590 ++_port_ptrs;
591 return *this;
592 }
593
594 port_ptrs<port_array_t, PortIndexes...>& operator*() { return _port_ptrs; }
595
596 //! Iterator pointing to the begin of @a port_array
597 multi_iterator(const port_array_t& port_array, sample_size_t _sample_count) :
598 _port_ptrs(port_array),
599 position(0),
600 sample_count(_sample_count)
601 {}
602
603 //! Iterator pointing to the end of any port array
604 multi_iterator(sample_size_t _sample_count) :
605 position(_sample_count),
606 sample_count(_sample_count)
607 {
608 }
609 };
610
611 /**
612 * @brief A container over a port array. Can be iterated.
613 *
614 * This class is being instantiated to mark
615 * over which ports you want to iterate.
616 */
617 template<class port_array_t_t, typename port_array_t_t::port_names_t ...PortIndexes>
618 class samples_container
619 {
620 const port_array_t_t& port_array_t;
621 const sample_size_t sample_count;
622 typedef multi_iterator<port_array_t_t, PortIndexes...> multi_itr_type;
623 public:
624 samples_container(const port_array_t_t& pa, sample_size_t sc)
625 : port_array_t(pa), sample_count(sc) {}
626 multi_itr_type begin() const {
627 return multi_itr_type(port_array_t, sample_count); }
628 multi_itr_type end() const { return multi_itr_type(sample_count); }
629 };
630
631 /**
632 * @brief A class that contains all ports.
633 *
634 * This includes all buffers and the buffer size.
635 */
636 template<class PortNamesT, const port_info_t* PortDesArray>
637 class port_array_t
638 {
639 private:
640 typedef port_array_t<PortNamesT, PortDesArray> m_type;
641
642 class type_helpers
643 {
644
645 template<const bitmask<port_types>* bm>
646 using t1 = typename return_value_access_type<data, bm>::type;
647 template<const bitmask<port_types>* bm>
648 using return_value_preparation = typename return_value_base_type<t1<bm>, bm>::type;
649 public:
650 template<std::size_t PortName>
651 class type_at_port
652 {
653 static constexpr auto arr_elem = PortDesArray[PortName];
654 static constexpr auto descr = arr_elem.descriptor;
655 public:
656 typedef return_value_preparation<&descr> type;
657 };
658
659 template<class T> struct _storage_t {
660 helpers::dont_instantiate_me<T> x;
661 };
662 template<int ...Is>
663 struct _storage_t<helpers::full_seq<Is...>>
664 {
665 typedef std::tuple<typename type_at_port<Is>::type...> type;
666 };
667 };
668
669 constexpr static std::size_t port_size = helpers::enum_size<PortNamesT>();
670 constexpr static const port_info_t* port_des_array = PortDesArray;
671 public:
672 typedef PortNamesT port_names_t;
673 template<int PortName>
674 using type_at = typename type_helpers::template type_at_port<PortName>::type;
675 private:
676 typedef typename type_helpers::template _storage_t<
677 typename helpers::template seq<port_size>>::type storage_t;
678 private:
679 /*
680 * data
681 */
682 storage_t storage;
683 int _current_sample_count;
684
685 template<int id>
686 static void set_static(port_array_t& p, data* d) {
687 p.set_internal<id>(d);
688 }
689
690 struct caller
691 {
692 void (&callback)(port_array_t&, data*);
693 };
694
695 template<class T>
696 static constexpr typename std::array<caller, port_size> init_callers(T)
697 {
698 static_assert(helpers::falsify<T>::value,
699 "This should not be instantiated.");
700 return {}; // constexpr function must have return value
701 }
702
703 template<int ...Is>
704 static constexpr typename std::array<caller, port_size> init_callers(helpers::full_seq<Is...>)
705 {
706 return {{{port_array_t::set_static<Is>}...}};
707 }
708
709 static constexpr typename std::array<caller, port_size> callers
710 = init_callers(typename helpers::seq<port_size>{});
711
712 static constexpr bool in_range_cond(int id)
713 {
714 return id >= 0 &&
715 (std::size_t)id < helpers::enum_size<port_names_t>();
716 }
717
718 template<int id>
719 void set_internal(data* d) {
720 assert(in_range_cond(id));
721 std::get<id>(storage).assign(d);
722 }
723 public:
724
725 #ifndef DOXYGEN_SHOULD_SKIP_THIS
726 //! Intended for internal use only
727 void set_caller(int id, data* d) {
728 callers[id].callback(*this, d);
729 }
730 //! Intended for internal use only
731 void set_current_sample_count(sample_size_t s) {
732 _current_sample_count = s;
733 }
734 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
735
736 template<std::size_t id>
737 type_at<id> get() const {
738 type_at<id> ret_val = std::get<id>(storage);
739 // buffer size is usually not set - set it
740 ret_val.set_size(_current_sample_count);
741 return ret_val;
742 }
743 template<port_names_t id>
744 type_at<(std::size_t)id> get() const {
745 return get<(std::size_t)id>();
746 }
747
748 //! lets you choose which buffers you want to iterate over
749 template<port_names_t ...port_ids>
750 samples_container<m_type, port_ids...> buffers() {
751 return samples_container<m_type, port_ids...>(
752 *this, _current_sample_count);
753 }
754
755 /* //! lets you iterate over all buffers
756 samples_container<m_type, port_ids...> all_buffers() {
757 return samples_container<m_type, port_ids...>(
758 *this, _current_sample_count);
759 }*/
760
761 //! A way the programmer can get the current sample count
762 //! in the run() function
763 sample_size_t current_sample_count(void) {
764 return _current_sample_count;
765 }
766 };
767
768 template<class PortNamesT, const port_info_t* port_des_array>
769 constexpr typename std::array<typename port_array_t<PortNamesT, port_des_array>::caller,
770 port_array_t<PortNamesT, port_des_array>::port_size>
771 port_array_t<PortNamesT, port_des_array>::callers;
772
773 //! A class which the programmer fills in to describe her/his plugin
774 struct info_t
775 {
776 unsigned long unique_id;
777 const char * label;
778 bitmask<properties> plugin_properties;
779 const char * name;
780 const char * maker;
781 const char * help;
782 const char * keywords[8];
783 const char * copyright;
784 void * implementation_data;
785 };
786
787 //! returns size of the port array
788 static constexpr port_size_t get_port_size(const ladspa::port_info_t* arr) {
789 return arr->is_final() ? 0 : get_port_size(arr + 1) + 1;
790 }
791
792 #ifndef DOXYGEN_SHOULD_SKIP_THIS
793 /**
794 * @brief The direct holder for the plugin class
795 *
796 * A struct between builder and plugin,
797 * in order to hold the port array.
798 * (it should not be held by the user)
799 *
800 * @note Internally, this class is being casted to LADSPA_Handle
801 */
802 template<class Plugin>
803 class plugin_holder_t
804 {
805 typedef port_array_t<typename Plugin::port_names,
806 Plugin::port_info> _port_array_t;
807
808 _port_array_t _ports;
809 Plugin plugin;
810
811 public:
812 template<class _Plugin, helpers::en_if_has<
813 _Plugin, helpers::has_ctor_1_args>* = nullptr>
814 plugin_holder_t(helpers::identity<_Plugin>,
815 sample_rate_t _sample_rate
816 ) : plugin(_sample_rate) {}
817
818 template<class _Plugin, helpers::en_if_doesnt_have<
819 _Plugin, helpers::has_ctor_1_args>* = nullptr>
820 plugin_holder_t(helpers::identity<_Plugin>,
821 sample_rate_t
822 ) {}
823
824 void run(sample_size_t _sample_count) {
825 _ports.set_current_sample_count(_sample_count);
826 plugin.run(_ports);
827 }
828
829 void connect_port(int _port, data* d) {
830 _ports.set_caller(_port, d);
831 }
832 };
833 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
834
835 /**
836 * @brief A class that sets up everything for the C ladpsa side.
837 *
838 * This includes the static descriptions, port buffers and callbacks.
839 * Don't use this class directly, please use the collection class instead.
840 */
841 template<class Plugin>
842 class builder
843 {
844 typedef plugin_holder_t<Plugin> _plugin_holder_t;
845
846 /*
847 * Data
848 */
849 static constexpr const info_t& descriptor = Plugin::info;
850 static constexpr const port_info_t* port_info = Plugin::port_info;
851 static constexpr port_size_t port_size = get_port_size(port_info);
852
853 /*
854 * This shifts the arrays
855 */
856 template<port_info_t::type PT, int N, class T, int... Is>
857 static constexpr auto _get_elem(helpers::full_seq<Is...>, T* lhs)
858 -> std::array<decltype(lhs[0].get(port_info_t::type_id<PT>())), N>
859 {
860 return {{lhs[Is].get(port_info_t::type_id<PT>())...}};
861 }
862
863 template<port_info_t::type PT, int N, class T>
864 static constexpr auto get_elem(T* lhs)
865 -> decltype( _get_elem<PT, N>(helpers::seq<N>{}, lhs) )
866 {
867 return _get_elem<PT, N>(helpers::seq<N>{}, lhs);
868 }
869
870 /*
871 * These functions are the ladspa callbacks
872 */
873
874 template<class _Plugin>
875 static LADSPA_Handle _instantiate(
876 const struct _LADSPA_Descriptor * d, sample_rate_t s) {
877 //return new _Plugin;
878 return new _plugin_holder_t(helpers::identity<Plugin>(), s);
879 }
880
881 static void _cleanup(LADSPA_Handle _instance) {
882 delete static_cast<_plugin_holder_t*>(_instance);
883 }
884
885 static void
886 _connect_port(LADSPA_Handle _instance,
887 port_size_t _port,
888 data * _data_location)
889 {
890 static_cast<_plugin_holder_t*>(_instance)->
891 connect_port(_port, _data_location);
892 //static_cast<_plugin_holder_t*>(_instance)->
893 // _ports.set_caller(_port, _data_location);
894 }
895
896 /* template<int i>
897 struct criterium_is_buffer
898 {
899 constexpr static bool value = port_info[i].descriptor.is(port_types::audio);
900 };*/
901
902 //void _activate(LADSPA_Handle Instance);
903 static void _run(LADSPA_Handle _instance,
904 sample_size_t _sample_count)
905 {
906
907 //Plugin* instance = &(static_cast<_plugin_holder_t>(_instance)->plugin);
908
909 // set_sizes(nullptr, _sample_count, helpers::seq<port_size, 0, criterium_is_buffer>{});
910 // _run_with_seq(_instance, _sample_count, helpers::gen_seq<port_size>{});
911 // instance->run(ports);
912
913 static_cast<_plugin_holder_t*>(_instance)->run(_sample_count);
914 }
915
916 static constexpr std::array<LADSPA_PortDescriptor, port_size>
917 port_descr
918 = get_elem<port_info_t::type::descriptor, port_size>(port_info);
919 static constexpr std::array<const char*, port_size>
920 port_names
921 = get_elem<port_info_t::type::name, port_size>(port_info);
922 static constexpr std::array<LADSPA_PortRangeHint, port_size>
923 port_range_hints
924 = get_elem<port_info_t::type::range_hint, port_size>(port_info);
925 static constexpr LADSPA_Descriptor descriptor_for_ladspa =
926 {
927 descriptor.unique_id,
928 descriptor.label,
929 descriptor.plugin_properties.get_bits(),
930 descriptor.name,
931 descriptor.maker,
932 descriptor.copyright,
933 port_size,
934 helpers::get_data(port_descr),
935 helpers::get_data(port_names),
936 helpers::get_data(port_range_hints),
937 descriptor.implementation_data,
938 _instantiate<Plugin>,
939 _connect_port,
940 nullptr, //_activate,
941 _run,
942 nullptr, // run_adding
943 nullptr, // set_run_adding_gain
944 nullptr, // deactivate
945 _cleanup
946 };
947 public:
948 static const LADSPA_Descriptor& get_ladspa_descriptor()
949 { return descriptor_for_ladspa; }
950 };
951
952 /*
953 * Static member definitions
954 */
955 template<class Plugin>
956 constexpr std::array<LADSPA_PortDescriptor,
957 builder<Plugin>::port_size>
958 builder<Plugin>::port_descr;
959 template<class Plugin>
960 constexpr std::array<const char*, builder<Plugin>::port_size>
961 builder<Plugin>::port_names;
962 template<class Plugin>
963 constexpr std::array<LADSPA_PortRangeHint, builder<Plugin>::port_size>
964 builder<Plugin>::port_range_hints;
965
966 template<class Plugin>
967 constexpr LADSPA_Descriptor builder<Plugin>::descriptor_for_ladspa;
968
969 //! common strings to be used
970 namespace strings
971 {
972 //! strings for the info_t::copyright field
973 namespace copyright
974 {
975 constexpr const char* none = "None";
976 constexpr const char* gpl3 = "GPL v3";
977 }
978 }
979
980 /**
981 * @brief This is for a collection of your plugin types.
982 *
983 * it helps you to select the correct LADSPA descriptor at runtime.
984 */
985 template<class ...Args>
986 class collection
987 {
988 struct caller
989 {
990 const LADSPA_Descriptor& (&callback)();
991 };
992
993 static constexpr std::array<caller, sizeof...(Args)> init_callers()
994 {
995 return {{{builder<Args>::get_ladspa_descriptor}...}};
996 }
997
998 static constexpr std::array<caller, sizeof...(Args)> callers
999 = init_callers();
1000 public:
1001 //! Returns the requested descriptor
1002 //! or nullptr if the index is out of range.
1003 static const LADSPA_Descriptor* get_ladspa_descriptor(
1004 plugin_index_t index)
1005 {
1006 return (index >= sizeof...(Args))
1007 ? nullptr
1008 : &callers[index].callback();
1009 }
1010 };
1011
1012 template<class ...Args>
1013 constexpr std::array<typename collection<Args...>::caller, sizeof...(Args)>
1014 collection<Args...>::callers;
1015
1016 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1017 struct correctness_checker
1018 {
1019 // TODO: different IDs, In Out, broken inplace etc
1020 };
1021 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
1022
1023 }
1024
1025 // sources:
1026 // [1] http://stackoverflow.com/questions/16137468/
1027 // sfinae-detect-constructor-with-one-argument
1028