1 // osc handler for supercollider-style communication, implementation
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.
21 #include "osc/OscOutboundPacketStream.h"
22 #include "osc/OscPrintReceivedElements.h"
24 #include "sc_msg_iter.h"
25 #include "sc_osc_handler.hpp"
26 #include "../server/server.hpp"
27 #include "utilities/sized_array.hpp"
29 #include "SC_OSC_Commands.h"
37 int32_t last_generated
= 0;
39 server_node
* find_node(int32_t target_id
)
42 target_id
= last_generated
;
44 server_node
* node
= instance
->find_node(target_id
);
47 log_printf("node not found: %d\n", target_id
);
52 abstract_group
* find_group(int32_t target_id
)
55 target_id
= last_generated
;
57 abstract_group
* node
= instance
->find_group(target_id
);
60 log("node not found or not a group\n");
64 bool check_node_id(int node_id
)
66 if (!instance
->node_id_available(node_id
)) {
67 log("node id %d already in use\n", node_id
);
73 void fill_notification(const server_node
* node
, osc::OutboundPacketStream
& p
)
78 const abstract_group
* parent_node
= node
->get_parent();
80 p
<< parent_node
->id();
83 if (parent_node
->is_parallel())
84 p
<< -2 << -2; /* we are in a parallel group, so we have no notion of previous/next */
87 const server_node
* prev_node
= node
->previous_node();
93 const server_node
* next_node
= node
->next_node();
100 /* is_synth, head, tail */
101 if (node
->is_synth())
104 const abstract_group
* node_group
= static_cast<const abstract_group
*>(node
);
107 if (node_group
->is_parallel())
111 const group
* node_real_group
= static_cast<const group
*>(node_group
);
112 if (node_real_group
->empty())
115 p
<< node_real_group
->head_node()->id()
116 << node_real_group
->tail_node()->id();
120 p
<< osc::EndMessage
;
123 spin_lock system_callback_allocator_lock
;
125 struct movable_string
127 /** allocate new string, only allowed to be called from the rt context */
128 explicit movable_string(const char * str
)
130 size_t length
= strlen(str
) + 1; /* terminating \0 */
131 char * data
= (char*)system_callback::allocate(length
);
136 /** copy constructor has move semantics!!! */
137 movable_string(movable_string
const & rhs
)
140 const_cast<movable_string
&>(rhs
).data_
= NULL
;
143 ~movable_string(void)
146 system_callback::deallocate((char*)data_
);
149 const char * c_str(void) const
158 template <typename T
>
161 /** allocate new array, only allowed to be called from the rt context */
162 movable_array(size_t length
, const T
* data
, bool locked
= false):
165 data_
= (T
*)system_callback::allocate(length
* sizeof(T
));
166 for (size_t i
= 0; i
!= length
; ++i
)
170 /** copy constructor has move semantics!!! */
171 movable_array(movable_array
const & rhs
)
173 length_
= rhs
.length_
;
175 const_cast<movable_array
&>(rhs
).data_
= NULL
;
181 system_callback::deallocate((char*)data_
);
184 const T
* data(void) const
189 const T
& operator[](size_t index
) const
194 size_t size(void) const
204 void send_done_message(nova_endpoint
const & endpoint
)
207 osc::OutboundPacketStream
p(buffer
, 128);
208 p
<< osc::BeginMessage("/done")
211 instance
->send(p
.Data(), p
.Size(), endpoint
);
214 void send_done_message(nova_endpoint
const & endpoint
, const char * cmd
)
217 osc::OutboundPacketStream
p(buffer
, 128);
218 p
<< osc::BeginMessage("/done")
222 instance
->send(p
.Data(), p
.Size(), endpoint
);
225 void send_done_message(nova_endpoint
const & endpoint
, const char * cmd
, osc::int32 index
)
228 osc::OutboundPacketStream
p(buffer
, 128);
229 p
<< osc::BeginMessage("/done")
234 instance
->send(p
.Data(), p
.Size(), endpoint
);
237 template <typename Functor
>
238 struct fn_system_callback
:
239 public system_callback
241 fn_system_callback (Functor
const & fn
):
253 template <typename Functor
>
254 struct fn_sync_callback
:
255 public audio_sync_callback
257 fn_sync_callback (Functor
const & fn
):
269 /** helper class for dispatching real-time and non real-time osc command callbacks
271 * uses template specialization to avoid unnecessary callback rescheduling
273 template <bool realtime
>
274 struct cmd_dispatcher
276 template <typename Functor
>
277 static void fire_system_callback(Functor
const & f
)
279 instance
->add_system_callback(new fn_system_callback
<Functor
>(f
));
282 template <typename Functor
>
283 static void fire_io_callback(Functor
const & f
)
285 instance
->add_io_callback(new fn_system_callback
<Functor
>(f
));
288 template <typename Functor
>
289 static void fire_rt_callback(Functor
const & f
)
291 instance
->add_sync_callback(new fn_sync_callback
<Functor
>(f
));
294 static void fire_done_message(nova_endpoint
const & endpoint
, const char * cmd
, osc::int32 index
)
296 fire_io_callback(boost::bind(send_done_message
, endpoint
, cmd
, index
));
301 struct cmd_dispatcher
<false>
303 template <typename Functor
>
304 static void fire_system_callback(Functor f
)
309 template <typename Functor
>
310 static void fire_rt_callback(Functor f
)
315 template <typename Functor
>
316 static void fire_io_callback(Functor f
)
321 static void fire_done_message(nova_endpoint
const & endpoint
, const char * cmd
, osc::int32 index
)
323 send_done_message (endpoint
, cmd
, index
);
332 void fire_notification(movable_array
<char> & msg
)
334 instance
->send_notification(msg
.data(), msg
.size());
337 void sc_notify_observers::notify(const char * address_pattern
, const server_node
* node
)
339 char buffer
[128]; // 128 byte should be enough
340 osc::OutboundPacketStream
p(buffer
, 128);
341 p
<< osc::BeginMessage(address_pattern
);
342 fill_notification(node
, p
);
344 movable_array
<char> message(p
.Size(), p
.Data());
345 cmd_dispatcher
<true>::fire_io_callback(boost::bind(fire_notification
, message
));
348 void fire_trigger(int32_t node_id
, int32_t trigger_id
, float value
)
350 char buffer
[128]; // 128 byte should be enough
351 osc::OutboundPacketStream
p(buffer
, 128);
352 p
<< osc::BeginMessage("/tr") << osc::int32(node_id
) << osc::int32(trigger_id
) << value
355 instance
->send_notification(p
.Data(), p
.Size());
358 void sc_notify_observers::send_trigger(int32_t node_id
, int32_t trigger_id
, float value
)
360 cmd_dispatcher
<true>::fire_io_callback(boost::bind(fire_trigger
, node_id
, trigger_id
, value
));
363 void free_mem_callback(movable_string
& cmd
,
364 movable_array
<float> & values
)
367 void fire_node_reply(int32_t node_id
, int reply_id
, movable_string
& cmd
,
368 movable_array
<float> & values
)
370 size_t buffer_size
= 1024 + strlen(cmd
.c_str()) + values
.size()*sizeof(float);
372 char * buffer
= (buffer_size
< 2048) ? (char*)alloca(buffer_size
)
373 : (char*)malloc(buffer_size
);
376 osc::OutboundPacketStream
p(buffer
, buffer_size
);
377 p
<< osc::BeginMessage(cmd
.c_str()) << osc::int32(node_id
) << osc::int32(reply_id
);
379 for (int i
= 0; i
!= values
.size(); ++i
)
382 p
<< osc::EndMessage
;
384 instance
->send_notification(p
.Data(), p
.Size());
386 cmd_dispatcher
<true>::fire_rt_callback(boost::bind(free_mem_callback
, cmd
, values
));
390 if (buffer_size
>= 2048)
394 void sc_notify_observers::send_node_reply(int32_t node_id
, int reply_id
, const char* command_name
,
395 int argument_count
, const float* values
)
397 spin_lock::scoped_lock
lock(system_callback_allocator_lock
); // called from rt helper threads, so we need to lock the memory pool
398 movable_string
cmd(command_name
);
399 movable_array
<float> value_array(argument_count
, values
);
401 cmd_dispatcher
<true>::fire_io_callback(boost::bind(fire_node_reply
, node_id
, reply_id
, cmd
, value_array
));
404 void sc_notify_observers::send_notification(const char * data
, size_t length
)
406 for (size_t i
= 0; i
!= observers
.size(); ++i
)
407 send_notification(data
, length
, observers
[i
]);
410 void sc_notify_observers::send_notification(const char * data
, size_t length
, nova_endpoint
const & endpoint
)
412 nova_protocol
const & prot
= endpoint
.protocol();
413 if (prot
.family() == AF_INET
&& prot
.type() == SOCK_DGRAM
)
415 udp::endpoint
ep(endpoint
.address(), endpoint
.port());
416 send_udp(data
, length
, ep
);
418 else if (prot
.family() == AF_INET
&& prot
.type() == SOCK_STREAM
)
420 tcp::endpoint
ep(endpoint
.address(), endpoint
.port());
421 send_tcp(data
, length
, ep
);
427 void sc_scheduled_bundles::bundle_node::run(void)
429 typedef osc::ReceivedBundleElement bundle_element
;
430 typedef osc::ReceivedBundle received_bundle
;
431 typedef osc::ReceivedMessage received_message
;
433 bundle_element
element(data_
);
435 if (element
.IsBundle()) {
436 received_bundle
bundle(element
);
437 instance
->handle_bundle
<true>(bundle
, endpoint_
);
439 received_message
message(element
);
440 instance
->handle_message
<true>(message
, element
.Size(), endpoint_
);
444 void sc_scheduled_bundles::insert_bundle(time_tag
const & timeout
, const char * data
, size_t length
,
445 nova_endpoint
const & endpoint
)
447 /* allocate chunk from realtime pool */
448 void * chunk
= rt_pool
.malloc(sizeof(bundle_node
) + length
+4);
449 bundle_node
* node
= (bundle_node
*)chunk
;
450 char * cpy
= (char*)chunk
+ sizeof(bundle_node
);
452 memcpy(cpy
, data
- 4, length
+4);
454 new(node
) bundle_node(timeout
, cpy
, endpoint
);
456 bundle_q
.insert(*node
);
459 void sc_scheduled_bundles::execute_bundles(time_tag
const & last
, time_tag
const & now
)
461 World
* world
= &sc_factory
->world
;
463 while(!bundle_q
.empty()) {
464 bundle_node
& front
= *bundle_q
.top();
465 time_tag
const & next_timestamp
= front
.timeout_
;
467 if (now
< next_timestamp
)
470 if (last
< next_timestamp
) {
471 // between last and now
472 time_tag time_since_last
= next_timestamp
- last
;
473 float samples_since_last
= time_since_last
.to_samples(world
->mSampleRate
);
476 float subsample_offset
= std::modf(samples_since_last
, &sample_offset
);
478 world
->mSampleOffset
= (int)sample_offset
;
479 world
->mSubsampleOffset
= subsample_offset
;
481 world
->mSampleOffset
= world
->mSubsampleOffset
= 0;
484 bundle_q
.erase_and_dispose(bundle_q
.top(), &dispose_bundle
);
487 world
->mSampleOffset
= world
->mSubsampleOffset
= 0;
491 void sc_osc_handler::open_tcp_acceptor(tcp
const & protocol
, unsigned int port
)
493 tcp_acceptor_
.open(protocol
);
494 tcp_acceptor_
.bind(tcp::endpoint(protocol
, port
));
495 tcp_acceptor_
.listen();
498 void sc_osc_handler::open_udp_socket(udp
const & protocol
, unsigned int port
)
500 sc_notify_observers::udp_socket
.open(protocol
);
501 sc_notify_observers::udp_socket
.bind(udp::endpoint(protocol
, port
));
504 bool sc_osc_handler::open_socket(int family
, int type
, int protocol
, unsigned int port
)
506 if (protocol
== IPPROTO_TCP
)
508 if ( type
!= SOCK_STREAM
)
511 if (family
== AF_INET
)
512 open_tcp_acceptor(tcp::v4(), port
);
513 else if (family
== AF_INET6
)
514 open_tcp_acceptor(tcp::v6(), port
);
519 else if (protocol
== IPPROTO_UDP
)
521 if ( type
!= SOCK_DGRAM
)
524 if (family
== AF_INET
)
525 open_udp_socket(udp::v4(), port
);
526 else if (family
== AF_INET6
)
527 open_udp_socket(udp::v6(), port
);
536 void sc_osc_handler::handle_receive_udp(const boost::system::error_code
& error
,
537 std::size_t bytes_transferred
)
539 if (unlikely(error
== error::operation_aborted
))
540 return; /* we're done */
542 if (error
== error::message_size
) {
543 overflow_vector
.insert(overflow_vector
.end(),
544 recv_buffer_
.begin(), recv_buffer_
.end());
549 std::cout
<< "sc_osc_handler received error code " << error
<< std::endl
;
554 if (overflow_vector
.empty())
555 handle_packet_async(recv_buffer_
.begin(), bytes_transferred
, udp_remote_endpoint_
);
557 overflow_vector
.insert(overflow_vector
.end(), recv_buffer_
.begin(), recv_buffer_
.end());
559 handle_packet_async(&overflow_vector
.front(), overflow_vector
.size(), udp_remote_endpoint_
);
561 handle_packet_async(overflow_vector
.data(), overflow_vector
.size(), udp_remote_endpoint_
);
563 overflow_vector
.clear();
570 void sc_osc_handler::tcp_connection::start(sc_osc_handler
* self
)
572 bool check_password
= true;
574 if (check_password
) {
575 boost::array
<char, 32> password
;
578 for (unsigned int i
=0; i
!=4; ++i
) {
579 size
= socket_
.receive(boost::asio::buffer(&msglen
, 4));
583 msglen
= ntohl(msglen
);
584 if (msglen
> password
.size())
587 size
= socket_
.receive(boost::asio::buffer(password
.data(), msglen
));
589 bool verified
= true;
590 if (size
!= msglen
||
591 strcmp(password
.data(), self
->tcp_password_
) != 0)
595 throw std::runtime_error("cannot verify password");
601 size
= socket_
.receive(boost::asio::buffer(&msglen
, 4));
602 if (size
!= sizeof(uint32_t))
603 throw std::runtime_error("read error");
605 msglen
= ntohl(msglen
);
607 sized_array
<char> recv_vector(msglen
+ sizeof(uint32_t));
609 std::memcpy((void*)recv_vector
.data(), &msglen
, sizeof(uint32_t));
610 size_t transfered
= socket_
.read_some(boost::asio::buffer((void*)(recv_vector
.data()+sizeof(uint32_t)),
611 recv_vector
.size()-sizeof(uint32_t)));
613 if (transfered
!= size_t(msglen
))
614 throw std::runtime_error("socket read sanity check failure");
616 self
->handle_packet_async(recv_vector
.data(), recv_vector
.size(), socket_
.remote_endpoint());
620 void sc_osc_handler::handle_packet_async(const char * data
, size_t length
,
621 nova_endpoint
const & endpoint
)
623 received_packet
* p
= received_packet::alloc_packet(data
, length
, endpoint
);
625 if (dump_osc_packets
== 1) {
626 osc_received_packet
packet (data
, length
);
627 cout
<< "received osc packet " << packet
<< endl
;
630 instance
->add_sync_callback(p
);
633 time_tag
sc_osc_handler::handle_bundle_nrt(const char * data
, size_t length
)
635 osc_received_packet
packet(data
, length
);
636 if (!packet
.IsBundle())
637 throw std::runtime_error("packet needs to be an osc bundle");
639 received_bundle
bundle(packet
);
640 handle_bundle
<false> (bundle
, nova_endpoint());
641 return bundle
.TimeTag();
645 sc_osc_handler::received_packet
*
646 sc_osc_handler::received_packet::alloc_packet(const char * data
, size_t length
,
647 nova_endpoint
const & remote_endpoint
)
649 /* received_packet struct and data array are located in one memory chunk */
650 void * chunk
= received_packet::allocate(sizeof(received_packet
) + length
);
651 received_packet
* p
= (received_packet
*)chunk
;
652 char * cpy
= (char*)(chunk
) + sizeof(received_packet
);
653 memcpy(cpy
, data
, length
);
655 new(p
) received_packet(cpy
, length
, remote_endpoint
);
659 void sc_osc_handler::received_packet::run(void)
661 instance
->handle_packet(data
, length
, endpoint_
);
664 void sc_osc_handler::handle_packet(const char * data
, std::size_t length
, nova_endpoint
const & endpoint
)
666 osc_received_packet
packet(data
, length
);
667 if (packet
.IsBundle())
669 received_bundle
bundle(packet
);
670 handle_bundle
<true> (bundle
, endpoint
);
674 received_message
message(packet
);
675 handle_message
<true> (message
, packet
.Size(), endpoint
);
679 template <bool realtime
>
680 void sc_osc_handler::handle_bundle(received_bundle
const & bundle
, nova_endpoint
const & endpoint
)
682 time_tag bundle_time
= bundle
.TimeTag();
684 typedef osc::ReceivedBundleElementIterator bundle_iterator
;
685 typedef osc::ReceivedBundleElement bundle_element
;
687 if (bundle_time
<= now
) {
688 for (bundle_iterator it
= bundle
.ElementsBegin(); it
!= bundle
.ElementsEnd(); ++it
) {
689 bundle_element
const & element
= *it
;
691 if (element
.IsBundle()) {
692 received_bundle
inner_bundle(element
);
693 handle_bundle
<realtime
>(inner_bundle
, endpoint
);
695 received_message
message(element
);
696 handle_message
<realtime
>(message
, element
.Size(), endpoint
);
700 for (bundle_iterator it
= bundle
.ElementsBegin(); it
!= bundle
.ElementsEnd(); ++it
) {
701 bundle_element
const & element
= *it
;
702 scheduled_bundles
.insert_bundle(bundle_time
, element
.Contents(), element
.Size(), endpoint
);
707 template <bool realtime
>
708 void sc_osc_handler::handle_message(received_message
const & message
, size_t msg_size
,
709 nova_endpoint
const & endpoint
)
712 if (message
.AddressPatternIsUInt32())
713 handle_message_int_address
<realtime
>(message
, msg_size
, endpoint
);
715 handle_message_sym_address
<realtime
>(message
, msg_size
, endpoint
);
716 } catch (std::exception
const & e
) {
717 log_printf("exception in handle_message: %s\n", e
.what());
723 typedef sc_osc_handler::received_message received_message
;
725 void send_udp_message(movable_array
<char> data
, nova_endpoint
const & endpoint
)
727 instance
->send(data
.data(), data
.size(), endpoint
);
731 int first_arg_as_int(received_message
const & message
)
733 osc::ReceivedMessageArgumentStream args
= message
.ArgumentStream();
741 void quit_perform(nova_endpoint
const & endpoint
)
743 send_done_message(endpoint
, "/quit");
744 instance
->terminate();
747 template <bool realtime
>
748 void handle_quit(nova_endpoint
const & endpoint
)
750 instance
->quit_received
= true;
751 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(quit_perform
, endpoint
));
754 void notify_perform(bool enable
, nova_endpoint
const & endpoint
)
757 instance
->add_observer(endpoint
);
759 instance
->remove_observer(endpoint
);
760 send_done_message(endpoint
, "/notify");
763 template <bool realtime
>
764 void handle_notify(received_message
const & message
, nova_endpoint
const & endpoint
)
766 int enable
= first_arg_as_int(message
);
767 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(notify_perform
, bool(enable
), endpoint
));
770 void status_perform(nova_endpoint
const & endpoint
)
772 if (unlikely(instance
->quit_received
)) // we don't reply once we are about to quit
776 typedef osc::int32 i32
;
778 float peak_load
, average_load
;
779 instance
->cpu_load(peak_load
, average_load
);
781 osc::OutboundPacketStream
p(buffer
, 1024);
782 p
<< osc::BeginMessage("/status.reply")
783 << (i32
)1 /* unused */
784 << (i32
)sc_factory
->ugen_count() /* ugens */
785 << (i32
)instance
->synth_count() /* synths */
786 << (i32
)instance
->group_count() /* groups */
787 << (i32
)instance
->prototype_count() /* synthdefs */
788 << average_load
/* average cpu % */
789 << peak_load
/* peak cpu % */
790 << instance
->get_samplerate() /* nominal samplerate */
791 << instance
->get_samplerate() /* actual samplerate */
794 instance
->send(p
.Data(), p
.Size(), endpoint
);
797 template <bool realtime
>
798 void handle_status(nova_endpoint
const & endpoint
)
800 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(status_perform
, endpoint
));
803 void handle_dumpOSC(received_message
const & message
)
805 int val
= first_arg_as_int(message
);
806 val
= min (1, val
); /* we just support one way of dumping osc messages */
808 instance
->dumpOSC(val
); /* thread-safe */
811 void sync_perform(osc::int32 id
, nova_endpoint
const & endpoint
)
814 osc::OutboundPacketStream
p(buffer
, 128);
815 p
<< osc::BeginMessage("/synced")
819 instance
->send(p
.Data(), p
.Size(), endpoint
);
822 template <bool realtime
>
823 void handle_sync(received_message
const & message
, nova_endpoint
const & endpoint
)
825 int id
= first_arg_as_int(message
);
827 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(sync_perform
, id
, endpoint
));
830 void handle_clearSched(void)
832 instance
->clear_scheduled_bundles();
835 void handle_error(received_message
const & message
)
837 int val
= first_arg_as_int(message
);
839 instance
->set_error_posting(val
); /* thread-safe */
842 void handle_unhandled_message(received_message
const & msg
)
844 log_printf("unhandled message: %s\n", msg
.AddressPattern());
847 static bool node_position_sanity_check(node_position_constraint
const & constraint
)
849 switch (constraint
.second
) {
853 server_node
* target
= constraint
.first
;
854 if (!target
->is_group()) {
855 log_printf("Invalid position constraint (target: %d, addAction: %d)\n", target
->id(), constraint
.second
);
864 sc_synth
* add_synth(const char * name
, int node_id
, int action
, int target_id
)
866 if (!check_node_id(node_id
))
869 server_node
* target
= find_node(target_id
);
873 node_position_constraint pos
= make_pair(target
, node_position(action
));
874 if (!node_position_sanity_check(pos
))
877 abstract_synth
* synth
= instance
->add_synth(name
, node_id
, pos
);
879 log_printf("Cannot create synth (synthdef: %s, node id: %d)\n", name
, node_id
);
881 last_generated
= node_id
;
882 return static_cast<sc_synth
*>(synth
);
885 /* extract float or int32 as float from argument iterator */
886 inline float extract_float_argument(osc::ReceivedMessageArgumentIterator
const & it
)
889 return it
->AsFloatUnchecked();
891 return float(it
->AsInt32Unchecked());
893 return float(it
->AsInt64Unchecked());
895 throw std::runtime_error("type cannot be converted to float");
898 inline void verify_argument(osc::ReceivedMessageArgumentIterator
const & it
,
899 osc::ReceivedMessageArgumentIterator
const & end
)
902 throw std::runtime_error("unexpected end of argument list");
905 template <bool IsAudio
, typename slot_type
>
906 static void apply_control_bus_mapping(server_node
& node
, slot_type slot
, int bus_index
);
908 template <typename control_id_type
>
909 void set_control_array(server_node
* node
, control_id_type control
, osc::ReceivedMessageArgumentIterator
& it
)
911 size_t array_size
= it
->ArraySize(); ++it
;
913 if (it
->IsArrayStart()) {
914 // nested arrays are basically user errors, but we handle them like normal arrays
915 log("Warning in /s_new handler: nested array argument detected");
916 set_control_array
<control_id_type
>(node
, control
, it
);
919 for (size_t i
= 0; i
!= array_size
; ++i
) {
920 if (it
->IsString() || it
->IsSymbol()) {
921 char const * name
= it
->AsStringUnchecked(); ++it
;
926 bus_id
= atoi(name
+1);
927 static_cast<sc_synth
*>(node
)->map_control_bus
<false>(control
, i
, bus_id
);
931 bus_id
= atoi(name
+1);
932 static_cast<sc_synth
*>(node
)->map_control_bus
<true>(control
, i
, bus_id
);
936 throw runtime_error("invalid name for control mapping");
939 float value
= extract_float_argument(it
++);
940 node
->set_control_array_element(control
, i
, value
);
945 if (!it
->IsArrayEnd())
946 throw runtime_error("missing array end tag");
947 ++it
; // skip array end
950 template <typename ControlSpecifier
>
951 void set_control(server_node
* node
, ControlSpecifier
const & control
, osc::ReceivedMessageArgumentIterator
& it
)
953 if (it
->IsArrayStart())
954 set_control_array(node
, control
, it
);
955 else if (it
->IsString() || it
->IsSymbol()) {
956 char const * name
= it
->AsStringUnchecked(); ++it
;
961 bus_id
= atoi(name
+1);
962 apply_control_bus_mapping
<false>(*node
, control
, bus_id
);
966 bus_id
= atoi(name
+1);
967 apply_control_bus_mapping
<true>(*node
, control
, bus_id
);
971 throw runtime_error("invalid name for control mapping");
975 float value
= extract_float_argument(it
++);
976 node
->set(control
, value
);
980 /* set control values of node from string/float or int/float pair */
981 void set_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
, osc::ReceivedMessageArgumentIterator end
)
984 osc::int32 index
= it
->AsInt32Unchecked(); ++it
;
985 if (it
== end
) return; // sclang sometimes uses an integer instead of an empty argument list
986 set_control(node
, index
, it
);
987 } else if (it
->IsString()) {
988 const char * str
= it
->AsStringUnchecked(); ++it
;
989 set_control(node
, str
, it
);
991 throw runtime_error("invalid argument");
994 void handle_s_new(received_message
const & msg
)
996 osc::ReceivedMessageArgumentIterator args
= msg
.ArgumentsBegin(), end
= msg
.ArgumentsEnd();
998 const char * def_name
= args
->AsString(); ++args
;
999 int32_t id
= args
->AsInt32(); ++args
;
1002 id
= instance
->generate_node_id();
1004 int32_t action
, target
;
1007 action
= args
->AsInt32(); ++args
;
1012 target
= args
->AsInt32(); ++args
;
1016 sc_synth
* synth
= add_synth(def_name
, id
, action
, target
);
1023 set_control(synth
, args
, end
);
1024 } catch(std::exception
& e
) {
1025 log_printf("exception in /s_new: %s\n", e
.what());
1030 void handle_g_new(received_message
const & msg
)
1032 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1034 while(!args
.Eos()) {
1035 osc::int32 node_id
, action
, target_id
;
1036 args
>> node_id
>> action
>> target_id
;
1039 node_id
= instance
->generate_node_id();
1040 else if (!check_node_id(node_id
))
1043 server_node
* target
= find_node(target_id
);
1048 node_position_constraint pos
= make_pair(target
, node_position(action
));
1049 if (!node_position_sanity_check(pos
))
1052 instance
->add_group(node_id
, pos
);
1053 last_generated
= node_id
;
1057 void handle_g_freeall(received_message
const & msg
)
1059 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1066 abstract_group
* group
= find_group(id
);
1070 bool success
= instance
->group_free_all(group
);
1073 log("/g_freeAll failue\n");
1077 void handle_g_deepFree(received_message
const & msg
)
1079 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1086 abstract_group
* group
= find_group(id
);
1090 bool success
= instance
->group_free_deep(group
);
1093 log("/g_freeDeep failue\n");
1097 void g_query_tree_fill_node(osc::OutboundPacketStream
& p
, bool flag
, server_node
const & node
)
1099 p
<< osc::int32(node
.id());
1100 if (node
.is_synth())
1103 p
<< osc::int32(static_cast<abstract_group
const &>(node
).child_count());
1105 if (node
.is_synth()) {
1106 sc_synth
const & scsynth
= static_cast<sc_synth
const&>(node
);
1107 p
<< scsynth
.prototype_name();
1110 osc::int32 controls
= scsynth
.mNumControls
;
1113 for (int i
= 0; i
!= controls
; ++i
) {
1114 p
<< osc::int32(i
); /** \todo later we can return symbols */
1116 if (scsynth
.mMapControls
[i
] != (scsynth
.mControls
+i
)) {
1117 /* we use a bus mapping */
1118 int bus
= (scsynth
.mMapControls
[i
]) - (scsynth
.mNode
.mWorld
->mControlBus
);
1120 sprintf(str
, "s%d", bus
);
1124 p
<< scsynth
.mControls
[i
];
1128 abstract_group
const & group
= static_cast<abstract_group
const &>(node
);
1129 group
.apply_on_children(boost::bind(g_query_tree_fill_node
, boost::ref(p
), flag
, _1
));
1133 template <bool realtime
>
1134 void g_query_tree(int node_id
, bool flag
, nova_endpoint
const & endpoint
)
1136 server_node
* node
= find_node(node_id
);
1137 if (!node
|| node
->is_synth())
1140 abstract_group
* group
= static_cast<abstract_group
*>(node
);
1142 size_t max_msg_size
= 1<<16;
1145 if (max_msg_size
> 1<<22)
1148 sized_array
<char, rt_pool_allocator
<char> > data(max_msg_size
);
1150 osc::OutboundPacketStream
p(data
.c_array(), max_msg_size
);
1151 p
<< osc::BeginMessage("/g_queryTree.reply")
1154 << osc::int32(group
->child_count());
1156 group
->apply_on_children(boost::bind(g_query_tree_fill_node
, boost::ref(p
), flag
, _1
));
1157 p
<< osc::EndMessage
;
1159 movable_array
<char> message(p
.Size(), data
.c_array());
1160 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
1165 max_msg_size
*= 2; /* if we run out of memory, retry with doubled memory resources */
1170 template <bool realtime
>
1171 void handle_g_queryTree(received_message
const & msg
, nova_endpoint
const & endpoint
)
1173 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1178 osc::int32 id
, flag
;
1180 g_query_tree
<realtime
>(id
, flag
, endpoint
);
1182 catch (std::exception
& e
) {
1183 log_printf("exception in handle_g_queryTree: %s\n", e
.what());
1188 typedef std::basic_stringstream
<char,
1189 std::char_traits
<char>/*,
1190 rt_pool_allocator<char>*/ > rt_string_stream
;
1192 void fill_spaces(rt_string_stream
& stream
, int level
)
1194 for (int i
= 0; i
!= level
*3; ++i
)
1198 void g_dump_node(rt_string_stream
& stream
, server_node
& node
, bool flag
, int level
)
1200 using namespace std
;
1201 fill_spaces(stream
, level
);
1203 if (node
.is_synth()) {
1204 abstract_synth
const & synth
= static_cast<abstract_synth
const &>(node
);
1205 stream
<< synth
.id() << " " << synth
.prototype_name() << endl
;
1211 abstract_group
& group
= static_cast<abstract_group
&>(node
);
1212 stream
<< group
.id();
1214 if (group
.is_parallel())
1215 stream
<< " parallel group";
1219 group
.apply_on_children(boost::bind(g_dump_node
, boost::ref(stream
), _1
, flag
, level
+ 1));
1223 void g_dump_tree(int id
, bool flag
)
1225 server_node
* node
= find_node(id
);
1229 // FIXME: can we completely avoid all internal allocations?
1230 rt_string_stream stream
;
1231 stream
<< "NODE TREE Group " << id
<< std::endl
;
1233 g_dump_node(stream
, *node
, flag
, 1);
1234 log(stream
.str().c_str(), stream
.str().size());
1237 void handle_g_dumpTree(received_message
const & msg
)
1239 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1244 osc::int32 id
, flag
;
1246 g_dump_tree(id
, flag
);
1248 catch (std::exception
& e
) {
1249 log_printf("exception in /g_dumpTree: %s\n", e
.what());
1254 void handle_n_free(received_message
const & msg
)
1256 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1264 server_node
* node
= find_node(id
);
1268 instance
->free_node(node
);
1270 catch (std::exception
& e
) {
1271 log_printf("exception in /n_free: %s\n", e
.what());
1276 /** macro to define an os command handler with a starting node id
1278 * it is mainly intended as decorator to avoid duplicate error handling code
1280 #define HANDLE_N_DECORATOR(cmd, function) \
1281 void handle_n_##cmd(received_message const & msg) \
1283 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); \
1284 osc::int32 id = it->AsInt32(); ++it; \
1286 server_node * node = find_node(id); \
1291 while (it != msg.ArgumentsEnd()) \
1292 function(node, it); \
1293 } catch(std::exception & e) { \
1294 log_printf("Exception during /n_" #cmd "handler: %s\n", e.what());\
1298 void set_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1300 if (it
->IsInt32()) {
1301 osc::int32 index
= it
->AsInt32Unchecked(); ++it
;
1302 set_control(node
, index
, it
);
1303 } else if (it
->IsString()) {
1304 const char * str
= it
->AsStringUnchecked(); ++it
;
1305 set_control(node
, str
, it
);
1307 throw runtime_error("invalid argument");
1311 HANDLE_N_DECORATOR(set
, set_control
)
1313 void set_control_n(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1315 if (it
->IsInt32()) {
1316 osc::int32 index
= it
->AsInt32Unchecked(); ++it
;
1317 osc::int32 count
= it
->AsInt32(); ++it
;
1319 for (int i
= 0; i
!= count
; ++i
)
1320 node
->set(index
+ i
, extract_float_argument(it
++));
1322 else if (it
->IsString()) {
1323 const char * str
= it
->AsStringUnchecked(); ++it
;
1324 osc::int32 count
= it
->AsInt32(); ++it
;
1326 sized_array
<float> values(count
);
1327 for (int i
= 0; i
!= count
; ++i
)
1328 values
[i
] = extract_float_argument(it
++);
1330 node
->set_control_array(str
, count
, values
.c_array());
1332 throw runtime_error("invalid argument");
1335 HANDLE_N_DECORATOR(setn
, set_control_n
)
1337 void fill_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1339 if (it
->IsInt32()) {
1340 osc::int32 index
= it
->AsInt32Unchecked(); ++it
;
1341 osc::int32 count
= it
->AsInt32(); ++it
;
1342 float value
= extract_float_argument(it
++);
1344 for (int i
= 0; i
!= count
; ++i
)
1345 node
->set(index
+ i
, value
);
1347 else if (it
->IsString()) {
1348 const char * str
= it
->AsStringUnchecked(); ++it
;
1349 osc::int32 count
= it
->AsInt32(); ++it
;
1350 float value
= extract_float_argument(it
++);
1352 sized_array
<float> values(count
);
1353 for (int i
= 0; i
!= count
; ++i
)
1356 node
->set_control_array(str
, count
, values
.c_array());
1358 throw runtime_error("invalid argument");
1361 HANDLE_N_DECORATOR(fill
, fill_control
)
1363 template <bool IsAudio
, typename slot_type
>
1364 void apply_control_bus_mapping(server_node
& node
, slot_type slot
, int bus_index
)
1366 if (node
.is_synth())
1367 static_cast<sc_synth
&>(node
).map_control_bus
<IsAudio
>(slot
, bus_index
);
1369 static_cast<abstract_group
&>(node
).apply_on_children(boost::bind(apply_control_bus_mapping
<IsAudio
, slot_type
>, _1
,
1373 template <bool IsAudio
, typename slot_type
>
1374 void apply_control_busn_mapping(server_node
& node
, slot_type slot
, int bus_index
, int count
)
1376 if (node
.is_synth())
1377 static_cast<sc_synth
&>(node
).map_control_buses
<IsAudio
>(slot
, bus_index
, count
);
1379 static_cast<abstract_group
&>(node
).apply_on_children(boost::bind(apply_control_busn_mapping
<IsAudio
, slot_type
>, _1
,
1380 slot
, bus_index
, count
));
1383 template <bool IsAudio
>
1384 void map_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1386 if (it
->IsInt32()) {
1387 osc::int32 control_index
= it
->AsInt32Unchecked(); ++it
;
1388 osc::int32 control_bus_index
= it
->AsInt32(); ++it
;
1390 apply_control_bus_mapping
<IsAudio
>(*node
, control_index
, control_bus_index
);
1392 else if (it
->IsString()) {
1393 const char * control_name
= it
->AsStringUnchecked(); ++it
;
1394 osc::int32 control_bus_index
= it
->AsInt32(); ++it
;
1396 apply_control_bus_mapping
<IsAudio
>(*node
, control_name
, control_bus_index
);
1398 throw runtime_error("invalid argument");
1401 template <bool IsAudio
>
1402 void mapn_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1404 if (it
->IsInt32()) {
1405 osc::int32 control_index
= it
->AsInt32Unchecked(); ++it
;
1406 osc::int32 bus_index
= it
->AsInt32(); ++it
;
1407 osc::int32 count
= it
->AsInt32(); ++it
;
1409 apply_control_busn_mapping
<IsAudio
>(*node
, control_index
, bus_index
, count
);
1411 else if (it
->IsString()) {
1412 const char * control_name
= it
->AsStringUnchecked(); ++it
;
1413 osc::int32 bus_index
= it
->AsInt32(); ++it
;
1414 osc::int32 count
= it
->AsInt32(); ++it
;
1416 apply_control_busn_mapping
<IsAudio
>(*node
, control_name
, bus_index
, count
);
1418 throw runtime_error("invalid argument");
1422 HANDLE_N_DECORATOR(map
, map_control
<false>)
1423 HANDLE_N_DECORATOR(mapa
, map_control
<true>)
1424 HANDLE_N_DECORATOR(mapn
, mapn_control
<false>)
1425 HANDLE_N_DECORATOR(mapan
, mapn_control
<true>)
1427 template <nova::node_position Relation
>
1428 void handle_n_before_or_after(received_message
const & msg
)
1430 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1432 while(!args
.Eos()) {
1433 osc::int32 node_a
, node_b
;
1434 args
>> node_a
>> node_b
;
1436 server_node
* a
= find_node(node_a
);
1439 server_node
* b
= find_node(node_b
);
1442 abstract_group::move_before_or_after
<Relation
>(a
, b
);
1448 template <nova::node_position Position
>
1449 void handle_g_head_or_tail(received_message
const & msg
)
1451 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1453 while(!args
.Eos()) {
1454 osc::int32 node_id
, target_id
;
1455 args
>> target_id
>> node_id
;
1457 server_node
* node
= find_node(node_id
);
1458 if (!node
) continue;
1460 abstract_group
* target_group
= find_group(target_id
);
1461 if (!target_group
) continue;
1463 abstract_group::move_to_head_or_tail
<Position
>(node
, target_group
);
1469 void handle_n_query(received_message
const & msg
, nova_endpoint
const & endpoint
)
1471 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1478 server_node
* node
= find_node(node_id
);
1482 char buffer
[128]; // 128 byte should be enough
1483 osc::OutboundPacketStream
p(buffer
, 128);
1484 p
<< osc::BeginMessage("/n_info");
1485 fill_notification(node
, p
);
1487 movable_array
<char> message(p
.Size(), p
.Data());
1488 cmd_dispatcher
<true>::fire_system_callback(boost::bind(send_udp_message
, message
, endpoint
));
1492 void handle_n_order(received_message
const & msg
)
1494 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1496 osc::int32 action
, target_id
;
1497 args
>> action
>> target_id
;
1499 server_node
* target
= find_node(target_id
);
1504 abstract_group
* target_parent
;
1505 if (action
== before
||
1507 target_parent
= target
->get_parent();
1509 if (target
->is_synth())
1510 throw std::runtime_error("invalid argument for n_order: argument is no synth");
1511 target_parent
= static_cast<abstract_group
*>(target
);
1519 server_node
* node
= find_node(node_id
);
1523 abstract_group
* node_parent
= node
->get_parent();
1525 /** \todo this can be optimized if node_parent == target_parent */
1526 node_parent
->remove_child(node
);
1527 if (action
== before
||
1529 target_parent
->add_child(node
, make_pair(target
, node_position(action
)));
1531 target_parent
->add_child(node
, node_position(action
));
1533 instance
->update_dsp_queue();
1537 void handle_n_run(received_message
const & msg
)
1539 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1541 while(!args
.Eos()) {
1542 osc::int32 node_id
, run_flag
;
1543 args
>> node_id
>> run_flag
;
1545 server_node
* node
= find_node(node_id
);
1550 instance
->node_resume(node
);
1552 instance
->node_pause(node
);
1556 void enable_tracing(server_node
& node
)
1558 if (node
.is_synth()) {
1559 sc_synth
& synth
= static_cast<sc_synth
&>(node
);
1560 synth
.enable_tracing();
1562 abstract_group
& group
= static_cast<abstract_group
&>(node
);
1563 group
.apply_on_children(enable_tracing
);
1567 void handle_n_trace(received_message
const & msg
)
1569 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1571 while(!args
.Eos()) {
1575 server_node
* node
= find_node(node_id
);
1579 enable_tracing(*node
);
1584 void handle_s_noid(received_message
const & msg
)
1586 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1588 while(!args
.Eos()) {
1591 instance
->synth_reassign_id(node_id
);
1595 int32_t get_control_index(sc_synth
* s
, osc::ReceivedMessageArgumentIterator
& it
, osc::OutboundPacketStream
& p
)
1600 control
= it
->AsInt32Unchecked(); ++it
;
1603 else if (it
->IsString())
1605 const char * control_str
= it
->AsStringUnchecked(); ++it
;
1606 control
= s
->resolve_slot(control_str
);
1609 else if (it
->IsSymbol())
1611 const char * control_str
= it
->AsSymbolUnchecked(); ++it
;
1612 control
= s
->resolve_slot(control_str
);
1613 p
<< osc::Symbol(control_str
);
1616 throw std::runtime_error("wrong argument type");
1620 template <bool realtime
>
1621 void handle_s_get(received_message
const & msg
, size_t msg_size
, nova_endpoint
const & endpoint
)
1623 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
1626 throw std::runtime_error("wrong argument type");
1628 int32_t node_id
= it
->AsInt32Unchecked(); ++it
;
1630 server_node
* node
= find_node(node_id
);
1631 if (!node
|| !node
->is_synth())
1632 throw std::runtime_error("node is not a synth");
1634 sc_synth
* s
= static_cast<sc_synth
*>(node
);
1636 size_t alloc_size
= msg_size
+ sizeof(float) * (msg
.ArgumentCount()-1) + 128;
1638 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
1640 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
1641 p
<< osc::BeginMessage("/n_set")
1644 while (it
!= msg
.ArgumentsEnd())
1646 int32_t control
= get_control_index(s
, it
, p
);
1647 p
<< s
->get(control
);
1649 p
<< osc::EndMessage
;
1651 movable_array
<char> message(p
.Size(), return_message
.c_array());
1652 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
1655 template <bool realtime
>
1656 void handle_s_getn(received_message
const & msg
, size_t msg_size
, nova_endpoint
const & endpoint
)
1658 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
1661 throw std::runtime_error("wrong argument type");
1663 int32_t node_id
= it
->AsInt32Unchecked(); ++it
;
1665 server_node
* node
= find_node(node_id
);
1666 if (!node
|| !node
->is_synth())
1667 throw std::runtime_error("node is not a synth");
1669 sc_synth
* s
= static_cast<sc_synth
*>(node
);
1671 /* count argument values */
1672 size_t argument_count
= 0;
1673 for (osc::ReceivedMessageArgumentIterator local
= it
; local
!= msg
.ArgumentsEnd(); ++local
)
1675 ++local
; /* skip control */
1676 if (local
== msg
.ArgumentsEnd())
1679 throw std::runtime_error("invalid count");
1680 argument_count
+= it
->AsInt32Unchecked(); ++it
;
1683 size_t alloc_size
= msg_size
+ sizeof(float) * (argument_count
) + 128;
1685 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
1687 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
1688 p
<< osc::BeginMessage("/n_setn")
1691 while (it
!= msg
.ArgumentsEnd())
1693 int32_t control
= get_control_index(s
, it
, p
);
1696 throw std::runtime_error("integer argument expected");
1698 int32_t control_count
= it
->AsInt32Unchecked(); ++it
;
1699 if (control_count
< 0)
1702 for (int i
= 0; i
!= control_count
; ++i
)
1703 p
<< s
->get(control
+ i
);
1705 p
<< osc::EndMessage
;
1707 movable_array
<char> message(p
.Size(), return_message
.c_array());
1708 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
1712 /** wrapper class for osc completion message
1714 struct completion_message
1716 /** constructor should only be used from the real-time thread */
1717 completion_message(size_t size
, const void * data
):
1721 data_
= system_callback::allocate(size
);
1722 memcpy(data_
, data
, size
);
1726 /** default constructor creates uninitialized object */
1727 completion_message(void):
1731 /** copy constructor has move semantics!!! */
1732 completion_message(completion_message
const & rhs
)
1737 completion_message
& operator=(completion_message
const & rhs
)
1741 const_cast<completion_message
&>(rhs
).size_
= 0;
1745 ~completion_message(void)
1748 system_callback::deallocate(data_
);
1751 /** handle package in the rt thread
1752 * not to be called from the rt thread
1754 void trigger_async(nova_endpoint
const & endpoint
)
1757 sc_osc_handler::received_packet
* p
=
1758 sc_osc_handler::received_packet::alloc_packet((char*)data_
, size_
, endpoint
);
1759 instance
->add_sync_callback(p
);
1763 /** handle package directly
1764 * only to be called from the rt thread
1766 void handle(nova_endpoint
const & endpoint
)
1769 instance
->handle_packet((char*)data_
, size_
, endpoint
);
1776 completion_message
extract_completion_message(osc::ReceivedMessageArgumentStream
& args
)
1778 osc::Blob
blob(0, 0);
1784 catch (osc::WrongArgumentTypeException
& e
)
1788 return completion_message (blob
.size
, blob
.data
);
1791 completion_message
extract_completion_message(osc::ReceivedMessageArgumentIterator
& it
)
1793 const void * data
= 0;
1794 unsigned long length
= 0;
1797 it
->AsBlobUnchecked(data
, length
);
1799 return completion_message(length
, data
);
1803 template <bool realtime
>
1804 void b_alloc_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1805 void b_alloc_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1807 template <bool realtime
>
1808 void b_alloc_1_nrt(uint32_t index
, uint32_t frames
, uint32_t channels
, completion_message
& msg
, nova_endpoint
const & endpoint
)
1810 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
1811 sample
* free_buf
= sc_factory
->get_nrt_mirror_buffer(index
);
1812 sc_factory
->allocate_buffer(index
, frames
, channels
);
1813 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_alloc_2_rt
<realtime
>, index
, msg
, free_buf
, endpoint
));
1816 template <bool realtime
>
1817 void b_alloc_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1819 sc_factory
->buffer_sync(index
);
1820 msg
.handle(endpoint
);
1821 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_alloc_3_nrt
, index
, free_buf
, endpoint
));
1824 void b_alloc_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1826 free_aligned(free_buf
);
1827 send_done_message(endpoint
, "/b_alloc", index
);
1830 template <bool realtime
>
1831 void handle_b_alloc(received_message
const & msg
, nova_endpoint
const & endpoint
)
1833 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1835 osc::int32 index
, frames
, channels
;
1837 args
>> index
>> frames
;
1844 completion_message message
= extract_completion_message(args
);
1846 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_alloc_1_nrt
<realtime
>, index
, frames
,
1847 channels
, message
, endpoint
));
1850 template <bool realtime
>
1851 void b_free_1_nrt(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
);
1852 template <bool realtime
>
1853 void b_free_2_rt(uint32_t index
, sample
* free_buf
, completion_message
& msg
, nova_endpoint
const & endpoint
);
1854 void b_free_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1856 template <bool realtime
>
1857 void b_free_1_nrt(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
1859 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
1860 sample
* free_buf
= sc_factory
->get_nrt_mirror_buffer(index
);
1861 sc_factory
->free_buffer(index
);
1862 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_free_2_rt
<realtime
>,
1863 index
, free_buf
, msg
, endpoint
));
1866 template <bool realtime
>
1867 void b_free_2_rt(uint32_t index
, sample
* free_buf
, completion_message
& msg
, nova_endpoint
const & endpoint
)
1869 sc_factory
->buffer_sync(index
);
1870 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_free_3_nrt
, index
, free_buf
, endpoint
));
1871 msg
.handle(endpoint
);
1874 void b_free_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1876 free_aligned(free_buf
);
1877 send_done_message(endpoint
, "/b_free", index
);
1881 template <bool realtime
>
1882 void handle_b_free(received_message
const & msg
, nova_endpoint
const & endpoint
)
1884 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1889 completion_message message
= extract_completion_message(args
);
1891 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_free_1_nrt
<realtime
>, index
, message
, endpoint
));
1894 template <bool realtime
>
1895 void b_allocRead_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1896 void b_allocRead_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1898 template <bool realtime
>
1899 void b_allocRead_1_nrt(uint32_t index
, movable_string
& filename
, uint32_t start
, uint32_t frames
, completion_message
& msg
,
1900 nova_endpoint
const & endpoint
)
1902 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
1903 sample
* free_buf
= sc_factory
->get_nrt_mirror_buffer(index
);
1904 int error
= sc_factory
->buffer_read_alloc(index
, filename
.c_str(), start
, frames
);
1906 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_allocRead_2_rt
<realtime
>, index
, msg
, free_buf
, endpoint
));
1908 /* post nice error message */;
1911 template <bool realtime
>
1912 void b_allocRead_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
,
1913 nova_endpoint
const & endpoint
)
1915 sc_factory
->buffer_sync(index
);
1916 msg
.handle(endpoint
);
1917 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_allocRead_3_nrt
, index
, free_buf
, endpoint
));
1920 void b_allocRead_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1922 free_aligned(free_buf
);
1923 send_done_message(endpoint
, "/b_allocRead", index
);
1926 template <bool realtime
>
1927 void handle_b_allocRead(received_message
const & msg
, nova_endpoint
const & endpoint
)
1929 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1932 const char * filename
;
1934 osc::int32 start
= 0;
1935 osc::int32 frames
= 0;
1937 args
>> index
>> filename
;
1945 completion_message message
= extract_completion_message(args
);
1947 movable_string
fname(filename
);
1948 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_allocRead_1_nrt
<realtime
>, index
,
1949 fname
, start
, frames
, message
, endpoint
));
1952 template <bool realtime
>
1953 void b_allocReadChannel_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
,
1954 nova_endpoint
const & endpoint
);
1955 void b_allocReadChannel_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1957 template <bool realtime
>
1958 void b_allocReadChannel_1_nrt(uint32_t index
, movable_string
const & filename
, uint32_t start
, uint32_t frames
,
1959 movable_array
<uint32_t> const & channels
, completion_message
& msg
,
1960 nova_endpoint
const & endpoint
)
1962 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
1963 sample
* free_buf
= sc_factory
->get_nrt_mirror_buffer(index
);
1964 int error
= sc_factory
->buffer_alloc_read_channels(index
, filename
.c_str(), start
, frames
,
1965 channels
.size(), channels
.data());
1967 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_allocReadChannel_2_rt
<realtime
>,
1968 index
, msg
, free_buf
, endpoint
));
1971 template <bool realtime
>
1972 void b_allocReadChannel_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
,
1973 nova_endpoint
const & endpoint
)
1975 sc_factory
->buffer_sync(index
);
1976 msg
.handle(endpoint
);
1977 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_allocReadChannel_3_nrt
,
1978 index
, free_buf
, endpoint
));
1981 void b_allocReadChannel_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1983 free_aligned(free_buf
);
1984 send_done_message(endpoint
, "/b_allocReadChannel", index
);
1988 template <bool realtime
>
1989 void handle_b_allocReadChannel(received_message
const & msg
, nova_endpoint
const & endpoint
)
1991 osc::ReceivedMessageArgumentIterator arg
= msg
.ArgumentsBegin();
1993 osc::int32 index
= arg
->AsInt32(); arg
++;
1994 const char * filename
= arg
->AsString(); arg
++;
1996 osc::int32 start
= arg
->AsInt32(); arg
++;
1997 size_t frames
= arg
->AsInt32(); arg
++;
1999 size_t channel_args
= msg
.ArgumentCount() - 4; /* we already consumed 4 elements */
2001 size_t channel_count
= 0;
2002 sized_array
<uint
, rt_pool_allocator
<uint
> > channels(channel_args
);
2004 for (uint i
= 0; i
!= channel_args
- 1; ++i
) // sclang fromats the last completion message as int, so we skip the last element
2006 if (arg
->IsInt32()) {
2007 channels
[i
] = arg
->AsInt32Unchecked(); arg
++;
2012 /* we reached the message blob */
2013 completion_message message
= extract_completion_message(arg
);
2015 movable_array
<uint32_t> channel_mapping(channel_count
, channels
.c_array());
2016 movable_string
fname(filename
);
2018 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_allocReadChannel_1_nrt
<realtime
>,
2019 index
, fname
, start
, frames
, channel_mapping
,
2020 message
, endpoint
));
2023 const char * b_write
= "/b_write";
2025 template <bool realtime
>
2026 void b_write_nrt_1(uint32_t index
, movable_string
const & filename
, movable_string
const & header_format
,
2027 movable_string
const & sample_format
, uint32_t start
, uint32_t frames
, bool leave_open
,
2028 completion_message
& msg
, nova_endpoint
const & endpoint
)
2030 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
2031 sc_factory
->buffer_write(index
, filename
.c_str(), header_format
.c_str(), sample_format
.c_str(), start
, frames
, leave_open
);
2032 msg
.trigger_async(endpoint
);
2033 cmd_dispatcher
<realtime
>::fire_done_message(endpoint
, b_write
, index
);
2036 void fire_b_write_exception(void)
2038 throw std::runtime_error("wrong arguments for /b_allocReadChannel");
2041 template <bool realtime
>
2042 void handle_b_write(received_message
const & msg
, nova_endpoint
const & endpoint
)
2044 osc::ReceivedMessageArgumentIterator arg
= msg
.ArgumentsBegin();
2045 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2048 osc::int32 index
= arg
->AsInt32(); arg
++;
2049 const char * filename
= arg
->AsString(); arg
++;
2050 const char * header_format
= arg
->AsString(); arg
++;
2051 const char * sample_format
= arg
->AsString(); arg
++;
2054 osc::int32 frames
= -1;
2055 osc::int32 start
= 0;
2056 osc::int32 leave_open
= 0;
2058 completion_message message
;
2061 if (!arg
->IsInt32())
2062 fire_b_write_exception();
2063 frames
= arg
->AsInt32Unchecked(); arg
++;
2069 if (!arg
->IsInt32())
2070 fire_b_write_exception();
2071 start
= arg
->AsInt32Unchecked(); arg
++;
2077 if (!arg
->IsInt32())
2078 fire_b_write_exception();
2079 leave_open
= arg
->AsInt32Unchecked(); arg
++;
2085 message
= extract_completion_message(arg
);
2088 movable_string
fname(filename
);
2089 movable_string
header_f(header_format
);
2090 movable_string
sample_f(sample_format
);
2092 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_write_nrt_1
<realtime
>, index
, fname
, header_f
, sample_f
,
2093 start
, frames
, bool(leave_open
), message
, endpoint
));
2096 template <bool realtime
>
2097 void b_read_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
);
2099 template <bool realtime
>
2100 void b_read_nrt_1(uint32_t index
, movable_string
& filename
, uint32_t start_file
, uint32_t frames
,
2101 uint32_t start_buffer
, bool leave_open
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2103 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
2104 sc_factory
->buffer_read(index
, filename
.c_str(), start_file
, frames
, start_buffer
, leave_open
);
2105 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_read_rt_2
<realtime
>, index
, msg
, endpoint
));
2108 const char * b_read
= "/b_read";
2109 template <bool realtime
>
2110 void b_read_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2112 sc_factory
->buffer_sync(index
);
2113 msg
.handle(endpoint
);
2114 cmd_dispatcher
<realtime
>::fire_done_message(endpoint
, b_read
, index
);
2117 void fire_b_read_exception(void)
2119 throw std::runtime_error("wrong arguments for /b_read");
2122 template <bool realtime
>
2123 void handle_b_read(received_message
const & msg
, nova_endpoint
const & endpoint
)
2125 osc::ReceivedMessageArgumentIterator arg
= msg
.ArgumentsBegin();
2126 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2129 osc::int32 index
= arg
->AsInt32(); arg
++;
2130 const char * filename
= arg
->AsString(); arg
++;
2133 osc::int32 start_file
= 0;
2134 osc::int32 frames
= -1;
2135 osc::int32 start_buffer
= 0;
2136 osc::int32 leave_open
= 0;
2138 completion_message message
;
2141 if (!arg
->IsInt32())
2142 fire_b_read_exception();
2143 start_file
= arg
->AsInt32Unchecked(); arg
++;
2149 if (!arg
->IsInt32())
2150 fire_b_read_exception();
2151 frames
= arg
->AsInt32Unchecked(); arg
++;
2157 if (!arg
->IsInt32())
2158 fire_b_read_exception();
2159 start_buffer
= arg
->AsInt32Unchecked(); arg
++;
2165 if (!arg
->IsInt32())
2166 fire_b_read_exception();
2167 leave_open
= arg
->AsInt32Unchecked(); arg
++;
2173 message
= extract_completion_message(arg
);
2176 movable_string
fname(filename
);
2178 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_read_nrt_1
<realtime
>, index
, fname
,
2179 start_file
, frames
, start_buffer
,
2180 bool(leave_open
), message
, endpoint
));
2184 template <bool realtime
>
2185 void b_readChannel_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
);
2187 template <bool realtime
>
2188 void b_readChannel_nrt_1(uint32_t index
, movable_string
& filename
, uint32_t start_file
, uint32_t frames
,
2189 uint32_t start_buffer
, bool leave_open
, movable_array
<uint32_t> & channel_map
,
2190 completion_message
& msg
, nova_endpoint
const & endpoint
)
2192 sc_factory
->buffer_read_channel(index
, filename
.c_str(), start_file
, frames
, start_buffer
, leave_open
,
2193 channel_map
.size(), channel_map
.data());
2194 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_readChannel_rt_2
<realtime
>, index
, msg
, endpoint
));
2197 const char * b_readChannel
= "/b_readChannel";
2198 template <bool realtime
>
2199 void b_readChannel_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2201 sc_factory
->buffer_sync(index
);
2202 msg
.handle(endpoint
);
2203 cmd_dispatcher
<realtime
>::fire_done_message(endpoint
, b_readChannel
, index
);
2206 void fire_b_readChannel_exception(void)
2208 throw std::runtime_error("wrong arguments for /b_readChannel");
2211 template <bool realtime
>
2212 void handle_b_readChannel(received_message
const & msg
, nova_endpoint
const & endpoint
)
2214 osc::ReceivedMessageArgumentIterator arg
= msg
.ArgumentsBegin();
2215 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2218 osc::int32 index
= arg
->AsInt32(); arg
++;
2219 const char * filename
= arg
->AsString(); arg
++;
2222 osc::int32 start_file
= 0;
2223 osc::int32 frames
= -1;
2224 osc::int32 start_buffer
= 0;
2225 osc::int32 leave_open
= 0;
2227 sized_array
<uint32_t, rt_pool_allocator
<uint32_t> > channel_mapping(int32_t(msg
.ArgumentCount())); /* larger than required */
2228 uint32_t channel_count
= 0;
2230 completion_message message
;
2233 if (!arg
->IsInt32())
2234 fire_b_read_exception();
2235 start_file
= arg
->AsInt32Unchecked(); arg
++;
2241 if (!arg
->IsInt32())
2242 fire_b_read_exception();
2243 frames
= arg
->AsInt32Unchecked(); arg
++;
2249 if (!arg
->IsInt32())
2250 fire_b_write_exception();
2251 start_buffer
= arg
->AsInt32Unchecked(); arg
++;
2257 if (!arg
->IsInt32())
2258 fire_b_write_exception();
2259 leave_open
= arg
->AsInt32Unchecked(); arg
++;
2266 if (arg
->IsBlob()) {
2267 message
= extract_completion_message(arg
);
2270 else if (arg
->IsInt32()) {
2271 channel_mapping
[channel_count
] = arg
->AsInt32Unchecked();
2275 fire_b_readChannel_exception();
2279 movable_string
fname(filename
);
2280 movable_array
<uint32_t> channel_map(channel_count
, channel_mapping
.c_array());
2282 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_readChannel_nrt_1
<realtime
>, index
, fname
,
2283 start_file
, frames
, start_buffer
,
2284 bool(leave_open
), channel_map
, message
, endpoint
));
2288 template <bool realtime
>
2289 void b_zero_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
);
2291 template <bool realtime
>
2292 void b_zero_nrt_1(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2294 sc_factory
->buffer_zero(index
);
2295 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_zero_rt_2
<realtime
>, index
, msg
, endpoint
));
2298 const char * b_zero
= "/b_zero";
2299 template <bool realtime
>
2300 void b_zero_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2302 sc_factory
->increment_write_updates(index
);
2303 msg
.handle(endpoint
);
2304 cmd_dispatcher
<realtime
>::fire_done_message(endpoint
, b_zero
, index
);
2307 template <bool realtime
>
2308 void handle_b_zero(received_message
const & msg
, nova_endpoint
const & endpoint
)
2310 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2314 completion_message message
= extract_completion_message(args
);
2316 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_zero_nrt_1
<realtime
>, index
, message
, endpoint
));
2319 void handle_b_set(received_message
const & msg
)
2321 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2322 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2323 verify_argument(it
, end
);
2324 osc::int32 buffer_index
= it
->AsInt32(); ++it
;
2326 buffer_wrapper::sample_t
* data
= sc_factory
->get_buffer(buffer_index
);
2329 osc::int32 index
= it
->AsInt32(); ++it
;
2330 float value
= extract_float_argument(it
++);
2332 data
[index
] = value
;
2336 void handle_b_setn(received_message
const & msg
)
2338 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2339 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2340 verify_argument(it
, end
);
2341 osc::int32 buffer_index
= it
->AsInt32(); ++it
;
2343 buffer_wrapper::sample_t
* data
= sc_factory
->get_buffer(buffer_index
);
2346 osc::int32 index
= it
->AsInt32(); ++it
;
2347 verify_argument(it
, end
);
2348 osc::int32 samples
= it
->AsInt32(); ++it
;
2350 for (int i
= 0; i
!= samples
; ++i
) {
2351 verify_argument(it
, end
);
2352 float value
= extract_float_argument(it
++);
2353 data
[index
+i
] = value
;
2358 void handle_b_fill(received_message
const & msg
)
2360 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2361 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2362 verify_argument(it
, end
);
2363 osc::int32 buffer_index
= it
->AsInt32(); ++it
;
2365 buffer_wrapper::sample_t
* data
= sc_factory
->get_buffer(buffer_index
);
2368 osc::int32 index
= it
->AsInt32(); ++it
;
2369 verify_argument(it
, end
);
2370 osc::int32 samples
= it
->AsInt32(); ++it
;
2371 verify_argument(it
, end
);
2372 float value
= extract_float_argument(it
++);
2374 for (int i
= 0; i
!= samples
; ++i
)
2375 data
[index
] = value
;
2379 template <bool realtime
>
2380 void handle_b_query(received_message
const & msg
, nova_endpoint
const & endpoint
)
2382 const size_t elem_size
= 3*sizeof(int) * sizeof(float);
2384 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2385 size_t arg_count
= msg
.ArgumentCount();
2387 size_t size
= elem_size
* arg_count
+ 128; /* should be more than required */
2388 sized_array
<char, rt_pool_allocator
<char> > data(size
);
2390 osc::OutboundPacketStream
p(data
.c_array(), size
);
2391 p
<< osc::BeginMessage("/b_info");
2393 while (!args
.Eos()) {
2394 osc::int32 buffer_index
;
2395 args
>> buffer_index
;
2397 SndBuf
* buf
= sc_factory
->get_buffer_struct(buffer_index
);
2400 << osc::int32(buf
->frames
)
2401 << osc::int32(buf
->channels
)
2402 << float (buf
->samplerate
);
2405 p
<< osc::EndMessage
;
2407 movable_array
<char> message(p
.Size(), data
.c_array());
2409 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2412 template <bool realtime
>
2413 void b_close_rt_2(completion_message
& msg
, nova_endpoint
const & endpoint
);
2415 template <bool realtime
>
2416 void b_close_nrt_1(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2418 sc_factory
->buffer_close(index
);
2419 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_close_rt_2
<realtime
>, msg
, endpoint
));
2422 template <bool realtime
>
2423 void b_close_rt_2(completion_message
& msg
, nova_endpoint
const & endpoint
)
2427 template <bool realtime
>
2428 void handle_b_close(received_message
const & msg
, nova_endpoint
const & endpoint
)
2430 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2434 completion_message message
= extract_completion_message(args
);
2435 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_close_nrt_1
<realtime
>, index
, message
, endpoint
));
2438 template <bool realtime
>
2439 void handle_b_get(received_message
const & msg
, nova_endpoint
const & endpoint
)
2441 const size_t elem_size
= sizeof(int) * sizeof(float);
2442 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2443 const size_t index_count
= msg
.ArgumentCount() - 1;
2444 const size_t alloc_size
= index_count
* elem_size
+ 128; /* hopefully enough */
2446 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
2448 osc::int32 buffer_index
;
2449 args
>> buffer_index
;
2451 const SndBuf
* buf
= sc_factory
->get_buffer_struct(buffer_index
);
2452 const sample
* data
= buf
->data
;
2453 const int max_sample
= buf
->frames
* buf
->channels
;
2455 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
2456 p
<< osc::BeginMessage("/b_set")
2465 if (index
< max_sample
)
2471 p
<< osc::EndMessage
;
2473 movable_array
<char> message(p
.Size(), return_message
.c_array());
2474 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2477 template<typename Alloc
>
2480 getn_data(int start
, int count
, const float * data
):
2481 start_index_(start
), data_(count
)
2483 data_
.reserve(count
);
2484 for (int i
= 0; i
!= count
; ++i
)
2489 std::vector
<float, Alloc
> data_
;
2492 template <bool realtime
>
2493 void handle_b_getn(received_message
const & msg
, nova_endpoint
const & endpoint
)
2495 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2497 typedef getn_data
<rt_pool_allocator
<float> > getn_data
;
2498 std::vector
<getn_data
, rt_pool_allocator
<getn_data
> > return_data
;
2500 osc::int32 buffer_index
;
2501 args
>> buffer_index
;
2503 const SndBuf
* buf
= sc_factory
->get_buffer_struct(buffer_index
);
2504 const sample
* data
= buf
->data
;
2505 const int max_sample
= buf
->frames
* buf
->channels
;
2509 osc::int32 index
, sample_count
;
2510 args
>> index
>> sample_count
;
2512 if (index
+ sample_count
<= max_sample
)
2513 return_data
.push_back(getn_data(index
, sample_count
, data
+ index
));
2516 size_t alloc_size
= 128;
2517 for (size_t i
= 0; i
!= return_data
.size(); ++i
)
2518 alloc_size
+= return_data
[i
].data_
.size() * (sizeof(float) + sizeof(int)) + 2*sizeof(int);
2520 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
2522 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
2523 p
<< osc::BeginMessage("/b_setn")
2526 for (size_t i
= 0; i
!= return_data
.size(); ++i
) {
2527 p
<< osc::int32(return_data
[i
].start_index_
)
2528 << osc::int32(return_data
[i
].data_
.size());
2530 for (size_t j
= 0; j
!= return_data
[i
].data_
.size(); ++j
)
2531 p
<< return_data
[i
].data_
[j
];
2534 p
<< osc::EndMessage
;
2536 movable_array
<char> message(p
.Size(), return_message
.c_array());
2537 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2541 template <bool realtime
>
2542 void b_gen_rt_2(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
2543 void b_gen_nrt_3(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
2545 template <bool realtime
>
2546 void b_gen_nrt_1(movable_array
<char> & message
, nova_endpoint
const & endpoint
)
2548 sc_msg_iter
msg(message
.size(), (char*)message
.data());
2550 int index
= msg
.geti();
2551 const char * generator
= (const char*)msg
.gets4();
2555 sample
* free_buf
= sc_factory
->buffer_generate(index
, generator
, msg
);
2556 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_gen_rt_2
<realtime
>, index
, free_buf
, endpoint
));
2559 template <bool realtime
>
2560 void b_gen_rt_2(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
2562 sc_factory
->buffer_sync(index
);
2563 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_gen_nrt_3
, index
, free_buf
, endpoint
));
2566 void b_gen_nrt_3(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
2568 free_aligned(free_buf
);
2569 send_done_message(endpoint
, "/b_gen", index
);
2572 template <bool realtime
>
2573 void handle_b_gen(received_message
const & msg
, size_t msg_size
, nova_endpoint
const & endpoint
)
2575 movable_array
<char> cmd (msg_size
, msg
.TypeTags()-1);
2576 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_gen_nrt_1
<realtime
>, cmd
, endpoint
));
2580 void handle_c_set(received_message
const & msg
)
2582 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2584 while (it
!= msg
.ArgumentsEnd()) {
2585 osc::int32 bus_index
= it
->AsInt32(); ++it
;
2586 float value
= extract_float_argument(it
++);
2588 sc_factory
->controlbus_set(bus_index
, value
);
2592 void handle_c_setn(received_message
const & msg
)
2594 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2596 while (it
!= msg
.ArgumentsEnd()) {
2597 osc::int32 bus_index
, bus_count
;
2598 bus_index
= it
->AsInt32(); ++it
;
2599 bus_count
= it
->AsInt32(); ++it
;
2601 for (int i
= 0; i
!= bus_count
; ++i
) {
2602 float value
= extract_float_argument(it
++);
2603 sc_factory
->controlbus_set(bus_index
+ i
, value
);
2608 void handle_c_fill(received_message
const & msg
)
2610 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2612 while (it
!= msg
.ArgumentsEnd()) {
2613 osc::int32 bus_index
, bus_count
;
2614 bus_index
= it
->AsInt32(); ++it
;
2615 bus_count
= it
->AsInt32(); ++it
;
2616 float value
= extract_float_argument(it
++);
2617 sc_factory
->controlbus_fill(bus_index
, bus_count
, value
);
2621 template <bool realtime
>
2622 void handle_c_get(received_message
const & msg
,
2623 nova_endpoint
const & endpoint
)
2625 const size_t elem_size
= sizeof(int) + sizeof(float);
2626 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2627 const size_t index_count
= msg
.ArgumentCount();
2628 const size_t alloc_size
= index_count
* elem_size
+ 128; /* hopefully enough */
2630 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
2632 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
2633 p
<< osc::BeginMessage("/c_set");
2640 p
<< index
<< sc_factory
->controlbus_get(index
);
2643 p
<< osc::EndMessage
;
2645 movable_array
<char> message(p
.Size(), return_message
.c_array());
2646 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2649 template <bool realtime
>
2650 void handle_c_getn(received_message
const & msg
, nova_endpoint
const & endpoint
)
2652 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2654 /* we pessimize, but better to allocate too much than too little */
2655 const size_t alloc_size
= 128 +
2656 (2 * sizeof(int) + 128*sizeof(float)) * msg
.ArgumentCount();
2658 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
2660 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
2661 p
<< osc::BeginMessage("/c_setn");
2665 osc::int32 bus_index
, bus_count
;
2666 args
>> bus_index
>> bus_count
;
2667 p
<< bus_index
<< bus_count
;
2669 for (int i
= 0; i
!= bus_count
; ++i
) {
2670 float value
= sc_factory
->controlbus_get(bus_index
+ i
);
2675 p
<< osc::EndMessage
;
2677 movable_array
<char> message(p
.Size(), return_message
.c_array());
2678 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2681 #ifdef BOOST_HAS_RVALUE_REFS
2682 std::pair
<sc_synth_prototype_ptr
*, size_t> wrap_synthdefs(std::vector
<sc_synthdef
> && defs
)
2684 std::vector
<sc_synthdef
> synthdefs(std::move(defs
));
2685 size_t count
= synthdefs
.size();
2686 sc_synth_prototype_ptr
* prototypes
= new sc_synth_prototype_ptr
[count
];
2688 for (size_t i
= 0; i
!= count
; ++i
)
2689 prototypes
[i
].reset(new sc_synth_prototype(std::move(synthdefs
[i
])));
2690 return std::make_pair(prototypes
, count
);
2693 std::pair
<sc_synth_prototype_ptr
*, size_t> wrap_synthdefs(std::vector
<sc_synthdef
> const & defs
)
2695 size_t count
= defs
.size();
2696 sc_synth_prototype_ptr
* prototypes
= new sc_synth_prototype_ptr
[count
];
2698 for (size_t i
= 0; i
!= count
; ++i
)
2699 prototypes
[i
].reset(new sc_synth_prototype(defs
[i
]));
2700 return std::make_pair(prototypes
, count
);
2703 template <bool realtime
>
2704 void d_recv_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2705 nova_endpoint
const & endpoint
);
2706 void d_recv_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
);
2708 template <bool realtime
>
2709 void d_recv_nrt(movable_array
<char> & def
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2712 sc_synth_prototype_ptr
* prototypes
;
2713 std::vector
<sc_synthdef
> synthdefs (read_synthdefs(def
.data()));
2715 #ifdef BOOST_HAS_RVALUE_REFS
2716 boost::tie(prototypes
, count
) = wrap_synthdefs(std::move(synthdefs
));
2718 boost::tie(prototypes
, count
) = wrap_synthdefs(synthdefs
);
2721 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(d_recv_rt2
<realtime
>, prototypes
, count
, msg
, endpoint
));
2724 template <bool realtime
>
2725 void d_recv_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2726 nova_endpoint
const & endpoint
)
2728 std::for_each(prototypes
, prototypes
+ prototype_count
,
2729 boost::bind(&synth_factory::register_prototype
, instance
, _1
));
2731 msg
.handle(endpoint
);
2732 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_recv_nrt3
, prototypes
, endpoint
));
2735 void d_recv_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
)
2737 delete[] prototypes
;
2738 send_done_message(endpoint
, "/d_recv");
2741 template <bool realtime
>
2742 void handle_d_recv(received_message
const & msg
,
2743 nova_endpoint
const & endpoint
)
2745 const void * synthdef_data
;
2746 unsigned long synthdef_size
;
2748 osc::ReceivedMessageArgumentIterator args
= msg
.ArgumentsBegin();
2750 args
->AsBlob(synthdef_data
, synthdef_size
); ++args
;
2751 movable_array
<char> def(synthdef_size
, (const char*)synthdef_data
);
2752 completion_message message
= extract_completion_message(args
);
2754 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_recv_nrt
<realtime
>, def
, message
, endpoint
));
2757 template <bool realtime
>
2758 void d_load_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2759 nova_endpoint
const & endpoint
);
2760 void d_load_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
);
2762 template <bool realtime
>
2763 void d_load_nrt(movable_string
& path
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2766 sc_synth_prototype_ptr
* prototypes
;
2767 /* todo: we need to implment some file name pattern matching */
2768 boost::tie(prototypes
, count
) = wrap_synthdefs(sc_read_synthdefs_file(path
.c_str()));
2770 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(d_load_rt2
<realtime
>, prototypes
, count
, msg
, endpoint
));
2773 template <bool realtime
>
2774 void d_load_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2775 nova_endpoint
const & endpoint
)
2777 std::for_each(prototypes
, prototypes
+ prototype_count
,
2778 boost::bind(&synth_factory::register_prototype
, instance
, _1
));
2780 msg
.handle(endpoint
);
2781 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_load_nrt3
, prototypes
, endpoint
));
2784 void d_load_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
)
2786 delete[] prototypes
;
2787 send_done_message(endpoint
, "/d_load");
2791 template <bool realtime
>
2792 void handle_d_load(received_message
const & msg
,
2793 nova_endpoint
const & endpoint
)
2795 osc::ReceivedMessageArgumentIterator args
= msg
.ArgumentsBegin();
2796 const char * path
= args
->AsString(); args
++;
2797 completion_message message
= extract_completion_message(args
);
2799 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_load_nrt
<realtime
>, movable_string(path
),
2800 message
, endpoint
));
2804 template <bool realtime
>
2805 void d_loadDir_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2806 nova_endpoint
const & endpoint
);
2807 void d_loadDir_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
);
2809 template <bool realtime
>
2810 void d_loadDir_nrt1(movable_string
& path
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2813 sc_synth_prototype_ptr
* prototypes
;
2814 boost::tie(prototypes
, count
) = wrap_synthdefs(sc_read_synthdefs_dir(path
.c_str()));
2816 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(d_loadDir_rt2
<realtime
>, prototypes
, count
, msg
, endpoint
));
2819 template <bool realtime
>
2820 void d_loadDir_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2821 nova_endpoint
const & endpoint
)
2823 std::for_each(prototypes
, prototypes
+ prototype_count
,
2824 boost::bind(&synth_factory::register_prototype
, instance
, _1
));
2826 msg
.handle(endpoint
);
2827 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_loadDir_nrt3
, prototypes
, endpoint
));
2830 void d_loadDir_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
)
2832 delete[] prototypes
;
2833 send_done_message(endpoint
, "/d_loadDir");
2836 template <bool realtime
>
2837 void handle_d_loadDir(received_message
const & msg
,
2838 nova_endpoint
const & endpoint
)
2840 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2844 completion_message message
= extract_completion_message(args
);
2846 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_loadDir_nrt1
<realtime
>,
2847 movable_string(path
), message
, endpoint
));
2851 void handle_d_free(received_message
const & msg
)
2853 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2857 const char * defname
;
2860 instance
->remove_prototype(defname
);
2864 void insert_parallel_group(int node_id
, int action
, int target_id
)
2867 node_id
= instance
->generate_node_id();
2868 else if (!check_node_id(node_id
))
2871 server_node
* target
= find_node(target_id
);
2875 node_position_constraint pos
= make_pair(target
, node_position(action
));
2876 if (!node_position_sanity_check(pos
))
2879 instance
->add_parallel_group(node_id
, pos
);
2880 last_generated
= node_id
;
2883 void handle_p_new(received_message
const & msg
)
2885 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2887 while(!args
.Eos()) {
2888 osc::int32 id
, action
, target
;
2889 args
>> id
>> action
>> target
;
2891 insert_parallel_group(id
, action
, target
);
2895 void handle_u_cmd(received_message
const & msg
, int size
)
2897 sc_msg_iter
args(size
, msg
.AddressPattern());
2899 int node_id
= args
.geti();
2901 server_node
* target_synth
= find_node(node_id
);
2903 if (target_synth
== NULL
|| target_synth
->is_group())
2906 sc_synth
* synth
= static_cast<sc_synth
*>(target_synth
);
2908 int ugen_index
= args
.geti();
2909 const char * cmd_name
= args
.gets();
2911 synth
->apply_unit_cmd(cmd_name
, ugen_index
, &args
);
2914 void handle_cmd(received_message
const & msg
, int size
, nova_endpoint
const & endpoint
, int skip_bytes
)
2916 sc_msg_iter
args(size
, msg
.AddressPattern() + skip_bytes
);
2918 const char * cmd
= args
.gets();
2920 sc_factory
->run_cmd_plugin(&sc_factory
->world
, cmd
, &args
, const_cast<nova_endpoint
*>(&endpoint
));
2925 template <bool realtime
>
2926 void sc_osc_handler::handle_message_int_address(received_message
const & message
,
2927 size_t msg_size
, nova_endpoint
const & endpoint
)
2929 uint32_t address
= message
.AddressPatternAsUInt32();
2934 handle_quit
<realtime
>(endpoint
);
2938 handle_s_new(message
);
2942 handle_s_noid(message
);
2946 handle_s_get
<realtime
>(message
, msg_size
, endpoint
);
2950 handle_s_getn
<realtime
>(message
, msg_size
, endpoint
);
2954 handle_notify
<realtime
>(message
, endpoint
);
2958 handle_status
<realtime
>(endpoint
);
2962 handle_dumpOSC(message
);
2966 handle_sync
<realtime
>(message
, endpoint
);
2969 case cmd_clearSched
:
2970 handle_clearSched();
2974 handle_error(message
);
2978 handle_g_new(message
);
2982 handle_g_head_or_tail
<head
>(message
);
2986 handle_g_head_or_tail
<tail
>(message
);
2990 handle_g_freeall(message
);
2993 case cmd_g_deepFree
:
2994 handle_g_deepFree(message
);
2997 case cmd_g_queryTree
:
2998 handle_g_queryTree
<realtime
>(message
, endpoint
);
3001 case cmd_g_dumpTree
:
3002 handle_g_dumpTree(message
);
3006 handle_n_free(message
);
3010 handle_n_set(message
);
3014 handle_n_setn(message
);
3018 handle_n_fill(message
);
3022 handle_n_map(message
);
3026 handle_n_mapn(message
);
3030 handle_n_mapa(message
);
3034 handle_n_mapan(message
);
3038 handle_n_query(message
, endpoint
);
3042 handle_n_order(message
);
3046 handle_n_run(message
);
3050 handle_n_before_or_after
<before
>(message
);
3054 handle_n_before_or_after
<after
>(message
);
3058 handle_n_trace(message
);
3062 handle_b_alloc
<realtime
>(message
, endpoint
);
3066 handle_u_cmd(message
, msg_size
);
3070 handle_b_free
<realtime
>(message
, endpoint
);
3073 case cmd_b_allocRead
:
3074 handle_b_allocRead
<realtime
>(message
, endpoint
);
3077 case cmd_b_allocReadChannel
:
3078 handle_b_allocReadChannel
<realtime
>(message
, endpoint
);
3082 handle_b_read
<realtime
>(message
, endpoint
);
3085 case cmd_b_readChannel
:
3086 handle_b_readChannel
<realtime
>(message
, endpoint
);
3090 handle_b_write
<realtime
>(message
, endpoint
);
3094 handle_b_zero
<realtime
>(message
, endpoint
);
3098 handle_b_set(message
);
3102 handle_b_setn(message
);
3106 handle_b_fill(message
);
3110 handle_b_query
<realtime
>(message
, endpoint
);
3114 handle_b_get
<realtime
>(message
, endpoint
);
3118 handle_b_getn
<realtime
>(message
, endpoint
);
3122 handle_b_gen
<realtime
>(message
, msg_size
, endpoint
);
3126 handle_b_close
<realtime
>(message
, endpoint
);
3130 handle_c_set(message
);
3134 handle_c_setn(message
);
3138 handle_c_fill(message
);
3142 handle_c_get
<realtime
>(message
, endpoint
);
3146 handle_c_getn
<realtime
>(message
, endpoint
);
3150 handle_d_recv
<realtime
>(message
, endpoint
);
3154 handle_d_load
<realtime
>(message
, endpoint
);
3158 handle_d_loadDir
<realtime
>(message
, endpoint
);
3162 handle_d_free(message
);
3166 handle_p_new(message
);
3170 handle_cmd(message
, msg_size
, endpoint
, 4);
3174 handle_unhandled_message(message
);
3181 template <bool realtime
>
3182 void dispatch_group_commands(const char * address
, received_message
const & message
,
3183 nova_endpoint
const & endpoint
)
3185 assert(address
[1] == 'g');
3186 assert(address
[2] == '_');
3188 if (strcmp(address
+3, "new") == 0) {
3189 handle_g_new(message
);
3192 if (strcmp(address
+3, "head") == 0) {
3193 handle_g_head_or_tail
<head
>(message
);
3196 if (strcmp(address
+3, "tail") == 0) {
3197 handle_g_head_or_tail
<tail
>(message
);
3200 if (strcmp(address
+3, "freeAll") == 0) {
3201 handle_g_freeall(message
);
3204 if (strcmp(address
+3, "deepFree") == 0) {
3205 handle_g_deepFree(message
);
3208 if (strcmp(address
+3, "queryTree") == 0) {
3209 handle_g_queryTree
<realtime
>(message
, endpoint
);
3213 if (strcmp(address
+3, "dumpTree") == 0) {
3214 handle_g_dumpTree(message
);
3219 template <bool realtime
>
3220 void dispatch_node_commands(const char * address
, received_message
const & message
,
3221 nova_endpoint
const & endpoint
)
3223 assert(address
[1] == 'n');
3224 assert(address
[2] == '_');
3226 if (strcmp(address
+3, "free") == 0) {
3227 handle_n_free(message
);
3231 if (strcmp(address
+3, "set") == 0) {
3232 handle_n_set(message
);
3236 if (strcmp(address
+3, "setn") == 0) {
3237 handle_n_setn(message
);
3241 if (strcmp(address
+3, "fill") == 0) {
3242 handle_n_fill(message
);
3246 if (strcmp(address
+3, "map") == 0) {
3247 handle_n_map(message
);
3251 if (strcmp(address
+3, "mapn") == 0) {
3252 handle_n_mapn(message
);
3256 if (strcmp(address
+3, "mapa") == 0) {
3257 handle_n_mapa(message
);
3261 if (strcmp(address
+3, "mapan") == 0) {
3262 handle_n_mapan(message
);
3266 if (strcmp(address
+3, "run") == 0) {
3267 handle_n_run(message
);
3271 if (strcmp(address
+3, "before") == 0) {
3272 handle_n_before_or_after
<before
>(message
);
3276 if (strcmp(address
+3, "after") == 0) {
3277 handle_n_before_or_after
<after
>(message
);
3281 if (strcmp(address
+3, "order") == 0) {
3282 handle_n_order(message
);
3286 if (strcmp(address
+3, "query") == 0) {
3287 handle_n_query(message
, endpoint
);
3291 if (strcmp(address
+3, "trace") == 0) {
3292 handle_n_trace(message
);
3297 template <bool realtime
>
3298 void dispatch_buffer_commands(const char * address
, received_message
const & message
,
3299 size_t msg_size
, nova_endpoint
const & endpoint
)
3301 assert(address
[1] == 'b');
3302 assert(address
[2] == '_');
3304 if (strcmp(address
+3, "alloc") == 0) {
3305 handle_b_alloc
<realtime
>(message
, endpoint
);
3309 if (strcmp(address
+3, "free") == 0) {
3310 handle_b_free
<realtime
>(message
, endpoint
);
3314 if (strcmp(address
+3, "allocRead") == 0) {
3315 handle_b_allocRead
<realtime
>(message
, endpoint
);
3318 if (strcmp(address
+3, "allocReadChannel") == 0) {
3319 handle_b_allocReadChannel
<realtime
>(message
, endpoint
);
3323 if (strcmp(address
+3, "read") == 0) {
3324 handle_b_read
<realtime
>(message
, endpoint
);
3328 if (strcmp(address
+3, "readChannel") == 0) {
3329 handle_b_readChannel
<realtime
>(message
, endpoint
);
3333 if (strcmp(address
+3, "write") == 0) {
3334 handle_b_write
<realtime
>(message
, endpoint
);
3338 if (strcmp(address
+3, "zero") == 0) {
3339 handle_b_zero
<realtime
>(message
, endpoint
);
3343 if (strcmp(address
+3, "set") == 0) {
3344 handle_b_set(message
);
3348 if (strcmp(address
+3, "setn") == 0) {
3349 handle_b_setn(message
);
3353 if (strcmp(address
+3, "fill") == 0) {
3354 handle_b_fill(message
);
3358 if (strcmp(address
+3, "query") == 0) {
3359 handle_b_query
<realtime
>(message
, endpoint
);
3363 if (strcmp(address
+3, "get") == 0) {
3364 handle_b_get
<realtime
>(message
, endpoint
);
3368 if (strcmp(address
+3, "getn") == 0) {
3369 handle_b_getn
<realtime
>(message
, endpoint
);
3373 if (strcmp(address
+3, "gen") == 0) {
3374 handle_b_gen
<realtime
>(message
, msg_size
, endpoint
);
3378 if (strcmp(address
+3, "close") == 0) {
3379 handle_b_close
<realtime
>(message
, endpoint
);
3384 template <bool realtime
>
3385 void dispatch_control_bus_commands(const char * address
, received_message
const & message
,
3386 nova_endpoint
const & endpoint
)
3388 assert(address
[1] == 'c');
3389 assert(address
[2] == '_');
3391 if (strcmp(address
+3, "set") == 0) {
3392 handle_c_set(message
);
3396 if (strcmp(address
+3, "setn") == 0) {
3397 handle_c_setn(message
);
3401 if (strcmp(address
+3, "fill") == 0) {
3402 handle_c_fill(message
);
3406 if (strcmp(address
+3, "get") == 0) {
3407 handle_c_get
<realtime
>(message
, endpoint
);
3411 if (strcmp(address
+3, "getn") == 0) {
3412 handle_c_getn
<realtime
>(message
, endpoint
);
3417 template <bool realtime
>
3418 void dispatch_synthdef_commands(const char * address
, received_message
const & message
,
3419 nova_endpoint
const & endpoint
)
3421 assert(address
[1] == 'd');
3422 assert(address
[2] == '_');
3424 if (strcmp(address
+3, "recv") == 0) {
3425 handle_d_recv
<realtime
>(message
, endpoint
);
3429 if (strcmp(address
+3, "load") == 0) {
3430 handle_d_load
<realtime
>(message
, endpoint
);
3434 if (strcmp(address
+3, "loadDir") == 0) {
3435 handle_d_loadDir
<realtime
>(message
, endpoint
);
3439 if (strcmp(address
+3, "free") == 0) {
3440 handle_d_free(message
);
3445 template <bool realtime
>
3446 void dispatch_synth_commands(const char * address
, received_message
const & message
, size_t msg_size
,
3447 nova_endpoint
const & endpoint
)
3449 assert(address
[1] == 's');
3450 assert(address
[2] == '_');
3452 if (strcmp(address
+3, "new") == 0) {
3453 handle_s_new(message
);
3457 if (strcmp(address
+3, "noid") == 0) {
3458 handle_s_noid(message
);
3462 if (strcmp(address
+3, "get") == 0) {
3463 handle_s_get
<realtime
>(message
, msg_size
, endpoint
);
3467 if (strcmp(address
+3, "getn") == 0) {
3468 handle_s_getn
<realtime
>(message
, msg_size
, endpoint
);
3475 template <bool realtime
>
3476 void sc_osc_handler::handle_message_sym_address(received_message
const & message
,
3477 size_t msg_size
, nova_endpoint
const & endpoint
)
3479 const char * address
= message
.AddressPattern();
3481 /* scsynth doesn't require the leading / */
3482 if(address
[0] != '/')
3485 if (address
[2] == '_')
3487 if (address
[1] == 'g') {
3488 dispatch_group_commands
<realtime
>(address
, message
, endpoint
);
3492 if (address
[1] == 'n') {
3493 dispatch_node_commands
<realtime
>(address
, message
, endpoint
);
3497 if (address
[1] == 'b') {
3498 dispatch_buffer_commands
<realtime
>(address
, message
, msg_size
, endpoint
);
3502 if (address
[1] == 'c') {
3503 dispatch_control_bus_commands
<realtime
>(address
, message
, endpoint
);
3507 if (address
[1] == 'd') {
3508 dispatch_synthdef_commands
<realtime
>(address
, message
, endpoint
);
3512 if (address
[1] == 's') {
3513 dispatch_synth_commands
<realtime
>(address
, message
, msg_size
, endpoint
);
3518 if (strcmp(address
+1, "p_new") == 0) {
3519 handle_p_new(message
);
3523 if (strcmp(address
+1, "u_cmd") == 0) {
3524 handle_u_cmd(message
, msg_size
);
3528 if (strcmp(address
+1, "status") == 0) {
3529 handle_status
<realtime
>(endpoint
);
3533 if (strcmp(address
+1, "sync") == 0) {
3534 handle_sync
<realtime
>(message
, endpoint
);
3538 if (strcmp(address
+1, "quit") == 0) {
3539 handle_quit
<realtime
>(endpoint
);
3543 if (strcmp(address
+1, "notify") == 0) {
3544 handle_notify
<realtime
>(message
, endpoint
);
3548 if (strcmp(address
+1, "dumpOSC") == 0) {
3549 handle_dumpOSC(message
);
3553 if (strcmp(address
+1, "clearSched") == 0) {
3554 handle_clearSched();
3558 if (strcmp(address
+1, "error") == 0) {
3559 handle_error(message
);
3563 if (strcmp(address
+1, "cmd") == 0) {
3564 handle_cmd(message
, msg_size
, endpoint
, 8);
3568 handle_unhandled_message(message
);
3572 template <bool realtime
>
3573 void handle_asynchronous_plugin_cleanup(World
* world
, void *cmdData
,
3574 AsyncFreeFn cleanup
)
3577 (cleanup
)(world
, cmdData
);
3580 template <bool realtime
>
3581 void handle_asynchronous_plugin_stage4(World
* world
, const char * cmdName
, void *cmdData
, AsyncStageFn stage4
,
3582 AsyncFreeFn cleanup
, completion_message
& msg
, nova_endpoint
const & endpoint
)
3585 (stage4
)(world
, cmdData
);
3587 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(handle_asynchronous_plugin_cleanup
<realtime
>, world
, cmdData
,
3590 send_done_message(endpoint
, cmdName
);
3593 template <bool realtime
>
3594 void handle_asynchronous_plugin_stage3(World
* world
, const char * cmdName
, void *cmdData
, AsyncStageFn stage3
, AsyncStageFn stage4
,
3595 AsyncFreeFn cleanup
, completion_message
& msg
, nova_endpoint
const & endpoint
)
3598 bool success
= (stage3
)(world
, cmdData
);
3600 msg
.handle(endpoint
);
3602 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage4
<realtime
>, world
, cmdName
,
3603 cmdData
, stage4
, cleanup
, msg
, endpoint
));
3606 template <bool realtime
>
3607 void handle_asynchronous_plugin_stage2(World
* world
, const char * cmdName
, void *cmdData
, AsyncStageFn stage2
,
3608 AsyncStageFn stage3
, AsyncStageFn stage4
,
3609 AsyncFreeFn cleanup
, completion_message
& msg
, nova_endpoint
const & endpoint
)
3612 (stage2
)(world
, cmdData
);
3614 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(handle_asynchronous_plugin_stage3
<realtime
>, world
, cmdName
,
3615 cmdData
, stage3
, stage4
,
3616 cleanup
, msg
, endpoint
));
3619 void sc_osc_handler::do_asynchronous_command(World
* world
, void* replyAddr
, const char* cmdName
, void *cmdData
,
3620 AsyncStageFn stage2
, AsyncStageFn stage3
, AsyncStageFn stage4
, AsyncFreeFn cleanup
,
3621 int completionMsgSize
, void* completionMsgData
)
3623 completion_message
msg(completionMsgSize
, completionMsgData
);
3624 nova_endpoint
endpoint(*static_cast<nova_endpoint
*>(replyAddr
));
3626 if (world
->mRealTime
)
3627 cmd_dispatcher
<true>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage2
<true>, world
, cmdName
,
3628 cmdData
, stage2
, stage3
, stage4
, cleanup
, msg
, endpoint
));
3630 cmd_dispatcher
<false>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage2
<false>, world
, cmdName
,
3631 cmdData
, stage2
, stage3
, stage4
, cleanup
, msg
, endpoint
));
3635 } /* namespace detail */
3636 } /* namespace nova */