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"
32 #include "malloc.h" // for alloca
41 int32_t last_generated
= 0;
43 server_node
* find_node(int32_t target_id
)
46 target_id
= last_generated
;
48 server_node
* node
= instance
->find_node(target_id
);
51 log_printf("node not found: %d\n", target_id
);
56 abstract_group
* find_group(int32_t target_id
)
59 target_id
= last_generated
;
61 abstract_group
* node
= instance
->find_group(target_id
);
64 log("node not found or not a group\n");
68 bool check_node_id(int node_id
)
70 if (!instance
->node_id_available(node_id
)) {
71 log("node id %d already in use\n", node_id
);
77 void fill_notification(const server_node
* node
, osc::OutboundPacketStream
& p
)
82 const abstract_group
* parent_node
= node
->get_parent();
84 p
<< parent_node
->id();
87 if (parent_node
->is_parallel())
88 p
<< -2 << -2; /* we are in a parallel group, so we have no notion of previous/next */
91 const server_node
* prev_node
= node
->previous_node();
97 const server_node
* next_node
= node
->next_node();
104 /* is_synth, head, tail */
105 if (node
->is_synth())
108 const abstract_group
* node_group
= static_cast<const abstract_group
*>(node
);
111 if (node_group
->is_parallel())
115 const group
* node_real_group
= static_cast<const group
*>(node_group
);
116 if (node_real_group
->empty())
119 p
<< node_real_group
->head_node()->id()
120 << node_real_group
->tail_node()->id();
124 p
<< osc::EndMessage
;
127 spin_lock system_callback_allocator_lock
;
129 struct movable_string
131 /** allocate new string, only allowed to be called from the rt context */
132 explicit movable_string(const char * str
)
134 size_t length
= strlen(str
) + 1; /* terminating \0 */
135 char * data
= (char*)system_callback::allocate(length
);
140 /** copy constructor has move semantics!!! */
141 movable_string(movable_string
const & rhs
)
144 const_cast<movable_string
&>(rhs
).data_
= NULL
;
147 ~movable_string(void)
150 system_callback::deallocate((char*)data_
);
153 const char * c_str(void) const
162 template <typename T
>
165 /** allocate new array, only allowed to be called from the rt context */
166 movable_array(size_t length
, const T
* data
, bool locked
= false):
169 data_
= (T
*)system_callback::allocate(length
* sizeof(T
));
170 for (size_t i
= 0; i
!= length
; ++i
)
174 /** copy constructor has move semantics!!! */
175 movable_array(movable_array
const & rhs
)
177 length_
= rhs
.length_
;
179 const_cast<movable_array
&>(rhs
).data_
= NULL
;
185 system_callback::deallocate((char*)data_
);
188 const T
* data(void) const
193 const T
& operator[](size_t index
) const
198 size_t size(void) const
208 void send_done_message(nova_endpoint
const & endpoint
)
211 osc::OutboundPacketStream
p(buffer
, 128);
212 p
<< osc::BeginMessage("/done")
215 instance
->send(p
.Data(), p
.Size(), endpoint
);
218 void send_done_message(nova_endpoint
const & endpoint
, const char * cmd
)
221 osc::OutboundPacketStream
p(buffer
, 128);
222 p
<< osc::BeginMessage("/done")
226 instance
->send(p
.Data(), p
.Size(), endpoint
);
229 void send_done_message(nova_endpoint
const & endpoint
, const char * cmd
, osc::int32 index
)
232 osc::OutboundPacketStream
p(buffer
, 128);
233 p
<< osc::BeginMessage("/done")
238 instance
->send(p
.Data(), p
.Size(), endpoint
);
241 template <typename Functor
>
242 struct fn_system_callback
:
243 public system_callback
245 fn_system_callback (Functor
const & fn
):
257 template <typename Functor
>
258 struct fn_sync_callback
:
259 public audio_sync_callback
261 fn_sync_callback (Functor
const & fn
):
273 /** helper class for dispatching real-time and non real-time osc command callbacks
275 * uses template specialization to avoid unnecessary callback rescheduling
277 template <bool realtime
>
278 struct cmd_dispatcher
280 template <typename Functor
>
281 static void fire_system_callback(Functor
const & f
)
283 instance
->add_system_callback(new fn_system_callback
<Functor
>(f
));
286 template <typename Functor
>
287 static void fire_io_callback(Functor
const & f
)
289 instance
->add_io_callback(new fn_system_callback
<Functor
>(f
));
292 template <typename Functor
>
293 static void fire_rt_callback(Functor
const & f
)
295 instance
->add_sync_callback(new fn_sync_callback
<Functor
>(f
));
298 static void fire_done_message(nova_endpoint
const & endpoint
, const char * cmd
, osc::int32 index
)
300 fire_io_callback(boost::bind(send_done_message
, endpoint
, cmd
, index
));
305 struct cmd_dispatcher
<false>
307 template <typename Functor
>
308 static void fire_system_callback(Functor f
)
313 template <typename Functor
>
314 static void fire_rt_callback(Functor f
)
319 template <typename Functor
>
320 static void fire_io_callback(Functor f
)
325 static void fire_done_message(nova_endpoint
const & endpoint
, const char * cmd
, osc::int32 index
)
327 send_done_message (endpoint
, cmd
, index
);
336 void fire_notification(movable_array
<char> & msg
)
338 instance
->send_notification(msg
.data(), msg
.size());
341 void sc_notify_observers::notify(const char * address_pattern
, const server_node
* node
)
343 char buffer
[128]; // 128 byte should be enough
344 osc::OutboundPacketStream
p(buffer
, 128);
345 p
<< osc::BeginMessage(address_pattern
);
346 fill_notification(node
, p
);
348 movable_array
<char> message(p
.Size(), p
.Data());
349 cmd_dispatcher
<true>::fire_io_callback(boost::bind(fire_notification
, message
));
352 void fire_trigger(int32_t node_id
, int32_t trigger_id
, float value
)
354 char buffer
[128]; // 128 byte should be enough
355 osc::OutboundPacketStream
p(buffer
, 128);
356 p
<< osc::BeginMessage("/tr") << osc::int32(node_id
) << osc::int32(trigger_id
) << value
359 instance
->send_notification(p
.Data(), p
.Size());
362 void sc_notify_observers::send_trigger(int32_t node_id
, int32_t trigger_id
, float value
)
364 cmd_dispatcher
<true>::fire_io_callback(boost::bind(fire_trigger
, node_id
, trigger_id
, value
));
367 void free_mem_callback(movable_string
& cmd
,
368 movable_array
<float> & values
)
371 void fire_node_reply(int32_t node_id
, int reply_id
, movable_string
& cmd
,
372 movable_array
<float> & values
)
374 size_t buffer_size
= 1024 + strlen(cmd
.c_str()) + values
.size()*sizeof(float);
376 char * buffer
= (buffer_size
< 2048) ? (char*)alloca(buffer_size
)
377 : (char*)malloc(buffer_size
);
380 osc::OutboundPacketStream
p(buffer
, buffer_size
);
381 p
<< osc::BeginMessage(cmd
.c_str()) << osc::int32(node_id
) << osc::int32(reply_id
);
383 for (int i
= 0; i
!= values
.size(); ++i
)
386 p
<< osc::EndMessage
;
388 instance
->send_notification(p
.Data(), p
.Size());
390 cmd_dispatcher
<true>::fire_rt_callback(boost::bind(free_mem_callback
, cmd
, values
));
394 if (buffer_size
>= 2048)
398 void sc_notify_observers::send_node_reply(int32_t node_id
, int reply_id
, const char* command_name
,
399 int argument_count
, const float* values
)
401 spin_lock::scoped_lock
lock(system_callback_allocator_lock
); // called from rt helper threads, so we need to lock the memory pool
402 movable_string
cmd(command_name
);
403 movable_array
<float> value_array(argument_count
, values
);
405 cmd_dispatcher
<true>::fire_io_callback(boost::bind(fire_node_reply
, node_id
, reply_id
, cmd
, value_array
));
408 void sc_notify_observers::send_notification(const char * data
, size_t length
)
410 for (size_t i
= 0; i
!= observers
.size(); ++i
)
411 send_notification(data
, length
, observers
[i
]);
414 void sc_notify_observers::send_notification(const char * data
, size_t length
, nova_endpoint
const & endpoint
)
416 nova_protocol
const & prot
= endpoint
.protocol();
417 if (prot
.family() == AF_INET
&& prot
.type() == SOCK_DGRAM
)
419 udp::endpoint
ep(endpoint
.address(), endpoint
.port());
420 send_udp(data
, length
, ep
);
422 else if (prot
.family() == AF_INET
&& prot
.type() == SOCK_STREAM
)
424 tcp::endpoint
ep(endpoint
.address(), endpoint
.port());
425 send_tcp(data
, length
, ep
);
431 void sc_scheduled_bundles::bundle_node::run(void)
433 typedef osc::ReceivedBundleElement bundle_element
;
434 typedef osc::ReceivedBundle received_bundle
;
435 typedef osc::ReceivedMessage received_message
;
437 bundle_element
element(data_
);
439 if (element
.IsBundle()) {
440 received_bundle
bundle(element
);
441 instance
->handle_bundle
<true>(bundle
, endpoint_
);
443 received_message
message(element
);
444 instance
->handle_message
<true>(message
, element
.Size(), endpoint_
);
448 void sc_scheduled_bundles::insert_bundle(time_tag
const & timeout
, const char * data
, size_t length
,
449 nova_endpoint
const & endpoint
)
451 /* allocate chunk from realtime pool */
452 void * chunk
= rt_pool
.malloc(sizeof(bundle_node
) + length
+4);
453 bundle_node
* node
= (bundle_node
*)chunk
;
454 char * cpy
= (char*)chunk
+ sizeof(bundle_node
);
456 memcpy(cpy
, data
- 4, length
+4);
458 new(node
) bundle_node(timeout
, cpy
, endpoint
);
460 bundle_q
.insert(*node
);
463 void sc_scheduled_bundles::execute_bundles(time_tag
const & last
, time_tag
const & now
)
465 World
* world
= &sc_factory
->world
;
467 while(!bundle_q
.empty()) {
468 bundle_node
& front
= *bundle_q
.top();
469 time_tag
const & next_timestamp
= front
.timeout_
;
471 if (now
< next_timestamp
)
474 if (last
< next_timestamp
) {
475 // between last and now
476 time_tag time_since_last
= next_timestamp
- last
;
477 float samples_since_last
= time_since_last
.to_samples(world
->mSampleRate
);
480 float subsample_offset
= std::modf(samples_since_last
, &sample_offset
);
482 world
->mSampleOffset
= (int)sample_offset
;
483 world
->mSubsampleOffset
= subsample_offset
;
485 world
->mSampleOffset
= world
->mSubsampleOffset
= 0;
488 bundle_q
.erase_and_dispose(bundle_q
.top(), &dispose_bundle
);
491 world
->mSampleOffset
= world
->mSubsampleOffset
= 0;
495 void sc_osc_handler::open_tcp_acceptor(tcp
const & protocol
, unsigned int port
)
497 tcp_acceptor_
.open(protocol
);
498 tcp_acceptor_
.bind(tcp::endpoint(protocol
, port
));
499 tcp_acceptor_
.listen();
502 void sc_osc_handler::open_udp_socket(udp
const & protocol
, unsigned int port
)
504 sc_notify_observers::udp_socket
.open(protocol
);
505 sc_notify_observers::udp_socket
.bind(udp::endpoint(protocol
, port
));
508 bool sc_osc_handler::open_socket(int family
, int type
, int protocol
, unsigned int port
)
510 if (protocol
== IPPROTO_TCP
)
512 if ( type
!= SOCK_STREAM
)
515 if (family
== AF_INET
)
516 open_tcp_acceptor(tcp::v4(), port
);
517 else if (family
== AF_INET6
)
518 open_tcp_acceptor(tcp::v6(), port
);
523 else if (protocol
== IPPROTO_UDP
)
525 if ( type
!= SOCK_DGRAM
)
528 if (family
== AF_INET
)
529 open_udp_socket(udp::v4(), port
);
530 else if (family
== AF_INET6
)
531 open_udp_socket(udp::v6(), port
);
540 void sc_osc_handler::handle_receive_udp(const boost::system::error_code
& error
,
541 std::size_t bytes_transferred
)
543 if (unlikely(error
== error::operation_aborted
))
544 return; /* we're done */
546 if (error
== error::message_size
) {
547 overflow_vector
.insert(overflow_vector
.end(),
548 recv_buffer_
.begin(), recv_buffer_
.end());
553 std::cout
<< "sc_osc_handler received error code " << error
<< std::endl
;
558 if (overflow_vector
.empty())
559 handle_packet_async(recv_buffer_
.begin(), bytes_transferred
, udp_remote_endpoint_
);
561 overflow_vector
.insert(overflow_vector
.end(), recv_buffer_
.begin(), recv_buffer_
.end());
563 handle_packet_async(&overflow_vector
.front(), overflow_vector
.size(), udp_remote_endpoint_
);
565 handle_packet_async(overflow_vector
.data(), overflow_vector
.size(), udp_remote_endpoint_
);
567 overflow_vector
.clear();
574 void sc_osc_handler::tcp_connection::start(sc_osc_handler
* self
)
576 bool check_password
= true;
578 if (check_password
) {
579 boost::array
<char, 32> password
;
582 for (unsigned int i
=0; i
!=4; ++i
) {
583 size
= socket_
.receive(boost::asio::buffer(&msglen
, 4));
587 msglen
= ntohl(msglen
);
588 if (msglen
> password
.size())
591 size
= socket_
.receive(boost::asio::buffer(password
.data(), msglen
));
593 bool verified
= true;
594 if (size
!= msglen
||
595 strcmp(password
.data(), self
->tcp_password_
) != 0)
599 throw std::runtime_error("cannot verify password");
605 size
= socket_
.receive(boost::asio::buffer(&msglen
, 4));
606 if (size
!= sizeof(uint32_t))
607 throw std::runtime_error("read error");
609 msglen
= ntohl(msglen
);
611 sized_array
<char> recv_vector(msglen
+ sizeof(uint32_t));
613 std::memcpy((void*)recv_vector
.data(), &msglen
, sizeof(uint32_t));
614 size_t transfered
= socket_
.read_some(boost::asio::buffer((void*)(recv_vector
.data()+sizeof(uint32_t)),
615 recv_vector
.size()-sizeof(uint32_t)));
617 if (transfered
!= size_t(msglen
))
618 throw std::runtime_error("socket read sanity check failure");
620 self
->handle_packet_async(recv_vector
.data(), recv_vector
.size(), socket_
.remote_endpoint());
624 void sc_osc_handler::handle_packet_async(const char * data
, size_t length
,
625 nova_endpoint
const & endpoint
)
627 received_packet
* p
= received_packet::alloc_packet(data
, length
, endpoint
);
629 if (dump_osc_packets
== 1) {
630 osc_received_packet
packet (data
, length
);
631 cout
<< "received osc packet " << packet
<< endl
;
634 instance
->add_sync_callback(p
);
637 time_tag
sc_osc_handler::handle_bundle_nrt(const char * data
, size_t length
)
639 osc_received_packet
packet(data
, length
);
640 if (!packet
.IsBundle())
641 throw std::runtime_error("packet needs to be an osc bundle");
643 received_bundle
bundle(packet
);
644 handle_bundle
<false> (bundle
, nova_endpoint());
645 return bundle
.TimeTag();
649 sc_osc_handler::received_packet
*
650 sc_osc_handler::received_packet::alloc_packet(const char * data
, size_t length
,
651 nova_endpoint
const & remote_endpoint
)
653 /* received_packet struct and data array are located in one memory chunk */
654 void * chunk
= received_packet::allocate(sizeof(received_packet
) + length
);
655 received_packet
* p
= (received_packet
*)chunk
;
656 char * cpy
= (char*)(chunk
) + sizeof(received_packet
);
657 memcpy(cpy
, data
, length
);
659 new(p
) received_packet(cpy
, length
, remote_endpoint
);
663 void sc_osc_handler::received_packet::run(void)
665 instance
->handle_packet(data
, length
, endpoint_
);
668 void sc_osc_handler::handle_packet(const char * data
, std::size_t length
, nova_endpoint
const & endpoint
)
670 osc_received_packet
packet(data
, length
);
671 if (packet
.IsBundle())
673 received_bundle
bundle(packet
);
674 handle_bundle
<true> (bundle
, endpoint
);
678 received_message
message(packet
);
679 handle_message
<true> (message
, packet
.Size(), endpoint
);
683 template <bool realtime
>
684 void sc_osc_handler::handle_bundle(received_bundle
const & bundle
, nova_endpoint
const & endpoint
)
686 time_tag bundle_time
= bundle
.TimeTag();
688 typedef osc::ReceivedBundleElementIterator bundle_iterator
;
689 typedef osc::ReceivedBundleElement bundle_element
;
691 if (bundle_time
<= now
) {
692 for (bundle_iterator it
= bundle
.ElementsBegin(); it
!= bundle
.ElementsEnd(); ++it
) {
693 bundle_element
const & element
= *it
;
695 if (element
.IsBundle()) {
696 received_bundle
inner_bundle(element
);
697 handle_bundle
<realtime
>(inner_bundle
, endpoint
);
699 received_message
message(element
);
700 handle_message
<realtime
>(message
, element
.Size(), endpoint
);
704 for (bundle_iterator it
= bundle
.ElementsBegin(); it
!= bundle
.ElementsEnd(); ++it
) {
705 bundle_element
const & element
= *it
;
706 scheduled_bundles
.insert_bundle(bundle_time
, element
.Contents(), element
.Size(), endpoint
);
711 template <bool realtime
>
712 void sc_osc_handler::handle_message(received_message
const & message
, size_t msg_size
,
713 nova_endpoint
const & endpoint
)
716 if (message
.AddressPatternIsUInt32())
717 handle_message_int_address
<realtime
>(message
, msg_size
, endpoint
);
719 handle_message_sym_address
<realtime
>(message
, msg_size
, endpoint
);
720 } catch (std::exception
const & e
) {
721 log_printf("exception in handle_message: %s\n", e
.what());
727 typedef sc_osc_handler::received_message received_message
;
729 void send_udp_message(movable_array
<char> data
, nova_endpoint
const & endpoint
)
731 instance
->send(data
.data(), data
.size(), endpoint
);
735 int first_arg_as_int(received_message
const & message
)
737 osc::ReceivedMessageArgumentStream args
= message
.ArgumentStream();
745 void quit_perform(nova_endpoint
const & endpoint
)
747 instance
->prepare_to_terminate();
748 send_done_message(endpoint
, "/quit");
749 instance
->terminate();
752 template <bool realtime
>
753 void handle_quit(nova_endpoint
const & endpoint
)
755 instance
->quit_received
= true;
756 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(quit_perform
, endpoint
));
759 void notify_perform(bool enable
, nova_endpoint
const & endpoint
)
762 instance
->add_observer(endpoint
);
764 instance
->remove_observer(endpoint
);
765 send_done_message(endpoint
, "/notify");
768 template <bool realtime
>
769 void handle_notify(received_message
const & message
, nova_endpoint
const & endpoint
)
771 int enable
= first_arg_as_int(message
);
772 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(notify_perform
, bool(enable
), endpoint
));
775 void status_perform(nova_endpoint
const & endpoint
)
777 if (unlikely(instance
->quit_received
)) // we don't reply once we are about to quit
781 typedef osc::int32 i32
;
783 float peak_load
, average_load
;
784 instance
->cpu_load(peak_load
, average_load
);
786 osc::OutboundPacketStream
p(buffer
, 1024);
787 p
<< osc::BeginMessage("/status.reply")
788 << (i32
)1 /* unused */
789 << (i32
)sc_factory
->ugen_count() /* ugens */
790 << (i32
)instance
->synth_count() /* synths */
791 << (i32
)instance
->group_count() /* groups */
792 << (i32
)instance
->prototype_count() /* synthdefs */
793 << average_load
/* average cpu % */
794 << peak_load
/* peak cpu % */
795 << instance
->get_samplerate() /* nominal samplerate */
796 << instance
->get_samplerate() /* actual samplerate */
799 instance
->send(p
.Data(), p
.Size(), endpoint
);
802 template <bool realtime
>
803 void handle_status(nova_endpoint
const & endpoint
)
805 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(status_perform
, endpoint
));
808 void handle_dumpOSC(received_message
const & message
)
810 int val
= first_arg_as_int(message
);
811 val
= min (1, val
); /* we just support one way of dumping osc messages */
813 instance
->dumpOSC(val
); /* thread-safe */
816 void sync_perform(osc::int32 id
, nova_endpoint
const & endpoint
)
819 osc::OutboundPacketStream
p(buffer
, 128);
820 p
<< osc::BeginMessage("/synced")
824 instance
->send(p
.Data(), p
.Size(), endpoint
);
827 template <bool realtime
>
828 void handle_sync(received_message
const & message
, nova_endpoint
const & endpoint
)
830 int id
= first_arg_as_int(message
);
832 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(sync_perform
, id
, endpoint
));
835 void handle_clearSched(void)
837 instance
->clear_scheduled_bundles();
840 void handle_error(received_message
const & message
)
842 int val
= first_arg_as_int(message
);
844 instance
->set_error_posting(val
); /* thread-safe */
847 void handle_unhandled_message(received_message
const & msg
)
849 log_printf("unhandled message: %s\n", msg
.AddressPattern());
852 static bool node_position_sanity_check(node_position_constraint
const & constraint
)
854 switch (constraint
.second
) {
858 server_node
* target
= constraint
.first
;
859 if (!target
->is_group()) {
860 log_printf("Invalid position constraint (target: %d, addAction: %d)\n", target
->id(), constraint
.second
);
869 sc_synth
* add_synth(const char * name
, int node_id
, int action
, int target_id
)
871 if (!check_node_id(node_id
))
874 server_node
* target
= find_node(target_id
);
878 node_position_constraint pos
= make_pair(target
, node_position(action
));
879 if (!node_position_sanity_check(pos
))
882 abstract_synth
* synth
= instance
->add_synth(name
, node_id
, pos
);
884 log_printf("Cannot create synth (synthdef: %s, node id: %d)\n", name
, node_id
);
886 last_generated
= node_id
;
887 return static_cast<sc_synth
*>(synth
);
890 /* extract float or int32 as float from argument iterator */
891 inline float extract_float_argument(osc::ReceivedMessageArgumentIterator
const & it
)
894 return it
->AsFloatUnchecked();
896 return float(it
->AsInt32Unchecked());
898 return float(it
->AsInt64Unchecked());
900 throw std::runtime_error("type cannot be converted to float");
903 inline void verify_argument(osc::ReceivedMessageArgumentIterator
const & it
,
904 osc::ReceivedMessageArgumentIterator
const & end
)
907 throw std::runtime_error("unexpected end of argument list");
910 template <bool IsAudio
, typename slot_type
>
911 static void apply_control_bus_mapping(server_node
& node
, slot_type slot
, int bus_index
);
913 template <typename control_id_type
>
914 void set_control_array(server_node
* node
, control_id_type control
, osc::ReceivedMessageArgumentIterator
& it
)
916 size_t array_size
= it
->ArraySize(); ++it
;
918 if (it
->IsArrayStart()) {
919 // nested arrays are basically user errors, but we handle them like normal arrays
920 log("Warning in /s_new handler: nested array argument detected");
921 set_control_array
<control_id_type
>(node
, control
, it
);
924 for (size_t i
= 0; i
!= array_size
; ++i
) {
925 if (it
->IsString() || it
->IsSymbol()) {
926 char const * name
= it
->AsStringUnchecked(); ++it
;
931 bus_id
= atoi(name
+1);
932 static_cast<sc_synth
*>(node
)->map_control_bus
<false>(control
, i
, bus_id
);
936 bus_id
= atoi(name
+1);
937 static_cast<sc_synth
*>(node
)->map_control_bus
<true>(control
, i
, bus_id
);
941 throw runtime_error("invalid name for control mapping");
944 float value
= extract_float_argument(it
++);
945 node
->set_control_array_element(control
, i
, value
);
950 if (!it
->IsArrayEnd())
951 throw runtime_error("missing array end tag");
952 ++it
; // skip array end
955 template <typename ControlSpecifier
>
956 void set_control(server_node
* node
, ControlSpecifier
const & control
, osc::ReceivedMessageArgumentIterator
& it
)
958 if (it
->IsArrayStart())
959 set_control_array(node
, control
, it
);
960 else if (it
->IsString() || it
->IsSymbol()) {
961 char const * name
= it
->AsStringUnchecked(); ++it
;
966 bus_id
= atoi(name
+1);
967 apply_control_bus_mapping
<false>(*node
, control
, bus_id
);
971 bus_id
= atoi(name
+1);
972 apply_control_bus_mapping
<true>(*node
, control
, bus_id
);
976 throw runtime_error("invalid name for control mapping");
980 float value
= extract_float_argument(it
++);
981 node
->set(control
, value
);
985 /* set control values of node from string/float or int/float pair */
986 void set_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
, osc::ReceivedMessageArgumentIterator end
)
989 osc::int32 index
= it
->AsInt32Unchecked(); ++it
;
990 if (it
== end
) return; // sclang sometimes uses an integer instead of an empty argument list
991 set_control(node
, index
, it
);
992 } else if (it
->IsString()) {
993 const char * str
= it
->AsStringUnchecked(); ++it
;
994 set_control(node
, str
, it
);
996 throw runtime_error("invalid argument");
999 void handle_s_new(received_message
const & msg
)
1001 osc::ReceivedMessageArgumentIterator args
= msg
.ArgumentsBegin(), end
= msg
.ArgumentsEnd();
1003 const char * def_name
= args
->AsString(); ++args
;
1004 int32_t id
= args
->AsInt32(); ++args
;
1007 id
= instance
->generate_node_id();
1009 int32_t action
, target
;
1012 action
= args
->AsInt32(); ++args
;
1017 target
= args
->AsInt32(); ++args
;
1021 sc_synth
* synth
= add_synth(def_name
, id
, action
, target
);
1028 set_control(synth
, args
, end
);
1029 } catch(std::exception
& e
) {
1030 log_printf("exception in /s_new: %s\n", e
.what());
1035 void handle_g_new(received_message
const & msg
)
1037 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1039 while(!args
.Eos()) {
1040 osc::int32 node_id
, action
, target_id
;
1041 args
>> node_id
>> action
>> target_id
;
1044 node_id
= instance
->generate_node_id();
1045 else if (!check_node_id(node_id
))
1048 server_node
* target
= find_node(target_id
);
1053 node_position_constraint pos
= make_pair(target
, node_position(action
));
1054 if (!node_position_sanity_check(pos
))
1057 instance
->add_group(node_id
, pos
);
1058 last_generated
= node_id
;
1062 void handle_g_freeall(received_message
const & msg
)
1064 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1071 abstract_group
* group
= find_group(id
);
1075 bool success
= instance
->group_free_all(group
);
1078 log("/g_freeAll failue\n");
1082 void handle_g_deepFree(received_message
const & msg
)
1084 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1091 abstract_group
* group
= find_group(id
);
1095 bool success
= instance
->group_free_deep(group
);
1098 log("/g_freeDeep failue\n");
1102 void g_query_tree_fill_node(osc::OutboundPacketStream
& p
, bool flag
, server_node
const & node
)
1104 p
<< osc::int32(node
.id());
1105 if (node
.is_synth())
1108 p
<< osc::int32(static_cast<abstract_group
const &>(node
).child_count());
1110 if (node
.is_synth()) {
1111 sc_synth
const & scsynth
= static_cast<sc_synth
const&>(node
);
1112 p
<< scsynth
.prototype_name();
1115 osc::int32 controls
= scsynth
.mNumControls
;
1118 for (int i
= 0; i
!= controls
; ++i
) {
1119 p
<< osc::int32(i
); /** \todo later we can return symbols */
1121 if (scsynth
.mMapControls
[i
] != (scsynth
.mControls
+i
)) {
1122 /* we use a bus mapping */
1123 int bus
= (scsynth
.mMapControls
[i
]) - (scsynth
.mNode
.mWorld
->mControlBus
);
1125 sprintf(str
, "s%d", bus
);
1129 p
<< scsynth
.mControls
[i
];
1133 abstract_group
const & group
= static_cast<abstract_group
const &>(node
);
1134 group
.apply_on_children(boost::bind(g_query_tree_fill_node
, boost::ref(p
), flag
, _1
));
1138 template <bool realtime
>
1139 void g_query_tree(int node_id
, bool flag
, nova_endpoint
const & endpoint
)
1141 server_node
* node
= find_node(node_id
);
1142 if (!node
|| node
->is_synth())
1145 abstract_group
* group
= static_cast<abstract_group
*>(node
);
1147 size_t max_msg_size
= 1<<16;
1150 if (max_msg_size
> 1<<22)
1153 sized_array
<char, rt_pool_allocator
<char> > data(max_msg_size
);
1155 osc::OutboundPacketStream
p(data
.c_array(), max_msg_size
);
1156 p
<< osc::BeginMessage("/g_queryTree.reply")
1159 << osc::int32(group
->child_count());
1161 group
->apply_on_children(boost::bind(g_query_tree_fill_node
, boost::ref(p
), flag
, _1
));
1162 p
<< osc::EndMessage
;
1164 movable_array
<char> message(p
.Size(), data
.c_array());
1165 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
1170 max_msg_size
*= 2; /* if we run out of memory, retry with doubled memory resources */
1175 template <bool realtime
>
1176 void handle_g_queryTree(received_message
const & msg
, nova_endpoint
const & endpoint
)
1178 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1183 osc::int32 id
, flag
;
1185 g_query_tree
<realtime
>(id
, flag
, endpoint
);
1187 catch (std::exception
& e
) {
1188 log_printf("exception in handle_g_queryTree: %s\n", e
.what());
1193 typedef std::basic_stringstream
<char,
1194 std::char_traits
<char>/*,
1195 rt_pool_allocator<char>*/ > rt_string_stream
;
1197 void fill_spaces(rt_string_stream
& stream
, int level
)
1199 for (int i
= 0; i
!= level
*3; ++i
)
1203 void g_dump_node(rt_string_stream
& stream
, server_node
& node
, bool flag
, int level
)
1205 using namespace std
;
1206 fill_spaces(stream
, level
);
1208 if (node
.is_synth()) {
1209 abstract_synth
const & synth
= static_cast<abstract_synth
const &>(node
);
1210 stream
<< synth
.id() << " " << synth
.prototype_name() << endl
;
1216 abstract_group
& group
= static_cast<abstract_group
&>(node
);
1217 stream
<< group
.id();
1219 if (group
.is_parallel())
1220 stream
<< " parallel group";
1224 group
.apply_on_children(boost::bind(g_dump_node
, boost::ref(stream
), _1
, flag
, level
+ 1));
1228 void g_dump_tree(int id
, bool flag
)
1230 server_node
* node
= find_node(id
);
1234 // FIXME: can we completely avoid all internal allocations?
1235 rt_string_stream stream
;
1236 stream
<< "NODE TREE Group " << id
<< std::endl
;
1238 g_dump_node(stream
, *node
, flag
, 1);
1239 log(stream
.str().c_str(), stream
.str().size());
1242 void handle_g_dumpTree(received_message
const & msg
)
1244 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1249 osc::int32 id
, flag
;
1251 g_dump_tree(id
, flag
);
1253 catch (std::exception
& e
) {
1254 log_printf("exception in /g_dumpTree: %s\n", e
.what());
1259 void handle_n_free(received_message
const & msg
)
1261 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1269 server_node
* node
= find_node(id
);
1273 instance
->free_node(node
);
1275 catch (std::exception
& e
) {
1276 log_printf("exception in /n_free: %s\n", e
.what());
1281 /** macro to define an os command handler with a starting node id
1283 * it is mainly intended as decorator to avoid duplicate error handling code
1285 #define HANDLE_N_DECORATOR(cmd, function) \
1286 void handle_n_##cmd(received_message const & msg) \
1288 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); \
1289 osc::int32 id = it->AsInt32(); ++it; \
1291 server_node * node = find_node(id); \
1296 while (it != msg.ArgumentsEnd()) \
1297 function(node, it); \
1298 } catch(std::exception & e) { \
1299 log_printf("Exception during /n_" #cmd "handler: %s\n", e.what());\
1303 void set_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1305 if (it
->IsInt32()) {
1306 osc::int32 index
= it
->AsInt32Unchecked(); ++it
;
1307 set_control(node
, index
, it
);
1308 } else if (it
->IsString()) {
1309 const char * str
= it
->AsStringUnchecked(); ++it
;
1310 set_control(node
, str
, it
);
1312 throw runtime_error("invalid argument");
1316 HANDLE_N_DECORATOR(set
, set_control
)
1318 void set_control_n(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1320 if (it
->IsInt32()) {
1321 osc::int32 index
= it
->AsInt32Unchecked(); ++it
;
1322 osc::int32 count
= it
->AsInt32(); ++it
;
1324 for (int i
= 0; i
!= count
; ++i
)
1325 node
->set(index
+ i
, extract_float_argument(it
++));
1327 else if (it
->IsString()) {
1328 const char * str
= it
->AsStringUnchecked(); ++it
;
1329 osc::int32 count
= it
->AsInt32(); ++it
;
1331 sized_array
<float> values(count
);
1332 for (int i
= 0; i
!= count
; ++i
)
1333 values
[i
] = extract_float_argument(it
++);
1335 node
->set_control_array(str
, count
, values
.c_array());
1337 throw runtime_error("invalid argument");
1340 HANDLE_N_DECORATOR(setn
, set_control_n
)
1342 void fill_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1344 if (it
->IsInt32()) {
1345 osc::int32 index
= it
->AsInt32Unchecked(); ++it
;
1346 osc::int32 count
= it
->AsInt32(); ++it
;
1347 float value
= extract_float_argument(it
++);
1349 for (int i
= 0; i
!= count
; ++i
)
1350 node
->set(index
+ i
, value
);
1352 else if (it
->IsString()) {
1353 const char * str
= it
->AsStringUnchecked(); ++it
;
1354 osc::int32 count
= it
->AsInt32(); ++it
;
1355 float value
= extract_float_argument(it
++);
1357 sized_array
<float> values(count
);
1358 for (int i
= 0; i
!= count
; ++i
)
1361 node
->set_control_array(str
, count
, values
.c_array());
1363 throw runtime_error("invalid argument");
1366 HANDLE_N_DECORATOR(fill
, fill_control
)
1368 template <bool IsAudio
, typename slot_type
>
1369 void apply_control_bus_mapping(server_node
& node
, slot_type slot
, int bus_index
)
1371 if (node
.is_synth())
1372 static_cast<sc_synth
&>(node
).map_control_bus
<IsAudio
>(slot
, bus_index
);
1374 static_cast<abstract_group
&>(node
).apply_on_children(boost::bind(apply_control_bus_mapping
<IsAudio
, slot_type
>, _1
,
1378 template <bool IsAudio
, typename slot_type
>
1379 void apply_control_busn_mapping(server_node
& node
, slot_type slot
, int bus_index
, int count
)
1381 if (node
.is_synth())
1382 static_cast<sc_synth
&>(node
).map_control_buses
<IsAudio
>(slot
, bus_index
, count
);
1384 static_cast<abstract_group
&>(node
).apply_on_children(boost::bind(apply_control_busn_mapping
<IsAudio
, slot_type
>, _1
,
1385 slot
, bus_index
, count
));
1388 template <bool IsAudio
>
1389 void map_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1391 if (it
->IsInt32()) {
1392 osc::int32 control_index
= it
->AsInt32Unchecked(); ++it
;
1393 osc::int32 control_bus_index
= it
->AsInt32(); ++it
;
1395 apply_control_bus_mapping
<IsAudio
>(*node
, control_index
, control_bus_index
);
1397 else if (it
->IsString()) {
1398 const char * control_name
= it
->AsStringUnchecked(); ++it
;
1399 osc::int32 control_bus_index
= it
->AsInt32(); ++it
;
1401 apply_control_bus_mapping
<IsAudio
>(*node
, control_name
, control_bus_index
);
1403 throw runtime_error("invalid argument");
1406 template <bool IsAudio
>
1407 void mapn_control(server_node
* node
, osc::ReceivedMessageArgumentIterator
& it
)
1409 if (it
->IsInt32()) {
1410 osc::int32 control_index
= it
->AsInt32Unchecked(); ++it
;
1411 osc::int32 bus_index
= it
->AsInt32(); ++it
;
1412 osc::int32 count
= it
->AsInt32(); ++it
;
1414 apply_control_busn_mapping
<IsAudio
>(*node
, control_index
, bus_index
, count
);
1416 else if (it
->IsString()) {
1417 const char * control_name
= it
->AsStringUnchecked(); ++it
;
1418 osc::int32 bus_index
= it
->AsInt32(); ++it
;
1419 osc::int32 count
= it
->AsInt32(); ++it
;
1421 apply_control_busn_mapping
<IsAudio
>(*node
, control_name
, bus_index
, count
);
1423 throw runtime_error("invalid argument");
1427 HANDLE_N_DECORATOR(map
, map_control
<false>)
1428 HANDLE_N_DECORATOR(mapa
, map_control
<true>)
1429 HANDLE_N_DECORATOR(mapn
, mapn_control
<false>)
1430 HANDLE_N_DECORATOR(mapan
, mapn_control
<true>)
1432 template <nova::node_position Relation
>
1433 void handle_n_before_or_after(received_message
const & msg
)
1435 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1437 while(!args
.Eos()) {
1438 osc::int32 node_a
, node_b
;
1439 args
>> node_a
>> node_b
;
1441 server_node
* a
= find_node(node_a
);
1444 server_node
* b
= find_node(node_b
);
1447 abstract_group::move_before_or_after
<Relation
>(a
, b
);
1453 template <nova::node_position Position
>
1454 void handle_g_head_or_tail(received_message
const & msg
)
1456 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1458 while(!args
.Eos()) {
1459 osc::int32 node_id
, target_id
;
1460 args
>> target_id
>> node_id
;
1462 server_node
* node
= find_node(node_id
);
1463 if (!node
) continue;
1465 abstract_group
* target_group
= find_group(target_id
);
1466 if (!target_group
) continue;
1468 abstract_group::move_to_head_or_tail
<Position
>(node
, target_group
);
1474 void handle_n_query(received_message
const & msg
, nova_endpoint
const & endpoint
)
1476 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1483 server_node
* node
= find_node(node_id
);
1487 char buffer
[128]; // 128 byte should be enough
1488 osc::OutboundPacketStream
p(buffer
, 128);
1489 p
<< osc::BeginMessage("/n_info");
1490 fill_notification(node
, p
);
1492 movable_array
<char> message(p
.Size(), p
.Data());
1493 cmd_dispatcher
<true>::fire_system_callback(boost::bind(send_udp_message
, message
, endpoint
));
1497 void handle_n_order(received_message
const & msg
)
1499 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1501 osc::int32 action
, target_id
;
1502 args
>> action
>> target_id
;
1504 server_node
* target
= find_node(target_id
);
1509 abstract_group
* target_parent
;
1510 if (action
== before
||
1512 target_parent
= target
->get_parent();
1514 if (target
->is_synth())
1515 throw std::runtime_error("invalid argument for n_order: argument is no synth");
1516 target_parent
= static_cast<abstract_group
*>(target
);
1524 server_node
* node
= find_node(node_id
);
1528 abstract_group
* node_parent
= node
->get_parent();
1530 /** \todo this can be optimized if node_parent == target_parent */
1531 node_parent
->remove_child(node
);
1532 if (action
== before
||
1534 target_parent
->add_child(node
, make_pair(target
, node_position(action
)));
1536 target_parent
->add_child(node
, node_position(action
));
1538 instance
->update_dsp_queue();
1542 void handle_n_run(received_message
const & msg
)
1544 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1546 while(!args
.Eos()) {
1547 osc::int32 node_id
, run_flag
;
1548 args
>> node_id
>> run_flag
;
1550 server_node
* node
= find_node(node_id
);
1555 instance
->node_resume(node
);
1557 instance
->node_pause(node
);
1561 void enable_tracing(server_node
& node
)
1563 if (node
.is_synth()) {
1564 sc_synth
& synth
= static_cast<sc_synth
&>(node
);
1565 synth
.enable_tracing();
1567 abstract_group
& group
= static_cast<abstract_group
&>(node
);
1568 group
.apply_on_children(enable_tracing
);
1572 void handle_n_trace(received_message
const & msg
)
1574 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1576 while(!args
.Eos()) {
1580 server_node
* node
= find_node(node_id
);
1584 enable_tracing(*node
);
1589 void handle_s_noid(received_message
const & msg
)
1591 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1593 while(!args
.Eos()) {
1596 instance
->synth_reassign_id(node_id
);
1600 int32_t get_control_index(sc_synth
* s
, osc::ReceivedMessageArgumentIterator
& it
, osc::OutboundPacketStream
& p
)
1605 control
= it
->AsInt32Unchecked(); ++it
;
1608 else if (it
->IsString())
1610 const char * control_str
= it
->AsStringUnchecked(); ++it
;
1611 control
= s
->resolve_slot(control_str
);
1614 else if (it
->IsSymbol())
1616 const char * control_str
= it
->AsSymbolUnchecked(); ++it
;
1617 control
= s
->resolve_slot(control_str
);
1618 p
<< osc::Symbol(control_str
);
1621 throw std::runtime_error("wrong argument type");
1625 template <bool realtime
>
1626 void handle_s_get(received_message
const & msg
, size_t msg_size
, nova_endpoint
const & endpoint
)
1628 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
1631 throw std::runtime_error("wrong argument type");
1633 int32_t node_id
= it
->AsInt32Unchecked(); ++it
;
1635 server_node
* node
= find_node(node_id
);
1636 if (!node
|| !node
->is_synth())
1637 throw std::runtime_error("node is not a synth");
1639 sc_synth
* s
= static_cast<sc_synth
*>(node
);
1641 size_t alloc_size
= msg_size
+ sizeof(float) * (msg
.ArgumentCount()-1) + 128;
1643 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
1645 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
1646 p
<< osc::BeginMessage("/n_set")
1649 while (it
!= msg
.ArgumentsEnd())
1651 int32_t control
= get_control_index(s
, it
, p
);
1652 p
<< s
->get(control
);
1654 p
<< osc::EndMessage
;
1656 movable_array
<char> message(p
.Size(), return_message
.c_array());
1657 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
1660 template <bool realtime
>
1661 void handle_s_getn(received_message
const & msg
, size_t msg_size
, nova_endpoint
const & endpoint
)
1663 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
1666 throw std::runtime_error("wrong argument type");
1668 int32_t node_id
= it
->AsInt32Unchecked(); ++it
;
1670 server_node
* node
= find_node(node_id
);
1671 if (!node
|| !node
->is_synth())
1672 throw std::runtime_error("node is not a synth");
1674 sc_synth
* s
= static_cast<sc_synth
*>(node
);
1676 /* count argument values */
1677 size_t argument_count
= 0;
1678 for (osc::ReceivedMessageArgumentIterator local
= it
; local
!= msg
.ArgumentsEnd(); ++local
)
1680 ++local
; /* skip control */
1681 if (local
== msg
.ArgumentsEnd())
1684 throw std::runtime_error("invalid count");
1685 argument_count
+= it
->AsInt32Unchecked(); ++it
;
1688 size_t alloc_size
= msg_size
+ sizeof(float) * (argument_count
) + 128;
1690 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
1692 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
1693 p
<< osc::BeginMessage("/n_setn")
1696 while (it
!= msg
.ArgumentsEnd())
1698 int32_t control
= get_control_index(s
, it
, p
);
1701 throw std::runtime_error("integer argument expected");
1703 int32_t control_count
= it
->AsInt32Unchecked(); ++it
;
1704 if (control_count
< 0)
1707 for (int i
= 0; i
!= control_count
; ++i
)
1708 p
<< s
->get(control
+ i
);
1710 p
<< osc::EndMessage
;
1712 movable_array
<char> message(p
.Size(), return_message
.c_array());
1713 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
1717 /** wrapper class for osc completion message
1719 struct completion_message
1721 /** constructor should only be used from the real-time thread */
1722 completion_message(size_t size
, const void * data
):
1726 data_
= system_callback::allocate(size
);
1727 memcpy(data_
, data
, size
);
1731 /** default constructor creates uninitialized object */
1732 completion_message(void):
1736 /** copy constructor has move semantics!!! */
1737 completion_message(completion_message
const & rhs
)
1742 completion_message
& operator=(completion_message
const & rhs
)
1746 const_cast<completion_message
&>(rhs
).size_
= 0;
1750 ~completion_message(void)
1753 system_callback::deallocate(data_
);
1756 /** handle package in the rt thread
1757 * not to be called from the rt thread
1759 void trigger_async(nova_endpoint
const & endpoint
)
1762 sc_osc_handler::received_packet
* p
=
1763 sc_osc_handler::received_packet::alloc_packet((char*)data_
, size_
, endpoint
);
1764 instance
->add_sync_callback(p
);
1768 /** handle package directly
1769 * only to be called from the rt thread
1771 void handle(nova_endpoint
const & endpoint
)
1774 instance
->handle_packet((char*)data_
, size_
, endpoint
);
1781 completion_message
extract_completion_message(osc::ReceivedMessageArgumentStream
& args
)
1783 osc::Blob
blob(0, 0);
1789 catch (osc::WrongArgumentTypeException
& e
)
1793 return completion_message (blob
.size
, blob
.data
);
1796 completion_message
extract_completion_message(osc::ReceivedMessageArgumentIterator
& it
)
1798 const void * data
= 0;
1799 unsigned long length
= 0;
1802 it
->AsBlobUnchecked(data
, length
);
1804 return completion_message(length
, data
);
1808 template <bool realtime
>
1809 void b_alloc_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1810 void b_alloc_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1812 template <bool realtime
>
1813 void b_alloc_1_nrt(uint32_t index
, uint32_t frames
, uint32_t channels
, completion_message
& msg
, nova_endpoint
const & endpoint
)
1815 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
1816 sample
* free_buf
= sc_factory
->get_nrt_mirror_buffer(index
);
1817 sc_factory
->allocate_buffer(index
, frames
, channels
);
1818 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_alloc_2_rt
<realtime
>, index
, msg
, free_buf
, endpoint
));
1821 template <bool realtime
>
1822 void b_alloc_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1824 sc_factory
->buffer_sync(index
);
1825 msg
.handle(endpoint
);
1826 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_alloc_3_nrt
, index
, free_buf
, endpoint
));
1829 void b_alloc_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1831 free_aligned(free_buf
);
1832 send_done_message(endpoint
, "/b_alloc", index
);
1835 template <bool realtime
>
1836 void handle_b_alloc(received_message
const & msg
, nova_endpoint
const & endpoint
)
1838 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1840 osc::int32 index
, frames
, channels
;
1842 args
>> index
>> frames
;
1849 completion_message message
= extract_completion_message(args
);
1851 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_alloc_1_nrt
<realtime
>, index
, frames
,
1852 channels
, message
, endpoint
));
1855 template <bool realtime
>
1856 void b_free_1_nrt(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
);
1857 template <bool realtime
>
1858 void b_free_2_rt(uint32_t index
, sample
* free_buf
, completion_message
& msg
, nova_endpoint
const & endpoint
);
1859 void b_free_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1861 template <bool realtime
>
1862 void b_free_1_nrt(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
1864 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
1865 sample
* free_buf
= sc_factory
->get_nrt_mirror_buffer(index
);
1866 sc_factory
->free_buffer(index
);
1867 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_free_2_rt
<realtime
>,
1868 index
, free_buf
, msg
, endpoint
));
1871 template <bool realtime
>
1872 void b_free_2_rt(uint32_t index
, sample
* free_buf
, completion_message
& msg
, nova_endpoint
const & endpoint
)
1874 sc_factory
->buffer_sync(index
);
1875 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_free_3_nrt
, index
, free_buf
, endpoint
));
1876 msg
.handle(endpoint
);
1879 void b_free_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1881 free_aligned(free_buf
);
1882 send_done_message(endpoint
, "/b_free", index
);
1886 template <bool realtime
>
1887 void handle_b_free(received_message
const & msg
, nova_endpoint
const & endpoint
)
1889 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1894 completion_message message
= extract_completion_message(args
);
1896 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_free_1_nrt
<realtime
>, index
, message
, endpoint
));
1899 template <bool realtime
>
1900 void b_allocRead_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1901 void b_allocRead_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1903 template <bool realtime
>
1904 void b_allocRead_1_nrt(uint32_t index
, movable_string
& filename
, uint32_t start
, uint32_t frames
, completion_message
& msg
,
1905 nova_endpoint
const & endpoint
)
1907 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
1908 sample
* free_buf
= sc_factory
->get_nrt_mirror_buffer(index
);
1909 int error
= sc_factory
->buffer_read_alloc(index
, filename
.c_str(), start
, frames
);
1911 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_allocRead_2_rt
<realtime
>, index
, msg
, free_buf
, endpoint
));
1913 /* post nice error message */;
1916 template <bool realtime
>
1917 void b_allocRead_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
,
1918 nova_endpoint
const & endpoint
)
1920 sc_factory
->buffer_sync(index
);
1921 msg
.handle(endpoint
);
1922 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_allocRead_3_nrt
, index
, free_buf
, endpoint
));
1925 void b_allocRead_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1927 free_aligned(free_buf
);
1928 send_done_message(endpoint
, "/b_allocRead", index
);
1931 template <bool realtime
>
1932 void handle_b_allocRead(received_message
const & msg
, nova_endpoint
const & endpoint
)
1934 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
1937 const char * filename
;
1939 osc::int32 start
= 0;
1940 osc::int32 frames
= 0;
1942 args
>> index
>> filename
;
1950 completion_message message
= extract_completion_message(args
);
1952 movable_string
fname(filename
);
1953 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_allocRead_1_nrt
<realtime
>, index
,
1954 fname
, start
, frames
, message
, endpoint
));
1957 template <bool realtime
>
1958 void b_allocReadChannel_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
,
1959 nova_endpoint
const & endpoint
);
1960 void b_allocReadChannel_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
1962 template <bool realtime
>
1963 void b_allocReadChannel_1_nrt(uint32_t index
, movable_string
const & filename
, uint32_t start
, uint32_t frames
,
1964 movable_array
<uint32_t> const & channels
, completion_message
& msg
,
1965 nova_endpoint
const & endpoint
)
1967 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
1968 sample
* free_buf
= sc_factory
->get_nrt_mirror_buffer(index
);
1969 int error
= sc_factory
->buffer_alloc_read_channels(index
, filename
.c_str(), start
, frames
,
1970 channels
.size(), channels
.data());
1972 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_allocReadChannel_2_rt
<realtime
>,
1973 index
, msg
, free_buf
, endpoint
));
1976 template <bool realtime
>
1977 void b_allocReadChannel_2_rt(uint32_t index
, completion_message
& msg
, sample
* free_buf
,
1978 nova_endpoint
const & endpoint
)
1980 sc_factory
->buffer_sync(index
);
1981 msg
.handle(endpoint
);
1982 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_allocReadChannel_3_nrt
,
1983 index
, free_buf
, endpoint
));
1986 void b_allocReadChannel_3_nrt(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
1988 free_aligned(free_buf
);
1989 send_done_message(endpoint
, "/b_allocReadChannel", index
);
1993 template <bool realtime
>
1994 void handle_b_allocReadChannel(received_message
const & msg
, nova_endpoint
const & endpoint
)
1996 osc::ReceivedMessageArgumentIterator arg
= msg
.ArgumentsBegin();
1998 osc::int32 index
= arg
->AsInt32(); arg
++;
1999 const char * filename
= arg
->AsString(); arg
++;
2001 osc::int32 start
= arg
->AsInt32(); arg
++;
2002 size_t frames
= arg
->AsInt32(); arg
++;
2004 size_t channel_args
= msg
.ArgumentCount() - 4; /* we already consumed 4 elements */
2006 size_t channel_count
= 0;
2007 sized_array
<uint
, rt_pool_allocator
<uint
> > channels(channel_args
);
2009 for (uint i
= 0; i
!= channel_args
- 1; ++i
) // sclang fromats the last completion message as int, so we skip the last element
2011 if (arg
->IsInt32()) {
2012 channels
[i
] = arg
->AsInt32Unchecked(); arg
++;
2017 /* we reached the message blob */
2018 completion_message message
= extract_completion_message(arg
);
2020 movable_array
<uint32_t> channel_mapping(channel_count
, channels
.c_array());
2021 movable_string
fname(filename
);
2023 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_allocReadChannel_1_nrt
<realtime
>,
2024 index
, fname
, start
, frames
, channel_mapping
,
2025 message
, endpoint
));
2028 const char * b_write
= "/b_write";
2030 template <bool realtime
>
2031 void b_write_nrt_1(uint32_t index
, movable_string
const & filename
, movable_string
const & header_format
,
2032 movable_string
const & sample_format
, uint32_t start
, uint32_t frames
, bool leave_open
,
2033 completion_message
& msg
, nova_endpoint
const & endpoint
)
2035 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
2036 sc_factory
->buffer_write(index
, filename
.c_str(), header_format
.c_str(), sample_format
.c_str(), start
, frames
, leave_open
);
2037 msg
.trigger_async(endpoint
);
2038 cmd_dispatcher
<realtime
>::fire_done_message(endpoint
, b_write
, index
);
2041 void fire_b_write_exception(void)
2043 throw std::runtime_error("wrong arguments for /b_allocReadChannel");
2046 template <bool realtime
>
2047 void handle_b_write(received_message
const & msg
, nova_endpoint
const & endpoint
)
2049 osc::ReceivedMessageArgumentIterator arg
= msg
.ArgumentsBegin();
2050 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2053 osc::int32 index
= arg
->AsInt32(); arg
++;
2054 const char * filename
= arg
->AsString(); arg
++;
2055 const char * header_format
= arg
->AsString(); arg
++;
2056 const char * sample_format
= arg
->AsString(); arg
++;
2059 osc::int32 frames
= -1;
2060 osc::int32 start
= 0;
2061 osc::int32 leave_open
= 0;
2063 completion_message message
;
2066 if (!arg
->IsInt32())
2067 fire_b_write_exception();
2068 frames
= arg
->AsInt32Unchecked(); arg
++;
2074 if (!arg
->IsInt32())
2075 fire_b_write_exception();
2076 start
= arg
->AsInt32Unchecked(); arg
++;
2082 if (!arg
->IsInt32())
2083 fire_b_write_exception();
2084 leave_open
= arg
->AsInt32Unchecked(); arg
++;
2090 message
= extract_completion_message(arg
);
2093 movable_string
fname(filename
);
2094 movable_string
header_f(header_format
);
2095 movable_string
sample_f(sample_format
);
2097 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_write_nrt_1
<realtime
>, index
, fname
, header_f
, sample_f
,
2098 start
, frames
, bool(leave_open
), message
, endpoint
));
2101 template <bool realtime
>
2102 void b_read_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
);
2104 template <bool realtime
>
2105 void b_read_nrt_1(uint32_t index
, movable_string
& filename
, uint32_t start_file
, uint32_t frames
,
2106 uint32_t start_buffer
, bool leave_open
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2108 sc_ugen_factory::buffer_lock_t
buffer_lock(sc_factory
->buffer_guard(index
));
2109 sc_factory
->buffer_read(index
, filename
.c_str(), start_file
, frames
, start_buffer
, leave_open
);
2110 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_read_rt_2
<realtime
>, index
, msg
, endpoint
));
2113 const char * b_read
= "/b_read";
2114 template <bool realtime
>
2115 void b_read_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2117 sc_factory
->buffer_sync(index
);
2118 msg
.handle(endpoint
);
2119 cmd_dispatcher
<realtime
>::fire_done_message(endpoint
, b_read
, index
);
2122 void fire_b_read_exception(void)
2124 throw std::runtime_error("wrong arguments for /b_read");
2127 template <bool realtime
>
2128 void handle_b_read(received_message
const & msg
, nova_endpoint
const & endpoint
)
2130 osc::ReceivedMessageArgumentIterator arg
= msg
.ArgumentsBegin();
2131 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2134 osc::int32 index
= arg
->AsInt32(); arg
++;
2135 const char * filename
= arg
->AsString(); arg
++;
2138 osc::int32 start_file
= 0;
2139 osc::int32 frames
= -1;
2140 osc::int32 start_buffer
= 0;
2141 osc::int32 leave_open
= 0;
2143 completion_message message
;
2146 if (!arg
->IsInt32())
2147 fire_b_read_exception();
2148 start_file
= arg
->AsInt32Unchecked(); arg
++;
2154 if (!arg
->IsInt32())
2155 fire_b_read_exception();
2156 frames
= arg
->AsInt32Unchecked(); arg
++;
2162 if (!arg
->IsInt32())
2163 fire_b_read_exception();
2164 start_buffer
= arg
->AsInt32Unchecked(); arg
++;
2170 if (!arg
->IsInt32())
2171 fire_b_read_exception();
2172 leave_open
= arg
->AsInt32Unchecked(); arg
++;
2178 message
= extract_completion_message(arg
);
2181 movable_string
fname(filename
);
2183 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_read_nrt_1
<realtime
>, index
, fname
,
2184 start_file
, frames
, start_buffer
,
2185 bool(leave_open
), message
, endpoint
));
2189 template <bool realtime
>
2190 void b_readChannel_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
);
2192 template <bool realtime
>
2193 void b_readChannel_nrt_1(uint32_t index
, movable_string
& filename
, uint32_t start_file
, uint32_t frames
,
2194 uint32_t start_buffer
, bool leave_open
, movable_array
<uint32_t> & channel_map
,
2195 completion_message
& msg
, nova_endpoint
const & endpoint
)
2197 sc_factory
->buffer_read_channel(index
, filename
.c_str(), start_file
, frames
, start_buffer
, leave_open
,
2198 channel_map
.size(), channel_map
.data());
2199 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_readChannel_rt_2
<realtime
>, index
, msg
, endpoint
));
2202 const char * b_readChannel
= "/b_readChannel";
2203 template <bool realtime
>
2204 void b_readChannel_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2206 sc_factory
->buffer_sync(index
);
2207 msg
.handle(endpoint
);
2208 cmd_dispatcher
<realtime
>::fire_done_message(endpoint
, b_readChannel
, index
);
2211 void fire_b_readChannel_exception(void)
2213 throw std::runtime_error("wrong arguments for /b_readChannel");
2216 template <bool realtime
>
2217 void handle_b_readChannel(received_message
const & msg
, nova_endpoint
const & endpoint
)
2219 osc::ReceivedMessageArgumentIterator arg
= msg
.ArgumentsBegin();
2220 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2223 osc::int32 index
= arg
->AsInt32(); arg
++;
2224 const char * filename
= arg
->AsString(); arg
++;
2227 osc::int32 start_file
= 0;
2228 osc::int32 frames
= -1;
2229 osc::int32 start_buffer
= 0;
2230 osc::int32 leave_open
= 0;
2232 sized_array
<uint32_t, rt_pool_allocator
<uint32_t> > channel_mapping(int32_t(msg
.ArgumentCount())); /* larger than required */
2233 uint32_t channel_count
= 0;
2235 completion_message message
;
2238 if (!arg
->IsInt32())
2239 fire_b_read_exception();
2240 start_file
= arg
->AsInt32Unchecked(); arg
++;
2246 if (!arg
->IsInt32())
2247 fire_b_read_exception();
2248 frames
= arg
->AsInt32Unchecked(); arg
++;
2254 if (!arg
->IsInt32())
2255 fire_b_write_exception();
2256 start_buffer
= arg
->AsInt32Unchecked(); arg
++;
2262 if (!arg
->IsInt32())
2263 fire_b_write_exception();
2264 leave_open
= arg
->AsInt32Unchecked(); arg
++;
2271 if (arg
->IsBlob()) {
2272 message
= extract_completion_message(arg
);
2275 else if (arg
->IsInt32()) {
2276 channel_mapping
[channel_count
] = arg
->AsInt32Unchecked();
2280 fire_b_readChannel_exception();
2284 movable_string
fname(filename
);
2285 movable_array
<uint32_t> channel_map(channel_count
, channel_mapping
.c_array());
2287 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_readChannel_nrt_1
<realtime
>, index
, fname
,
2288 start_file
, frames
, start_buffer
,
2289 bool(leave_open
), channel_map
, message
, endpoint
));
2293 template <bool realtime
>
2294 void b_zero_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
);
2296 template <bool realtime
>
2297 void b_zero_nrt_1(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2299 sc_factory
->buffer_zero(index
);
2300 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_zero_rt_2
<realtime
>, index
, msg
, endpoint
));
2303 const char * b_zero
= "/b_zero";
2304 template <bool realtime
>
2305 void b_zero_rt_2(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2307 sc_factory
->increment_write_updates(index
);
2308 msg
.handle(endpoint
);
2309 cmd_dispatcher
<realtime
>::fire_done_message(endpoint
, b_zero
, index
);
2312 template <bool realtime
>
2313 void handle_b_zero(received_message
const & msg
, nova_endpoint
const & endpoint
)
2315 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2319 completion_message message
= extract_completion_message(args
);
2321 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_zero_nrt_1
<realtime
>, index
, message
, endpoint
));
2324 void handle_b_set(received_message
const & msg
)
2326 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2327 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2328 verify_argument(it
, end
);
2329 osc::int32 buffer_index
= it
->AsInt32(); ++it
;
2331 buffer_wrapper::sample_t
* data
= sc_factory
->get_buffer(buffer_index
);
2334 osc::int32 index
= it
->AsInt32(); ++it
;
2335 float value
= extract_float_argument(it
++);
2337 data
[index
] = value
;
2341 void handle_b_setn(received_message
const & msg
)
2343 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2344 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2345 verify_argument(it
, end
);
2346 osc::int32 buffer_index
= it
->AsInt32(); ++it
;
2348 buffer_wrapper::sample_t
* data
= sc_factory
->get_buffer(buffer_index
);
2351 osc::int32 index
= it
->AsInt32(); ++it
;
2352 verify_argument(it
, end
);
2353 osc::int32 samples
= it
->AsInt32(); ++it
;
2355 for (int i
= 0; i
!= samples
; ++i
) {
2356 verify_argument(it
, end
);
2357 float value
= extract_float_argument(it
++);
2358 data
[index
+i
] = value
;
2363 void handle_b_fill(received_message
const & msg
)
2365 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2366 osc::ReceivedMessageArgumentIterator end
= msg
.ArgumentsEnd();
2367 verify_argument(it
, end
);
2368 osc::int32 buffer_index
= it
->AsInt32(); ++it
;
2370 buffer_wrapper::sample_t
* data
= sc_factory
->get_buffer(buffer_index
);
2373 osc::int32 index
= it
->AsInt32(); ++it
;
2374 verify_argument(it
, end
);
2375 osc::int32 samples
= it
->AsInt32(); ++it
;
2376 verify_argument(it
, end
);
2377 float value
= extract_float_argument(it
++);
2379 for (int i
= 0; i
!= samples
; ++i
)
2380 data
[index
] = value
;
2384 template <bool realtime
>
2385 void handle_b_query(received_message
const & msg
, nova_endpoint
const & endpoint
)
2387 const size_t elem_size
= 3*sizeof(int) * sizeof(float);
2389 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2390 size_t arg_count
= msg
.ArgumentCount();
2392 size_t size
= elem_size
* arg_count
+ 128; /* should be more than required */
2393 sized_array
<char, rt_pool_allocator
<char> > data(size
);
2395 osc::OutboundPacketStream
p(data
.c_array(), size
);
2396 p
<< osc::BeginMessage("/b_info");
2398 while (!args
.Eos()) {
2399 osc::int32 buffer_index
;
2400 args
>> buffer_index
;
2402 SndBuf
* buf
= sc_factory
->get_buffer_struct(buffer_index
);
2405 << osc::int32(buf
->frames
)
2406 << osc::int32(buf
->channels
)
2407 << float (buf
->samplerate
);
2410 p
<< osc::EndMessage
;
2412 movable_array
<char> message(p
.Size(), data
.c_array());
2414 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2417 template <bool realtime
>
2418 void b_close_rt_2(completion_message
& msg
, nova_endpoint
const & endpoint
);
2420 template <bool realtime
>
2421 void b_close_nrt_1(uint32_t index
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2423 sc_factory
->buffer_close(index
);
2424 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_close_rt_2
<realtime
>, msg
, endpoint
));
2427 template <bool realtime
>
2428 void b_close_rt_2(completion_message
& msg
, nova_endpoint
const & endpoint
)
2432 template <bool realtime
>
2433 void handle_b_close(received_message
const & msg
, nova_endpoint
const & endpoint
)
2435 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2439 completion_message message
= extract_completion_message(args
);
2440 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_close_nrt_1
<realtime
>, index
, message
, endpoint
));
2443 template <bool realtime
>
2444 void handle_b_get(received_message
const & msg
, nova_endpoint
const & endpoint
)
2446 const size_t elem_size
= sizeof(int) * sizeof(float);
2447 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2448 const size_t index_count
= msg
.ArgumentCount() - 1;
2449 const size_t alloc_size
= index_count
* elem_size
+ 128; /* hopefully enough */
2451 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
2453 osc::int32 buffer_index
;
2454 args
>> buffer_index
;
2456 const SndBuf
* buf
= sc_factory
->get_buffer_struct(buffer_index
);
2457 const sample
* data
= buf
->data
;
2458 const int max_sample
= buf
->frames
* buf
->channels
;
2460 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
2461 p
<< osc::BeginMessage("/b_set")
2470 if (index
< max_sample
)
2476 p
<< osc::EndMessage
;
2478 movable_array
<char> message(p
.Size(), return_message
.c_array());
2479 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2482 template<typename Alloc
>
2485 getn_data(int start
, int count
, const float * data
):
2486 start_index_(start
), data_(count
)
2488 data_
.reserve(count
);
2489 for (int i
= 0; i
!= count
; ++i
)
2494 std::vector
<float, Alloc
> data_
;
2497 template <bool realtime
>
2498 void handle_b_getn(received_message
const & msg
, nova_endpoint
const & endpoint
)
2500 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2502 typedef getn_data
<rt_pool_allocator
<float> > getn_data
;
2503 std::vector
<getn_data
, rt_pool_allocator
<getn_data
> > return_data
;
2505 osc::int32 buffer_index
;
2506 args
>> buffer_index
;
2508 const SndBuf
* buf
= sc_factory
->get_buffer_struct(buffer_index
);
2509 const sample
* data
= buf
->data
;
2510 const int max_sample
= buf
->frames
* buf
->channels
;
2514 osc::int32 index
, sample_count
;
2515 args
>> index
>> sample_count
;
2517 if (index
+ sample_count
<= max_sample
)
2518 return_data
.push_back(getn_data(index
, sample_count
, data
+ index
));
2521 size_t alloc_size
= 128;
2522 for (size_t i
= 0; i
!= return_data
.size(); ++i
)
2523 alloc_size
+= return_data
[i
].data_
.size() * (sizeof(float) + sizeof(int)) + 2*sizeof(int);
2525 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
2527 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
2528 p
<< osc::BeginMessage("/b_setn")
2531 for (size_t i
= 0; i
!= return_data
.size(); ++i
) {
2532 p
<< osc::int32(return_data
[i
].start_index_
)
2533 << osc::int32(return_data
[i
].data_
.size());
2535 for (size_t j
= 0; j
!= return_data
[i
].data_
.size(); ++j
)
2536 p
<< return_data
[i
].data_
[j
];
2539 p
<< osc::EndMessage
;
2541 movable_array
<char> message(p
.Size(), return_message
.c_array());
2542 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2546 template <bool realtime
>
2547 void b_gen_rt_2(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
2548 void b_gen_nrt_3(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
);
2550 template <bool realtime
>
2551 void b_gen_nrt_1(movable_array
<char> & message
, nova_endpoint
const & endpoint
)
2553 const char * data
= (char*)message
.data();
2554 const char * msg_data
= OSCstrskip(data
); // skip address
2555 size_t diff
= msg_data
- data
;
2557 sc_msg_iter
msg(message
.size() - diff
, msg_data
);
2559 char nextTag
= msg
.nextTag();
2560 if (nextTag
!= 'i') {
2561 printf("/b_gen handler: invalid buffer index type %c\n", nextTag
);
2564 int index
= msg
.geti();
2566 const char * generator
= (const char*)msg
.gets4();
2568 if (nextTag
+= 'i') {
2569 printf("/b_gen handler: invalid bufgen name\n");
2574 sample
* free_buf
= sc_factory
->buffer_generate(index
, generator
, msg
);
2575 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(b_gen_rt_2
<realtime
>, index
, free_buf
, endpoint
));
2578 template <bool realtime
>
2579 void b_gen_rt_2(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
2581 sc_factory
->buffer_sync(index
);
2582 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_gen_nrt_3
, index
, free_buf
, endpoint
));
2585 void b_gen_nrt_3(uint32_t index
, sample
* free_buf
, nova_endpoint
const & endpoint
)
2587 free_aligned(free_buf
);
2588 send_done_message(endpoint
, "/b_gen", index
);
2591 template <bool realtime
>
2592 void handle_b_gen(received_message
const & msg
, size_t msg_size
, nova_endpoint
const & endpoint
)
2594 movable_array
<char> cmd (msg_size
, msg
.AddressPattern());
2595 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(b_gen_nrt_1
<realtime
>, cmd
, endpoint
));
2599 void handle_c_set(received_message
const & msg
)
2601 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2603 while (it
!= msg
.ArgumentsEnd()) {
2604 osc::int32 bus_index
= it
->AsInt32(); ++it
;
2605 float value
= extract_float_argument(it
++);
2607 sc_factory
->controlbus_set(bus_index
, value
);
2611 void handle_c_setn(received_message
const & msg
)
2613 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2615 while (it
!= msg
.ArgumentsEnd()) {
2616 osc::int32 bus_index
, bus_count
;
2617 bus_index
= it
->AsInt32(); ++it
;
2618 bus_count
= it
->AsInt32(); ++it
;
2620 for (int i
= 0; i
!= bus_count
; ++i
) {
2621 float value
= extract_float_argument(it
++);
2622 sc_factory
->controlbus_set(bus_index
+ i
, value
);
2627 void handle_c_fill(received_message
const & msg
)
2629 osc::ReceivedMessageArgumentIterator it
= msg
.ArgumentsBegin();
2631 while (it
!= msg
.ArgumentsEnd()) {
2632 osc::int32 bus_index
, bus_count
;
2633 bus_index
= it
->AsInt32(); ++it
;
2634 bus_count
= it
->AsInt32(); ++it
;
2635 float value
= extract_float_argument(it
++);
2636 sc_factory
->controlbus_fill(bus_index
, bus_count
, value
);
2640 template <bool realtime
>
2641 void handle_c_get(received_message
const & msg
,
2642 nova_endpoint
const & endpoint
)
2644 const size_t elem_size
= sizeof(int) + sizeof(float);
2645 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2646 const size_t index_count
= msg
.ArgumentCount();
2647 const size_t alloc_size
= index_count
* elem_size
+ 128; /* hopefully enough */
2649 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
2651 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
2652 p
<< osc::BeginMessage("/c_set");
2659 p
<< index
<< sc_factory
->controlbus_get(index
);
2662 p
<< osc::EndMessage
;
2664 movable_array
<char> message(p
.Size(), return_message
.c_array());
2665 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2668 template <bool realtime
>
2669 void handle_c_getn(received_message
const & msg
, nova_endpoint
const & endpoint
)
2671 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2673 /* we pessimize, but better to allocate too much than too little */
2674 const size_t alloc_size
= 128 +
2675 (2 * sizeof(int) + 128*sizeof(float)) * msg
.ArgumentCount();
2677 sized_array
<char, rt_pool_allocator
<char> > return_message(alloc_size
);
2679 osc::OutboundPacketStream
p(return_message
.c_array(), alloc_size
);
2680 p
<< osc::BeginMessage("/c_setn");
2684 osc::int32 bus_index
, bus_count
;
2685 args
>> bus_index
>> bus_count
;
2686 p
<< bus_index
<< bus_count
;
2688 for (int i
= 0; i
!= bus_count
; ++i
) {
2689 float value
= sc_factory
->controlbus_get(bus_index
+ i
);
2694 p
<< osc::EndMessage
;
2696 movable_array
<char> message(p
.Size(), return_message
.c_array());
2697 cmd_dispatcher
<realtime
>::fire_io_callback(boost::bind(send_udp_message
, message
, endpoint
));
2700 #ifdef BOOST_HAS_RVALUE_REFS
2701 std::pair
<sc_synth_prototype_ptr
*, size_t> wrap_synthdefs(std::vector
<sc_synthdef
> && defs
)
2703 std::vector
<sc_synthdef
> synthdefs(std::move(defs
));
2704 size_t count
= synthdefs
.size();
2705 sc_synth_prototype_ptr
* prototypes
= new sc_synth_prototype_ptr
[count
];
2707 for (size_t i
= 0; i
!= count
; ++i
)
2708 prototypes
[i
].reset(new sc_synth_prototype(std::move(synthdefs
[i
])));
2709 return std::make_pair(prototypes
, count
);
2712 std::pair
<sc_synth_prototype_ptr
*, size_t> wrap_synthdefs(std::vector
<sc_synthdef
> const & defs
)
2714 size_t count
= defs
.size();
2715 sc_synth_prototype_ptr
* prototypes
= new sc_synth_prototype_ptr
[count
];
2717 for (size_t i
= 0; i
!= count
; ++i
)
2718 prototypes
[i
].reset(new sc_synth_prototype(defs
[i
]));
2719 return std::make_pair(prototypes
, count
);
2722 template <bool realtime
>
2723 void d_recv_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2724 nova_endpoint
const & endpoint
);
2725 void d_recv_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
);
2727 template <bool realtime
>
2728 void d_recv_nrt(movable_array
<char> & def
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2731 sc_synth_prototype_ptr
* prototypes
;
2732 std::vector
<sc_synthdef
> synthdefs (read_synthdefs(def
.data()));
2734 #ifdef BOOST_HAS_RVALUE_REFS
2735 boost::tie(prototypes
, count
) = wrap_synthdefs(std::move(synthdefs
));
2737 boost::tie(prototypes
, count
) = wrap_synthdefs(synthdefs
);
2740 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(d_recv_rt2
<realtime
>, prototypes
, count
, msg
, endpoint
));
2743 template <bool realtime
>
2744 void d_recv_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2745 nova_endpoint
const & endpoint
)
2747 std::for_each(prototypes
, prototypes
+ prototype_count
,
2748 boost::bind(&synth_factory::register_prototype
, instance
, _1
));
2750 msg
.handle(endpoint
);
2751 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_recv_nrt3
, prototypes
, endpoint
));
2754 void d_recv_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
)
2756 delete[] prototypes
;
2757 send_done_message(endpoint
, "/d_recv");
2760 template <bool realtime
>
2761 void handle_d_recv(received_message
const & msg
,
2762 nova_endpoint
const & endpoint
)
2764 const void * synthdef_data
;
2765 unsigned long synthdef_size
;
2767 osc::ReceivedMessageArgumentIterator args
= msg
.ArgumentsBegin();
2769 args
->AsBlob(synthdef_data
, synthdef_size
); ++args
;
2770 movable_array
<char> def(synthdef_size
, (const char*)synthdef_data
);
2771 completion_message message
= extract_completion_message(args
);
2773 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_recv_nrt
<realtime
>, def
, message
, endpoint
));
2776 template <bool realtime
>
2777 void d_load_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2778 nova_endpoint
const & endpoint
);
2779 void d_load_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
);
2781 template <bool realtime
>
2782 void d_load_nrt(movable_string
& path
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2785 sc_synth_prototype_ptr
* prototypes
;
2786 /* todo: we need to implment some file name pattern matching */
2787 boost::tie(prototypes
, count
) = wrap_synthdefs(sc_read_synthdefs_file(path
.c_str()));
2789 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(d_load_rt2
<realtime
>, prototypes
, count
, msg
, endpoint
));
2792 template <bool realtime
>
2793 void d_load_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2794 nova_endpoint
const & endpoint
)
2796 std::for_each(prototypes
, prototypes
+ prototype_count
,
2797 boost::bind(&synth_factory::register_prototype
, instance
, _1
));
2799 msg
.handle(endpoint
);
2800 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_load_nrt3
, prototypes
, endpoint
));
2803 void d_load_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
)
2805 delete[] prototypes
;
2806 send_done_message(endpoint
, "/d_load");
2810 template <bool realtime
>
2811 void handle_d_load(received_message
const & msg
,
2812 nova_endpoint
const & endpoint
)
2814 osc::ReceivedMessageArgumentIterator args
= msg
.ArgumentsBegin();
2815 const char * path
= args
->AsString(); args
++;
2816 completion_message message
= extract_completion_message(args
);
2818 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_load_nrt
<realtime
>, movable_string(path
),
2819 message
, endpoint
));
2823 template <bool realtime
>
2824 void d_loadDir_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2825 nova_endpoint
const & endpoint
);
2826 void d_loadDir_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
);
2828 template <bool realtime
>
2829 void d_loadDir_nrt1(movable_string
& path
, completion_message
& msg
, nova_endpoint
const & endpoint
)
2832 sc_synth_prototype_ptr
* prototypes
;
2833 boost::tie(prototypes
, count
) = wrap_synthdefs(sc_read_synthdefs_dir(path
.c_str()));
2835 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(d_loadDir_rt2
<realtime
>, prototypes
, count
, msg
, endpoint
));
2838 template <bool realtime
>
2839 void d_loadDir_rt2(sc_synth_prototype_ptr
* prototypes
, size_t prototype_count
, completion_message
& msg
,
2840 nova_endpoint
const & endpoint
)
2842 std::for_each(prototypes
, prototypes
+ prototype_count
,
2843 boost::bind(&synth_factory::register_prototype
, instance
, _1
));
2845 msg
.handle(endpoint
);
2846 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_loadDir_nrt3
, prototypes
, endpoint
));
2849 void d_loadDir_nrt3(sc_synth_prototype_ptr
* prototypes
, nova_endpoint
const & endpoint
)
2851 delete[] prototypes
;
2852 send_done_message(endpoint
, "/d_loadDir");
2855 template <bool realtime
>
2856 void handle_d_loadDir(received_message
const & msg
,
2857 nova_endpoint
const & endpoint
)
2859 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2863 completion_message message
= extract_completion_message(args
);
2865 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(d_loadDir_nrt1
<realtime
>,
2866 movable_string(path
), message
, endpoint
));
2870 void handle_d_free(received_message
const & msg
)
2872 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2876 const char * defname
;
2879 instance
->remove_prototype(defname
);
2883 void insert_parallel_group(int node_id
, int action
, int target_id
)
2886 node_id
= instance
->generate_node_id();
2887 else if (!check_node_id(node_id
))
2890 server_node
* target
= find_node(target_id
);
2894 node_position_constraint pos
= make_pair(target
, node_position(action
));
2895 if (!node_position_sanity_check(pos
))
2898 instance
->add_parallel_group(node_id
, pos
);
2899 last_generated
= node_id
;
2902 void handle_p_new(received_message
const & msg
)
2904 osc::ReceivedMessageArgumentStream args
= msg
.ArgumentStream();
2906 while(!args
.Eos()) {
2907 osc::int32 id
, action
, target
;
2908 args
>> id
>> action
>> target
;
2910 insert_parallel_group(id
, action
, target
);
2914 void handle_u_cmd(received_message
const & msg
, int size
)
2916 sc_msg_iter
args(size
, msg
.AddressPattern());
2918 int node_id
= args
.geti();
2920 server_node
* target_synth
= find_node(node_id
);
2922 if (target_synth
== NULL
|| target_synth
->is_group())
2925 sc_synth
* synth
= static_cast<sc_synth
*>(target_synth
);
2927 int ugen_index
= args
.geti();
2928 const char * cmd_name
= args
.gets();
2930 synth
->apply_unit_cmd(cmd_name
, ugen_index
, &args
);
2933 void handle_cmd(received_message
const & msg
, int size
, nova_endpoint
const & endpoint
, int skip_bytes
)
2935 sc_msg_iter
args(size
, msg
.AddressPattern() + skip_bytes
);
2937 const char * cmd
= args
.gets();
2939 sc_factory
->run_cmd_plugin(&sc_factory
->world
, cmd
, &args
, const_cast<nova_endpoint
*>(&endpoint
));
2944 template <bool realtime
>
2945 void sc_osc_handler::handle_message_int_address(received_message
const & message
,
2946 size_t msg_size
, nova_endpoint
const & endpoint
)
2948 uint32_t address
= message
.AddressPatternAsUInt32();
2953 handle_quit
<realtime
>(endpoint
);
2957 handle_s_new(message
);
2961 handle_s_noid(message
);
2965 handle_s_get
<realtime
>(message
, msg_size
, endpoint
);
2969 handle_s_getn
<realtime
>(message
, msg_size
, endpoint
);
2973 handle_notify
<realtime
>(message
, endpoint
);
2977 handle_status
<realtime
>(endpoint
);
2981 handle_dumpOSC(message
);
2985 handle_sync
<realtime
>(message
, endpoint
);
2988 case cmd_clearSched
:
2989 handle_clearSched();
2993 handle_error(message
);
2997 handle_g_new(message
);
3001 handle_g_head_or_tail
<head
>(message
);
3005 handle_g_head_or_tail
<tail
>(message
);
3009 handle_g_freeall(message
);
3012 case cmd_g_deepFree
:
3013 handle_g_deepFree(message
);
3016 case cmd_g_queryTree
:
3017 handle_g_queryTree
<realtime
>(message
, endpoint
);
3020 case cmd_g_dumpTree
:
3021 handle_g_dumpTree(message
);
3025 handle_n_free(message
);
3029 handle_n_set(message
);
3033 handle_n_setn(message
);
3037 handle_n_fill(message
);
3041 handle_n_map(message
);
3045 handle_n_mapn(message
);
3049 handle_n_mapa(message
);
3053 handle_n_mapan(message
);
3057 handle_n_query(message
, endpoint
);
3061 handle_n_order(message
);
3065 handle_n_run(message
);
3069 handle_n_before_or_after
<before
>(message
);
3073 handle_n_before_or_after
<after
>(message
);
3077 handle_n_trace(message
);
3081 handle_b_alloc
<realtime
>(message
, endpoint
);
3085 handle_u_cmd(message
, msg_size
);
3089 handle_b_free
<realtime
>(message
, endpoint
);
3092 case cmd_b_allocRead
:
3093 handle_b_allocRead
<realtime
>(message
, endpoint
);
3096 case cmd_b_allocReadChannel
:
3097 handle_b_allocReadChannel
<realtime
>(message
, endpoint
);
3101 handle_b_read
<realtime
>(message
, endpoint
);
3104 case cmd_b_readChannel
:
3105 handle_b_readChannel
<realtime
>(message
, endpoint
);
3109 handle_b_write
<realtime
>(message
, endpoint
);
3113 handle_b_zero
<realtime
>(message
, endpoint
);
3117 handle_b_set(message
);
3121 handle_b_setn(message
);
3125 handle_b_fill(message
);
3129 handle_b_query
<realtime
>(message
, endpoint
);
3133 handle_b_get
<realtime
>(message
, endpoint
);
3137 handle_b_getn
<realtime
>(message
, endpoint
);
3141 handle_b_gen
<realtime
>(message
, msg_size
, endpoint
);
3145 handle_b_close
<realtime
>(message
, endpoint
);
3149 handle_c_set(message
);
3153 handle_c_setn(message
);
3157 handle_c_fill(message
);
3161 handle_c_get
<realtime
>(message
, endpoint
);
3165 handle_c_getn
<realtime
>(message
, endpoint
);
3169 handle_d_recv
<realtime
>(message
, endpoint
);
3173 handle_d_load
<realtime
>(message
, endpoint
);
3177 handle_d_loadDir
<realtime
>(message
, endpoint
);
3181 handle_d_free(message
);
3185 handle_p_new(message
);
3189 handle_cmd(message
, msg_size
, endpoint
, 4);
3193 handle_unhandled_message(message
);
3200 template <bool realtime
>
3201 void dispatch_group_commands(const char * address
, received_message
const & message
,
3202 nova_endpoint
const & endpoint
)
3204 assert(address
[1] == 'g');
3205 assert(address
[2] == '_');
3207 if (strcmp(address
+3, "new") == 0) {
3208 handle_g_new(message
);
3211 if (strcmp(address
+3, "head") == 0) {
3212 handle_g_head_or_tail
<head
>(message
);
3215 if (strcmp(address
+3, "tail") == 0) {
3216 handle_g_head_or_tail
<tail
>(message
);
3219 if (strcmp(address
+3, "freeAll") == 0) {
3220 handle_g_freeall(message
);
3223 if (strcmp(address
+3, "deepFree") == 0) {
3224 handle_g_deepFree(message
);
3227 if (strcmp(address
+3, "queryTree") == 0) {
3228 handle_g_queryTree
<realtime
>(message
, endpoint
);
3232 if (strcmp(address
+3, "dumpTree") == 0) {
3233 handle_g_dumpTree(message
);
3238 template <bool realtime
>
3239 void dispatch_node_commands(const char * address
, received_message
const & message
,
3240 nova_endpoint
const & endpoint
)
3242 assert(address
[1] == 'n');
3243 assert(address
[2] == '_');
3245 if (strcmp(address
+3, "free") == 0) {
3246 handle_n_free(message
);
3250 if (strcmp(address
+3, "set") == 0) {
3251 handle_n_set(message
);
3255 if (strcmp(address
+3, "setn") == 0) {
3256 handle_n_setn(message
);
3260 if (strcmp(address
+3, "fill") == 0) {
3261 handle_n_fill(message
);
3265 if (strcmp(address
+3, "map") == 0) {
3266 handle_n_map(message
);
3270 if (strcmp(address
+3, "mapn") == 0) {
3271 handle_n_mapn(message
);
3275 if (strcmp(address
+3, "mapa") == 0) {
3276 handle_n_mapa(message
);
3280 if (strcmp(address
+3, "mapan") == 0) {
3281 handle_n_mapan(message
);
3285 if (strcmp(address
+3, "run") == 0) {
3286 handle_n_run(message
);
3290 if (strcmp(address
+3, "before") == 0) {
3291 handle_n_before_or_after
<before
>(message
);
3295 if (strcmp(address
+3, "after") == 0) {
3296 handle_n_before_or_after
<after
>(message
);
3300 if (strcmp(address
+3, "order") == 0) {
3301 handle_n_order(message
);
3305 if (strcmp(address
+3, "query") == 0) {
3306 handle_n_query(message
, endpoint
);
3310 if (strcmp(address
+3, "trace") == 0) {
3311 handle_n_trace(message
);
3316 template <bool realtime
>
3317 void dispatch_buffer_commands(const char * address
, received_message
const & message
,
3318 size_t msg_size
, nova_endpoint
const & endpoint
)
3320 assert(address
[1] == 'b');
3321 assert(address
[2] == '_');
3323 if (strcmp(address
+3, "alloc") == 0) {
3324 handle_b_alloc
<realtime
>(message
, endpoint
);
3328 if (strcmp(address
+3, "free") == 0) {
3329 handle_b_free
<realtime
>(message
, endpoint
);
3333 if (strcmp(address
+3, "allocRead") == 0) {
3334 handle_b_allocRead
<realtime
>(message
, endpoint
);
3337 if (strcmp(address
+3, "allocReadChannel") == 0) {
3338 handle_b_allocReadChannel
<realtime
>(message
, endpoint
);
3342 if (strcmp(address
+3, "read") == 0) {
3343 handle_b_read
<realtime
>(message
, endpoint
);
3347 if (strcmp(address
+3, "readChannel") == 0) {
3348 handle_b_readChannel
<realtime
>(message
, endpoint
);
3352 if (strcmp(address
+3, "write") == 0) {
3353 handle_b_write
<realtime
>(message
, endpoint
);
3357 if (strcmp(address
+3, "zero") == 0) {
3358 handle_b_zero
<realtime
>(message
, endpoint
);
3362 if (strcmp(address
+3, "set") == 0) {
3363 handle_b_set(message
);
3367 if (strcmp(address
+3, "setn") == 0) {
3368 handle_b_setn(message
);
3372 if (strcmp(address
+3, "fill") == 0) {
3373 handle_b_fill(message
);
3377 if (strcmp(address
+3, "query") == 0) {
3378 handle_b_query
<realtime
>(message
, endpoint
);
3382 if (strcmp(address
+3, "get") == 0) {
3383 handle_b_get
<realtime
>(message
, endpoint
);
3387 if (strcmp(address
+3, "getn") == 0) {
3388 handle_b_getn
<realtime
>(message
, endpoint
);
3392 if (strcmp(address
+3, "gen") == 0) {
3393 handle_b_gen
<realtime
>(message
, msg_size
, endpoint
);
3397 if (strcmp(address
+3, "close") == 0) {
3398 handle_b_close
<realtime
>(message
, endpoint
);
3403 template <bool realtime
>
3404 void dispatch_control_bus_commands(const char * address
, received_message
const & message
,
3405 nova_endpoint
const & endpoint
)
3407 assert(address
[1] == 'c');
3408 assert(address
[2] == '_');
3410 if (strcmp(address
+3, "set") == 0) {
3411 handle_c_set(message
);
3415 if (strcmp(address
+3, "setn") == 0) {
3416 handle_c_setn(message
);
3420 if (strcmp(address
+3, "fill") == 0) {
3421 handle_c_fill(message
);
3425 if (strcmp(address
+3, "get") == 0) {
3426 handle_c_get
<realtime
>(message
, endpoint
);
3430 if (strcmp(address
+3, "getn") == 0) {
3431 handle_c_getn
<realtime
>(message
, endpoint
);
3436 template <bool realtime
>
3437 void dispatch_synthdef_commands(const char * address
, received_message
const & message
,
3438 nova_endpoint
const & endpoint
)
3440 assert(address
[1] == 'd');
3441 assert(address
[2] == '_');
3443 if (strcmp(address
+3, "recv") == 0) {
3444 handle_d_recv
<realtime
>(message
, endpoint
);
3448 if (strcmp(address
+3, "load") == 0) {
3449 handle_d_load
<realtime
>(message
, endpoint
);
3453 if (strcmp(address
+3, "loadDir") == 0) {
3454 handle_d_loadDir
<realtime
>(message
, endpoint
);
3458 if (strcmp(address
+3, "free") == 0) {
3459 handle_d_free(message
);
3464 template <bool realtime
>
3465 void dispatch_synth_commands(const char * address
, received_message
const & message
, size_t msg_size
,
3466 nova_endpoint
const & endpoint
)
3468 assert(address
[1] == 's');
3469 assert(address
[2] == '_');
3471 if (strcmp(address
+3, "new") == 0) {
3472 handle_s_new(message
);
3476 if (strcmp(address
+3, "noid") == 0) {
3477 handle_s_noid(message
);
3481 if (strcmp(address
+3, "get") == 0) {
3482 handle_s_get
<realtime
>(message
, msg_size
, endpoint
);
3486 if (strcmp(address
+3, "getn") == 0) {
3487 handle_s_getn
<realtime
>(message
, msg_size
, endpoint
);
3494 template <bool realtime
>
3495 void sc_osc_handler::handle_message_sym_address(received_message
const & message
,
3496 size_t msg_size
, nova_endpoint
const & endpoint
)
3498 const char * address
= message
.AddressPattern();
3500 /* scsynth doesn't require the leading / */
3501 if(address
[0] != '/')
3504 if (address
[2] == '_')
3506 if (address
[1] == 'g') {
3507 dispatch_group_commands
<realtime
>(address
, message
, endpoint
);
3511 if (address
[1] == 'n') {
3512 dispatch_node_commands
<realtime
>(address
, message
, endpoint
);
3516 if (address
[1] == 'b') {
3517 dispatch_buffer_commands
<realtime
>(address
, message
, msg_size
, endpoint
);
3521 if (address
[1] == 'c') {
3522 dispatch_control_bus_commands
<realtime
>(address
, message
, endpoint
);
3526 if (address
[1] == 'd') {
3527 dispatch_synthdef_commands
<realtime
>(address
, message
, endpoint
);
3531 if (address
[1] == 's') {
3532 dispatch_synth_commands
<realtime
>(address
, message
, msg_size
, endpoint
);
3537 if (strcmp(address
+1, "p_new") == 0) {
3538 handle_p_new(message
);
3542 if (strcmp(address
+1, "u_cmd") == 0) {
3543 handle_u_cmd(message
, msg_size
);
3547 if (strcmp(address
+1, "status") == 0) {
3548 handle_status
<realtime
>(endpoint
);
3552 if (strcmp(address
+1, "sync") == 0) {
3553 handle_sync
<realtime
>(message
, endpoint
);
3557 if (strcmp(address
+1, "quit") == 0) {
3558 handle_quit
<realtime
>(endpoint
);
3562 if (strcmp(address
+1, "notify") == 0) {
3563 handle_notify
<realtime
>(message
, endpoint
);
3567 if (strcmp(address
+1, "dumpOSC") == 0) {
3568 handle_dumpOSC(message
);
3572 if (strcmp(address
+1, "clearSched") == 0) {
3573 handle_clearSched();
3577 if (strcmp(address
+1, "error") == 0) {
3578 handle_error(message
);
3582 if (strcmp(address
+1, "cmd") == 0) {
3583 handle_cmd(message
, msg_size
, endpoint
, 8);
3587 handle_unhandled_message(message
);
3591 template <bool realtime
>
3592 void handle_asynchronous_plugin_cleanup(World
* world
, void *cmdData
,
3593 AsyncFreeFn cleanup
)
3596 (cleanup
)(world
, cmdData
);
3599 template <bool realtime
>
3600 void handle_asynchronous_plugin_stage4(World
* world
, const char * cmdName
, void *cmdData
, AsyncStageFn stage4
,
3601 AsyncFreeFn cleanup
, completion_message
& msg
, nova_endpoint
const & endpoint
)
3604 (stage4
)(world
, cmdData
);
3606 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(handle_asynchronous_plugin_cleanup
<realtime
>, world
, cmdData
,
3609 send_done_message(endpoint
, cmdName
);
3612 template <bool realtime
>
3613 void handle_asynchronous_plugin_stage3(World
* world
, const char * cmdName
, void *cmdData
, AsyncStageFn stage3
, AsyncStageFn stage4
,
3614 AsyncFreeFn cleanup
, completion_message
& msg
, nova_endpoint
const & endpoint
)
3617 bool success
= (stage3
)(world
, cmdData
);
3619 msg
.handle(endpoint
);
3621 cmd_dispatcher
<realtime
>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage4
<realtime
>, world
, cmdName
,
3622 cmdData
, stage4
, cleanup
, msg
, endpoint
));
3625 template <bool realtime
>
3626 void handle_asynchronous_plugin_stage2(World
* world
, const char * cmdName
, void *cmdData
, AsyncStageFn stage2
,
3627 AsyncStageFn stage3
, AsyncStageFn stage4
,
3628 AsyncFreeFn cleanup
, completion_message
& msg
, nova_endpoint
const & endpoint
)
3631 (stage2
)(world
, cmdData
);
3633 cmd_dispatcher
<realtime
>::fire_rt_callback(boost::bind(handle_asynchronous_plugin_stage3
<realtime
>, world
, cmdName
,
3634 cmdData
, stage3
, stage4
,
3635 cleanup
, msg
, endpoint
));
3638 void sc_osc_handler::do_asynchronous_command(World
* world
, void* replyAddr
, const char* cmdName
, void *cmdData
,
3639 AsyncStageFn stage2
, AsyncStageFn stage3
, AsyncStageFn stage4
, AsyncFreeFn cleanup
,
3640 int completionMsgSize
, void* completionMsgData
)
3642 completion_message
msg(completionMsgSize
, completionMsgData
);
3643 nova_endpoint
endpoint(*static_cast<nova_endpoint
*>(replyAddr
));
3645 if (world
->mRealTime
)
3646 cmd_dispatcher
<true>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage2
<true>, world
, cmdName
,
3647 cmdData
, stage2
, stage3
, stage4
, cleanup
, msg
, endpoint
));
3649 cmd_dispatcher
<false>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage2
<false>, world
, cmdName
,
3650 cmdData
, stage2
, stage3
, stage4
, cleanup
, msg
, endpoint
));
3654 } /* namespace detail */
3655 } /* namespace nova */