Fix scvim regsitry file for updated filename (thanks Carlo Capocasa)
[supercollider.git] / server / supernova / sc / sc_ugen_factory.cpp
blobc638511af7734459acaf480bddaf62cbced2c0b3
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.
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.
19 /* \todo for now we use dlopen, later we want to become cross-platform
22 #ifdef DLOPEN
23 #include <dlfcn.h>
24 #endif
26 #include <boost/filesystem.hpp>
28 #include "sc_ugen_factory.hpp"
30 #include "SC_World.h"
31 #include "SC_Wire.h"
33 namespace nova {
35 sc_ugen_factory * sc_factory;
37 Unit * sc_ugen_def::construct(sc_synthdef::unit_spec_t const & unit_spec, sc_synth * s, World * world, linear_allocator & allocator)
39 const int buffer_length = world->mBufLength;
41 const size_t output_count = unit_spec.output_specs.size();
43 /* size for wires and buffers */
44 Unit * unit = (Unit*)allocator.alloc<uint8_t>(alloc_size);
45 memset(unit, 0, alloc_size);
46 unit->mInBuf = allocator.alloc<float*>(unit_spec.input_specs.size());
47 unit->mOutBuf = allocator.alloc<float*>(unit_spec.output_specs.size());
48 unit->mInput = allocator.alloc<Wire*>(unit_spec.input_specs.size());
49 unit->mOutput = allocator.alloc<Wire*>(unit_spec.output_specs.size());
51 unit->mNumInputs = unit_spec.input_specs.size();
52 unit->mNumOutputs = unit_spec.output_specs.size();
54 /* initialize members */
55 unit->mCalcRate = unit_spec.rate;
56 unit->mSpecialIndex = unit_spec.special_index;
57 unit->mDone = false;
58 unit->mUnitDef = reinterpret_cast<struct UnitDef*>(this); /* we abuse this field to store our reference */
59 unit->mWorld = world;
61 /* initialize members from synth */
62 unit->mParent = static_cast<Graph*>(s);
63 if (unit_spec.rate == 2)
64 unit->mRate = &world->mFullRate;
65 else
66 unit->mRate = &world->mBufRate;
68 unit->mBufLength = unit->mRate->mBufLength;
70 float * buffer_base = s->unit_buffers;
72 /* allocate buffers */
73 for (size_t i = 0; i != output_count; ++i) {
74 Wire * w = allocator.alloc<Wire>();
76 w->mFromUnit = unit;
77 w->mCalcRate = unit->mCalcRate;
79 w->mBuffer = 0;
80 w->mScalarValue = 0;
82 if (unit->mCalcRate == 2) {
83 /* allocate a new buffer */
84 assert(unit_spec.buffer_mapping[i] >= 0);
85 std::size_t buffer_id = unit_spec.buffer_mapping[i];
86 unit->mOutBuf[i] = buffer_base + buffer_length * buffer_id;
87 w->mBuffer = unit->mOutBuf[i];
89 else
90 unit->mOutBuf[i] = &w->mScalarValue;
92 unit->mOutput[i] = w;
95 /* prepare inputs */
96 for (size_t i = 0; i != unit_spec.input_specs.size(); ++i)
98 int source = unit_spec.input_specs[i].source;
99 int index = unit_spec.input_specs[i].index;
101 if (source == -1)
102 unit->mInput[i] = &unit->mParent->mWire[index];
103 else
105 Unit * prev = s->units[source];
106 unit->mInput[i] = prev->mOutput[index];
109 if (unit->mInput[i]->mCalcRate == 2)
110 unit->mInBuf[i] = unit->mInput[i]->mBuffer;
111 else
112 unit->mInBuf[i] = &unit->mInput[i]->mScalarValue;
115 return unit;
118 bool sc_ugen_def::add_command(const char* cmd_name, UnitCmdFunc func)
120 sc_unitcmd_def * def = new sc_unitcmd_def(cmd_name, func);
121 unitcmd_set.insert(*def);
122 return true;
125 void sc_ugen_def::run_unit_command(const char * cmd_name, Unit * unit, struct sc_msg_iter *args)
127 unitcmd_set_type::iterator it = unitcmd_set.find(cmd_name, named_hash_hash(), named_hash_equal());
129 if (it != unitcmd_set.end())
130 it->run(unit, args);
133 sample * sc_bufgen_def::run(World * world, uint32_t buffer_index, struct sc_msg_iter *args)
135 SndBuf * buf = World_GetNRTBuf(world, buffer_index);
136 sample * data = buf->data;
138 (func)(world, buf, args);
140 if (data == buf->data)
141 return NULL;
142 else
143 return data;
146 void sc_plugin_container::register_ugen(const char *inUnitClassName, size_t inAllocSize,
147 UnitCtorFunc inCtor, UnitDtorFunc inDtor, uint32 inFlags)
149 sc_ugen_def * def = new sc_ugen_def(inUnitClassName, inAllocSize, inCtor, inDtor, inFlags);
150 ugen_set.insert(*def);
153 void sc_plugin_container::register_bufgen(const char * name, BufGenFunc func)
155 sc_bufgen_def * def = new sc_bufgen_def(name, func);
156 bufgen_set.insert(*def);
159 sc_ugen_def * sc_plugin_container::find_ugen(c_string const & name)
161 ugen_set_type::iterator it = ugen_set.find(name, named_hash_hash(), named_hash_equal());
162 if (it == ugen_set.end()) {
163 std::cerr << "ugen not registered: " << name.c_str() << std::endl;
164 return 0;
166 return &*it;
169 bool sc_plugin_container::register_ugen_command_function(const char * ugen_name, const char * cmd_name,
170 UnitCmdFunc func)
172 sc_ugen_def * def = find_ugen(c_string(ugen_name));
173 if (def)
174 return false;
175 return def->add_command(cmd_name, func);
178 bool sc_plugin_container::register_cmd_plugin(const char * cmd_name, PlugInCmdFunc func, void * user_data)
180 cmdplugin_set_type::iterator it = cmdplugin_set.find(cmd_name, named_hash_hash(), named_hash_equal());
181 if (it != cmdplugin_set.end()) {
182 std::cerr << "cmd plugin already registered: " << cmd_name << std::endl;
183 return false;
186 sc_cmdplugin_def * def = new sc_cmdplugin_def(cmd_name, func, user_data);
187 cmdplugin_set.insert(*def);
189 return true;
192 sample * sc_plugin_container::run_bufgen(World * world, const char * name, uint32_t buffer_index, struct sc_msg_iter *args)
194 bufgen_set_type::iterator it = bufgen_set.find(name, named_hash_hash(), named_hash_equal());
195 if (it == bufgen_set.end()) {
196 std::cerr << "unable to find buffer generator: " << name << std::endl;
197 return NULL;
200 return it->run(world, buffer_index, args);
204 bool sc_plugin_container::run_cmd_plugin(World * world, const char * name, struct sc_msg_iter *args, void *replyAddr)
206 cmdplugin_set_type::iterator it = cmdplugin_set.find(name, named_hash_hash(), named_hash_equal());
207 if (it == cmdplugin_set.end()) {
208 std::cerr << "unable to find cmd plugin: " << name << std::endl;
209 return false;
212 it->run(world, args, replyAddr);
214 return true;
218 void sc_ugen_factory::load_plugin_folder (boost::filesystem::path const & path)
220 using namespace boost::filesystem;
222 directory_iterator end;
224 if (!is_directory(path))
225 return;
227 for (directory_iterator it(path); it != end; ++it) {
228 if (is_regular_file(it->status()))
229 load_plugin(it->path());
233 #ifdef DLOPEN
234 void sc_ugen_factory::load_plugin ( boost::filesystem::path const & path )
236 using namespace std;
237 void * handle = dlopen(path.string().c_str(), RTLD_NOW | RTLD_LOCAL);
238 if (handle == NULL) {
239 cerr << "Cannot open plugin: " << dlerror() << endl;
240 return;
243 typedef int (*info_function)();
245 info_function api_version = reinterpret_cast<info_function>(dlsym(handle, "api_version"));
246 int plugin_api_version = 1; // default
247 if (api_version)
248 plugin_api_version = (*api_version)();
250 if (plugin_api_version != sc_api_version) {
251 cerr << "API Version Mismatch: " << path << endl;
252 dlclose(handle);
253 return;
256 void * load_symbol = dlsym(handle, "load");
257 if (!load_symbol) {
258 dlclose(handle);
259 return;
262 open_handles.push_back(handle);
263 LoadPlugInFunc load_func = reinterpret_cast<LoadPlugInFunc>(load_symbol);
264 (*load_func)(&sc_interface);
266 /* don't close the handle */
267 return;
270 void sc_ugen_factory::close_handles(void)
272 #if 0
273 /* closing the handles has some unwanted side effects, so we leave them open */
274 foreach(void * handle, open_handles)
275 dlclose(handle);
276 #endif
279 #else
280 void sc_ugen_factory::load_plugin ( boost::filesystem::path const & path )
284 void sc_ugen_factory::close_handles(void)
286 #endif
288 } /* namespace nova */