1 // interface for supercollider plugins
2 // Copyright (C) 2009, 2010 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 #include <cstdarg>
20 #include <random>
21
22 #include "SC_SndFileHelpers.hpp"
23
24 #include "sc_plugin_interface.hpp"
25 #include "sc_ugen_factory.hpp"
26 #include "sc_synth.hpp"
27
28 #include "nova-simd/simd_memory.hpp"
29
30 #include "../server/server_args.hpp"
31 #include "../server/memory_pool.hpp"
32 #include "../server/server.hpp"
33 #include "malloc_aligned.hpp"
34 #include "../utilities/sized_array.hpp"
35
36 #include "SC_Prototypes.h"
37 #include "SC_Unit.h"
38 #include "SC_Lock.h"
39 #include "clz.h"
40 #include "SC_fftlib.h"
41 #include "SC_Lock.h"
42 #include "../../common/Samp.hpp"
43 #include "../../common/SC_SndFileHelpers.hpp"
44
45 #include <boost/math/constants/constants.hpp>
46
47 // undefine the shadowed scfft functions
48 #undef scfft_create
49 #undef scfft_dofft
50 #undef scfft_doifft
51 #undef scfft_destroy
52
53 namespace nova {
54
55 spin_lock log_guard; // needs to be acquired for logging from the helper threads!
56
57 namespace {
58
59 spin_lock rt_pool_guard;
60
as_Node(server_node * node)61 inline Node* as_Node(server_node* node) {
62 if (node == nullptr)
63 return nullptr;
64
65 // hack!!! we only assume that the 32bit integer mID member can be accessed via Node
66 if (node->is_synth()) {
67 sc_synth* s = static_cast<sc_synth*>(node);
68 return &s->mNode;
69 } else {
70 void* nodePointer = &node->node_id;
71 return (Node*)nodePointer;
72 }
73 }
74
pause_node(Unit * unit)75 void pause_node(Unit* unit) {
76 server_node* node = static_cast<sc_synth*>(unit->mParent);
77 sc_factory->add_pause_node(node);
78 }
79
free_node(Unit * unit)80 void free_node(Unit* unit) {
81 server_node* node = static_cast<sc_synth*>(unit->mParent);
82 sc_factory->add_done_node(node);
83 }
84
free_node_and_preceding(Unit * unit)85 void free_node_and_preceding(Unit* unit) {
86 server_node* node = static_cast<sc_synth*>(unit->mParent);
87 sc_factory->add_done_node(node);
88
89 if (node->get_parent()->is_parallel()) {
90 spin_lock::scoped_lock lock(log_guard);
91 log("parallel groups have no notion of preceding nodes\n");
92 return;
93 }
94
95 server_node* preceding = node->previous_node();
96 if (preceding)
97 sc_factory->add_done_node(preceding);
98 }
99
free_node_and_pause_preceding(Unit * unit)100 void free_node_and_pause_preceding(Unit* unit) {
101 server_node* node = static_cast<sc_synth*>(unit->mParent);
102 sc_factory->add_done_node(node);
103
104 if (node->get_parent()->is_parallel()) {
105 spin_lock::scoped_lock lock(log_guard);
106 log("parallel groups have no notion of preceding nodes\n");
107 return;
108 }
109
110 server_node* preceding = node->previous_node();
111 if (preceding)
112 sc_factory->add_pause_node(preceding);
113 }
114
free_node_and_preceding_children(Unit * unit)115 void free_node_and_preceding_children(Unit* unit) {
116 server_node* node = static_cast<sc_synth*>(unit->mParent);
117 sc_factory->add_done_node(node);
118
119 if (node->get_parent()->is_parallel()) {
120 spin_lock::scoped_lock lock(log_guard);
121 log("parallel groups have no notion of preceding nodes");
122 return;
123 }
124
125 server_node* preceding = node->previous_node();
126 if (!preceding)
127 return;
128 if (preceding->is_synth())
129 sc_factory->add_done_node(preceding);
130 else {
131 abstract_group* preceding_group = static_cast<abstract_group*>(preceding);
132 sc_factory->add_freeAll_node(preceding_group);
133 }
134 }
135
136
free_node_and_preceding_deep(Unit * unit)137 void free_node_and_preceding_deep(Unit* unit) {
138 server_node* node = static_cast<sc_synth*>(unit->mParent);
139 sc_factory->add_done_node(node);
140
141 if (node->get_parent()->is_parallel()) {
142 log("parallel groups have no notion of preceding nodes\n");
143 return;
144 }
145
146 server_node* preceding = node->previous_node();
147 if (!preceding)
148 return;
149 if (preceding->is_synth())
150 sc_factory->add_done_node(preceding);
151 else {
152 abstract_group* preceding_group = static_cast<abstract_group*>(preceding);
153 sc_factory->add_freeDeep_node(preceding_group);
154 }
155 }
156
free_node_and_all_preceding(Unit * unit)157 void free_node_and_all_preceding(Unit* unit) {
158 server_node* node = static_cast<sc_synth*>(unit->mParent);
159 sc_factory->add_done_node(node);
160
161 if (node->get_parent()->is_parallel()) {
162 spin_lock::scoped_lock lock(log_guard);
163 log("parallel groups have no notion of preceding nodes\n");
164 return;
165 }
166
167 for (;;) {
168 node = node->previous_node();
169 if (node)
170 sc_factory->add_done_node(node);
171 else
172 return;
173 }
174 }
175
free_node_and_following(Unit * unit)176 void free_node_and_following(Unit* unit) {
177 server_node* node = static_cast<sc_synth*>(unit->mParent);
178 sc_factory->add_done_node(node);
179
180 if (node->get_parent()->is_parallel()) {
181 spin_lock::scoped_lock lock(log_guard);
182 log("parallel groups have no notion of following nodes\n");
183 return;
184 }
185
186 server_node* next = node->next_node();
187 if (next)
188 sc_factory->add_done_node(next);
189 }
190
free_node_and_pause_following(Unit * unit)191 void free_node_and_pause_following(Unit* unit) {
192 server_node* node = static_cast<sc_synth*>(unit->mParent);
193 sc_factory->add_done_node(node);
194
195 if (node->get_parent()->is_parallel()) {
196 spin_lock::scoped_lock lock(log_guard);
197 log("parallel groups have no notion of following nodes\n");
198 return;
199 }
200
201 server_node* next = node->next_node();
202 if (next)
203 sc_factory->add_pause_node(next);
204 }
205
free_node_and_resume_following(Unit * unit)206 void free_node_and_resume_following(Unit* unit) {
207 server_node* node = static_cast<sc_synth*>(unit->mParent);
208 sc_factory->add_done_node(node);
209
210 if (node->get_parent()->is_parallel()) {
211 spin_lock::scoped_lock lock(log_guard);
212 log("parallel groups have no notion of following nodes\n");
213 return;
214 }
215
216 server_node* next = node->next_node();
217 if (next)
218 sc_factory->add_resume_node(next);
219 }
220
free_node_and_following_children(Unit * unit)221 void free_node_and_following_children(Unit* unit) {
222 server_node* node = static_cast<sc_synth*>(unit->mParent);
223 sc_factory->add_done_node(node);
224
225 if (node->get_parent()->is_parallel()) {
226 spin_lock::scoped_lock lock(log_guard);
227 log("parallel groups have no notion of following nodes\n");
228 return;
229 }
230
231 server_node* following = node->previous_node();
232 if (!following)
233 return;
234 if (following->is_synth())
235 sc_factory->add_done_node(following);
236 else {
237 abstract_group* following_group = static_cast<abstract_group*>(following);
238 sc_factory->add_freeAll_node(following_group);
239 }
240 }
241
free_node_and_following_deep(Unit * unit)242 void free_node_and_following_deep(Unit* unit) {
243 server_node* node = static_cast<sc_synth*>(unit->mParent);
244 sc_factory->add_done_node(node);
245
246 if (node->get_parent()->is_parallel()) {
247 spin_lock::scoped_lock lock(log_guard);
248 log("parallel groups have no notion of following nodes\n");
249 return;
250 }
251
252 server_node* following = node->previous_node();
253 if (!following)
254 return;
255 if (following->is_synth())
256 sc_factory->add_done_node(following);
257 else {
258 abstract_group* following_group = static_cast<abstract_group*>(following);
259 sc_factory->add_freeDeep_node(following_group);
260 }
261 }
262
free_node_and_all_following(Unit * unit)263 void free_node_and_all_following(Unit* unit) {
264 server_node* node = static_cast<sc_synth*>(unit->mParent);
265 sc_factory->add_done_node(node);
266
267 if (node->get_parent()->is_parallel()) {
268 spin_lock::scoped_lock lock(log_guard);
269 log("parallel groups have no notion of following nodes\n");
270 return;
271 }
272
273 for (;;) {
274 node = node->previous_node();
275 if (node)
276 sc_factory->add_done_node(node);
277 else
278 return;
279 }
280 }
281
free_group_members(Unit * unit)282 void free_group_members(Unit* unit) {
283 server_node* node = static_cast<sc_synth*>(unit->mParent);
284 abstract_group* group = const_cast<abstract_group*>(node->get_parent());
285
286 sc_factory->add_freeAll_node(group);
287 }
288
free_parent_group(Unit * unit)289 void free_parent_group(Unit* unit) {
290 server_node* node = static_cast<sc_synth*>(unit->mParent);
291 abstract_group* group = const_cast<abstract_group*>(node->get_parent());
292 sc_factory->add_done_node(group);
293 }
294
get_scope_buffer(World * inWorld,int index,int channels,int maxFrames,ScopeBufferHnd & hnd)295 bool get_scope_buffer(World* inWorld, int index, int channels, int maxFrames, ScopeBufferHnd& hnd) {
296 scope_buffer_writer writer = instance->get_scope_buffer_writer(index, channels, maxFrames);
297
298 if (writer.valid()) {
299 hnd.internalData = writer.buffer;
300 hnd.data = writer.data();
301 hnd.channels = channels;
302 hnd.maxFrames = maxFrames;
303 return true;
304 } else {
305 hnd.internalData = nullptr;
306 return false;
307 }
308 }
309
push_scope_buffer(World * inWorld,ScopeBufferHnd & hnd,int frames)310 void push_scope_buffer(World* inWorld, ScopeBufferHnd& hnd, int frames) {
311 scope_buffer_writer writer(reinterpret_cast<scope_buffer*>(hnd.internalData));
312 writer.push(frames);
313 hnd.data = writer.data();
314 }
315
release_scope_buffer(World * inWorld,ScopeBufferHnd & hnd)316 void release_scope_buffer(World* inWorld, ScopeBufferHnd& hnd) {
317 scope_buffer_writer writer(reinterpret_cast<scope_buffer*>(hnd.internalData));
318 instance->release_scope_buffer_writer(writer);
319 }
320
321 } /* namespace */
322 } /* namespace nova */
323
324 extern "C" {
325
define_unit(const char * inUnitClassName,size_t inAllocSize,UnitCtorFunc inCtor,UnitDtorFunc inDtor,uint32 inFlags)326 bool define_unit(const char* inUnitClassName, size_t inAllocSize, UnitCtorFunc inCtor, UnitDtorFunc inDtor,
327 uint32 inFlags) {
328 try {
329 nova::sc_factory->register_ugen(inUnitClassName, inAllocSize, inCtor, inDtor, inFlags);
330 return true;
331 } catch (...) {
332 return false;
333 }
334 }
335
define_bufgen(const char * name,BufGenFunc func)336 bool define_bufgen(const char* name, BufGenFunc func) {
337 try {
338 nova::sc_factory->register_bufgen(name, func);
339 return true;
340 } catch (...) {
341 return false;
342 }
343 }
344
define_unitcmd(const char * unitClassName,const char * cmdName,UnitCmdFunc inFunc)345 bool define_unitcmd(const char* unitClassName, const char* cmdName, UnitCmdFunc inFunc) {
346 return nova::sc_factory->register_ugen_command_function(unitClassName, cmdName, inFunc);
347 }
348
define_plugincmd(const char * name,PlugInCmdFunc func,void * user_data)349 bool define_plugincmd(const char* name, PlugInCmdFunc func, void* user_data) {
350 return nova::sc_factory->register_cmd_plugin(name, func, user_data);
351 }
352
rt_alloc(World * dummy,size_t size)353 void* rt_alloc(World* dummy, size_t size) {
354 nova::spin_lock::scoped_lock lock(nova::rt_pool_guard);
355 if (size)
356 return nova::rt_pool.malloc(size);
357 else
358 return nullptr;
359 }
360
rt_realloc(World * dummy,void * ptr,size_t size)361 void* rt_realloc(World* dummy, void* ptr, size_t size) {
362 nova::spin_lock::scoped_lock lock(nova::rt_pool_guard);
363 return nova::rt_pool.realloc(ptr, size);
364 }
365
rt_free(World * dummy,void * ptr)366 void rt_free(World* dummy, void* ptr) {
367 nova::spin_lock::scoped_lock lock(nova::rt_pool_guard);
368 if (ptr)
369 nova::rt_pool.free(ptr);
370 }
371
nrt_alloc(size_t size)372 void* nrt_alloc(size_t size) { return malloc(size); }
373
nrt_realloc(void * ptr,size_t size)374 void* nrt_realloc(void* ptr, size_t size) { return realloc(ptr, size); }
375
nrt_free(void * ptr)376 void nrt_free(void* ptr) { free(ptr); }
377
nrt_alloc_2(World * dummy,size_t size)378 void* nrt_alloc_2(World* dummy, size_t size) { return malloc(size); }
379
nrt_realloc_2(World * dummy,void * ptr,size_t size)380 void* nrt_realloc_2(World* dummy, void* ptr, size_t size) { return realloc(ptr, size); }
381
nrt_free_2(World * dummy,void * ptr)382 void nrt_free_2(World* dummy, void* ptr) { free(ptr); }
383
384
clear_outputs(Unit * unit,int samples)385 void clear_outputs(Unit* unit, int samples) {
386 const uint32_t outputs = unit->mNumOutputs;
387
388 if ((samples & 63) == 0) {
389 const uint32_t loops = samples / 64;
390
391 for (int i = 0; i != outputs; ++i) {
392 float* buffer = unit->mOutBuf[i];
393 for (int loop = 0; loop != loops; ++loop) {
394 nova::zerovec_simd<64>(buffer + loop * 64);
395 }
396 }
397 return;
398 }
399
400 if ((samples & 15) == 0) {
401 for (int i = 0; i != outputs; ++i)
402 nova::zerovec_simd(unit->mOutBuf[i], samples);
403 return;
404 }
405
406 for (int i = 0; i != outputs; ++i)
407 nova::zerovec(unit->mOutBuf[i], samples);
408 }
409
node_end(struct Node * node)410 void node_end(struct Node* node) {
411 nova::server_node* s = nova::instance->find_node(node->mID);
412 nova::sc_factory->add_done_node(s);
413 }
414
node_set_run(struct Node * node,int run)415 void node_set_run(struct Node* node, int run) {
416 using namespace nova;
417 server_node* s = instance->find_node(node->mID);
418
419 if (run == 0)
420 sc_factory->add_pause_node(s);
421 else
422 sc_factory->add_resume_node(s);
423 }
424
425
print(const char * fmt,...)426 int print(const char* fmt, ...) {
427 va_list vargs;
428 va_start(vargs, fmt);
429
430 nova::log_guard.lock();
431 bool status = nova::instance->log_printf(fmt, vargs);
432 nova::log_guard.unlock();
433
434 va_end(vargs);
435 return (status == true) ? 0 : -1;
436 }
437
438 /* todo: we need to implement most of the done actions */
done_action(int done_action,struct Unit * unit)439 void done_action(int done_action, struct Unit* unit) {
440 using namespace nova;
441 switch (done_action) {
442 case 0:
443 // do nothing when the UGen is finished
444 return;
445
446 case 1:
447 // pause the enclosing synth, but do not free it
448 nova::pause_node(unit);
449 return;
450 case 2:
451 // free the enclosing synth
452 nova::free_node(unit);
453 return;
454
455 case 3:
456 // free both this synth and the preceding node
457 nova::free_node_and_preceding(unit);
458 return;
459
460 case 4:
461 // free both this synth and the following node
462 nova::free_node_and_following(unit);
463 return;
464
465 case 5:
466 // free this synth; if the preceding node is a group then do g_freeAll on it, else free it
467 nova::free_node_and_preceding_children(unit);
468 return;
469
470 case 6:
471 nova::free_node_and_following_children(unit);
472 // free this synth; if the following node is a group then do g_freeAll on it, else free it
473 return;
474
475 case 7:
476 // free this synth and all preceding nodes in this group
477 nova::free_node_and_all_preceding(unit);
478 return;
479
480 case 8:
481 // free this synth and all following nodes in this group
482 nova::free_node_and_all_following(unit);
483 return;
484
485 case 9:
486 // free this synth and pause the preceding node
487 nova::free_node_and_pause_preceding(unit);
488 return;
489
490 case 10:
491 // free this synth and pause the following node
492 nova::free_node_and_pause_following(unit);
493 return;
494
495 case 11:
496 // free this synth and if the preceding node is a group then do g_deepFree on it, else free it
497 nova::free_node_and_preceding_deep(unit);
498 return;
499
500 case 12:
501 // free this synth and if the following node is a group then do g_deepFree on it, else free it
502 nova::free_node_and_following_deep(unit);
503 return;
504
505 case 13:
506 // free this synth and all other nodes in this group (before and after)
507 nova::free_group_members(unit);
508 return;
509
510 case 14:
511 // free the enclosing group and all nodes within it (including this synth)
512 nova::free_parent_group(unit);
513 return;
514
515 case 15:
516 // free this synth and resume the following node
517 nova::free_node_and_resume_following(unit);
518 return;
519
520 default:
521 return;
522 }
523 }
524
buf_alloc(SndBuf * buf,int channels,int frames,double samplerate)525 int buf_alloc(SndBuf* buf, int channels, int frames, double samplerate) {
526 try {
527 nova::sc_factory->allocate_buffer(buf, channels, frames, samplerate);
528 return kSCErr_None;
529 } catch (std::exception const& e) {
530 std::cout << e.what() << std::endl;
531 return kSCErr_Failed;
532 }
533 }
534
send_trigger(Node * unit,int trigger_id,float value)535 void send_trigger(Node* unit, int trigger_id, float value) {
536 nova::instance->send_trigger(unit->mID, trigger_id, value);
537 }
538
world_lock(World * world)539 void world_lock(World* world) { reinterpret_cast<SC_Lock*>(world->mNRTLock)->lock(); }
540
world_unlock(World * world)541 void world_unlock(World* world) { reinterpret_cast<SC_Lock*>(world->mNRTLock)->unlock(); }
542
get_node(World * world,int id)543 Node* get_node(World* world, int id) {
544 nova::server_node* node = nova::instance->find_node(id);
545 return nova::as_Node(node);
546 }
547
send_node_reply(Node * node,int reply_id,const char * command_name,int argument_count,const float * values)548 void send_node_reply(Node* node, int reply_id, const char* command_name, int argument_count, const float* values) {
549 if (!nova::sc_factory->world.mRealTime)
550 return;
551
552 nova::instance->send_node_reply(node->mID, reply_id, command_name, argument_count, values);
553 }
554
do_asynchronous_command(World * inWorld,void * replyAddr,const char * cmdName,void * cmdData,AsyncStageFn stage2,AsyncStageFn stage3,AsyncStageFn stage4,AsyncFreeFn cleanup,int completionMsgSize,void * completionMsgData)555 int do_asynchronous_command(
556 World* inWorld, void* replyAddr, const char* cmdName, void* cmdData,
557 AsyncStageFn stage2, // stage2 is non real time
558 AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true
559 AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true
560 AsyncFreeFn cleanup, int completionMsgSize, void* completionMsgData) {
561 nova::instance->do_asynchronous_command(inWorld, replyAddr, cmdName, cmdData, stage2, stage3, stage4, cleanup,
562 completionMsgSize, completionMsgData);
563 return 0;
564 }
565
send_message_from_RT(World * world,struct FifoMsg & msg)566 bool send_message_from_RT(World* world, struct FifoMsg& msg) {
567 nova::instance->send_message_from_RT(world, msg);
568 return true;
569 }
570
send_message_to_RT(World * world,struct FifoMsg & msg)571 bool send_message_to_RT(World* world, struct FifoMsg& msg) {
572 nova::instance->send_message_to_RT(world, msg);
573 return true;
574 }
575
576 } /* extern "C" */
577
578 namespace nova {
579
580
initialize_rate(Rate & rate,double sample_rate,int blocksize)581 inline void initialize_rate(Rate& rate, double sample_rate, int blocksize) {
582 rate.mSampleRate = sample_rate;
583 rate.mSampleDur = 1. / sample_rate;
584 rate.mRadiansPerSample = 2 * boost::math::constants::pi<double>() / sample_rate;
585
586 rate.mBufLength = blocksize;
587 rate.mBufDuration = blocksize / sample_rate;
588 rate.mBufRate = sample_rate / blocksize;
589 rate.mSlopeFactor = 1. / blocksize;
590
591 div_t div_result = std::div(blocksize, 3);
592 rate.mFilterLoops = div_result.quot;
593 rate.mFilterRemain = div_result.rem;
594 if (rate.mFilterLoops == 0.)
595 rate.mFilterSlope = 0.;
596 else
597 rate.mFilterSlope = 1. / rate.mFilterLoops;
598 }
599
600
initialize(server_arguments const & args,float * control_busses)601 void sc_plugin_interface::initialize(server_arguments const& args, float* control_busses) {
602 const bool nrt_mode = args.non_rt;
603
604 done_nodes.reserve(64);
605 pause_nodes.reserve(16);
606 resume_nodes.reserve(16);
607 freeAll_nodes.reserve(16);
608 freeDeep_nodes.reserve(16);
609
610 /* define functions */
611 sc_interface.fDefineUnit = &define_unit;
612 sc_interface.fDefineBufGen = &define_bufgen;
613 sc_interface.fDefinePlugInCmd = &define_plugincmd;
614 sc_interface.fDefineUnitCmd = &define_unitcmd;
615
616 /* interface functions */
617 sc_interface.fNodeEnd = &node_end;
618 sc_interface.fGetNode = &get_node;
619 sc_interface.fNodeRun = &node_set_run;
620 sc_interface.fPrint = &print;
621 sc_interface.fDoneAction = &done_action;
622 sc_interface.fSendMsgFromRT = &send_message_from_RT;
623 sc_interface.fSendMsgToRT = &send_message_to_RT;
624
625 /* sndfile functions */
626 #ifdef NO_LIBSNDFILE
627 sc_interface.fSndFileFormatInfoFromStrings = nullptr;
628 #else
629 sc_interface.fSndFileFormatInfoFromStrings = &sndfileFormatInfoFromStrings;
630 #endif
631
632 /* wave tables */
633 sc_interface.mSine = gSine;
634 sc_interface.mCosecant = gInvSine;
635 sc_interface.mSineSize = kSineSize;
636 sc_interface.mSineWavetable = gSineWavetable;
637
638 /* memory allocation */
639 if (!nrt_mode) {
640 sc_interface.fRTAlloc = &rt_alloc;
641 sc_interface.fRTRealloc = &rt_realloc;
642 sc_interface.fRTFree = &rt_free;
643 } else {
644 sc_interface.fRTAlloc = &nrt_alloc_2;
645 sc_interface.fRTRealloc = &nrt_realloc_2;
646 sc_interface.fRTFree = &nrt_free_2;
647 }
648
649 sc_interface.fNRTAlloc = &nrt_alloc;
650 sc_interface.fNRTRealloc = &nrt_realloc;
651 sc_interface.fNRTFree = &nrt_free;
652
653 /* ugen functions */
654 sc_interface.fClearUnitOutputs = clear_outputs;
655
656 /* buffer functions */
657 sc_interface.fBufAlloc = &buf_alloc;
658
659 /* trigger functions */
660 sc_interface.fSendTrigger = &send_trigger;
661 sc_interface.fSendNodeReply = &send_node_reply;
662
663 /* world locks */
664 sc_interface.fNRTLock = &world_lock;
665 sc_interface.fNRTUnlock = &world_unlock;
666 world.mNRTLock = new SC_Lock();
667
668 /* fft library */
669 sc_interface.fSCfftCreate = &scfft_create;
670 sc_interface.fSCfftDestroy = &scfft_destroy;
671 sc_interface.fSCfftDoFFT = &scfft_dofft;
672 sc_interface.fSCfftDoIFFT = &scfft_doifft;
673
674 /* scope API */
675 sc_interface.fGetScopeBuffer = &get_scope_buffer;
676 sc_interface.fPushScopeBuffer = &push_scope_buffer;
677 sc_interface.fReleaseScopeBuffer = &release_scope_buffer;
678
679 /* osc plugins */
680 sc_interface.fDoAsynchronousCommand = &do_asynchronous_command;
681
682 /* initialize world */
683 /* control busses */
684 world.mControlBus = control_busses;
685 world.mNumControlBusChannels = args.control_busses;
686 world.mControlBusTouched = new int32[args.control_busses];
687 std::fill(world.mControlBusTouched, world.mControlBusTouched + args.control_busses, -1);
688
689 /* audio busses */
690 audio_busses.initialize(args.audio_busses, args.blocksize);
691
692 world.mAudioBus = audio_busses.buffers;
693 world.mNumAudioBusChannels = args.audio_busses;
694 world.mAudioBusTouched = new int32[args.audio_busses];
695 world.mAudioBusLocks = audio_busses.locks;
696 world.mControlBusLock = new spin_lock();
697 std::fill(world.mAudioBusTouched, world.mAudioBusTouched + args.audio_busses, -1);
698
699 /* audio buffers */
700 world.mNumSndBufs = args.buffers;
701 world.mSndBufs = new SndBuf[world.mNumSndBufs];
702 world.mSndBufsNonRealTimeMirror = new SndBuf[world.mNumSndBufs];
703 world.mSndBufUpdates = new SndBufUpdates[world.mNumSndBufs];
704 memset(world.mSndBufs, 0, world.mNumSndBufs * sizeof(SndBuf));
705 memset(world.mSndBufsNonRealTimeMirror, 0, world.mNumSndBufs * sizeof(SndBuf));
706 memset(world.mSndBufUpdates, 0, world.mNumSndBufs * sizeof(SndBufUpdates));
707 world.mBufCounter = 0;
708
709 async_buffer_guards.reset(new std::mutex[world.mNumSndBufs]);
710
711 /* audio settings */
712 world.mBufLength = args.blocksize;
713 world.mSampleRate = args.samplerate;
714
715 initialize_rate(world.mFullRate, args.samplerate, args.blocksize);
716 initialize_rate(world.mBufRate, double(args.samplerate) / args.blocksize, 1);
717
718 world.mNumInputs = args.input_channels;
719 world.mNumOutputs = args.output_channels;
720
721 world.mRealTime = !args.non_rt;
722 world.mVerbosity = args.verbosity;
723
724 /* rngs */
725 world.mNumRGens = args.rng_count;
726 world.mRGen = new RGen[world.mNumRGens];
727 std::vector<std::uint32_t> seeds(world.mNumRGens);
728
729 try {
730 std::random_device rd;
731 std::seed_seq seq({ rd(), rd(), rd() });
732 seq.generate(seeds.begin(), seeds.end());
733 } catch (...) {
734 auto now = std::chrono::high_resolution_clock::now();
735
736 auto seconds = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
737
738 std::seed_seq seq({ seconds.count() });
739 seq.generate(seeds.begin(), seeds.end());
740 }
741
742 for (int i = 0; i < world.mNumRGens; ++i)
743 world.mRGen[i].init(seeds[i]);
744 }
745
reset_sampling_rate(int sr)746 void sc_plugin_interface::reset_sampling_rate(int sr) {
747 world.mSampleRate = sr;
748
749 initialize_rate(world.mFullRate, sr, world.mBufLength);
750 initialize_rate(world.mBufRate, double(sr) / world.mBufLength, 1);
751 }
752
753
apply_done_actions(void)754 void sc_done_action_handler::apply_done_actions(void) {
755 for (server_node* node : done_nodes)
756 instance->free_node(node);
757 done_nodes.clear();
758
759 for (server_node* node : resume_nodes)
760 instance->node_resume(node);
761 resume_nodes.clear();
762
763 for (server_node* node : pause_nodes)
764 instance->node_pause(node);
765 pause_nodes.clear();
766
767 for (abstract_group* group : freeDeep_nodes)
768 instance->group_free_deep(group);
769 freeDeep_nodes.clear();
770
771 for (abstract_group* group : freeAll_nodes)
772 instance->group_free_all(group);
773 freeAll_nodes.clear();
774 }
775
~sc_plugin_interface(void)776 sc_plugin_interface::~sc_plugin_interface(void) {
777 delete[] world.mAudioBusTouched;
778 delete[] world.mControlBusTouched;
779 delete[] world.mSndBufs;
780 delete[] world.mSndBufsNonRealTimeMirror;
781 delete[] world.mSndBufUpdates;
782 delete[] world.mRGen;
783 delete reinterpret_cast<SC_Lock*>(world.mNRTLock);
784 }
785
786 namespace {
787
allocate_buffer(size_t samples)788 sample* allocate_buffer(size_t samples) {
789 const size_t alloc_size = samples * sizeof(sample);
790 sample* ret = (sample*)calloc_aligned(alloc_size);
791 if (ret)
792 mlock(ret, alloc_size);
793 return ret;
794 }
795
bufmask(int32 x)796 inline int32 bufmask(int32 x) { return (1 << (31 - CLZ(x))) - 1; }
797
sndbuf_init(SndBuf * buf)798 inline void sndbuf_init(SndBuf* buf) {
799 buf->samplerate = 0;
800 buf->sampledur = 0;
801 buf->data = nullptr;
802 buf->channels = 0;
803 buf->samples = 0;
804 buf->frames = 0;
805 buf->mask = 0;
806 buf->mask1 = 0;
807 buf->coord = 0;
808 buf->sndfile = nullptr;
809 buf->isLocal = false;
810 }
811
sndbuf_copy(SndBuf * dest,const SndBuf * src)812 inline void sndbuf_copy(SndBuf* dest, const SndBuf* src) {
813 dest->samplerate = src->samplerate;
814 dest->sampledur = src->sampledur;
815 dest->data = src->data;
816 dest->channels = src->channels;
817 dest->samples = src->samples;
818 dest->frames = src->frames;
819 dest->mask = src->mask;
820 dest->mask1 = src->mask1;
821 dest->coord = src->coord;
822 dest->sndfile = src->sndfile;
823 dest->isLocal = src->isLocal;
824 }
825
compute_remaining_samples(size_t frames_per_read,size_t already_read,size_t total_frames)826 static inline size_t compute_remaining_samples(size_t frames_per_read, size_t already_read, size_t total_frames) {
827 int remain = frames_per_read;
828 if (already_read + frames_per_read > total_frames)
829 remain = total_frames - already_read;
830 return remain;
831 }
832
read_channel(SndfileHandle & sf,uint32_t channel_count,const uint32_t * channel_data,uint32 total_frames,sample * data)833 void read_channel(SndfileHandle& sf, uint32_t channel_count, const uint32_t* channel_data, uint32 total_frames,
834 sample* data) {
835 const unsigned int frames_per_read = 1024;
836 sized_array<sample> read_frame(sf.channels() * frames_per_read);
837
838 if (channel_count == 1) {
839 // fast-path for single-channel read
840 for (size_t i = 0; i < total_frames; i += frames_per_read) {
841 int remaining_samples = compute_remaining_samples(frames_per_read, i, total_frames);
842 size_t read = sf.readf(read_frame.c_array(), remaining_samples);
843
844 size_t channel_mapping = channel_data[0];
845 for (size_t frame = 0; frame != read; ++frame) {
846 data[0] = read_frame[frame * sf.channels() + channel_mapping];
847 data += channel_count;
848 }
849 }
850 } else {
851 for (size_t i = 0; i < total_frames; i += frames_per_read) {
852 int remaining_samples = compute_remaining_samples(frames_per_read, i, total_frames);
853 size_t read = sf.readf(read_frame.c_array(), remaining_samples);
854
855 for (size_t frame = 0; frame != read; ++frame) {
856 for (size_t c = 0; c != channel_count; ++c) {
857 size_t channel_mapping = channel_data[c];
858 data[c] = read_frame[frame * sf.channels() + channel_mapping];
859 }
860 data += channel_count;
861 }
862 }
863 }
864 }
865
866 } /* namespace */
867
allocate_buffer(SndBuf * buf,uint32_t frames,uint32_t channels,double samplerate)868 void sc_plugin_interface::allocate_buffer(SndBuf* buf, uint32_t frames, uint32_t channels, double samplerate) {
869 const uint32_t samples = frames * channels;
870 if (samples == 0)
871 throw std::runtime_error("invalid buffer size");
872
873 sample* data = nova::allocate_buffer(samples);
874 if (data == nullptr)
875 throw std::runtime_error("could not allocate memory");
876
877 buf->data = data;
878 buf->channels = channels;
879 buf->frames = frames;
880 buf->samples = samples;
881 buf->mask = bufmask(samples); /* for delay lines */
882 buf->mask1 = buf->mask - 1; /* for oscillators */
883 buf->samplerate = samplerate;
884 buf->sampledur = 1.0 / samplerate;
885 buf->isLocal = false;
886 }
887
allocate_buffer(uint32_t index,uint32_t frames,uint32_t channels)888 SndBuf* sc_plugin_interface::allocate_buffer(uint32_t index, uint32_t frames, uint32_t channels) {
889 SndBuf* buf = World_GetNRTBuf(&world, index);
890 allocate_buffer(buf, frames, channels, world.mFullRate.mSampleRate);
891 return buf;
892 }
893
buffer_read_alloc(uint32_t index,const char * filename,uint32_t start,uint32_t frames)894 void sc_plugin_interface::buffer_read_alloc(uint32_t index, const char* filename, uint32_t start, uint32_t frames) {
895 auto f = makeSndfileHandle(filename);
896 if (f.rawHandle() == nullptr)
897 throw std::runtime_error(f.strError());
898
899 const size_t sf_frames = f.frames();
900
901 if (start > sf_frames)
902 start = sf_frames;
903
904 if (frames == 0 || frames > sf_frames - start)
905 frames = sf_frames - start;
906
907 SndBuf* buf = World_GetNRTBuf(&world, index);
908 allocate_buffer(buf, frames, f.channels(), f.samplerate());
909
910 f.seek(start, SEEK_SET);
911 f.readf(buf->data, frames);
912 }
913
914
buffer_alloc_read_channels(uint32_t index,const char * filename,uint32_t start,uint32_t frames,uint32_t channel_count,const uint32_t * channel_data)915 void sc_plugin_interface::buffer_alloc_read_channels(uint32_t index, const char* filename, uint32_t start,
916 uint32_t frames, uint32_t channel_count,
917 const uint32_t* channel_data) {
918 // If no channel argument provided we read all channels.
919 if (channel_count == 0) {
920 buffer_read_alloc(index, filename, start, frames);
921 return;
922 }
923
924 auto f = makeSndfileHandle(filename);
925 if (f.rawHandle() == nullptr)
926 throw std::runtime_error(f.strError());
927
928 uint32_t sf_channels = uint32_t(f.channels());
929 const uint32_t* max_chan = std::max_element(channel_data, channel_data + channel_count);
930 if (*max_chan >= sf_channels)
931 throw std::runtime_error("Channel out of range");
932
933 const size_t sf_frames = f.frames();
934
935 if (start > sf_frames)
936 start = sf_frames;
937
938 if (frames == 0 || frames > sf_frames - start)
939 frames = sf_frames - start;
940
941 SndBuf* buf = World_GetNRTBuf(&world, index);
942 allocate_buffer(buf, frames, channel_count, f.samplerate());
943
944 f.seek(start, SEEK_SET);
945 read_channel(f, channel_count, channel_data, frames, buf->data);
946 }
947
948
buffer_write(uint32_t index,const char * filename,const char * header_format,const char * sample_format,uint32_t start,uint32_t frames,bool leave_open)949 void sc_plugin_interface::buffer_write(uint32_t index, const char* filename, const char* header_format,
950 const char* sample_format, uint32_t start, uint32_t frames, bool leave_open) {
951 SndBuf* buf = World_GetNRTBuf(&world, index);
952 int format = headerFormatFromString(header_format) | sampleFormatFromString(sample_format);
953
954 auto sf = makeSndfileHandle(filename, SFM_WRITE, format, buf->channels, buf->samplerate);
955
956 if (sf.rawHandle() == nullptr)
957 throw std::runtime_error(sf.strError());
958
959 if (frames == 0xffffffff)
960 frames = buf->frames;
961
962 const uint32_t remain = uint32_t(buf->frames) > start ? buf->frames - start : 0;
963 const uint32_t frames_to_write = std::min(remain, frames);
964
965 if (frames_to_write)
966 sf.writef(buf->data + start * buf->channels, frames_to_write);
967
968 if (leave_open && !buf->sndfile)
969 buf->sndfile = sf.takeOwnership();
970 }
971
buffer_read_verify(SndfileHandle & sf,size_t min_length,size_t samplerate,bool check_samplerate)972 static void buffer_read_verify(SndfileHandle& sf, size_t min_length, size_t samplerate, bool check_samplerate) {
973 if (sf.rawHandle() == nullptr)
974 throw std::runtime_error(sf.strError());
975 if (sf.frames() < min_length)
976 throw std::runtime_error("no more frames to read");
977
978 if (check_samplerate && (sf.samplerate() != samplerate))
979 throw std::runtime_error("sample rate mismatch");
980 }
981
buffer_read(uint32_t index,const char * filename,uint32_t start_file,uint32_t frames,uint32_t start_buffer,bool leave_open)982 void sc_plugin_interface::buffer_read(uint32_t index, const char* filename, uint32_t start_file, uint32_t frames,
983 uint32_t start_buffer, bool leave_open) {
984 SndBuf* buf = World_GetNRTBuf(&world, index);
985
986 if (uint32_t(buf->frames) < start_buffer)
987 throw std::runtime_error("buffer already full");
988
989 auto sf = makeSndfileHandle(filename, SFM_READ);
990 buffer_read_verify(sf, start_file, buf->samplerate, !leave_open);
991
992 if (sf.channels() != buf->channels)
993 throw std::runtime_error("channel count mismatch");
994
995 const uint32_t buffer_remain = buf->frames - start_buffer;
996 const uint32_t file_remain = sf.frames() - start_file;
997 const uint32_t frames_to_read = std::min(frames, std::min(buffer_remain, file_remain));
998
999 sf.seek(start_file, SEEK_SET);
1000 sf.readf(buf->data + start_buffer * buf->channels, frames_to_read);
1001
1002 if (leave_open)
1003 buf->sndfile = sf.takeOwnership();
1004 }
1005
buffer_read_channel(uint32_t index,const char * filename,uint32_t start_file,uint32_t frames,uint32_t start_buffer,bool leave_open,uint32_t channel_count,const uint32_t * channel_data)1006 void sc_plugin_interface::buffer_read_channel(uint32_t index, const char* filename, uint32_t start_file,
1007 uint32_t frames, uint32_t start_buffer, bool leave_open,
1008 uint32_t channel_count, const uint32_t* channel_data) {
1009 SndBuf* buf = World_GetNRTBuf(&world, index);
1010
1011 if (channel_count != uint32_t(buf->channels))
1012 throw std::runtime_error("channel count mismatch");
1013
1014 if (uint32_t(buf->frames) >= start_buffer)
1015 throw std::runtime_error("buffer already full");
1016
1017 auto sf = makeSndfileHandle(filename, SFM_READ);
1018 buffer_read_verify(sf, start_file, buf->samplerate, !leave_open);
1019
1020 uint32_t sf_channels = uint32_t(sf.channels());
1021 const uint32_t* max_chan = std::max_element(channel_data, channel_data + channel_count);
1022 if (*max_chan >= sf_channels)
1023 throw std::runtime_error("channel count mismatch");
1024
1025 const uint32_t buffer_remain = buf->frames - start_buffer;
1026 const uint32_t file_remain = sf.frames() - start_file;
1027
1028 const uint32_t frames_to_read = std::min(frames, std::min(buffer_remain, file_remain));
1029
1030 sf.seek(start_file, SEEK_SET);
1031 read_channel(sf, channel_count, channel_data, frames_to_read, buf->data);
1032
1033 if (leave_open)
1034 buf->sndfile = sf.takeOwnership();
1035 }
1036
buffer_close(uint32_t index)1037 void sc_plugin_interface::buffer_close(uint32_t index) {
1038 SndBuf* buf = World_GetNRTBuf(&world, index);
1039
1040 if (buf->sndfile == nullptr)
1041 return;
1042 sf_close(buf->sndfile);
1043 buf->sndfile = nullptr;
1044 }
1045
1046
buffer_zero(uint32_t index)1047 void sc_plugin_interface::buffer_zero(uint32_t index) {
1048 SndBuf* buf = World_GetNRTBuf(&world, index);
1049
1050 uint32_t length = buf->frames * buf->channels;
1051
1052 uint32_t unrolled = length & ~63;
1053 uint32_t remain = length & 63;
1054
1055 zerovec_simd(buf->data, unrolled);
1056 zerovec(buf->data + unrolled, remain);
1057 }
1058
buffer_generate(uint32_t buffer_index,const char * cmd_name,struct sc_msg_iter & msg)1059 sample* sc_plugin_interface::buffer_generate(uint32_t buffer_index, const char* cmd_name, struct sc_msg_iter& msg) {
1060 return sc_factory->run_bufgen(&world, cmd_name, buffer_index, &msg);
1061 }
1062
buffer_sync(uint32_t index)1063 void sc_plugin_interface::buffer_sync(uint32_t index) noexcept {
1064 sndbuf_copy(world.mSndBufs + index, world.mSndBufsNonRealTimeMirror + index);
1065 increment_write_updates(index);
1066 }
1067
free_buffer(uint32_t index)1068 void sc_plugin_interface::free_buffer(uint32_t index) {
1069 SndBuf* buf = world.mSndBufsNonRealTimeMirror + index;
1070 if (buf->sndfile)
1071 sf_close(buf->sndfile);
1072
1073 sndbuf_init(buf);
1074 }
1075
1076 } /* namespace nova */
1077