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"
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
;
58 unit
->mUnitDef
= reinterpret_cast<struct UnitDef
*>(this); /* we abuse this field to store our reference */
61 /* initialize members from synth */
62 unit
->mParent
= static_cast<Graph
*>(s
);
63 if (unit_spec
.rate
== 2)
64 unit
->mRate
= &world
->mFullRate
;
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
>();
77 w
->mCalcRate
= unit
->mCalcRate
;
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
];
90 unit
->mOutBuf
[i
] = &w
->mScalarValue
;
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
;
102 unit
->mInput
[i
] = &unit
->mParent
->mWire
[index
];
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
;
112 unit
->mInBuf
[i
] = &unit
->mInput
[i
]->mScalarValue
;
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
);
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())
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
)
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
;
169 bool sc_plugin_container::register_ugen_command_function(const char * ugen_name
, const char * cmd_name
,
172 sc_ugen_def
* def
= find_ugen(c_string(ugen_name
));
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
;
186 sc_cmdplugin_def
* def
= new sc_cmdplugin_def(cmd_name
, func
, user_data
);
187 cmdplugin_set
.insert(*def
);
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
;
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
;
212 it
->run(world
, args
, replyAddr
);
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
))
227 for (directory_iterator
it(path
); it
!= end
; ++it
) {
228 if (is_regular_file(it
->status()))
229 load_plugin(it
->path());
234 void sc_ugen_factory::load_plugin ( boost::filesystem::path
const & path
)
237 void * handle
= dlopen(path
.string().c_str(), RTLD_NOW
| RTLD_LOCAL
);
238 if (handle
== NULL
) {
239 cerr
<< "Cannot open plugin: " << dlerror() << endl
;
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
248 plugin_api_version
= (*api_version
)();
250 if (plugin_api_version
!= sc_api_version
) {
251 cerr
<< "API Version Mismatch: " << path
<< endl
;
256 void * load_symbol
= dlsym(handle
, "load");
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 */
270 void sc_ugen_factory::close_handles(void)
273 /* closing the handles has some unwanted side effects, so we leave them open */
274 foreach(void * handle
, open_handles
)
280 void sc_ugen_factory::load_plugin ( boost::filesystem::path
const & path
)
284 void sc_ugen_factory::close_handles(void)
288 } /* namespace nova */