1 // interface for supercollider plugins
2 // Copyright (C) 2009, 2010 Tim Blechmann
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; see the file COPYING. If not, write to
16 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 // Boston, MA 02111-1307, USA.
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"
36 #include "SC_Prototypes.h"
37 #include "SC_Errors.h"
39 #include "SC_fftlib.h"
40 #include "../../common/SC_SndFileHelpers.hpp"
42 // undefine the shadowed scfft functions
50 spin_lock log_guard
; // needs to be acquired for logging from the helper threads!
54 inline Node
* as_Node(server_node
* node
)
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
);
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");
92 server_node
* preceding
= node
->previous_node();
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");
108 server_node
* preceding
= node
->previous_node();
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");
124 server_node
* preceding
= node
->previous_node();
127 if (preceding
->is_synth())
128 sc_factory
->add_done_node(preceding
);
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");
146 server_node
* preceding
= node
->previous_node();
149 if (preceding
->is_synth())
150 sc_factory
->add_done_node(preceding
);
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");
169 node
= node
->previous_node();
171 sc_factory
->add_done_node(node
);
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");
188 server_node
* next
= node
->next_node();
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");
204 server_node
* next
= node
->next_node();
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");
220 server_node
* following
= node
->previous_node();
223 if (following
->is_synth())
224 sc_factory
->add_done_node(following
);
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");
242 server_node
* following
= node
->previous_node();
245 if (following
->is_synth())
246 sc_factory
->add_done_node(following
);
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");
265 node
= node
->previous_node();
267 sc_factory
->add_done_node(node
);
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
;
300 hnd
.internalData
= 0;
305 void push_scope_buffer(World
*inWorld
, ScopeBufferHnd
&hnd
, int frames
)
307 scope_buffer_writer
writer(reinterpret_cast<scope_buffer
*>(hnd
.internalData
));
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
);
319 } /* namespace nova */
324 bool define_unit(const char *inUnitClassName
, size_t inAllocSize
,
325 UnitCtorFunc inCtor
, UnitDtorFunc inDtor
, uint32 inFlags
)
328 nova::sc_factory
->register_ugen(inUnitClassName
, inAllocSize
, inCtor
, inDtor
, inFlags
);
337 bool define_bufgen(const char * name
, BufGenFunc func
)
340 nova::sc_factory
->register_bufgen(name
, func
);
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
)
363 return nova::rt_pool
.malloc(size
);
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
)
376 nova::rt_pool
.free(ptr
);
379 void * nrt_alloc(size_t size
)
384 void * nrt_realloc(void * ptr
, size_t size
)
386 return realloc(ptr
, size
);
389 void nrt_free(void * 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
);
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
);
418 sc_factory
->add_pause_node(s
);
420 sc_factory
->add_resume_node(s
);
424 int print(const char *fmt
, ...)
427 va_start(vargs
, fmt
);
429 nova::log_guard
.lock();
430 bool status
= nova::instance
->log_printf(fmt
, vargs
);
431 nova::log_guard
.unlock();
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
) {
443 // do nothing when the UGen is finished
447 // pause the enclosing synth, but do not free it
448 nova::pause_node(unit
);
451 // free the enclosing synth
452 nova::free_node(unit
);
456 // free both this synth and the preceding node
457 nova::free_node_and_preceding(unit
);
461 // free both this synth and the following node
462 nova::free_node_and_following(unit
);
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
);
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
476 //free this synth and all preceding nodes in this group
477 nova::free_node_and_all_preceding(unit
);
481 //free this synth and all following nodes in this group
482 nova::free_node_and_all_following(unit
);
486 // free this synth and pause the preceding node
487 nova::free_node_and_pause_preceding(unit
);
491 // free this synth and pause the following node
492 nova::free_node_and_pause_following(unit
);
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
);
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
);
506 // free this synth and all other nodes in this group (before and after)
507 nova::free_group_members(unit
);
511 // free the enclosing group and all nodes within it (including this synth)
512 nova::free_parent_group(unit
);
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
)
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
559 int completionMsgSize
, void* completionMsgData
)
561 nova::instance
->do_asynchronous_command(inWorld
, replyAddr
, cmdName
, cmdData
,
562 stage2
, stage3
, stage4
, cleanup
,
563 completionMsgSize
, completionMsgData
);
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.;
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 */
617 sc_interface
.fSndFileFormatInfoFromStrings
= NULL
;
619 sc_interface
.fSndFileFormatInfoFromStrings
= &sndfileFormatInfoFromStrings
;
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
;
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
;
648 sc_interface
.fNRTLock
= &world_lock
;
649 sc_interface
.fNRTUnlock
= &world_unlock
;
650 world
.mNRTLock
= new SC_Lock();
653 sc_interface
.fSCfftCreate
= &scfft_create
;
654 sc_interface
.fSCfftDestroy
= &scfft_destroy
;
655 sc_interface
.fSCfftDoFFT
= &scfft_dofft
;
656 sc_interface
.fSCfftDoIFFT
= &scfft_doifft
;
659 sc_interface
.fGetScopeBuffer
= &get_scope_buffer
;
660 sc_interface
.fPushScopeBuffer
= &push_scope_buffer
;
661 sc_interface
.fReleaseScopeBuffer
= &release_scope_buffer
;
664 sc_interface
.fDoAsynchronousCommand
= &do_asynchronous_command
;
666 /* initialize world */
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);
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);
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
]);
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
));
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
));
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
;
749 sample
* allocate_buffer(size_t samples
)
751 const size_t alloc_size
= samples
* sizeof(sample
);
752 sample
* ret
= (sample
*)calloc_aligned(alloc_size
);
754 mlock(ret
, alloc_size
);
758 void free_buffer(sample
* chunk
)
763 inline int32
bufmask(int32 x
)
765 return (1 << (31 - CLZ(x
))) - 1;
768 inline void sndbuf_init(SndBuf
* buf
)
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
;
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
;
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
;
841 int sc_plugin_interface::allocate_buffer(SndBuf
* buf
, uint32_t frames
, uint32_t channels
, double samplerate
)
843 const uint32_t samples
= frames
* channels
;
845 return kSCErr_Failed
; /* invalid buffer size */
847 sample
* data
= nova::allocate_buffer(samples
);
849 return kSCErr_Failed
; /* could not allocate memory */
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;
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
);
871 int sc_plugin_interface::buffer_read_alloc(uint32_t index
, const char * filename
, uint32_t start
, uint32_t frames
)
873 SndfileHandle
f(filename
);
875 return -1; /* file cannot be opened */
877 const size_t sf_frames
= f
.frames();
879 if (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
);
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
);
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
)
907 const size_t sf_frames
= f
.frames();
909 if (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
);
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
);
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
);
943 sf
.writef(buf
->data
+ start
* buf
->channels
, frames_to_write
);
945 if (leave_open
&& !buf
->sndfile
)
946 buf
->sndfile
= sf
.takeOwnership();
951 static int buffer_read_verify(SndfileHandle
const & sf
, size_t min_length
, size_t samplerate
)
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 */
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
);
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
);
986 buf
->sndfile
= sf
.takeOwnership();
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
);
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
)
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
);
1020 buf
->sndfile
= sf
.takeOwnership();
1024 void sc_plugin_interface::buffer_close(uint32_t index
)
1026 SndBuf
* buf
= World_GetNRTBuf(&world
, index
);
1028 if (buf
->sndfile
== NULL
)
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
;
1063 sf_close(buf
->sndfile
);
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
1076 synths_to_initialize
= false;
1077 uninitialized_synths
.clear();
1080 } /* namespace nova */