Change PG_03 discussion of rests to use Rest()
[supercollider.git] / server / supernova / sc / sc_osc_handler.cpp
blob50840a5a6822cb23489463a04ddf3fac2e455b5d
1 // osc handler for supercollider-style communication, implementation
2 // Copyright (C) 2009, 2010 Tim Blechmann
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; see the file COPYING. If not, write to
16 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 // Boston, MA 02111-1307, USA.
19 #include <iostream>
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"
31 namespace nova {
33 using namespace std;
35 namespace {
37 int32_t last_generated = 0;
39 server_node * find_node(int32_t target_id)
41 if (target_id == -1)
42 target_id = last_generated;
44 server_node * node = instance->find_node(target_id);
46 if (node == NULL)
47 log_printf("node not found: %d\n", target_id);
49 return node;
52 abstract_group * find_group(int32_t target_id)
54 if (target_id == -1)
55 target_id = last_generated;
57 abstract_group * node = instance->find_group(target_id);
59 if (node == NULL)
60 log("node not found or not a group\n");
61 return node;
64 bool check_node_id(int node_id)
66 if (!instance->node_id_available(node_id)) {
67 log("node id %d already in use\n", node_id);
68 return false;
70 return true;
73 void fill_notification(const server_node * node, osc::OutboundPacketStream & p)
75 p << node->id();
77 /* parent */
78 const abstract_group * parent_node = node->get_parent();
79 assert(parent_node);
80 p << parent_node->id();
82 /* previous/next */
83 if (parent_node->is_parallel())
84 p << -2 << -2; /* we are in a parallel group, so we have no notion of previous/next */
85 else
87 const server_node * prev_node = node->previous_node();
88 if (prev_node)
89 p << prev_node->id();
90 else
91 p << -1;
93 const server_node * next_node = node->next_node();
94 if (next_node)
95 p << next_node->id();
96 else
97 p << -1;
100 /* is_synth, head, tail */
101 if (node->is_synth())
102 p << 0;
103 else {
104 const abstract_group * node_group = static_cast<const abstract_group*>(node);
105 p << 1;
107 if (node_group->is_parallel())
108 p << -2 << -2;
109 else
111 const group * node_real_group = static_cast<const group*>(node_group);
112 if (node_real_group->empty())
113 p << -1 << -1;
114 else
115 p << node_real_group->head_node()->id()
116 << node_real_group->tail_node()->id();
120 p << osc::EndMessage;
123 spin_lock system_callback_allocator_lock;
125 struct movable_string
127 /** allocate new string, only allowed to be called from the rt context */
128 explicit movable_string(const char * str)
130 size_t length = strlen(str) + 1; /* terminating \0 */
131 char * data = (char*)system_callback::allocate(length);
132 strcpy(data, str);
133 data_ = data;
136 /** copy constructor has move semantics!!! */
137 movable_string(movable_string const & rhs)
139 data_ = rhs.data_;
140 const_cast<movable_string&>(rhs).data_ = NULL;
143 ~movable_string(void)
145 if (data_)
146 system_callback::deallocate((char*)data_);
149 const char * c_str(void) const
151 return data_;
154 private:
155 const char * data_;
158 template <typename T>
159 struct movable_array
161 /** allocate new array, only allowed to be called from the rt context */
162 movable_array(size_t length, const T * data, bool locked = false):
163 length_(length)
165 data_ = (T*)system_callback::allocate(length * sizeof(T));
166 for (size_t i = 0; i != length; ++i)
167 data_[i] = data[i];
170 /** copy constructor has move semantics!!! */
171 movable_array(movable_array const & rhs)
173 length_ = rhs.length_;
174 data_ = rhs.data_;
175 const_cast<movable_array&>(rhs).data_ = NULL;
178 ~movable_array(void)
180 if (data_)
181 system_callback::deallocate((char*)data_);
184 const T * data(void) const
186 return data_;
189 const T & operator[](size_t index) const
191 return data_[index];
194 size_t size(void) const
196 return length_;
199 private:
200 size_t length_;
201 T * data_;
204 void send_done_message(nova_endpoint const & endpoint)
206 char buffer[128];
207 osc::OutboundPacketStream p(buffer, 128);
208 p << osc::BeginMessage("/done")
209 << osc::EndMessage;
211 instance->send(p.Data(), p.Size(), endpoint);
214 void send_done_message(nova_endpoint const & endpoint, const char * cmd)
216 char buffer[128];
217 osc::OutboundPacketStream p(buffer, 128);
218 p << osc::BeginMessage("/done")
219 << cmd
220 << osc::EndMessage;
222 instance->send(p.Data(), p.Size(), endpoint);
225 void send_done_message(nova_endpoint const & endpoint, const char * cmd, osc::int32 index)
227 char buffer[128];
228 osc::OutboundPacketStream p(buffer, 128);
229 p << osc::BeginMessage("/done")
230 << cmd
231 << index
232 << osc::EndMessage;
234 instance->send(p.Data(), p.Size(), endpoint);
237 template <typename Functor>
238 struct fn_system_callback:
239 public system_callback
241 fn_system_callback (Functor const & fn):
242 fn_(fn)
245 void run(void)
247 fn_();
250 Functor fn_;
253 template <typename Functor>
254 struct fn_sync_callback:
255 public audio_sync_callback
257 fn_sync_callback (Functor const & fn):
258 fn_(fn)
261 void run(void)
263 fn_();
266 Functor fn_;
269 /** helper class for dispatching real-time and non real-time osc command callbacks
271 * uses template specialization to avoid unnecessary callback rescheduling
273 template <bool realtime>
274 struct cmd_dispatcher
276 template <typename Functor>
277 static void fire_system_callback(Functor const & f)
279 instance->add_system_callback(new fn_system_callback<Functor>(f));
282 template <typename Functor>
283 static void fire_io_callback(Functor const & f)
285 instance->add_io_callback(new fn_system_callback<Functor>(f));
288 template <typename Functor>
289 static void fire_rt_callback(Functor const & f)
291 instance->add_sync_callback(new fn_sync_callback<Functor>(f));
294 static void fire_done_message(nova_endpoint const & endpoint, const char * cmd, osc::int32 index)
296 fire_io_callback(boost::bind(send_done_message, endpoint, cmd, index));
300 template <>
301 struct cmd_dispatcher<false>
303 template <typename Functor>
304 static void fire_system_callback(Functor f)
306 f();
309 template <typename Functor>
310 static void fire_rt_callback(Functor f)
312 f();
315 template <typename Functor>
316 static void fire_io_callback(Functor f)
318 f();
321 static void fire_done_message(nova_endpoint const & endpoint, const char * cmd, osc::int32 index)
323 send_done_message (endpoint, cmd, index);
327 } /* namespace */
329 namespace detail {
330 using nova::log;
332 void fire_notification(movable_array<char> & msg)
334 instance->send_notification(msg.data(), msg.size());
337 void sc_notify_observers::notify(const char * address_pattern, const server_node * node)
339 char buffer[128]; // 128 byte should be enough
340 osc::OutboundPacketStream p(buffer, 128);
341 p << osc::BeginMessage(address_pattern);
342 fill_notification(node, p);
344 movable_array<char> message(p.Size(), p.Data());
345 cmd_dispatcher<true>::fire_io_callback(boost::bind(fire_notification, message));
348 void fire_trigger(int32_t node_id, int32_t trigger_id, float value)
350 char buffer[128]; // 128 byte should be enough
351 osc::OutboundPacketStream p(buffer, 128);
352 p << osc::BeginMessage("/tr") << osc::int32(node_id) << osc::int32(trigger_id) << value
353 << osc::EndMessage;
355 instance->send_notification(p.Data(), p.Size());
358 void sc_notify_observers::send_trigger(int32_t node_id, int32_t trigger_id, float value)
360 cmd_dispatcher<true>::fire_io_callback(boost::bind(fire_trigger, node_id, trigger_id, value));
363 void free_mem_callback(movable_string & cmd,
364 movable_array<float> & values)
367 void fire_node_reply(int32_t node_id, int reply_id, movable_string & cmd,
368 movable_array<float> & values)
370 size_t buffer_size = 1024 + strlen(cmd.c_str()) + values.size()*sizeof(float);
372 char * buffer = (buffer_size < 2048) ? (char*)alloca(buffer_size)
373 : (char*)malloc(buffer_size);
375 try {
376 osc::OutboundPacketStream p(buffer, buffer_size);
377 p << osc::BeginMessage(cmd.c_str()) << osc::int32(node_id) << osc::int32(reply_id);
379 for (int i = 0; i != values.size(); ++i)
380 p << values[i];
382 p << osc::EndMessage;
384 instance->send_notification(p.Data(), p.Size());
386 cmd_dispatcher<true>::fire_rt_callback(boost::bind(free_mem_callback, cmd, values));
387 } catch (...) {
390 if (buffer_size >= 2048)
391 free(buffer);
394 void sc_notify_observers::send_node_reply(int32_t node_id, int reply_id, const char* command_name,
395 int argument_count, const float* values)
397 spin_lock::scoped_lock lock(system_callback_allocator_lock); // called from rt helper threads, so we need to lock the memory pool
398 movable_string cmd(command_name);
399 movable_array<float> value_array(argument_count, values);
401 cmd_dispatcher<true>::fire_io_callback(boost::bind(fire_node_reply, node_id, reply_id, cmd, value_array));
404 void sc_notify_observers::send_notification(const char * data, size_t length)
406 for (size_t i = 0; i != observers.size(); ++i)
407 send_notification(data, length, observers[i]);
410 void sc_notify_observers::send_notification(const char * data, size_t length, nova_endpoint const & endpoint)
412 nova_protocol const & prot = endpoint.protocol();
413 if (prot.family() == AF_INET && prot.type() == SOCK_DGRAM)
415 udp::endpoint ep(endpoint.address(), endpoint.port());
416 send_udp(data, length, ep);
418 else if (prot.family() == AF_INET && prot.type() == SOCK_STREAM)
420 tcp::endpoint ep(endpoint.address(), endpoint.port());
421 send_tcp(data, length, ep);
427 void sc_scheduled_bundles::bundle_node::run(void)
429 typedef osc::ReceivedBundleElement bundle_element;
430 typedef osc::ReceivedBundle received_bundle;
431 typedef osc::ReceivedMessage received_message;
433 bundle_element element(data_);
435 if (element.IsBundle()) {
436 received_bundle bundle(element);
437 instance->handle_bundle<true>(bundle, endpoint_);
438 } else {
439 received_message message(element);
440 instance->handle_message<true>(message, element.Size(), endpoint_);
444 void sc_scheduled_bundles::insert_bundle(time_tag const & timeout, const char * data, size_t length,
445 nova_endpoint const & endpoint)
447 /* allocate chunk from realtime pool */
448 void * chunk = rt_pool.malloc(sizeof(bundle_node) + length+4);
449 bundle_node * node = (bundle_node*)chunk;
450 char * cpy = (char*)chunk + sizeof(bundle_node);
452 memcpy(cpy, data - 4, length+4);
454 new(node) bundle_node(timeout, cpy, endpoint);
456 bundle_q.insert(*node);
459 void sc_scheduled_bundles::execute_bundles(time_tag const & last, time_tag const & now)
461 World * world = &sc_factory->world;
463 while(!bundle_q.empty()) {
464 bundle_node & front = *bundle_q.top();
465 time_tag const & next_timestamp = front.timeout_;
467 if (now < next_timestamp)
468 break;
470 if (last < next_timestamp) {
471 // between last and now
472 time_tag time_since_last = next_timestamp - last;
473 float samples_since_last = time_since_last.to_samples(world->mSampleRate);
475 float sample_offset;
476 float subsample_offset = std::modf(samples_since_last, &sample_offset);
478 world->mSampleOffset = (int)sample_offset;
479 world->mSubsampleOffset = subsample_offset;
480 } else
481 world->mSampleOffset = world->mSubsampleOffset = 0;
483 front.run();
484 bundle_q.erase_and_dispose(bundle_q.top(), &dispose_bundle);
487 world->mSampleOffset = world->mSubsampleOffset = 0;
491 void sc_osc_handler::open_tcp_acceptor(tcp const & protocol, unsigned int port)
493 tcp_acceptor_.open(protocol);
494 tcp_acceptor_.bind(tcp::endpoint(protocol, port));
495 tcp_acceptor_.listen();
498 void sc_osc_handler::open_udp_socket(udp const & protocol, unsigned int port)
500 sc_notify_observers::udp_socket.open(protocol);
501 sc_notify_observers::udp_socket.bind(udp::endpoint(protocol, port));
504 bool sc_osc_handler::open_socket(int family, int type, int protocol, unsigned int port)
506 if (protocol == IPPROTO_TCP)
508 if ( type != SOCK_STREAM )
509 return false;
511 if (family == AF_INET)
512 open_tcp_acceptor(tcp::v4(), port);
513 else if (family == AF_INET6)
514 open_tcp_acceptor(tcp::v6(), port);
515 else
516 return false;
517 return true;
519 else if (protocol == IPPROTO_UDP)
521 if ( type != SOCK_DGRAM )
522 return false;
524 if (family == AF_INET)
525 open_udp_socket(udp::v4(), port);
526 else if (family == AF_INET6)
527 open_udp_socket(udp::v6(), port);
528 else
529 return false;
530 start_receive_udp();
531 return true;
533 return false;
536 void sc_osc_handler::handle_receive_udp(const boost::system::error_code& error,
537 std::size_t bytes_transferred)
539 if (unlikely(error == error::operation_aborted))
540 return; /* we're done */
542 if (error == error::message_size) {
543 overflow_vector.insert(overflow_vector.end(),
544 recv_buffer_.begin(), recv_buffer_.end());
545 return;
548 if (error) {
549 std::cout << "sc_osc_handler received error code " << error << std::endl;
550 start_receive_udp();
551 return;
554 if (overflow_vector.empty())
555 handle_packet_async(recv_buffer_.begin(), bytes_transferred, udp_remote_endpoint_);
556 else {
557 overflow_vector.insert(overflow_vector.end(), recv_buffer_.begin(), recv_buffer_.end());
558 #ifdef __PATHCC__
559 handle_packet_async(&overflow_vector.front(), overflow_vector.size(), udp_remote_endpoint_);
560 #else
561 handle_packet_async(overflow_vector.data(), overflow_vector.size(), udp_remote_endpoint_);
562 #endif
563 overflow_vector.clear();
566 start_receive_udp();
567 return;
570 void sc_osc_handler::tcp_connection::start(sc_osc_handler * self)
572 bool check_password = true;
574 if (check_password) {
575 boost::array<char, 32> password;
576 size_t size;
577 uint32_t msglen;
578 for (unsigned int i=0; i!=4; ++i) {
579 size = socket_.receive(boost::asio::buffer(&msglen, 4));
580 if (size != 4)
581 return;
583 msglen = ntohl(msglen);
584 if (msglen > password.size())
585 return;
587 size = socket_.receive(boost::asio::buffer(password.data(), msglen));
589 bool verified = true;
590 if (size != msglen ||
591 strcmp(password.data(), self->tcp_password_) != 0)
592 verified = false;
594 if (!verified)
595 throw std::runtime_error("cannot verify password");
599 size_t size;
600 uint32_t msglen;
601 size = socket_.receive(boost::asio::buffer(&msglen, 4));
602 if (size != sizeof(uint32_t))
603 throw std::runtime_error("read error");
605 msglen = ntohl(msglen);
607 sized_array<char> recv_vector(msglen + sizeof(uint32_t));
609 std::memcpy((void*)recv_vector.data(), &msglen, sizeof(uint32_t));
610 size_t transfered = socket_.read_some(boost::asio::buffer((void*)(recv_vector.data()+sizeof(uint32_t)),
611 recv_vector.size()-sizeof(uint32_t)));
613 if (transfered != size_t(msglen))
614 throw std::runtime_error("socket read sanity check failure");
616 self->handle_packet_async(recv_vector.data(), recv_vector.size(), socket_.remote_endpoint());
620 void sc_osc_handler::handle_packet_async(const char * data, size_t length,
621 nova_endpoint const & endpoint)
623 received_packet * p = received_packet::alloc_packet(data, length, endpoint);
625 if (dump_osc_packets == 1) {
626 osc_received_packet packet (data, length);
627 cout << "received osc packet " << packet << endl;
630 instance->add_sync_callback(p);
633 time_tag sc_osc_handler::handle_bundle_nrt(const char * data, size_t length)
635 osc_received_packet packet(data, length);
636 if (!packet.IsBundle())
637 throw std::runtime_error("packet needs to be an osc bundle");
639 received_bundle bundle(packet);
640 handle_bundle<false> (bundle, nova_endpoint());
641 return bundle.TimeTag();
645 sc_osc_handler::received_packet *
646 sc_osc_handler::received_packet::alloc_packet(const char * data, size_t length,
647 nova_endpoint const & remote_endpoint)
649 /* received_packet struct and data array are located in one memory chunk */
650 void * chunk = received_packet::allocate(sizeof(received_packet) + length);
651 received_packet * p = (received_packet*)chunk;
652 char * cpy = (char*)(chunk) + sizeof(received_packet);
653 memcpy(cpy, data, length);
655 new(p) received_packet(cpy, length, remote_endpoint);
656 return p;
659 void sc_osc_handler::received_packet::run(void)
661 instance->handle_packet(data, length, endpoint_);
664 void sc_osc_handler::handle_packet(const char * data, std::size_t length, nova_endpoint const & endpoint)
666 osc_received_packet packet(data, length);
667 if (packet.IsBundle())
669 received_bundle bundle(packet);
670 handle_bundle<true> (bundle, endpoint);
672 else
674 received_message message(packet);
675 handle_message<true> (message, packet.Size(), endpoint);
679 template <bool realtime>
680 void sc_osc_handler::handle_bundle(received_bundle const & bundle, nova_endpoint const & endpoint)
682 time_tag bundle_time = bundle.TimeTag();
684 typedef osc::ReceivedBundleElementIterator bundle_iterator;
685 typedef osc::ReceivedBundleElement bundle_element;
687 if (bundle_time <= now) {
688 for (bundle_iterator it = bundle.ElementsBegin(); it != bundle.ElementsEnd(); ++it) {
689 bundle_element const & element = *it;
691 if (element.IsBundle()) {
692 received_bundle inner_bundle(element);
693 handle_bundle<realtime>(inner_bundle, endpoint);
694 } else {
695 received_message message(element);
696 handle_message<realtime>(message, element.Size(), endpoint);
699 } else {
700 for (bundle_iterator it = bundle.ElementsBegin(); it != bundle.ElementsEnd(); ++it) {
701 bundle_element const & element = *it;
702 scheduled_bundles.insert_bundle(bundle_time, element.Contents(), element.Size(), endpoint);
707 template <bool realtime>
708 void sc_osc_handler::handle_message(received_message const & message, size_t msg_size,
709 nova_endpoint const & endpoint)
711 try {
712 if (message.AddressPatternIsUInt32())
713 handle_message_int_address<realtime>(message, msg_size, endpoint);
714 else
715 handle_message_sym_address<realtime>(message, msg_size, endpoint);
716 } catch (std::exception const & e) {
717 log_printf("exception in handle_message: %s\n", e.what());
721 namespace {
723 typedef sc_osc_handler::received_message received_message;
725 void send_udp_message(movable_array<char> data, nova_endpoint const & endpoint)
727 instance->send(data.data(), data.size(), endpoint);
731 int first_arg_as_int(received_message const & message)
733 osc::ReceivedMessageArgumentStream args = message.ArgumentStream();
734 osc::int32 val;
736 args >> val;
738 return val;
741 void quit_perform(nova_endpoint const & endpoint)
743 send_done_message(endpoint, "/quit");
744 instance->terminate();
747 template <bool realtime>
748 void handle_quit(nova_endpoint const & endpoint)
750 instance->quit_received = true;
751 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(quit_perform, endpoint));
754 void notify_perform(bool enable, nova_endpoint const & endpoint)
756 if (enable)
757 instance->add_observer(endpoint);
758 else
759 instance->remove_observer(endpoint);
760 send_done_message(endpoint, "/notify");
763 template <bool realtime>
764 void handle_notify(received_message const & message, nova_endpoint const & endpoint)
766 int enable = first_arg_as_int(message);
767 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(notify_perform, bool(enable), endpoint));
770 void status_perform(nova_endpoint const & endpoint)
772 if (unlikely(instance->quit_received)) // we don't reply once we are about to quit
773 return;
775 char buffer[1024];
776 typedef osc::int32 i32;
778 float peak_load, average_load;
779 instance->cpu_load(peak_load, average_load);
781 osc::OutboundPacketStream p(buffer, 1024);
782 p << osc::BeginMessage("/status.reply")
783 << (i32)1 /* unused */
784 << (i32)sc_factory->ugen_count() /* ugens */
785 << (i32)instance->synth_count() /* synths */
786 << (i32)instance->group_count() /* groups */
787 << (i32)instance->prototype_count() /* synthdefs */
788 << average_load /* average cpu % */
789 << peak_load /* peak cpu % */
790 << instance->get_samplerate() /* nominal samplerate */
791 << instance->get_samplerate() /* actual samplerate */
792 << osc::EndMessage;
794 instance->send(p.Data(), p.Size(), endpoint);
797 template <bool realtime>
798 void handle_status(nova_endpoint const & endpoint)
800 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(status_perform, endpoint));
803 void handle_dumpOSC(received_message const & message)
805 int val = first_arg_as_int(message);
806 val = min (1, val); /* we just support one way of dumping osc messages */
808 instance->dumpOSC(val); /* thread-safe */
811 void sync_perform(osc::int32 id, nova_endpoint const & endpoint)
813 char buffer[128];
814 osc::OutboundPacketStream p(buffer, 128);
815 p << osc::BeginMessage("/synced")
816 << id
817 << osc::EndMessage;
819 instance->send(p.Data(), p.Size(), endpoint);
822 template <bool realtime>
823 void handle_sync(received_message const & message, nova_endpoint const & endpoint)
825 int id = first_arg_as_int(message);
827 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(sync_perform, id, endpoint));
830 void handle_clearSched(void)
832 instance->clear_scheduled_bundles();
835 void handle_error(received_message const & message)
837 int val = first_arg_as_int(message);
839 instance->set_error_posting(val); /* thread-safe */
842 void handle_unhandled_message(received_message const & msg)
844 log_printf("unhandled message: %s\n", msg.AddressPattern());
847 sc_synth * add_synth(const char * name, int node_id, int action, int target_id)
849 if (!check_node_id(node_id))
850 return 0;
852 server_node * target = find_node(target_id);
853 if (target == NULL)
854 return NULL;
856 node_position_constraint pos = make_pair(target, node_position(action));
857 abstract_synth * synth = instance->add_synth(name, node_id, pos);
858 if (!synth)
859 log_printf("Cannot create synth (synthdef: %s, node id: %d)\n", name, node_id);
861 last_generated = node_id;
862 return static_cast<sc_synth*>(synth);
865 /* extract float or int32 as float from argument iterator */
866 inline float extract_float_argument(osc::ReceivedMessageArgumentIterator const & it)
868 if (it->IsFloat())
869 return it->AsFloatUnchecked();
870 if (it->IsInt32())
871 return float(it->AsInt32Unchecked());
872 if (it->IsInt64())
873 return float(it->AsInt64Unchecked());
875 throw std::runtime_error("type cannot be converted to float");
878 inline void verify_argument(osc::ReceivedMessageArgumentIterator const & it,
879 osc::ReceivedMessageArgumentIterator const & end)
881 if (it == end)
882 throw std::runtime_error("unexpected end of argument list");
885 template <bool IsAudio, typename slot_type>
886 static void apply_control_bus_mapping(server_node & node, slot_type slot, int bus_index);
888 template <typename control_id_type>
889 void set_control_array(server_node * node, control_id_type control, osc::ReceivedMessageArgumentIterator & it)
891 size_t array_size = it->ArraySize(); ++it;
893 if (it->IsArrayStart()) {
894 // nested arrays are basically user errors, but we handle them like normal arrays
895 log("Warning in /s_new handler: nested array argument detected");
896 set_control_array<control_id_type>(node, control, it);
897 return;
898 } else {
899 for (size_t i = 0; i != array_size; ++i) {
900 if (it->IsString() || it->IsSymbol()) {
901 char const * name = it->AsStringUnchecked(); ++it;
902 int bus_id;
904 switch (name[0]) {
905 case 'c':
906 bus_id = atoi(name+1);
907 static_cast<sc_synth*>(node)->map_control_bus<false>(control, i, bus_id);
908 break;
910 case 'a':
911 bus_id = atoi(name+1);
912 static_cast<sc_synth*>(node)->map_control_bus<true>(control, i, bus_id);
913 break;
915 default:
916 throw runtime_error("invalid name for control mapping");
918 } else {
919 float value = extract_float_argument(it++);
920 node->set_control_array_element(control, i, value);
925 if (!it->IsArrayEnd())
926 throw runtime_error("missing array end tag");
927 ++it; // skip array end
930 template <typename ControlSpecifier>
931 void set_control(server_node * node, ControlSpecifier const & control, osc::ReceivedMessageArgumentIterator & it)
933 if (it->IsArrayStart())
934 set_control_array(node, control, it);
935 else if (it->IsString() || it->IsSymbol()) {
936 char const * name = it->AsStringUnchecked(); ++it;
937 int bus_id;
939 switch (name[0]) {
940 case 'c':
941 bus_id = atoi(name+1);
942 apply_control_bus_mapping<false>(*node, control, bus_id);
943 break;
945 case 'a':
946 bus_id = atoi(name+1);
947 apply_control_bus_mapping<true>(*node, control, bus_id);
948 break;
950 default:
951 throw runtime_error("invalid name for control mapping");
954 } else {
955 float value = extract_float_argument(it++);
956 node->set(control, value);
960 /* set control values of node from string/float or int/float pair */
961 void set_control(server_node * node, osc::ReceivedMessageArgumentIterator & it, osc::ReceivedMessageArgumentIterator end)
963 if (it->IsInt32()) {
964 osc::int32 index = it->AsInt32Unchecked(); ++it;
965 if (it == end) return; // sclang sometimes uses an integer instead of an empty argument list
966 set_control(node, index, it);
967 } else if (it->IsString()) {
968 const char * str = it->AsStringUnchecked(); ++it;
969 set_control(node, str, it);
970 } else
971 throw runtime_error("invalid argument");
974 void handle_s_new(received_message const & msg)
976 osc::ReceivedMessageArgumentIterator args = msg.ArgumentsBegin(), end = msg.ArgumentsEnd();
978 const char * def_name = args->AsString(); ++args;
979 int32_t id = args->AsInt32(); ++args;
981 if (id == -1)
982 id = instance->generate_node_id();
984 int32_t action, target;
986 if (args != end) {
987 action = args->AsInt32(); ++args;
988 } else
989 action = 0;
991 if (args != end) {
992 target = args->AsInt32(); ++args;
993 } else
994 target = 0;
996 sc_synth * synth = add_synth(def_name, id, action, target);
998 if (synth == NULL)
999 return;
1001 try {
1002 while (args != end)
1003 set_control(synth, args, end);
1004 } catch(std::exception & e) {
1005 log_printf("exception in /s_new: %s\n", e.what());
1010 void handle_g_new(received_message const & msg)
1012 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1014 while(!args.Eos()) {
1015 osc::int32 node_id, action, target_id;
1016 args >> node_id >> action >> target_id;
1018 if (node_id == -1)
1019 node_id = instance->generate_node_id();
1020 else if (!check_node_id(node_id))
1021 continue;
1023 server_node * target = find_node(target_id);
1025 if (!target)
1026 continue;
1028 node_position_constraint pos = make_pair(target, node_position(action));
1030 instance->add_group(node_id, pos);
1031 last_generated = node_id;
1035 void handle_g_freeall(received_message const & msg)
1037 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1039 while(!args.Eos())
1041 osc::int32 id;
1042 args >> id;
1044 abstract_group * group = find_group(id);
1045 if (!group)
1046 continue;
1048 bool success = instance->group_free_all(group);
1050 if (!success)
1051 log("/g_freeAll failue\n");
1055 void handle_g_deepFree(received_message const & msg)
1057 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1059 while(!args.Eos())
1061 osc::int32 id;
1062 args >> id;
1064 abstract_group * group = find_group(id);
1065 if (!group)
1066 continue;
1068 bool success = instance->group_free_deep(group);
1070 if (!success)
1071 log("/g_freeDeep failue\n");
1075 void g_query_tree_fill_node(osc::OutboundPacketStream & p, bool flag, server_node const & node)
1077 p << osc::int32(node.id());
1078 if (node.is_synth())
1079 p << -1;
1080 else
1081 p << osc::int32(static_cast<abstract_group const &>(node).child_count());
1083 if (node.is_synth()) {
1084 sc_synth const & scsynth = static_cast<sc_synth const&>(node);
1085 p << scsynth.prototype_name();
1087 if (flag) {
1088 osc::int32 controls = scsynth.mNumControls;
1089 p << controls;
1091 for (int i = 0; i != controls; ++i) {
1092 p << osc::int32(i); /** \todo later we can return symbols */
1094 if (scsynth.mMapControls[i] != (scsynth.mControls+i)) {
1095 /* we use a bus mapping */
1096 int bus = (scsynth.mMapControls[i]) - (scsynth.mNode.mWorld->mControlBus);
1097 char str[10];
1098 sprintf(str, "s%d", bus);
1099 p << str;
1101 else
1102 p << scsynth.mControls[i];
1105 } else {
1106 abstract_group const & group = static_cast<abstract_group const &>(node);
1107 group.apply_on_children(boost::bind(g_query_tree_fill_node, boost::ref(p), flag, _1));
1111 template <bool realtime>
1112 void g_query_tree(int node_id, bool flag, nova_endpoint const & endpoint)
1114 server_node * node = find_node(node_id);
1115 if (!node || node->is_synth())
1116 return;
1118 abstract_group * group = static_cast<abstract_group*>(node);
1120 size_t max_msg_size = 1<<16;
1121 for(;;) {
1122 try {
1123 if (max_msg_size > 1<<22)
1124 return;
1126 sized_array<char, rt_pool_allocator<char> > data(max_msg_size);
1128 osc::OutboundPacketStream p(data.c_array(), max_msg_size);
1129 p << osc::BeginMessage("/g_queryTree.reply")
1130 << (flag ? 1 : 0)
1131 << node_id
1132 << osc::int32(group->child_count());
1134 group->apply_on_children(boost::bind(g_query_tree_fill_node, boost::ref(p), flag, _1));
1135 p << osc::EndMessage;
1137 movable_array<char> message(p.Size(), data.c_array());
1138 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
1139 return;
1141 catch(...)
1143 max_msg_size *= 2; /* if we run out of memory, retry with doubled memory resources */
1148 template <bool realtime>
1149 void handle_g_queryTree(received_message const & msg, nova_endpoint const & endpoint)
1151 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1153 while(!args.Eos())
1155 try {
1156 osc::int32 id, flag;
1157 args >> id >> flag;
1158 g_query_tree<realtime>(id, flag, endpoint);
1160 catch (std::exception & e) {
1161 log_printf("exception in handle_g_queryTree: %s\n", e.what());
1166 typedef std::basic_stringstream <char,
1167 std::char_traits <char>/*,
1168 rt_pool_allocator<char>*/ > rt_string_stream;
1170 void fill_spaces(rt_string_stream & stream, int level)
1172 for (int i = 0; i != level*3; ++i)
1173 stream << ' ';
1176 void g_dump_node(rt_string_stream & stream, server_node & node, bool flag, int level)
1178 using namespace std;
1179 fill_spaces(stream, level);
1181 if (node.is_synth()) {
1182 abstract_synth const & synth = static_cast<abstract_synth const &>(node);
1183 stream << synth.id() << " " << synth.prototype_name() << endl;
1185 if (flag) {
1186 /* dump controls */
1188 } else {
1189 abstract_group & group = static_cast<abstract_group &>(node);
1190 stream << group.id();
1192 if (group.is_parallel())
1193 stream << " parallel group";
1194 else
1195 stream << " group";
1196 stream << endl;
1197 group.apply_on_children(boost::bind(g_dump_node, boost::ref(stream), _1, flag, level + 1));
1201 void g_dump_tree(int id, bool flag)
1203 server_node * node = find_node(id);
1204 if (!node)
1205 return;
1207 // FIXME: can we completely avoid all internal allocations?
1208 rt_string_stream stream;
1209 stream << "NODE TREE Group " << id << std::endl;
1211 g_dump_node(stream, *node, flag, 1);
1212 log(stream.str().c_str(), stream.str().size());
1215 void handle_g_dumpTree(received_message const & msg)
1217 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1219 while(!args.Eos())
1221 try {
1222 osc::int32 id, flag;
1223 args >> id >> flag;
1224 g_dump_tree(id, flag);
1226 catch (std::exception & e) {
1227 log_printf("exception in /g_dumpTree: %s\n", e.what());
1232 void handle_n_free(received_message const & msg)
1234 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1236 while(!args.Eos())
1238 try {
1239 osc::int32 id;
1240 args >> id;
1242 server_node * node = find_node(id);
1243 if (!node)
1244 continue;
1246 instance->free_node(node);
1248 catch (std::exception & e) {
1249 log_printf("exception in /n_free: %s\n", e.what());
1254 /** macro to define an os command handler with a starting node id
1256 * it is mainly intended as decorator to avoid duplicate error handling code
1258 #define HANDLE_N_DECORATOR(cmd, function) \
1259 void handle_n_##cmd(received_message const & msg) \
1261 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); \
1262 osc::int32 id = it->AsInt32(); ++it; \
1264 server_node * node = find_node(id); \
1265 if (!node) \
1266 return; \
1268 try { \
1269 while (it != msg.ArgumentsEnd()) \
1270 function(node, it); \
1271 } catch(std::exception & e) { \
1272 log_printf("Exception during /n_" #cmd "handler: %s\n", e.what());\
1276 void set_control(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1278 if (it->IsInt32()) {
1279 osc::int32 index = it->AsInt32Unchecked(); ++it;
1280 set_control(node, index, it);
1281 } else if (it->IsString()) {
1282 const char * str = it->AsStringUnchecked(); ++it;
1283 set_control(node, str, it);
1284 } else
1285 throw runtime_error("invalid argument");
1289 HANDLE_N_DECORATOR(set, set_control)
1291 void set_control_n(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1293 if (it->IsInt32()) {
1294 osc::int32 index = it->AsInt32Unchecked(); ++it;
1295 osc::int32 count = it->AsInt32(); ++it;
1297 for (int i = 0; i != count; ++i)
1298 node->set(index + i, extract_float_argument(it++));
1300 else if (it->IsString()) {
1301 const char * str = it->AsStringUnchecked(); ++it;
1302 osc::int32 count = it->AsInt32(); ++it;
1304 sized_array<float> values(count);
1305 for (int i = 0; i != count; ++i)
1306 values[i] = extract_float_argument(it++);
1308 node->set_control_array(str, count, values.c_array());
1309 } else
1310 throw runtime_error("invalid argument");
1313 HANDLE_N_DECORATOR(setn, set_control_n)
1315 void fill_control(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1317 if (it->IsInt32()) {
1318 osc::int32 index = it->AsInt32Unchecked(); ++it;
1319 osc::int32 count = it->AsInt32(); ++it;
1320 float value = extract_float_argument(it++);
1322 for (int i = 0; i != count; ++i)
1323 node->set(index + i, value);
1325 else if (it->IsString()) {
1326 const char * str = it->AsStringUnchecked(); ++it;
1327 osc::int32 count = it->AsInt32(); ++it;
1328 float value = extract_float_argument(it++);
1330 sized_array<float> values(count);
1331 for (int i = 0; i != count; ++i)
1332 values[i] = value;
1334 node->set_control_array(str, count, values.c_array());
1335 } else
1336 throw runtime_error("invalid argument");
1339 HANDLE_N_DECORATOR(fill, fill_control)
1341 template <bool IsAudio, typename slot_type>
1342 void apply_control_bus_mapping(server_node & node, slot_type slot, int bus_index)
1344 if (node.is_synth())
1345 static_cast<sc_synth&>(node).map_control_bus<IsAudio>(slot, bus_index);
1346 else
1347 static_cast<abstract_group&>(node).apply_on_children(boost::bind(apply_control_bus_mapping<IsAudio, slot_type>, _1,
1348 slot, bus_index));
1351 template <bool IsAudio, typename slot_type>
1352 void apply_control_busn_mapping(server_node & node, slot_type slot, int bus_index, int count)
1354 if (node.is_synth())
1355 static_cast<sc_synth&>(node).map_control_buses<IsAudio>(slot, bus_index, count);
1356 else
1357 static_cast<abstract_group&>(node).apply_on_children(boost::bind(apply_control_busn_mapping<IsAudio, slot_type>, _1,
1358 slot, bus_index, count));
1361 template <bool IsAudio>
1362 void map_control(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1364 if (it->IsInt32()) {
1365 osc::int32 control_index = it->AsInt32Unchecked(); ++it;
1366 osc::int32 control_bus_index = it->AsInt32(); ++it;
1368 apply_control_bus_mapping<IsAudio>(*node, control_index, control_bus_index);
1370 else if (it->IsString()) {
1371 const char * control_name = it->AsStringUnchecked(); ++it;
1372 osc::int32 control_bus_index = it->AsInt32(); ++it;
1374 apply_control_bus_mapping<IsAudio>(*node, control_name, control_bus_index);
1375 } else
1376 throw runtime_error("invalid argument");
1379 template <bool IsAudio>
1380 void mapn_control(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1382 if (it->IsInt32()) {
1383 osc::int32 control_index = it->AsInt32Unchecked(); ++it;
1384 osc::int32 bus_index = it->AsInt32(); ++it;
1385 osc::int32 count = it->AsInt32(); ++it;
1387 apply_control_busn_mapping<IsAudio>(*node, control_index, bus_index, count);
1389 else if (it->IsString()) {
1390 const char * control_name = it->AsStringUnchecked(); ++it;
1391 osc::int32 bus_index = it->AsInt32(); ++it;
1392 osc::int32 count = it->AsInt32(); ++it;
1394 apply_control_busn_mapping<IsAudio>(*node, control_name, bus_index, count);
1395 } else
1396 throw runtime_error("invalid argument");
1400 HANDLE_N_DECORATOR(map, map_control<false>)
1401 HANDLE_N_DECORATOR(mapa, map_control<true>)
1402 HANDLE_N_DECORATOR(mapn, mapn_control<false>)
1403 HANDLE_N_DECORATOR(mapan, mapn_control<true>)
1405 template <nova::node_position Relation>
1406 void handle_n_before_or_after(received_message const & msg)
1408 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1410 while(!args.Eos()) {
1411 osc::int32 node_a, node_b;
1412 args >> node_a >> node_b;
1414 server_node * a = find_node(node_a);
1415 if (!a) continue;
1417 server_node * b = find_node(node_b);
1418 if (!b) continue;
1420 abstract_group::move_before_or_after<Relation>(a, b);
1426 template <nova::node_position Position>
1427 void handle_g_head_or_tail(received_message const & msg)
1429 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1431 while(!args.Eos()) {
1432 osc::int32 node_id, target_id;
1433 args >> target_id >> node_id;
1435 server_node * node = find_node(node_id);
1436 if (!node) continue;
1438 abstract_group * target_group = find_group(target_id);
1439 if (!target_group) continue;
1441 abstract_group::move_to_head_or_tail<Position>(node, target_group);
1447 void handle_n_query(received_message const & msg, nova_endpoint const & endpoint)
1449 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1451 while(!args.Eos())
1453 osc::int32 node_id;
1454 args >> node_id;
1456 server_node * node = find_node(node_id);
1457 if (!node)
1458 continue;
1460 char buffer[128]; // 128 byte should be enough
1461 osc::OutboundPacketStream p(buffer, 128);
1462 p << osc::BeginMessage("/n_info");
1463 fill_notification(node, p);
1465 movable_array<char> message(p.Size(), p.Data());
1466 cmd_dispatcher<true>::fire_system_callback(boost::bind(send_udp_message, message, endpoint));
1470 void handle_n_order(received_message const & msg)
1472 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1474 osc::int32 action, target_id;
1475 args >> action >> target_id;
1477 server_node * target = find_node(target_id);
1479 if (target == NULL)
1480 return;
1482 abstract_group * target_parent;
1483 if (action == before ||
1484 action == after)
1485 target_parent = target->get_parent();
1486 else {
1487 if (target->is_synth())
1488 throw std::runtime_error("invalid argument for n_order: argument is no synth");
1489 target_parent = static_cast<abstract_group*>(target);
1492 while (!args.Eos())
1494 osc::int32 node_id;
1495 args >> node_id;
1497 server_node * node = find_node(node_id);
1498 if (node == NULL)
1499 continue;
1501 abstract_group * node_parent = node->get_parent();
1503 /** \todo this can be optimized if node_parent == target_parent */
1504 node_parent->remove_child(node);
1505 if (action == before ||
1506 action == after)
1507 target_parent->add_child(node, make_pair(target, node_position(action)));
1508 else
1509 target_parent->add_child(node, node_position(action));
1511 instance->update_dsp_queue();
1515 void handle_n_run(received_message const & msg)
1517 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1519 while(!args.Eos()) {
1520 osc::int32 node_id, run_flag;
1521 args >> node_id >> run_flag;
1523 server_node * node = find_node(node_id);
1524 if(!node)
1525 continue;
1527 if (run_flag)
1528 instance->node_resume(node);
1529 else
1530 instance->node_pause(node);
1534 void enable_tracing(server_node & node)
1536 if (node.is_synth()) {
1537 sc_synth & synth = static_cast<sc_synth&>(node);
1538 synth.enable_tracing();
1539 } else {
1540 abstract_group & group = static_cast<abstract_group&>(node);
1541 group.apply_on_children(enable_tracing);
1545 void handle_n_trace(received_message const & msg)
1547 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1549 while(!args.Eos()) {
1550 osc::int32 node_id;
1551 args >> node_id;
1553 server_node * node = find_node(node_id);
1554 if (!node)
1555 continue;
1557 enable_tracing(*node);
1562 void handle_s_noid(received_message const & msg)
1564 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1566 while(!args.Eos()) {
1567 osc::int32 node_id;
1568 args >> node_id;
1569 instance->synth_reassign_id(node_id);
1573 int32_t get_control_index(sc_synth * s, osc::ReceivedMessageArgumentIterator & it, osc::OutboundPacketStream & p)
1575 int32_t control;
1576 if (it->IsInt32())
1578 control = it->AsInt32Unchecked(); ++it;
1579 p << control;
1581 else if (it->IsString())
1583 const char * control_str = it->AsStringUnchecked(); ++it;
1584 control = s->resolve_slot(control_str);
1585 p << control_str;
1587 else if (it->IsSymbol())
1589 const char * control_str = it->AsSymbolUnchecked(); ++it;
1590 control = s->resolve_slot(control_str);
1591 p << osc::Symbol(control_str);
1593 else
1594 throw std::runtime_error("wrong argument type");
1595 return control;
1598 template <bool realtime>
1599 void handle_s_get(received_message const & msg, size_t msg_size, nova_endpoint const & endpoint)
1601 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
1603 if (!it->IsInt32())
1604 throw std::runtime_error("wrong argument type");
1606 int32_t node_id = it->AsInt32Unchecked(); ++it;
1608 server_node * node = find_node(node_id);
1609 if (!node || !node->is_synth())
1610 throw std::runtime_error("node is not a synth");
1612 sc_synth * s = static_cast<sc_synth*>(node);
1614 size_t alloc_size = msg_size + sizeof(float) * (msg.ArgumentCount()-1) + 128;
1616 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
1618 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
1619 p << osc::BeginMessage("/n_set")
1620 << node_id;
1622 while (it != msg.ArgumentsEnd())
1624 int32_t control = get_control_index(s, it, p);
1625 p << s->get(control);
1627 p << osc::EndMessage;
1629 movable_array<char> message(p.Size(), return_message.c_array());
1630 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
1633 template <bool realtime>
1634 void handle_s_getn(received_message const & msg, size_t msg_size, nova_endpoint const & endpoint)
1636 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
1638 if (!it->IsInt32())
1639 throw std::runtime_error("wrong argument type");
1641 int32_t node_id = it->AsInt32Unchecked(); ++it;
1643 server_node * node = find_node(node_id);
1644 if (!node || !node->is_synth())
1645 throw std::runtime_error("node is not a synth");
1647 sc_synth * s = static_cast<sc_synth*>(node);
1649 /* count argument values */
1650 size_t argument_count = 0;
1651 for (osc::ReceivedMessageArgumentIterator local = it; local != msg.ArgumentsEnd(); ++local)
1653 ++local; /* skip control */
1654 if (local == msg.ArgumentsEnd())
1655 break;
1656 if (!it->IsInt32())
1657 throw std::runtime_error("invalid count");
1658 argument_count += it->AsInt32Unchecked(); ++it;
1661 size_t alloc_size = msg_size + sizeof(float) * (argument_count) + 128;
1663 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
1665 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
1666 p << osc::BeginMessage("/n_setn")
1667 << node_id;
1669 while (it != msg.ArgumentsEnd())
1671 int32_t control = get_control_index(s, it, p);
1673 if (!it->IsInt32())
1674 throw std::runtime_error("integer argument expected");
1676 int32_t control_count = it->AsInt32Unchecked(); ++it;
1677 if (control_count < 0)
1678 break;
1680 for (int i = 0; i != control_count; ++i)
1681 p << s->get(control + i);
1683 p << osc::EndMessage;
1685 movable_array<char> message(p.Size(), return_message.c_array());
1686 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
1690 /** wrapper class for osc completion message
1692 struct completion_message
1694 /** constructor should only be used from the real-time thread */
1695 completion_message(size_t size, const void * data):
1696 size_(size)
1698 if (size) {
1699 data_ = system_callback::allocate(size);
1700 memcpy(data_, data, size);
1704 /** default constructor creates uninitialized object */
1705 completion_message(void):
1706 size_(0)
1709 /** copy constructor has move semantics!!! */
1710 completion_message(completion_message const & rhs)
1712 operator=(rhs);
1715 completion_message& operator=(completion_message const & rhs)
1717 size_ = rhs.size_;
1718 data_ = rhs.data_;
1719 const_cast<completion_message&>(rhs).size_ = 0;
1720 return *this;
1723 ~completion_message(void)
1725 if (size_)
1726 system_callback::deallocate(data_);
1729 /** handle package in the rt thread
1730 * not to be called from the rt thread
1732 void trigger_async(nova_endpoint const & endpoint)
1734 if (size_) {
1735 sc_osc_handler::received_packet * p =
1736 sc_osc_handler::received_packet::alloc_packet((char*)data_, size_, endpoint);
1737 instance->add_sync_callback(p);
1741 /** handle package directly
1742 * only to be called from the rt thread
1744 void handle(nova_endpoint const & endpoint)
1746 if (size_)
1747 instance->handle_packet((char*)data_, size_, endpoint);
1750 size_t size_;
1751 void * data_;
1754 completion_message extract_completion_message(osc::ReceivedMessageArgumentStream & args)
1756 osc::Blob blob(0, 0);
1758 if (!args.Eos()) {
1759 try {
1760 args >> blob;
1762 catch (osc::WrongArgumentTypeException & e)
1766 return completion_message (blob.size, blob.data);
1769 completion_message extract_completion_message(osc::ReceivedMessageArgumentIterator & it)
1771 const void * data = 0;
1772 unsigned long length = 0;
1774 if (it->IsBlob())
1775 it->AsBlobUnchecked(data, length);
1776 ++it;
1777 return completion_message(length, data);
1781 template <bool realtime>
1782 void b_alloc_2_rt(uint32_t index, completion_message & msg, sample * free_buf, nova_endpoint const & endpoint);
1783 void b_alloc_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
1785 template <bool realtime>
1786 void b_alloc_1_nrt(uint32_t index, uint32_t frames, uint32_t channels, completion_message & msg, nova_endpoint const & endpoint)
1788 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
1789 sample * free_buf = sc_factory->get_nrt_mirror_buffer(index);
1790 sc_factory->allocate_buffer(index, frames, channels);
1791 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_alloc_2_rt<realtime>, index, msg, free_buf, endpoint));
1794 template <bool realtime>
1795 void b_alloc_2_rt(uint32_t index, completion_message & msg, sample * free_buf, nova_endpoint const & endpoint)
1797 sc_factory->buffer_sync(index);
1798 msg.handle(endpoint);
1799 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_alloc_3_nrt, index, free_buf, endpoint));
1802 void b_alloc_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
1804 free_aligned(free_buf);
1805 send_done_message(endpoint, "/b_alloc", index);
1808 template <bool realtime>
1809 void handle_b_alloc(received_message const & msg, nova_endpoint const & endpoint)
1811 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1813 osc::int32 index, frames, channels;
1815 args >> index >> frames;
1817 if (!args.Eos())
1818 args >> channels;
1819 else
1820 channels = 1;
1822 completion_message message = extract_completion_message(args);
1824 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_alloc_1_nrt<realtime>, index, frames,
1825 channels, message, endpoint));
1828 template <bool realtime>
1829 void b_free_1_nrt(uint32_t index, completion_message & msg, nova_endpoint const & endpoint);
1830 template <bool realtime>
1831 void b_free_2_rt(uint32_t index, sample * free_buf, completion_message & msg, nova_endpoint const & endpoint);
1832 void b_free_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
1834 template <bool realtime>
1835 void b_free_1_nrt(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
1837 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
1838 sample * free_buf = sc_factory->get_nrt_mirror_buffer(index);
1839 sc_factory->free_buffer(index);
1840 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_free_2_rt<realtime>,
1841 index, free_buf, msg, endpoint));
1844 template <bool realtime>
1845 void b_free_2_rt(uint32_t index, sample * free_buf, completion_message & msg, nova_endpoint const & endpoint)
1847 sc_factory->buffer_sync(index);
1848 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_free_3_nrt, index, free_buf, endpoint));
1849 msg.handle(endpoint);
1852 void b_free_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
1854 free_aligned(free_buf);
1855 send_done_message(endpoint, "/b_free", index);
1859 template <bool realtime>
1860 void handle_b_free(received_message const & msg, nova_endpoint const & endpoint)
1862 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1864 osc::int32 index;
1865 args >> index;
1867 completion_message message = extract_completion_message(args);
1869 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_free_1_nrt<realtime>, index, message, endpoint));
1872 template <bool realtime>
1873 void b_allocRead_2_rt(uint32_t index, completion_message & msg, sample * free_buf, nova_endpoint const & endpoint);
1874 void b_allocRead_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
1876 template <bool realtime>
1877 void b_allocRead_1_nrt(uint32_t index, movable_string & filename, uint32_t start, uint32_t frames, completion_message & msg,
1878 nova_endpoint const & endpoint)
1880 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
1881 sample * free_buf = sc_factory->get_nrt_mirror_buffer(index);
1882 int error = sc_factory->buffer_read_alloc(index, filename.c_str(), start, frames);
1883 if (!error)
1884 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_allocRead_2_rt<realtime>, index, msg, free_buf, endpoint));
1885 else
1886 /* post nice error message */;
1889 template <bool realtime>
1890 void b_allocRead_2_rt(uint32_t index, completion_message & msg, sample * free_buf,
1891 nova_endpoint const & endpoint)
1893 sc_factory->buffer_sync(index);
1894 msg.handle(endpoint);
1895 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_allocRead_3_nrt, index, free_buf, endpoint));
1898 void b_allocRead_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
1900 free_aligned(free_buf);
1901 send_done_message(endpoint, "/b_allocRead", index);
1904 template <bool realtime>
1905 void handle_b_allocRead(received_message const & msg, nova_endpoint const & endpoint)
1907 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1909 osc::int32 index;
1910 const char * filename;
1912 osc::int32 start = 0;
1913 osc::int32 frames = 0;
1915 args >> index >> filename;
1917 if (!args.Eos())
1918 args >> start;
1920 if (!args.Eos())
1921 args >> frames;
1923 completion_message message = extract_completion_message(args);
1925 movable_string fname(filename);
1926 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_allocRead_1_nrt<realtime>, index,
1927 fname, start, frames, message, endpoint));
1930 template <bool realtime>
1931 void b_allocReadChannel_2_rt(uint32_t index, completion_message & msg, sample * free_buf,
1932 nova_endpoint const & endpoint);
1933 void b_allocReadChannel_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
1935 template <bool realtime>
1936 void b_allocReadChannel_1_nrt(uint32_t index, movable_string const & filename, uint32_t start, uint32_t frames,
1937 movable_array<uint32_t> const & channels, completion_message & msg,
1938 nova_endpoint const & endpoint)
1940 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
1941 sample * free_buf = sc_factory->get_nrt_mirror_buffer(index);
1942 int error = sc_factory->buffer_alloc_read_channels(index, filename.c_str(), start, frames,
1943 channels.size(), channels.data());
1944 if (!error)
1945 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_allocReadChannel_2_rt<realtime>,
1946 index, msg, free_buf, endpoint));
1949 template <bool realtime>
1950 void b_allocReadChannel_2_rt(uint32_t index, completion_message & msg, sample * free_buf,
1951 nova_endpoint const & endpoint)
1953 sc_factory->buffer_sync(index);
1954 msg.handle(endpoint);
1955 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_allocReadChannel_3_nrt,
1956 index, free_buf, endpoint));
1959 void b_allocReadChannel_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
1961 free_aligned(free_buf);
1962 send_done_message(endpoint, "/b_allocReadChannel", index);
1966 template <bool realtime>
1967 void handle_b_allocReadChannel(received_message const & msg, nova_endpoint const & endpoint)
1969 osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin();
1971 osc::int32 index = arg->AsInt32(); arg++;
1972 const char * filename = arg->AsString(); arg++;
1974 osc::int32 start = arg->AsInt32(); arg++;
1975 size_t frames = arg->AsInt32(); arg++;
1977 size_t channel_args = msg.ArgumentCount() - 4; /* we already consumed 4 elements */
1979 size_t channel_count = 0;
1980 sized_array<uint, rt_pool_allocator<uint> > channels(channel_args);
1982 for (uint i = 0; i != channel_args - 1; ++i) // sclang fromats the last completion message as int, so we skip the last element
1984 if (arg->IsInt32()) {
1985 channels[i] = arg->AsInt32Unchecked(); arg++;
1986 ++channel_count;
1990 /* we reached the message blob */
1991 completion_message message = extract_completion_message(arg);
1993 movable_array<uint32_t> channel_mapping(channel_count, channels.c_array());
1994 movable_string fname(filename);
1996 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_allocReadChannel_1_nrt<realtime>,
1997 index, fname, start, frames, channel_mapping,
1998 message, endpoint));
2001 const char * b_write = "/b_write";
2003 template <bool realtime>
2004 void b_write_nrt_1(uint32_t index, movable_string const & filename, movable_string const & header_format,
2005 movable_string const & sample_format, uint32_t start, uint32_t frames, bool leave_open,
2006 completion_message & msg, nova_endpoint const & endpoint)
2008 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
2009 sc_factory->buffer_write(index, filename.c_str(), header_format.c_str(), sample_format.c_str(), start, frames, leave_open);
2010 msg.trigger_async(endpoint);
2011 cmd_dispatcher<realtime>::fire_done_message(endpoint, b_write, index);
2014 void fire_b_write_exception(void)
2016 throw std::runtime_error("wrong arguments for /b_allocReadChannel");
2019 template <bool realtime>
2020 void handle_b_write(received_message const & msg, nova_endpoint const & endpoint)
2022 osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin();
2023 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2025 /* required args */
2026 osc::int32 index = arg->AsInt32(); arg++;
2027 const char * filename = arg->AsString(); arg++;
2028 const char * header_format = arg->AsString(); arg++;
2029 const char * sample_format = arg->AsString(); arg++;
2031 /* optional args */
2032 osc::int32 frames = -1;
2033 osc::int32 start = 0;
2034 osc::int32 leave_open = 0;
2036 completion_message message;
2038 if (arg != end) {
2039 if (!arg->IsInt32())
2040 fire_b_write_exception();
2041 frames = arg->AsInt32Unchecked(); arg++;
2043 else
2044 goto fire_callback;
2046 if (arg != end) {
2047 if (!arg->IsInt32())
2048 fire_b_write_exception();
2049 start = arg->AsInt32Unchecked(); arg++;
2051 else
2052 goto fire_callback;
2054 if (arg != end) {
2055 if (!arg->IsInt32())
2056 fire_b_write_exception();
2057 leave_open = arg->AsInt32Unchecked(); arg++;
2059 else
2060 goto fire_callback;
2062 if (arg != end)
2063 message = extract_completion_message(arg);
2065 fire_callback:
2066 movable_string fname(filename);
2067 movable_string header_f(header_format);
2068 movable_string sample_f(sample_format);
2070 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_write_nrt_1<realtime>, index, fname, header_f, sample_f,
2071 start, frames, bool(leave_open), message, endpoint));
2074 template <bool realtime>
2075 void b_read_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint);
2077 template <bool realtime>
2078 void b_read_nrt_1(uint32_t index, movable_string & filename, uint32_t start_file, uint32_t frames,
2079 uint32_t start_buffer, bool leave_open, completion_message & msg, nova_endpoint const & endpoint)
2081 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
2082 sc_factory->buffer_read(index, filename.c_str(), start_file, frames, start_buffer, leave_open);
2083 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_read_rt_2<realtime>, index, msg, endpoint));
2086 const char * b_read = "/b_read";
2087 template <bool realtime>
2088 void b_read_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2090 sc_factory->buffer_sync(index);
2091 msg.handle(endpoint);
2092 cmd_dispatcher<realtime>::fire_done_message(endpoint, b_read, index);
2095 void fire_b_read_exception(void)
2097 throw std::runtime_error("wrong arguments for /b_read");
2100 template <bool realtime>
2101 void handle_b_read(received_message const & msg, nova_endpoint const & endpoint)
2103 osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin();
2104 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2106 /* required args */
2107 osc::int32 index = arg->AsInt32(); arg++;
2108 const char * filename = arg->AsString(); arg++;
2110 /* optional args */
2111 osc::int32 start_file = 0;
2112 osc::int32 frames = -1;
2113 osc::int32 start_buffer = 0;
2114 osc::int32 leave_open = 0;
2116 completion_message message;
2118 if (arg != end) {
2119 if (!arg->IsInt32())
2120 fire_b_read_exception();
2121 start_file = arg->AsInt32Unchecked(); arg++;
2123 else
2124 goto fire_callback;
2126 if (arg != end) {
2127 if (!arg->IsInt32())
2128 fire_b_read_exception();
2129 frames = arg->AsInt32Unchecked(); arg++;
2131 else
2132 goto fire_callback;
2134 if (arg != end) {
2135 if (!arg->IsInt32())
2136 fire_b_read_exception();
2137 start_buffer = arg->AsInt32Unchecked(); arg++;
2139 else
2140 goto fire_callback;
2142 if (arg != end) {
2143 if (!arg->IsInt32())
2144 fire_b_read_exception();
2145 leave_open = arg->AsInt32Unchecked(); arg++;
2147 else
2148 goto fire_callback;
2150 if (arg != end)
2151 message = extract_completion_message(arg);
2153 fire_callback:
2154 movable_string fname(filename);
2156 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_read_nrt_1<realtime>, index, fname,
2157 start_file, frames, start_buffer,
2158 bool(leave_open), message, endpoint));
2162 template <bool realtime>
2163 void b_readChannel_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint);
2165 template <bool realtime>
2166 void b_readChannel_nrt_1(uint32_t index, movable_string & filename, uint32_t start_file, uint32_t frames,
2167 uint32_t start_buffer, bool leave_open, movable_array<uint32_t> & channel_map,
2168 completion_message & msg, nova_endpoint const & endpoint)
2170 sc_factory->buffer_read_channel(index, filename.c_str(), start_file, frames, start_buffer, leave_open,
2171 channel_map.size(), channel_map.data());
2172 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_readChannel_rt_2<realtime>, index, msg, endpoint));
2175 const char * b_readChannel = "/b_readChannel";
2176 template <bool realtime>
2177 void b_readChannel_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2179 sc_factory->buffer_sync(index);
2180 msg.handle(endpoint);
2181 cmd_dispatcher<realtime>::fire_done_message(endpoint, b_readChannel, index);
2184 void fire_b_readChannel_exception(void)
2186 throw std::runtime_error("wrong arguments for /b_readChannel");
2189 template <bool realtime>
2190 void handle_b_readChannel(received_message const & msg, nova_endpoint const & endpoint)
2192 osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin();
2193 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2195 /* required args */
2196 osc::int32 index = arg->AsInt32(); arg++;
2197 const char * filename = arg->AsString(); arg++;
2199 /* optional args */
2200 osc::int32 start_file = 0;
2201 osc::int32 frames = -1;
2202 osc::int32 start_buffer = 0;
2203 osc::int32 leave_open = 0;
2205 sized_array<uint32_t, rt_pool_allocator<uint32_t> > channel_mapping(int32_t(msg.ArgumentCount())); /* larger than required */
2206 uint32_t channel_count = 0;
2208 completion_message message;
2210 if (arg != end) {
2211 if (!arg->IsInt32())
2212 fire_b_read_exception();
2213 start_file = arg->AsInt32Unchecked(); arg++;
2215 else
2216 goto fire_callback;
2218 if (arg != end) {
2219 if (!arg->IsInt32())
2220 fire_b_read_exception();
2221 frames = arg->AsInt32Unchecked(); arg++;
2223 else
2224 goto fire_callback;
2226 if (arg != end) {
2227 if (!arg->IsInt32())
2228 fire_b_write_exception();
2229 start_buffer = arg->AsInt32Unchecked(); arg++;
2231 else
2232 goto fire_callback;
2234 if (arg != end) {
2235 if (!arg->IsInt32())
2236 fire_b_write_exception();
2237 leave_open = arg->AsInt32Unchecked(); arg++;
2239 else
2240 goto fire_callback;
2242 while (arg != end)
2244 if (arg->IsBlob()) {
2245 message = extract_completion_message(arg);
2246 goto fire_callback;
2248 else if (arg->IsInt32()) {
2249 channel_mapping[channel_count] = arg->AsInt32Unchecked();
2250 ++arg;
2252 else
2253 fire_b_readChannel_exception();
2256 fire_callback:
2257 movable_string fname(filename);
2258 movable_array<uint32_t> channel_map(channel_count, channel_mapping.c_array());
2260 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_readChannel_nrt_1<realtime>, index, fname,
2261 start_file, frames, start_buffer,
2262 bool(leave_open), channel_map, message, endpoint));
2266 template <bool realtime>
2267 void b_zero_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint);
2269 template <bool realtime>
2270 void b_zero_nrt_1(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2272 sc_factory->buffer_zero(index);
2273 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_zero_rt_2<realtime>, index, msg, endpoint));
2276 const char * b_zero = "/b_zero";
2277 template <bool realtime>
2278 void b_zero_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2280 sc_factory->increment_write_updates(index);
2281 msg.handle(endpoint);
2282 cmd_dispatcher<realtime>::fire_done_message(endpoint, b_zero, index);
2285 template <bool realtime>
2286 void handle_b_zero(received_message const & msg, nova_endpoint const & endpoint)
2288 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2290 osc::int32 index;
2291 args >> index;
2292 completion_message message = extract_completion_message(args);
2294 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_zero_nrt_1<realtime>, index, message, endpoint));
2297 void handle_b_set(received_message const & msg)
2299 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2300 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2301 verify_argument(it, end);
2302 osc::int32 buffer_index = it->AsInt32(); ++it;
2304 buffer_wrapper::sample_t * data = sc_factory->get_buffer(buffer_index);
2306 while (it != end) {
2307 osc::int32 index = it->AsInt32(); ++it;
2308 float value = extract_float_argument(it++);
2310 data[index] = value;
2314 void handle_b_setn(received_message const & msg)
2316 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2317 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2318 verify_argument(it, end);
2319 osc::int32 buffer_index = it->AsInt32(); ++it;
2321 buffer_wrapper::sample_t * data = sc_factory->get_buffer(buffer_index);
2323 while (it != end) {
2324 osc::int32 index = it->AsInt32(); ++it;
2325 verify_argument(it, end);
2326 osc::int32 samples = it->AsInt32(); ++it;
2328 for (int i = 0; i != samples; ++i) {
2329 verify_argument(it, end);
2330 float value = extract_float_argument(it++);
2331 data[index+i] = value;
2336 void handle_b_fill(received_message const & msg)
2338 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2339 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2340 verify_argument(it, end);
2341 osc::int32 buffer_index = it->AsInt32(); ++it;
2343 buffer_wrapper::sample_t * data = sc_factory->get_buffer(buffer_index);
2345 while (it != end) {
2346 osc::int32 index = it->AsInt32(); ++it;
2347 verify_argument(it, end);
2348 osc::int32 samples = it->AsInt32(); ++it;
2349 verify_argument(it, end);
2350 float value = extract_float_argument(it++);
2352 for (int i = 0; i != samples; ++i)
2353 data[index] = value;
2357 template <bool realtime>
2358 void handle_b_query(received_message const & msg, nova_endpoint const & endpoint)
2360 const size_t elem_size = 3*sizeof(int) * sizeof(float);
2362 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2363 size_t arg_count = msg.ArgumentCount();
2365 size_t size = elem_size * arg_count + 128; /* should be more than required */
2366 sized_array<char, rt_pool_allocator<char> > data(size);
2368 osc::OutboundPacketStream p(data.c_array(), size);
2369 p << osc::BeginMessage("/b_info");
2371 while (!args.Eos()) {
2372 osc::int32 buffer_index;
2373 args >> buffer_index;
2375 SndBuf * buf = sc_factory->get_buffer_struct(buffer_index);
2377 p << buffer_index
2378 << osc::int32(buf->frames)
2379 << osc::int32(buf->channels)
2380 << float (buf->samplerate);
2383 p << osc::EndMessage;
2385 movable_array<char> message(p.Size(), data.c_array());
2387 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2390 template <bool realtime>
2391 void b_close_rt_2(completion_message & msg, nova_endpoint const & endpoint);
2393 template <bool realtime>
2394 void b_close_nrt_1(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2396 sc_factory->buffer_close(index);
2397 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_close_rt_2<realtime>, msg, endpoint));
2400 template <bool realtime>
2401 void b_close_rt_2(completion_message & msg, nova_endpoint const & endpoint)
2405 template <bool realtime>
2406 void handle_b_close(received_message const & msg, nova_endpoint const & endpoint)
2408 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2409 osc::int32 index;
2410 args >> index;
2412 completion_message message = extract_completion_message(args);
2413 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_close_nrt_1<realtime>, index, message, endpoint));
2416 template <bool realtime>
2417 void handle_b_get(received_message const & msg, nova_endpoint const & endpoint)
2419 const size_t elem_size = sizeof(int) * sizeof(float);
2420 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2421 const size_t index_count = msg.ArgumentCount() - 1;
2422 const size_t alloc_size = index_count * elem_size + 128; /* hopefully enough */
2424 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
2426 osc::int32 buffer_index;
2427 args >> buffer_index;
2429 const SndBuf * buf = sc_factory->get_buffer_struct(buffer_index);
2430 const sample * data = buf->data;
2431 const int max_sample = buf->frames * buf->channels;
2433 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
2434 p << osc::BeginMessage("/b_set")
2435 << buffer_index;
2437 while (!args.Eos())
2439 osc::int32 index;
2440 args >> index;
2441 p << index;
2443 if (index < max_sample)
2444 p << data[index];
2445 else
2446 p << 0.f;
2449 p << osc::EndMessage;
2451 movable_array<char> message(p.Size(), return_message.c_array());
2452 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2455 template<typename Alloc>
2456 struct getn_data
2458 getn_data(int start, int count, const float * data):
2459 start_index_(start), data_(count)
2461 data_.reserve(count);
2462 for (int i = 0; i != count; ++i)
2463 data_[i] = data[i];
2466 int start_index_;
2467 std::vector<float, Alloc> data_;
2470 template <bool realtime>
2471 void handle_b_getn(received_message const & msg, nova_endpoint const & endpoint)
2473 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2475 typedef getn_data<rt_pool_allocator<float> > getn_data;
2476 std::vector<getn_data, rt_pool_allocator<getn_data> > return_data;
2478 osc::int32 buffer_index;
2479 args >> buffer_index;
2481 const SndBuf * buf = sc_factory->get_buffer_struct(buffer_index);
2482 const sample * data = buf->data;
2483 const int max_sample = buf->frames * buf->channels;
2485 while (!args.Eos())
2487 osc::int32 index, sample_count;
2488 args >> index >> sample_count;
2490 if (index + sample_count <= max_sample)
2491 return_data.push_back(getn_data(index, sample_count, data + index));
2494 size_t alloc_size = 128;
2495 for (size_t i = 0; i != return_data.size(); ++i)
2496 alloc_size += return_data[i].data_.size() * (sizeof(float) + sizeof(int)) + 2*sizeof(int);
2498 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
2500 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
2501 p << osc::BeginMessage("/b_setn")
2502 << buffer_index;
2504 for (size_t i = 0; i != return_data.size(); ++i) {
2505 p << osc::int32(return_data[i].start_index_)
2506 << osc::int32(return_data[i].data_.size());
2508 for (size_t j = 0; j != return_data[i].data_.size(); ++j)
2509 p << return_data[i].data_[j];
2512 p << osc::EndMessage;
2514 movable_array<char> message(p.Size(), return_message.c_array());
2515 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2519 template <bool realtime>
2520 void b_gen_rt_2(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
2521 void b_gen_nrt_3(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
2523 template <bool realtime>
2524 void b_gen_nrt_1(movable_array<char> & message, nova_endpoint const & endpoint)
2526 sc_msg_iter msg(message.size(), (char*)message.data());
2528 int index = msg.geti();
2529 const char * generator = (const char*)msg.gets4();
2530 if (!generator)
2531 return;
2533 sample * free_buf = sc_factory->buffer_generate(index, generator, msg);
2534 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_gen_rt_2<realtime>, index, free_buf, endpoint));
2537 template <bool realtime>
2538 void b_gen_rt_2(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
2540 sc_factory->buffer_sync(index);
2541 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_gen_nrt_3, index, free_buf, endpoint));
2544 void b_gen_nrt_3(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
2546 free_aligned(free_buf);
2547 send_done_message(endpoint, "/b_gen", index);
2550 template <bool realtime>
2551 void handle_b_gen(received_message const & msg, size_t msg_size, nova_endpoint const & endpoint)
2553 movable_array<char> cmd (msg_size, msg.TypeTags()-1);
2554 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_gen_nrt_1<realtime>, cmd, endpoint));
2558 void handle_c_set(received_message const & msg)
2560 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2562 while (it != msg.ArgumentsEnd()) {
2563 osc::int32 bus_index = it->AsInt32(); ++it;
2564 float value = extract_float_argument(it++);
2566 sc_factory->controlbus_set(bus_index, value);
2570 void handle_c_setn(received_message const & msg)
2572 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2574 while (it != msg.ArgumentsEnd()) {
2575 osc::int32 bus_index, bus_count;
2576 bus_index = it->AsInt32(); ++it;
2577 bus_count = it->AsInt32(); ++it;
2579 for (int i = 0; i != bus_count; ++i) {
2580 float value = extract_float_argument(it++);
2581 sc_factory->controlbus_set(bus_index + i, value);
2586 void handle_c_fill(received_message const & msg)
2588 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2590 while (it != msg.ArgumentsEnd()) {
2591 osc::int32 bus_index, bus_count;
2592 bus_index = it->AsInt32(); ++it;
2593 bus_count = it->AsInt32(); ++it;
2594 float value = extract_float_argument(it++);
2595 sc_factory->controlbus_fill(bus_index, bus_count, value);
2599 template <bool realtime>
2600 void handle_c_get(received_message const & msg,
2601 nova_endpoint const & endpoint)
2603 const size_t elem_size = sizeof(int) + sizeof(float);
2604 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2605 const size_t index_count = msg.ArgumentCount();
2606 const size_t alloc_size = index_count * elem_size + 128; /* hopefully enough */
2608 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
2610 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
2611 p << osc::BeginMessage("/c_set");
2613 while (!args.Eos())
2615 osc::int32 index;
2616 args >> index;
2618 p << index << sc_factory->controlbus_get(index);
2621 p << osc::EndMessage;
2623 movable_array<char> message(p.Size(), return_message.c_array());
2624 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2627 template <bool realtime>
2628 void handle_c_getn(received_message const & msg, nova_endpoint const & endpoint)
2630 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2632 /* we pessimize, but better to allocate too much than too little */
2633 const size_t alloc_size = 128 +
2634 (2 * sizeof(int) + 128*sizeof(float)) * msg.ArgumentCount();
2636 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
2638 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
2639 p << osc::BeginMessage("/c_setn");
2641 while (!args.Eos())
2643 osc::int32 bus_index, bus_count;
2644 args >> bus_index >> bus_count;
2645 p << bus_index << bus_count;
2647 for (int i = 0; i != bus_count; ++i) {
2648 float value = sc_factory->controlbus_get(bus_index + i);
2649 p << value;
2653 p << osc::EndMessage;
2655 movable_array<char> message(p.Size(), return_message.c_array());
2656 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2659 #ifdef BOOST_HAS_RVALUE_REFS
2660 std::pair<sc_synth_prototype_ptr *, size_t> wrap_synthdefs(std::vector<sc_synthdef> && defs)
2662 std::vector<sc_synthdef> synthdefs(std::move(defs));
2663 size_t count = synthdefs.size();
2664 sc_synth_prototype_ptr * prototypes = new sc_synth_prototype_ptr [count];
2666 for (size_t i = 0; i != count; ++i)
2667 prototypes[i].reset(new sc_synth_prototype(std::move(synthdefs[i])));
2668 return std::make_pair(prototypes, count);
2670 #endif
2671 std::pair<sc_synth_prototype_ptr *, size_t> wrap_synthdefs(std::vector<sc_synthdef> const & defs)
2673 size_t count = defs.size();
2674 sc_synth_prototype_ptr * prototypes = new sc_synth_prototype_ptr [count];
2676 for (size_t i = 0; i != count; ++i)
2677 prototypes[i].reset(new sc_synth_prototype(defs[i]));
2678 return std::make_pair(prototypes, count);
2681 template <bool realtime>
2682 void d_recv_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2683 nova_endpoint const & endpoint);
2684 void d_recv_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint);
2686 template <bool realtime>
2687 void d_recv_nrt(movable_array<char> & def, completion_message & msg, nova_endpoint const & endpoint)
2689 size_t count;
2690 sc_synth_prototype_ptr * prototypes;
2691 std::vector<sc_synthdef> synthdefs (read_synthdefs(def.data()));
2693 #ifdef BOOST_HAS_RVALUE_REFS
2694 boost::tie(prototypes, count) = wrap_synthdefs(std::move(synthdefs));
2695 #else
2696 boost::tie(prototypes, count) = wrap_synthdefs(synthdefs);
2697 #endif
2699 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(d_recv_rt2<realtime>, prototypes, count, msg, endpoint));
2702 template <bool realtime>
2703 void d_recv_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2704 nova_endpoint const & endpoint)
2706 std::for_each(prototypes, prototypes + prototype_count,
2707 boost::bind(&synth_factory::register_prototype, instance, _1));
2709 msg.handle(endpoint);
2710 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_recv_nrt3, prototypes, endpoint));
2713 void d_recv_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint)
2715 delete[] prototypes;
2716 send_done_message(endpoint, "/d_recv");
2719 template <bool realtime>
2720 void handle_d_recv(received_message const & msg,
2721 nova_endpoint const & endpoint)
2723 const void * synthdef_data;
2724 unsigned long synthdef_size;
2726 osc::ReceivedMessageArgumentIterator args = msg.ArgumentsBegin();
2728 args->AsBlob(synthdef_data, synthdef_size); ++args;
2729 movable_array<char> def(synthdef_size, (const char*)synthdef_data);
2730 completion_message message = extract_completion_message(args);
2732 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_recv_nrt<realtime>, def, message, endpoint));
2735 template <bool realtime>
2736 void d_load_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2737 nova_endpoint const & endpoint);
2738 void d_load_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint);
2740 template <bool realtime>
2741 void d_load_nrt(movable_string & path, completion_message & msg, nova_endpoint const & endpoint)
2743 size_t count;
2744 sc_synth_prototype_ptr * prototypes;
2745 /* todo: we need to implment some file name pattern matching */
2746 boost::tie(prototypes, count) = wrap_synthdefs(sc_read_synthdefs_file(path.c_str()));
2748 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(d_load_rt2<realtime>, prototypes, count, msg, endpoint));
2751 template <bool realtime>
2752 void d_load_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2753 nova_endpoint const & endpoint)
2755 std::for_each(prototypes, prototypes + prototype_count,
2756 boost::bind(&synth_factory::register_prototype, instance, _1));
2758 msg.handle(endpoint);
2759 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_load_nrt3, prototypes, endpoint));
2762 void d_load_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint)
2764 delete[] prototypes;
2765 send_done_message(endpoint, "/d_load");
2769 template <bool realtime>
2770 void handle_d_load(received_message const & msg,
2771 nova_endpoint const & endpoint)
2773 osc::ReceivedMessageArgumentIterator args = msg.ArgumentsBegin();
2774 const char * path = args->AsString(); args++;
2775 completion_message message = extract_completion_message(args);
2777 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_load_nrt<realtime>, movable_string(path),
2778 message, endpoint));
2782 template <bool realtime>
2783 void d_loadDir_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2784 nova_endpoint const & endpoint);
2785 void d_loadDir_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint);
2787 template <bool realtime>
2788 void d_loadDir_nrt1(movable_string & path, completion_message & msg, nova_endpoint const & endpoint)
2790 size_t count;
2791 sc_synth_prototype_ptr * prototypes;
2792 boost::tie(prototypes, count) = wrap_synthdefs(sc_read_synthdefs_dir(path.c_str()));
2794 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(d_loadDir_rt2<realtime>, prototypes, count, msg, endpoint));
2797 template <bool realtime>
2798 void d_loadDir_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2799 nova_endpoint const & endpoint)
2801 std::for_each(prototypes, prototypes + prototype_count,
2802 boost::bind(&synth_factory::register_prototype, instance, _1));
2804 msg.handle(endpoint);
2805 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_loadDir_nrt3, prototypes, endpoint));
2808 void d_loadDir_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint)
2810 delete[] prototypes;
2811 send_done_message(endpoint, "/d_loadDir");
2814 template <bool realtime>
2815 void handle_d_loadDir(received_message const & msg,
2816 nova_endpoint const & endpoint)
2818 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2819 const char * path;
2821 args >> path;
2822 completion_message message = extract_completion_message(args);
2824 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_loadDir_nrt1<realtime>,
2825 movable_string(path), message, endpoint));
2829 void handle_d_free(received_message const & msg)
2831 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2833 while(!args.Eos())
2835 const char * defname;
2836 args >> defname;
2838 instance->remove_prototype(defname);
2842 void insert_parallel_group(int node_id, int action, int target_id)
2844 if (node_id == -1)
2845 node_id = instance->generate_node_id();
2846 else if (!check_node_id(node_id))
2847 return;
2849 server_node * target = find_node(target_id);
2850 if(!target)
2851 return;
2853 node_position_constraint pos = make_pair(target, node_position(action));
2855 instance->add_parallel_group(node_id, pos);
2856 last_generated = node_id;
2859 void handle_p_new(received_message const & msg)
2861 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2863 while(!args.Eos())
2865 osc::int32 id, action, target;
2866 args >> id >> action >> target;
2868 insert_parallel_group(id, action, target);
2872 void handle_u_cmd(received_message const & msg, int size)
2874 sc_msg_iter args(size, msg.AddressPattern());
2876 int node_id = args.geti();
2878 server_node * target_synth = find_node(node_id);
2880 if (target_synth == NULL || target_synth->is_group())
2881 return;
2883 sc_synth * synth = static_cast<sc_synth*>(target_synth);
2885 int ugen_index = args.geti();
2886 const char * cmd_name = args.gets();
2888 synth->apply_unit_cmd(cmd_name, ugen_index, &args);
2891 void handle_cmd(received_message const & msg, int size, nova_endpoint const & endpoint, int skip_bytes)
2893 sc_msg_iter args(size, msg.AddressPattern() + skip_bytes);
2895 const char * cmd = args.gets();
2897 sc_factory->run_cmd_plugin(&sc_factory->world, cmd, &args, const_cast<nova_endpoint*>(&endpoint));
2900 } /* namespace */
2902 template <bool realtime>
2903 void sc_osc_handler::handle_message_int_address(received_message const & message,
2904 size_t msg_size, nova_endpoint const & endpoint)
2906 uint32_t address = message.AddressPatternAsUInt32();
2908 switch (address)
2910 case cmd_quit:
2911 handle_quit<realtime>(endpoint);
2912 break;
2914 case cmd_s_new:
2915 handle_s_new(message);
2916 break;
2918 case cmd_s_noid:
2919 handle_s_noid(message);
2920 break;
2922 case cmd_s_get:
2923 handle_s_get<realtime>(message, msg_size, endpoint);
2924 break;
2926 case cmd_s_getn:
2927 handle_s_getn<realtime>(message, msg_size, endpoint);
2928 break;
2930 case cmd_notify:
2931 handle_notify<realtime>(message, endpoint);
2932 break;
2934 case cmd_status:
2935 handle_status<realtime>(endpoint);
2936 break;
2938 case cmd_dumpOSC:
2939 handle_dumpOSC(message);
2940 break;
2942 case cmd_sync:
2943 handle_sync<realtime>(message, endpoint);
2944 break;
2946 case cmd_clearSched:
2947 handle_clearSched();
2948 break;
2950 case cmd_error:
2951 handle_error(message);
2952 break;
2954 case cmd_g_new:
2955 handle_g_new(message);
2956 break;
2958 case cmd_g_head:
2959 handle_g_head_or_tail<head>(message);
2960 break;
2962 case cmd_g_tail:
2963 handle_g_head_or_tail<tail>(message);
2964 break;
2966 case cmd_g_freeAll:
2967 handle_g_freeall(message);
2968 break;
2970 case cmd_g_deepFree:
2971 handle_g_deepFree(message);
2972 break;
2974 case cmd_g_queryTree:
2975 handle_g_queryTree<realtime>(message, endpoint);
2976 break;
2978 case cmd_g_dumpTree:
2979 handle_g_dumpTree(message);
2980 break;
2982 case cmd_n_free:
2983 handle_n_free(message);
2984 break;
2986 case cmd_n_set:
2987 handle_n_set(message);
2988 break;
2990 case cmd_n_setn:
2991 handle_n_setn(message);
2992 break;
2994 case cmd_n_fill:
2995 handle_n_fill(message);
2996 break;
2998 case cmd_n_map:
2999 handle_n_map(message);
3000 break;
3002 case cmd_n_mapn:
3003 handle_n_mapn(message);
3004 break;
3006 case cmd_n_mapa:
3007 handle_n_mapa(message);
3008 break;
3010 case cmd_n_mapan:
3011 handle_n_mapan(message);
3012 break;
3014 case cmd_n_query:
3015 handle_n_query(message, endpoint);
3016 break;
3018 case cmd_n_order:
3019 handle_n_order(message);
3020 break;
3022 case cmd_n_run:
3023 handle_n_run(message);
3024 break;
3026 case cmd_n_before:
3027 handle_n_before_or_after<before>(message);
3028 break;
3030 case cmd_n_after:
3031 handle_n_before_or_after<after>(message);
3032 break;
3034 case cmd_n_trace:
3035 handle_n_trace(message);
3036 break;
3038 case cmd_b_alloc:
3039 handle_b_alloc<realtime>(message, endpoint);
3040 break;
3042 case cmd_u_cmd:
3043 handle_u_cmd(message, msg_size);
3044 break;
3046 case cmd_b_free:
3047 handle_b_free<realtime>(message, endpoint);
3048 break;
3050 case cmd_b_allocRead:
3051 handle_b_allocRead<realtime>(message, endpoint);
3052 break;
3054 case cmd_b_allocReadChannel:
3055 handle_b_allocReadChannel<realtime>(message, endpoint);
3056 break;
3058 case cmd_b_read:
3059 handle_b_read<realtime>(message, endpoint);
3060 break;
3062 case cmd_b_readChannel:
3063 handle_b_readChannel<realtime>(message, endpoint);
3064 break;
3066 case cmd_b_write:
3067 handle_b_write<realtime>(message, endpoint);
3068 break;
3070 case cmd_b_zero:
3071 handle_b_zero<realtime>(message, endpoint);
3072 break;
3074 case cmd_b_set:
3075 handle_b_set(message);
3076 break;
3078 case cmd_b_setn:
3079 handle_b_setn(message);
3080 break;
3082 case cmd_b_fill:
3083 handle_b_fill(message);
3084 break;
3086 case cmd_b_query:
3087 handle_b_query<realtime>(message, endpoint);
3088 break;
3090 case cmd_b_get:
3091 handle_b_get<realtime>(message, endpoint);
3092 break;
3094 case cmd_b_getn:
3095 handle_b_getn<realtime>(message, endpoint);
3096 break;
3098 case cmd_b_gen:
3099 handle_b_gen<realtime>(message, msg_size, endpoint);
3100 break;
3102 case cmd_b_close:
3103 handle_b_close<realtime>(message, endpoint);
3104 break;
3106 case cmd_c_set:
3107 handle_c_set(message);
3108 break;
3110 case cmd_c_setn:
3111 handle_c_setn(message);
3112 break;
3114 case cmd_c_fill:
3115 handle_c_fill(message);
3116 break;
3118 case cmd_c_get:
3119 handle_c_get<realtime>(message, endpoint);
3120 break;
3122 case cmd_c_getn:
3123 handle_c_getn<realtime>(message, endpoint);
3124 break;
3126 case cmd_d_recv:
3127 handle_d_recv<realtime>(message, endpoint);
3128 break;
3130 case cmd_d_load:
3131 handle_d_load<realtime>(message, endpoint);
3132 break;
3134 case cmd_d_loadDir:
3135 handle_d_loadDir<realtime>(message, endpoint);
3136 break;
3138 case cmd_d_free:
3139 handle_d_free(message);
3140 break;
3142 case cmd_p_new:
3143 handle_p_new(message);
3144 break;
3146 case cmd_cmd:
3147 handle_cmd(message, msg_size, endpoint, 4);
3148 break;
3150 default:
3151 handle_unhandled_message(message);
3155 namespace
3158 template <bool realtime>
3159 void dispatch_group_commands(const char * address, received_message const & message,
3160 nova_endpoint const & endpoint)
3162 assert(address[1] == 'g');
3163 assert(address[2] == '_');
3165 if (strcmp(address+3, "new") == 0) {
3166 handle_g_new(message);
3167 return;
3169 if (strcmp(address+3, "head") == 0) {
3170 handle_g_head_or_tail<head>(message);
3171 return;
3173 if (strcmp(address+3, "tail") == 0) {
3174 handle_g_head_or_tail<tail>(message);
3175 return;
3177 if (strcmp(address+3, "freeAll") == 0) {
3178 handle_g_freeall(message);
3179 return;
3181 if (strcmp(address+3, "deepFree") == 0) {
3182 handle_g_deepFree(message);
3183 return;
3185 if (strcmp(address+3, "queryTree") == 0) {
3186 handle_g_queryTree<realtime>(message, endpoint);
3187 return;
3190 if (strcmp(address+3, "dumpTree") == 0) {
3191 handle_g_dumpTree(message);
3192 return;
3196 template <bool realtime>
3197 void dispatch_node_commands(const char * address, received_message const & message,
3198 nova_endpoint const & endpoint)
3200 assert(address[1] == 'n');
3201 assert(address[2] == '_');
3203 if (strcmp(address+3, "free") == 0) {
3204 handle_n_free(message);
3205 return;
3208 if (strcmp(address+3, "set") == 0) {
3209 handle_n_set(message);
3210 return;
3213 if (strcmp(address+3, "setn") == 0) {
3214 handle_n_setn(message);
3215 return;
3218 if (strcmp(address+3, "fill") == 0) {
3219 handle_n_fill(message);
3220 return;
3223 if (strcmp(address+3, "map") == 0) {
3224 handle_n_map(message);
3225 return;
3228 if (strcmp(address+3, "mapn") == 0) {
3229 handle_n_mapn(message);
3230 return;
3233 if (strcmp(address+3, "mapa") == 0) {
3234 handle_n_mapa(message);
3235 return;
3238 if (strcmp(address+3, "mapan") == 0) {
3239 handle_n_mapan(message);
3240 return;
3243 if (strcmp(address+3, "run") == 0) {
3244 handle_n_run(message);
3245 return;
3248 if (strcmp(address+3, "before") == 0) {
3249 handle_n_before_or_after<before>(message);
3250 return;
3253 if (strcmp(address+3, "after") == 0) {
3254 handle_n_before_or_after<after>(message);
3255 return;
3258 if (strcmp(address+3, "order") == 0) {
3259 handle_n_order(message);
3260 return;
3263 if (strcmp(address+3, "query") == 0) {
3264 handle_n_query(message, endpoint);
3265 return;
3268 if (strcmp(address+3, "trace") == 0) {
3269 handle_n_trace(message);
3270 return;
3274 template <bool realtime>
3275 void dispatch_buffer_commands(const char * address, received_message const & message,
3276 size_t msg_size, nova_endpoint const & endpoint)
3278 assert(address[1] == 'b');
3279 assert(address[2] == '_');
3281 if (strcmp(address+3, "alloc") == 0) {
3282 handle_b_alloc<realtime>(message, endpoint);
3283 return;
3286 if (strcmp(address+3, "free") == 0) {
3287 handle_b_free<realtime>(message, endpoint);
3288 return;
3291 if (strcmp(address+3, "allocRead") == 0) {
3292 handle_b_allocRead<realtime>(message, endpoint);
3293 return;
3295 if (strcmp(address+3, "allocReadChannel") == 0) {
3296 handle_b_allocReadChannel<realtime>(message, endpoint);
3297 return;
3300 if (strcmp(address+3, "read") == 0) {
3301 handle_b_read<realtime>(message, endpoint);
3302 return;
3305 if (strcmp(address+3, "readChannel") == 0) {
3306 handle_b_readChannel<realtime>(message, endpoint);
3307 return;
3310 if (strcmp(address+3, "write") == 0) {
3311 handle_b_write<realtime>(message, endpoint);
3312 return;
3315 if (strcmp(address+3, "zero") == 0) {
3316 handle_b_zero<realtime>(message, endpoint);
3317 return;
3320 if (strcmp(address+3, "set") == 0) {
3321 handle_b_set(message);
3322 return;
3325 if (strcmp(address+3, "setn") == 0) {
3326 handle_b_setn(message);
3327 return;
3330 if (strcmp(address+3, "fill") == 0) {
3331 handle_b_fill(message);
3332 return;
3335 if (strcmp(address+3, "query") == 0) {
3336 handle_b_query<realtime>(message, endpoint);
3337 return;
3340 if (strcmp(address+3, "get") == 0) {
3341 handle_b_get<realtime>(message, endpoint);
3342 return;
3345 if (strcmp(address+3, "getn") == 0) {
3346 handle_b_getn<realtime>(message, endpoint);
3347 return;
3350 if (strcmp(address+3, "gen") == 0) {
3351 handle_b_gen<realtime>(message, msg_size, endpoint);
3352 return;
3355 if (strcmp(address+3, "close") == 0) {
3356 handle_b_close<realtime>(message, endpoint);
3357 return;
3361 template <bool realtime>
3362 void dispatch_control_bus_commands(const char * address, received_message const & message,
3363 nova_endpoint const & endpoint)
3365 assert(address[1] == 'c');
3366 assert(address[2] == '_');
3368 if (strcmp(address+3, "set") == 0) {
3369 handle_c_set(message);
3370 return;
3373 if (strcmp(address+3, "setn") == 0) {
3374 handle_c_setn(message);
3375 return;
3378 if (strcmp(address+3, "fill") == 0) {
3379 handle_c_fill(message);
3380 return;
3383 if (strcmp(address+3, "get") == 0) {
3384 handle_c_get<realtime>(message, endpoint);
3385 return;
3388 if (strcmp(address+3, "getn") == 0) {
3389 handle_c_getn<realtime>(message, endpoint);
3390 return;
3394 template <bool realtime>
3395 void dispatch_synthdef_commands(const char * address, received_message const & message,
3396 nova_endpoint const & endpoint)
3398 assert(address[1] == 'd');
3399 assert(address[2] == '_');
3401 if (strcmp(address+3, "recv") == 0) {
3402 handle_d_recv<realtime>(message, endpoint);
3403 return;
3406 if (strcmp(address+3, "load") == 0) {
3407 handle_d_load<realtime>(message, endpoint);
3408 return;
3411 if (strcmp(address+3, "loadDir") == 0) {
3412 handle_d_loadDir<realtime>(message, endpoint);
3413 return;
3416 if (strcmp(address+3, "free") == 0) {
3417 handle_d_free(message);
3418 return;
3422 template <bool realtime>
3423 void dispatch_synth_commands(const char * address, received_message const & message, size_t msg_size,
3424 nova_endpoint const & endpoint)
3426 assert(address[1] == 's');
3427 assert(address[2] == '_');
3429 if (strcmp(address+3, "new") == 0) {
3430 handle_s_new(message);
3431 return;
3434 if (strcmp(address+3, "noid") == 0) {
3435 handle_s_noid(message);
3436 return;
3439 if (strcmp(address+3, "get") == 0) {
3440 handle_s_get<realtime>(message, msg_size, endpoint);
3441 return;
3444 if (strcmp(address+3, "getn") == 0) {
3445 handle_s_getn<realtime>(message, msg_size, endpoint);
3446 return;
3450 } /* namespace */
3452 template <bool realtime>
3453 void sc_osc_handler::handle_message_sym_address(received_message const & message,
3454 size_t msg_size, nova_endpoint const & endpoint)
3456 const char * address = message.AddressPattern();
3458 /* scsynth doesn't require the leading / */
3459 if(address[0] != '/')
3460 address -= 1;
3462 if (address[2] == '_')
3464 if (address[1] == 'g') {
3465 dispatch_group_commands<realtime>(address, message, endpoint);
3466 return;
3469 if (address[1] == 'n') {
3470 dispatch_node_commands<realtime>(address, message, endpoint);
3471 return;
3474 if (address[1] == 'b') {
3475 dispatch_buffer_commands<realtime>(address, message, msg_size, endpoint);
3476 return;
3479 if (address[1] == 'c') {
3480 dispatch_control_bus_commands<realtime>(address, message, endpoint);
3481 return;
3484 if (address[1] == 'd') {
3485 dispatch_synthdef_commands<realtime>(address, message, endpoint);
3486 return;
3489 if (address[1] == 's') {
3490 dispatch_synth_commands<realtime>(address, message, msg_size, endpoint);
3491 return;
3495 if (strcmp(address+1, "p_new") == 0) {
3496 handle_p_new(message);
3497 return;
3500 if (strcmp(address+1, "u_cmd") == 0) {
3501 handle_u_cmd(message, msg_size);
3502 return;
3505 if (strcmp(address+1, "status") == 0) {
3506 handle_status<realtime>(endpoint);
3507 return;
3510 if (strcmp(address+1, "sync") == 0) {
3511 handle_sync<realtime>(message, endpoint);
3512 return;
3515 if (strcmp(address+1, "quit") == 0) {
3516 handle_quit<realtime>(endpoint);
3517 return;
3520 if (strcmp(address+1, "notify") == 0) {
3521 handle_notify<realtime>(message, endpoint);
3522 return;
3525 if (strcmp(address+1, "dumpOSC") == 0) {
3526 handle_dumpOSC(message);
3527 return;
3530 if (strcmp(address+1, "clearSched") == 0) {
3531 handle_clearSched();
3532 return;
3535 if (strcmp(address+1, "error") == 0) {
3536 handle_error(message);
3537 return;
3540 if (strcmp(address+1, "cmd") == 0) {
3541 handle_cmd(message, msg_size, endpoint, 8);
3542 return;
3545 handle_unhandled_message(message);
3549 template <bool realtime>
3550 void handle_asynchronous_plugin_cleanup(World * world, void *cmdData,
3551 AsyncFreeFn cleanup)
3553 if (cleanup)
3554 (cleanup)(world, cmdData);
3557 template <bool realtime>
3558 void handle_asynchronous_plugin_stage4(World * world, const char * cmdName, void *cmdData, AsyncStageFn stage4,
3559 AsyncFreeFn cleanup, completion_message & msg, nova_endpoint const & endpoint)
3561 if (stage4)
3562 (stage4)(world, cmdData);
3564 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(handle_asynchronous_plugin_cleanup<realtime>, world, cmdData,
3565 cleanup));
3567 send_done_message(endpoint, cmdName);
3570 template <bool realtime>
3571 void handle_asynchronous_plugin_stage3(World * world, const char * cmdName, void *cmdData, AsyncStageFn stage3, AsyncStageFn stage4,
3572 AsyncFreeFn cleanup, completion_message & msg, nova_endpoint const & endpoint)
3574 if (stage3) {
3575 bool success = (stage3)(world, cmdData);
3576 if (success)
3577 msg.handle(endpoint);
3579 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage4<realtime>, world, cmdName,
3580 cmdData, stage4, cleanup, msg, endpoint));
3583 template <bool realtime>
3584 void handle_asynchronous_plugin_stage2(World * world, const char * cmdName, void *cmdData, AsyncStageFn stage2,
3585 AsyncStageFn stage3, AsyncStageFn stage4,
3586 AsyncFreeFn cleanup, completion_message & msg, nova_endpoint const & endpoint)
3588 if (stage2)
3589 (stage2)(world, cmdData);
3591 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(handle_asynchronous_plugin_stage3<realtime>, world, cmdName,
3592 cmdData, stage3, stage4,
3593 cleanup, msg, endpoint));
3596 void sc_osc_handler::do_asynchronous_command(World * world, void* replyAddr, const char* cmdName, void *cmdData,
3597 AsyncStageFn stage2, AsyncStageFn stage3, AsyncStageFn stage4, AsyncFreeFn cleanup,
3598 int completionMsgSize, void* completionMsgData)
3600 completion_message msg(completionMsgSize, completionMsgData);
3601 nova_endpoint endpoint(*static_cast<nova_endpoint*>(replyAddr));
3603 if (world->mRealTime)
3604 cmd_dispatcher<true>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage2<true>, world, cmdName,
3605 cmdData, stage2, stage3, stage4, cleanup, msg, endpoint));
3606 else
3607 cmd_dispatcher<false>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage2<false>, world, cmdName,
3608 cmdData, stage2, stage3, stage4, cleanup, msg, endpoint));
3612 } /* namespace detail */
3613 } /* namespace nova */