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