Fix scvim regsitry file for updated filename (thanks Carlo Capocasa)
[supercollider.git] / server / supernova / sc / sc_plugin_interface.cpp
blobe273305359739d389feb8a9a75776c5e240d6c90
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.
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 #include <cstdarg>
21 #include "sndfile.hh"
23 #include "sc_plugin_interface.hpp"
24 #include "sc_ugen_factory.hpp"
25 #include "sc_synth.hpp"
27 #include "nova-simd/simd_memory.hpp"
29 #include "../server/server_args.hpp"
30 #include "../server/memory_pool.hpp"
31 #include "../server/server.hpp"
32 #include "../utilities/malloc_aligned.hpp"
33 #include "../utilities/sized_array.hpp"
35 #include "SC_Samp.h"
36 #include "SC_Prototypes.h"
37 #include "SC_Errors.h"
38 #include "SC_Unit.h"
39 #include "clz.h"
40 #include "SC_fftlib.h"
41 #include "../../common/SC_SndFileHelpers.hpp"
43 // undefine the shadowed scfft functions
44 #undef scfft_create
45 #undef scfft_dofft
46 #undef scfft_doifft
47 #undef scfft_destroy
49 namespace nova {
51 spin_lock log_guard; // needs to be acquired for logging from the helper threads!
53 namespace {
55 inline Node * as_Node(server_node * node)
57 if (node == NULL)
58 return NULL;
60 // hack!!! we only assume that the 32bit integer mID member can be accessed via Node
61 if (node->is_synth()) {
62 sc_synth * s = static_cast<sc_synth*>(node);
63 return &s->mNode;
64 } else {
65 void * nodePointer = &node->node_id;
66 return (Node*)nodePointer;
70 void pause_node(Unit * unit)
72 server_node * node = static_cast<sc_synth*>(unit->mParent);
73 sc_factory->add_pause_node(node);
76 void free_node(Unit * unit)
78 server_node * node = static_cast<sc_synth*>(unit->mParent);
79 sc_factory->add_done_node(node);
82 void free_node_and_preceding(Unit * unit)
84 server_node * node = static_cast<sc_synth*>(unit->mParent);
85 sc_factory->add_done_node(node);
87 if (node->get_parent()->is_parallel()) {
88 spin_lock::scoped_lock lock(log_guard);
89 log("parallel groups have no notion of preceding nodes\n");
90 return;
93 server_node * preceding = node->previous_node();
94 if (preceding)
95 sc_factory->add_done_node(preceding);
98 void free_node_and_pause_preceding(Unit * unit)
100 server_node * node = static_cast<sc_synth*>(unit->mParent);
101 sc_factory->add_done_node(node);
103 if (node->get_parent()->is_parallel()) {
104 spin_lock::scoped_lock lock(log_guard);
105 log("parallel groups have no notion of preceding nodes\n");
106 return;
109 server_node * preceding = node->previous_node();
110 if (preceding)
111 sc_factory->add_pause_node(preceding);
114 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);
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;
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);
137 void free_node_and_preceding_deep(Unit * unit)
139 server_node * node = static_cast<sc_synth*>(unit->mParent);
140 sc_factory->add_done_node(node);
142 if (node->get_parent()->is_parallel()) {
143 log("parallel groups have no notion of preceding nodes\n");
144 return;
147 server_node * preceding = node->previous_node();
148 if (!preceding)
149 return;
150 if (preceding->is_synth())
151 sc_factory->add_done_node(preceding);
152 else {
153 abstract_group * preceding_group = static_cast<abstract_group*>(preceding);
154 sc_factory->add_freeDeep_node(preceding_group);
158 void free_node_and_all_preceding(Unit * unit)
160 server_node * node = static_cast<sc_synth*>(unit->mParent);
161 sc_factory->add_done_node(node);
163 if (node->get_parent()->is_parallel()) {
164 spin_lock::scoped_lock lock(log_guard);
165 log("parallel groups have no notion of preceding nodes\n");
166 return;
169 for(;;) {
170 node = node->previous_node();
171 if (node)
172 sc_factory->add_done_node(node);
173 else
174 return;
178 void free_node_and_following(Unit * unit)
180 server_node * node = static_cast<sc_synth*>(unit->mParent);
181 sc_factory->add_done_node(node);
183 if (node->get_parent()->is_parallel()) {
184 spin_lock::scoped_lock lock(log_guard);
185 log("parallel groups have no notion of following nodes\n");
186 return;
189 server_node * next = node->next_node();
190 if (next)
191 sc_factory->add_done_node(next);
194 void free_node_and_pause_following(Unit * unit)
196 server_node * node = static_cast<sc_synth*>(unit->mParent);
197 sc_factory->add_done_node(node);
199 if (node->get_parent()->is_parallel()) {
200 spin_lock::scoped_lock lock(log_guard);
201 log("parallel groups have no notion of following nodes\n");
202 return;
205 server_node * next = node->next_node();
206 if (next)
207 sc_factory->add_pause_node(next);
210 void free_node_and_following_children(Unit * unit)
212 server_node * node = static_cast<sc_synth*>(unit->mParent);
213 sc_factory->add_done_node(node);
215 if (node->get_parent()->is_parallel()) {
216 spin_lock::scoped_lock lock(log_guard);
217 log("parallel groups have no notion of following nodes\n");
218 return;
221 server_node * following = node->previous_node();
222 if (!following)
223 return;
224 if (following->is_synth())
225 sc_factory->add_done_node(following);
226 else {
227 abstract_group * following_group = static_cast<abstract_group*>(following);
228 sc_factory->add_freeAll_node(following_group);
232 void free_node_and_following_deep(Unit * unit)
234 server_node * node = static_cast<sc_synth*>(unit->mParent);
235 sc_factory->add_done_node(node);
237 if (node->get_parent()->is_parallel()) {
238 spin_lock::scoped_lock lock(log_guard);
239 log("parallel groups have no notion of following nodes\n");
240 return;
243 server_node * following = node->previous_node();
244 if (!following)
245 return;
246 if (following->is_synth())
247 sc_factory->add_done_node(following);
248 else {
249 abstract_group * following_group = static_cast<abstract_group*>(following);
250 sc_factory->add_freeDeep_node(following_group);
254 void free_node_and_all_following(Unit * unit)
256 server_node * node = static_cast<sc_synth*>(unit->mParent);
257 sc_factory->add_done_node(node);
259 if (node->get_parent()->is_parallel()) {
260 spin_lock::scoped_lock lock(log_guard);
261 log("parallel groups have no notion of following nodes\n");
262 return;
265 for(;;) {
266 node = node->previous_node();
267 if (node)
268 sc_factory->add_done_node(node);
269 else
270 return;
274 void free_group_members(Unit * unit)
276 server_node * node = static_cast<sc_synth*>(unit->mParent);
277 abstract_group * group = const_cast<abstract_group*>(node->get_parent());
279 sc_factory->add_freeAll_node(group);
282 void free_parent_group(Unit * unit)
284 server_node * node = static_cast<sc_synth*>(unit->mParent);
285 abstract_group * group = const_cast<abstract_group*>(node->get_parent());
286 sc_factory->add_done_node(group);
289 bool get_scope_buffer(World *inWorld, int index, int channels, int maxFrames, ScopeBufferHnd &hnd)
291 scope_buffer_writer writer = instance->get_scope_buffer_writer( index, channels, maxFrames );
293 if( writer.valid() ) {
294 hnd.internalData = writer.buffer;
295 hnd.data = writer.data();
296 hnd.channels = channels;
297 hnd.maxFrames = maxFrames;
298 return true;
300 else {
301 hnd.internalData = 0;
302 return false;
306 void push_scope_buffer(World *inWorld, ScopeBufferHnd &hnd, int frames)
308 scope_buffer_writer writer(reinterpret_cast<scope_buffer*>(hnd.internalData));
309 writer.push(frames);
310 hnd.data = writer.data();
313 void release_scope_buffer(World *inWorld, ScopeBufferHnd &hnd)
315 scope_buffer_writer writer(reinterpret_cast<scope_buffer*>(hnd.internalData));
316 instance->release_scope_buffer_writer( writer );
319 } /* namespace */
320 } /* namespace nova */
322 extern "C"
325 bool define_unit(const char *inUnitClassName, size_t inAllocSize,
326 UnitCtorFunc inCtor, UnitDtorFunc inDtor, uint32 inFlags)
328 try {
329 nova::sc_factory->register_ugen(inUnitClassName, inAllocSize, inCtor, inDtor, inFlags);
330 return true;
332 catch(...)
334 return false;
338 bool define_bufgen(const char * name, BufGenFunc func)
340 try {
341 nova::sc_factory->register_bufgen(name, func);
342 return true;
344 catch(...)
346 return false;
350 bool define_unitcmd(const char * unitClassName, const char * cmdName, UnitCmdFunc inFunc)
352 return nova::sc_factory->register_ugen_command_function(unitClassName, cmdName, inFunc);
356 bool define_plugincmd(const char * name, PlugInCmdFunc func, void * user_data)
358 return nova::sc_factory->register_cmd_plugin(name, func, user_data);
361 void * rt_alloc(World * dummy, size_t size)
363 if (size)
364 return nova::rt_pool.malloc(size);
365 else
366 return NULL;
369 void * rt_realloc(World * dummy, void * ptr, size_t size)
371 return nova::rt_pool.realloc(ptr, size);
374 void rt_free(World * dummy, void * ptr)
376 if (ptr)
377 nova::rt_pool.free(ptr);
380 void * nrt_alloc(size_t size)
382 return malloc(size);
385 void * nrt_realloc(void * ptr, size_t size)
387 return realloc(ptr, size);
390 void nrt_free(void * ptr)
392 free(ptr);
395 void clear_outputs(Unit *unit, int samples)
397 size_t outputs = unit->mNumOutputs;
399 if ((samples & 15) == 0)
400 for (size_t i=0; i!=outputs; ++i)
401 nova::zerovec_simd(unit->mOutBuf[i], samples);
402 else
403 for (size_t i=0; i!=outputs; ++i)
404 nova::zerovec(unit->mOutBuf[i], samples);
407 void node_end(struct Node * node)
409 nova::server_node * s = nova::instance->find_node(node->mID);
410 nova::sc_factory->add_done_node(s);
413 void node_set_run(struct Node * node, int run)
415 using namespace nova;
416 server_node * s = instance->find_node(node->mID);
418 if (run == 0)
419 sc_factory->add_pause_node(s);
420 else
421 sc_factory->add_resume_node(s);
425 int print(const char *fmt, ...)
427 va_list vargs;
428 va_start(vargs, fmt);
430 nova::log_guard.lock();
431 bool status = nova::instance->log_printf(fmt, vargs);
432 nova::log_guard.unlock();
434 va_end(vargs);
435 return (status == true) ? 0 : -1;
438 /* todo: we need to implement most of the done actions */
439 void done_action(int done_action, struct Unit *unit)
441 using namespace nova;
442 switch(done_action) {
443 case 0:
444 // do nothing when the UGen is finished
445 return;
447 case 1:
448 // pause the enclosing synth, but do not free it
449 nova::pause_node(unit);
450 return;
451 case 2:
452 // free the enclosing synth
453 nova::free_node(unit);
454 return;
456 case 3:
457 // free both this synth and the preceding node
458 nova::free_node_and_preceding(unit);
459 return;
461 case 4:
462 // free both this synth and the following node
463 nova::free_node_and_following(unit);
464 return;
466 case 5:
467 // free this synth; if the preceding node is a group then do g_freeAll on it, else free it
468 nova::free_node_and_preceding_children(unit);
469 return;
471 case 6:
472 nova::free_node_and_following_children(unit);
473 // free this synth; if the following node is a group then do g_freeAll on it, else free it
474 return;
476 case 7:
477 //free this synth and all preceding nodes in this group
478 nova::free_node_and_all_preceding(unit);
479 return;
481 case 8:
482 //free this synth and all following nodes in this group
483 nova::free_node_and_all_following(unit);
484 return;
486 case 9:
487 // free this synth and pause the preceding node
488 nova::free_node_and_pause_preceding(unit);
489 return;
491 case 10:
492 // free this synth and pause the following node
493 nova::free_node_and_pause_following(unit);
494 return;
496 case 11:
497 // free this synth and if the preceding node is a group then do g_deepFree on it, else free it
498 nova::free_node_and_preceding_deep(unit);
499 return;
501 case 12:
502 // free this synth and if the following node is a group then do g_deepFree on it, else free it
503 nova::free_node_and_following_deep(unit);
504 return;
506 case 13:
507 // free this synth and all other nodes in this group (before and after)
508 nova::free_group_members(unit);
509 return;
511 case 14:
512 // free the enclosing group and all nodes within it (including this synth)
513 nova::free_parent_group(unit);
514 return;
516 default:
517 return;
521 int buf_alloc(SndBuf * buf, int channels, int frames, double samplerate)
523 return nova::sc_factory->allocate_buffer(buf, channels, frames, samplerate);
526 void send_trigger(Node * unit, int trigger_id, float value)
528 nova::instance->send_trigger(unit->mID, trigger_id, value);
531 void world_lock(World *world)
533 world->mNRTLock->Lock();
536 void world_unlock(World *world)
538 world->mNRTLock->Unlock();
541 Node * get_node(World *world, int id)
543 nova::server_node * node = nova::instance->find_node(id);
544 return nova::as_Node(node);
547 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;
552 nova::instance->send_node_reply(node->mID, reply_id, command_name, argument_count, values);
555 int do_asynchronous_command(World *inWorld, void* replyAddr, const char* cmdName, void *cmdData,
556 AsyncStageFn stage2, // stage2 is non real time
557 AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true
558 AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true
559 AsyncFreeFn cleanup,
560 int completionMsgSize, void* completionMsgData)
562 nova::instance->do_asynchronous_command(inWorld, replyAddr, cmdName, cmdData,
563 stage2, stage3, stage4, cleanup,
564 completionMsgSize, completionMsgData);
565 return 0;
568 } /* extern "C" */
570 namespace nova
574 inline void initialize_rate(Rate & rate, double sample_rate, int blocksize)
576 rate.mSampleRate = sample_rate;
577 rate.mSampleDur = 1. / sample_rate;
578 rate.mRadiansPerSample = 2 * M_PI / sample_rate;
580 rate.mBufLength = blocksize;
581 rate.mBufDuration = blocksize / sample_rate;
582 rate.mBufRate = sample_rate / blocksize;
583 rate.mSlopeFactor = 1. / blocksize;
585 div_t div_result = std::div(blocksize, 3);
586 rate.mFilterLoops = div_result.quot;
587 rate.mFilterRemain = div_result.rem;
588 if (rate.mFilterLoops == 0.)
589 rate.mFilterSlope = 0.;
590 else
591 rate.mFilterSlope = 1. / rate.mFilterLoops;
595 void sc_plugin_interface::initialize(server_arguments const & args, float * control_busses)
597 done_nodes.reserve(64);
598 pause_nodes.reserve(16);
599 resume_nodes.reserve(16);
600 freeAll_nodes.reserve(16);
601 freeDeep_nodes.reserve(16);
603 /* define functions */
604 sc_interface.fDefineUnit = &define_unit;
605 sc_interface.fDefineBufGen = &define_bufgen;
606 sc_interface.fDefinePlugInCmd = &define_plugincmd;
607 sc_interface.fDefineUnitCmd = &define_unitcmd;
609 /* interface functions */
610 sc_interface.fNodeEnd = &node_end;
611 sc_interface.fGetNode = &get_node;
612 sc_interface.fNodeRun = &node_set_run;
613 sc_interface.fPrint = &print;
614 sc_interface.fDoneAction = &done_action;
616 /* sndfile functions */
617 #ifdef NO_LIBSNDFILE
618 sc_interface.fSndFileFormatInfoFromStrings = NULL;
619 #else
620 sc_interface.fSndFileFormatInfoFromStrings = &sndfileFormatInfoFromStrings;
621 #endif
623 /* wave tables */
624 sc_interface.mSine = gSine;
625 sc_interface.mCosecant = gInvSine;
626 sc_interface.mSineSize = kSineSize;
627 sc_interface.mSineWavetable = gSineWavetable;
629 /* memory allocation */
630 sc_interface.fRTAlloc = &rt_alloc;
631 sc_interface.fRTRealloc = &rt_realloc;
632 sc_interface.fRTFree = &rt_free;
634 sc_interface.fNRTAlloc = &nrt_alloc;
635 sc_interface.fNRTRealloc = &nrt_realloc;
636 sc_interface.fNRTFree = &nrt_free;
638 /* ugen functions */
639 sc_interface.fClearUnitOutputs = clear_outputs;
641 /* buffer functions */
642 sc_interface.fBufAlloc = &buf_alloc;
644 /* trigger functions */
645 sc_interface.fSendTrigger = &send_trigger;
646 sc_interface.fSendNodeReply = &send_node_reply;
648 /* world locks */
649 sc_interface.fNRTLock = &world_lock;
650 sc_interface.fNRTUnlock = &world_unlock;
651 world.mNRTLock = new SC_Lock();
653 /* fft library */
654 sc_interface.fSCfftCreate = &scfft_create;
655 sc_interface.fSCfftDestroy = &scfft_destroy;
656 sc_interface.fSCfftDoFFT = &scfft_dofft;
657 sc_interface.fSCfftDoIFFT = &scfft_doifft;
659 /* scope API */
660 sc_interface.fGetScopeBuffer = &get_scope_buffer;
661 sc_interface.fPushScopeBuffer = &push_scope_buffer;
662 sc_interface.fReleaseScopeBuffer = &release_scope_buffer;
664 /* osc plugins */
665 sc_interface.fDoAsynchronousCommand = &do_asynchronous_command;
667 /* initialize world */
668 /* control busses */
669 world.mControlBus = control_busses;
670 world.mNumControlBusChannels = args.control_busses;
671 world.mControlBusTouched = new int32[args.control_busses];
672 std::fill(world.mControlBusTouched, world.mControlBusTouched + args.control_busses, -1);
674 /* audio busses */
675 audio_busses.initialize(args.audio_busses, args.blocksize);
677 world.mAudioBus = audio_busses.buffers;
678 world.mNumAudioBusChannels = args.audio_busses;
679 world.mAudioBusTouched = new int32[args.audio_busses];
680 world.mAudioBusLocks = audio_busses.locks;
681 world.mControlBusLock = new spin_lock();
682 std::fill(world.mAudioBusTouched, world.mAudioBusTouched + args.audio_busses, -1);
684 /* audio buffers */
685 world.mNumSndBufs = args.buffers;
686 world.mSndBufs = new SndBuf[world.mNumSndBufs];
687 world.mSndBufsNonRealTimeMirror = new SndBuf[world.mNumSndBufs];
688 world.mSndBufUpdates = new SndBufUpdates[world.mNumSndBufs];
689 memset(world.mSndBufs, 0, world.mNumSndBufs*sizeof(SndBuf));
690 memset(world.mSndBufsNonRealTimeMirror, 0, world.mNumSndBufs*sizeof(SndBuf));
691 memset(world.mSndBufUpdates, 0, world.mNumSndBufs*sizeof(SndBufUpdates));
692 world.mBufCounter = 0;
694 async_buffer_guards.reset(new boost::mutex[world.mNumSndBufs]);
696 /* audio settings */
697 world.mBufLength = args.blocksize;
698 world.mSampleRate = args.samplerate;
700 initialize_rate(world.mFullRate, args.samplerate, args.blocksize);
701 initialize_rate(world.mBufRate, double(args.samplerate)/args.blocksize, 1);
703 world.mNumInputs = args.input_channels;
704 world.mNumOutputs = args.output_channels;
706 world.mRealTime = !args.non_rt;
709 void sc_plugin_interface::reset_sampling_rate(int sr)
711 world.mSampleRate = sr;
713 initialize_rate(world.mFullRate, sr, world.mBufLength);
714 initialize_rate(world.mBufRate, double(sr)/world.mBufLength, 1);
718 void sc_done_action_handler::update_nodegraph(void)
720 std::for_each(done_nodes.begin(), done_nodes.end(), boost::bind(&nova_server::free_node, instance, _1));
721 done_nodes.clear();
723 std::for_each(resume_nodes.begin(), resume_nodes.end(), boost::bind(&nova_server::node_resume, instance, _1));
724 resume_nodes.clear();
726 std::for_each(pause_nodes.begin(), pause_nodes.end(), boost::bind(&nova_server::node_pause, instance, _1));
727 pause_nodes.clear();
729 std::for_each(freeDeep_nodes.begin(), freeDeep_nodes.end(), boost::bind(&nova_server::group_free_deep, instance, _1));
730 freeDeep_nodes.clear();
732 std::for_each(freeAll_nodes.begin(), freeAll_nodes.end(), boost::bind(&nova_server::group_free_all, instance, _1));
733 freeAll_nodes.clear();
736 sc_plugin_interface::~sc_plugin_interface(void)
738 delete[] world.mAudioBusTouched;
739 delete[] world.mControlBus;
740 delete[] world.mControlBusTouched;
741 delete[] world.mSndBufs;
742 delete[] world.mSndBufsNonRealTimeMirror;
743 delete[] world.mSndBufUpdates;
744 delete world.mNRTLock;
747 namespace
750 sample * allocate_buffer(size_t samples)
752 const size_t alloc_size = samples * sizeof(sample);
753 sample * ret = (sample*)calloc_aligned(alloc_size);
754 if (ret)
755 mlock(ret, alloc_size);
756 return ret;
759 void free_buffer(sample * chunk)
761 free_aligned(chunk);
764 inline int32 bufmask(int32 x)
766 return (1 << (31 - CLZ(x))) - 1;
769 inline void sndbuf_init(SndBuf * buf)
771 buf->samplerate = 0;
772 buf->sampledur = 0;
773 buf->data = 0;
774 buf->channels = 0;
775 buf->samples = 0;
776 buf->frames = 0;
777 buf->mask = 0;
778 buf->mask1 = 0;
779 buf->coord = 0;
780 buf->sndfile = 0;
781 buf->isLocal = false;
784 inline void sndbuf_copy(SndBuf * dest, const SndBuf * src)
786 dest->samplerate = src->samplerate;
787 dest->sampledur = src->sampledur;
788 dest->data = src->data;
789 dest->channels = src->channels;
790 dest->samples = src->samples;
791 dest->frames = src->frames;
792 dest->mask = src->mask;
793 dest->mask1 = src->mask1;
794 dest->coord = src->coord;
795 dest->sndfile = src->sndfile;
796 dest->isLocal = src->isLocal;
799 static inline size_t compute_remaining_samples(size_t frames_per_read, size_t already_read, size_t total_frames)
801 int remain = frames_per_read;
802 if (already_read + frames_per_read > total_frames)
803 remain = total_frames - already_read;
804 return remain;
807 void read_channel(SndfileHandle & sf, uint32_t channel_count, const uint32_t * channel_data, uint32 total_frames, sample * data)
809 const unsigned int frames_per_read = 1024;
810 sized_array<sample> read_frame(sf.channels() * frames_per_read);
812 if (channel_count == 1) {
813 // fast-path for single-channel read
814 for (size_t i = 0; i < total_frames; i += frames_per_read) {
815 int remaining_samples = compute_remaining_samples(frames_per_read, i, total_frames);
816 size_t read = sf.readf(read_frame.c_array(), remaining_samples);
818 size_t channel_mapping = channel_data[0];
819 for (size_t frame = 0; frame != read; ++frame) {
820 data[0] = read_frame[frame * sf.channels() + channel_mapping];
821 data += channel_count;
824 } else {
825 for (size_t i = 0; i < total_frames; i += frames_per_read) {
826 int remaining_samples = compute_remaining_samples(frames_per_read, i, total_frames);
827 size_t read = sf.readf(read_frame.c_array(), remaining_samples);
829 for (size_t frame = 0; frame != read; ++frame) {
830 for (size_t c = 0; c != channel_count; ++c) {
831 size_t channel_mapping = channel_data[c];
832 data[c] = read_frame[frame * sf.channels() + channel_mapping];
834 data += channel_count;
840 } /* namespace */
842 int sc_plugin_interface::allocate_buffer(SndBuf * buf, uint32_t frames, uint32_t channels, double samplerate)
844 const uint32_t samples = frames * channels;
845 if (samples == 0)
846 return kSCErr_Failed; /* invalid buffer size */
848 sample * data = nova::allocate_buffer(samples);
849 if (data == NULL)
850 return kSCErr_Failed; /* could not allocate memory */
852 buf->data = data;
854 buf->channels = channels;
855 buf->frames = frames;
856 buf->samples = samples;
857 buf->mask = bufmask(samples); /* for delay lines */
858 buf->mask1 = buf->mask - 1; /* for oscillators */
859 buf->samplerate = samplerate;
860 buf->sampledur = 1.0 / samplerate;
861 buf->isLocal = false;
862 return kSCErr_None;
865 SndBuf * sc_plugin_interface::allocate_buffer(uint32_t index, uint32_t frames, uint32_t channels)
867 SndBuf * buf = World_GetNRTBuf(&world, index);
868 allocate_buffer(buf, frames, channels, world.mFullRate.mSampleRate);
869 return buf;
872 int sc_plugin_interface::buffer_read_alloc(uint32_t index, const char * filename, uint32_t start, uint32_t frames)
874 SndfileHandle f(filename);
875 if (!f)
876 return -1; /* file cannot be opened */
878 const size_t sf_frames = f.frames();
880 if (start > sf_frames)
881 start = sf_frames;
883 if (frames == 0 || frames > sf_frames - start)
884 frames = sf_frames - start;
886 SndBuf * buf = World_GetNRTBuf(&world, index);
887 allocate_buffer(buf, frames, f.channels(), f.samplerate());
889 f.seek(start, SEEK_SET);
890 f.readf(buf->data, frames);
891 return 0;
895 int sc_plugin_interface::buffer_alloc_read_channels(uint32_t index, const char * filename, uint32_t start,
896 uint32_t frames, uint32_t channel_count,
897 const uint32_t * channel_data)
899 SndfileHandle f(filename);
900 if (!f)
901 return -1; /* file cannot be opened */
903 uint32_t sf_channels = uint32_t(f.channels());
904 const uint32_t * max_chan = std::max_element(channel_data, channel_data + channel_count);
905 if (*max_chan >= sf_channels)
906 return -2;
908 const size_t sf_frames = f.frames();
910 if (start > sf_frames)
911 start = sf_frames;
913 if (frames == 0 || frames > sf_frames - start)
914 frames = sf_frames - start;
916 SndBuf * buf = World_GetNRTBuf(&world, index);
917 allocate_buffer(buf, frames, channel_count, f.samplerate());
919 f.seek(start, SEEK_SET);
920 read_channel(f, channel_count, channel_data, frames, buf->data);
922 return 0;
926 int sc_plugin_interface::buffer_write(uint32_t index, const char * filename, const char * header_format, const char * sample_format,
927 uint32_t start, uint32_t frames, bool leave_open)
929 SndBuf * buf = World_GetNRTBuf(&world, index);
930 int format = headerFormatFromString(header_format) | sampleFormatFromString(sample_format);
932 SndfileHandle sf(filename, SFM_WRITE, format, buf->channels, buf->samplerate);
934 if (!sf)
935 return -1;
937 if (frames == 0xffffffff)
938 frames = buf->frames;
940 const uint32_t remain = uint32_t(buf->frames) > start ? buf->frames - start : 0;
941 const uint32_t frames_to_write = std::min(remain, frames);
943 if (frames_to_write)
944 sf.writef(buf->data + start * buf->channels, frames_to_write);
946 if (leave_open && !buf->sndfile)
947 buf->sndfile = sf.takeOwnership();
949 return 0;
952 static int buffer_read_verify(SndfileHandle const & sf, size_t min_length, size_t samplerate)
954 if (!sf)
955 return -1;
956 if (sf.frames() < min_length)
957 return -2; /* no more frames to read */
958 if (sf.samplerate() != samplerate)
959 return -3; /* sample rate mismatch */
960 return 0;
963 int sc_plugin_interface::buffer_read(uint32_t index, const char * filename, uint32_t start_file, uint32_t frames,
964 uint32_t start_buffer, bool leave_open)
966 SndBuf * buf = World_GetNRTBuf(&world, index);
968 if (uint32_t(buf->frames) < start_buffer)
969 return -2; /* buffer already full */
971 SndfileHandle sf(filename, SFM_READ);
972 int error = buffer_read_verify(sf, start_file, buf->samplerate);
973 if (error)
974 return error;
976 if (sf.channels() != buf->channels)
977 return -3; /* sample rate or channel count mismatch */
979 const uint32_t buffer_remain = buf->frames - start_buffer;
980 const uint32_t file_remain = sf.frames() - start_file;
981 const uint32_t frames_to_read = std::min(frames, std::min(buffer_remain, file_remain));
983 sf.seek(start_file, SEEK_SET);
984 sf.readf(buf->data + start_buffer*buf->channels, frames_to_read);
986 if (leave_open)
987 buf->sndfile = sf.takeOwnership();
988 return 0;
991 int sc_plugin_interface::buffer_read_channel(uint32_t index, const char * filename, uint32_t start_file, uint32_t frames,
992 uint32_t start_buffer, bool leave_open, uint32_t channel_count,
993 const uint32_t * channel_data)
995 SndBuf * buf = World_GetNRTBuf(&world, index);
997 if (channel_count != uint32_t(buf->channels))
998 return -2; /* channel count mismatch */
1000 if (uint32_t(buf->frames) >= start_buffer)
1001 return -2; /* buffer already full */
1003 SndfileHandle sf(filename, SFM_READ);
1004 int error = buffer_read_verify(sf, start_file, buf->samplerate);
1005 if (error)
1006 return error;
1008 uint32_t sf_channels = uint32_t(sf.channels());
1009 const uint32_t * max_chan = std::max_element(channel_data, channel_data + channel_count);
1010 if (*max_chan >= sf_channels)
1011 return -2;
1012 const uint32_t buffer_remain = buf->frames - start_buffer;
1013 const uint32_t file_remain = sf.frames() - start_file;
1015 const uint32_t frames_to_read = std::min(frames, std::min(buffer_remain, file_remain));
1017 sf.seek(start_file, SEEK_SET);
1018 read_channel(sf, channel_count, channel_data, frames, buf->data);
1020 if (leave_open)
1021 buf->sndfile = sf.takeOwnership();
1022 return 0;
1025 void sc_plugin_interface::buffer_close(uint32_t index)
1027 SndBuf * buf = World_GetNRTBuf(&world, index);
1029 if (buf->sndfile == NULL)
1030 return;
1031 sf_close(buf->sndfile);
1032 buf->sndfile = NULL;
1036 void sc_plugin_interface::buffer_zero(uint32_t index)
1038 SndBuf * buf = World_GetNRTBuf(&world, index);
1040 uint32_t length = buf->frames * buf->channels;
1042 uint32_t unrolled = length & ~63;
1043 uint32_t remain = length & 63;
1045 zerovec_simd(buf->data, unrolled);
1046 zerovec(buf->data + unrolled, remain);
1049 sample * sc_plugin_interface::buffer_generate(uint32_t buffer_index, const char* cmd_name, struct sc_msg_iter & msg)
1051 return sc_factory->run_bufgen(&world, cmd_name, buffer_index, &msg);
1054 void sc_plugin_interface::buffer_sync(uint32_t index)
1056 sndbuf_copy(world.mSndBufs + index, world.mSndBufsNonRealTimeMirror + index);
1057 increment_write_updates(index);
1060 void sc_plugin_interface::free_buffer(uint32_t index)
1062 SndBuf * buf = world.mSndBufsNonRealTimeMirror + index;
1063 if (buf->sndfile)
1064 sf_close(buf->sndfile);
1065 sndbuf_init(buf);
1068 void sc_plugin_interface::initialize_synths_perform(void)
1070 for (std::size_t i = 0; i != uninitialized_synths.size(); ++i)
1072 sc_synth * synth = static_cast<sc_synth*>(uninitialized_synths[i]);
1073 if (likely(synth->get_parent())) // it is possible to remove a synth before it is initialized
1074 synth->prepare();
1075 synth->release();
1077 synths_to_initialize = false;
1078 uninitialized_synths.clear();
1081 } /* namespace nova */