Change PG_03 discussion of rests to use Rest()
[supercollider.git] / server / supernova / sc / sc_plugin_interface.cpp
blobcdb0b6db403f9b07665c082f8778edf51c1d7ebe
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 "clz.h"
39 #include "SC_fftlib.h"
40 #include "../../common/SC_SndFileHelpers.hpp"
42 // undefine the shadowed scfft functions
43 #undef scfft_create
44 #undef scfft_dofft
45 #undef scfft_doifft
46 #undef scfft_destroy
48 namespace nova {
50 spin_lock log_guard; // needs to be acquired for logging from the helper threads!
52 namespace {
54 inline Node * as_Node(server_node * node)
56 if (node == NULL)
57 return NULL;
59 // hack!!! we only assume that the 32bit integer mID member can be accessed via Node
60 if (node->is_synth()) {
61 sc_synth * s = static_cast<sc_synth*>(node);
62 return &s->mNode;
63 } else {
64 void * nodePointer = &node->node_id;
65 return (Node*)nodePointer;
69 void pause_node(Unit * unit)
71 server_node * node = static_cast<sc_synth*>(unit->mParent);
72 sc_factory->add_pause_node(node);
75 void free_node(Unit * unit)
77 server_node * node = static_cast<sc_synth*>(unit->mParent);
78 sc_factory->add_done_node(node);
81 void free_node_and_preceding(Unit * unit)
83 server_node * node = static_cast<sc_synth*>(unit->mParent);
84 sc_factory->add_done_node(node);
86 if (node->get_parent()->is_parallel()) {
87 spin_lock::scoped_lock lock(log_guard);
88 log("parallel groups have no notion of preceding nodes\n");
89 return;
92 server_node * preceding = node->previous_node();
93 if (preceding)
94 sc_factory->add_done_node(preceding);
97 void free_node_and_pause_preceding(Unit * unit)
99 server_node * node = static_cast<sc_synth*>(unit->mParent);
100 sc_factory->add_done_node(node);
102 if (node->get_parent()->is_parallel()) {
103 spin_lock::scoped_lock lock(log_guard);
104 log("parallel groups have no notion of preceding nodes\n");
105 return;
108 server_node * preceding = node->previous_node();
109 if (preceding)
110 sc_factory->add_pause_node(preceding);
113 void free_node_and_preceding_children(Unit * unit)
115 server_node * node = static_cast<sc_synth*>(unit->mParent);
116 sc_factory->add_done_node(node);
118 if (node->get_parent()->is_parallel()) {
119 spin_lock::scoped_lock lock(log_guard);
120 log("parallel groups have no notion of preceding nodes");
121 return;
124 server_node * preceding = node->previous_node();
125 if (!preceding)
126 return;
127 if (preceding->is_synth())
128 sc_factory->add_done_node(preceding);
129 else {
130 abstract_group * preceding_group = static_cast<abstract_group*>(preceding);
131 sc_factory->add_freeAll_node(preceding_group);
136 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);
141 if (node->get_parent()->is_parallel()) {
142 log("parallel groups have no notion of preceding nodes\n");
143 return;
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);
157 void free_node_and_all_preceding(Unit * unit)
159 server_node * node = static_cast<sc_synth*>(unit->mParent);
160 sc_factory->add_done_node(node);
162 if (node->get_parent()->is_parallel()) {
163 spin_lock::scoped_lock lock(log_guard);
164 log("parallel groups have no notion of preceding nodes\n");
165 return;
168 for(;;) {
169 node = node->previous_node();
170 if (node)
171 sc_factory->add_done_node(node);
172 else
173 return;
177 void free_node_and_following(Unit * unit)
179 server_node * node = static_cast<sc_synth*>(unit->mParent);
180 sc_factory->add_done_node(node);
182 if (node->get_parent()->is_parallel()) {
183 spin_lock::scoped_lock lock(log_guard);
184 log("parallel groups have no notion of following nodes\n");
185 return;
188 server_node * next = node->next_node();
189 if (next)
190 sc_factory->add_done_node(next);
193 void free_node_and_pause_following(Unit * unit)
195 server_node * node = static_cast<sc_synth*>(unit->mParent);
196 sc_factory->add_done_node(node);
198 if (node->get_parent()->is_parallel()) {
199 spin_lock::scoped_lock lock(log_guard);
200 log("parallel groups have no notion of following nodes\n");
201 return;
204 server_node * next = node->next_node();
205 if (next)
206 sc_factory->add_pause_node(next);
209 void free_node_and_following_children(Unit * unit)
211 server_node * node = static_cast<sc_synth*>(unit->mParent);
212 sc_factory->add_done_node(node);
214 if (node->get_parent()->is_parallel()) {
215 spin_lock::scoped_lock lock(log_guard);
216 log("parallel groups have no notion of following nodes\n");
217 return;
220 server_node * following = node->previous_node();
221 if (!following)
222 return;
223 if (following->is_synth())
224 sc_factory->add_done_node(following);
225 else {
226 abstract_group * following_group = static_cast<abstract_group*>(following);
227 sc_factory->add_freeAll_node(following_group);
231 void free_node_and_following_deep(Unit * unit)
233 server_node * node = static_cast<sc_synth*>(unit->mParent);
234 sc_factory->add_done_node(node);
236 if (node->get_parent()->is_parallel()) {
237 spin_lock::scoped_lock lock(log_guard);
238 log("parallel groups have no notion of following nodes\n");
239 return;
242 server_node * following = node->previous_node();
243 if (!following)
244 return;
245 if (following->is_synth())
246 sc_factory->add_done_node(following);
247 else {
248 abstract_group * following_group = static_cast<abstract_group*>(following);
249 sc_factory->add_freeDeep_node(following_group);
253 void free_node_and_all_following(Unit * unit)
255 server_node * node = static_cast<sc_synth*>(unit->mParent);
256 sc_factory->add_done_node(node);
258 if (node->get_parent()->is_parallel()) {
259 spin_lock::scoped_lock lock(log_guard);
260 log("parallel groups have no notion of following nodes\n");
261 return;
264 for(;;) {
265 node = node->previous_node();
266 if (node)
267 sc_factory->add_done_node(node);
268 else
269 return;
273 void free_group_members(Unit * unit)
275 server_node * node = static_cast<sc_synth*>(unit->mParent);
276 abstract_group * group = const_cast<abstract_group*>(node->get_parent());
278 sc_factory->add_freeAll_node(group);
281 void free_parent_group(Unit * unit)
283 server_node * node = static_cast<sc_synth*>(unit->mParent);
284 abstract_group * group = const_cast<abstract_group*>(node->get_parent());
285 sc_factory->add_done_node(group);
288 bool get_scope_buffer(World *inWorld, int index, int channels, int maxFrames, ScopeBufferHnd &hnd)
290 scope_buffer_writer writer = instance->get_scope_buffer_writer( index, channels, maxFrames );
292 if( writer.valid() ) {
293 hnd.internalData = writer.buffer;
294 hnd.data = writer.data();
295 hnd.channels = channels;
296 hnd.maxFrames = maxFrames;
297 return true;
299 else {
300 hnd.internalData = 0;
301 return false;
305 void push_scope_buffer(World *inWorld, ScopeBufferHnd &hnd, int frames)
307 scope_buffer_writer writer(reinterpret_cast<scope_buffer*>(hnd.internalData));
308 writer.push(frames);
309 hnd.data = writer.data();
312 void release_scope_buffer(World *inWorld, ScopeBufferHnd &hnd)
314 scope_buffer_writer writer(reinterpret_cast<scope_buffer*>(hnd.internalData));
315 instance->release_scope_buffer_writer( writer );
318 } /* namespace */
319 } /* namespace nova */
321 extern "C"
324 bool define_unit(const char *inUnitClassName, size_t inAllocSize,
325 UnitCtorFunc inCtor, UnitDtorFunc inDtor, uint32 inFlags)
327 try {
328 nova::sc_factory->register_ugen(inUnitClassName, inAllocSize, inCtor, inDtor, inFlags);
329 return true;
331 catch(...)
333 return false;
337 bool define_bufgen(const char * name, BufGenFunc func)
339 try {
340 nova::sc_factory->register_bufgen(name, func);
341 return true;
343 catch(...)
345 return false;
349 bool define_unitcmd(const char * unitClassName, const char * cmdName, UnitCmdFunc inFunc)
351 return nova::sc_factory->register_ugen_command_function(unitClassName, cmdName, inFunc);
355 bool define_plugincmd(const char * name, PlugInCmdFunc func, void * user_data)
357 return nova::sc_factory->register_cmd_plugin(name, func, user_data);
360 void * rt_alloc(World * dummy, size_t size)
362 if (size)
363 return nova::rt_pool.malloc(size);
364 else
365 return NULL;
368 void * rt_realloc(World * dummy, void * ptr, size_t size)
370 return nova::rt_pool.realloc(ptr, size);
373 void rt_free(World * dummy, void * ptr)
375 if (ptr)
376 nova::rt_pool.free(ptr);
379 void * nrt_alloc(size_t size)
381 return malloc(size);
384 void * nrt_realloc(void * ptr, size_t size)
386 return realloc(ptr, size);
389 void nrt_free(void * ptr)
391 free(ptr);
394 void clear_outputs(Unit *unit, int samples)
396 size_t outputs = unit->mNumOutputs;
398 if ((samples & 15) == 0)
399 for (size_t i=0; i!=outputs; ++i)
400 nova::zerovec_simd(OUT(i), samples);
401 else
402 for (size_t i=0; i!=outputs; ++i)
403 nova::zerovec(OUT(i), samples);
406 void node_end(struct Node * node)
408 nova::server_node * s = nova::instance->find_node(node->mID);
409 nova::sc_factory->add_done_node(s);
412 void node_set_run(struct Node * node, int run)
414 using namespace nova;
415 server_node * s = instance->find_node(node->mID);
417 if (run == 0)
418 sc_factory->add_pause_node(s);
419 else
420 sc_factory->add_resume_node(s);
424 int print(const char *fmt, ...)
426 va_list vargs;
427 va_start(vargs, fmt);
429 nova::log_guard.lock();
430 bool status = nova::instance->log_printf(fmt, vargs);
431 nova::log_guard.unlock();
433 va_end(vargs);
434 return (status == true) ? 0 : -1;
437 /* todo: we need to implement most of the done actions */
438 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;
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;
455 case 3:
456 // free both this synth and the preceding node
457 nova::free_node_and_preceding(unit);
458 return;
460 case 4:
461 // free both this synth and the following node
462 nova::free_node_and_following(unit);
463 return;
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;
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;
475 case 7:
476 //free this synth and all preceding nodes in this group
477 nova::free_node_and_all_preceding(unit);
478 return;
480 case 8:
481 //free this synth and all following nodes in this group
482 nova::free_node_and_all_following(unit);
483 return;
485 case 9:
486 // free this synth and pause the preceding node
487 nova::free_node_and_pause_preceding(unit);
488 return;
490 case 10:
491 // free this synth and pause the following node
492 nova::free_node_and_pause_following(unit);
493 return;
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;
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;
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;
510 case 14:
511 // free the enclosing group and all nodes within it (including this synth)
512 nova::free_parent_group(unit);
513 return;
515 default:
516 return;
520 int buf_alloc(SndBuf * buf, int channels, int frames, double samplerate)
522 return nova::sc_factory->allocate_buffer(buf, channels, frames, samplerate);
525 void send_trigger(Node * unit, int trigger_id, float value)
527 nova::instance->send_trigger(unit->mID, trigger_id, value);
530 void world_lock(World *world)
532 world->mNRTLock->Lock();
535 void world_unlock(World *world)
537 world->mNRTLock->Unlock();
540 Node * get_node(World *world, int id)
542 nova::server_node * node = nova::instance->find_node(id);
543 return nova::as_Node(node);
546 void send_node_reply(Node* node, int reply_id, const char* command_name, int argument_count, const float* values)
548 if (!nova::sc_factory->world.mRealTime)
549 return;
551 nova::instance->send_node_reply(node->mID, reply_id, command_name, argument_count, values);
554 int do_asynchronous_command(World *inWorld, void* replyAddr, const char* cmdName, void *cmdData,
555 AsyncStageFn stage2, // stage2 is non real time
556 AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true
557 AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true
558 AsyncFreeFn cleanup,
559 int completionMsgSize, void* completionMsgData)
561 nova::instance->do_asynchronous_command(inWorld, replyAddr, cmdName, cmdData,
562 stage2, stage3, stage4, cleanup,
563 completionMsgSize, completionMsgData);
564 return 0;
567 } /* extern "C" */
569 namespace nova
573 inline void initialize_rate(Rate & rate, double sample_rate, int blocksize)
575 rate.mSampleRate = sample_rate;
576 rate.mSampleDur = 1. / sample_rate;
577 rate.mRadiansPerSample = 2 * M_PI / sample_rate;
579 rate.mBufLength = blocksize;
580 rate.mBufDuration = blocksize / sample_rate;
581 rate.mBufRate = sample_rate / blocksize;
582 rate.mSlopeFactor = 1. / blocksize;
584 div_t div_result = std::div(blocksize, 3);
585 rate.mFilterLoops = div_result.quot;
586 rate.mFilterRemain = div_result.rem;
587 if (rate.mFilterLoops == 0.)
588 rate.mFilterSlope = 0.;
589 else
590 rate.mFilterSlope = 1. / rate.mFilterLoops;
594 void sc_plugin_interface::initialize(server_arguments const & args, float * control_busses)
596 done_nodes.reserve(64);
597 pause_nodes.reserve(16);
598 resume_nodes.reserve(16);
599 freeAll_nodes.reserve(16);
600 freeDeep_nodes.reserve(16);
602 /* define functions */
603 sc_interface.fDefineUnit = &define_unit;
604 sc_interface.fDefineBufGen = &define_bufgen;
605 sc_interface.fDefinePlugInCmd = &define_plugincmd;
606 sc_interface.fDefineUnitCmd = &define_unitcmd;
608 /* interface functions */
609 sc_interface.fNodeEnd = &node_end;
610 sc_interface.fGetNode = &get_node;
611 sc_interface.fNodeRun = &node_set_run;
612 sc_interface.fPrint = &print;
613 sc_interface.fDoneAction = &done_action;
615 /* sndfile functions */
616 #ifdef NO_LIBSNDFILE
617 sc_interface.fSndFileFormatInfoFromStrings = NULL;
618 #else
619 sc_interface.fSndFileFormatInfoFromStrings = &sndfileFormatInfoFromStrings;
620 #endif
622 /* wave tables */
623 sc_interface.mSine = gSine;
624 sc_interface.mCosecant = gInvSine;
625 sc_interface.mSineSize = kSineSize;
626 sc_interface.mSineWavetable = gSineWavetable;
628 /* memory allocation */
629 sc_interface.fRTAlloc = &rt_alloc;
630 sc_interface.fRTRealloc = &rt_realloc;
631 sc_interface.fRTFree = &rt_free;
633 sc_interface.fNRTAlloc = &nrt_alloc;
634 sc_interface.fNRTRealloc = &nrt_realloc;
635 sc_interface.fNRTFree = &nrt_free;
637 /* ugen functions */
638 sc_interface.fClearUnitOutputs = clear_outputs;
640 /* buffer functions */
641 sc_interface.fBufAlloc = &buf_alloc;
643 /* trigger functions */
644 sc_interface.fSendTrigger = &send_trigger;
645 sc_interface.fSendNodeReply = &send_node_reply;
647 /* world locks */
648 sc_interface.fNRTLock = &world_lock;
649 sc_interface.fNRTUnlock = &world_unlock;
650 world.mNRTLock = new SC_Lock();
652 /* fft library */
653 sc_interface.fSCfftCreate = &scfft_create;
654 sc_interface.fSCfftDestroy = &scfft_destroy;
655 sc_interface.fSCfftDoFFT = &scfft_dofft;
656 sc_interface.fSCfftDoIFFT = &scfft_doifft;
658 /* scope API */
659 sc_interface.fGetScopeBuffer = &get_scope_buffer;
660 sc_interface.fPushScopeBuffer = &push_scope_buffer;
661 sc_interface.fReleaseScopeBuffer = &release_scope_buffer;
663 /* osc plugins */
664 sc_interface.fDoAsynchronousCommand = &do_asynchronous_command;
666 /* initialize world */
667 /* control busses */
668 world.mControlBus = control_busses;
669 world.mNumControlBusChannels = args.control_busses;
670 world.mControlBusTouched = new int32[args.control_busses];
671 std::fill(world.mControlBusTouched, world.mControlBusTouched + args.control_busses, -1);
673 /* audio busses */
674 audio_busses.initialize(args.audio_busses, args.blocksize);
676 world.mAudioBus = audio_busses.buffers;
677 world.mNumAudioBusChannels = args.audio_busses;
678 world.mAudioBusTouched = new int32[args.audio_busses];
679 world.mAudioBusLocks = audio_busses.locks;
680 world.mControlBusLock = new spin_lock();
681 std::fill(world.mAudioBusTouched, world.mAudioBusTouched + args.audio_busses, -1);
683 /* audio buffers */
684 world.mNumSndBufs = args.buffers;
685 world.mSndBufs = new SndBuf[world.mNumSndBufs];
686 world.mSndBufsNonRealTimeMirror = new SndBuf[world.mNumSndBufs];
687 world.mSndBufUpdates = new SndBufUpdates[world.mNumSndBufs];
688 memset(world.mSndBufs, 0, world.mNumSndBufs*sizeof(SndBuf));
689 memset(world.mSndBufsNonRealTimeMirror, 0, world.mNumSndBufs*sizeof(SndBuf));
690 memset(world.mSndBufUpdates, 0, world.mNumSndBufs*sizeof(SndBufUpdates));
691 world.mBufCounter = 0;
693 async_buffer_guards.reset(new boost::mutex[world.mNumSndBufs]);
695 /* audio settings */
696 world.mBufLength = args.blocksize;
697 world.mSampleRate = args.samplerate;
699 initialize_rate(world.mFullRate, args.samplerate, args.blocksize);
700 initialize_rate(world.mBufRate, double(args.samplerate)/args.blocksize, 1);
702 world.mNumInputs = args.input_channels;
703 world.mNumOutputs = args.output_channels;
705 world.mRealTime = !args.non_rt;
708 void sc_plugin_interface::reset_sampling_rate(int sr)
710 world.mSampleRate = sr;
712 initialize_rate(world.mFullRate, sr, world.mBufLength);
713 initialize_rate(world.mBufRate, double(sr)/world.mBufLength, 1);
717 void sc_done_action_handler::update_nodegraph(void)
719 std::for_each(done_nodes.begin(), done_nodes.end(), boost::bind(&nova_server::free_node, instance, _1));
720 done_nodes.clear();
722 std::for_each(resume_nodes.begin(), resume_nodes.end(), boost::bind(&nova_server::node_resume, instance, _1));
723 resume_nodes.clear();
725 std::for_each(pause_nodes.begin(), pause_nodes.end(), boost::bind(&nova_server::node_pause, instance, _1));
726 pause_nodes.clear();
728 std::for_each(freeDeep_nodes.begin(), freeDeep_nodes.end(), boost::bind(&nova_server::group_free_deep, instance, _1));
729 freeDeep_nodes.clear();
731 std::for_each(freeAll_nodes.begin(), freeAll_nodes.end(), boost::bind(&nova_server::group_free_all, instance, _1));
732 freeAll_nodes.clear();
735 sc_plugin_interface::~sc_plugin_interface(void)
737 delete[] world.mAudioBusTouched;
738 delete[] world.mControlBus;
739 delete[] world.mControlBusTouched;
740 delete[] world.mSndBufs;
741 delete[] world.mSndBufsNonRealTimeMirror;
742 delete[] world.mSndBufUpdates;
743 delete world.mNRTLock;
746 namespace
749 sample * allocate_buffer(size_t samples)
751 const size_t alloc_size = samples * sizeof(sample);
752 sample * ret = (sample*)calloc_aligned(alloc_size);
753 if (ret)
754 mlock(ret, alloc_size);
755 return ret;
758 void free_buffer(sample * chunk)
760 free_aligned(chunk);
763 inline int32 bufmask(int32 x)
765 return (1 << (31 - CLZ(x))) - 1;
768 inline void sndbuf_init(SndBuf * buf)
770 buf->samplerate = 0;
771 buf->sampledur = 0;
772 buf->data = 0;
773 buf->channels = 0;
774 buf->samples = 0;
775 buf->frames = 0;
776 buf->mask = 0;
777 buf->mask1 = 0;
778 buf->coord = 0;
779 buf->sndfile = 0;
780 buf->isLocal = false;
783 inline void sndbuf_copy(SndBuf * dest, const SndBuf * src)
785 dest->samplerate = src->samplerate;
786 dest->sampledur = src->sampledur;
787 dest->data = src->data;
788 dest->channels = src->channels;
789 dest->samples = src->samples;
790 dest->frames = src->frames;
791 dest->mask = src->mask;
792 dest->mask1 = src->mask1;
793 dest->coord = src->coord;
794 dest->sndfile = src->sndfile;
795 dest->isLocal = src->isLocal;
798 static inline size_t compute_remaining_samples(size_t frames_per_read, size_t already_read, size_t total_frames)
800 int remain = frames_per_read;
801 if (already_read + frames_per_read > total_frames)
802 remain = total_frames - already_read;
803 return remain;
806 void read_channel(SndfileHandle & sf, uint32_t channel_count, const uint32_t * channel_data, uint32 total_frames, sample * data)
808 const unsigned int frames_per_read = 1024;
809 sized_array<sample> read_frame(sf.channels() * frames_per_read);
811 if (channel_count == 1) {
812 // fast-path for single-channel read
813 for (size_t i = 0; i < total_frames; i += frames_per_read) {
814 int remaining_samples = compute_remaining_samples(frames_per_read, i, total_frames);
815 size_t read = sf.readf(read_frame.c_array(), remaining_samples);
817 size_t channel_mapping = channel_data[0];
818 for (size_t frame = 0; frame != read; ++frame) {
819 data[0] = read_frame[frame * sf.channels() + channel_mapping];
820 data += channel_count;
823 } else {
824 for (size_t i = 0; i < total_frames; i += frames_per_read) {
825 int remaining_samples = compute_remaining_samples(frames_per_read, i, total_frames);
826 size_t read = sf.readf(read_frame.c_array(), remaining_samples);
828 for (size_t frame = 0; frame != read; ++frame) {
829 for (size_t c = 0; c != channel_count; ++c) {
830 size_t channel_mapping = channel_data[c];
831 data[c] = read_frame[frame * sf.channels() + channel_mapping];
833 data += channel_count;
839 } /* namespace */
841 int sc_plugin_interface::allocate_buffer(SndBuf * buf, uint32_t frames, uint32_t channels, double samplerate)
843 const uint32_t samples = frames * channels;
844 if (samples == 0)
845 return kSCErr_Failed; /* invalid buffer size */
847 sample * data = nova::allocate_buffer(samples);
848 if (data == NULL)
849 return kSCErr_Failed; /* could not allocate memory */
851 buf->data = data;
853 buf->channels = channels;
854 buf->frames = frames;
855 buf->samples = samples;
856 buf->mask = bufmask(samples); /* for delay lines */
857 buf->mask1 = buf->mask - 1; /* for oscillators */
858 buf->samplerate = samplerate;
859 buf->sampledur = 1.0 / samplerate;
860 buf->isLocal = false;
861 return kSCErr_None;
864 SndBuf * sc_plugin_interface::allocate_buffer(uint32_t index, uint32_t frames, uint32_t channels)
866 SndBuf * buf = World_GetNRTBuf(&world, index);
867 allocate_buffer(buf, frames, channels, world.mFullRate.mSampleRate);
868 return buf;
871 int sc_plugin_interface::buffer_read_alloc(uint32_t index, const char * filename, uint32_t start, uint32_t frames)
873 SndfileHandle f(filename);
874 if (!f)
875 return -1; /* file cannot be opened */
877 const size_t sf_frames = f.frames();
879 if (start > sf_frames)
880 start = sf_frames;
882 if (frames == 0 || frames > sf_frames - start)
883 frames = sf_frames - start;
885 SndBuf * buf = World_GetNRTBuf(&world, index);
886 allocate_buffer(buf, frames, f.channels(), f.samplerate());
888 f.seek(start, SEEK_SET);
889 f.readf(buf->data, frames);
890 return 0;
894 int sc_plugin_interface::buffer_alloc_read_channels(uint32_t index, const char * filename, uint32_t start,
895 uint32_t frames, uint32_t channel_count,
896 const uint32_t * channel_data)
898 SndfileHandle f(filename);
899 if (!f)
900 return -1; /* file cannot be opened */
902 uint32_t sf_channels = uint32_t(f.channels());
903 const uint32_t * max_chan = std::max_element(channel_data, channel_data + channel_count);
904 if (*max_chan >= sf_channels)
905 return -2;
907 const size_t sf_frames = f.frames();
909 if (start > sf_frames)
910 start = sf_frames;
912 if (frames == 0 || frames > sf_frames - start)
913 frames = sf_frames - start;
915 SndBuf * buf = World_GetNRTBuf(&world, index);
916 allocate_buffer(buf, frames, channel_count, f.samplerate());
918 f.seek(start, SEEK_SET);
919 read_channel(f, channel_count, channel_data, frames, buf->data);
921 return 0;
925 int sc_plugin_interface::buffer_write(uint32_t index, const char * filename, const char * header_format, const char * sample_format,
926 uint32_t start, uint32_t frames, bool leave_open)
928 SndBuf * buf = World_GetNRTBuf(&world, index);
929 int format = headerFormatFromString(header_format) | sampleFormatFromString(sample_format);
931 SndfileHandle sf(filename, SFM_WRITE, format, buf->channels, buf->samplerate);
933 if (!sf)
934 return -1;
936 if (frames == 0xffffffff)
937 frames = buf->frames;
939 const uint32_t remain = uint32_t(buf->frames) > start ? buf->frames - start : 0;
940 const uint32_t frames_to_write = std::min(remain, frames);
942 if (frames_to_write)
943 sf.writef(buf->data + start * buf->channels, frames_to_write);
945 if (leave_open && !buf->sndfile)
946 buf->sndfile = sf.takeOwnership();
948 return 0;
951 static int buffer_read_verify(SndfileHandle const & sf, size_t min_length, size_t samplerate)
953 if (!sf)
954 return -1;
955 if (sf.frames() < min_length)
956 return -2; /* no more frames to read */
957 if (sf.samplerate() != samplerate)
958 return -3; /* sample rate mismatch */
959 return 0;
962 int sc_plugin_interface::buffer_read(uint32_t index, const char * filename, uint32_t start_file, uint32_t frames,
963 uint32_t start_buffer, bool leave_open)
965 SndBuf * buf = World_GetNRTBuf(&world, index);
967 if (uint32_t(buf->frames) < start_buffer)
968 return -2; /* buffer already full */
970 SndfileHandle sf(filename, SFM_READ);
971 int error = buffer_read_verify(sf, start_file, buf->samplerate);
972 if (error)
973 return error;
975 if (sf.channels() != buf->channels)
976 return -3; /* sample rate or channel count mismatch */
978 const uint32_t buffer_remain = buf->frames - start_buffer;
979 const uint32_t file_remain = sf.frames() - start_file;
980 const uint32_t frames_to_read = std::min(frames, std::min(buffer_remain, file_remain));
982 sf.seek(start_file, SEEK_SET);
983 sf.readf(buf->data + start_buffer*buf->channels, frames_to_read);
985 if (leave_open)
986 buf->sndfile = sf.takeOwnership();
987 return 0;
990 int sc_plugin_interface::buffer_read_channel(uint32_t index, const char * filename, uint32_t start_file, uint32_t frames,
991 uint32_t start_buffer, bool leave_open, uint32_t channel_count,
992 const uint32_t * channel_data)
994 SndBuf * buf = World_GetNRTBuf(&world, index);
996 if (channel_count != uint32_t(buf->channels))
997 return -2; /* channel count mismatch */
999 if (uint32_t(buf->frames) >= start_buffer)
1000 return -2; /* buffer already full */
1002 SndfileHandle sf(filename, SFM_READ);
1003 int error = buffer_read_verify(sf, start_file, buf->samplerate);
1004 if (error)
1005 return error;
1007 uint32_t sf_channels = uint32_t(sf.channels());
1008 const uint32_t * max_chan = std::max_element(channel_data, channel_data + channel_count);
1009 if (*max_chan >= sf_channels)
1010 return -2;
1011 const uint32_t buffer_remain = buf->frames - start_buffer;
1012 const uint32_t file_remain = sf.frames() - start_file;
1014 const uint32_t frames_to_read = std::min(frames, std::min(buffer_remain, file_remain));
1016 sf.seek(start_file, SEEK_SET);
1017 read_channel(sf, channel_count, channel_data, frames, buf->data);
1019 if (leave_open)
1020 buf->sndfile = sf.takeOwnership();
1021 return 0;
1024 void sc_plugin_interface::buffer_close(uint32_t index)
1026 SndBuf * buf = World_GetNRTBuf(&world, index);
1028 if (buf->sndfile == NULL)
1029 return;
1030 sf_close(buf->sndfile);
1031 buf->sndfile = NULL;
1035 void sc_plugin_interface::buffer_zero(uint32_t index)
1037 SndBuf * buf = World_GetNRTBuf(&world, index);
1039 uint32_t length = buf->frames * buf->channels;
1041 uint32_t unrolled = length & ~63;
1042 uint32_t remain = length & 63;
1044 zerovec_simd(buf->data, unrolled);
1045 zerovec(buf->data + unrolled, remain);
1048 sample * sc_plugin_interface::buffer_generate(uint32_t buffer_index, const char* cmd_name, struct sc_msg_iter & msg)
1050 return sc_factory->run_bufgen(&world, cmd_name, buffer_index, &msg);
1053 void sc_plugin_interface::buffer_sync(uint32_t index)
1055 sndbuf_copy(world.mSndBufs + index, world.mSndBufsNonRealTimeMirror + index);
1056 increment_write_updates(index);
1059 void sc_plugin_interface::free_buffer(uint32_t index)
1061 SndBuf * buf = world.mSndBufsNonRealTimeMirror + index;
1062 if (buf->sndfile)
1063 sf_close(buf->sndfile);
1064 sndbuf_init(buf);
1067 void sc_plugin_interface::initialize_synths_perform(void)
1069 for (std::size_t i = 0; i != uninitialized_synths.size(); ++i)
1071 sc_synth * synth = static_cast<sc_synth*>(uninitialized_synths[i]);
1072 if (likely(synth->get_parent())) // it is possible to remove a synth before it is initialized
1073 synth->prepare();
1074 synth->release();
1076 synths_to_initialize = false;
1077 uninitialized_synths.clear();
1080 } /* namespace nova */