From 4a3d5572058b4f7bb1e44bdf4c87209cf7777ae9 Mon Sep 17 00:00:00 2001 From: werman Date: Wed, 21 Feb 2018 19:46:55 +0200 Subject: [PATCH] Add LADSPA support, add instructions for linux, fix compilation on linux. - Add LADSPA support to load plugin into pulseaudio. - Add instructions for working with pulseaudio. - Fix compilation on linux. - Updated readme. --- CMakeLists.txt | 1 + README.md | 61 +- src/common/CMakeLists.txt | 2 + src/ladspa_plugin/CMakeLists.txt | 42 + src/ladspa_plugin/RnNoiseLadspaPlugin.cpp | 2 + src/ladspa_plugin/RnNoiseLadspaPlugin.h | 65 ++ src/ladspa_plugin/ladspa++.h | 1026 +++++++++++++++++ src/ladspa_plugin/ladspa.h | 603 ++++++++++ src/lv2_plugin/CMakeLists.txt | 16 +- src/lv2_plugin/RnNoiseLv2Lib.h | 2 +- src/lv2_plugin/RnNoiseLv2Plugin.h | 2 +- .../{lv2/lv2plug.in/ns => }/lv2core/Lib.hpp | 2 +- .../lv2plug.in/ns => }/lv2core/Plugin.hpp | 2 +- .../{lv2/lv2plug.in/ns => }/lv2core/lv2.h | 0 .../lv2plug.in/ns => }/lv2core/lv2_util.h | 2 +- src/rnnoise/CMakeLists.txt | 2 + src/vst_plugin/CMakeLists.txt | 6 +- 17 files changed, 1813 insertions(+), 23 deletions(-) create mode 100644 src/ladspa_plugin/CMakeLists.txt create mode 100644 src/ladspa_plugin/RnNoiseLadspaPlugin.cpp create mode 100644 src/ladspa_plugin/RnNoiseLadspaPlugin.h create mode 100644 src/ladspa_plugin/ladspa++.h create mode 100644 src/ladspa_plugin/ladspa.h rename src/lv2_plugin/{lv2/lv2plug.in/ns => }/lv2core/Lib.hpp (98%) rename src/lv2_plugin/{lv2/lv2plug.in/ns => }/lv2core/Plugin.hpp (99%) rename src/lv2_plugin/{lv2/lv2plug.in/ns => }/lv2core/lv2.h (100%) rename src/lv2_plugin/{lv2/lv2plug.in/ns => }/lv2core/lv2_util.h (98%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 54228417..dcf232d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,3 +6,4 @@ add_subdirectory(src/rnnoise) add_subdirectory(src/common) add_subdirectory(src/vst_plugin) add_subdirectory(src/lv2_plugin) +add_subdirectory(src/ladspa_plugin) \ No newline at end of file diff --git a/README.md b/README.md index 853be924..38d1d6fa 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# VST Noise Suppression Plugin +# Real-time Noise Suppression Plugin (VST2, LV2, LADSPA) -A real-time noise suppression VST and LV2 plugin for voice based on [Xiph's RNNoise](https://github.com/xiph/rnnoise). [More info about the base library](https://people.xiph.org/~jm/demo/rnnoise/). +A real-time noise suppression plugin for voice based on [Xiph's RNNoise](https://github.com/xiph/rnnoise). [More info about the base library](https://people.xiph.org/~jm/demo/rnnoise/). ## About @@ -12,32 +12,75 @@ The plugin is made to work with 1 channel, 16 bit, 48000 Hz audio input. Other s ## How-to -### Windows + Equalizer APO +### Windows + Equalizer APO (VST2) + To check or change mic settings go to "Recording devices" -> "Recording" -> "Properties" of the target mic -> "Advanced". To enable the plugin in Equalizer APO select "Plugins" -> "VST Plugin" and specify the plugin dll. ### Linux -Testing required. +#### Pulseaudio + +The idea is: + +- Create a sink from which apps will take audio later and which will be the end think in the chain. +- Load the plugin which outputs to already created sink ('sink_master' parameter) and has input sink ('sink_name' parameter, sink will be created). +- Create loopback from microphone ('source') to input sink of plugin ('sink') with 1 channel. + + +``` +pacmd load-module module-null-sink sink_name=mic_denoised_out + +pacmd load-module module-ladspa-sink sink_name=mic_raw_in sink_master=mic_denoised_out label=noise_suppressor plugin=librnnoise_ladspa_x64.so + +pacmd load-module module-loopback source=your_mic_name sink=mic_raw_in channels=1 +``` + +This should be executed every time pulse audio is launched. This can be done by creating file in ~/.config/pulse/default.pa with: + +``` +.include /etc/pulse/default.pa + +load-module module-null-sink sink_name=mic_denoised_out +load-module module-ladspa-sink sink_name=mic_raw_in sink_master=mic_denoised_out label=noise_suppressor plugin=librnnoise_ladspa_x64.so +load-module module-loopback source=your_mic_name sink=mic_raw_in channels=1 + +set-default-source mic_denoised_out.monitor +``` + +Your mic name can be found by: + +``` +pacmd list-sources +``` + +You may still need to set correct input for application, this can be done in audio mixer panel (if you have one) in 'Recording' tab where you should set 'Monitor of Null Output' as source. + +Useful detailed info about pulseaudio logic [toadjaune/pulseaudio-config](https://github.com/toadjaune/pulseaudio-config). + +The [thread](https://bugs.freedesktop.org/show_bug.cgi?id=101043) which helped me with how to post-process mic output and make it available to applications. ## Status -The plugin is tested with Equalizer APO v1.2 x64 (open source system-wide equalizer for Windows). It is a minimal proof-of-concept work. +The plugin is tested with Equalizer APO v1.2 x64 (open source system-wide equalizer for Windows) and tested with pulse audio on arch linux. I'm not associated with the original work in any way and have only superficial understanding of it. The original author will probably create something better out of their work but for now I don't see any analogs with similar capabilities so I have created a usable one. ## Developing -The plugin is built with gcc in mingw environment for x32 and x64 architectures, the current cmake project is made for such environment and may need changes in order to support other ones. - VST sdk files aren't shipped here due to their license. You need to download VST sdk and copy several files to src/pluginterfaces/vst2.x/ and to src/vst2.x/. You can find sdk [here](https://www.steinberg.net/en/company/developers.html). -LV2 sdk files are +LV2 and LADSPA sdk files are in repository. + +All improvements are welcomed! ## ☑ TODO -- [X] Create LV2 plugin. +- [X] Create LV2 plugin. (Untested) +- [X] Create LADSPA plugin. +- [X] Create correct setup with pulseaudio. +- [ ] Create package for linux distros (I don't here experience here so help is highly appreciated). - [ ] Try to train the net with data for specific cases and see if will do better for them. ## License diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index f29823d3..dba2f626 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -3,6 +3,8 @@ project(RnNoisePluginCommon LANGUAGES CXX) set(CMAKE_CXX_STANDARD 14) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + set(COMMON_SRC include/common/RnNoiseCommonPlugin.h src/RnNoiseCommonPlugin.cpp) diff --git a/src/ladspa_plugin/CMakeLists.txt b/src/ladspa_plugin/CMakeLists.txt new file mode 100644 index 00000000..ba17e1f9 --- /dev/null +++ b/src/ladspa_plugin/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 3.6) +project(rnnoise_ladspa_plugin LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 14) + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +set(PROJECT_ROOT ../../../) + +set(LADSPA_INTERFACE_SRC + ladspa.h + ladspa++.h) + +set(LADSPA_IMPL_SRC + RnNoiseLadspaPlugin.h + RnNoiseLadspaPlugin.cpp) + +set(LADSPA_PLUGIN_SOURCES + ${LADSPA_INTERFACE_SRC} + ${LADSPA_IMPL_SRC}) + +function(build bit) + set(LADSPA_TARGET_X${bit} rnnoise_ladspa_x${bit}) + + add_library(${LADSPA_TARGET_X${bit}} SHARED ${LADSPA_PLUGIN_SOURCES}) + + target_link_libraries(${LADSPA_TARGET_X${bit}} RnNoisePluginCommon "-static-libgcc -static-libstdc++ -m${bit}") + + set(X${bit}_COMPILE_OPTIONS + "-m${bit};" + "$<$:-O3;>") + + target_compile_options(${LADSPA_TARGET_X${bit}} PRIVATE ${X${bit}_COMPILE_OPTIONS}) + + set_target_properties(${LADSPA_TARGET_X${bit}} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_ROOT}/bin/x${bit}/ladspa") +endfunction() + +build(32) +build(64) diff --git a/src/ladspa_plugin/RnNoiseLadspaPlugin.cpp b/src/ladspa_plugin/RnNoiseLadspaPlugin.cpp new file mode 100644 index 00000000..e7b12466 --- /dev/null +++ b/src/ladspa_plugin/RnNoiseLadspaPlugin.cpp @@ -0,0 +1,2 @@ +#include "RnNoiseLadspaPlugin.h" + diff --git a/src/ladspa_plugin/RnNoiseLadspaPlugin.h b/src/ladspa_plugin/RnNoiseLadspaPlugin.h new file mode 100644 index 00000000..8197a17f --- /dev/null +++ b/src/ladspa_plugin/RnNoiseLadspaPlugin.h @@ -0,0 +1,65 @@ +#pragma once + +#include "ladspa++.h" +#include "common/RnNoiseCommonPlugin.h" + +using namespace ladspa; + +struct RnNoise { + enum class port_names { + in_1, + out_1, + size + }; + + static constexpr port_info_t port_info[] = + { + port_info_common::audio_input, + port_info_common::audio_output, + port_info_common::final_port + }; + + static constexpr info_t info = + { + 9354877, // unique id + "noise_suppressor", + properties::realtime, + "Noise Suppressor for Voice", + "werman", + "Removes wide range of noises from voice in real time, based on Xiph's RNNoise library.", + {"voice", "noise suppression", "de-noise"}, + strings::copyright::gpl3, + nullptr // implementation data + }; + + RnNoise() { + m_rnNoisePlugin.init(); + } + + ~RnNoise() { + m_rnNoisePlugin.deinit(); + } + + void run(port_array_t &ports) { + + const_buffer in_buffer = ports.get(); + buffer out_buffer = ports.get(); + + m_rnNoisePlugin.process(in_buffer.data(), out_buffer.data(), in_buffer.size()); + } + + RnNoiseCommonPlugin m_rnNoisePlugin; +}; + +/* + * to be called by ladspa + */ + +void _init() {} + +void _fini() {} + +const LADSPA_Descriptor * +ladspa_descriptor(plugin_index_t index) { + return collection::get_ladspa_descriptor(index); +} \ No newline at end of file diff --git a/src/ladspa_plugin/ladspa++.h b/src/ladspa_plugin/ladspa++.h new file mode 100644 index 00000000..f41ba596 --- /dev/null +++ b/src/ladspa_plugin/ladspa++.h @@ -0,0 +1,1026 @@ +/*************************************************************************/ +/* ladspa++ - A C++ wrapper for ladspa */ +/* Copyright (C) 2014 */ +/* Johannes Lorenz */ +/* https://github.com/JohannesLorenz/ */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 3 of the License, or (at */ +/* your option) any later version. */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ +/* General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA */ +/*************************************************************************/ + +#include +#include +#include + +#include "ladspa.h" + +namespace ladspa +{ + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + + namespace helpers + { + +/* + * sequences + */ + +//! default criterium argument, which accepts all numbers + template + struct criterium_true { + static constexpr bool value = true; + }; + +//! the resulting sequence type to test for + template + struct full_seq + { + }; + + namespace seq_helpers + { + + template class Criterium, int ...Seq> + struct _seq_recurse; + +//! @a cond is true => spawn @a I into seq and recurse + template class Criterium, bool cond, int ...Seq> + struct _seq_check + { + using type = typename _seq_recurse::type; + }; + +//! @a cond is false => skip @a I in sequence and recurse + template class Criterium, int ...Seq> + struct _seq_check + { + using type = typename _seq_recurse::type; + }; + +//! counting down, we have not reached the @a Start -> evaluate @a Criterium + template class Criterium, int ...Seq> + struct _seq + { + using type = typename _seq_check::value, Seq...>::type; + }; + +//! counting down, we have reached the @a Start + template class Criterium, int ...Seq> + struct _seq + { + using type = full_seq; + }; + +//! sequence recursion, just decrements @a I + template class Criterium, int ...Seq> + struct _seq_recurse + { + using type = typename _seq::type; + }; + + } // namespace seq_helpers + +//! creates maths like range, i.e. [Start, N] + template class Criterium = criterium_true> + using math_seq = typename seq_helpers::_seq::type; + +//! creates C like range, i.e. [Start-1, N-1]. Criterium is *not* counted for i-1 + template class Criterium = criterium_true> + using seq = math_seq; + + template static void do_nothing(Args...) {} + +/* + * avoiding instantiations + */ + template class falsify : std::false_type { }; + template class falsify_id : std::false_type { }; + template + class dont_instantiate_me { + static_assert(falsify::value, "This should not be instantiated."); + }; + template + class dont_instantiate_me_id { + static_assert(falsify_id::value, "This should not be instantiated."); + }; + +/* + * accessing helpers + */ +//! a quick fix since array's data() member is not constexpr + template + constexpr const T* get_data(const std::array& a) + { + return &a.front(); + } + + template + constexpr std::size_t enum_size() { return (std::size_t)EnumClass::size; } + +//! checks whether class @a T has a ctor with two arguments +//! @note: if we need multiple of those, inherit from a base class +// Source: [1] + template + class has_ctor_1_args + { + struct any + { + template< + typename U, typename Sfinae = + typename std::enable_if< false == + std::is_same::value, U >::type + > + operator U() const; + }; + + template + static int32_t sfinae( decltype( U( any( ) ) ) * ); + template + static int8_t sfinae( ... ); + + public: + static constexpr bool value = + sizeof( sfinae( nullptr ) ) == sizeof( int32_t ); + }; + + template class HaveClass> + using en_if_has = typename std::enable_if::value>::type; + + template class HaveClass> + using en_if_doesnt_have = typename std::enable_if::value>::type; + +/* + * misc + */ + template struct identity {}; + +//! if @a Type is the nth integer in @a Others, returns n + template + struct id_in_list; + + template + struct id_in_list + { + static constexpr size_t value = -1; + }; + + template + struct id_in_list + { + static constexpr size_t value = 0; + }; + + template + struct id_in_list + { + static constexpr size_t value + = id_in_list::value + 1; + }; + + } // namespace helpers + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +//! A struct describing ladspa++'s version + struct version_t + { + char major; + char minor; + char patch; + }; + +//! This object can be used to receive the current ladspa++ version + constexpr static version_t version = { 1, 0, 0 }; + + typedef unsigned long port_size_t; + typedef unsigned long sample_size_t; + typedef unsigned long sample_rate_t; + typedef unsigned long plugin_index_t; + typedef LADSPA_Data data; + +/** + * @brief A simple, type safe implementation of a bitmask. + * + * Its purpose is to be dependent on a class T, which means that bitmasks from + * different contexts can not be put into one operator. + */ + template + class bitmask + { + int bits; + public: + // member functions + constexpr int get_bits() const { return bits; } + constexpr bool is(const bitmask property) const { + return bits & property.bits; + } + constexpr bitmask(int _bits = 0) : bits(_bits) {} + + // related functions + friend constexpr bitmask operator| + (const bitmask& l, const bitmask& r) + { + return bitmask(l.bits|r.bits); + } + }; + +/** + * @brief Struct containing bits for ladspa properties. + * + * The bits specify optional properties of the plugin. + */ + struct properties + { + typedef bitmask m; + static constexpr m realtime = LADSPA_PROPERTY_REALTIME; + static constexpr m inplace_broken = LADSPA_PROPERTY_INPLACE_BROKEN; + static constexpr m hard_rt_capable = LADSPA_PROPERTY_HARD_RT_CAPABLE; + }; + +/** + * @brief Struct containing bits for ladspa's port types. + * + * The bits describe the basic communication type of a port. + */ + struct port_types + { + typedef bitmask m; + // ladspa forbids input + output + static constexpr m input = LADSPA_PORT_INPUT; + static constexpr m output = LADSPA_PORT_OUTPUT; + // ladspa forbids audio + control + static constexpr m control = LADSPA_PORT_CONTROL; + static constexpr m audio = LADSPA_PORT_AUDIO; + }; + +/** + * @brief Struct containing bits for ladspa's port hints. + * + * The bits give hints about the port's data range. + */ + struct port_hints + { + typedef bitmask m; + static constexpr m bounded_below = LADSPA_HINT_BOUNDED_BELOW; + static constexpr m bounded_above = LADSPA_HINT_BOUNDED_ABOVE; + static constexpr m toggled = LADSPA_HINT_TOGGLED; + static constexpr m sample_rate = LADSPA_HINT_SAMPLE_RATE; + static constexpr m logarithmic = LADSPA_HINT_LOGARITHMIC; + static constexpr m integer = LADSPA_HINT_INTEGER; + + static constexpr m default_mask = LADSPA_HINT_DEFAULT_MASK; + static constexpr m default_none = LADSPA_HINT_DEFAULT_NONE; + static constexpr m default_minimum = LADSPA_HINT_DEFAULT_MINIMUM; + static constexpr m default_low = LADSPA_HINT_DEFAULT_MIDDLE; + static constexpr m default_high = LADSPA_HINT_DEFAULT_HIGH; + static constexpr m default_maximum = LADSPA_HINT_DEFAULT_MAXIMUM; + static constexpr m default_0 = LADSPA_HINT_DEFAULT_0; + static constexpr m default_1 = LADSPA_HINT_DEFAULT_1; + static constexpr m default_100 = LADSPA_HINT_DEFAULT_100; + static constexpr m default_440 = LADSPA_HINT_DEFAULT_440; + }; + +/** + * @brief Class to access a whole buffer of @a T, like std::vector. + * + * Can be hard copied, this will be cheap. + * The class can contain a size information, or not. + */ + template + class buffer_template + { + T* _data; + //! this is overhead for multiple equal-sized buffers + //! however, this overhead is not much + std::size_t _size; + public: + buffer_template() {} + buffer_template(T* _in_data, std::size_t _in_size) + : _data(_in_data), _size(_in_size) {} + + void assign(T* _in_data) { _data = _in_data; } + void set_size(std::size_t _in_size) { _size = _in_size; } + +// void set_size(std::size_t _in_size) const { return _size; } + std::size_t size() const { return _size; } + + T& operator[](std::size_t n) { return _data[n]; } + const T& operator[](std::size_t n) const { return _data[n]; } + + T* begin() { return _data; } + const T* begin() const { return _data; } + T* end() { return _data + size(); } + const T* end() const { return _data + size(); } + T* data() { return begin(); } + const T* data() const { return begin(); } + }; + +//! A class that behaves like a reference to @a T. + template + class pointer_template + { + T* _data; + public: + pointer_template() {} + pointer_template(T* _in_data) + : _data(_in_data) {} + pointer_template(T* _in_data, int ) + : pointer_template(_in_data) {} + + void assign(T* _in_data) { _data = _in_data; } + void set_size(std::size_t _in_size) const {} + + operator const T&() const { return *_data; } + operator T&() { return *_data; } + }; + +//! Class for mutable buffers (like out ports) + typedef buffer_template buffer; +//! Class for const buffers (like in ports) + typedef buffer_template const_buffer; +//! Class for mutable single values (like in ports) + typedef pointer_template pointer; +//! Class for const single values (like out ports) + typedef pointer_template const_pointer; + +//! A class which describes a port. + struct port_info_t + { + //! A class which describes the numeric range for a port's values + struct range_hint_t + { + bitmask descriptor; + data lower_bound; + data upper_bound; + }; + + enum class type + { + name, + descriptor, + range_hint + }; + + const char* name; //!< Name of the port. Should be short. + const char* desription; //!< A short description about what it does + bitmask descriptor; //!< Information about the port type + range_hint_t hint; //!< Information about numeric range + + constexpr bool is_final() const { return (name == nullptr); } + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + //! This class is used in combination with the get() functions + template struct type_id {}; + + // get function overloads + constexpr const char* get(type_id) const { return name; } + constexpr LADSPA_PortDescriptor get(type_id) const { + return descriptor.get_bits(); + } + constexpr LADSPA_PortRangeHint get(type_id) const { + return { hint.descriptor.get_bits(), + hint.lower_bound, + hint.upper_bound }; + } +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + /* + * Predefined, common types + */ + +// constexpr const static port_info_t audio_input, +// audio_output; + + +/* constexpr const static port_info_t audio_input = { + "Input", "Effect's audio input (mono).", + port_types::input | port_types::audio, {0} }; + constexpr const static port_info_t audio_output = { + "Output", "Effect's audio output (mono).", + port_types::output | port_types::audio, {0} };*/ + }; + +//! A list of very common ports + namespace port_info_common + { + constexpr static port_info_t audio_input = { + "Input", "Effect's audio input (mono).", + port_types::input | port_types::audio }; + constexpr static port_info_t audio_input_l = { + "Input (L)", "Effect's audio input (left).", + port_types::input | port_types::audio }; + constexpr static port_info_t audio_input_r = { + "Input (R)", "Effect's audio input (right).", + port_types::input | port_types::audio }; + + constexpr static port_info_t audio_output = { + "Output", "Effect's audio output (mono).", + port_types::output | port_types::audio }; + constexpr static port_info_t audio_output_l = { + "Output (L)", "Effect's audio output (mono).", + port_types::output | port_types::audio }; + constexpr static port_info_t audio_output_r = { + "Output (R)", "Effect's audio output (right).", + port_types::output | port_types::audio }; + + // more ports can be added on request... + + //! port marking the end, recognized via the nullptr + constexpr static port_info_t final_port = { nullptr, + "Final port (internal use only).", 0, {0,0,0} }; + } + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +/* + * Return value specialisations for port_array_t + */ + template* bm, class Enable = void> + struct return_value_base_type + { + typedef buffer_template type; + }; + + template* bm> + struct return_value_base_type + is(port_types::control)>::type> + { + typedef pointer_template type; + }; + + template* bm, + class Enable = void> + struct return_value_access_type + { + typedef const base_type type; + }; + + template* bm> + struct return_value_access_type + is(port_types::output)>::type> + { + typedef base_type type; + }; + + template + class port_array_t; + + template + class port_ptrs + { + helpers::dont_instantiate_me s; + }; +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +/** + * @brief The result of dereferencing a multi_iterator. + * + * This class holds multiple pointers to the elements of multiple vectors. + * The position of these different pointers is always equal. + * From outside, there a no pointers, but references. + */ + template::port_names_t ...PortIndexes> + class port_ptrs, PortIndexes...> + { + class type_helpers + { + template* bm> + using t1 = typename return_value_access_type::type; + + public: + template + class type_at_port + { + static constexpr auto arr_elem = PortDesArray[PortName]; + static constexpr auto descr = arr_elem.descriptor; + public: + typedef t1<&descr> type; // data or const data + }; + + template + struct _storage_t + { + typedef typename std::tuple + ::type*...> type; + }; + }; + public: + template + using type_at = typename type_helpers::template type_at_port::type; + + private: + typedef typename type_helpers::template _storage_t<(int)PortIndexes...>::type + storage_t; + + storage_t pointers; //!< valid if we are not at the end() + + typedef port_array_t port_array_t_t; + + template + type_at*& get_ptr() { + return std::get::value>(port_ptrs::pointers); + } + + template + type_at<(std::size_t)id>*& get_ptr() { + return get_ptr<(std::size_t)id>(); + } + + template + type_at& get() { + return *get_ptr(); + } + + public: + port_ptrs(const port_array_t_t& port_array_t) + : pointers(port_array_t.template get().begin()...) {} + port_ptrs() {} + + void operator++() + { + helpers::do_nothing(++(get_ptr())...); + } + + template + type_at<(std::size_t)id>& get() { + return get<(std::size_t)id>(); + } + }; + +/** + * @brief An iterator over a port array container. + * + * This class holds multiple pointers to the elements of multiple vectors. + * The position of these different pointers is always equal. + */ + template + class multi_iterator + { + private: + typedef multi_iterator m_type; + + port_ptrs _port_ptrs; + std::size_t position; //!< valid if we are not at the end() + const sample_size_t sample_count; //! note: this parameter could be obsolete, or useful... + + public: + bool operator!=(const m_type& other) + { + return position != other.position; + } + + m_type& operator++() + { + ++position; + ++_port_ptrs; + return *this; + } + + port_ptrs& operator*() { return _port_ptrs; } + + //! Iterator pointing to the begin of @a port_array + multi_iterator(const port_array_t& port_array, sample_size_t _sample_count) : + _port_ptrs(port_array), + position(0), + sample_count(_sample_count) + {} + + //! Iterator pointing to the end of any port array + multi_iterator(sample_size_t _sample_count) : + position(_sample_count), + sample_count(_sample_count) + { + } + }; + +/** + * @brief A container over a port array. Can be iterated. + * + * This class is being instantiated to mark + * over which ports you want to iterate. + */ + template + class samples_container + { + const port_array_t_t& port_array_t; + const sample_size_t sample_count; + typedef multi_iterator multi_itr_type; + public: + samples_container(const port_array_t_t& pa, sample_size_t sc) + : port_array_t(pa), sample_count(sc) {} + multi_itr_type begin() const { + return multi_itr_type(port_array_t, sample_count); } + multi_itr_type end() const { return multi_itr_type(sample_count); } + }; + +/** + * @brief A class that contains all ports. + * + * This includes all buffers and the buffer size. + */ + template + class port_array_t + { + private: + typedef port_array_t m_type; + + class type_helpers + { + + template* bm> + using t1 = typename return_value_access_type::type; + template* bm> + using return_value_preparation = typename return_value_base_type, bm>::type; + public: + template + class type_at_port + { + static constexpr auto arr_elem = PortDesArray[PortName]; + static constexpr auto descr = arr_elem.descriptor; + public: + typedef return_value_preparation<&descr> type; + }; + + template struct _storage_t { + helpers::dont_instantiate_me x; + }; + template + struct _storage_t> + { + typedef std::tuple::type...> type; + }; + }; + + constexpr static std::size_t port_size = helpers::enum_size(); + constexpr static const port_info_t* port_des_array = PortDesArray; + public: + typedef PortNamesT port_names_t; + template + using type_at = typename type_helpers::template type_at_port::type; + private: + typedef typename type_helpers::template _storage_t< + typename helpers::template seq>::type storage_t; + private: + /* + * data + */ + storage_t storage; + int _current_sample_count; + + template + static void set_static(port_array_t& p, data* d) { + p.set_internal(d); + } + + struct caller + { + void (&callback)(port_array_t&, data*); + }; + + template + static constexpr typename std::array init_callers(T) + { + static_assert(helpers::falsify::value, + "This should not be instantiated."); + return {}; // constexpr function must have return value + } + + template + static constexpr typename std::array init_callers(helpers::full_seq) + { + return {{{port_array_t::set_static}...}}; + } + + static constexpr typename std::array callers + = init_callers(typename helpers::seq{}); + + static constexpr bool in_range_cond(int id) + { + return id >= 0 && + (std::size_t)id < helpers::enum_size(); + } + + template + void set_internal(data* d) { + assert(in_range_cond(id)); + std::get(storage).assign(d); + } + public: + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + //! Intended for internal use only + void set_caller(int id, data* d) { + callers[id].callback(*this, d); + } + //! Intended for internal use only + void set_current_sample_count(sample_size_t s) { + _current_sample_count = s; + } +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + + template + type_at get() const { + type_at ret_val = std::get(storage); + // buffer size is usually not set - set it + ret_val.set_size(_current_sample_count); + return ret_val; + } + template + type_at<(std::size_t)id> get() const { + return get<(std::size_t)id>(); + } + + //! lets you choose which buffers you want to iterate over + template + samples_container buffers() { + return samples_container( + *this, _current_sample_count); + } + +/* //! lets you iterate over all buffers + samples_container all_buffers() { + return samples_container( + *this, _current_sample_count); + }*/ + + //! A way the programmer can get the current sample count + //! in the run() function + sample_size_t current_sample_count(void) { + return _current_sample_count; + } + }; + + template + constexpr typename std::array::caller, + port_array_t::port_size> + port_array_t::callers; + +//! A class which the programmer fills in to describe her/his plugin + struct info_t + { + unsigned long unique_id; + const char * label; + bitmask plugin_properties; + const char * name; + const char * maker; + const char * help; + const char * keywords[8]; + const char * copyright; + void * implementation_data; + }; + +//! returns size of the port array + static constexpr port_size_t get_port_size(const ladspa::port_info_t* arr) { + return arr->is_final() ? 0 : get_port_size(arr + 1) + 1; + } + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +/** + * @brief The direct holder for the plugin class + * + * A struct between builder and plugin, + * in order to hold the port array. + * (it should not be held by the user) + * + * @note Internally, this class is being casted to LADSPA_Handle + */ + template + class plugin_holder_t + { + typedef port_array_t _port_array_t; + + _port_array_t _ports; + Plugin plugin; + + public: + template* = nullptr> + plugin_holder_t(helpers::identity<_Plugin>, + sample_rate_t _sample_rate + ) : plugin(_sample_rate) {} + + template* = nullptr> + plugin_holder_t(helpers::identity<_Plugin>, + sample_rate_t + ) {} + + void run(sample_size_t _sample_count) { + _ports.set_current_sample_count(_sample_count); + plugin.run(_ports); + } + + void connect_port(int _port, data* d) { + _ports.set_caller(_port, d); + } + }; +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +/** + * @brief A class that sets up everything for the C ladpsa side. + * + * This includes the static descriptions, port buffers and callbacks. + * You do not use this class, please use the collection class instead. + */ + template + class builder + { + typedef plugin_holder_t _plugin_holder_t; + + /* + * Data + */ + static constexpr const info_t& descriptor = Plugin::info; + static constexpr const port_info_t* port_info = Plugin::port_info; + static constexpr port_size_t port_size = get_port_size(port_info); + + /* + * This shifts the arrays + */ + template + static constexpr auto _get_elem(helpers::full_seq, T* lhs) + -> std::array())), N> + { + return {{lhs[Is].get(port_info_t::type_id())...}}; + } + + template + static constexpr auto get_elem(T* lhs) + -> decltype( _get_elem(helpers::seq{}, lhs) ) + { + return _get_elem(helpers::seq{}, lhs); + } + + /* + * These functions are the ladspa callbacks + */ + + template + static LADSPA_Handle _instantiate( + const struct _LADSPA_Descriptor * d, sample_rate_t s) { + //return new _Plugin; + return new _plugin_holder_t(helpers::identity(), s); + } + + static void _cleanup(LADSPA_Handle _instance) { + delete static_cast<_plugin_holder_t*>(_instance); + } + + static void + _connect_port(LADSPA_Handle _instance, + port_size_t _port, + data * _data_location) + { + static_cast<_plugin_holder_t*>(_instance)-> + connect_port(_port, _data_location); + //static_cast<_plugin_holder_t*>(_instance)-> + // _ports.set_caller(_port, _data_location); + } + + template + struct criterium_is_buffer + { + constexpr static bool value = port_info[i].descriptor.is(port_types::audio); + }; + + //void _activate(LADSPA_Handle Instance); + static void _run(LADSPA_Handle _instance, + sample_size_t _sample_count) + { + + //Plugin* instance = &(static_cast<_plugin_holder_t>(_instance)->plugin); + +// set_sizes(nullptr, _sample_count, helpers::seq{}); + // _run_with_seq(_instance, _sample_count, helpers::gen_seq{}); + // instance->run(ports); + + static_cast<_plugin_holder_t*>(_instance)->run(_sample_count); + } + + static constexpr std::array + port_descr + = get_elem(port_info); + static constexpr std::array + port_names + = get_elem(port_info); + static constexpr std::array + port_range_hints + = get_elem(port_info); + static constexpr LADSPA_Descriptor descriptor_for_ladspa = + { + descriptor.unique_id, + descriptor.label, + descriptor.plugin_properties.get_bits(), + descriptor.name, + descriptor.maker, + descriptor.copyright, + port_size, + helpers::get_data(port_descr), + helpers::get_data(port_names), + helpers::get_data(port_range_hints), + descriptor.implementation_data, + _instantiate, + _connect_port, + nullptr, //_activate, + _run, + nullptr, // run_adding + nullptr, // set_run_adding_gain + nullptr, // deactivate + _cleanup + }; + public: + static const LADSPA_Descriptor& get_ladspa_descriptor() + { return descriptor_for_ladspa; } + }; + +/* + * Static member definitions + */ + template + constexpr std::array::port_size> + builder::port_descr; + template + constexpr std::array::port_size> + builder::port_names; + template + constexpr std::array::port_size> + builder::port_range_hints; + + template + constexpr LADSPA_Descriptor builder::descriptor_for_ladspa; + +//! common strings to be used + namespace strings + { + //! strings for the info_t::copyright field + namespace copyright + { + constexpr const char* none = "None"; + constexpr const char* gpl3 = "GPL v3"; + } + } + +/** + * @brief This is for a collection of your plugin types. + * + * it helps you to select the correct descriptor at runtime. + */ + template + class collection + { + struct caller + { + const LADSPA_Descriptor& (&callback)(); + }; + + static constexpr std::array init_callers() + { + return {{{builder::get_ladspa_descriptor}...}}; + } + + static constexpr std::array callers + = init_callers(); + public: + //! Returns the requested descriptor + //! or nullptr if the index is out of range. + static const LADSPA_Descriptor* get_ladspa_descriptor( + plugin_index_t index) + { + return (index >= sizeof...(Args)) + ? nullptr + : &callers[index].callback(); + } + }; + + template + constexpr std::array::caller, sizeof...(Args)> + collection::callers; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + struct correctness_checker + { + // TODO: different IDs, In Out, broken inplace etc + }; +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +} + +// sources: +// [1] http://stackoverflow.com/questions/16137468/ +// sfinae-detect-constructor-with-one-argument diff --git a/src/ladspa_plugin/ladspa.h b/src/ladspa_plugin/ladspa.h new file mode 100644 index 00000000..d09b5bc3 --- /dev/null +++ b/src/ladspa_plugin/ladspa.h @@ -0,0 +1,603 @@ +/* ladspa.h + + Linux Audio Developer's Simple Plugin API Version 1.1[LGPL]. + Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, + Stefan Westerfeld. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. */ + +#ifndef LADSPA_INCLUDED +#define LADSPA_INCLUDED + +#define LADSPA_VERSION "1.1" +#define LADSPA_VERSION_MAJOR 1 +#define LADSPA_VERSION_MINOR 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*****************************************************************************/ + +/* Overview: + + There is a large number of synthesis packages in use or development + on the Linux platform at this time. This API (`The Linux Audio + Developer's Simple Plugin API') attempts to give programmers the + ability to write simple `plugin' audio processors in C/C++ and link + them dynamically (`plug') into a range of these packages (`hosts'). + It should be possible for any host and any plugin to communicate + completely through this interface. + + This API is deliberately short and simple. To achieve compatibility + with a range of promising Linux sound synthesis packages it + attempts to find the `greatest common divisor' in their logical + behaviour. Having said this, certain limiting decisions are + implicit, notably the use of a fixed type (LADSPA_Data) for all + data transfer and absence of a parameterised `initialisation' + phase. See below for the LADSPA_Data typedef. + + Plugins are expected to distinguish between control and audio + data. Plugins have `ports' that are inputs or outputs for audio or + control data and each plugin is `run' for a `block' corresponding + to a short time interval measured in samples. Audio data is + communicated using arrays of LADSPA_Data, allowing a block of audio + to be processed by the plugin in a single pass. Control data is + communicated using single LADSPA_Data values. Control data has a + single value at the start of a call to the `run()' or `run_adding()' + function, and may be considered to remain this value for its + duration. The plugin may assume that all its input and output ports + have been connected to the relevant data location (see the + `connect_port()' function below) before it is asked to run. + + Plugins will reside in shared object files suitable for dynamic + linking by dlopen() and family. The file will provide a number of + `plugin types' that can be used to instantiate actual plugins + (sometimes known as `plugin instances') that can be connected + together to perform tasks. + + This API contains very limited error-handling. */ + +/*****************************************************************************/ + +/* Fundamental data type passed in and out of plugin. This data type + is used to communicate audio samples and control values. It is + assumed that the plugin will work sensibly given any numeric input + value although it may have a preferred range (see hints below). + + For audio it is generally assumed that 1.0f is the `0dB' reference + amplitude and is a `normal' signal level. */ + +typedef float LADSPA_Data; + +/*****************************************************************************/ + +/* Special Plugin Properties: + + Optional features of the plugin type are encapsulated in the + LADSPA_Properties type. This is assembled by ORing individual + properties together. */ + +typedef int LADSPA_Properties; + +/* Property LADSPA_PROPERTY_REALTIME indicates that the plugin has a + real-time dependency (e.g. listens to a MIDI device) and so its + output must not be cached or subject to significant latency. */ +#define LADSPA_PROPERTY_REALTIME 0x1 + +/* Property LADSPA_PROPERTY_INPLACE_BROKEN indicates that the plugin + may cease to work correctly if the host elects to use the same data + location for both input and output (see connect_port()). This + should be avoided as enabling this flag makes it impossible for + hosts to use the plugin to process audio `in-place.' */ +#define LADSPA_PROPERTY_INPLACE_BROKEN 0x2 + +/* Property LADSPA_PROPERTY_HARD_RT_CAPABLE indicates that the plugin + is capable of running not only in a conventional host but also in a + `hard real-time' environment. To qualify for this the plugin must + satisfy all of the following: + + (1) The plugin must not use malloc(), free() or other heap memory + management within its run() or run_adding() functions. All new + memory used in run() must be managed via the stack. These + restrictions only apply to the run() function. + + (2) The plugin will not attempt to make use of any library + functions with the exceptions of functions in the ANSI standard C + and C maths libraries, which the host is expected to provide. + + (3) The plugin will not access files, devices, pipes, sockets, IPC + or any other mechanism that might result in process or thread + blocking. + + (4) The plugin will take an amount of time to execute a run() or + run_adding() call approximately of form (A+B*SampleCount) where A + and B depend on the machine and host in use. This amount of time + may not depend on input signals or plugin state. The host is left + the responsibility to perform timings to estimate upper bounds for + A and B. */ +#define LADSPA_PROPERTY_HARD_RT_CAPABLE 0x4 + +#define LADSPA_IS_REALTIME(x) ((x) & LADSPA_PROPERTY_REALTIME) +#define LADSPA_IS_INPLACE_BROKEN(x) ((x) & LADSPA_PROPERTY_INPLACE_BROKEN) +#define LADSPA_IS_HARD_RT_CAPABLE(x) ((x) & LADSPA_PROPERTY_HARD_RT_CAPABLE) + +/*****************************************************************************/ + +/* Plugin Ports: + + Plugins have `ports' that are inputs or outputs for audio or + data. Ports can communicate arrays of LADSPA_Data (for audio + inputs/outputs) or single LADSPA_Data values (for control + input/outputs). This information is encapsulated in the + LADSPA_PortDescriptor type which is assembled by ORing individual + properties together. + + Note that a port must be an input or an output port but not both + and that a port must be a control or audio port but not both. */ + +typedef int LADSPA_PortDescriptor; + +/* Property LADSPA_PORT_INPUT indicates that the port is an input. */ +#define LADSPA_PORT_INPUT 0x1 + +/* Property LADSPA_PORT_OUTPUT indicates that the port is an output. */ +#define LADSPA_PORT_OUTPUT 0x2 + +/* Property LADSPA_PORT_CONTROL indicates that the port is a control + port. */ +#define LADSPA_PORT_CONTROL 0x4 + +/* Property LADSPA_PORT_AUDIO indicates that the port is a audio + port. */ +#define LADSPA_PORT_AUDIO 0x8 + +#define LADSPA_IS_PORT_INPUT(x) ((x) & LADSPA_PORT_INPUT) +#define LADSPA_IS_PORT_OUTPUT(x) ((x) & LADSPA_PORT_OUTPUT) +#define LADSPA_IS_PORT_CONTROL(x) ((x) & LADSPA_PORT_CONTROL) +#define LADSPA_IS_PORT_AUDIO(x) ((x) & LADSPA_PORT_AUDIO) + +/*****************************************************************************/ + +/* Plugin Port Range Hints: + + The host may wish to provide a representation of data entering or + leaving a plugin (e.g. to generate a GUI automatically). To make + this more meaningful, the plugin should provide `hints' to the host + describing the usual values taken by the data. + + Note that these are only hints. The host may ignore them and the + plugin must not assume that data supplied to it is meaningful. If + the plugin receives invalid input data it is expected to continue + to run without failure and, where possible, produce a sensible + output (e.g. a high-pass filter given a negative cutoff frequency + might switch to an all-pass mode). + + Hints are meaningful for all input and output ports but hints for + input control ports are expected to be particularly useful. + + More hint information is encapsulated in the + LADSPA_PortRangeHintDescriptor type which is assembled by ORing + individual hint types together. Hints may require further + LowerBound and UpperBound information. + + All the hint information for a particular port is aggregated in the + LADSPA_PortRangeHint structure. */ + +typedef int LADSPA_PortRangeHintDescriptor; + +/* Hint LADSPA_HINT_BOUNDED_BELOW indicates that the LowerBound field + of the LADSPA_PortRangeHint should be considered meaningful. The + value in this field should be considered the (inclusive) lower + bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also + specified then the value of LowerBound should be multiplied by the + sample rate. */ +#define LADSPA_HINT_BOUNDED_BELOW 0x1 + +/* Hint LADSPA_HINT_BOUNDED_ABOVE indicates that the UpperBound field + of the LADSPA_PortRangeHint should be considered meaningful. The + value in this field should be considered the (inclusive) upper + bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also + specified then the value of UpperBound should be multiplied by the + sample rate. */ +#define LADSPA_HINT_BOUNDED_ABOVE 0x2 + +/* Hint LADSPA_HINT_TOGGLED indicates that the data item should be + considered a Boolean toggle. Data less than or equal to zero should + be considered `off' or `false,' and data above zero should be + considered `on' or `true.' LADSPA_HINT_TOGGLED may not be used in + conjunction with any other hint except LADSPA_HINT_DEFAULT_0 or + LADSPA_HINT_DEFAULT_1. */ +#define LADSPA_HINT_TOGGLED 0x4 + +/* Hint LADSPA_HINT_SAMPLE_RATE indicates that any bounds specified + should be interpreted as multiples of the sample rate. For + instance, a frequency range from 0Hz to the Nyquist frequency (half + the sample rate) could be requested by this hint in conjunction + with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds + at all must support this hint to retain meaning. */ +#define LADSPA_HINT_SAMPLE_RATE 0x8 + +/* Hint LADSPA_HINT_LOGARITHMIC indicates that it is likely that the + user will find it more intuitive to view values using a logarithmic + scale. This is particularly useful for frequencies and gains. */ +#define LADSPA_HINT_LOGARITHMIC 0x10 + +/* Hint LADSPA_HINT_INTEGER indicates that a user interface would + probably wish to provide a stepped control taking only integer + values. Any bounds set should be slightly wider than the actual + integer range required to avoid floating point rounding errors. For + instance, the integer set {0,1,2,3} might be described as [-0.1, + 3.1]. */ +#define LADSPA_HINT_INTEGER 0x20 + +/* The various LADSPA_HINT_HAS_DEFAULT_* hints indicate a `normal' + value for the port that is sensible as a default. For instance, + this value is suitable for use as an initial value in a user + interface or as a value the host might assign to a control port + when the user has not provided one. Defaults are encoded using a + mask so only one default may be specified for a port. Some of the + hints make use of lower and upper bounds, in which case the + relevant bound or bounds must be available and + LADSPA_HINT_SAMPLE_RATE must be applied as usual. The resulting + default must be rounded if LADSPA_HINT_INTEGER is present. Default + values were introduced in LADSPA v1.1. */ +#define LADSPA_HINT_DEFAULT_MASK 0x3C0 + +/* This default values indicates that no default is provided. */ +#define LADSPA_HINT_DEFAULT_NONE 0x0 + +/* This default hint indicates that the suggested lower bound for the + port should be used. */ +#define LADSPA_HINT_DEFAULT_MINIMUM 0x40 + +/* This default hint indicates that a low value between the suggested + lower and upper bounds should be chosen. For ports with + LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.75 + + log(upper) * 0.25). Otherwise, this should be (lower * 0.75 + upper + * 0.25). */ +#define LADSPA_HINT_DEFAULT_LOW 0x80 + +/* This default hint indicates that a middle value between the + suggested lower and upper bounds should be chosen. For ports with + LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.5 + + log(upper) * 0.5). Otherwise, this should be (lower * 0.5 + upper * + 0.5). */ +#define LADSPA_HINT_DEFAULT_MIDDLE 0xC0 + +/* This default hint indicates that a high value between the suggested + lower and upper bounds should be chosen. For ports with + LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.25 + + log(upper) * 0.75). Otherwise, this should be (lower * 0.25 + upper + * 0.75). */ +#define LADSPA_HINT_DEFAULT_HIGH 0x100 + +/* This default hint indicates that the suggested upper bound for the + port should be used. */ +#define LADSPA_HINT_DEFAULT_MAXIMUM 0x140 + +/* This default hint indicates that the number 0 should be used. Note + that this default may be used in conjunction with + LADSPA_HINT_TOGGLED. */ +#define LADSPA_HINT_DEFAULT_0 0x200 + +/* This default hint indicates that the number 1 should be used. Note + that this default may be used in conjunction with + LADSPA_HINT_TOGGLED. */ +#define LADSPA_HINT_DEFAULT_1 0x240 + +/* This default hint indicates that the number 100 should be used. */ +#define LADSPA_HINT_DEFAULT_100 0x280 + +/* This default hint indicates that the Hz frequency of `concert A' + should be used. This will be 440 unless the host uses an unusual + tuning convention, in which case it may be within a few Hz. */ +#define LADSPA_HINT_DEFAULT_440 0x2C0 + +#define LADSPA_IS_HINT_BOUNDED_BELOW(x) ((x) & LADSPA_HINT_BOUNDED_BELOW) +#define LADSPA_IS_HINT_BOUNDED_ABOVE(x) ((x) & LADSPA_HINT_BOUNDED_ABOVE) +#define LADSPA_IS_HINT_TOGGLED(x) ((x) & LADSPA_HINT_TOGGLED) +#define LADSPA_IS_HINT_SAMPLE_RATE(x) ((x) & LADSPA_HINT_SAMPLE_RATE) +#define LADSPA_IS_HINT_LOGARITHMIC(x) ((x) & LADSPA_HINT_LOGARITHMIC) +#define LADSPA_IS_HINT_INTEGER(x) ((x) & LADSPA_HINT_INTEGER) + +#define LADSPA_IS_HINT_HAS_DEFAULT(x) ((x) & LADSPA_HINT_DEFAULT_MASK) +#define LADSPA_IS_HINT_DEFAULT_MINIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_MINIMUM) +#define LADSPA_IS_HINT_DEFAULT_LOW(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_LOW) +#define LADSPA_IS_HINT_DEFAULT_MIDDLE(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_MIDDLE) +#define LADSPA_IS_HINT_DEFAULT_HIGH(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_HIGH) +#define LADSPA_IS_HINT_DEFAULT_MAXIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_MAXIMUM) +#define LADSPA_IS_HINT_DEFAULT_0(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_0) +#define LADSPA_IS_HINT_DEFAULT_1(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_1) +#define LADSPA_IS_HINT_DEFAULT_100(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_100) +#define LADSPA_IS_HINT_DEFAULT_440(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_440) + +typedef struct _LADSPA_PortRangeHint { + + /* Hints about the port. */ + LADSPA_PortRangeHintDescriptor HintDescriptor; + + /* Meaningful when hint LADSPA_HINT_BOUNDED_BELOW is active. When + LADSPA_HINT_SAMPLE_RATE is also active then this value should be + multiplied by the relevant sample rate. */ + LADSPA_Data LowerBound; + + /* Meaningful when hint LADSPA_HINT_BOUNDED_ABOVE is active. When + LADSPA_HINT_SAMPLE_RATE is also active then this value should be + multiplied by the relevant sample rate. */ + LADSPA_Data UpperBound; + +} LADSPA_PortRangeHint; + +/*****************************************************************************/ + +/* Plugin Handles: + + This plugin handle indicates a particular instance of the plugin + concerned. It is valid to compare this to NULL (0 for C++) but + otherwise the host should not attempt to interpret it. The plugin + may use it to reference internal instance data. */ + +typedef void * LADSPA_Handle; + +/*****************************************************************************/ + +/* Descriptor for a Type of Plugin: + + This structure is used to describe a plugin type. It provides a + number of functions to examine the type, instantiate it, link it to + buffers and workspaces and to run it. */ + +typedef struct _LADSPA_Descriptor { + + /* This numeric identifier indicates the plugin type + uniquely. Plugin programmers may reserve ranges of IDs from a + central body to avoid clashes. Hosts may assume that IDs are + below 0x1000000. */ + unsigned long UniqueID; + + /* This identifier can be used as a unique, case-sensitive + identifier for the plugin type within the plugin file. Plugin + types should be identified by file and label rather than by index + or plugin name, which may be changed in new plugin + versions. Labels must not contain white-space characters. */ + const char * Label; + + /* This indicates a number of properties of the plugin. */ + LADSPA_Properties Properties; + + /* This member points to the null-terminated name of the plugin + (e.g. "Sine Oscillator"). */ + const char * Name; + + /* This member points to the null-terminated string indicating the + maker of the plugin. This can be an empty string but not NULL. */ + const char * Maker; + + /* This member points to the null-terminated string indicating any + copyright applying to the plugin. If no Copyright applies the + string "None" should be used. */ + const char * Copyright; + + /* This indicates the number of ports (input AND output) present on + the plugin. */ + unsigned long PortCount; + + /* This member indicates an array of port descriptors. Valid indices + vary from 0 to PortCount-1. */ + const LADSPA_PortDescriptor * PortDescriptors; + + /* This member indicates an array of null-terminated strings + describing ports (e.g. "Frequency (Hz)"). Valid indices vary from + 0 to PortCount-1. */ + const char * const * PortNames; + + /* This member indicates an array of range hints for each port (see + above). Valid indices vary from 0 to PortCount-1. */ + const LADSPA_PortRangeHint * PortRangeHints; + + /* This may be used by the plugin developer to pass any custom + implementation data into an instantiate call. It must not be used + or interpreted by the host. It is expected that most plugin + writers will not use this facility as LADSPA_Handle should be + used to hold instance data. */ + void * ImplementationData; + + /* This member is a function pointer that instantiates a plugin. A + handle is returned indicating the new plugin instance. The + instantiation function accepts a sample rate as a parameter. The + plugin descriptor from which this instantiate function was found + must also be passed. This function must return NULL if + instantiation fails. + + Note that instance initialisation should generally occur in + activate() rather than here. */ + LADSPA_Handle (*instantiate)(const struct _LADSPA_Descriptor * Descriptor, + unsigned long SampleRate); + + /* This member is a function pointer that connects a port on an + instantiated plugin to a memory location at which a block of data + for the port will be read/written. The data location is expected + to be an array of LADSPA_Data for audio ports or a single + LADSPA_Data value for control ports. Memory issues will be + managed by the host. The plugin must read/write the data at these + locations every time run() or run_adding() is called and the data + present at the time of this connection call should not be + considered meaningful. + + connect_port() may be called more than once for a plugin instance + to allow the host to change the buffers that the plugin is + reading or writing. These calls may be made before or after + activate() or deactivate() calls. + + connect_port() must be called at least once for each port before + run() or run_adding() is called. When working with blocks of + LADSPA_Data the plugin should pay careful attention to the block + size passed to the run function as the block allocated may only + just be large enough to contain the block of samples. + + Plugin writers should be aware that the host may elect to use the + same buffer for more than one port and even use the same buffer + for both input and output (see LADSPA_PROPERTY_INPLACE_BROKEN). + However, overlapped buffers or use of a single buffer for both + audio and control data may result in unexpected behaviour. */ + void (*connect_port)(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation); + + /* This member is a function pointer that initialises a plugin + instance and activates it for use. This is separated from + instantiate() to aid real-time support and so that hosts can + reinitialise a plugin instance by calling deactivate() and then + activate(). In this case the plugin instance must reset all state + information dependent on the history of the plugin instance + except for any data locations provided by connect_port() and any + gain set by set_run_adding_gain(). If there is nothing for + activate() to do then the plugin writer may provide a NULL rather + than an empty function. + + When present, hosts must call this function once before run() (or + run_adding()) is called for the first time. This call should be + made as close to the run() call as possible and indicates to + real-time plugins that they are now live. Plugins should not rely + on a prompt call to run() after activate(). activate() may not be + called again unless deactivate() is called first. Note that + connect_port() may be called before or after a call to + activate(). */ + void (*activate)(LADSPA_Handle Instance); + + /* This method is a function pointer that runs an instance of a + plugin for a block. Two parameters are required: the first is a + handle to the particular instance to be run and the second + indicates the block size (in samples) for which the plugin + instance may run. + + Note that if an activate() function exists then it must be called + before run() or run_adding(). If deactivate() is called for a + plugin instance then the plugin instance may not be reused until + activate() has been called again. + + If the plugin has the property LADSPA_PROPERTY_HARD_RT_CAPABLE + then there are various things that the plugin should not do + within the run() or run_adding() functions (see above). */ + void (*run)(LADSPA_Handle Instance, + unsigned long SampleCount); + + /* This method is a function pointer that runs an instance of a + plugin for a block. This has identical behaviour to run() except + in the way data is output from the plugin. When run() is used, + values are written directly to the memory areas associated with + the output ports. However when run_adding() is called, values + must be added to the values already present in the memory + areas. Furthermore, output values written must be scaled by the + current gain set by set_run_adding_gain() (see below) before + addition. + + run_adding() is optional. When it is not provided by a plugin, + this function pointer must be set to NULL. When it is provided, + the function set_run_adding_gain() must be provided also. */ + void (*run_adding)(LADSPA_Handle Instance, + unsigned long SampleCount); + + /* This method is a function pointer that sets the output gain for + use when run_adding() is called (see above). If this function is + never called the gain is assumed to default to 1. Gain + information should be retained when activate() or deactivate() + are called. + + This function should be provided by the plugin if and only if the + run_adding() function is provided. When it is absent this + function pointer must be set to NULL. */ + void (*set_run_adding_gain)(LADSPA_Handle Instance, + LADSPA_Data Gain); + + /* This is the counterpart to activate() (see above). If there is + nothing for deactivate() to do then the plugin writer may provide + a NULL rather than an empty function. + + Hosts must deactivate all activated units after they have been + run() (or run_adding()) for the last time. This call should be + made as close to the last run() call as possible and indicates to + real-time plugins that they are no longer live. Plugins should + not rely on prompt deactivation. Note that connect_port() may be + called before or after a call to deactivate(). + + Deactivation is not similar to pausing as the plugin instance + will be reinitialised when activate() is called to reuse it. */ + void (*deactivate)(LADSPA_Handle Instance); + + /* Once an instance of a plugin has been finished with it can be + deleted using the following function. The instance handle passed + ceases to be valid after this call. + + If activate() was called for a plugin instance then a + corresponding call to deactivate() must be made before cleanup() + is called. */ + void (*cleanup)(LADSPA_Handle Instance); + +} LADSPA_Descriptor; + +/**********************************************************************/ + +/* Accessing a Plugin: */ + +/* The exact mechanism by which plugins are loaded is host-dependent, + however all most hosts will need to know is the name of shared + object file containing the plugin types. To allow multiple hosts to + share plugin types, hosts may wish to check for environment + variable LADSPA_PATH. If present, this should contain a + colon-separated path indicating directories that should be searched + (in order) when loading plugin types. + + A plugin programmer must include a function called + "ladspa_descriptor" with the following function prototype within + the shared object file. This function will have C-style linkage (if + you are using C++ this is taken care of by the `extern "C"' clause + at the top of the file). + + A host will find the plugin shared object file by one means or + another, find the ladspa_descriptor() function, call it, and + proceed from there. + + Plugin types are accessed by index (not ID) using values from 0 + upwards. Out of range indexes must result in this function + returning NULL, so the plugin count can be determined by checking + for the least index that results in NULL being returned. */ + +const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index); + +/* Datatype corresponding to the ladspa_descriptor() function. */ +typedef const LADSPA_Descriptor * +(*LADSPA_Descriptor_Function)(unsigned long Index); + +/**********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* LADSPA_INCLUDED */ + +/* EOF */ diff --git a/src/lv2_plugin/CMakeLists.txt b/src/lv2_plugin/CMakeLists.txt index 8385fdf6..e172771e 100644 --- a/src/lv2_plugin/CMakeLists.txt +++ b/src/lv2_plugin/CMakeLists.txt @@ -3,15 +3,17 @@ project(rnnoise_lv2_plugin LANGUAGES CXX) set(CMAKE_CXX_STANDARD 14) -include_directories(/) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) set(PROJECT_ROOT ../../../) set(LV2_INTERFACE_SRC - lv2/lv2plug.in/ns/lv2core/lv2.h - lv2/lv2plug.in/ns/lv2core/lv2_util.h - lv2/lv2plug.in/ns/lv2core/Plugin.hpp - lv2/lv2plug.in/ns/lv2core/Lib.hpp) + lv2core/lv2.h + lv2core/lv2_util.h + lv2core/Plugin.hpp + lv2core/Lib.hpp) set(LV2_IMPL_SRC RnNoiseLv2Plugin.h @@ -28,7 +30,7 @@ function(build bit) add_library(${LV2_TARGET_X${bit}} SHARED ${LV2_PLUGIN_SOURCES}) - target_link_libraries(${LV2_TARGET_X${bit}} RnNoisePluginCommon "-static -static-libgcc -static-libstdc++ -m${bit}") + target_link_libraries(${LV2_TARGET_X${bit}} RnNoisePluginCommon "-static-libgcc -static-libstdc++ -m${bit}") set(X${bit}_COMPILE_OPTIONS "-m${bit};" @@ -37,7 +39,7 @@ function(build bit) target_compile_options(${LV2_TARGET_X${bit}} PRIVATE ${X${bit}_COMPILE_OPTIONS}) set_target_properties(${LV2_TARGET_X${bit}} PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${PROJECT_ROOT}/bin/x${bit}/rnnoise.lv2") + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_ROOT}/bin/x${bit}/rnnoise.lv2") configure_file(resources/manifest_x${bit}.ttl ${PROJECT_ROOT}/bin/x${bit}/rnnoise.lv2/manifest.ttl) configure_file(resources/rnnoise.ttl ${PROJECT_ROOT}/bin/x${bit}/rnnoise.lv2/rnnoise.ttl) diff --git a/src/lv2_plugin/RnNoiseLv2Lib.h b/src/lv2_plugin/RnNoiseLv2Lib.h index 53c62036..f0f80f52 100644 --- a/src/lv2_plugin/RnNoiseLv2Lib.h +++ b/src/lv2_plugin/RnNoiseLv2Lib.h @@ -1,7 +1,7 @@ #pragma once #include -#include "lv2/lv2plug.in/ns/lv2core/Lib.hpp" +#include "lv2core/Lib.hpp" #include "RnNoiseLv2Plugin.h" diff --git a/src/lv2_plugin/RnNoiseLv2Plugin.h b/src/lv2_plugin/RnNoiseLv2Plugin.h index 04a62bd9..81995582 100644 --- a/src/lv2_plugin/RnNoiseLv2Plugin.h +++ b/src/lv2_plugin/RnNoiseLv2Plugin.h @@ -1,7 +1,7 @@ #pragma once #include -#include "lv2/lv2plug.in/ns/lv2core/Plugin.hpp" +#include "lv2core/Plugin.hpp" class RnNoiseCommonPlugin; diff --git a/src/lv2_plugin/lv2/lv2plug.in/ns/lv2core/Lib.hpp b/src/lv2_plugin/lv2core/Lib.hpp similarity index 98% rename from src/lv2_plugin/lv2/lv2plug.in/ns/lv2core/Lib.hpp rename to src/lv2_plugin/lv2core/Lib.hpp index ddf31d27..3e4e6db4 100644 --- a/src/lv2_plugin/lv2/lv2plug.in/ns/lv2core/Lib.hpp +++ b/src/lv2_plugin/lv2core/Lib.hpp @@ -17,7 +17,7 @@ #ifndef LV2_LIB_HPP #define LV2_LIB_HPP -#include "lv2/lv2plug.in/ns/lv2core/Plugin.hpp" +#include "lv2core/Plugin.hpp" namespace lv2 { diff --git a/src/lv2_plugin/lv2/lv2plug.in/ns/lv2core/Plugin.hpp b/src/lv2_plugin/lv2core/Plugin.hpp similarity index 99% rename from src/lv2_plugin/lv2/lv2plug.in/ns/lv2core/Plugin.hpp rename to src/lv2_plugin/lv2core/Plugin.hpp index caf8b911..8fe63c42 100644 --- a/src/lv2_plugin/lv2/lv2plug.in/ns/lv2core/Plugin.hpp +++ b/src/lv2_plugin/lv2core/Plugin.hpp @@ -17,7 +17,7 @@ #ifndef LV2_PLUGIN_HPP #define LV2_PLUGIN_HPP -#include "lv2/lv2plug.in/ns/lv2core/lv2.h" +#include "lv2core/lv2.h" namespace lv2 { diff --git a/src/lv2_plugin/lv2/lv2plug.in/ns/lv2core/lv2.h b/src/lv2_plugin/lv2core/lv2.h similarity index 100% rename from src/lv2_plugin/lv2/lv2plug.in/ns/lv2core/lv2.h rename to src/lv2_plugin/lv2core/lv2.h diff --git a/src/lv2_plugin/lv2/lv2plug.in/ns/lv2core/lv2_util.h b/src/lv2_plugin/lv2core/lv2_util.h similarity index 98% rename from src/lv2_plugin/lv2/lv2plug.in/ns/lv2core/lv2_util.h rename to src/lv2_plugin/lv2core/lv2_util.h index 20cc72d1..3470dfb9 100644 --- a/src/lv2_plugin/lv2/lv2plug.in/ns/lv2core/lv2_util.h +++ b/src/lv2_plugin/lv2core/lv2_util.h @@ -23,7 +23,7 @@ #include #include -#include "lv2/lv2plug.in/ns/lv2core/lv2.h" +#include "lv2core/lv2.h" #ifdef __cplusplus extern "C" { diff --git a/src/rnnoise/CMakeLists.txt b/src/rnnoise/CMakeLists.txt index 4d9d938b..f4cd378c 100644 --- a/src/rnnoise/CMakeLists.txt +++ b/src/rnnoise/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 3.6) project(RnNoise LANGUAGES C) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + set(RN_NOISE_SRC include/rnnoise/_kiss_fft_guts.h include/rnnoise/arch.h diff --git a/src/vst_plugin/CMakeLists.txt b/src/vst_plugin/CMakeLists.txt index 0fcf8a6a..ee10bf8a 100644 --- a/src/vst_plugin/CMakeLists.txt +++ b/src/vst_plugin/CMakeLists.txt @@ -3,7 +3,9 @@ project(rnnoise_vst2_plugin) set(CMAKE_CXX_STANDARD 14) -include_directories(/) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) set(PROJECT_ROOT ../../../) @@ -40,7 +42,7 @@ function(build bit) target_compile_options(${VST2_TARGET_X${bit}} PRIVATE ${X${bit}_COMPILE_OPTIONS}) set_target_properties(${VST2_TARGET_X${bit}} PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${PROJECT_ROOT}/bin/x${bit}/vst") + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_ROOT}/bin/x${bit}/vst") endfunction() build(32)