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 sc_synth
* add_synth(const char * name
, int node_id
, int action
, int target_id
)
849 if (!check_node_id(node_id
))
852 server_node
* target
= find_node(target_id
);
856 node_position_constraint pos
= make_pair(target
, node_position(action
));
857 abstract_synth
* synth
= instance
->add_synth(name
, node_id
, pos
);
859 log_printf("Cannot create synth (synthdef: %s, node id: %d)\n", name
, node_id
);
861 last_generated
= node_id
;
862 return static_cast<sc_synth
*>(synth
);
865 /* extract float or int32 as float from argument iterator */
866 inline float extract_float_argument(osc::ReceivedMessageArgumentIterator
const & it
)
869 return it
->AsFloatUnchecked();
871 return float(it
->AsInt32Unchecked());
873 return float(it
->AsInt64Unchecked());
875 throw std::runtime_error("type cannot be converted to float");
878 inline void verify_argument(osc::ReceivedMessageArgumentIterator
const & it
,
879 osc::ReceivedMessageArgumentIterator
const & end
)
882 throw std::runtime_error("unexpected end of argument list");
885 template <bool IsAudio
, typename slot_type
>
886 static void apply_control_bus_mapping(server_node
& node
, slot_type slot
, int bus_index
);
888 template <typename control_id_type
>
889 void set_control_array(server_node
* node
, control_id_type control
, osc::ReceivedMessageArgumentIterator
& it
)
891 size_t array_size
= it
->ArraySize(); ++it
;
893 if (it
->IsArrayStart()) {
894 // nested arrays are basically user errors, but we handle them like normal arrays
895 log("Warning in /s_new handler: nested array argument detected");
896 set_control_array
<control_id_type
>(node
, control
, it
);
899 for (size_t i
= 0; i
!= array_size
; ++i
) {
900 if (it
->IsString() || it
->IsSymbol()) {
901 char const * name
= it
->AsStringUnchecked(); ++it
;
906 bus_id
= atoi(name
+1);
907 static_cast<sc_synth
*>(node
)->map_control_bus
<false>(control
, i
, bus_id
);
911 bus_id
= atoi(name
+1);
912 static_cast<sc_synth
*>(node
)->map_control_bus
<true>(control
, i
, bus_id
);
916 throw runtime_error("invalid name for control mapping");
919 float value
= extract_float_argument(it
++);
920 node
->set_control_array_element(control
, i
, value
);
925 if (!it
->IsArrayEnd())
926 throw runtime_error("missing array end tag");
927 ++it
; // skip array end
930 template <typename ControlSpecifier
>
931 void set_control(server_node
* node
, ControlSpecifier
const & control
, osc::ReceivedMessageArgumentIterator
& it
)
933 if (it
->IsArrayStart())
934 set_control_array(node
, control
, it
);
935 else if (it
->IsString() || it
->IsSymbol()) {
936 char const * name
= it
->AsStringUnchecked(); ++it
;
941 bus_id
= atoi(name
+1);
942 apply_control_bus_mapping
<false>(*node
, control
, bus_id
);
946 bus_id
= atoi(name
+1);
947 apply_control_bus_mapping
<true>(*node
, control
, bus_id
);
951 throw runtime_error("invalid name for control mapping");
955 float value
= extract_float_argument(it
++);
956 node
->set(control
, value
);
960 /* set control values of node from string/float or int/float pair */
961 void set_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
, osc::ReceivedMessageArgumentIterator end
)
964 osc::int32 index
= it
->AsInt32Unchecked(); ++it
;
965 if (it
== end
) return; // sclang sometimes uses an integer instead of an empty argument list
966 set_control(node
, index
, it
);
967 } else if (it
->IsString()) {
968 const char * str
= it
->AsStringUnchecked(); ++it
;
969 set_control(node
, str
, it
);
971 throw runtime_error("invalid argument");
974 void handle_s_new(received_message
const & msg
)
976 osc::ReceivedMessageArgumentIterator args
= msg
.ArgumentsBegin(), end
= msg
.ArgumentsEnd();
978 const char * def_name
= args
->AsString(); ++args
;
979 int32_t id
= args
->AsInt32(); ++args
;
982 id
= instance
->generate_node_id();
984 int32_t action
, target
;
987 action
= args
->AsInt32(); ++args
;
992 target
= args
->AsInt32(); ++args
;
996 sc_synth
* synth
= add_synth(def_name
, id
, action
, target
);
1003 set_control(synth
, args
, end
);
1004 } catch(std::exception
& e
) {
1005 log_printf("exception in /s_new: %s\n", e
.what());
1010 void handle_g_new(received_message
const & msg
)
1012 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1014 while(!args
.Eos()) {
1015 osc::int32 node_id
, action
, target_id
;
1016 args
>> node_id
>> action
>> target_id
;
1019 node_id
= instance
->generate_node_id();
1020 else if (!check_node_id(node_id
))
1023 server_node
* target
= find_node(target_id
);
1028 node_position_constraint pos
= make_pair(target
, node_position(action
));
1030 instance
->add_group(node_id
, pos
);
1031 last_generated
= node_id
;
1035 void handle_g_freeall(received_message
const & msg
)
1037 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1044 abstract_group
* group
= find_group(id
);
1048 bool success
= instance
->group_free_all(group
);
1051 log("/g_freeAll failue\n");
1055 void handle_g_deepFree(received_message
const & msg
)
1057 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1064 abstract_group
* group
= find_group(id
);
1068 bool success
= instance
->group_free_deep(group
);
1071 log("/g_freeDeep failue\n");
1075 void g_query_tree_fill_node(osc::OutboundPacketStream
& p
, bool flag
, server_node
const & node
)
1077 p
<< osc::int32(node
.id());
1078 if (node
.is_synth())
1081 p
<< osc::int32(static_cast<abstract_group
const &>(node
).child_count());
1083 if (node
.is_synth()) {
1084 sc_synth
const & scsynth
= static_cast<sc_synth
const&>(node
);
1085 p
<< scsynth
.prototype_name();
1088 osc::int32 controls
= scsynth
.mNumControls
;
1091 for (int i
= 0; i
!= controls
; ++i
) {
1092 p
<< osc::int32(i
); /** \todo later we can return symbols */
1094 if (scsynth
.mMapControls
[i
] != (scsynth
.mControls
+i
)) {
1095 /* we use a bus mapping */
1096 int bus
= (scsynth
.mMapControls
[i
]) - (scsynth
.mNode
.mWorld
->mControlBus
);
1098 sprintf(str
, "s%d", bus
);
1102 p
<< scsynth
.mControls
[i
];
1106 abstract_group
const & group
= static_cast<abstract_group
const &>(node
);
1107 group
.apply_on_children(boost::bind(g_query_tree_fill_node
, boost::ref(p
), flag
, _1
));
1111 template <bool realtime
>
1112 void g_query_tree(int node_id
, bool flag
, nova_endpoint
const & endpoint
)
1114 server_node
* node
= find_node(node_id
);
1115 if (!node
|| node
->is_synth())
1118 abstract_group
* group
= static_cast<abstract_group
*>(node
);
1120 size_t max_msg_size
= 1<<16;
1123 if (max_msg_size
> 1<<22)
1126 sized_array
<char, rt_pool_allocator
<char> > data(max_msg_size
);
1128 osc::OutboundPacketStream
p(data
.c_array(), max_msg_size
);
1129 p
<< osc::BeginMessage("/g_queryTree.reply")
1132 << osc::int32(group
->child_count());
1134 group
->apply_on_children(boost::bind(g_query_tree_fill_node
, boost::ref(p
), flag
, _1
));
1135 p
<< osc::EndMessage
;
1137 movable_array
<char> message(p
.Size(), data
.c_array());
1138 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
1143 max_msg_size
*= 2; /* if we run out of memory, retry with doubled memory resources */
1148 template <bool realtime
>
1149 void handle_g_queryTree(received_message
const & msg
, nova_endpoint
const & endpoint
)
1151 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1156 osc::int32 id
, flag
;
1158 g_query_tree
<realtime
>(id
, flag
, endpoint
);
1160 catch (std::exception
& e
) {
1161 log_printf("exception in handle_g_queryTree: %s\n", e
.what());
1166 typedef std::basic_stringstream
<char,
1167 std::char_traits
<char>/*,
1168 rt_pool_allocator<char>*/ > rt_string_stream
;
1170 void fill_spaces(rt_string_stream
& stream
, int level
)
1172 for (int i
= 0; i
!= level
*3; ++i
)
1176 void g_dump_node(rt_string_stream
& stream
, server_node
& node
, bool flag
, int level
)
1178 using namespace std
;
1179 fill_spaces(stream
, level
);
1181 if (node
.is_synth()) {
1182 abstract_synth
const & synth
= static_cast<abstract_synth
const &>(node
);
1183 stream
<< synth
.id() << " " << synth
.prototype_name() << endl
;
1189 abstract_group
& group
= static_cast<abstract_group
&>(node
);
1190 stream
<< group
.id();
1192 if (group
.is_parallel())
1193 stream
<< " parallel group";
1197 group
.apply_on_children(boost::bind(g_dump_node
, boost::ref(stream
), _1
, flag
, level
+ 1));
1201 void g_dump_tree(int id
, bool flag
)
1203 server_node
* node
= find_node(id
);
1207 // FIXME: can we completely avoid all internal allocations?
1208 rt_string_stream stream
;
1209 stream
<< "NODE TREE Group " << id
<< std::endl
;
1211 g_dump_node(stream
, *node
, flag
, 1);
1212 log(stream
.str().c_str(), stream
.str().size());
1215 void handle_g_dumpTree(received_message
const & msg
)
1217 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1222 osc::int32 id
, flag
;
1224 g_dump_tree(id
, flag
);
1226 catch (std::exception
& e
) {
1227 log_printf("exception in /g_dumpTree: %s\n", e
.what());
1232 void handle_n_free(received_message
const & msg
)
1234 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1242 server_node
* node
= find_node(id
);
1246 instance
->free_node(node
);
1248 catch (std::exception
& e
) {
1249 log_printf("exception in /n_free: %s\n", e
.what());
1254 /** macro to define an os command handler with a starting node id
1256 * it is mainly intended as decorator to avoid duplicate error handling code
1258 #define HANDLE_N_DECORATOR(cmd, function) \
1259 void handle_n_##cmd(received_message const & msg) \
1261 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); \
1262 osc::int32 id = it->AsInt32(); ++it; \
1264 server_node * node = find_node(id); \
1269 while (it != msg.ArgumentsEnd()) \
1270 function(node, it); \
1271 } catch(std::exception & e) { \
1272 log_printf("Exception during /n_" #cmd "handler: %s\n", e.what());\
1276 void set_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1278 if (it
->IsInt32()) {
1279 osc::int32 index
= it
->AsInt32Unchecked(); ++it
;
1280 set_control(node
, index
, it
);
1281 } else if (it
->IsString()) {
1282 const char * str
= it
->AsStringUnchecked(); ++it
;
1283 set_control(node
, str
, it
);
1285 throw runtime_error("invalid argument");
1289 HANDLE_N_DECORATOR(set
, set_control
)
1291 void set_control_n(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1293 if (it
->IsInt32()) {
1294 osc::int32 index
= it
->AsInt32Unchecked(); ++it
;
1295 osc::int32 count
= it
->AsInt32(); ++it
;
1297 for (int i
= 0; i
!= count
; ++i
)
1298 node
->set(index
+ i
, extract_float_argument(it
++));
1300 else if (it
->IsString()) {
1301 const char * str
= it
->AsStringUnchecked(); ++it
;
1302 osc::int32 count
= it
->AsInt32(); ++it
;
1304 sized_array
<float> values(count
);
1305 for (int i
= 0; i
!= count
; ++i
)
1306 values
[i
] = extract_float_argument(it
++);
1308 node
->set_control_array(str
, count
, values
.c_array());
1310 throw runtime_error("invalid argument");
1313 HANDLE_N_DECORATOR(setn
, set_control_n
)
1315 void fill_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1317 if (it
->IsInt32()) {
1318 osc::int32 index
= it
->AsInt32Unchecked(); ++it
;
1319 osc::int32 count
= it
->AsInt32(); ++it
;
1320 float value
= extract_float_argument(it
++);
1322 for (int i
= 0; i
!= count
; ++i
)
1323 node
->set(index
+ i
, value
);
1325 else if (it
->IsString()) {
1326 const char * str
= it
->AsStringUnchecked(); ++it
;
1327 osc::int32 count
= it
->AsInt32(); ++it
;
1328 float value
= extract_float_argument(it
++);
1330 sized_array
<float> values(count
);
1331 for (int i
= 0; i
!= count
; ++i
)
1334 node
->set_control_array(str
, count
, values
.c_array());
1336 throw runtime_error("invalid argument");
1339 HANDLE_N_DECORATOR(fill
, fill_control
)
1341 template <bool IsAudio
, typename slot_type
>
1342 void apply_control_bus_mapping(server_node
& node
, slot_type slot
, int bus_index
)
1344 if (node
.is_synth())
1345 static_cast<sc_synth
&>(node
).map_control_bus
<IsAudio
>(slot
, bus_index
);
1347 static_cast<abstract_group
&>(node
).apply_on_children(boost::bind(apply_control_bus_mapping
<IsAudio
, slot_type
>, _1
,
1351 template <bool IsAudio
, typename slot_type
>
1352 void apply_control_busn_mapping(server_node
& node
, slot_type slot
, int bus_index
, int count
)
1354 if (node
.is_synth())
1355 static_cast<sc_synth
&>(node
).map_control_buses
<IsAudio
>(slot
, bus_index
, count
);
1357 static_cast<abstract_group
&>(node
).apply_on_children(boost::bind(apply_control_busn_mapping
<IsAudio
, slot_type
>, _1
,
1358 slot
, bus_index
, count
));
1361 template <bool IsAudio
>
1362 void map_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1364 if (it
->IsInt32()) {
1365 osc::int32 control_index
= it
->AsInt32Unchecked(); ++it
;
1366 osc::int32 control_bus_index
= it
->AsInt32(); ++it
;
1368 apply_control_bus_mapping
<IsAudio
>(*node
, control_index
, control_bus_index
);
1370 else if (it
->IsString()) {
1371 const char * control_name
= it
->AsStringUnchecked(); ++it
;
1372 osc::int32 control_bus_index
= it
->AsInt32(); ++it
;
1374 apply_control_bus_mapping
<IsAudio
>(*node
, control_name
, control_bus_index
);
1376 throw runtime_error("invalid argument");
1379 template <bool IsAudio
>
1380 void mapn_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1382 if (it
->IsInt32()) {
1383 osc::int32 control_index
= it
->AsInt32Unchecked(); ++it
;
1384 osc::int32 bus_index
= it
->AsInt32(); ++it
;
1385 osc::int32 count
= it
->AsInt32(); ++it
;
1387 apply_control_busn_mapping
<IsAudio
>(*node
, control_index
, bus_index
, count
);
1389 else if (it
->IsString()) {
1390 const char * control_name
= it
->AsStringUnchecked(); ++it
;
1391 osc::int32 bus_index
= it
->AsInt32(); ++it
;
1392 osc::int32 count
= it
->AsInt32(); ++it
;
1394 apply_control_busn_mapping
<IsAudio
>(*node
, control_name
, bus_index
, count
);
1396 throw runtime_error("invalid argument");
1400 HANDLE_N_DECORATOR(map
, map_control
<false>)
1401 HANDLE_N_DECORATOR(mapa
, map_control
<true>)
1402 HANDLE_N_DECORATOR(mapn
, mapn_control
<false>)
1403 HANDLE_N_DECORATOR(mapan
, mapn_control
<true>)
1405 template <nova::node_position Relation
>
1406 void handle_n_before_or_after(received_message
const & msg
)
1408 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1410 while(!args
.Eos()) {
1411 osc::int32 node_a
, node_b
;
1412 args
>> node_a
>> node_b
;
1414 server_node
* a
= find_node(node_a
);
1417 server_node
* b
= find_node(node_b
);
1420 abstract_group::move_before_or_after
<Relation
>(a
, b
);
1426 template <nova::node_position Position
>
1427 void handle_g_head_or_tail(received_message
const & msg
)
1429 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1431 while(!args
.Eos()) {
1432 osc::int32 node_id
, target_id
;
1433 args
>> target_id
>> node_id
;
1435 server_node
* node
= find_node(node_id
);
1436 if (!node
) continue;
1438 abstract_group
* target_group
= find_group(target_id
);
1439 if (!target_group
) continue;
1441 abstract_group::move_to_head_or_tail
<Position
>(node
, target_group
);
1447 void handle_n_query(received_message
const & msg
, nova_endpoint
const & endpoint
)
1449 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1456 server_node
* node
= find_node(node_id
);
1460 char buffer
[128]; // 128 byte should be enough
1461 osc::OutboundPacketStream
p(buffer
, 128);
1462 p
<< osc::BeginMessage("/n_info");
1463 fill_notification(node
, p
);
1465 movable_array
<char> message(p
.Size(), p
.Data());
1466 cmd_dispatcher
<true>::fire_system_callback(boost::bind(send_udp_message
, message
, endpoint
));
1470 void handle_n_order(received_message
const & msg
)
1472 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1474 osc::int32 action
, target_id
;
1475 args
>> action
>> target_id
;
1477 server_node
* target
= find_node(target_id
);
1482 abstract_group
* target_parent
;
1483 if (action
== before
||
1485 target_parent
= target
->get_parent();
1487 if (target
->is_synth())
1488 throw std::runtime_error("invalid argument for n_order: argument is no synth");
1489 target_parent
= static_cast<abstract_group
*>(target
);
1497 server_node
* node
= find_node(node_id
);
1501 abstract_group
* node_parent
= node
->get_parent();
1503 /** \todo this can be optimized if node_parent == target_parent */
1504 node_parent
->remove_child(node
);
1505 if (action
== before
||
1507 target_parent
->add_child(node
, make_pair(target
, node_position(action
)));
1509 target_parent
->add_child(node
, node_position(action
));
1511 instance
->update_dsp_queue();
1515 void handle_n_run(received_message
const & msg
)
1517 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1519 while(!args
.Eos()) {
1520 osc::int32 node_id
, run_flag
;
1521 args
>> node_id
>> run_flag
;
1523 server_node
* node
= find_node(node_id
);
1528 instance
->node_resume(node
);
1530 instance
->node_pause(node
);
1534 void enable_tracing(server_node
& node
)
1536 if (node
.is_synth()) {
1537 sc_synth
& synth
= static_cast<sc_synth
&>(node
);
1538 synth
.enable_tracing();
1540 abstract_group
& group
= static_cast<abstract_group
&>(node
);
1541 group
.apply_on_children(enable_tracing
);
1545 void handle_n_trace(received_message
const & msg
)
1547 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1549 while(!args
.Eos()) {
1553 server_node
* node
= find_node(node_id
);
1557 enable_tracing(*node
);
1562 void handle_s_noid(received_message
const & msg
)
1564 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1566 while(!args
.Eos()) {
1569 instance
->synth_reassign_id(node_id
);
1573 int32_t get_control_index(sc_synth
* s
, osc::ReceivedMessageArgumentIterator
& it
, osc::OutboundPacketStream
& p
)
1578 control
= it
->AsInt32Unchecked(); ++it
;
1581 else if (it
->IsString())
1583 const char * control_str
= it
->AsStringUnchecked(); ++it
;
1584 control
= s
->resolve_slot(control_str
);
1587 else if (it
->IsSymbol())
1589 const char * control_str
= it
->AsSymbolUnchecked(); ++it
;
1590 control
= s
->resolve_slot(control_str
);
1591 p
<< osc::Symbol(control_str
);
1594 throw std::runtime_error("wrong argument type");
1598 template <bool realtime
>
1599 void handle_s_get(received_message
const & msg
, size_t msg_size
, nova_endpoint
const & endpoint
)
1601 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
1604 throw std::runtime_error("wrong argument type");
1606 int32_t node_id
= it
->AsInt32Unchecked(); ++it
;
1608 server_node
* node
= find_node(node_id
);
1609 if (!node
|| !node
->is_synth())
1610 throw std::runtime_error("node is not a synth");
1612 sc_synth
* s
= static_cast<sc_synth
*>(node
);
1614 size_t alloc_size
= msg_size
+ sizeof(float) * (msg
.ArgumentCount()-1) + 128;
1616 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
1618 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
1619 p
<< osc::BeginMessage("/n_set")
1622 while (it
!= msg
.ArgumentsEnd())
1624 int32_t control
= get_control_index(s
, it
, p
);
1625 p
<< s
->get(control
);
1627 p
<< osc::EndMessage
;
1629 movable_array
<char> message(p
.Size(), return_message
.c_array());
1630 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
1633 template <bool realtime
>
1634 void handle_s_getn(received_message
const & msg
, size_t msg_size
, nova_endpoint
const & endpoint
)
1636 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
1639 throw std::runtime_error("wrong argument type");
1641 int32_t node_id
= it
->AsInt32Unchecked(); ++it
;
1643 server_node
* node
= find_node(node_id
);
1644 if (!node
|| !node
->is_synth())
1645 throw std::runtime_error("node is not a synth");
1647 sc_synth
* s
= static_cast<sc_synth
*>(node
);
1649 /* count argument values */
1650 size_t argument_count
= 0;
1651 for (osc::ReceivedMessageArgumentIterator local
= it
; local
!= msg
.ArgumentsEnd(); ++local
)
1653 ++local
; /* skip control */
1654 if (local
== msg
.ArgumentsEnd())
1657 throw std::runtime_error("invalid count");
1658 argument_count
+= it
->AsInt32Unchecked(); ++it
;
1661 size_t alloc_size
= msg_size
+ sizeof(float) * (argument_count
) + 128;
1663 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
1665 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
1666 p
<< osc::BeginMessage("/n_setn")
1669 while (it
!= msg
.ArgumentsEnd())
1671 int32_t control
= get_control_index(s
, it
, p
);
1674 throw std::runtime_error("integer argument expected");
1676 int32_t control_count
= it
->AsInt32Unchecked(); ++it
;
1677 if (control_count
< 0)
1680 for (int i
= 0; i
!= control_count
; ++i
)
1681 p
<< s
->get(control
+ i
);
1683 p
<< osc::EndMessage
;
1685 movable_array
<char> message(p
.Size(), return_message
.c_array());
1686 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
1690 /** wrapper class for osc completion message
1692 struct completion_message
1694 /** constructor should only be used from the real-time thread */
1695 completion_message(size_t size
, const void * data
):
1699 data_
= system_callback::allocate(size
);
1700 memcpy(data_
, data
, size
);
1704 /** default constructor creates uninitialized object */
1705 completion_message(void):
1709 /** copy constructor has move semantics!!! */
1710 completion_message(completion_message
const & rhs
)
1715 completion_message
& operator=(completion_message
const & rhs
)
1719 const_cast<completion_message
&>(rhs
).size_
= 0;
1723 ~completion_message(void)
1726 system_callback::deallocate(data_
);
1729 /** handle package in the rt thread
1730 * not to be called from the rt thread
1732 void trigger_async(nova_endpoint
const & endpoint
)
1735 sc_osc_handler::received_packet
* p
=
1736 sc_osc_handler::received_packet::alloc_packet((char*)data_
, size_
, endpoint
);
1737 instance
->add_sync_callback(p
);
1741 /** handle package directly
1742 * only to be called from the rt thread
1744 void handle(nova_endpoint
const & endpoint
)
1747 instance
->handle_packet((char*)data_
, size_
, endpoint
);
1754 completion_message
extract_completion_message(osc::ReceivedMessageArgumentStream
& args
)
1756 osc::Blob
blob(0, 0);
1762 catch (osc::WrongArgumentTypeException
& e
)
1766 return completion_message (blob
.size
, blob
.data
);
1769 completion_message
extract_completion_message(osc::ReceivedMessageArgumentIterator
& it
)
1771 const void * data
= 0;
1772 unsigned long length
= 0;
1775 it
->AsBlobUnchecked(data
, length
);
1777 return completion_message(length
, data
);
1781 template <bool realtime
>
1782 void b_alloc_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1783 void b_alloc_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1785 template <bool realtime
>
1786 void b_alloc_1_nrt(uint32_t index
, uint32_t frames
, uint32_t channels
, completion_message
& msg
, nova_endpoint
const & endpoint
)
1788 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
1789 sample
* free_buf
= sc_factory
->get_nrt_mirror_buffer(index
);
1790 sc_factory
->allocate_buffer(index
, frames
, channels
);
1791 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_alloc_2_rt
<realtime
>, index
, msg
, free_buf
, endpoint
));
1794 template <bool realtime
>
1795 void b_alloc_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1797 sc_factory
->buffer_sync(index
);
1798 msg
.handle(endpoint
);
1799 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_alloc_3_nrt
, index
, free_buf
, endpoint
));
1802 void b_alloc_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1804 free_aligned(free_buf
);
1805 send_done_message(endpoint
, "/b_alloc", index
);
1808 template <bool realtime
>
1809 void handle_b_alloc(received_message
const & msg
, nova_endpoint
const & endpoint
)
1811 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1813 osc::int32 index
, frames
, channels
;
1815 args
>> index
>> frames
;
1822 completion_message message
= extract_completion_message(args
);
1824 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_alloc_1_nrt
<realtime
>, index
, frames
,
1825 channels
, message
, endpoint
));
1828 template <bool realtime
>
1829 void b_free_1_nrt(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
);
1830 template <bool realtime
>
1831 void b_free_2_rt(uint32_t index
, sample
* free_buf
, completion_message
& msg
, nova_endpoint
const & endpoint
);
1832 void b_free_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1834 template <bool realtime
>
1835 void b_free_1_nrt(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
1837 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
1838 sample
* free_buf
= sc_factory
->get_nrt_mirror_buffer(index
);
1839 sc_factory
->free_buffer(index
);
1840 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_free_2_rt
<realtime
>,
1841 index
, free_buf
, msg
, endpoint
));
1844 template <bool realtime
>
1845 void b_free_2_rt(uint32_t index
, sample
* free_buf
, completion_message
& msg
, nova_endpoint
const & endpoint
)
1847 sc_factory
->buffer_sync(index
);
1848 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_free_3_nrt
, index
, free_buf
, endpoint
));
1849 msg
.handle(endpoint
);
1852 void b_free_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1854 free_aligned(free_buf
);
1855 send_done_message(endpoint
, "/b_free", index
);
1859 template <bool realtime
>
1860 void handle_b_free(received_message
const & msg
, nova_endpoint
const & endpoint
)
1862 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1867 completion_message message
= extract_completion_message(args
);
1869 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_free_1_nrt
<realtime
>, index
, message
, endpoint
));
1872 template <bool realtime
>
1873 void b_allocRead_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1874 void b_allocRead_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1876 template <bool realtime
>
1877 void b_allocRead_1_nrt(uint32_t index
, movable_string
& filename
, uint32_t start
, uint32_t frames
, completion_message
& msg
,
1878 nova_endpoint
const & endpoint
)
1880 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
1881 sample
* free_buf
= sc_factory
->get_nrt_mirror_buffer(index
);
1882 int error
= sc_factory
->buffer_read_alloc(index
, filename
.c_str(), start
, frames
);
1884 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_allocRead_2_rt
<realtime
>, index
, msg
, free_buf
, endpoint
));
1886 /* post nice error message */;
1889 template <bool realtime
>
1890 void b_allocRead_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
,
1891 nova_endpoint
const & endpoint
)
1893 sc_factory
->buffer_sync(index
);
1894 msg
.handle(endpoint
);
1895 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_allocRead_3_nrt
, index
, free_buf
, endpoint
));
1898 void b_allocRead_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1900 free_aligned(free_buf
);
1901 send_done_message(endpoint
, "/b_allocRead", index
);
1904 template <bool realtime
>
1905 void handle_b_allocRead(received_message
const & msg
, nova_endpoint
const & endpoint
)
1907 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1910 const char * filename
;
1912 osc::int32 start
= 0;
1913 osc::int32 frames
= 0;
1915 args
>> index
>> filename
;
1923 completion_message message
= extract_completion_message(args
);
1925 movable_string
fname(filename
);
1926 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_allocRead_1_nrt
<realtime
>, index
,
1927 fname
, start
, frames
, message
, endpoint
));
1930 template <bool realtime
>
1931 void b_allocReadChannel_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
,
1932 nova_endpoint
const & endpoint
);
1933 void b_allocReadChannel_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1935 template <bool realtime
>
1936 void b_allocReadChannel_1_nrt(uint32_t index
, movable_string
const & filename
, uint32_t start
, uint32_t frames
,
1937 movable_array
<uint32_t> const & channels
, completion_message
& msg
,
1938 nova_endpoint
const & endpoint
)
1940 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
1941 sample
* free_buf
= sc_factory
->get_nrt_mirror_buffer(index
);
1942 int error
= sc_factory
->buffer_alloc_read_channels(index
, filename
.c_str(), start
, frames
,
1943 channels
.size(), channels
.data());
1945 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_allocReadChannel_2_rt
<realtime
>,
1946 index
, msg
, free_buf
, endpoint
));
1949 template <bool realtime
>
1950 void b_allocReadChannel_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
,
1951 nova_endpoint
const & endpoint
)
1953 sc_factory
->buffer_sync(index
);
1954 msg
.handle(endpoint
);
1955 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_allocReadChannel_3_nrt
,
1956 index
, free_buf
, endpoint
));
1959 void b_allocReadChannel_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1961 free_aligned(free_buf
);
1962 send_done_message(endpoint
, "/b_allocReadChannel", index
);
1966 template <bool realtime
>
1967 void handle_b_allocReadChannel(received_message
const & msg
, nova_endpoint
const & endpoint
)
1969 osc::ReceivedMessageArgumentIterator arg
= msg
.ArgumentsBegin();
1971 osc::int32 index
= arg
->AsInt32(); arg
++;
1972 const char * filename
= arg
->AsString(); arg
++;
1974 osc::int32 start
= arg
->AsInt32(); arg
++;
1975 size_t frames
= arg
->AsInt32(); arg
++;
1977 size_t channel_args
= msg
.ArgumentCount() - 4; /* we already consumed 4 elements */
1979 size_t channel_count
= 0;
1980 sized_array
<uint
, rt_pool_allocator
<uint
> > channels(channel_args
);
1982 for (uint i
= 0; i
!= channel_args
- 1; ++i
) // sclang fromats the last completion message as int, so we skip the last element
1984 if (arg
->IsInt32()) {
1985 channels
[i
] = arg
->AsInt32Unchecked(); arg
++;
1990 /* we reached the message blob */
1991 completion_message message
= extract_completion_message(arg
);
1993 movable_array
<uint32_t> channel_mapping(channel_count
, channels
.c_array());
1994 movable_string
fname(filename
);
1996 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_allocReadChannel_1_nrt
<realtime
>,
1997 index
, fname
, start
, frames
, channel_mapping
,
1998 message
, endpoint
));
2001 const char * b_write
= "/b_write";
2003 template <bool realtime
>
2004 void b_write_nrt_1(uint32_t index
, movable_string
const & filename
, movable_string
const & header_format
,
2005 movable_string
const & sample_format
, uint32_t start
, uint32_t frames
, bool leave_open
,
2006 completion_message
& msg
, nova_endpoint
const & endpoint
)
2008 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
2009 sc_factory
->buffer_write(index
, filename
.c_str(), header_format
.c_str(), sample_format
.c_str(), start
, frames
, leave_open
);
2010 msg
.trigger_async(endpoint
);
2011 cmd_dispatcher
<realtime
>::fire_done_message(endpoint
, b_write
, index
);
2014 void fire_b_write_exception(void)
2016 throw std::runtime_error("wrong arguments for /b_allocReadChannel");
2019 template <bool realtime
>
2020 void handle_b_write(received_message
const & msg
, nova_endpoint
const & endpoint
)
2022 osc::ReceivedMessageArgumentIterator arg
= msg
.ArgumentsBegin();
2023 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2026 osc::int32 index
= arg
->AsInt32(); arg
++;
2027 const char * filename
= arg
->AsString(); arg
++;
2028 const char * header_format
= arg
->AsString(); arg
++;
2029 const char * sample_format
= arg
->AsString(); arg
++;
2032 osc::int32 frames
= -1;
2033 osc::int32 start
= 0;
2034 osc::int32 leave_open
= 0;
2036 completion_message message
;
2039 if (!arg
->IsInt32())
2040 fire_b_write_exception();
2041 frames
= arg
->AsInt32Unchecked(); arg
++;
2047 if (!arg
->IsInt32())
2048 fire_b_write_exception();
2049 start
= arg
->AsInt32Unchecked(); arg
++;
2055 if (!arg
->IsInt32())
2056 fire_b_write_exception();
2057 leave_open
= arg
->AsInt32Unchecked(); arg
++;
2063 message
= extract_completion_message(arg
);
2066 movable_string
fname(filename
);
2067 movable_string
header_f(header_format
);
2068 movable_string
sample_f(sample_format
);
2070 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_write_nrt_1
<realtime
>, index
, fname
, header_f
, sample_f
,
2071 start
, frames
, bool(leave_open
), message
, endpoint
));
2074 template <bool realtime
>
2075 void b_read_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
);
2077 template <bool realtime
>
2078 void b_read_nrt_1(uint32_t index
, movable_string
& filename
, uint32_t start_file
, uint32_t frames
,
2079 uint32_t start_buffer
, bool leave_open
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2081 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
2082 sc_factory
->buffer_read(index
, filename
.c_str(), start_file
, frames
, start_buffer
, leave_open
);
2083 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_read_rt_2
<realtime
>, index
, msg
, endpoint
));
2086 const char * b_read
= "/b_read";
2087 template <bool realtime
>
2088 void b_read_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2090 sc_factory
->buffer_sync(index
);
2091 msg
.handle(endpoint
);
2092 cmd_dispatcher
<realtime
>::fire_done_message(endpoint
, b_read
, index
);
2095 void fire_b_read_exception(void)
2097 throw std::runtime_error("wrong arguments for /b_read");
2100 template <bool realtime
>
2101 void handle_b_read(received_message
const & msg
, nova_endpoint
const & endpoint
)
2103 osc::ReceivedMessageArgumentIterator arg
= msg
.ArgumentsBegin();
2104 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2107 osc::int32 index
= arg
->AsInt32(); arg
++;
2108 const char * filename
= arg
->AsString(); arg
++;
2111 osc::int32 start_file
= 0;
2112 osc::int32 frames
= -1;
2113 osc::int32 start_buffer
= 0;
2114 osc::int32 leave_open
= 0;
2116 completion_message message
;
2119 if (!arg
->IsInt32())
2120 fire_b_read_exception();
2121 start_file
= arg
->AsInt32Unchecked(); arg
++;
2127 if (!arg
->IsInt32())
2128 fire_b_read_exception();
2129 frames
= arg
->AsInt32Unchecked(); arg
++;
2135 if (!arg
->IsInt32())
2136 fire_b_read_exception();
2137 start_buffer
= arg
->AsInt32Unchecked(); arg
++;
2143 if (!arg
->IsInt32())
2144 fire_b_read_exception();
2145 leave_open
= arg
->AsInt32Unchecked(); arg
++;
2151 message
= extract_completion_message(arg
);
2154 movable_string
fname(filename
);
2156 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_read_nrt_1
<realtime
>, index
, fname
,
2157 start_file
, frames
, start_buffer
,
2158 bool(leave_open
), message
, endpoint
));
2162 template <bool realtime
>
2163 void b_readChannel_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
);
2165 template <bool realtime
>
2166 void b_readChannel_nrt_1(uint32_t index
, movable_string
& filename
, uint32_t start_file
, uint32_t frames
,
2167 uint32_t start_buffer
, bool leave_open
, movable_array
<uint32_t> & channel_map
,
2168 completion_message
& msg
, nova_endpoint
const & endpoint
)
2170 sc_factory
->buffer_read_channel(index
, filename
.c_str(), start_file
, frames
, start_buffer
, leave_open
,
2171 channel_map
.size(), channel_map
.data());
2172 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_readChannel_rt_2
<realtime
>, index
, msg
, endpoint
));
2175 const char * b_readChannel
= "/b_readChannel";
2176 template <bool realtime
>
2177 void b_readChannel_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2179 sc_factory
->buffer_sync(index
);
2180 msg
.handle(endpoint
);
2181 cmd_dispatcher
<realtime
>::fire_done_message(endpoint
, b_readChannel
, index
);
2184 void fire_b_readChannel_exception(void)
2186 throw std::runtime_error("wrong arguments for /b_readChannel");
2189 template <bool realtime
>
2190 void handle_b_readChannel(received_message
const & msg
, nova_endpoint
const & endpoint
)
2192 osc::ReceivedMessageArgumentIterator arg
= msg
.ArgumentsBegin();
2193 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2196 osc::int32 index
= arg
->AsInt32(); arg
++;
2197 const char * filename
= arg
->AsString(); arg
++;
2200 osc::int32 start_file
= 0;
2201 osc::int32 frames
= -1;
2202 osc::int32 start_buffer
= 0;
2203 osc::int32 leave_open
= 0;
2205 sized_array
<uint32_t, rt_pool_allocator
<uint32_t> > channel_mapping(int32_t(msg
.ArgumentCount())); /* larger than required */
2206 uint32_t channel_count
= 0;
2208 completion_message message
;
2211 if (!arg
->IsInt32())
2212 fire_b_read_exception();
2213 start_file
= arg
->AsInt32Unchecked(); arg
++;
2219 if (!arg
->IsInt32())
2220 fire_b_read_exception();
2221 frames
= arg
->AsInt32Unchecked(); arg
++;
2227 if (!arg
->IsInt32())
2228 fire_b_write_exception();
2229 start_buffer
= arg
->AsInt32Unchecked(); arg
++;
2235 if (!arg
->IsInt32())
2236 fire_b_write_exception();
2237 leave_open
= arg
->AsInt32Unchecked(); arg
++;
2244 if (arg
->IsBlob()) {
2245 message
= extract_completion_message(arg
);
2248 else if (arg
->IsInt32()) {
2249 channel_mapping
[channel_count
] = arg
->AsInt32Unchecked();
2253 fire_b_readChannel_exception();
2257 movable_string
fname(filename
);
2258 movable_array
<uint32_t> channel_map(channel_count
, channel_mapping
.c_array());
2260 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_readChannel_nrt_1
<realtime
>, index
, fname
,
2261 start_file
, frames
, start_buffer
,
2262 bool(leave_open
), channel_map
, message
, endpoint
));
2266 template <bool realtime
>
2267 void b_zero_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
);
2269 template <bool realtime
>
2270 void b_zero_nrt_1(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2272 sc_factory
->buffer_zero(index
);
2273 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_zero_rt_2
<realtime
>, index
, msg
, endpoint
));
2276 const char * b_zero
= "/b_zero";
2277 template <bool realtime
>
2278 void b_zero_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2280 sc_factory
->increment_write_updates(index
);
2281 msg
.handle(endpoint
);
2282 cmd_dispatcher
<realtime
>::fire_done_message(endpoint
, b_zero
, index
);
2285 template <bool realtime
>
2286 void handle_b_zero(received_message
const & msg
, nova_endpoint
const & endpoint
)
2288 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2292 completion_message message
= extract_completion_message(args
);
2294 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_zero_nrt_1
<realtime
>, index
, message
, endpoint
));
2297 void handle_b_set(received_message
const & msg
)
2299 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2300 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2301 verify_argument(it
, end
);
2302 osc::int32 buffer_index
= it
->AsInt32(); ++it
;
2304 buffer_wrapper::sample_t
* data
= sc_factory
->get_buffer(buffer_index
);
2307 osc::int32 index
= it
->AsInt32(); ++it
;
2308 float value
= extract_float_argument(it
++);
2310 data
[index
] = value
;
2314 void handle_b_setn(received_message
const & msg
)
2316 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2317 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2318 verify_argument(it
, end
);
2319 osc::int32 buffer_index
= it
->AsInt32(); ++it
;
2321 buffer_wrapper::sample_t
* data
= sc_factory
->get_buffer(buffer_index
);
2324 osc::int32 index
= it
->AsInt32(); ++it
;
2325 verify_argument(it
, end
);
2326 osc::int32 samples
= it
->AsInt32(); ++it
;
2328 for (int i
= 0; i
!= samples
; ++i
) {
2329 verify_argument(it
, end
);
2330 float value
= extract_float_argument(it
++);
2331 data
[index
+i
] = value
;
2336 void handle_b_fill(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
;
2349 verify_argument(it
, end
);
2350 float value
= extract_float_argument(it
++);
2352 for (int i
= 0; i
!= samples
; ++i
)
2353 data
[index
] = value
;
2357 template <bool realtime
>
2358 void handle_b_query(received_message
const & msg
, nova_endpoint
const & endpoint
)
2360 const size_t elem_size
= 3*sizeof(int) * sizeof(float);
2362 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2363 size_t arg_count
= msg
.ArgumentCount();
2365 size_t size
= elem_size
* arg_count
+ 128; /* should be more than required */
2366 sized_array
<char, rt_pool_allocator
<char> > data(size
);
2368 osc::OutboundPacketStream
p(data
.c_array(), size
);
2369 p
<< osc::BeginMessage("/b_info");
2371 while (!args
.Eos()) {
2372 osc::int32 buffer_index
;
2373 args
>> buffer_index
;
2375 SndBuf
* buf
= sc_factory
->get_buffer_struct(buffer_index
);
2378 << osc::int32(buf
->frames
)
2379 << osc::int32(buf
->channels
)
2380 << float (buf
->samplerate
);
2383 p
<< osc::EndMessage
;
2385 movable_array
<char> message(p
.Size(), data
.c_array());
2387 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2390 template <bool realtime
>
2391 void b_close_rt_2(completion_message
& msg
, nova_endpoint
const & endpoint
);
2393 template <bool realtime
>
2394 void b_close_nrt_1(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2396 sc_factory
->buffer_close(index
);
2397 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_close_rt_2
<realtime
>, msg
, endpoint
));
2400 template <bool realtime
>
2401 void b_close_rt_2(completion_message
& msg
, nova_endpoint
const & endpoint
)
2405 template <bool realtime
>
2406 void handle_b_close(received_message
const & msg
, nova_endpoint
const & endpoint
)
2408 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2412 completion_message message
= extract_completion_message(args
);
2413 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_close_nrt_1
<realtime
>, index
, message
, endpoint
));
2416 template <bool realtime
>
2417 void handle_b_get(received_message
const & msg
, nova_endpoint
const & endpoint
)
2419 const size_t elem_size
= sizeof(int) * sizeof(float);
2420 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2421 const size_t index_count
= msg
.ArgumentCount() - 1;
2422 const size_t alloc_size
= index_count
* elem_size
+ 128; /* hopefully enough */
2424 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
2426 osc::int32 buffer_index
;
2427 args
>> buffer_index
;
2429 const SndBuf
* buf
= sc_factory
->get_buffer_struct(buffer_index
);
2430 const sample
* data
= buf
->data
;
2431 const int max_sample
= buf
->frames
* buf
->channels
;
2433 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
2434 p
<< osc::BeginMessage("/b_set")
2443 if (index
< max_sample
)
2449 p
<< osc::EndMessage
;
2451 movable_array
<char> message(p
.Size(), return_message
.c_array());
2452 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2455 template<typename Alloc
>
2458 getn_data(int start
, int count
, const float * data
):
2459 start_index_(start
), data_(count
)
2461 data_
.reserve(count
);
2462 for (int i
= 0; i
!= count
; ++i
)
2467 std::vector
<float, Alloc
> data_
;
2470 template <bool realtime
>
2471 void handle_b_getn(received_message
const & msg
, nova_endpoint
const & endpoint
)
2473 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2475 typedef getn_data
<rt_pool_allocator
<float> > getn_data
;
2476 std::vector
<getn_data
, rt_pool_allocator
<getn_data
> > return_data
;
2478 osc::int32 buffer_index
;
2479 args
>> buffer_index
;
2481 const SndBuf
* buf
= sc_factory
->get_buffer_struct(buffer_index
);
2482 const sample
* data
= buf
->data
;
2483 const int max_sample
= buf
->frames
* buf
->channels
;
2487 osc::int32 index
, sample_count
;
2488 args
>> index
>> sample_count
;
2490 if (index
+ sample_count
<= max_sample
)
2491 return_data
.push_back(getn_data(index
, sample_count
, data
+ index
));
2494 size_t alloc_size
= 128;
2495 for (size_t i
= 0; i
!= return_data
.size(); ++i
)
2496 alloc_size
+= return_data
[i
].data_
.size() * (sizeof(float) + sizeof(int)) + 2*sizeof(int);
2498 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
2500 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
2501 p
<< osc::BeginMessage("/b_setn")
2504 for (size_t i
= 0; i
!= return_data
.size(); ++i
) {
2505 p
<< osc::int32(return_data
[i
].start_index_
)
2506 << osc::int32(return_data
[i
].data_
.size());
2508 for (size_t j
= 0; j
!= return_data
[i
].data_
.size(); ++j
)
2509 p
<< return_data
[i
].data_
[j
];
2512 p
<< osc::EndMessage
;
2514 movable_array
<char> message(p
.Size(), return_message
.c_array());
2515 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2519 template <bool realtime
>
2520 void b_gen_rt_2(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
2521 void b_gen_nrt_3(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
2523 template <bool realtime
>
2524 void b_gen_nrt_1(movable_array
<char> & message
, nova_endpoint
const & endpoint
)
2526 sc_msg_iter
msg(message
.size(), (char*)message
.data());
2528 int index
= msg
.geti();
2529 const char * generator
= (const char*)msg
.gets4();
2533 sample
* free_buf
= sc_factory
->buffer_generate(index
, generator
, msg
);
2534 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_gen_rt_2
<realtime
>, index
, free_buf
, endpoint
));
2537 template <bool realtime
>
2538 void b_gen_rt_2(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
2540 sc_factory
->buffer_sync(index
);
2541 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_gen_nrt_3
, index
, free_buf
, endpoint
));
2544 void b_gen_nrt_3(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
2546 free_aligned(free_buf
);
2547 send_done_message(endpoint
, "/b_gen", index
);
2550 template <bool realtime
>
2551 void handle_b_gen(received_message
const & msg
, size_t msg_size
, nova_endpoint
const & endpoint
)
2553 movable_array
<char> cmd (msg_size
, msg
.TypeTags()-1);
2554 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_gen_nrt_1
<realtime
>, cmd
, endpoint
));
2558 void handle_c_set(received_message
const & msg
)
2560 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2562 while (it
!= msg
.ArgumentsEnd()) {
2563 osc::int32 bus_index
= it
->AsInt32(); ++it
;
2564 float value
= extract_float_argument(it
++);
2566 sc_factory
->controlbus_set(bus_index
, value
);
2570 void handle_c_setn(received_message
const & msg
)
2572 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2574 while (it
!= msg
.ArgumentsEnd()) {
2575 osc::int32 bus_index
, bus_count
;
2576 bus_index
= it
->AsInt32(); ++it
;
2577 bus_count
= it
->AsInt32(); ++it
;
2579 for (int i
= 0; i
!= bus_count
; ++i
) {
2580 float value
= extract_float_argument(it
++);
2581 sc_factory
->controlbus_set(bus_index
+ i
, value
);
2586 void handle_c_fill(received_message
const & msg
)
2588 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2590 while (it
!= msg
.ArgumentsEnd()) {
2591 osc::int32 bus_index
, bus_count
;
2592 bus_index
= it
->AsInt32(); ++it
;
2593 bus_count
= it
->AsInt32(); ++it
;
2594 float value
= extract_float_argument(it
++);
2595 sc_factory
->controlbus_fill(bus_index
, bus_count
, value
);
2599 template <bool realtime
>
2600 void handle_c_get(received_message
const & msg
,
2601 nova_endpoint
const & endpoint
)
2603 const size_t elem_size
= sizeof(int) + sizeof(float);
2604 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2605 const size_t index_count
= msg
.ArgumentCount();
2606 const size_t alloc_size
= index_count
* elem_size
+ 128; /* hopefully enough */
2608 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
2610 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
2611 p
<< osc::BeginMessage("/c_set");
2618 p
<< index
<< sc_factory
->controlbus_get(index
);
2621 p
<< osc::EndMessage
;
2623 movable_array
<char> message(p
.Size(), return_message
.c_array());
2624 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2627 template <bool realtime
>
2628 void handle_c_getn(received_message
const & msg
, nova_endpoint
const & endpoint
)
2630 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2632 /* we pessimize, but better to allocate too much than too little */
2633 const size_t alloc_size
= 128 +
2634 (2 * sizeof(int) + 128*sizeof(float)) * msg
.ArgumentCount();
2636 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
2638 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
2639 p
<< osc::BeginMessage("/c_setn");
2643 osc::int32 bus_index
, bus_count
;
2644 args
>> bus_index
>> bus_count
;
2645 p
<< bus_index
<< bus_count
;
2647 for (int i
= 0; i
!= bus_count
; ++i
) {
2648 float value
= sc_factory
->controlbus_get(bus_index
+ i
);
2653 p
<< osc::EndMessage
;
2655 movable_array
<char> message(p
.Size(), return_message
.c_array());
2656 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2659 #ifdef BOOST_HAS_RVALUE_REFS
2660 std::pair
<sc_synth_prototype_ptr
*, size_t> wrap_synthdefs(std::vector
<sc_synthdef
> && defs
)
2662 std::vector
<sc_synthdef
> synthdefs(std::move(defs
));
2663 size_t count
= synthdefs
.size();
2664 sc_synth_prototype_ptr
* prototypes
= new sc_synth_prototype_ptr
[count
];
2666 for (size_t i
= 0; i
!= count
; ++i
)
2667 prototypes
[i
].reset(new sc_synth_prototype(std::move(synthdefs
[i
])));
2668 return std::make_pair(prototypes
, count
);
2671 std::pair
<sc_synth_prototype_ptr
*, size_t> wrap_synthdefs(std::vector
<sc_synthdef
> const & defs
)
2673 size_t count
= defs
.size();
2674 sc_synth_prototype_ptr
* prototypes
= new sc_synth_prototype_ptr
[count
];
2676 for (size_t i
= 0; i
!= count
; ++i
)
2677 prototypes
[i
].reset(new sc_synth_prototype(defs
[i
]));
2678 return std::make_pair(prototypes
, count
);
2681 template <bool realtime
>
2682 void d_recv_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2683 nova_endpoint
const & endpoint
);
2684 void d_recv_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
);
2686 template <bool realtime
>
2687 void d_recv_nrt(movable_array
<char> & def
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2690 sc_synth_prototype_ptr
* prototypes
;
2691 std::vector
<sc_synthdef
> synthdefs (read_synthdefs(def
.data()));
2693 #ifdef BOOST_HAS_RVALUE_REFS
2694 boost::tie(prototypes
, count
) = wrap_synthdefs(std::move(synthdefs
));
2696 boost::tie(prototypes
, count
) = wrap_synthdefs(synthdefs
);
2699 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(d_recv_rt2
<realtime
>, prototypes
, count
, msg
, endpoint
));
2702 template <bool realtime
>
2703 void d_recv_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2704 nova_endpoint
const & endpoint
)
2706 std::for_each(prototypes
, prototypes
+ prototype_count
,
2707 boost::bind(&synth_factory::register_prototype
, instance
, _1
));
2709 msg
.handle(endpoint
);
2710 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_recv_nrt3
, prototypes
, endpoint
));
2713 void d_recv_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
)
2715 delete[] prototypes
;
2716 send_done_message(endpoint
, "/d_recv");
2719 template <bool realtime
>
2720 void handle_d_recv(received_message
const & msg
,
2721 nova_endpoint
const & endpoint
)
2723 const void * synthdef_data
;
2724 unsigned long synthdef_size
;
2726 osc::ReceivedMessageArgumentIterator args
= msg
.ArgumentsBegin();
2728 args
->AsBlob(synthdef_data
, synthdef_size
); ++args
;
2729 movable_array
<char> def(synthdef_size
, (const char*)synthdef_data
);
2730 completion_message message
= extract_completion_message(args
);
2732 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_recv_nrt
<realtime
>, def
, message
, endpoint
));
2735 template <bool realtime
>
2736 void d_load_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2737 nova_endpoint
const & endpoint
);
2738 void d_load_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
);
2740 template <bool realtime
>
2741 void d_load_nrt(movable_string
& path
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2744 sc_synth_prototype_ptr
* prototypes
;
2745 /* todo: we need to implment some file name pattern matching */
2746 boost::tie(prototypes
, count
) = wrap_synthdefs(sc_read_synthdefs_file(path
.c_str()));
2748 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(d_load_rt2
<realtime
>, prototypes
, count
, msg
, endpoint
));
2751 template <bool realtime
>
2752 void d_load_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2753 nova_endpoint
const & endpoint
)
2755 std::for_each(prototypes
, prototypes
+ prototype_count
,
2756 boost::bind(&synth_factory::register_prototype
, instance
, _1
));
2758 msg
.handle(endpoint
);
2759 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_load_nrt3
, prototypes
, endpoint
));
2762 void d_load_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
)
2764 delete[] prototypes
;
2765 send_done_message(endpoint
, "/d_load");
2769 template <bool realtime
>
2770 void handle_d_load(received_message
const & msg
,
2771 nova_endpoint
const & endpoint
)
2773 osc::ReceivedMessageArgumentIterator args
= msg
.ArgumentsBegin();
2774 const char * path
= args
->AsString(); args
++;
2775 completion_message message
= extract_completion_message(args
);
2777 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_load_nrt
<realtime
>, movable_string(path
),
2778 message
, endpoint
));
2782 template <bool realtime
>
2783 void d_loadDir_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2784 nova_endpoint
const & endpoint
);
2785 void d_loadDir_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
);
2787 template <bool realtime
>
2788 void d_loadDir_nrt1(movable_string
& path
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2791 sc_synth_prototype_ptr
* prototypes
;
2792 boost::tie(prototypes
, count
) = wrap_synthdefs(sc_read_synthdefs_dir(path
.c_str()));
2794 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(d_loadDir_rt2
<realtime
>, prototypes
, count
, msg
, endpoint
));
2797 template <bool realtime
>
2798 void d_loadDir_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2799 nova_endpoint
const & endpoint
)
2801 std::for_each(prototypes
, prototypes
+ prototype_count
,
2802 boost::bind(&synth_factory::register_prototype
, instance
, _1
));
2804 msg
.handle(endpoint
);
2805 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_loadDir_nrt3
, prototypes
, endpoint
));
2808 void d_loadDir_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
)
2810 delete[] prototypes
;
2811 send_done_message(endpoint
, "/d_loadDir");
2814 template <bool realtime
>
2815 void handle_d_loadDir(received_message
const & msg
,
2816 nova_endpoint
const & endpoint
)
2818 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2822 completion_message message
= extract_completion_message(args
);
2824 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_loadDir_nrt1
<realtime
>,
2825 movable_string(path
), message
, endpoint
));
2829 void handle_d_free(received_message
const & msg
)
2831 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2835 const char * defname
;
2838 instance
->remove_prototype(defname
);
2842 void insert_parallel_group(int node_id
, int action
, int target_id
)
2845 node_id
= instance
->generate_node_id();
2846 else if (!check_node_id(node_id
))
2849 server_node
* target
= find_node(target_id
);
2853 node_position_constraint pos
= make_pair(target
, node_position(action
));
2855 instance
->add_parallel_group(node_id
, pos
);
2856 last_generated
= node_id
;
2859 void handle_p_new(received_message
const & msg
)
2861 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2865 osc::int32 id
, action
, target
;
2866 args
>> id
>> action
>> target
;
2868 insert_parallel_group(id
, action
, target
);
2872 void handle_u_cmd(received_message
const & msg
, int size
)
2874 sc_msg_iter
args(size
, msg
.AddressPattern());
2876 int node_id
= args
.geti();
2878 server_node
* target_synth
= find_node(node_id
);
2880 if (target_synth
== NULL
|| target_synth
->is_group())
2883 sc_synth
* synth
= static_cast<sc_synth
*>(target_synth
);
2885 int ugen_index
= args
.geti();
2886 const char * cmd_name
= args
.gets();
2888 synth
->apply_unit_cmd(cmd_name
, ugen_index
, &args
);
2891 void handle_cmd(received_message
const & msg
, int size
, nova_endpoint
const & endpoint
, int skip_bytes
)
2893 sc_msg_iter
args(size
, msg
.AddressPattern() + skip_bytes
);
2895 const char * cmd
= args
.gets();
2897 sc_factory
->run_cmd_plugin(&sc_factory
->world
, cmd
, &args
, const_cast<nova_endpoint
*>(&endpoint
));
2902 template <bool realtime
>
2903 void sc_osc_handler::handle_message_int_address(received_message
const & message
,
2904 size_t msg_size
, nova_endpoint
const & endpoint
)
2906 uint32_t address
= message
.AddressPatternAsUInt32();
2911 handle_quit
<realtime
>(endpoint
);
2915 handle_s_new(message
);
2919 handle_s_noid(message
);
2923 handle_s_get
<realtime
>(message
, msg_size
, endpoint
);
2927 handle_s_getn
<realtime
>(message
, msg_size
, endpoint
);
2931 handle_notify
<realtime
>(message
, endpoint
);
2935 handle_status
<realtime
>(endpoint
);
2939 handle_dumpOSC(message
);
2943 handle_sync
<realtime
>(message
, endpoint
);
2946 case cmd_clearSched
:
2947 handle_clearSched();
2951 handle_error(message
);
2955 handle_g_new(message
);
2959 handle_g_head_or_tail
<head
>(message
);
2963 handle_g_head_or_tail
<tail
>(message
);
2967 handle_g_freeall(message
);
2970 case cmd_g_deepFree
:
2971 handle_g_deepFree(message
);
2974 case cmd_g_queryTree
:
2975 handle_g_queryTree
<realtime
>(message
, endpoint
);
2978 case cmd_g_dumpTree
:
2979 handle_g_dumpTree(message
);
2983 handle_n_free(message
);
2987 handle_n_set(message
);
2991 handle_n_setn(message
);
2995 handle_n_fill(message
);
2999 handle_n_map(message
);
3003 handle_n_mapn(message
);
3007 handle_n_mapa(message
);
3011 handle_n_mapan(message
);
3015 handle_n_query(message
, endpoint
);
3019 handle_n_order(message
);
3023 handle_n_run(message
);
3027 handle_n_before_or_after
<before
>(message
);
3031 handle_n_before_or_after
<after
>(message
);
3035 handle_n_trace(message
);
3039 handle_b_alloc
<realtime
>(message
, endpoint
);
3043 handle_u_cmd(message
, msg_size
);
3047 handle_b_free
<realtime
>(message
, endpoint
);
3050 case cmd_b_allocRead
:
3051 handle_b_allocRead
<realtime
>(message
, endpoint
);
3054 case cmd_b_allocReadChannel
:
3055 handle_b_allocReadChannel
<realtime
>(message
, endpoint
);
3059 handle_b_read
<realtime
>(message
, endpoint
);
3062 case cmd_b_readChannel
:
3063 handle_b_readChannel
<realtime
>(message
, endpoint
);
3067 handle_b_write
<realtime
>(message
, endpoint
);
3071 handle_b_zero
<realtime
>(message
, endpoint
);
3075 handle_b_set(message
);
3079 handle_b_setn(message
);
3083 handle_b_fill(message
);
3087 handle_b_query
<realtime
>(message
, endpoint
);
3091 handle_b_get
<realtime
>(message
, endpoint
);
3095 handle_b_getn
<realtime
>(message
, endpoint
);
3099 handle_b_gen
<realtime
>(message
, msg_size
, endpoint
);
3103 handle_b_close
<realtime
>(message
, endpoint
);
3107 handle_c_set(message
);
3111 handle_c_setn(message
);
3115 handle_c_fill(message
);
3119 handle_c_get
<realtime
>(message
, endpoint
);
3123 handle_c_getn
<realtime
>(message
, endpoint
);
3127 handle_d_recv
<realtime
>(message
, endpoint
);
3131 handle_d_load
<realtime
>(message
, endpoint
);
3135 handle_d_loadDir
<realtime
>(message
, endpoint
);
3139 handle_d_free(message
);
3143 handle_p_new(message
);
3147 handle_cmd(message
, msg_size
, endpoint
, 4);
3151 handle_unhandled_message(message
);
3158 template <bool realtime
>
3159 void dispatch_group_commands(const char * address
, received_message
const & message
,
3160 nova_endpoint
const & endpoint
)
3162 assert(address
[1] == 'g');
3163 assert(address
[2] == '_');
3165 if (strcmp(address
+3, "new") == 0) {
3166 handle_g_new(message
);
3169 if (strcmp(address
+3, "head") == 0) {
3170 handle_g_head_or_tail
<head
>(message
);
3173 if (strcmp(address
+3, "tail") == 0) {
3174 handle_g_head_or_tail
<tail
>(message
);
3177 if (strcmp(address
+3, "freeAll") == 0) {
3178 handle_g_freeall(message
);
3181 if (strcmp(address
+3, "deepFree") == 0) {
3182 handle_g_deepFree(message
);
3185 if (strcmp(address
+3, "queryTree") == 0) {
3186 handle_g_queryTree
<realtime
>(message
, endpoint
);
3190 if (strcmp(address
+3, "dumpTree") == 0) {
3191 handle_g_dumpTree(message
);
3196 template <bool realtime
>
3197 void dispatch_node_commands(const char * address
, received_message
const & message
,
3198 nova_endpoint
const & endpoint
)
3200 assert(address
[1] == 'n');
3201 assert(address
[2] == '_');
3203 if (strcmp(address
+3, "free") == 0) {
3204 handle_n_free(message
);
3208 if (strcmp(address
+3, "set") == 0) {
3209 handle_n_set(message
);
3213 if (strcmp(address
+3, "setn") == 0) {
3214 handle_n_setn(message
);
3218 if (strcmp(address
+3, "fill") == 0) {
3219 handle_n_fill(message
);
3223 if (strcmp(address
+3, "map") == 0) {
3224 handle_n_map(message
);
3228 if (strcmp(address
+3, "mapn") == 0) {
3229 handle_n_mapn(message
);
3233 if (strcmp(address
+3, "mapa") == 0) {
3234 handle_n_mapa(message
);
3238 if (strcmp(address
+3, "mapan") == 0) {
3239 handle_n_mapan(message
);
3243 if (strcmp(address
+3, "run") == 0) {
3244 handle_n_run(message
);
3248 if (strcmp(address
+3, "before") == 0) {
3249 handle_n_before_or_after
<before
>(message
);
3253 if (strcmp(address
+3, "after") == 0) {
3254 handle_n_before_or_after
<after
>(message
);
3258 if (strcmp(address
+3, "order") == 0) {
3259 handle_n_order(message
);
3263 if (strcmp(address
+3, "query") == 0) {
3264 handle_n_query(message
, endpoint
);
3268 if (strcmp(address
+3, "trace") == 0) {
3269 handle_n_trace(message
);
3274 template <bool realtime
>
3275 void dispatch_buffer_commands(const char * address
, received_message
const & message
,
3276 size_t msg_size
, nova_endpoint
const & endpoint
)
3278 assert(address
[1] == 'b');
3279 assert(address
[2] == '_');
3281 if (strcmp(address
+3, "alloc") == 0) {
3282 handle_b_alloc
<realtime
>(message
, endpoint
);
3286 if (strcmp(address
+3, "free") == 0) {
3287 handle_b_free
<realtime
>(message
, endpoint
);
3291 if (strcmp(address
+3, "allocRead") == 0) {
3292 handle_b_allocRead
<realtime
>(message
, endpoint
);
3295 if (strcmp(address
+3, "allocReadChannel") == 0) {
3296 handle_b_allocReadChannel
<realtime
>(message
, endpoint
);
3300 if (strcmp(address
+3, "read") == 0) {
3301 handle_b_read
<realtime
>(message
, endpoint
);
3305 if (strcmp(address
+3, "readChannel") == 0) {
3306 handle_b_readChannel
<realtime
>(message
, endpoint
);
3310 if (strcmp(address
+3, "write") == 0) {
3311 handle_b_write
<realtime
>(message
, endpoint
);
3315 if (strcmp(address
+3, "zero") == 0) {
3316 handle_b_zero
<realtime
>(message
, endpoint
);
3320 if (strcmp(address
+3, "set") == 0) {
3321 handle_b_set(message
);
3325 if (strcmp(address
+3, "setn") == 0) {
3326 handle_b_setn(message
);
3330 if (strcmp(address
+3, "fill") == 0) {
3331 handle_b_fill(message
);
3335 if (strcmp(address
+3, "query") == 0) {
3336 handle_b_query
<realtime
>(message
, endpoint
);
3340 if (strcmp(address
+3, "get") == 0) {
3341 handle_b_get
<realtime
>(message
, endpoint
);
3345 if (strcmp(address
+3, "getn") == 0) {
3346 handle_b_getn
<realtime
>(message
, endpoint
);
3350 if (strcmp(address
+3, "gen") == 0) {
3351 handle_b_gen
<realtime
>(message
, msg_size
, endpoint
);
3355 if (strcmp(address
+3, "close") == 0) {
3356 handle_b_close
<realtime
>(message
, endpoint
);
3361 template <bool realtime
>
3362 void dispatch_control_bus_commands(const char * address
, received_message
const & message
,
3363 nova_endpoint
const & endpoint
)
3365 assert(address
[1] == 'c');
3366 assert(address
[2] == '_');
3368 if (strcmp(address
+3, "set") == 0) {
3369 handle_c_set(message
);
3373 if (strcmp(address
+3, "setn") == 0) {
3374 handle_c_setn(message
);
3378 if (strcmp(address
+3, "fill") == 0) {
3379 handle_c_fill(message
);
3383 if (strcmp(address
+3, "get") == 0) {
3384 handle_c_get
<realtime
>(message
, endpoint
);
3388 if (strcmp(address
+3, "getn") == 0) {
3389 handle_c_getn
<realtime
>(message
, endpoint
);
3394 template <bool realtime
>
3395 void dispatch_synthdef_commands(const char * address
, received_message
const & message
,
3396 nova_endpoint
const & endpoint
)
3398 assert(address
[1] == 'd');
3399 assert(address
[2] == '_');
3401 if (strcmp(address
+3, "recv") == 0) {
3402 handle_d_recv
<realtime
>(message
, endpoint
);
3406 if (strcmp(address
+3, "load") == 0) {
3407 handle_d_load
<realtime
>(message
, endpoint
);
3411 if (strcmp(address
+3, "loadDir") == 0) {
3412 handle_d_loadDir
<realtime
>(message
, endpoint
);
3416 if (strcmp(address
+3, "free") == 0) {
3417 handle_d_free(message
);
3422 template <bool realtime
>
3423 void dispatch_synth_commands(const char * address
, received_message
const & message
, size_t msg_size
,
3424 nova_endpoint
const & endpoint
)
3426 assert(address
[1] == 's');
3427 assert(address
[2] == '_');
3429 if (strcmp(address
+3, "new") == 0) {
3430 handle_s_new(message
);
3434 if (strcmp(address
+3, "noid") == 0) {
3435 handle_s_noid(message
);
3439 if (strcmp(address
+3, "get") == 0) {
3440 handle_s_get
<realtime
>(message
, msg_size
, endpoint
);
3444 if (strcmp(address
+3, "getn") == 0) {
3445 handle_s_getn
<realtime
>(message
, msg_size
, endpoint
);
3452 template <bool realtime
>
3453 void sc_osc_handler::handle_message_sym_address(received_message
const & message
,
3454 size_t msg_size
, nova_endpoint
const & endpoint
)
3456 const char * address
= message
.AddressPattern();
3458 /* scsynth doesn't require the leading / */
3459 if(address
[0] != '/')
3462 if (address
[2] == '_')
3464 if (address
[1] == 'g') {
3465 dispatch_group_commands
<realtime
>(address
, message
, endpoint
);
3469 if (address
[1] == 'n') {
3470 dispatch_node_commands
<realtime
>(address
, message
, endpoint
);
3474 if (address
[1] == 'b') {
3475 dispatch_buffer_commands
<realtime
>(address
, message
, msg_size
, endpoint
);
3479 if (address
[1] == 'c') {
3480 dispatch_control_bus_commands
<realtime
>(address
, message
, endpoint
);
3484 if (address
[1] == 'd') {
3485 dispatch_synthdef_commands
<realtime
>(address
, message
, endpoint
);
3489 if (address
[1] == 's') {
3490 dispatch_synth_commands
<realtime
>(address
, message
, msg_size
, endpoint
);
3495 if (strcmp(address
+1, "p_new") == 0) {
3496 handle_p_new(message
);
3500 if (strcmp(address
+1, "u_cmd") == 0) {
3501 handle_u_cmd(message
, msg_size
);
3505 if (strcmp(address
+1, "status") == 0) {
3506 handle_status
<realtime
>(endpoint
);
3510 if (strcmp(address
+1, "sync") == 0) {
3511 handle_sync
<realtime
>(message
, endpoint
);
3515 if (strcmp(address
+1, "quit") == 0) {
3516 handle_quit
<realtime
>(endpoint
);
3520 if (strcmp(address
+1, "notify") == 0) {
3521 handle_notify
<realtime
>(message
, endpoint
);
3525 if (strcmp(address
+1, "dumpOSC") == 0) {
3526 handle_dumpOSC(message
);
3530 if (strcmp(address
+1, "clearSched") == 0) {
3531 handle_clearSched();
3535 if (strcmp(address
+1, "error") == 0) {
3536 handle_error(message
);
3540 if (strcmp(address
+1, "cmd") == 0) {
3541 handle_cmd(message
, msg_size
, endpoint
, 8);
3545 handle_unhandled_message(message
);
3549 template <bool realtime
>
3550 void handle_asynchronous_plugin_cleanup(World
* world
, void *cmdData
,
3551 AsyncFreeFn cleanup
)
3554 (cleanup
)(world
, cmdData
);
3557 template <bool realtime
>
3558 void handle_asynchronous_plugin_stage4(World
* world
, const char * cmdName
, void *cmdData
, AsyncStageFn stage4
,
3559 AsyncFreeFn cleanup
, completion_message
& msg
, nova_endpoint
const & endpoint
)
3562 (stage4
)(world
, cmdData
);
3564 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(handle_asynchronous_plugin_cleanup
<realtime
>, world
, cmdData
,
3567 send_done_message(endpoint
, cmdName
);
3570 template <bool realtime
>
3571 void handle_asynchronous_plugin_stage3(World
* world
, const char * cmdName
, void *cmdData
, AsyncStageFn stage3
, AsyncStageFn stage4
,
3572 AsyncFreeFn cleanup
, completion_message
& msg
, nova_endpoint
const & endpoint
)
3575 bool success
= (stage3
)(world
, cmdData
);
3577 msg
.handle(endpoint
);
3579 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage4
<realtime
>, world
, cmdName
,
3580 cmdData
, stage4
, cleanup
, msg
, endpoint
));
3583 template <bool realtime
>
3584 void handle_asynchronous_plugin_stage2(World
* world
, const char * cmdName
, void *cmdData
, AsyncStageFn stage2
,
3585 AsyncStageFn stage3
, AsyncStageFn stage4
,
3586 AsyncFreeFn cleanup
, completion_message
& msg
, nova_endpoint
const & endpoint
)
3589 (stage2
)(world
, cmdData
);
3591 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(handle_asynchronous_plugin_stage3
<realtime
>, world
, cmdName
,
3592 cmdData
, stage3
, stage4
,
3593 cleanup
, msg
, endpoint
));
3596 void sc_osc_handler::do_asynchronous_command(World
* world
, void* replyAddr
, const char* cmdName
, void *cmdData
,
3597 AsyncStageFn stage2
, AsyncStageFn stage3
, AsyncStageFn stage4
, AsyncFreeFn cleanup
,
3598 int completionMsgSize
, void* completionMsgData
)
3600 completion_message
msg(completionMsgSize
, completionMsgData
);
3601 nova_endpoint
endpoint(*static_cast<nova_endpoint
*>(replyAddr
));
3603 if (world
->mRealTime
)
3604 cmd_dispatcher
<true>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage2
<true>, world
, cmdName
,
3605 cmdData
, stage2
, stage3
, stage4
, cleanup
, msg
, endpoint
));
3607 cmd_dispatcher
<false>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage2
<false>, world
, cmdName
,
3608 cmdData
, stage2
, stage3
, stage4
, cleanup
, msg
, endpoint
));
3612 } /* namespace detail */
3613 } /* namespace nova */