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