1 // prototype of a supercollider-synthdef-based synth prototype 2 // Copyright (C) 2009 Tim Blechmann 3 // 4 // This program is free software; you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation; either version 2 of the License, or 7 // (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; see the file COPYING. If not, write to 16 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 // Boston, MA 02111-1307, USA. 18 19 #pragma once 20 21 #include <boost/intrusive/set.hpp> 22 #include <boost/intrusive/unordered_set.hpp> 23 #include <boost/checked_delete.hpp> 24 25 #include "sc_synthdef.hpp" 26 #include "sc_synth.hpp" 27 #include "sc_plugin_interface.hpp" 28 29 #include "SC_InterfaceTable.h" 30 #include "SC_Unit.h" 31 32 #include "utilities/named_hash_entry.hpp" 33 34 namespace nova { 35 namespace bi = boost::intrusive; 36 37 struct sc_unitcmd_def : public named_hash_entry { 38 const UnitCmdFunc func; 39 sc_unitcmd_defnova::sc_unitcmd_def40 sc_unitcmd_def(const char* cmd_name, UnitCmdFunc func): named_hash_entry(cmd_name), func(func) {} 41 runnova::sc_unitcmd_def42 void run(Unit* unit, struct sc_msg_iter* args) { (func)(unit, args); } 43 }; 44 45 class sc_ugen_def : public aligned_class, public named_hash_entry { 46 private: 47 const size_t alloc_size; 48 const UnitCtorFunc ctor; 49 const UnitDtorFunc dtor; 50 const uint32_t flags; 51 52 static const std::size_t unitcmd_set_bucket_count = 4; 53 typedef bi::unordered_set<sc_unitcmd_def, bi::constant_time_size<false>, bi::power_2_buckets<true>, 54 bi::store_hash<true>> 55 unitcmd_set_type; 56 57 unitcmd_set_type::bucket_type unitcmd_set_buckets[unitcmd_set_bucket_count]; 58 unitcmd_set_type unitcmd_set; 59 60 public: sc_ugen_def(const char * inUnitClassName,size_t inAllocSize,UnitCtorFunc inCtor,UnitDtorFunc inDtor,uint32 inFlags)61 sc_ugen_def(const char* inUnitClassName, size_t inAllocSize, UnitCtorFunc inCtor, UnitDtorFunc inDtor, 62 uint32 inFlags): 63 named_hash_entry(inUnitClassName), 64 alloc_size(inAllocSize), 65 ctor(inCtor), 66 dtor(inDtor), 67 flags(inFlags), 68 unitcmd_set(unitcmd_set_type::bucket_traits(unitcmd_set_buckets, unitcmd_set_bucket_count)) {} 69 70 Unit* construct(sc_synthdef::unit_spec_t const& unit_spec, sc_synth* parent, int parentIndex, World* world, 71 linear_allocator& allocator); 72 initialize(Unit * unit)73 void initialize(Unit* unit) { (*ctor)(unit); } 74 destruct(Unit * unit)75 void destruct(Unit* unit) { 76 if (dtor) 77 (*dtor)(unit); 78 } 79 cant_alias(void) const80 bool cant_alias(void) const { return flags & kUnitDef_CantAliasInputsToOutputs; } 81 memory_requirement(void) const82 std::size_t memory_requirement(void) const { 83 return alloc_size + 64; // overallocate to allow alignment 84 } 85 86 bool add_command(const char* cmd_name, UnitCmdFunc func); 87 void run_unit_command(const char* cmd_name, Unit* unit, struct sc_msg_iter* args); 88 }; 89 90 struct sc_bufgen_def : public named_hash_entry { 91 const BufGenFunc func; 92 sc_bufgen_defnova::sc_bufgen_def93 sc_bufgen_def(const char* name, BufGenFunc func): named_hash_entry(name), func(func) {} 94 95 sample* run(World* world, uint32_t buffer_index, struct sc_msg_iter* args); 96 }; 97 98 struct sc_cmdplugin_def : public named_hash_entry { 99 const PlugInCmdFunc func; 100 void* user_data; 101 sc_cmdplugin_defnova::sc_cmdplugin_def102 sc_cmdplugin_def(const char* name, PlugInCmdFunc func, void* user_data): 103 named_hash_entry(name), 104 func(func), 105 user_data(user_data) {} 106 runnova::sc_cmdplugin_def107 void run(World* world, struct sc_msg_iter* args, void* replyAddr) { (func)(world, user_data, args, replyAddr); } 108 }; 109 110 class sc_plugin_container { 111 static const std::size_t ugen_set_bucket_count = 512; 112 typedef bi::unordered_set<sc_ugen_def, bi::constant_time_size<false>, bi::power_2_buckets<true>, 113 bi::store_hash<true>> 114 ugen_set_type; 115 116 static const std::size_t bufgen_set_bucket_count = 64; 117 typedef bi::unordered_set<sc_bufgen_def, bi::constant_time_size<false>, bi::power_2_buckets<true>, 118 bi::store_hash<true>> 119 bufgen_set_type; 120 121 static const std::size_t cmdplugin_set_bucket_count = 8; 122 typedef bi::unordered_set<sc_cmdplugin_def, bi::constant_time_size<false>, bi::power_2_buckets<true>, 123 bi::store_hash<true>> 124 cmdplugin_set_type; 125 126 ugen_set_type::bucket_type ugen_set_buckets[ugen_set_bucket_count]; 127 ugen_set_type ugen_set; 128 129 bufgen_set_type::bucket_type bufgen_set_buckets[bufgen_set_bucket_count]; 130 bufgen_set_type bufgen_set; 131 132 cmdplugin_set_type::bucket_type cmdplugin_set_buckets[cmdplugin_set_bucket_count]; 133 cmdplugin_set_type cmdplugin_set; 134 135 protected: sc_plugin_container(void)136 sc_plugin_container(void): 137 ugen_set(ugen_set_type::bucket_traits(ugen_set_buckets, ugen_set_bucket_count)), 138 bufgen_set(bufgen_set_type::bucket_traits(bufgen_set_buckets, bufgen_set_bucket_count)), 139 cmdplugin_set(cmdplugin_set_type::bucket_traits(cmdplugin_set_buckets, cmdplugin_set_bucket_count)) {} 140 ~sc_plugin_container(void)141 ~sc_plugin_container(void) { 142 ugen_set.clear_and_dispose(boost::checked_delete<sc_ugen_def>); 143 bufgen_set.clear_and_dispose(boost::checked_delete<sc_bufgen_def>); 144 cmdplugin_set.clear_and_dispose(boost::checked_delete<sc_cmdplugin_def>); 145 } 146 147 public: 148 void register_ugen(const char* inUnitClassName, size_t inAllocSize, UnitCtorFunc inCtor, UnitDtorFunc inDtor, 149 uint32 inFlags); 150 151 void register_bufgen(const char* name, BufGenFunc func); 152 153 sc_ugen_def* find_ugen(symbol const& name); 154 155 bool register_ugen_command_function(const char* ugen_name, const char* cmd_name, UnitCmdFunc); 156 bool register_cmd_plugin(const char* cmd_name, PlugInCmdFunc func, void* user_data); 157 158 sample* run_bufgen(World* world, const char* name, uint32_t buffer_index, struct sc_msg_iter* args); 159 bool run_cmd_plugin(World* world, const char* name, struct sc_msg_iter* args, void* replyAddr); 160 }; 161 162 /** factory class for supercollider ugens 163 * 164 * \todo do we need to take care of thread safety? */ 165 class sc_ugen_factory : public sc_plugin_interface, public sc_plugin_container { 166 public: 167 sc_ugen_factory() = default; 168 ~sc_ugen_factory(void)169 ~sc_ugen_factory(void) { close_handles(); } 170 171 /* @{ */ 172 /** ugen count handling */ allocate_ugens(uint32_t count)173 void allocate_ugens(uint32_t count) { ugen_count_ += count; } 174 free_ugens(uint32_t count)175 void free_ugens(uint32_t count) { ugen_count_ -= count; } 176 ugen_count(void) const177 uint32_t ugen_count(void) const { return ugen_count_; } 178 /* @} */ 179 180 void load_plugin_folder(boost::filesystem::path const& path); 181 void load_plugin(boost::filesystem::path const& path); 182 183 private: 184 void close_handles(void); 185 186 uint32_t ugen_count_ = 0; 187 std::vector<void*> open_handles; 188 }; 189 190 extern std::unique_ptr<sc_ugen_factory> sc_factory; 191 192 } /* namespace nova */ 193