1 // prototype of a supercollider-synthdef-based synth prototype
2 // Copyright (C) 2009 Tim Blechmann
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.
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
26 #include <boost/filesystem.hpp>
28 #include "sc_ugen_factory.hpp"
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
;
59 unit
->mUnitDef
= reinterpret_cast<struct UnitDef
*>(this); /* we abuse this field to store our reference */
62 /* initialize members from synth */
63 unit
->mParent
= static_cast<Graph
*>(s
);
64 if (unit_spec
.rate
== 2)
65 unit
->mRate
= &world
->mFullRate
;
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
);
78 w
->mCalcRate
= unit
->mCalcRate
;
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
];
91 unit
->mOutBuf
[i
] = &w
->mScalarValue
;
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
;
103 unit
->mInput
[i
] = &unit
->mParent
->mWire
[index
];
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
;
113 unit
->mInBuf
[i
] = &unit
->mInput
[i
]->mScalarValue
;
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
);
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())
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
)
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
;
170 bool sc_plugin_container::register_ugen_command_function(const char * ugen_name
, const char * cmd_name
,
173 sc_ugen_def
* def
= find_ugen(c_string(ugen_name
));
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
;
187 sc_cmdplugin_def
* def
= new sc_cmdplugin_def(cmd_name
, func
, user_data
);
188 cmdplugin_set
.insert(*def
);
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
;
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
;
213 it
->run(world
, args
, replyAddr
);
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
))
228 for (directory_iterator
it(path
); it
!= end
; ++it
) {
229 if (is_regular_file(it
->status()))
230 load_plugin(it
->path());
235 void sc_ugen_factory::load_plugin ( boost::filesystem::path
const & path
)
238 void * handle
= dlopen(path
.string().c_str(), RTLD_NOW
| RTLD_LOCAL
);
239 if (handle
== NULL
) {
240 cerr
<< "Cannot open plugin: " << dlerror() << endl
;
244 typedef int (*info_function
)();
246 info_function api_version
= reinterpret_cast<info_function
>(dlsym(handle
, "api_version"));
248 if ((*api_version
)() != sc_api_version
) {
249 cerr
<< "API Version Mismatch: " << path
<< endl
;
255 void * load_symbol
= dlsym(handle
, "load");
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 */
269 void sc_ugen_factory::close_handles(void)
272 /* closing the handles has some unwanted side effects, so we leave them open */
273 foreach(void * handle
, open_handles
)
279 void sc_ugen_factory::load_plugin ( boost::filesystem::path
const & path
)
283 void sc_ugen_factory::close_handles(void)
287 } /* namespace nova */