bumping version to 3.5-rc1
[supercollider.git] / server / supernova / sc / sc_ugen_factory.cpp
blobb838e7c72afd95ec399693ff50496c237798e27f
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
36 sc_ugen_factory * sc_factory;
38 Unit * sc_ugen_def::construct(sc_synthdef::unit_spec_t const & unit_spec, sc_synth * s, World * world, char *& chunk)
40 const int buffer_length = world->mBufLength;
42 const size_t output_count = unit_spec.output_specs.size();
44 /* size for wires and buffers */
45 memset(chunk, 0, alloc_size);
46 Unit * unit = (Unit*)chunk; chunk += alloc_size;
47 unit->mInBuf = (float**)chunk; chunk += unit_spec.input_specs.size() * sizeof(float*);
48 unit->mOutBuf = (float**)chunk; chunk += unit_spec.output_specs.size() * sizeof(float*);
49 unit->mInput = (Wire**)chunk; chunk += unit_spec.input_specs.size() * sizeof(Wire*);
50 unit->mOutput = (Wire**)chunk; chunk += unit_spec.output_specs.size() * sizeof(Wire*);
52 unit->mNumInputs = unit_spec.input_specs.size();
53 unit->mNumOutputs = unit_spec.output_specs.size();
55 /* initialize members */
56 unit->mCalcRate = unit_spec.rate;
57 unit->mSpecialIndex = unit_spec.special_index;
58 unit->mDone = false;
59 unit->mUnitDef = reinterpret_cast<struct UnitDef*>(this); /* we abuse this field to store our reference */
60 unit->mWorld = world;
62 /* initialize members from synth */
63 unit->mParent = static_cast<Graph*>(s);
64 if (unit_spec.rate == 2)
65 unit->mRate = &world->mFullRate;
66 else
67 unit->mRate = &world->mBufRate;
69 unit->mBufLength = unit->mRate->mBufLength;
71 float * buffer_base = s->unit_buffers;
73 /* allocate buffers */
74 for (size_t i = 0; i != output_count; ++i) {
75 Wire * w = (Wire*)chunk; chunk += sizeof(Wire);
77 w->mFromUnit = unit;
78 w->mCalcRate = unit->mCalcRate;
80 w->mBuffer = 0;
81 w->mScalarValue = 0;
83 if (unit->mCalcRate == 2) {
84 /* allocate a new buffer */
85 assert(unit_spec.buffer_mapping[i] >= 0);
86 std::size_t buffer_id = unit_spec.buffer_mapping[i];
87 unit->mOutBuf[i] = buffer_base + buffer_length * buffer_id;
88 w->mBuffer = unit->mOutBuf[i];
90 else
91 unit->mOutBuf[i] = &w->mScalarValue;
93 unit->mOutput[i] = w;
96 /* prepare inputs */
97 for (size_t i = 0; i != unit_spec.input_specs.size(); ++i)
99 int source = unit_spec.input_specs[i].source;
100 int index = unit_spec.input_specs[i].index;
102 if (source == -1)
103 unit->mInput[i] = &unit->mParent->mWire[index];
104 else
106 Unit * prev = s->units[source];
107 unit->mInput[i] = prev->mOutput[index];
110 if (unit->mInput[i]->mCalcRate == 2)
111 unit->mInBuf[i] = unit->mInput[i]->mBuffer;
112 else
113 unit->mInBuf[i] = &unit->mInput[i]->mScalarValue;
116 return unit;
119 bool sc_ugen_def::add_command(const char* cmd_name, UnitCmdFunc func)
121 sc_unitcmd_def * def = new sc_unitcmd_def(cmd_name, func);
122 unitcmd_set.insert(*def);
123 return true;
126 void sc_ugen_def::run_unit_command(const char * cmd_name, Unit * unit, struct sc_msg_iter *args)
128 unitcmd_set_type::iterator it = unitcmd_set.find(cmd_name, named_hash_hash(), named_hash_equal());
130 if (it != unitcmd_set.end())
131 it->run(unit, args);
134 sample * sc_bufgen_def::run(World * world, uint32_t buffer_index, struct sc_msg_iter *args)
136 SndBuf * buf = World_GetNRTBuf(world, buffer_index);
137 sample * data = buf->data;
139 (func)(world, buf, args);
141 if (data == buf->data)
142 return NULL;
143 else
144 return data;
147 void sc_plugin_container::register_ugen(const char *inUnitClassName, size_t inAllocSize,
148 UnitCtorFunc inCtor, UnitDtorFunc inDtor, uint32 inFlags)
150 sc_ugen_def * def = new sc_ugen_def(inUnitClassName, inAllocSize, inCtor, inDtor, inFlags);
151 ugen_set.insert(*def);
154 void sc_plugin_container::register_bufgen(const char * name, BufGenFunc func)
156 sc_bufgen_def * def = new sc_bufgen_def(name, func);
157 bufgen_set.insert(*def);
160 sc_ugen_def * sc_plugin_container::find_ugen(c_string const & name)
162 ugen_set_type::iterator it = ugen_set.find(name, named_hash_hash(), named_hash_equal());
163 if (it == ugen_set.end()) {
164 std::cerr << "ugen not registered: " << name.c_str() << std::endl;
165 return 0;
167 return &*it;
170 bool sc_plugin_container::register_ugen_command_function(const char * ugen_name, const char * cmd_name,
171 UnitCmdFunc func)
173 sc_ugen_def * def = find_ugen(c_string(ugen_name));
174 if (def)
175 return false;
176 return def->add_command(cmd_name, func);
179 bool sc_plugin_container::register_cmd_plugin(const char * cmd_name, PlugInCmdFunc func, void * user_data)
181 cmdplugin_set_type::iterator it = cmdplugin_set.find(cmd_name, named_hash_hash(), named_hash_equal());
182 if (it != cmdplugin_set.end()) {
183 std::cerr << "cmd plugin already registered: " << cmd_name << std::endl;
184 return false;
187 sc_cmdplugin_def * def = new sc_cmdplugin_def(cmd_name, func, user_data);
188 cmdplugin_set.insert(*def);
190 return true;
193 sample * sc_plugin_container::run_bufgen(World * world, const char * name, uint32_t buffer_index, struct sc_msg_iter *args)
195 bufgen_set_type::iterator it = bufgen_set.find(name, named_hash_hash(), named_hash_equal());
196 if (it == bufgen_set.end()) {
197 std::cerr << "unable to find buffer generator: " << name << std::endl;
198 return NULL;
201 return it->run(world, buffer_index, args);
205 bool sc_plugin_container::run_cmd_plugin(World * world, const char * name, struct sc_msg_iter *args, void *replyAddr)
207 cmdplugin_set_type::iterator it = cmdplugin_set.find(name, named_hash_hash(), named_hash_equal());
208 if (it == cmdplugin_set.end()) {
209 std::cerr << "unable to find cmd plugin: " << name << std::endl;
210 return false;
213 it->run(world, args, replyAddr);
215 return true;
219 void sc_ugen_factory::load_plugin_folder (boost::filesystem::path const & path)
221 using namespace boost::filesystem;
223 directory_iterator end;
225 if (!is_directory(path))
226 return;
228 for (directory_iterator it(path); it != end; ++it) {
229 if (is_regular_file(it->status()))
230 load_plugin(it->path());
234 #ifdef DLOPEN
235 void sc_ugen_factory::load_plugin ( boost::filesystem::path const & path )
237 using namespace std;
238 void * handle = dlopen(path.string().c_str(), RTLD_NOW | RTLD_LOCAL);
239 if (handle == NULL) {
240 cerr << "Cannot open plugin: " << dlerror() << endl;
241 return;
244 typedef int (*info_function)();
246 info_function api_version = reinterpret_cast<info_function>(dlsym(handle, "api_version"));
247 if (api_version) {
248 if ((*api_version)() != sc_api_version) {
249 cerr << "API Version Mismatch: " << path << endl;
250 dlclose(handle);
251 return;
255 void * load_symbol = dlsym(handle, "load");
256 if (!load_symbol) {
257 dlclose(handle);
258 return;
261 open_handles.push_back(handle);
262 LoadPlugInFunc load_func = reinterpret_cast<LoadPlugInFunc>(load_symbol);
263 (*load_func)(&sc_interface);
265 /* don't close the handle */
266 return;
269 void sc_ugen_factory::close_handles(void)
271 #if 0
272 /* closing the handles has some unwanted side effects, so we leave them open */
273 foreach(void * handle, open_handles)
274 dlclose(handle);
275 #endif
278 #else
279 void sc_ugen_factory::load_plugin ( boost::filesystem::path const & path )
283 void sc_ugen_factory::close_handles(void)
285 #endif
287 } /* namespace nova */