bumping version to 3.5-rc1
[supercollider.git] / server / supernova / sc / sc_osc_handler.cpp
blobe09897f00c3913baddeb929a0f8ef6e0cbefc855
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 static bool node_position_sanity_check(node_position_constraint const & constraint)
849 switch (constraint.second) {
850 case head:
851 case tail:
852 case insert: {
853 server_node * target = constraint.first;
854 if (!target->is_group()) {
855 log_printf("Invalid position constraint (target: %d, addAction: %d)\n", target->id(), constraint.second);
856 return false;
861 return true;
864 sc_synth * add_synth(const char * name, int node_id, int action, int target_id)
866 if (!check_node_id(node_id))
867 return 0;
869 server_node * target = find_node(target_id);
870 if (target == NULL)
871 return NULL;
873 node_position_constraint pos = make_pair(target, node_position(action));
874 if (!node_position_sanity_check(pos))
875 return NULL;
877 abstract_synth * synth = instance->add_synth(name, node_id, pos);
878 if (!synth)
879 log_printf("Cannot create synth (synthdef: %s, node id: %d)\n", name, node_id);
881 last_generated = node_id;
882 return static_cast<sc_synth*>(synth);
885 /* extract float or int32 as float from argument iterator */
886 inline float extract_float_argument(osc::ReceivedMessageArgumentIterator const & it)
888 if (it->IsFloat())
889 return it->AsFloatUnchecked();
890 if (it->IsInt32())
891 return float(it->AsInt32Unchecked());
892 if (it->IsInt64())
893 return float(it->AsInt64Unchecked());
895 throw std::runtime_error("type cannot be converted to float");
898 inline void verify_argument(osc::ReceivedMessageArgumentIterator const & it,
899 osc::ReceivedMessageArgumentIterator const & end)
901 if (it == end)
902 throw std::runtime_error("unexpected end of argument list");
905 template <bool IsAudio, typename slot_type>
906 static void apply_control_bus_mapping(server_node & node, slot_type slot, int bus_index);
908 template <typename control_id_type>
909 void set_control_array(server_node * node, control_id_type control, osc::ReceivedMessageArgumentIterator & it)
911 size_t array_size = it->ArraySize(); ++it;
913 if (it->IsArrayStart()) {
914 // nested arrays are basically user errors, but we handle them like normal arrays
915 log("Warning in /s_new handler: nested array argument detected");
916 set_control_array<control_id_type>(node, control, it);
917 return;
918 } else {
919 for (size_t i = 0; i != array_size; ++i) {
920 if (it->IsString() || it->IsSymbol()) {
921 char const * name = it->AsStringUnchecked(); ++it;
922 int bus_id;
924 switch (name[0]) {
925 case 'c':
926 bus_id = atoi(name+1);
927 static_cast<sc_synth*>(node)->map_control_bus<false>(control, i, bus_id);
928 break;
930 case 'a':
931 bus_id = atoi(name+1);
932 static_cast<sc_synth*>(node)->map_control_bus<true>(control, i, bus_id);
933 break;
935 default:
936 throw runtime_error("invalid name for control mapping");
938 } else {
939 float value = extract_float_argument(it++);
940 node->set_control_array_element(control, i, value);
945 if (!it->IsArrayEnd())
946 throw runtime_error("missing array end tag");
947 ++it; // skip array end
950 template <typename ControlSpecifier>
951 void set_control(server_node * node, ControlSpecifier const & control, osc::ReceivedMessageArgumentIterator & it)
953 if (it->IsArrayStart())
954 set_control_array(node, control, it);
955 else if (it->IsString() || it->IsSymbol()) {
956 char const * name = it->AsStringUnchecked(); ++it;
957 int bus_id;
959 switch (name[0]) {
960 case 'c':
961 bus_id = atoi(name+1);
962 apply_control_bus_mapping<false>(*node, control, bus_id);
963 break;
965 case 'a':
966 bus_id = atoi(name+1);
967 apply_control_bus_mapping<true>(*node, control, bus_id);
968 break;
970 default:
971 throw runtime_error("invalid name for control mapping");
974 } else {
975 float value = extract_float_argument(it++);
976 node->set(control, value);
980 /* set control values of node from string/float or int/float pair */
981 void set_control(server_node * node, osc::ReceivedMessageArgumentIterator & it, osc::ReceivedMessageArgumentIterator end)
983 if (it->IsInt32()) {
984 osc::int32 index = it->AsInt32Unchecked(); ++it;
985 if (it == end) return; // sclang sometimes uses an integer instead of an empty argument list
986 set_control(node, index, it);
987 } else if (it->IsString()) {
988 const char * str = it->AsStringUnchecked(); ++it;
989 set_control(node, str, it);
990 } else
991 throw runtime_error("invalid argument");
994 void handle_s_new(received_message const & msg)
996 osc::ReceivedMessageArgumentIterator args = msg.ArgumentsBegin(), end = msg.ArgumentsEnd();
998 const char * def_name = args->AsString(); ++args;
999 int32_t id = args->AsInt32(); ++args;
1001 if (id == -1)
1002 id = instance->generate_node_id();
1004 int32_t action, target;
1006 if (args != end) {
1007 action = args->AsInt32(); ++args;
1008 } else
1009 action = 0;
1011 if (args != end) {
1012 target = args->AsInt32(); ++args;
1013 } else
1014 target = 0;
1016 sc_synth * synth = add_synth(def_name, id, action, target);
1018 if (synth == NULL)
1019 return;
1021 try {
1022 while (args != end)
1023 set_control(synth, args, end);
1024 } catch(std::exception & e) {
1025 log_printf("exception in /s_new: %s\n", e.what());
1030 void handle_g_new(received_message const & msg)
1032 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1034 while(!args.Eos()) {
1035 osc::int32 node_id, action, target_id;
1036 args >> node_id >> action >> target_id;
1038 if (node_id == -1)
1039 node_id = instance->generate_node_id();
1040 else if (!check_node_id(node_id))
1041 continue;
1043 server_node * target = find_node(target_id);
1045 if (!target)
1046 continue;
1048 node_position_constraint pos = make_pair(target, node_position(action));
1049 if (!node_position_sanity_check(pos))
1050 continue;
1052 instance->add_group(node_id, pos);
1053 last_generated = node_id;
1057 void handle_g_freeall(received_message const & msg)
1059 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1061 while(!args.Eos())
1063 osc::int32 id;
1064 args >> id;
1066 abstract_group * group = find_group(id);
1067 if (!group)
1068 continue;
1070 bool success = instance->group_free_all(group);
1072 if (!success)
1073 log("/g_freeAll failue\n");
1077 void handle_g_deepFree(received_message const & msg)
1079 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1081 while(!args.Eos())
1083 osc::int32 id;
1084 args >> id;
1086 abstract_group * group = find_group(id);
1087 if (!group)
1088 continue;
1090 bool success = instance->group_free_deep(group);
1092 if (!success)
1093 log("/g_freeDeep failue\n");
1097 void g_query_tree_fill_node(osc::OutboundPacketStream & p, bool flag, server_node const & node)
1099 p << osc::int32(node.id());
1100 if (node.is_synth())
1101 p << -1;
1102 else
1103 p << osc::int32(static_cast<abstract_group const &>(node).child_count());
1105 if (node.is_synth()) {
1106 sc_synth const & scsynth = static_cast<sc_synth const&>(node);
1107 p << scsynth.prototype_name();
1109 if (flag) {
1110 osc::int32 controls = scsynth.mNumControls;
1111 p << controls;
1113 for (int i = 0; i != controls; ++i) {
1114 p << osc::int32(i); /** \todo later we can return symbols */
1116 if (scsynth.mMapControls[i] != (scsynth.mControls+i)) {
1117 /* we use a bus mapping */
1118 int bus = (scsynth.mMapControls[i]) - (scsynth.mNode.mWorld->mControlBus);
1119 char str[10];
1120 sprintf(str, "s%d", bus);
1121 p << str;
1123 else
1124 p << scsynth.mControls[i];
1127 } else {
1128 abstract_group const & group = static_cast<abstract_group const &>(node);
1129 group.apply_on_children(boost::bind(g_query_tree_fill_node, boost::ref(p), flag, _1));
1133 template <bool realtime>
1134 void g_query_tree(int node_id, bool flag, nova_endpoint const & endpoint)
1136 server_node * node = find_node(node_id);
1137 if (!node || node->is_synth())
1138 return;
1140 abstract_group * group = static_cast<abstract_group*>(node);
1142 size_t max_msg_size = 1<<16;
1143 for(;;) {
1144 try {
1145 if (max_msg_size > 1<<22)
1146 return;
1148 sized_array<char, rt_pool_allocator<char> > data(max_msg_size);
1150 osc::OutboundPacketStream p(data.c_array(), max_msg_size);
1151 p << osc::BeginMessage("/g_queryTree.reply")
1152 << (flag ? 1 : 0)
1153 << node_id
1154 << osc::int32(group->child_count());
1156 group->apply_on_children(boost::bind(g_query_tree_fill_node, boost::ref(p), flag, _1));
1157 p << osc::EndMessage;
1159 movable_array<char> message(p.Size(), data.c_array());
1160 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
1161 return;
1163 catch(...)
1165 max_msg_size *= 2; /* if we run out of memory, retry with doubled memory resources */
1170 template <bool realtime>
1171 void handle_g_queryTree(received_message const & msg, nova_endpoint const & endpoint)
1173 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1175 while(!args.Eos())
1177 try {
1178 osc::int32 id, flag;
1179 args >> id >> flag;
1180 g_query_tree<realtime>(id, flag, endpoint);
1182 catch (std::exception & e) {
1183 log_printf("exception in handle_g_queryTree: %s\n", e.what());
1188 typedef std::basic_stringstream <char,
1189 std::char_traits <char>/*,
1190 rt_pool_allocator<char>*/ > rt_string_stream;
1192 void fill_spaces(rt_string_stream & stream, int level)
1194 for (int i = 0; i != level*3; ++i)
1195 stream << ' ';
1198 void g_dump_node(rt_string_stream & stream, server_node & node, bool flag, int level)
1200 using namespace std;
1201 fill_spaces(stream, level);
1203 if (node.is_synth()) {
1204 abstract_synth const & synth = static_cast<abstract_synth const &>(node);
1205 stream << synth.id() << " " << synth.prototype_name() << endl;
1207 if (flag) {
1208 /* dump controls */
1210 } else {
1211 abstract_group & group = static_cast<abstract_group &>(node);
1212 stream << group.id();
1214 if (group.is_parallel())
1215 stream << " parallel group";
1216 else
1217 stream << " group";
1218 stream << endl;
1219 group.apply_on_children(boost::bind(g_dump_node, boost::ref(stream), _1, flag, level + 1));
1223 void g_dump_tree(int id, bool flag)
1225 server_node * node = find_node(id);
1226 if (!node)
1227 return;
1229 // FIXME: can we completely avoid all internal allocations?
1230 rt_string_stream stream;
1231 stream << "NODE TREE Group " << id << std::endl;
1233 g_dump_node(stream, *node, flag, 1);
1234 log(stream.str().c_str(), stream.str().size());
1237 void handle_g_dumpTree(received_message const & msg)
1239 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1241 while(!args.Eos())
1243 try {
1244 osc::int32 id, flag;
1245 args >> id >> flag;
1246 g_dump_tree(id, flag);
1248 catch (std::exception & e) {
1249 log_printf("exception in /g_dumpTree: %s\n", e.what());
1254 void handle_n_free(received_message const & msg)
1256 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1258 while(!args.Eos())
1260 try {
1261 osc::int32 id;
1262 args >> id;
1264 server_node * node = find_node(id);
1265 if (!node)
1266 continue;
1268 instance->free_node(node);
1270 catch (std::exception & e) {
1271 log_printf("exception in /n_free: %s\n", e.what());
1276 /** macro to define an os command handler with a starting node id
1278 * it is mainly intended as decorator to avoid duplicate error handling code
1280 #define HANDLE_N_DECORATOR(cmd, function) \
1281 void handle_n_##cmd(received_message const & msg) \
1283 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); \
1284 osc::int32 id = it->AsInt32(); ++it; \
1286 server_node * node = find_node(id); \
1287 if (!node) \
1288 return; \
1290 try { \
1291 while (it != msg.ArgumentsEnd()) \
1292 function(node, it); \
1293 } catch(std::exception & e) { \
1294 log_printf("Exception during /n_" #cmd "handler: %s\n", e.what());\
1298 void set_control(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1300 if (it->IsInt32()) {
1301 osc::int32 index = it->AsInt32Unchecked(); ++it;
1302 set_control(node, index, it);
1303 } else if (it->IsString()) {
1304 const char * str = it->AsStringUnchecked(); ++it;
1305 set_control(node, str, it);
1306 } else
1307 throw runtime_error("invalid argument");
1311 HANDLE_N_DECORATOR(set, set_control)
1313 void set_control_n(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1315 if (it->IsInt32()) {
1316 osc::int32 index = it->AsInt32Unchecked(); ++it;
1317 osc::int32 count = it->AsInt32(); ++it;
1319 for (int i = 0; i != count; ++i)
1320 node->set(index + i, extract_float_argument(it++));
1322 else if (it->IsString()) {
1323 const char * str = it->AsStringUnchecked(); ++it;
1324 osc::int32 count = it->AsInt32(); ++it;
1326 sized_array<float> values(count);
1327 for (int i = 0; i != count; ++i)
1328 values[i] = extract_float_argument(it++);
1330 node->set_control_array(str, count, values.c_array());
1331 } else
1332 throw runtime_error("invalid argument");
1335 HANDLE_N_DECORATOR(setn, set_control_n)
1337 void fill_control(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1339 if (it->IsInt32()) {
1340 osc::int32 index = it->AsInt32Unchecked(); ++it;
1341 osc::int32 count = it->AsInt32(); ++it;
1342 float value = extract_float_argument(it++);
1344 for (int i = 0; i != count; ++i)
1345 node->set(index + i, value);
1347 else if (it->IsString()) {
1348 const char * str = it->AsStringUnchecked(); ++it;
1349 osc::int32 count = it->AsInt32(); ++it;
1350 float value = extract_float_argument(it++);
1352 sized_array<float> values(count);
1353 for (int i = 0; i != count; ++i)
1354 values[i] = value;
1356 node->set_control_array(str, count, values.c_array());
1357 } else
1358 throw runtime_error("invalid argument");
1361 HANDLE_N_DECORATOR(fill, fill_control)
1363 template <bool IsAudio, typename slot_type>
1364 void apply_control_bus_mapping(server_node & node, slot_type slot, int bus_index)
1366 if (node.is_synth())
1367 static_cast<sc_synth&>(node).map_control_bus<IsAudio>(slot, bus_index);
1368 else
1369 static_cast<abstract_group&>(node).apply_on_children(boost::bind(apply_control_bus_mapping<IsAudio, slot_type>, _1,
1370 slot, bus_index));
1373 template <bool IsAudio, typename slot_type>
1374 void apply_control_busn_mapping(server_node & node, slot_type slot, int bus_index, int count)
1376 if (node.is_synth())
1377 static_cast<sc_synth&>(node).map_control_buses<IsAudio>(slot, bus_index, count);
1378 else
1379 static_cast<abstract_group&>(node).apply_on_children(boost::bind(apply_control_busn_mapping<IsAudio, slot_type>, _1,
1380 slot, bus_index, count));
1383 template <bool IsAudio>
1384 void map_control(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1386 if (it->IsInt32()) {
1387 osc::int32 control_index = it->AsInt32Unchecked(); ++it;
1388 osc::int32 control_bus_index = it->AsInt32(); ++it;
1390 apply_control_bus_mapping<IsAudio>(*node, control_index, control_bus_index);
1392 else if (it->IsString()) {
1393 const char * control_name = it->AsStringUnchecked(); ++it;
1394 osc::int32 control_bus_index = it->AsInt32(); ++it;
1396 apply_control_bus_mapping<IsAudio>(*node, control_name, control_bus_index);
1397 } else
1398 throw runtime_error("invalid argument");
1401 template <bool IsAudio>
1402 void mapn_control(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1404 if (it->IsInt32()) {
1405 osc::int32 control_index = it->AsInt32Unchecked(); ++it;
1406 osc::int32 bus_index = it->AsInt32(); ++it;
1407 osc::int32 count = it->AsInt32(); ++it;
1409 apply_control_busn_mapping<IsAudio>(*node, control_index, bus_index, count);
1411 else if (it->IsString()) {
1412 const char * control_name = it->AsStringUnchecked(); ++it;
1413 osc::int32 bus_index = it->AsInt32(); ++it;
1414 osc::int32 count = it->AsInt32(); ++it;
1416 apply_control_busn_mapping<IsAudio>(*node, control_name, bus_index, count);
1417 } else
1418 throw runtime_error("invalid argument");
1422 HANDLE_N_DECORATOR(map, map_control<false>)
1423 HANDLE_N_DECORATOR(mapa, map_control<true>)
1424 HANDLE_N_DECORATOR(mapn, mapn_control<false>)
1425 HANDLE_N_DECORATOR(mapan, mapn_control<true>)
1427 template <nova::node_position Relation>
1428 void handle_n_before_or_after(received_message const & msg)
1430 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1432 while(!args.Eos()) {
1433 osc::int32 node_a, node_b;
1434 args >> node_a >> node_b;
1436 server_node * a = find_node(node_a);
1437 if (!a) continue;
1439 server_node * b = find_node(node_b);
1440 if (!b) continue;
1442 abstract_group::move_before_or_after<Relation>(a, b);
1448 template <nova::node_position Position>
1449 void handle_g_head_or_tail(received_message const & msg)
1451 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1453 while(!args.Eos()) {
1454 osc::int32 node_id, target_id;
1455 args >> target_id >> node_id;
1457 server_node * node = find_node(node_id);
1458 if (!node) continue;
1460 abstract_group * target_group = find_group(target_id);
1461 if (!target_group) continue;
1463 abstract_group::move_to_head_or_tail<Position>(node, target_group);
1469 void handle_n_query(received_message const & msg, nova_endpoint const & endpoint)
1471 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1473 while(!args.Eos())
1475 osc::int32 node_id;
1476 args >> node_id;
1478 server_node * node = find_node(node_id);
1479 if (!node)
1480 continue;
1482 char buffer[128]; // 128 byte should be enough
1483 osc::OutboundPacketStream p(buffer, 128);
1484 p << osc::BeginMessage("/n_info");
1485 fill_notification(node, p);
1487 movable_array<char> message(p.Size(), p.Data());
1488 cmd_dispatcher<true>::fire_system_callback(boost::bind(send_udp_message, message, endpoint));
1492 void handle_n_order(received_message const & msg)
1494 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1496 osc::int32 action, target_id;
1497 args >> action >> target_id;
1499 server_node * target = find_node(target_id);
1501 if (target == NULL)
1502 return;
1504 abstract_group * target_parent;
1505 if (action == before ||
1506 action == after)
1507 target_parent = target->get_parent();
1508 else {
1509 if (target->is_synth())
1510 throw std::runtime_error("invalid argument for n_order: argument is no synth");
1511 target_parent = static_cast<abstract_group*>(target);
1514 while (!args.Eos())
1516 osc::int32 node_id;
1517 args >> node_id;
1519 server_node * node = find_node(node_id);
1520 if (node == NULL)
1521 continue;
1523 abstract_group * node_parent = node->get_parent();
1525 /** \todo this can be optimized if node_parent == target_parent */
1526 node_parent->remove_child(node);
1527 if (action == before ||
1528 action == after)
1529 target_parent->add_child(node, make_pair(target, node_position(action)));
1530 else
1531 target_parent->add_child(node, node_position(action));
1533 instance->update_dsp_queue();
1537 void handle_n_run(received_message const & msg)
1539 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1541 while(!args.Eos()) {
1542 osc::int32 node_id, run_flag;
1543 args >> node_id >> run_flag;
1545 server_node * node = find_node(node_id);
1546 if(!node)
1547 continue;
1549 if (run_flag)
1550 instance->node_resume(node);
1551 else
1552 instance->node_pause(node);
1556 void enable_tracing(server_node & node)
1558 if (node.is_synth()) {
1559 sc_synth & synth = static_cast<sc_synth&>(node);
1560 synth.enable_tracing();
1561 } else {
1562 abstract_group & group = static_cast<abstract_group&>(node);
1563 group.apply_on_children(enable_tracing);
1567 void handle_n_trace(received_message const & msg)
1569 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1571 while(!args.Eos()) {
1572 osc::int32 node_id;
1573 args >> node_id;
1575 server_node * node = find_node(node_id);
1576 if (!node)
1577 continue;
1579 enable_tracing(*node);
1584 void handle_s_noid(received_message const & msg)
1586 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1588 while(!args.Eos()) {
1589 osc::int32 node_id;
1590 args >> node_id;
1591 instance->synth_reassign_id(node_id);
1595 int32_t get_control_index(sc_synth * s, osc::ReceivedMessageArgumentIterator & it, osc::OutboundPacketStream & p)
1597 int32_t control;
1598 if (it->IsInt32())
1600 control = it->AsInt32Unchecked(); ++it;
1601 p << control;
1603 else if (it->IsString())
1605 const char * control_str = it->AsStringUnchecked(); ++it;
1606 control = s->resolve_slot(control_str);
1607 p << control_str;
1609 else if (it->IsSymbol())
1611 const char * control_str = it->AsSymbolUnchecked(); ++it;
1612 control = s->resolve_slot(control_str);
1613 p << osc::Symbol(control_str);
1615 else
1616 throw std::runtime_error("wrong argument type");
1617 return control;
1620 template <bool realtime>
1621 void handle_s_get(received_message const & msg, size_t msg_size, nova_endpoint const & endpoint)
1623 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
1625 if (!it->IsInt32())
1626 throw std::runtime_error("wrong argument type");
1628 int32_t node_id = it->AsInt32Unchecked(); ++it;
1630 server_node * node = find_node(node_id);
1631 if (!node || !node->is_synth())
1632 throw std::runtime_error("node is not a synth");
1634 sc_synth * s = static_cast<sc_synth*>(node);
1636 size_t alloc_size = msg_size + sizeof(float) * (msg.ArgumentCount()-1) + 128;
1638 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
1640 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
1641 p << osc::BeginMessage("/n_set")
1642 << node_id;
1644 while (it != msg.ArgumentsEnd())
1646 int32_t control = get_control_index(s, it, p);
1647 p << s->get(control);
1649 p << osc::EndMessage;
1651 movable_array<char> message(p.Size(), return_message.c_array());
1652 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
1655 template <bool realtime>
1656 void handle_s_getn(received_message const & msg, size_t msg_size, nova_endpoint const & endpoint)
1658 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
1660 if (!it->IsInt32())
1661 throw std::runtime_error("wrong argument type");
1663 int32_t node_id = it->AsInt32Unchecked(); ++it;
1665 server_node * node = find_node(node_id);
1666 if (!node || !node->is_synth())
1667 throw std::runtime_error("node is not a synth");
1669 sc_synth * s = static_cast<sc_synth*>(node);
1671 /* count argument values */
1672 size_t argument_count = 0;
1673 for (osc::ReceivedMessageArgumentIterator local = it; local != msg.ArgumentsEnd(); ++local)
1675 ++local; /* skip control */
1676 if (local == msg.ArgumentsEnd())
1677 break;
1678 if (!it->IsInt32())
1679 throw std::runtime_error("invalid count");
1680 argument_count += it->AsInt32Unchecked(); ++it;
1683 size_t alloc_size = msg_size + sizeof(float) * (argument_count) + 128;
1685 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
1687 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
1688 p << osc::BeginMessage("/n_setn")
1689 << node_id;
1691 while (it != msg.ArgumentsEnd())
1693 int32_t control = get_control_index(s, it, p);
1695 if (!it->IsInt32())
1696 throw std::runtime_error("integer argument expected");
1698 int32_t control_count = it->AsInt32Unchecked(); ++it;
1699 if (control_count < 0)
1700 break;
1702 for (int i = 0; i != control_count; ++i)
1703 p << s->get(control + i);
1705 p << osc::EndMessage;
1707 movable_array<char> message(p.Size(), return_message.c_array());
1708 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
1712 /** wrapper class for osc completion message
1714 struct completion_message
1716 /** constructor should only be used from the real-time thread */
1717 completion_message(size_t size, const void * data):
1718 size_(size)
1720 if (size) {
1721 data_ = system_callback::allocate(size);
1722 memcpy(data_, data, size);
1726 /** default constructor creates uninitialized object */
1727 completion_message(void):
1728 size_(0)
1731 /** copy constructor has move semantics!!! */
1732 completion_message(completion_message const & rhs)
1734 operator=(rhs);
1737 completion_message& operator=(completion_message const & rhs)
1739 size_ = rhs.size_;
1740 data_ = rhs.data_;
1741 const_cast<completion_message&>(rhs).size_ = 0;
1742 return *this;
1745 ~completion_message(void)
1747 if (size_)
1748 system_callback::deallocate(data_);
1751 /** handle package in the rt thread
1752 * not to be called from the rt thread
1754 void trigger_async(nova_endpoint const & endpoint)
1756 if (size_) {
1757 sc_osc_handler::received_packet * p =
1758 sc_osc_handler::received_packet::alloc_packet((char*)data_, size_, endpoint);
1759 instance->add_sync_callback(p);
1763 /** handle package directly
1764 * only to be called from the rt thread
1766 void handle(nova_endpoint const & endpoint)
1768 if (size_)
1769 instance->handle_packet((char*)data_, size_, endpoint);
1772 size_t size_;
1773 void * data_;
1776 completion_message extract_completion_message(osc::ReceivedMessageArgumentStream & args)
1778 osc::Blob blob(0, 0);
1780 if (!args.Eos()) {
1781 try {
1782 args >> blob;
1784 catch (osc::WrongArgumentTypeException & e)
1788 return completion_message (blob.size, blob.data);
1791 completion_message extract_completion_message(osc::ReceivedMessageArgumentIterator & it)
1793 const void * data = 0;
1794 unsigned long length = 0;
1796 if (it->IsBlob())
1797 it->AsBlobUnchecked(data, length);
1798 ++it;
1799 return completion_message(length, data);
1803 template <bool realtime>
1804 void b_alloc_2_rt(uint32_t index, completion_message & msg, sample * free_buf, nova_endpoint const & endpoint);
1805 void b_alloc_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
1807 template <bool realtime>
1808 void b_alloc_1_nrt(uint32_t index, uint32_t frames, uint32_t channels, completion_message & msg, nova_endpoint const & endpoint)
1810 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
1811 sample * free_buf = sc_factory->get_nrt_mirror_buffer(index);
1812 sc_factory->allocate_buffer(index, frames, channels);
1813 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_alloc_2_rt<realtime>, index, msg, free_buf, endpoint));
1816 template <bool realtime>
1817 void b_alloc_2_rt(uint32_t index, completion_message & msg, sample * free_buf, nova_endpoint const & endpoint)
1819 sc_factory->buffer_sync(index);
1820 msg.handle(endpoint);
1821 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_alloc_3_nrt, index, free_buf, endpoint));
1824 void b_alloc_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
1826 free_aligned(free_buf);
1827 send_done_message(endpoint, "/b_alloc", index);
1830 template <bool realtime>
1831 void handle_b_alloc(received_message const & msg, nova_endpoint const & endpoint)
1833 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1835 osc::int32 index, frames, channels;
1837 args >> index >> frames;
1839 if (!args.Eos())
1840 args >> channels;
1841 else
1842 channels = 1;
1844 completion_message message = extract_completion_message(args);
1846 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_alloc_1_nrt<realtime>, index, frames,
1847 channels, message, endpoint));
1850 template <bool realtime>
1851 void b_free_1_nrt(uint32_t index, completion_message & msg, nova_endpoint const & endpoint);
1852 template <bool realtime>
1853 void b_free_2_rt(uint32_t index, sample * free_buf, completion_message & msg, nova_endpoint const & endpoint);
1854 void b_free_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
1856 template <bool realtime>
1857 void b_free_1_nrt(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
1859 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
1860 sample * free_buf = sc_factory->get_nrt_mirror_buffer(index);
1861 sc_factory->free_buffer(index);
1862 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_free_2_rt<realtime>,
1863 index, free_buf, msg, endpoint));
1866 template <bool realtime>
1867 void b_free_2_rt(uint32_t index, sample * free_buf, completion_message & msg, nova_endpoint const & endpoint)
1869 sc_factory->buffer_sync(index);
1870 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_free_3_nrt, index, free_buf, endpoint));
1871 msg.handle(endpoint);
1874 void b_free_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
1876 free_aligned(free_buf);
1877 send_done_message(endpoint, "/b_free", index);
1881 template <bool realtime>
1882 void handle_b_free(received_message const & msg, nova_endpoint const & endpoint)
1884 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1886 osc::int32 index;
1887 args >> index;
1889 completion_message message = extract_completion_message(args);
1891 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_free_1_nrt<realtime>, index, message, endpoint));
1894 template <bool realtime>
1895 void b_allocRead_2_rt(uint32_t index, completion_message & msg, sample * free_buf, nova_endpoint const & endpoint);
1896 void b_allocRead_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
1898 template <bool realtime>
1899 void b_allocRead_1_nrt(uint32_t index, movable_string & filename, uint32_t start, uint32_t frames, completion_message & msg,
1900 nova_endpoint const & endpoint)
1902 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
1903 sample * free_buf = sc_factory->get_nrt_mirror_buffer(index);
1904 int error = sc_factory->buffer_read_alloc(index, filename.c_str(), start, frames);
1905 if (!error)
1906 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_allocRead_2_rt<realtime>, index, msg, free_buf, endpoint));
1907 else
1908 /* post nice error message */;
1911 template <bool realtime>
1912 void b_allocRead_2_rt(uint32_t index, completion_message & msg, sample * free_buf,
1913 nova_endpoint const & endpoint)
1915 sc_factory->buffer_sync(index);
1916 msg.handle(endpoint);
1917 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_allocRead_3_nrt, index, free_buf, endpoint));
1920 void b_allocRead_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
1922 free_aligned(free_buf);
1923 send_done_message(endpoint, "/b_allocRead", index);
1926 template <bool realtime>
1927 void handle_b_allocRead(received_message const & msg, nova_endpoint const & endpoint)
1929 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1931 osc::int32 index;
1932 const char * filename;
1934 osc::int32 start = 0;
1935 osc::int32 frames = 0;
1937 args >> index >> filename;
1939 if (!args.Eos())
1940 args >> start;
1942 if (!args.Eos())
1943 args >> frames;
1945 completion_message message = extract_completion_message(args);
1947 movable_string fname(filename);
1948 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_allocRead_1_nrt<realtime>, index,
1949 fname, start, frames, message, endpoint));
1952 template <bool realtime>
1953 void b_allocReadChannel_2_rt(uint32_t index, completion_message & msg, sample * free_buf,
1954 nova_endpoint const & endpoint);
1955 void b_allocReadChannel_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
1957 template <bool realtime>
1958 void b_allocReadChannel_1_nrt(uint32_t index, movable_string const & filename, uint32_t start, uint32_t frames,
1959 movable_array<uint32_t> const & channels, completion_message & msg,
1960 nova_endpoint const & endpoint)
1962 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
1963 sample * free_buf = sc_factory->get_nrt_mirror_buffer(index);
1964 int error = sc_factory->buffer_alloc_read_channels(index, filename.c_str(), start, frames,
1965 channels.size(), channels.data());
1966 if (!error)
1967 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_allocReadChannel_2_rt<realtime>,
1968 index, msg, free_buf, endpoint));
1971 template <bool realtime>
1972 void b_allocReadChannel_2_rt(uint32_t index, completion_message & msg, sample * free_buf,
1973 nova_endpoint const & endpoint)
1975 sc_factory->buffer_sync(index);
1976 msg.handle(endpoint);
1977 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_allocReadChannel_3_nrt,
1978 index, free_buf, endpoint));
1981 void b_allocReadChannel_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
1983 free_aligned(free_buf);
1984 send_done_message(endpoint, "/b_allocReadChannel", index);
1988 template <bool realtime>
1989 void handle_b_allocReadChannel(received_message const & msg, nova_endpoint const & endpoint)
1991 osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin();
1993 osc::int32 index = arg->AsInt32(); arg++;
1994 const char * filename = arg->AsString(); arg++;
1996 osc::int32 start = arg->AsInt32(); arg++;
1997 size_t frames = arg->AsInt32(); arg++;
1999 size_t channel_args = msg.ArgumentCount() - 4; /* we already consumed 4 elements */
2001 size_t channel_count = 0;
2002 sized_array<uint, rt_pool_allocator<uint> > channels(channel_args);
2004 for (uint i = 0; i != channel_args - 1; ++i) // sclang fromats the last completion message as int, so we skip the last element
2006 if (arg->IsInt32()) {
2007 channels[i] = arg->AsInt32Unchecked(); arg++;
2008 ++channel_count;
2012 /* we reached the message blob */
2013 completion_message message = extract_completion_message(arg);
2015 movable_array<uint32_t> channel_mapping(channel_count, channels.c_array());
2016 movable_string fname(filename);
2018 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_allocReadChannel_1_nrt<realtime>,
2019 index, fname, start, frames, channel_mapping,
2020 message, endpoint));
2023 const char * b_write = "/b_write";
2025 template <bool realtime>
2026 void b_write_nrt_1(uint32_t index, movable_string const & filename, movable_string const & header_format,
2027 movable_string const & sample_format, uint32_t start, uint32_t frames, bool leave_open,
2028 completion_message & msg, nova_endpoint const & endpoint)
2030 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
2031 sc_factory->buffer_write(index, filename.c_str(), header_format.c_str(), sample_format.c_str(), start, frames, leave_open);
2032 msg.trigger_async(endpoint);
2033 cmd_dispatcher<realtime>::fire_done_message(endpoint, b_write, index);
2036 void fire_b_write_exception(void)
2038 throw std::runtime_error("wrong arguments for /b_allocReadChannel");
2041 template <bool realtime>
2042 void handle_b_write(received_message const & msg, nova_endpoint const & endpoint)
2044 osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin();
2045 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2047 /* required args */
2048 osc::int32 index = arg->AsInt32(); arg++;
2049 const char * filename = arg->AsString(); arg++;
2050 const char * header_format = arg->AsString(); arg++;
2051 const char * sample_format = arg->AsString(); arg++;
2053 /* optional args */
2054 osc::int32 frames = -1;
2055 osc::int32 start = 0;
2056 osc::int32 leave_open = 0;
2058 completion_message message;
2060 if (arg != end) {
2061 if (!arg->IsInt32())
2062 fire_b_write_exception();
2063 frames = arg->AsInt32Unchecked(); arg++;
2065 else
2066 goto fire_callback;
2068 if (arg != end) {
2069 if (!arg->IsInt32())
2070 fire_b_write_exception();
2071 start = arg->AsInt32Unchecked(); arg++;
2073 else
2074 goto fire_callback;
2076 if (arg != end) {
2077 if (!arg->IsInt32())
2078 fire_b_write_exception();
2079 leave_open = arg->AsInt32Unchecked(); arg++;
2081 else
2082 goto fire_callback;
2084 if (arg != end)
2085 message = extract_completion_message(arg);
2087 fire_callback:
2088 movable_string fname(filename);
2089 movable_string header_f(header_format);
2090 movable_string sample_f(sample_format);
2092 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_write_nrt_1<realtime>, index, fname, header_f, sample_f,
2093 start, frames, bool(leave_open), message, endpoint));
2096 template <bool realtime>
2097 void b_read_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint);
2099 template <bool realtime>
2100 void b_read_nrt_1(uint32_t index, movable_string & filename, uint32_t start_file, uint32_t frames,
2101 uint32_t start_buffer, bool leave_open, completion_message & msg, nova_endpoint const & endpoint)
2103 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
2104 sc_factory->buffer_read(index, filename.c_str(), start_file, frames, start_buffer, leave_open);
2105 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_read_rt_2<realtime>, index, msg, endpoint));
2108 const char * b_read = "/b_read";
2109 template <bool realtime>
2110 void b_read_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2112 sc_factory->buffer_sync(index);
2113 msg.handle(endpoint);
2114 cmd_dispatcher<realtime>::fire_done_message(endpoint, b_read, index);
2117 void fire_b_read_exception(void)
2119 throw std::runtime_error("wrong arguments for /b_read");
2122 template <bool realtime>
2123 void handle_b_read(received_message const & msg, nova_endpoint const & endpoint)
2125 osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin();
2126 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2128 /* required args */
2129 osc::int32 index = arg->AsInt32(); arg++;
2130 const char * filename = arg->AsString(); arg++;
2132 /* optional args */
2133 osc::int32 start_file = 0;
2134 osc::int32 frames = -1;
2135 osc::int32 start_buffer = 0;
2136 osc::int32 leave_open = 0;
2138 completion_message message;
2140 if (arg != end) {
2141 if (!arg->IsInt32())
2142 fire_b_read_exception();
2143 start_file = arg->AsInt32Unchecked(); arg++;
2145 else
2146 goto fire_callback;
2148 if (arg != end) {
2149 if (!arg->IsInt32())
2150 fire_b_read_exception();
2151 frames = arg->AsInt32Unchecked(); arg++;
2153 else
2154 goto fire_callback;
2156 if (arg != end) {
2157 if (!arg->IsInt32())
2158 fire_b_read_exception();
2159 start_buffer = arg->AsInt32Unchecked(); arg++;
2161 else
2162 goto fire_callback;
2164 if (arg != end) {
2165 if (!arg->IsInt32())
2166 fire_b_read_exception();
2167 leave_open = arg->AsInt32Unchecked(); arg++;
2169 else
2170 goto fire_callback;
2172 if (arg != end)
2173 message = extract_completion_message(arg);
2175 fire_callback:
2176 movable_string fname(filename);
2178 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_read_nrt_1<realtime>, index, fname,
2179 start_file, frames, start_buffer,
2180 bool(leave_open), message, endpoint));
2184 template <bool realtime>
2185 void b_readChannel_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint);
2187 template <bool realtime>
2188 void b_readChannel_nrt_1(uint32_t index, movable_string & filename, uint32_t start_file, uint32_t frames,
2189 uint32_t start_buffer, bool leave_open, movable_array<uint32_t> & channel_map,
2190 completion_message & msg, nova_endpoint const & endpoint)
2192 sc_factory->buffer_read_channel(index, filename.c_str(), start_file, frames, start_buffer, leave_open,
2193 channel_map.size(), channel_map.data());
2194 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_readChannel_rt_2<realtime>, index, msg, endpoint));
2197 const char * b_readChannel = "/b_readChannel";
2198 template <bool realtime>
2199 void b_readChannel_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2201 sc_factory->buffer_sync(index);
2202 msg.handle(endpoint);
2203 cmd_dispatcher<realtime>::fire_done_message(endpoint, b_readChannel, index);
2206 void fire_b_readChannel_exception(void)
2208 throw std::runtime_error("wrong arguments for /b_readChannel");
2211 template <bool realtime>
2212 void handle_b_readChannel(received_message const & msg, nova_endpoint const & endpoint)
2214 osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin();
2215 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2217 /* required args */
2218 osc::int32 index = arg->AsInt32(); arg++;
2219 const char * filename = arg->AsString(); arg++;
2221 /* optional args */
2222 osc::int32 start_file = 0;
2223 osc::int32 frames = -1;
2224 osc::int32 start_buffer = 0;
2225 osc::int32 leave_open = 0;
2227 sized_array<uint32_t, rt_pool_allocator<uint32_t> > channel_mapping(int32_t(msg.ArgumentCount())); /* larger than required */
2228 uint32_t channel_count = 0;
2230 completion_message message;
2232 if (arg != end) {
2233 if (!arg->IsInt32())
2234 fire_b_read_exception();
2235 start_file = arg->AsInt32Unchecked(); arg++;
2237 else
2238 goto fire_callback;
2240 if (arg != end) {
2241 if (!arg->IsInt32())
2242 fire_b_read_exception();
2243 frames = arg->AsInt32Unchecked(); arg++;
2245 else
2246 goto fire_callback;
2248 if (arg != end) {
2249 if (!arg->IsInt32())
2250 fire_b_write_exception();
2251 start_buffer = arg->AsInt32Unchecked(); arg++;
2253 else
2254 goto fire_callback;
2256 if (arg != end) {
2257 if (!arg->IsInt32())
2258 fire_b_write_exception();
2259 leave_open = arg->AsInt32Unchecked(); arg++;
2261 else
2262 goto fire_callback;
2264 while (arg != end)
2266 if (arg->IsBlob()) {
2267 message = extract_completion_message(arg);
2268 goto fire_callback;
2270 else if (arg->IsInt32()) {
2271 channel_mapping[channel_count] = arg->AsInt32Unchecked();
2272 ++arg;
2274 else
2275 fire_b_readChannel_exception();
2278 fire_callback:
2279 movable_string fname(filename);
2280 movable_array<uint32_t> channel_map(channel_count, channel_mapping.c_array());
2282 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_readChannel_nrt_1<realtime>, index, fname,
2283 start_file, frames, start_buffer,
2284 bool(leave_open), channel_map, message, endpoint));
2288 template <bool realtime>
2289 void b_zero_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint);
2291 template <bool realtime>
2292 void b_zero_nrt_1(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2294 sc_factory->buffer_zero(index);
2295 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_zero_rt_2<realtime>, index, msg, endpoint));
2298 const char * b_zero = "/b_zero";
2299 template <bool realtime>
2300 void b_zero_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2302 sc_factory->increment_write_updates(index);
2303 msg.handle(endpoint);
2304 cmd_dispatcher<realtime>::fire_done_message(endpoint, b_zero, index);
2307 template <bool realtime>
2308 void handle_b_zero(received_message const & msg, nova_endpoint const & endpoint)
2310 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2312 osc::int32 index;
2313 args >> index;
2314 completion_message message = extract_completion_message(args);
2316 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_zero_nrt_1<realtime>, index, message, endpoint));
2319 void handle_b_set(received_message const & msg)
2321 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2322 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2323 verify_argument(it, end);
2324 osc::int32 buffer_index = it->AsInt32(); ++it;
2326 buffer_wrapper::sample_t * data = sc_factory->get_buffer(buffer_index);
2328 while (it != end) {
2329 osc::int32 index = it->AsInt32(); ++it;
2330 float value = extract_float_argument(it++);
2332 data[index] = value;
2336 void handle_b_setn(received_message const & msg)
2338 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2339 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2340 verify_argument(it, end);
2341 osc::int32 buffer_index = it->AsInt32(); ++it;
2343 buffer_wrapper::sample_t * data = sc_factory->get_buffer(buffer_index);
2345 while (it != end) {
2346 osc::int32 index = it->AsInt32(); ++it;
2347 verify_argument(it, end);
2348 osc::int32 samples = it->AsInt32(); ++it;
2350 for (int i = 0; i != samples; ++i) {
2351 verify_argument(it, end);
2352 float value = extract_float_argument(it++);
2353 data[index+i] = value;
2358 void handle_b_fill(received_message const & msg)
2360 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2361 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2362 verify_argument(it, end);
2363 osc::int32 buffer_index = it->AsInt32(); ++it;
2365 buffer_wrapper::sample_t * data = sc_factory->get_buffer(buffer_index);
2367 while (it != end) {
2368 osc::int32 index = it->AsInt32(); ++it;
2369 verify_argument(it, end);
2370 osc::int32 samples = it->AsInt32(); ++it;
2371 verify_argument(it, end);
2372 float value = extract_float_argument(it++);
2374 for (int i = 0; i != samples; ++i)
2375 data[index] = value;
2379 template <bool realtime>
2380 void handle_b_query(received_message const & msg, nova_endpoint const & endpoint)
2382 const size_t elem_size = 3*sizeof(int) * sizeof(float);
2384 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2385 size_t arg_count = msg.ArgumentCount();
2387 size_t size = elem_size * arg_count + 128; /* should be more than required */
2388 sized_array<char, rt_pool_allocator<char> > data(size);
2390 osc::OutboundPacketStream p(data.c_array(), size);
2391 p << osc::BeginMessage("/b_info");
2393 while (!args.Eos()) {
2394 osc::int32 buffer_index;
2395 args >> buffer_index;
2397 SndBuf * buf = sc_factory->get_buffer_struct(buffer_index);
2399 p << buffer_index
2400 << osc::int32(buf->frames)
2401 << osc::int32(buf->channels)
2402 << float (buf->samplerate);
2405 p << osc::EndMessage;
2407 movable_array<char> message(p.Size(), data.c_array());
2409 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2412 template <bool realtime>
2413 void b_close_rt_2(completion_message & msg, nova_endpoint const & endpoint);
2415 template <bool realtime>
2416 void b_close_nrt_1(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2418 sc_factory->buffer_close(index);
2419 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_close_rt_2<realtime>, msg, endpoint));
2422 template <bool realtime>
2423 void b_close_rt_2(completion_message & msg, nova_endpoint const & endpoint)
2427 template <bool realtime>
2428 void handle_b_close(received_message const & msg, nova_endpoint const & endpoint)
2430 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2431 osc::int32 index;
2432 args >> index;
2434 completion_message message = extract_completion_message(args);
2435 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_close_nrt_1<realtime>, index, message, endpoint));
2438 template <bool realtime>
2439 void handle_b_get(received_message const & msg, nova_endpoint const & endpoint)
2441 const size_t elem_size = sizeof(int) * sizeof(float);
2442 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2443 const size_t index_count = msg.ArgumentCount() - 1;
2444 const size_t alloc_size = index_count * elem_size + 128; /* hopefully enough */
2446 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
2448 osc::int32 buffer_index;
2449 args >> buffer_index;
2451 const SndBuf * buf = sc_factory->get_buffer_struct(buffer_index);
2452 const sample * data = buf->data;
2453 const int max_sample = buf->frames * buf->channels;
2455 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
2456 p << osc::BeginMessage("/b_set")
2457 << buffer_index;
2459 while (!args.Eos())
2461 osc::int32 index;
2462 args >> index;
2463 p << index;
2465 if (index < max_sample)
2466 p << data[index];
2467 else
2468 p << 0.f;
2471 p << osc::EndMessage;
2473 movable_array<char> message(p.Size(), return_message.c_array());
2474 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2477 template<typename Alloc>
2478 struct getn_data
2480 getn_data(int start, int count, const float * data):
2481 start_index_(start), data_(count)
2483 data_.reserve(count);
2484 for (int i = 0; i != count; ++i)
2485 data_[i] = data[i];
2488 int start_index_;
2489 std::vector<float, Alloc> data_;
2492 template <bool realtime>
2493 void handle_b_getn(received_message const & msg, nova_endpoint const & endpoint)
2495 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2497 typedef getn_data<rt_pool_allocator<float> > getn_data;
2498 std::vector<getn_data, rt_pool_allocator<getn_data> > return_data;
2500 osc::int32 buffer_index;
2501 args >> buffer_index;
2503 const SndBuf * buf = sc_factory->get_buffer_struct(buffer_index);
2504 const sample * data = buf->data;
2505 const int max_sample = buf->frames * buf->channels;
2507 while (!args.Eos())
2509 osc::int32 index, sample_count;
2510 args >> index >> sample_count;
2512 if (index + sample_count <= max_sample)
2513 return_data.push_back(getn_data(index, sample_count, data + index));
2516 size_t alloc_size = 128;
2517 for (size_t i = 0; i != return_data.size(); ++i)
2518 alloc_size += return_data[i].data_.size() * (sizeof(float) + sizeof(int)) + 2*sizeof(int);
2520 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
2522 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
2523 p << osc::BeginMessage("/b_setn")
2524 << buffer_index;
2526 for (size_t i = 0; i != return_data.size(); ++i) {
2527 p << osc::int32(return_data[i].start_index_)
2528 << osc::int32(return_data[i].data_.size());
2530 for (size_t j = 0; j != return_data[i].data_.size(); ++j)
2531 p << return_data[i].data_[j];
2534 p << osc::EndMessage;
2536 movable_array<char> message(p.Size(), return_message.c_array());
2537 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2541 template <bool realtime>
2542 void b_gen_rt_2(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
2543 void b_gen_nrt_3(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
2545 template <bool realtime>
2546 void b_gen_nrt_1(movable_array<char> & message, nova_endpoint const & endpoint)
2548 sc_msg_iter msg(message.size(), (char*)message.data());
2550 int index = msg.geti();
2551 const char * generator = (const char*)msg.gets4();
2552 if (!generator)
2553 return;
2555 sample * free_buf = sc_factory->buffer_generate(index, generator, msg);
2556 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_gen_rt_2<realtime>, index, free_buf, endpoint));
2559 template <bool realtime>
2560 void b_gen_rt_2(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
2562 sc_factory->buffer_sync(index);
2563 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_gen_nrt_3, index, free_buf, endpoint));
2566 void b_gen_nrt_3(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
2568 free_aligned(free_buf);
2569 send_done_message(endpoint, "/b_gen", index);
2572 template <bool realtime>
2573 void handle_b_gen(received_message const & msg, size_t msg_size, nova_endpoint const & endpoint)
2575 movable_array<char> cmd (msg_size, msg.TypeTags()-1);
2576 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_gen_nrt_1<realtime>, cmd, endpoint));
2580 void handle_c_set(received_message const & msg)
2582 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2584 while (it != msg.ArgumentsEnd()) {
2585 osc::int32 bus_index = it->AsInt32(); ++it;
2586 float value = extract_float_argument(it++);
2588 sc_factory->controlbus_set(bus_index, value);
2592 void handle_c_setn(received_message const & msg)
2594 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2596 while (it != msg.ArgumentsEnd()) {
2597 osc::int32 bus_index, bus_count;
2598 bus_index = it->AsInt32(); ++it;
2599 bus_count = it->AsInt32(); ++it;
2601 for (int i = 0; i != bus_count; ++i) {
2602 float value = extract_float_argument(it++);
2603 sc_factory->controlbus_set(bus_index + i, value);
2608 void handle_c_fill(received_message const & msg)
2610 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2612 while (it != msg.ArgumentsEnd()) {
2613 osc::int32 bus_index, bus_count;
2614 bus_index = it->AsInt32(); ++it;
2615 bus_count = it->AsInt32(); ++it;
2616 float value = extract_float_argument(it++);
2617 sc_factory->controlbus_fill(bus_index, bus_count, value);
2621 template <bool realtime>
2622 void handle_c_get(received_message const & msg,
2623 nova_endpoint const & endpoint)
2625 const size_t elem_size = sizeof(int) + sizeof(float);
2626 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2627 const size_t index_count = msg.ArgumentCount();
2628 const size_t alloc_size = index_count * elem_size + 128; /* hopefully enough */
2630 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
2632 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
2633 p << osc::BeginMessage("/c_set");
2635 while (!args.Eos())
2637 osc::int32 index;
2638 args >> index;
2640 p << index << sc_factory->controlbus_get(index);
2643 p << osc::EndMessage;
2645 movable_array<char> message(p.Size(), return_message.c_array());
2646 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2649 template <bool realtime>
2650 void handle_c_getn(received_message const & msg, nova_endpoint const & endpoint)
2652 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2654 /* we pessimize, but better to allocate too much than too little */
2655 const size_t alloc_size = 128 +
2656 (2 * sizeof(int) + 128*sizeof(float)) * msg.ArgumentCount();
2658 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
2660 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
2661 p << osc::BeginMessage("/c_setn");
2663 while (!args.Eos())
2665 osc::int32 bus_index, bus_count;
2666 args >> bus_index >> bus_count;
2667 p << bus_index << bus_count;
2669 for (int i = 0; i != bus_count; ++i) {
2670 float value = sc_factory->controlbus_get(bus_index + i);
2671 p << value;
2675 p << osc::EndMessage;
2677 movable_array<char> message(p.Size(), return_message.c_array());
2678 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2681 #ifdef BOOST_HAS_RVALUE_REFS
2682 std::pair<sc_synth_prototype_ptr *, size_t> wrap_synthdefs(std::vector<sc_synthdef> && defs)
2684 std::vector<sc_synthdef> synthdefs(std::move(defs));
2685 size_t count = synthdefs.size();
2686 sc_synth_prototype_ptr * prototypes = new sc_synth_prototype_ptr [count];
2688 for (size_t i = 0; i != count; ++i)
2689 prototypes[i].reset(new sc_synth_prototype(std::move(synthdefs[i])));
2690 return std::make_pair(prototypes, count);
2692 #endif
2693 std::pair<sc_synth_prototype_ptr *, size_t> wrap_synthdefs(std::vector<sc_synthdef> const & defs)
2695 size_t count = defs.size();
2696 sc_synth_prototype_ptr * prototypes = new sc_synth_prototype_ptr [count];
2698 for (size_t i = 0; i != count; ++i)
2699 prototypes[i].reset(new sc_synth_prototype(defs[i]));
2700 return std::make_pair(prototypes, count);
2703 template <bool realtime>
2704 void d_recv_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2705 nova_endpoint const & endpoint);
2706 void d_recv_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint);
2708 template <bool realtime>
2709 void d_recv_nrt(movable_array<char> & def, completion_message & msg, nova_endpoint const & endpoint)
2711 size_t count;
2712 sc_synth_prototype_ptr * prototypes;
2713 std::vector<sc_synthdef> synthdefs (read_synthdefs(def.data()));
2715 #ifdef BOOST_HAS_RVALUE_REFS
2716 boost::tie(prototypes, count) = wrap_synthdefs(std::move(synthdefs));
2717 #else
2718 boost::tie(prototypes, count) = wrap_synthdefs(synthdefs);
2719 #endif
2721 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(d_recv_rt2<realtime>, prototypes, count, msg, endpoint));
2724 template <bool realtime>
2725 void d_recv_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2726 nova_endpoint const & endpoint)
2728 std::for_each(prototypes, prototypes + prototype_count,
2729 boost::bind(&synth_factory::register_prototype, instance, _1));
2731 msg.handle(endpoint);
2732 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_recv_nrt3, prototypes, endpoint));
2735 void d_recv_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint)
2737 delete[] prototypes;
2738 send_done_message(endpoint, "/d_recv");
2741 template <bool realtime>
2742 void handle_d_recv(received_message const & msg,
2743 nova_endpoint const & endpoint)
2745 const void * synthdef_data;
2746 unsigned long synthdef_size;
2748 osc::ReceivedMessageArgumentIterator args = msg.ArgumentsBegin();
2750 args->AsBlob(synthdef_data, synthdef_size); ++args;
2751 movable_array<char> def(synthdef_size, (const char*)synthdef_data);
2752 completion_message message = extract_completion_message(args);
2754 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_recv_nrt<realtime>, def, message, endpoint));
2757 template <bool realtime>
2758 void d_load_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2759 nova_endpoint const & endpoint);
2760 void d_load_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint);
2762 template <bool realtime>
2763 void d_load_nrt(movable_string & path, completion_message & msg, nova_endpoint const & endpoint)
2765 size_t count;
2766 sc_synth_prototype_ptr * prototypes;
2767 /* todo: we need to implment some file name pattern matching */
2768 boost::tie(prototypes, count) = wrap_synthdefs(sc_read_synthdefs_file(path.c_str()));
2770 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(d_load_rt2<realtime>, prototypes, count, msg, endpoint));
2773 template <bool realtime>
2774 void d_load_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2775 nova_endpoint const & endpoint)
2777 std::for_each(prototypes, prototypes + prototype_count,
2778 boost::bind(&synth_factory::register_prototype, instance, _1));
2780 msg.handle(endpoint);
2781 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_load_nrt3, prototypes, endpoint));
2784 void d_load_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint)
2786 delete[] prototypes;
2787 send_done_message(endpoint, "/d_load");
2791 template <bool realtime>
2792 void handle_d_load(received_message const & msg,
2793 nova_endpoint const & endpoint)
2795 osc::ReceivedMessageArgumentIterator args = msg.ArgumentsBegin();
2796 const char * path = args->AsString(); args++;
2797 completion_message message = extract_completion_message(args);
2799 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_load_nrt<realtime>, movable_string(path),
2800 message, endpoint));
2804 template <bool realtime>
2805 void d_loadDir_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2806 nova_endpoint const & endpoint);
2807 void d_loadDir_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint);
2809 template <bool realtime>
2810 void d_loadDir_nrt1(movable_string & path, completion_message & msg, nova_endpoint const & endpoint)
2812 size_t count;
2813 sc_synth_prototype_ptr * prototypes;
2814 boost::tie(prototypes, count) = wrap_synthdefs(sc_read_synthdefs_dir(path.c_str()));
2816 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(d_loadDir_rt2<realtime>, prototypes, count, msg, endpoint));
2819 template <bool realtime>
2820 void d_loadDir_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2821 nova_endpoint const & endpoint)
2823 std::for_each(prototypes, prototypes + prototype_count,
2824 boost::bind(&synth_factory::register_prototype, instance, _1));
2826 msg.handle(endpoint);
2827 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_loadDir_nrt3, prototypes, endpoint));
2830 void d_loadDir_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint)
2832 delete[] prototypes;
2833 send_done_message(endpoint, "/d_loadDir");
2836 template <bool realtime>
2837 void handle_d_loadDir(received_message const & msg,
2838 nova_endpoint const & endpoint)
2840 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2841 const char * path;
2843 args >> path;
2844 completion_message message = extract_completion_message(args);
2846 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_loadDir_nrt1<realtime>,
2847 movable_string(path), message, endpoint));
2851 void handle_d_free(received_message const & msg)
2853 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2855 while(!args.Eos())
2857 const char * defname;
2858 args >> defname;
2860 instance->remove_prototype(defname);
2864 void insert_parallel_group(int node_id, int action, int target_id)
2866 if (node_id == -1)
2867 node_id = instance->generate_node_id();
2868 else if (!check_node_id(node_id))
2869 return;
2871 server_node * target = find_node(target_id);
2872 if(!target)
2873 return;
2875 node_position_constraint pos = make_pair(target, node_position(action));
2876 if (!node_position_sanity_check(pos))
2877 return;
2879 instance->add_parallel_group(node_id, pos);
2880 last_generated = node_id;
2883 void handle_p_new(received_message const & msg)
2885 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2887 while(!args.Eos()) {
2888 osc::int32 id, action, target;
2889 args >> id >> action >> target;
2891 insert_parallel_group(id, action, target);
2895 void handle_u_cmd(received_message const & msg, int size)
2897 sc_msg_iter args(size, msg.AddressPattern());
2899 int node_id = args.geti();
2901 server_node * target_synth = find_node(node_id);
2903 if (target_synth == NULL || target_synth->is_group())
2904 return;
2906 sc_synth * synth = static_cast<sc_synth*>(target_synth);
2908 int ugen_index = args.geti();
2909 const char * cmd_name = args.gets();
2911 synth->apply_unit_cmd(cmd_name, ugen_index, &args);
2914 void handle_cmd(received_message const & msg, int size, nova_endpoint const & endpoint, int skip_bytes)
2916 sc_msg_iter args(size, msg.AddressPattern() + skip_bytes);
2918 const char * cmd = args.gets();
2920 sc_factory->run_cmd_plugin(&sc_factory->world, cmd, &args, const_cast<nova_endpoint*>(&endpoint));
2923 } /* namespace */
2925 template <bool realtime>
2926 void sc_osc_handler::handle_message_int_address(received_message const & message,
2927 size_t msg_size, nova_endpoint const & endpoint)
2929 uint32_t address = message.AddressPatternAsUInt32();
2931 switch (address)
2933 case cmd_quit:
2934 handle_quit<realtime>(endpoint);
2935 break;
2937 case cmd_s_new:
2938 handle_s_new(message);
2939 break;
2941 case cmd_s_noid:
2942 handle_s_noid(message);
2943 break;
2945 case cmd_s_get:
2946 handle_s_get<realtime>(message, msg_size, endpoint);
2947 break;
2949 case cmd_s_getn:
2950 handle_s_getn<realtime>(message, msg_size, endpoint);
2951 break;
2953 case cmd_notify:
2954 handle_notify<realtime>(message, endpoint);
2955 break;
2957 case cmd_status:
2958 handle_status<realtime>(endpoint);
2959 break;
2961 case cmd_dumpOSC:
2962 handle_dumpOSC(message);
2963 break;
2965 case cmd_sync:
2966 handle_sync<realtime>(message, endpoint);
2967 break;
2969 case cmd_clearSched:
2970 handle_clearSched();
2971 break;
2973 case cmd_error:
2974 handle_error(message);
2975 break;
2977 case cmd_g_new:
2978 handle_g_new(message);
2979 break;
2981 case cmd_g_head:
2982 handle_g_head_or_tail<head>(message);
2983 break;
2985 case cmd_g_tail:
2986 handle_g_head_or_tail<tail>(message);
2987 break;
2989 case cmd_g_freeAll:
2990 handle_g_freeall(message);
2991 break;
2993 case cmd_g_deepFree:
2994 handle_g_deepFree(message);
2995 break;
2997 case cmd_g_queryTree:
2998 handle_g_queryTree<realtime>(message, endpoint);
2999 break;
3001 case cmd_g_dumpTree:
3002 handle_g_dumpTree(message);
3003 break;
3005 case cmd_n_free:
3006 handle_n_free(message);
3007 break;
3009 case cmd_n_set:
3010 handle_n_set(message);
3011 break;
3013 case cmd_n_setn:
3014 handle_n_setn(message);
3015 break;
3017 case cmd_n_fill:
3018 handle_n_fill(message);
3019 break;
3021 case cmd_n_map:
3022 handle_n_map(message);
3023 break;
3025 case cmd_n_mapn:
3026 handle_n_mapn(message);
3027 break;
3029 case cmd_n_mapa:
3030 handle_n_mapa(message);
3031 break;
3033 case cmd_n_mapan:
3034 handle_n_mapan(message);
3035 break;
3037 case cmd_n_query:
3038 handle_n_query(message, endpoint);
3039 break;
3041 case cmd_n_order:
3042 handle_n_order(message);
3043 break;
3045 case cmd_n_run:
3046 handle_n_run(message);
3047 break;
3049 case cmd_n_before:
3050 handle_n_before_or_after<before>(message);
3051 break;
3053 case cmd_n_after:
3054 handle_n_before_or_after<after>(message);
3055 break;
3057 case cmd_n_trace:
3058 handle_n_trace(message);
3059 break;
3061 case cmd_b_alloc:
3062 handle_b_alloc<realtime>(message, endpoint);
3063 break;
3065 case cmd_u_cmd:
3066 handle_u_cmd(message, msg_size);
3067 break;
3069 case cmd_b_free:
3070 handle_b_free<realtime>(message, endpoint);
3071 break;
3073 case cmd_b_allocRead:
3074 handle_b_allocRead<realtime>(message, endpoint);
3075 break;
3077 case cmd_b_allocReadChannel:
3078 handle_b_allocReadChannel<realtime>(message, endpoint);
3079 break;
3081 case cmd_b_read:
3082 handle_b_read<realtime>(message, endpoint);
3083 break;
3085 case cmd_b_readChannel:
3086 handle_b_readChannel<realtime>(message, endpoint);
3087 break;
3089 case cmd_b_write:
3090 handle_b_write<realtime>(message, endpoint);
3091 break;
3093 case cmd_b_zero:
3094 handle_b_zero<realtime>(message, endpoint);
3095 break;
3097 case cmd_b_set:
3098 handle_b_set(message);
3099 break;
3101 case cmd_b_setn:
3102 handle_b_setn(message);
3103 break;
3105 case cmd_b_fill:
3106 handle_b_fill(message);
3107 break;
3109 case cmd_b_query:
3110 handle_b_query<realtime>(message, endpoint);
3111 break;
3113 case cmd_b_get:
3114 handle_b_get<realtime>(message, endpoint);
3115 break;
3117 case cmd_b_getn:
3118 handle_b_getn<realtime>(message, endpoint);
3119 break;
3121 case cmd_b_gen:
3122 handle_b_gen<realtime>(message, msg_size, endpoint);
3123 break;
3125 case cmd_b_close:
3126 handle_b_close<realtime>(message, endpoint);
3127 break;
3129 case cmd_c_set:
3130 handle_c_set(message);
3131 break;
3133 case cmd_c_setn:
3134 handle_c_setn(message);
3135 break;
3137 case cmd_c_fill:
3138 handle_c_fill(message);
3139 break;
3141 case cmd_c_get:
3142 handle_c_get<realtime>(message, endpoint);
3143 break;
3145 case cmd_c_getn:
3146 handle_c_getn<realtime>(message, endpoint);
3147 break;
3149 case cmd_d_recv:
3150 handle_d_recv<realtime>(message, endpoint);
3151 break;
3153 case cmd_d_load:
3154 handle_d_load<realtime>(message, endpoint);
3155 break;
3157 case cmd_d_loadDir:
3158 handle_d_loadDir<realtime>(message, endpoint);
3159 break;
3161 case cmd_d_free:
3162 handle_d_free(message);
3163 break;
3165 case cmd_p_new:
3166 handle_p_new(message);
3167 break;
3169 case cmd_cmd:
3170 handle_cmd(message, msg_size, endpoint, 4);
3171 break;
3173 default:
3174 handle_unhandled_message(message);
3178 namespace
3181 template <bool realtime>
3182 void dispatch_group_commands(const char * address, received_message const & message,
3183 nova_endpoint const & endpoint)
3185 assert(address[1] == 'g');
3186 assert(address[2] == '_');
3188 if (strcmp(address+3, "new") == 0) {
3189 handle_g_new(message);
3190 return;
3192 if (strcmp(address+3, "head") == 0) {
3193 handle_g_head_or_tail<head>(message);
3194 return;
3196 if (strcmp(address+3, "tail") == 0) {
3197 handle_g_head_or_tail<tail>(message);
3198 return;
3200 if (strcmp(address+3, "freeAll") == 0) {
3201 handle_g_freeall(message);
3202 return;
3204 if (strcmp(address+3, "deepFree") == 0) {
3205 handle_g_deepFree(message);
3206 return;
3208 if (strcmp(address+3, "queryTree") == 0) {
3209 handle_g_queryTree<realtime>(message, endpoint);
3210 return;
3213 if (strcmp(address+3, "dumpTree") == 0) {
3214 handle_g_dumpTree(message);
3215 return;
3219 template <bool realtime>
3220 void dispatch_node_commands(const char * address, received_message const & message,
3221 nova_endpoint const & endpoint)
3223 assert(address[1] == 'n');
3224 assert(address[2] == '_');
3226 if (strcmp(address+3, "free") == 0) {
3227 handle_n_free(message);
3228 return;
3231 if (strcmp(address+3, "set") == 0) {
3232 handle_n_set(message);
3233 return;
3236 if (strcmp(address+3, "setn") == 0) {
3237 handle_n_setn(message);
3238 return;
3241 if (strcmp(address+3, "fill") == 0) {
3242 handle_n_fill(message);
3243 return;
3246 if (strcmp(address+3, "map") == 0) {
3247 handle_n_map(message);
3248 return;
3251 if (strcmp(address+3, "mapn") == 0) {
3252 handle_n_mapn(message);
3253 return;
3256 if (strcmp(address+3, "mapa") == 0) {
3257 handle_n_mapa(message);
3258 return;
3261 if (strcmp(address+3, "mapan") == 0) {
3262 handle_n_mapan(message);
3263 return;
3266 if (strcmp(address+3, "run") == 0) {
3267 handle_n_run(message);
3268 return;
3271 if (strcmp(address+3, "before") == 0) {
3272 handle_n_before_or_after<before>(message);
3273 return;
3276 if (strcmp(address+3, "after") == 0) {
3277 handle_n_before_or_after<after>(message);
3278 return;
3281 if (strcmp(address+3, "order") == 0) {
3282 handle_n_order(message);
3283 return;
3286 if (strcmp(address+3, "query") == 0) {
3287 handle_n_query(message, endpoint);
3288 return;
3291 if (strcmp(address+3, "trace") == 0) {
3292 handle_n_trace(message);
3293 return;
3297 template <bool realtime>
3298 void dispatch_buffer_commands(const char * address, received_message const & message,
3299 size_t msg_size, nova_endpoint const & endpoint)
3301 assert(address[1] == 'b');
3302 assert(address[2] == '_');
3304 if (strcmp(address+3, "alloc") == 0) {
3305 handle_b_alloc<realtime>(message, endpoint);
3306 return;
3309 if (strcmp(address+3, "free") == 0) {
3310 handle_b_free<realtime>(message, endpoint);
3311 return;
3314 if (strcmp(address+3, "allocRead") == 0) {
3315 handle_b_allocRead<realtime>(message, endpoint);
3316 return;
3318 if (strcmp(address+3, "allocReadChannel") == 0) {
3319 handle_b_allocReadChannel<realtime>(message, endpoint);
3320 return;
3323 if (strcmp(address+3, "read") == 0) {
3324 handle_b_read<realtime>(message, endpoint);
3325 return;
3328 if (strcmp(address+3, "readChannel") == 0) {
3329 handle_b_readChannel<realtime>(message, endpoint);
3330 return;
3333 if (strcmp(address+3, "write") == 0) {
3334 handle_b_write<realtime>(message, endpoint);
3335 return;
3338 if (strcmp(address+3, "zero") == 0) {
3339 handle_b_zero<realtime>(message, endpoint);
3340 return;
3343 if (strcmp(address+3, "set") == 0) {
3344 handle_b_set(message);
3345 return;
3348 if (strcmp(address+3, "setn") == 0) {
3349 handle_b_setn(message);
3350 return;
3353 if (strcmp(address+3, "fill") == 0) {
3354 handle_b_fill(message);
3355 return;
3358 if (strcmp(address+3, "query") == 0) {
3359 handle_b_query<realtime>(message, endpoint);
3360 return;
3363 if (strcmp(address+3, "get") == 0) {
3364 handle_b_get<realtime>(message, endpoint);
3365 return;
3368 if (strcmp(address+3, "getn") == 0) {
3369 handle_b_getn<realtime>(message, endpoint);
3370 return;
3373 if (strcmp(address+3, "gen") == 0) {
3374 handle_b_gen<realtime>(message, msg_size, endpoint);
3375 return;
3378 if (strcmp(address+3, "close") == 0) {
3379 handle_b_close<realtime>(message, endpoint);
3380 return;
3384 template <bool realtime>
3385 void dispatch_control_bus_commands(const char * address, received_message const & message,
3386 nova_endpoint const & endpoint)
3388 assert(address[1] == 'c');
3389 assert(address[2] == '_');
3391 if (strcmp(address+3, "set") == 0) {
3392 handle_c_set(message);
3393 return;
3396 if (strcmp(address+3, "setn") == 0) {
3397 handle_c_setn(message);
3398 return;
3401 if (strcmp(address+3, "fill") == 0) {
3402 handle_c_fill(message);
3403 return;
3406 if (strcmp(address+3, "get") == 0) {
3407 handle_c_get<realtime>(message, endpoint);
3408 return;
3411 if (strcmp(address+3, "getn") == 0) {
3412 handle_c_getn<realtime>(message, endpoint);
3413 return;
3417 template <bool realtime>
3418 void dispatch_synthdef_commands(const char * address, received_message const & message,
3419 nova_endpoint const & endpoint)
3421 assert(address[1] == 'd');
3422 assert(address[2] == '_');
3424 if (strcmp(address+3, "recv") == 0) {
3425 handle_d_recv<realtime>(message, endpoint);
3426 return;
3429 if (strcmp(address+3, "load") == 0) {
3430 handle_d_load<realtime>(message, endpoint);
3431 return;
3434 if (strcmp(address+3, "loadDir") == 0) {
3435 handle_d_loadDir<realtime>(message, endpoint);
3436 return;
3439 if (strcmp(address+3, "free") == 0) {
3440 handle_d_free(message);
3441 return;
3445 template <bool realtime>
3446 void dispatch_synth_commands(const char * address, received_message const & message, size_t msg_size,
3447 nova_endpoint const & endpoint)
3449 assert(address[1] == 's');
3450 assert(address[2] == '_');
3452 if (strcmp(address+3, "new") == 0) {
3453 handle_s_new(message);
3454 return;
3457 if (strcmp(address+3, "noid") == 0) {
3458 handle_s_noid(message);
3459 return;
3462 if (strcmp(address+3, "get") == 0) {
3463 handle_s_get<realtime>(message, msg_size, endpoint);
3464 return;
3467 if (strcmp(address+3, "getn") == 0) {
3468 handle_s_getn<realtime>(message, msg_size, endpoint);
3469 return;
3473 } /* namespace */
3475 template <bool realtime>
3476 void sc_osc_handler::handle_message_sym_address(received_message const & message,
3477 size_t msg_size, nova_endpoint const & endpoint)
3479 const char * address = message.AddressPattern();
3481 /* scsynth doesn't require the leading / */
3482 if(address[0] != '/')
3483 address -= 1;
3485 if (address[2] == '_')
3487 if (address[1] == 'g') {
3488 dispatch_group_commands<realtime>(address, message, endpoint);
3489 return;
3492 if (address[1] == 'n') {
3493 dispatch_node_commands<realtime>(address, message, endpoint);
3494 return;
3497 if (address[1] == 'b') {
3498 dispatch_buffer_commands<realtime>(address, message, msg_size, endpoint);
3499 return;
3502 if (address[1] == 'c') {
3503 dispatch_control_bus_commands<realtime>(address, message, endpoint);
3504 return;
3507 if (address[1] == 'd') {
3508 dispatch_synthdef_commands<realtime>(address, message, endpoint);
3509 return;
3512 if (address[1] == 's') {
3513 dispatch_synth_commands<realtime>(address, message, msg_size, endpoint);
3514 return;
3518 if (strcmp(address+1, "p_new") == 0) {
3519 handle_p_new(message);
3520 return;
3523 if (strcmp(address+1, "u_cmd") == 0) {
3524 handle_u_cmd(message, msg_size);
3525 return;
3528 if (strcmp(address+1, "status") == 0) {
3529 handle_status<realtime>(endpoint);
3530 return;
3533 if (strcmp(address+1, "sync") == 0) {
3534 handle_sync<realtime>(message, endpoint);
3535 return;
3538 if (strcmp(address+1, "quit") == 0) {
3539 handle_quit<realtime>(endpoint);
3540 return;
3543 if (strcmp(address+1, "notify") == 0) {
3544 handle_notify<realtime>(message, endpoint);
3545 return;
3548 if (strcmp(address+1, "dumpOSC") == 0) {
3549 handle_dumpOSC(message);
3550 return;
3553 if (strcmp(address+1, "clearSched") == 0) {
3554 handle_clearSched();
3555 return;
3558 if (strcmp(address+1, "error") == 0) {
3559 handle_error(message);
3560 return;
3563 if (strcmp(address+1, "cmd") == 0) {
3564 handle_cmd(message, msg_size, endpoint, 8);
3565 return;
3568 handle_unhandled_message(message);
3572 template <bool realtime>
3573 void handle_asynchronous_plugin_cleanup(World * world, void *cmdData,
3574 AsyncFreeFn cleanup)
3576 if (cleanup)
3577 (cleanup)(world, cmdData);
3580 template <bool realtime>
3581 void handle_asynchronous_plugin_stage4(World * world, const char * cmdName, void *cmdData, AsyncStageFn stage4,
3582 AsyncFreeFn cleanup, completion_message & msg, nova_endpoint const & endpoint)
3584 if (stage4)
3585 (stage4)(world, cmdData);
3587 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(handle_asynchronous_plugin_cleanup<realtime>, world, cmdData,
3588 cleanup));
3590 send_done_message(endpoint, cmdName);
3593 template <bool realtime>
3594 void handle_asynchronous_plugin_stage3(World * world, const char * cmdName, void *cmdData, AsyncStageFn stage3, AsyncStageFn stage4,
3595 AsyncFreeFn cleanup, completion_message & msg, nova_endpoint const & endpoint)
3597 if (stage3) {
3598 bool success = (stage3)(world, cmdData);
3599 if (success)
3600 msg.handle(endpoint);
3602 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage4<realtime>, world, cmdName,
3603 cmdData, stage4, cleanup, msg, endpoint));
3606 template <bool realtime>
3607 void handle_asynchronous_plugin_stage2(World * world, const char * cmdName, void *cmdData, AsyncStageFn stage2,
3608 AsyncStageFn stage3, AsyncStageFn stage4,
3609 AsyncFreeFn cleanup, completion_message & msg, nova_endpoint const & endpoint)
3611 if (stage2)
3612 (stage2)(world, cmdData);
3614 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(handle_asynchronous_plugin_stage3<realtime>, world, cmdName,
3615 cmdData, stage3, stage4,
3616 cleanup, msg, endpoint));
3619 void sc_osc_handler::do_asynchronous_command(World * world, void* replyAddr, const char* cmdName, void *cmdData,
3620 AsyncStageFn stage2, AsyncStageFn stage3, AsyncStageFn stage4, AsyncFreeFn cleanup,
3621 int completionMsgSize, void* completionMsgData)
3623 completion_message msg(completionMsgSize, completionMsgData);
3624 nova_endpoint endpoint(*static_cast<nova_endpoint*>(replyAddr));
3626 if (world->mRealTime)
3627 cmd_dispatcher<true>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage2<true>, world, cmdName,
3628 cmdData, stage2, stage3, stage4, cleanup, msg, endpoint));
3629 else
3630 cmd_dispatcher<false>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage2<false>, world, cmdName,
3631 cmdData, stage2, stage3, stage4, cleanup, msg, endpoint));
3635 } /* namespace detail */
3636 } /* namespace nova */