Fix scvim regsitry file for updated filename (thanks Carlo Capocasa)
[supercollider.git] / server / supernova / sc / sc_osc_handler.cpp
blob6b7d5c49aef09925654c7b6514daf608246061e8
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 #ifdef _WIN32
32 #include "malloc.h" // for alloca
33 #endif
35 namespace nova {
37 using namespace std;
39 namespace {
41 int32_t last_generated = 0;
43 server_node * find_node(int32_t target_id)
45 if (target_id == -1)
46 target_id = last_generated;
48 server_node * node = instance->find_node(target_id);
50 if (node == NULL)
51 log_printf("node not found: %d\n", target_id);
53 return node;
56 abstract_group * find_group(int32_t target_id)
58 if (target_id == -1)
59 target_id = last_generated;
61 abstract_group * node = instance->find_group(target_id);
63 if (node == NULL)
64 log("node not found or not a group\n");
65 return node;
68 bool check_node_id(int node_id)
70 if (!instance->node_id_available(node_id)) {
71 log("node id %d already in use\n", node_id);
72 return false;
74 return true;
77 void fill_notification(const server_node * node, osc::OutboundPacketStream & p)
79 p << node->id();
81 /* parent */
82 const abstract_group * parent_node = node->get_parent();
83 assert(parent_node);
84 p << parent_node->id();
86 /* previous/next */
87 if (parent_node->is_parallel())
88 p << -2 << -2; /* we are in a parallel group, so we have no notion of previous/next */
89 else
91 const server_node * prev_node = node->previous_node();
92 if (prev_node)
93 p << prev_node->id();
94 else
95 p << -1;
97 const server_node * next_node = node->next_node();
98 if (next_node)
99 p << next_node->id();
100 else
101 p << -1;
104 /* is_synth, head, tail */
105 if (node->is_synth())
106 p << 0;
107 else {
108 const abstract_group * node_group = static_cast<const abstract_group*>(node);
109 p << 1;
111 if (node_group->is_parallel())
112 p << -2 << -2;
113 else
115 const group * node_real_group = static_cast<const group*>(node_group);
116 if (node_real_group->empty())
117 p << -1 << -1;
118 else
119 p << node_real_group->head_node()->id()
120 << node_real_group->tail_node()->id();
124 p << osc::EndMessage;
127 spin_lock system_callback_allocator_lock;
129 struct movable_string
131 /** allocate new string, only allowed to be called from the rt context */
132 explicit movable_string(const char * str)
134 size_t length = strlen(str) + 1; /* terminating \0 */
135 char * data = (char*)system_callback::allocate(length);
136 strcpy(data, str);
137 data_ = data;
140 /** copy constructor has move semantics!!! */
141 movable_string(movable_string const & rhs)
143 data_ = rhs.data_;
144 const_cast<movable_string&>(rhs).data_ = NULL;
147 ~movable_string(void)
149 if (data_)
150 system_callback::deallocate((char*)data_);
153 const char * c_str(void) const
155 return data_;
158 private:
159 const char * data_;
162 template <typename T>
163 struct movable_array
165 /** allocate new array, only allowed to be called from the rt context */
166 movable_array(size_t length, const T * data, bool locked = false):
167 length_(length)
169 data_ = (T*)system_callback::allocate(length * sizeof(T));
170 for (size_t i = 0; i != length; ++i)
171 data_[i] = data[i];
174 /** copy constructor has move semantics!!! */
175 movable_array(movable_array const & rhs)
177 length_ = rhs.length_;
178 data_ = rhs.data_;
179 const_cast<movable_array&>(rhs).data_ = NULL;
182 ~movable_array(void)
184 if (data_)
185 system_callback::deallocate((char*)data_);
188 const T * data(void) const
190 return data_;
193 const T & operator[](size_t index) const
195 return data_[index];
198 size_t size(void) const
200 return length_;
203 private:
204 size_t length_;
205 T * data_;
208 void send_done_message(nova_endpoint const & endpoint)
210 char buffer[128];
211 osc::OutboundPacketStream p(buffer, 128);
212 p << osc::BeginMessage("/done")
213 << osc::EndMessage;
215 instance->send(p.Data(), p.Size(), endpoint);
218 void send_done_message(nova_endpoint const & endpoint, const char * cmd)
220 char buffer[128];
221 osc::OutboundPacketStream p(buffer, 128);
222 p << osc::BeginMessage("/done")
223 << cmd
224 << osc::EndMessage;
226 instance->send(p.Data(), p.Size(), endpoint);
229 void send_done_message(nova_endpoint const & endpoint, const char * cmd, osc::int32 index)
231 char buffer[128];
232 osc::OutboundPacketStream p(buffer, 128);
233 p << osc::BeginMessage("/done")
234 << cmd
235 << index
236 << osc::EndMessage;
238 instance->send(p.Data(), p.Size(), endpoint);
241 template <typename Functor>
242 struct fn_system_callback:
243 public system_callback
245 fn_system_callback (Functor const & fn):
246 fn_(fn)
249 void run(void)
251 fn_();
254 Functor fn_;
257 template <typename Functor>
258 struct fn_sync_callback:
259 public audio_sync_callback
261 fn_sync_callback (Functor const & fn):
262 fn_(fn)
265 void run(void)
267 fn_();
270 Functor fn_;
273 /** helper class for dispatching real-time and non real-time osc command callbacks
275 * uses template specialization to avoid unnecessary callback rescheduling
277 template <bool realtime>
278 struct cmd_dispatcher
280 template <typename Functor>
281 static void fire_system_callback(Functor const & f)
283 instance->add_system_callback(new fn_system_callback<Functor>(f));
286 template <typename Functor>
287 static void fire_io_callback(Functor const & f)
289 instance->add_io_callback(new fn_system_callback<Functor>(f));
292 template <typename Functor>
293 static void fire_rt_callback(Functor const & f)
295 instance->add_sync_callback(new fn_sync_callback<Functor>(f));
298 static void fire_done_message(nova_endpoint const & endpoint, const char * cmd, osc::int32 index)
300 fire_io_callback(boost::bind(send_done_message, endpoint, cmd, index));
304 template <>
305 struct cmd_dispatcher<false>
307 template <typename Functor>
308 static void fire_system_callback(Functor f)
310 f();
313 template <typename Functor>
314 static void fire_rt_callback(Functor f)
316 f();
319 template <typename Functor>
320 static void fire_io_callback(Functor f)
322 f();
325 static void fire_done_message(nova_endpoint const & endpoint, const char * cmd, osc::int32 index)
327 send_done_message (endpoint, cmd, index);
331 } /* namespace */
333 namespace detail {
334 using nova::log;
336 void fire_notification(movable_array<char> & msg)
338 instance->send_notification(msg.data(), msg.size());
341 void sc_notify_observers::notify(const char * address_pattern, const server_node * node)
343 char buffer[128]; // 128 byte should be enough
344 osc::OutboundPacketStream p(buffer, 128);
345 p << osc::BeginMessage(address_pattern);
346 fill_notification(node, p);
348 movable_array<char> message(p.Size(), p.Data());
349 cmd_dispatcher<true>::fire_io_callback(boost::bind(fire_notification, message));
352 void fire_trigger(int32_t node_id, int32_t trigger_id, float value)
354 char buffer[128]; // 128 byte should be enough
355 osc::OutboundPacketStream p(buffer, 128);
356 p << osc::BeginMessage("/tr") << osc::int32(node_id) << osc::int32(trigger_id) << value
357 << osc::EndMessage;
359 instance->send_notification(p.Data(), p.Size());
362 void sc_notify_observers::send_trigger(int32_t node_id, int32_t trigger_id, float value)
364 cmd_dispatcher<true>::fire_io_callback(boost::bind(fire_trigger, node_id, trigger_id, value));
367 void free_mem_callback(movable_string & cmd,
368 movable_array<float> & values)
371 void fire_node_reply(int32_t node_id, int reply_id, movable_string & cmd,
372 movable_array<float> & values)
374 size_t buffer_size = 1024 + strlen(cmd.c_str()) + values.size()*sizeof(float);
376 char * buffer = (buffer_size < 2048) ? (char*)alloca(buffer_size)
377 : (char*)malloc(buffer_size);
379 try {
380 osc::OutboundPacketStream p(buffer, buffer_size);
381 p << osc::BeginMessage(cmd.c_str()) << osc::int32(node_id) << osc::int32(reply_id);
383 for (int i = 0; i != values.size(); ++i)
384 p << values[i];
386 p << osc::EndMessage;
388 instance->send_notification(p.Data(), p.Size());
390 cmd_dispatcher<true>::fire_rt_callback(boost::bind(free_mem_callback, cmd, values));
391 } catch (...) {
394 if (buffer_size >= 2048)
395 free(buffer);
398 void sc_notify_observers::send_node_reply(int32_t node_id, int reply_id, const char* command_name,
399 int argument_count, const float* values)
401 spin_lock::scoped_lock lock(system_callback_allocator_lock); // called from rt helper threads, so we need to lock the memory pool
402 movable_string cmd(command_name);
403 movable_array<float> value_array(argument_count, values);
405 cmd_dispatcher<true>::fire_io_callback(boost::bind(fire_node_reply, node_id, reply_id, cmd, value_array));
408 void sc_notify_observers::send_notification(const char * data, size_t length)
410 for (size_t i = 0; i != observers.size(); ++i)
411 send_notification(data, length, observers[i]);
414 void sc_notify_observers::send_notification(const char * data, size_t length, nova_endpoint const & endpoint)
416 nova_protocol const & prot = endpoint.protocol();
417 if (prot.family() == AF_INET && prot.type() == SOCK_DGRAM)
419 udp::endpoint ep(endpoint.address(), endpoint.port());
420 send_udp(data, length, ep);
422 else if (prot.family() == AF_INET && prot.type() == SOCK_STREAM)
424 tcp::endpoint ep(endpoint.address(), endpoint.port());
425 send_tcp(data, length, ep);
431 void sc_scheduled_bundles::bundle_node::run(void)
433 typedef osc::ReceivedBundleElement bundle_element;
434 typedef osc::ReceivedBundle received_bundle;
435 typedef osc::ReceivedMessage received_message;
437 bundle_element element(data_);
439 if (element.IsBundle()) {
440 received_bundle bundle(element);
441 instance->handle_bundle<true>(bundle, endpoint_);
442 } else {
443 received_message message(element);
444 instance->handle_message<true>(message, element.Size(), endpoint_);
448 void sc_scheduled_bundles::insert_bundle(time_tag const & timeout, const char * data, size_t length,
449 nova_endpoint const & endpoint)
451 /* allocate chunk from realtime pool */
452 void * chunk = rt_pool.malloc(sizeof(bundle_node) + length+4);
453 bundle_node * node = (bundle_node*)chunk;
454 char * cpy = (char*)chunk + sizeof(bundle_node);
456 memcpy(cpy, data - 4, length+4);
458 new(node) bundle_node(timeout, cpy, endpoint);
460 bundle_q.insert(*node);
463 void sc_scheduled_bundles::execute_bundles(time_tag const & last, time_tag const & now)
465 World * world = &sc_factory->world;
467 while(!bundle_q.empty()) {
468 bundle_node & front = *bundle_q.top();
469 time_tag const & next_timestamp = front.timeout_;
471 if (now < next_timestamp)
472 break;
474 if (last < next_timestamp) {
475 // between last and now
476 time_tag time_since_last = next_timestamp - last;
477 float samples_since_last = time_since_last.to_samples(world->mSampleRate);
479 float sample_offset;
480 float subsample_offset = std::modf(samples_since_last, &sample_offset);
482 world->mSampleOffset = (int)sample_offset;
483 world->mSubsampleOffset = subsample_offset;
484 } else
485 world->mSampleOffset = world->mSubsampleOffset = 0;
487 front.run();
488 bundle_q.erase_and_dispose(bundle_q.top(), &dispose_bundle);
491 world->mSampleOffset = world->mSubsampleOffset = 0;
495 void sc_osc_handler::open_tcp_acceptor(tcp const & protocol, unsigned int port)
497 tcp_acceptor_.open(protocol);
498 tcp_acceptor_.bind(tcp::endpoint(protocol, port));
499 tcp_acceptor_.listen();
502 void sc_osc_handler::open_udp_socket(udp const & protocol, unsigned int port)
504 sc_notify_observers::udp_socket.open(protocol);
505 sc_notify_observers::udp_socket.bind(udp::endpoint(protocol, port));
508 bool sc_osc_handler::open_socket(int family, int type, int protocol, unsigned int port)
510 if (protocol == IPPROTO_TCP)
512 if ( type != SOCK_STREAM )
513 return false;
515 if (family == AF_INET)
516 open_tcp_acceptor(tcp::v4(), port);
517 else if (family == AF_INET6)
518 open_tcp_acceptor(tcp::v6(), port);
519 else
520 return false;
521 return true;
523 else if (protocol == IPPROTO_UDP)
525 if ( type != SOCK_DGRAM )
526 return false;
528 if (family == AF_INET)
529 open_udp_socket(udp::v4(), port);
530 else if (family == AF_INET6)
531 open_udp_socket(udp::v6(), port);
532 else
533 return false;
534 start_receive_udp();
535 return true;
537 return false;
540 void sc_osc_handler::handle_receive_udp(const boost::system::error_code& error,
541 std::size_t bytes_transferred)
543 if (unlikely(error == error::operation_aborted))
544 return; /* we're done */
546 if (error == error::message_size) {
547 overflow_vector.insert(overflow_vector.end(),
548 recv_buffer_.begin(), recv_buffer_.end());
549 return;
552 if (error) {
553 std::cout << "sc_osc_handler received error code " << error << std::endl;
554 start_receive_udp();
555 return;
558 if (overflow_vector.empty())
559 handle_packet_async(recv_buffer_.begin(), bytes_transferred, udp_remote_endpoint_);
560 else {
561 overflow_vector.insert(overflow_vector.end(), recv_buffer_.begin(), recv_buffer_.end());
562 #ifdef __PATHCC__
563 handle_packet_async(&overflow_vector.front(), overflow_vector.size(), udp_remote_endpoint_);
564 #else
565 handle_packet_async(overflow_vector.data(), overflow_vector.size(), udp_remote_endpoint_);
566 #endif
567 overflow_vector.clear();
570 start_receive_udp();
571 return;
574 void sc_osc_handler::tcp_connection::start(sc_osc_handler * self)
576 bool check_password = true;
578 if (check_password) {
579 boost::array<char, 32> password;
580 size_t size;
581 uint32_t msglen;
582 for (unsigned int i=0; i!=4; ++i) {
583 size = socket_.receive(boost::asio::buffer(&msglen, 4));
584 if (size != 4)
585 return;
587 msglen = ntohl(msglen);
588 if (msglen > password.size())
589 return;
591 size = socket_.receive(boost::asio::buffer(password.data(), msglen));
593 bool verified = true;
594 if (size != msglen ||
595 strcmp(password.data(), self->tcp_password_) != 0)
596 verified = false;
598 if (!verified)
599 throw std::runtime_error("cannot verify password");
603 size_t size;
604 uint32_t msglen;
605 size = socket_.receive(boost::asio::buffer(&msglen, 4));
606 if (size != sizeof(uint32_t))
607 throw std::runtime_error("read error");
609 msglen = ntohl(msglen);
611 sized_array<char> recv_vector(msglen + sizeof(uint32_t));
613 std::memcpy((void*)recv_vector.data(), &msglen, sizeof(uint32_t));
614 size_t transfered = socket_.read_some(boost::asio::buffer((void*)(recv_vector.data()+sizeof(uint32_t)),
615 recv_vector.size()-sizeof(uint32_t)));
617 if (transfered != size_t(msglen))
618 throw std::runtime_error("socket read sanity check failure");
620 self->handle_packet_async(recv_vector.data(), recv_vector.size(), socket_.remote_endpoint());
624 void sc_osc_handler::handle_packet_async(const char * data, size_t length,
625 nova_endpoint const & endpoint)
627 received_packet * p = received_packet::alloc_packet(data, length, endpoint);
629 if (dump_osc_packets == 1) {
630 osc_received_packet packet (data, length);
631 cout << "received osc packet " << packet << endl;
634 instance->add_sync_callback(p);
637 time_tag sc_osc_handler::handle_bundle_nrt(const char * data, size_t length)
639 osc_received_packet packet(data, length);
640 if (!packet.IsBundle())
641 throw std::runtime_error("packet needs to be an osc bundle");
643 received_bundle bundle(packet);
644 handle_bundle<false> (bundle, nova_endpoint());
645 return bundle.TimeTag();
649 sc_osc_handler::received_packet *
650 sc_osc_handler::received_packet::alloc_packet(const char * data, size_t length,
651 nova_endpoint const & remote_endpoint)
653 /* received_packet struct and data array are located in one memory chunk */
654 void * chunk = received_packet::allocate(sizeof(received_packet) + length);
655 received_packet * p = (received_packet*)chunk;
656 char * cpy = (char*)(chunk) + sizeof(received_packet);
657 memcpy(cpy, data, length);
659 new(p) received_packet(cpy, length, remote_endpoint);
660 return p;
663 void sc_osc_handler::received_packet::run(void)
665 instance->handle_packet(data, length, endpoint_);
668 void sc_osc_handler::handle_packet(const char * data, std::size_t length, nova_endpoint const & endpoint)
670 osc_received_packet packet(data, length);
671 if (packet.IsBundle())
673 received_bundle bundle(packet);
674 handle_bundle<true> (bundle, endpoint);
676 else
678 received_message message(packet);
679 handle_message<true> (message, packet.Size(), endpoint);
683 template <bool realtime>
684 void sc_osc_handler::handle_bundle(received_bundle const & bundle, nova_endpoint const & endpoint)
686 time_tag bundle_time = bundle.TimeTag();
688 typedef osc::ReceivedBundleElementIterator bundle_iterator;
689 typedef osc::ReceivedBundleElement bundle_element;
691 if (bundle_time <= now) {
692 for (bundle_iterator it = bundle.ElementsBegin(); it != bundle.ElementsEnd(); ++it) {
693 bundle_element const & element = *it;
695 if (element.IsBundle()) {
696 received_bundle inner_bundle(element);
697 handle_bundle<realtime>(inner_bundle, endpoint);
698 } else {
699 received_message message(element);
700 handle_message<realtime>(message, element.Size(), endpoint);
703 } else {
704 for (bundle_iterator it = bundle.ElementsBegin(); it != bundle.ElementsEnd(); ++it) {
705 bundle_element const & element = *it;
706 scheduled_bundles.insert_bundle(bundle_time, element.Contents(), element.Size(), endpoint);
711 template <bool realtime>
712 void sc_osc_handler::handle_message(received_message const & message, size_t msg_size,
713 nova_endpoint const & endpoint)
715 try {
716 if (message.AddressPatternIsUInt32())
717 handle_message_int_address<realtime>(message, msg_size, endpoint);
718 else
719 handle_message_sym_address<realtime>(message, msg_size, endpoint);
720 } catch (std::exception const & e) {
721 log_printf("exception in handle_message: %s\n", e.what());
725 namespace {
727 typedef sc_osc_handler::received_message received_message;
729 void send_udp_message(movable_array<char> data, nova_endpoint const & endpoint)
731 instance->send(data.data(), data.size(), endpoint);
735 int first_arg_as_int(received_message const & message)
737 osc::ReceivedMessageArgumentStream args = message.ArgumentStream();
738 osc::int32 val;
740 args >> val;
742 return val;
745 void quit_perform(nova_endpoint const & endpoint)
747 instance->prepare_to_terminate();
748 send_done_message(endpoint, "/quit");
749 instance->terminate();
752 template <bool realtime>
753 void handle_quit(nova_endpoint const & endpoint)
755 instance->quit_received = true;
756 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(quit_perform, endpoint));
759 void notify_perform(bool enable, nova_endpoint const & endpoint)
761 if (enable)
762 instance->add_observer(endpoint);
763 else
764 instance->remove_observer(endpoint);
765 send_done_message(endpoint, "/notify");
768 template <bool realtime>
769 void handle_notify(received_message const & message, nova_endpoint const & endpoint)
771 int enable = first_arg_as_int(message);
772 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(notify_perform, bool(enable), endpoint));
775 void status_perform(nova_endpoint const & endpoint)
777 if (unlikely(instance->quit_received)) // we don't reply once we are about to quit
778 return;
780 char buffer[1024];
781 typedef osc::int32 i32;
783 float peak_load, average_load;
784 instance->cpu_load(peak_load, average_load);
786 osc::OutboundPacketStream p(buffer, 1024);
787 p << osc::BeginMessage("/status.reply")
788 << (i32)1 /* unused */
789 << (i32)sc_factory->ugen_count() /* ugens */
790 << (i32)instance->synth_count() /* synths */
791 << (i32)instance->group_count() /* groups */
792 << (i32)instance->prototype_count() /* synthdefs */
793 << average_load /* average cpu % */
794 << peak_load /* peak cpu % */
795 << instance->get_samplerate() /* nominal samplerate */
796 << instance->get_samplerate() /* actual samplerate */
797 << osc::EndMessage;
799 instance->send(p.Data(), p.Size(), endpoint);
802 template <bool realtime>
803 void handle_status(nova_endpoint const & endpoint)
805 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(status_perform, endpoint));
808 void handle_dumpOSC(received_message const & message)
810 int val = first_arg_as_int(message);
811 val = min (1, val); /* we just support one way of dumping osc messages */
813 instance->dumpOSC(val); /* thread-safe */
816 void sync_perform(osc::int32 id, nova_endpoint const & endpoint)
818 char buffer[128];
819 osc::OutboundPacketStream p(buffer, 128);
820 p << osc::BeginMessage("/synced")
821 << id
822 << osc::EndMessage;
824 instance->send(p.Data(), p.Size(), endpoint);
827 template <bool realtime>
828 void handle_sync(received_message const & message, nova_endpoint const & endpoint)
830 int id = first_arg_as_int(message);
832 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(sync_perform, id, endpoint));
835 void handle_clearSched(void)
837 instance->clear_scheduled_bundles();
840 void handle_error(received_message const & message)
842 int val = first_arg_as_int(message);
844 instance->set_error_posting(val); /* thread-safe */
847 void handle_unhandled_message(received_message const & msg)
849 log_printf("unhandled message: %s\n", msg.AddressPattern());
852 static bool node_position_sanity_check(node_position_constraint const & constraint)
854 switch (constraint.second) {
855 case head:
856 case tail:
857 case insert: {
858 server_node * target = constraint.first;
859 if (!target->is_group()) {
860 log_printf("Invalid position constraint (target: %d, addAction: %d)\n", target->id(), constraint.second);
861 return false;
866 return true;
869 sc_synth * add_synth(const char * name, int node_id, int action, int target_id)
871 if (!check_node_id(node_id))
872 return 0;
874 server_node * target = find_node(target_id);
875 if (target == NULL)
876 return NULL;
878 node_position_constraint pos = make_pair(target, node_position(action));
879 if (!node_position_sanity_check(pos))
880 return NULL;
882 abstract_synth * synth = instance->add_synth(name, node_id, pos);
883 if (!synth)
884 log_printf("Cannot create synth (synthdef: %s, node id: %d)\n", name, node_id);
886 last_generated = node_id;
887 return static_cast<sc_synth*>(synth);
890 /* extract float or int32 as float from argument iterator */
891 inline float extract_float_argument(osc::ReceivedMessageArgumentIterator const & it)
893 if (it->IsFloat())
894 return it->AsFloatUnchecked();
895 if (it->IsInt32())
896 return float(it->AsInt32Unchecked());
897 if (it->IsInt64())
898 return float(it->AsInt64Unchecked());
900 throw std::runtime_error("type cannot be converted to float");
903 inline void verify_argument(osc::ReceivedMessageArgumentIterator const & it,
904 osc::ReceivedMessageArgumentIterator const & end)
906 if (it == end)
907 throw std::runtime_error("unexpected end of argument list");
910 template <bool IsAudio, typename slot_type>
911 static void apply_control_bus_mapping(server_node & node, slot_type slot, int bus_index);
913 template <typename control_id_type>
914 void set_control_array(server_node * node, control_id_type control, osc::ReceivedMessageArgumentIterator & it)
916 size_t array_size = it->ArraySize(); ++it;
918 if (it->IsArrayStart()) {
919 // nested arrays are basically user errors, but we handle them like normal arrays
920 log("Warning in /s_new handler: nested array argument detected");
921 set_control_array<control_id_type>(node, control, it);
922 return;
923 } else {
924 for (size_t i = 0; i != array_size; ++i) {
925 if (it->IsString() || it->IsSymbol()) {
926 char const * name = it->AsStringUnchecked(); ++it;
927 int bus_id;
929 switch (name[0]) {
930 case 'c':
931 bus_id = atoi(name+1);
932 static_cast<sc_synth*>(node)->map_control_bus<false>(control, i, bus_id);
933 break;
935 case 'a':
936 bus_id = atoi(name+1);
937 static_cast<sc_synth*>(node)->map_control_bus<true>(control, i, bus_id);
938 break;
940 default:
941 throw runtime_error("invalid name for control mapping");
943 } else {
944 float value = extract_float_argument(it++);
945 node->set_control_array_element(control, i, value);
950 if (!it->IsArrayEnd())
951 throw runtime_error("missing array end tag");
952 ++it; // skip array end
955 template <typename ControlSpecifier>
956 void set_control(server_node * node, ControlSpecifier const & control, osc::ReceivedMessageArgumentIterator & it)
958 if (it->IsArrayStart())
959 set_control_array(node, control, it);
960 else if (it->IsString() || it->IsSymbol()) {
961 char const * name = it->AsStringUnchecked(); ++it;
962 int bus_id;
964 switch (name[0]) {
965 case 'c':
966 bus_id = atoi(name+1);
967 apply_control_bus_mapping<false>(*node, control, bus_id);
968 break;
970 case 'a':
971 bus_id = atoi(name+1);
972 apply_control_bus_mapping<true>(*node, control, bus_id);
973 break;
975 default:
976 throw runtime_error("invalid name for control mapping");
979 } else {
980 float value = extract_float_argument(it++);
981 node->set(control, value);
985 /* set control values of node from string/float or int/float pair */
986 void set_control(server_node * node, osc::ReceivedMessageArgumentIterator & it, osc::ReceivedMessageArgumentIterator end)
988 if (it->IsInt32()) {
989 osc::int32 index = it->AsInt32Unchecked(); ++it;
990 if (it == end) return; // sclang sometimes uses an integer instead of an empty argument list
991 set_control(node, index, it);
992 } else if (it->IsString()) {
993 const char * str = it->AsStringUnchecked(); ++it;
994 set_control(node, str, it);
995 } else
996 throw runtime_error("invalid argument");
999 void handle_s_new(received_message const & msg)
1001 osc::ReceivedMessageArgumentIterator args = msg.ArgumentsBegin(), end = msg.ArgumentsEnd();
1003 const char * def_name = args->AsString(); ++args;
1004 int32_t id = args->AsInt32(); ++args;
1006 if (id == -1)
1007 id = instance->generate_node_id();
1009 int32_t action, target;
1011 if (args != end) {
1012 action = args->AsInt32(); ++args;
1013 } else
1014 action = 0;
1016 if (args != end) {
1017 target = args->AsInt32(); ++args;
1018 } else
1019 target = 0;
1021 sc_synth * synth = add_synth(def_name, id, action, target);
1023 if (synth == NULL)
1024 return;
1026 try {
1027 while (args != end)
1028 set_control(synth, args, end);
1029 } catch(std::exception & e) {
1030 log_printf("exception in /s_new: %s\n", e.what());
1035 void handle_g_new(received_message const & msg)
1037 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1039 while(!args.Eos()) {
1040 osc::int32 node_id, action, target_id;
1041 args >> node_id >> action >> target_id;
1043 if (node_id == -1)
1044 node_id = instance->generate_node_id();
1045 else if (!check_node_id(node_id))
1046 continue;
1048 server_node * target = find_node(target_id);
1050 if (!target)
1051 continue;
1053 node_position_constraint pos = make_pair(target, node_position(action));
1054 if (!node_position_sanity_check(pos))
1055 continue;
1057 instance->add_group(node_id, pos);
1058 last_generated = node_id;
1062 void handle_g_freeall(received_message const & msg)
1064 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1066 while(!args.Eos())
1068 osc::int32 id;
1069 args >> id;
1071 abstract_group * group = find_group(id);
1072 if (!group)
1073 continue;
1075 bool success = instance->group_free_all(group);
1077 if (!success)
1078 log("/g_freeAll failue\n");
1082 void handle_g_deepFree(received_message const & msg)
1084 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1086 while(!args.Eos())
1088 osc::int32 id;
1089 args >> id;
1091 abstract_group * group = find_group(id);
1092 if (!group)
1093 continue;
1095 bool success = instance->group_free_deep(group);
1097 if (!success)
1098 log("/g_freeDeep failue\n");
1102 void g_query_tree_fill_node(osc::OutboundPacketStream & p, bool flag, server_node const & node)
1104 p << osc::int32(node.id());
1105 if (node.is_synth())
1106 p << -1;
1107 else
1108 p << osc::int32(static_cast<abstract_group const &>(node).child_count());
1110 if (node.is_synth()) {
1111 sc_synth const & scsynth = static_cast<sc_synth const&>(node);
1112 p << scsynth.prototype_name();
1114 if (flag) {
1115 osc::int32 controls = scsynth.mNumControls;
1116 p << controls;
1118 for (int i = 0; i != controls; ++i) {
1119 p << osc::int32(i); /** \todo later we can return symbols */
1121 if (scsynth.mMapControls[i] != (scsynth.mControls+i)) {
1122 /* we use a bus mapping */
1123 int bus = (scsynth.mMapControls[i]) - (scsynth.mNode.mWorld->mControlBus);
1124 char str[10];
1125 sprintf(str, "s%d", bus);
1126 p << str;
1128 else
1129 p << scsynth.mControls[i];
1132 } else {
1133 abstract_group const & group = static_cast<abstract_group const &>(node);
1134 group.apply_on_children(boost::bind(g_query_tree_fill_node, boost::ref(p), flag, _1));
1138 template <bool realtime>
1139 void g_query_tree(int node_id, bool flag, nova_endpoint const & endpoint)
1141 server_node * node = find_node(node_id);
1142 if (!node || node->is_synth())
1143 return;
1145 abstract_group * group = static_cast<abstract_group*>(node);
1147 size_t max_msg_size = 1<<16;
1148 for(;;) {
1149 try {
1150 if (max_msg_size > 1<<22)
1151 return;
1153 sized_array<char, rt_pool_allocator<char> > data(max_msg_size);
1155 osc::OutboundPacketStream p(data.c_array(), max_msg_size);
1156 p << osc::BeginMessage("/g_queryTree.reply")
1157 << (flag ? 1 : 0)
1158 << node_id
1159 << osc::int32(group->child_count());
1161 group->apply_on_children(boost::bind(g_query_tree_fill_node, boost::ref(p), flag, _1));
1162 p << osc::EndMessage;
1164 movable_array<char> message(p.Size(), data.c_array());
1165 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
1166 return;
1168 catch(...)
1170 max_msg_size *= 2; /* if we run out of memory, retry with doubled memory resources */
1175 template <bool realtime>
1176 void handle_g_queryTree(received_message const & msg, nova_endpoint const & endpoint)
1178 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1180 while(!args.Eos())
1182 try {
1183 osc::int32 id, flag;
1184 args >> id >> flag;
1185 g_query_tree<realtime>(id, flag, endpoint);
1187 catch (std::exception & e) {
1188 log_printf("exception in handle_g_queryTree: %s\n", e.what());
1193 typedef std::basic_stringstream <char,
1194 std::char_traits <char>/*,
1195 rt_pool_allocator<char>*/ > rt_string_stream;
1197 void fill_spaces(rt_string_stream & stream, int level)
1199 for (int i = 0; i != level*3; ++i)
1200 stream << ' ';
1203 void g_dump_node(rt_string_stream & stream, server_node & node, bool flag, int level)
1205 using namespace std;
1206 fill_spaces(stream, level);
1208 if (node.is_synth()) {
1209 abstract_synth const & synth = static_cast<abstract_synth const &>(node);
1210 stream << synth.id() << " " << synth.prototype_name() << endl;
1212 if (flag) {
1213 /* dump controls */
1215 } else {
1216 abstract_group & group = static_cast<abstract_group &>(node);
1217 stream << group.id();
1219 if (group.is_parallel())
1220 stream << " parallel group";
1221 else
1222 stream << " group";
1223 stream << endl;
1224 group.apply_on_children(boost::bind(g_dump_node, boost::ref(stream), _1, flag, level + 1));
1228 void g_dump_tree(int id, bool flag)
1230 server_node * node = find_node(id);
1231 if (!node)
1232 return;
1234 // FIXME: can we completely avoid all internal allocations?
1235 rt_string_stream stream;
1236 stream << "NODE TREE Group " << id << std::endl;
1238 g_dump_node(stream, *node, flag, 1);
1239 log(stream.str().c_str(), stream.str().size());
1242 void handle_g_dumpTree(received_message const & msg)
1244 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1246 while(!args.Eos())
1248 try {
1249 osc::int32 id, flag;
1250 args >> id >> flag;
1251 g_dump_tree(id, flag);
1253 catch (std::exception & e) {
1254 log_printf("exception in /g_dumpTree: %s\n", e.what());
1259 void handle_n_free(received_message const & msg)
1261 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1263 while(!args.Eos())
1265 try {
1266 osc::int32 id;
1267 args >> id;
1269 server_node * node = find_node(id);
1270 if (!node)
1271 continue;
1273 instance->free_node(node);
1275 catch (std::exception & e) {
1276 log_printf("exception in /n_free: %s\n", e.what());
1281 /** macro to define an os command handler with a starting node id
1283 * it is mainly intended as decorator to avoid duplicate error handling code
1285 #define HANDLE_N_DECORATOR(cmd, function) \
1286 void handle_n_##cmd(received_message const & msg) \
1288 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); \
1289 osc::int32 id = it->AsInt32(); ++it; \
1291 server_node * node = find_node(id); \
1292 if (!node) \
1293 return; \
1295 try { \
1296 while (it != msg.ArgumentsEnd()) \
1297 function(node, it); \
1298 } catch(std::exception & e) { \
1299 log_printf("Exception during /n_" #cmd "handler: %s\n", e.what());\
1303 void set_control(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1305 if (it->IsInt32()) {
1306 osc::int32 index = it->AsInt32Unchecked(); ++it;
1307 set_control(node, index, it);
1308 } else if (it->IsString()) {
1309 const char * str = it->AsStringUnchecked(); ++it;
1310 set_control(node, str, it);
1311 } else
1312 throw runtime_error("invalid argument");
1316 HANDLE_N_DECORATOR(set, set_control)
1318 void set_control_n(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1320 if (it->IsInt32()) {
1321 osc::int32 index = it->AsInt32Unchecked(); ++it;
1322 osc::int32 count = it->AsInt32(); ++it;
1324 for (int i = 0; i != count; ++i)
1325 node->set(index + i, extract_float_argument(it++));
1327 else if (it->IsString()) {
1328 const char * str = it->AsStringUnchecked(); ++it;
1329 osc::int32 count = it->AsInt32(); ++it;
1331 sized_array<float> values(count);
1332 for (int i = 0; i != count; ++i)
1333 values[i] = extract_float_argument(it++);
1335 node->set_control_array(str, count, values.c_array());
1336 } else
1337 throw runtime_error("invalid argument");
1340 HANDLE_N_DECORATOR(setn, set_control_n)
1342 void fill_control(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1344 if (it->IsInt32()) {
1345 osc::int32 index = it->AsInt32Unchecked(); ++it;
1346 osc::int32 count = it->AsInt32(); ++it;
1347 float value = extract_float_argument(it++);
1349 for (int i = 0; i != count; ++i)
1350 node->set(index + i, value);
1352 else if (it->IsString()) {
1353 const char * str = it->AsStringUnchecked(); ++it;
1354 osc::int32 count = it->AsInt32(); ++it;
1355 float value = extract_float_argument(it++);
1357 sized_array<float> values(count);
1358 for (int i = 0; i != count; ++i)
1359 values[i] = value;
1361 node->set_control_array(str, count, values.c_array());
1362 } else
1363 throw runtime_error("invalid argument");
1366 HANDLE_N_DECORATOR(fill, fill_control)
1368 template <bool IsAudio, typename slot_type>
1369 void apply_control_bus_mapping(server_node & node, slot_type slot, int bus_index)
1371 if (node.is_synth())
1372 static_cast<sc_synth&>(node).map_control_bus<IsAudio>(slot, bus_index);
1373 else
1374 static_cast<abstract_group&>(node).apply_on_children(boost::bind(apply_control_bus_mapping<IsAudio, slot_type>, _1,
1375 slot, bus_index));
1378 template <bool IsAudio, typename slot_type>
1379 void apply_control_busn_mapping(server_node & node, slot_type slot, int bus_index, int count)
1381 if (node.is_synth())
1382 static_cast<sc_synth&>(node).map_control_buses<IsAudio>(slot, bus_index, count);
1383 else
1384 static_cast<abstract_group&>(node).apply_on_children(boost::bind(apply_control_busn_mapping<IsAudio, slot_type>, _1,
1385 slot, bus_index, count));
1388 template <bool IsAudio>
1389 void map_control(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1391 if (it->IsInt32()) {
1392 osc::int32 control_index = it->AsInt32Unchecked(); ++it;
1393 osc::int32 control_bus_index = it->AsInt32(); ++it;
1395 apply_control_bus_mapping<IsAudio>(*node, control_index, control_bus_index);
1397 else if (it->IsString()) {
1398 const char * control_name = it->AsStringUnchecked(); ++it;
1399 osc::int32 control_bus_index = it->AsInt32(); ++it;
1401 apply_control_bus_mapping<IsAudio>(*node, control_name, control_bus_index);
1402 } else
1403 throw runtime_error("invalid argument");
1406 template <bool IsAudio>
1407 void mapn_control(server_node * node, osc::ReceivedMessageArgumentIterator & it)
1409 if (it->IsInt32()) {
1410 osc::int32 control_index = it->AsInt32Unchecked(); ++it;
1411 osc::int32 bus_index = it->AsInt32(); ++it;
1412 osc::int32 count = it->AsInt32(); ++it;
1414 apply_control_busn_mapping<IsAudio>(*node, control_index, bus_index, count);
1416 else if (it->IsString()) {
1417 const char * control_name = it->AsStringUnchecked(); ++it;
1418 osc::int32 bus_index = it->AsInt32(); ++it;
1419 osc::int32 count = it->AsInt32(); ++it;
1421 apply_control_busn_mapping<IsAudio>(*node, control_name, bus_index, count);
1422 } else
1423 throw runtime_error("invalid argument");
1427 HANDLE_N_DECORATOR(map, map_control<false>)
1428 HANDLE_N_DECORATOR(mapa, map_control<true>)
1429 HANDLE_N_DECORATOR(mapn, mapn_control<false>)
1430 HANDLE_N_DECORATOR(mapan, mapn_control<true>)
1432 template <nova::node_position Relation>
1433 void handle_n_before_or_after(received_message const & msg)
1435 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1437 while(!args.Eos()) {
1438 osc::int32 node_a, node_b;
1439 args >> node_a >> node_b;
1441 server_node * a = find_node(node_a);
1442 if (!a) continue;
1444 server_node * b = find_node(node_b);
1445 if (!b) continue;
1447 abstract_group::move_before_or_after<Relation>(a, b);
1453 template <nova::node_position Position>
1454 void handle_g_head_or_tail(received_message const & msg)
1456 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1458 while(!args.Eos()) {
1459 osc::int32 node_id, target_id;
1460 args >> target_id >> node_id;
1462 server_node * node = find_node(node_id);
1463 if (!node) continue;
1465 abstract_group * target_group = find_group(target_id);
1466 if (!target_group) continue;
1468 abstract_group::move_to_head_or_tail<Position>(node, target_group);
1474 void handle_n_query(received_message const & msg, nova_endpoint const & endpoint)
1476 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1478 while(!args.Eos())
1480 osc::int32 node_id;
1481 args >> node_id;
1483 server_node * node = find_node(node_id);
1484 if (!node)
1485 continue;
1487 char buffer[128]; // 128 byte should be enough
1488 osc::OutboundPacketStream p(buffer, 128);
1489 p << osc::BeginMessage("/n_info");
1490 fill_notification(node, p);
1492 movable_array<char> message(p.Size(), p.Data());
1493 cmd_dispatcher<true>::fire_system_callback(boost::bind(send_udp_message, message, endpoint));
1497 void handle_n_order(received_message const & msg)
1499 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1501 osc::int32 action, target_id;
1502 args >> action >> target_id;
1504 server_node * target = find_node(target_id);
1506 if (target == NULL)
1507 return;
1509 abstract_group * target_parent;
1510 if (action == before ||
1511 action == after)
1512 target_parent = target->get_parent();
1513 else {
1514 if (target->is_synth())
1515 throw std::runtime_error("invalid argument for n_order: argument is no synth");
1516 target_parent = static_cast<abstract_group*>(target);
1519 while (!args.Eos())
1521 osc::int32 node_id;
1522 args >> node_id;
1524 server_node * node = find_node(node_id);
1525 if (node == NULL)
1526 continue;
1528 abstract_group * node_parent = node->get_parent();
1530 /** \todo this can be optimized if node_parent == target_parent */
1531 node_parent->remove_child(node);
1532 if (action == before ||
1533 action == after)
1534 target_parent->add_child(node, make_pair(target, node_position(action)));
1535 else
1536 target_parent->add_child(node, node_position(action));
1538 instance->update_dsp_queue();
1542 void handle_n_run(received_message const & msg)
1544 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1546 while(!args.Eos()) {
1547 osc::int32 node_id, run_flag;
1548 args >> node_id >> run_flag;
1550 server_node * node = find_node(node_id);
1551 if(!node)
1552 continue;
1554 if (run_flag)
1555 instance->node_resume(node);
1556 else
1557 instance->node_pause(node);
1561 void enable_tracing(server_node & node)
1563 if (node.is_synth()) {
1564 sc_synth & synth = static_cast<sc_synth&>(node);
1565 synth.enable_tracing();
1566 } else {
1567 abstract_group & group = static_cast<abstract_group&>(node);
1568 group.apply_on_children(enable_tracing);
1572 void handle_n_trace(received_message const & msg)
1574 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1576 while(!args.Eos()) {
1577 osc::int32 node_id;
1578 args >> node_id;
1580 server_node * node = find_node(node_id);
1581 if (!node)
1582 continue;
1584 enable_tracing(*node);
1589 void handle_s_noid(received_message const & msg)
1591 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1593 while(!args.Eos()) {
1594 osc::int32 node_id;
1595 args >> node_id;
1596 instance->synth_reassign_id(node_id);
1600 int32_t get_control_index(sc_synth * s, osc::ReceivedMessageArgumentIterator & it, osc::OutboundPacketStream & p)
1602 int32_t control;
1603 if (it->IsInt32())
1605 control = it->AsInt32Unchecked(); ++it;
1606 p << control;
1608 else if (it->IsString())
1610 const char * control_str = it->AsStringUnchecked(); ++it;
1611 control = s->resolve_slot(control_str);
1612 p << control_str;
1614 else if (it->IsSymbol())
1616 const char * control_str = it->AsSymbolUnchecked(); ++it;
1617 control = s->resolve_slot(control_str);
1618 p << osc::Symbol(control_str);
1620 else
1621 throw std::runtime_error("wrong argument type");
1622 return control;
1625 template <bool realtime>
1626 void handle_s_get(received_message const & msg, size_t msg_size, nova_endpoint const & endpoint)
1628 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
1630 if (!it->IsInt32())
1631 throw std::runtime_error("wrong argument type");
1633 int32_t node_id = it->AsInt32Unchecked(); ++it;
1635 server_node * node = find_node(node_id);
1636 if (!node || !node->is_synth())
1637 throw std::runtime_error("node is not a synth");
1639 sc_synth * s = static_cast<sc_synth*>(node);
1641 size_t alloc_size = msg_size + sizeof(float) * (msg.ArgumentCount()-1) + 128;
1643 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
1645 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
1646 p << osc::BeginMessage("/n_set")
1647 << node_id;
1649 while (it != msg.ArgumentsEnd())
1651 int32_t control = get_control_index(s, it, p);
1652 p << s->get(control);
1654 p << osc::EndMessage;
1656 movable_array<char> message(p.Size(), return_message.c_array());
1657 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
1660 template <bool realtime>
1661 void handle_s_getn(received_message const & msg, size_t msg_size, nova_endpoint const & endpoint)
1663 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
1665 if (!it->IsInt32())
1666 throw std::runtime_error("wrong argument type");
1668 int32_t node_id = it->AsInt32Unchecked(); ++it;
1670 server_node * node = find_node(node_id);
1671 if (!node || !node->is_synth())
1672 throw std::runtime_error("node is not a synth");
1674 sc_synth * s = static_cast<sc_synth*>(node);
1676 /* count argument values */
1677 size_t argument_count = 0;
1678 for (osc::ReceivedMessageArgumentIterator local = it; local != msg.ArgumentsEnd(); ++local)
1680 ++local; /* skip control */
1681 if (local == msg.ArgumentsEnd())
1682 break;
1683 if (!it->IsInt32())
1684 throw std::runtime_error("invalid count");
1685 argument_count += it->AsInt32Unchecked(); ++it;
1688 size_t alloc_size = msg_size + sizeof(float) * (argument_count) + 128;
1690 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
1692 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
1693 p << osc::BeginMessage("/n_setn")
1694 << node_id;
1696 while (it != msg.ArgumentsEnd())
1698 int32_t control = get_control_index(s, it, p);
1700 if (!it->IsInt32())
1701 throw std::runtime_error("integer argument expected");
1703 int32_t control_count = it->AsInt32Unchecked(); ++it;
1704 if (control_count < 0)
1705 break;
1707 for (int i = 0; i != control_count; ++i)
1708 p << s->get(control + i);
1710 p << osc::EndMessage;
1712 movable_array<char> message(p.Size(), return_message.c_array());
1713 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
1717 /** wrapper class for osc completion message
1719 struct completion_message
1721 /** constructor should only be used from the real-time thread */
1722 completion_message(size_t size, const void * data):
1723 size_(size)
1725 if (size) {
1726 data_ = system_callback::allocate(size);
1727 memcpy(data_, data, size);
1731 /** default constructor creates uninitialized object */
1732 completion_message(void):
1733 size_(0)
1736 /** copy constructor has move semantics!!! */
1737 completion_message(completion_message const & rhs)
1739 operator=(rhs);
1742 completion_message& operator=(completion_message const & rhs)
1744 size_ = rhs.size_;
1745 data_ = rhs.data_;
1746 const_cast<completion_message&>(rhs).size_ = 0;
1747 return *this;
1750 ~completion_message(void)
1752 if (size_)
1753 system_callback::deallocate(data_);
1756 /** handle package in the rt thread
1757 * not to be called from the rt thread
1759 void trigger_async(nova_endpoint const & endpoint)
1761 if (size_) {
1762 sc_osc_handler::received_packet * p =
1763 sc_osc_handler::received_packet::alloc_packet((char*)data_, size_, endpoint);
1764 instance->add_sync_callback(p);
1768 /** handle package directly
1769 * only to be called from the rt thread
1771 void handle(nova_endpoint const & endpoint)
1773 if (size_)
1774 instance->handle_packet((char*)data_, size_, endpoint);
1777 size_t size_;
1778 void * data_;
1781 completion_message extract_completion_message(osc::ReceivedMessageArgumentStream & args)
1783 osc::Blob blob(0, 0);
1785 if (!args.Eos()) {
1786 try {
1787 args >> blob;
1789 catch (osc::WrongArgumentTypeException & e)
1793 return completion_message (blob.size, blob.data);
1796 completion_message extract_completion_message(osc::ReceivedMessageArgumentIterator & it)
1798 const void * data = 0;
1799 unsigned long length = 0;
1801 if (it->IsBlob())
1802 it->AsBlobUnchecked(data, length);
1803 ++it;
1804 return completion_message(length, data);
1808 template <bool realtime>
1809 void b_alloc_2_rt(uint32_t index, completion_message & msg, sample * free_buf, nova_endpoint const & endpoint);
1810 void b_alloc_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
1812 template <bool realtime>
1813 void b_alloc_1_nrt(uint32_t index, uint32_t frames, uint32_t channels, completion_message & msg, nova_endpoint const & endpoint)
1815 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
1816 sample * free_buf = sc_factory->get_nrt_mirror_buffer(index);
1817 sc_factory->allocate_buffer(index, frames, channels);
1818 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_alloc_2_rt<realtime>, index, msg, free_buf, endpoint));
1821 template <bool realtime>
1822 void b_alloc_2_rt(uint32_t index, completion_message & msg, sample * free_buf, nova_endpoint const & endpoint)
1824 sc_factory->buffer_sync(index);
1825 msg.handle(endpoint);
1826 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_alloc_3_nrt, index, free_buf, endpoint));
1829 void b_alloc_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
1831 free_aligned(free_buf);
1832 send_done_message(endpoint, "/b_alloc", index);
1835 template <bool realtime>
1836 void handle_b_alloc(received_message const & msg, nova_endpoint const & endpoint)
1838 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1840 osc::int32 index, frames, channels;
1842 args >> index >> frames;
1844 if (!args.Eos())
1845 args >> channels;
1846 else
1847 channels = 1;
1849 completion_message message = extract_completion_message(args);
1851 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_alloc_1_nrt<realtime>, index, frames,
1852 channels, message, endpoint));
1855 template <bool realtime>
1856 void b_free_1_nrt(uint32_t index, completion_message & msg, nova_endpoint const & endpoint);
1857 template <bool realtime>
1858 void b_free_2_rt(uint32_t index, sample * free_buf, completion_message & msg, nova_endpoint const & endpoint);
1859 void b_free_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
1861 template <bool realtime>
1862 void b_free_1_nrt(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
1864 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
1865 sample * free_buf = sc_factory->get_nrt_mirror_buffer(index);
1866 sc_factory->free_buffer(index);
1867 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_free_2_rt<realtime>,
1868 index, free_buf, msg, endpoint));
1871 template <bool realtime>
1872 void b_free_2_rt(uint32_t index, sample * free_buf, completion_message & msg, nova_endpoint const & endpoint)
1874 sc_factory->buffer_sync(index);
1875 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_free_3_nrt, index, free_buf, endpoint));
1876 msg.handle(endpoint);
1879 void b_free_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
1881 free_aligned(free_buf);
1882 send_done_message(endpoint, "/b_free", index);
1886 template <bool realtime>
1887 void handle_b_free(received_message const & msg, nova_endpoint const & endpoint)
1889 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1891 osc::int32 index;
1892 args >> index;
1894 completion_message message = extract_completion_message(args);
1896 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_free_1_nrt<realtime>, index, message, endpoint));
1899 template <bool realtime>
1900 void b_allocRead_2_rt(uint32_t index, completion_message & msg, sample * free_buf, nova_endpoint const & endpoint);
1901 void b_allocRead_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
1903 template <bool realtime>
1904 void b_allocRead_1_nrt(uint32_t index, movable_string & filename, uint32_t start, uint32_t frames, completion_message & msg,
1905 nova_endpoint const & endpoint)
1907 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
1908 sample * free_buf = sc_factory->get_nrt_mirror_buffer(index);
1909 int error = sc_factory->buffer_read_alloc(index, filename.c_str(), start, frames);
1910 if (!error)
1911 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_allocRead_2_rt<realtime>, index, msg, free_buf, endpoint));
1912 else
1913 /* post nice error message */;
1916 template <bool realtime>
1917 void b_allocRead_2_rt(uint32_t index, completion_message & msg, sample * free_buf,
1918 nova_endpoint const & endpoint)
1920 sc_factory->buffer_sync(index);
1921 msg.handle(endpoint);
1922 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_allocRead_3_nrt, index, free_buf, endpoint));
1925 void b_allocRead_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
1927 free_aligned(free_buf);
1928 send_done_message(endpoint, "/b_allocRead", index);
1931 template <bool realtime>
1932 void handle_b_allocRead(received_message const & msg, nova_endpoint const & endpoint)
1934 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
1936 osc::int32 index;
1937 const char * filename;
1939 osc::int32 start = 0;
1940 osc::int32 frames = 0;
1942 args >> index >> filename;
1944 if (!args.Eos())
1945 args >> start;
1947 if (!args.Eos())
1948 args >> frames;
1950 completion_message message = extract_completion_message(args);
1952 movable_string fname(filename);
1953 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_allocRead_1_nrt<realtime>, index,
1954 fname, start, frames, message, endpoint));
1957 template <bool realtime>
1958 void b_allocReadChannel_2_rt(uint32_t index, completion_message & msg, sample * free_buf,
1959 nova_endpoint const & endpoint);
1960 void b_allocReadChannel_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
1962 template <bool realtime>
1963 void b_allocReadChannel_1_nrt(uint32_t index, movable_string const & filename, uint32_t start, uint32_t frames,
1964 movable_array<uint32_t> const & channels, completion_message & msg,
1965 nova_endpoint const & endpoint)
1967 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
1968 sample * free_buf = sc_factory->get_nrt_mirror_buffer(index);
1969 int error = sc_factory->buffer_alloc_read_channels(index, filename.c_str(), start, frames,
1970 channels.size(), channels.data());
1971 if (!error)
1972 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_allocReadChannel_2_rt<realtime>,
1973 index, msg, free_buf, endpoint));
1976 template <bool realtime>
1977 void b_allocReadChannel_2_rt(uint32_t index, completion_message & msg, sample * free_buf,
1978 nova_endpoint const & endpoint)
1980 sc_factory->buffer_sync(index);
1981 msg.handle(endpoint);
1982 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_allocReadChannel_3_nrt,
1983 index, free_buf, endpoint));
1986 void b_allocReadChannel_3_nrt(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
1988 free_aligned(free_buf);
1989 send_done_message(endpoint, "/b_allocReadChannel", index);
1993 template <bool realtime>
1994 void handle_b_allocReadChannel(received_message const & msg, nova_endpoint const & endpoint)
1996 osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin();
1998 osc::int32 index = arg->AsInt32(); arg++;
1999 const char * filename = arg->AsString(); arg++;
2001 osc::int32 start = arg->AsInt32(); arg++;
2002 size_t frames = arg->AsInt32(); arg++;
2004 size_t channel_args = msg.ArgumentCount() - 4; /* we already consumed 4 elements */
2006 size_t channel_count = 0;
2007 sized_array<uint, rt_pool_allocator<uint> > channels(channel_args);
2009 for (uint i = 0; i != channel_args - 1; ++i) // sclang fromats the last completion message as int, so we skip the last element
2011 if (arg->IsInt32()) {
2012 channels[i] = arg->AsInt32Unchecked(); arg++;
2013 ++channel_count;
2017 /* we reached the message blob */
2018 completion_message message = extract_completion_message(arg);
2020 movable_array<uint32_t> channel_mapping(channel_count, channels.c_array());
2021 movable_string fname(filename);
2023 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_allocReadChannel_1_nrt<realtime>,
2024 index, fname, start, frames, channel_mapping,
2025 message, endpoint));
2028 const char * b_write = "/b_write";
2030 template <bool realtime>
2031 void b_write_nrt_1(uint32_t index, movable_string const & filename, movable_string const & header_format,
2032 movable_string const & sample_format, uint32_t start, uint32_t frames, bool leave_open,
2033 completion_message & msg, nova_endpoint const & endpoint)
2035 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
2036 sc_factory->buffer_write(index, filename.c_str(), header_format.c_str(), sample_format.c_str(), start, frames, leave_open);
2037 msg.trigger_async(endpoint);
2038 cmd_dispatcher<realtime>::fire_done_message(endpoint, b_write, index);
2041 void fire_b_write_exception(void)
2043 throw std::runtime_error("wrong arguments for /b_allocReadChannel");
2046 template <bool realtime>
2047 void handle_b_write(received_message const & msg, nova_endpoint const & endpoint)
2049 osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin();
2050 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2052 /* required args */
2053 osc::int32 index = arg->AsInt32(); arg++;
2054 const char * filename = arg->AsString(); arg++;
2055 const char * header_format = arg->AsString(); arg++;
2056 const char * sample_format = arg->AsString(); arg++;
2058 /* optional args */
2059 osc::int32 frames = -1;
2060 osc::int32 start = 0;
2061 osc::int32 leave_open = 0;
2063 completion_message message;
2065 if (arg != end) {
2066 if (!arg->IsInt32())
2067 fire_b_write_exception();
2068 frames = arg->AsInt32Unchecked(); arg++;
2070 else
2071 goto fire_callback;
2073 if (arg != end) {
2074 if (!arg->IsInt32())
2075 fire_b_write_exception();
2076 start = arg->AsInt32Unchecked(); arg++;
2078 else
2079 goto fire_callback;
2081 if (arg != end) {
2082 if (!arg->IsInt32())
2083 fire_b_write_exception();
2084 leave_open = arg->AsInt32Unchecked(); arg++;
2086 else
2087 goto fire_callback;
2089 if (arg != end)
2090 message = extract_completion_message(arg);
2092 fire_callback:
2093 movable_string fname(filename);
2094 movable_string header_f(header_format);
2095 movable_string sample_f(sample_format);
2097 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_write_nrt_1<realtime>, index, fname, header_f, sample_f,
2098 start, frames, bool(leave_open), message, endpoint));
2101 template <bool realtime>
2102 void b_read_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint);
2104 template <bool realtime>
2105 void b_read_nrt_1(uint32_t index, movable_string & filename, uint32_t start_file, uint32_t frames,
2106 uint32_t start_buffer, bool leave_open, completion_message & msg, nova_endpoint const & endpoint)
2108 sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index));
2109 sc_factory->buffer_read(index, filename.c_str(), start_file, frames, start_buffer, leave_open);
2110 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_read_rt_2<realtime>, index, msg, endpoint));
2113 const char * b_read = "/b_read";
2114 template <bool realtime>
2115 void b_read_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2117 sc_factory->buffer_sync(index);
2118 msg.handle(endpoint);
2119 cmd_dispatcher<realtime>::fire_done_message(endpoint, b_read, index);
2122 void fire_b_read_exception(void)
2124 throw std::runtime_error("wrong arguments for /b_read");
2127 template <bool realtime>
2128 void handle_b_read(received_message const & msg, nova_endpoint const & endpoint)
2130 osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin();
2131 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2133 /* required args */
2134 osc::int32 index = arg->AsInt32(); arg++;
2135 const char * filename = arg->AsString(); arg++;
2137 /* optional args */
2138 osc::int32 start_file = 0;
2139 osc::int32 frames = -1;
2140 osc::int32 start_buffer = 0;
2141 osc::int32 leave_open = 0;
2143 completion_message message;
2145 if (arg != end) {
2146 if (!arg->IsInt32())
2147 fire_b_read_exception();
2148 start_file = arg->AsInt32Unchecked(); arg++;
2150 else
2151 goto fire_callback;
2153 if (arg != end) {
2154 if (!arg->IsInt32())
2155 fire_b_read_exception();
2156 frames = arg->AsInt32Unchecked(); arg++;
2158 else
2159 goto fire_callback;
2161 if (arg != end) {
2162 if (!arg->IsInt32())
2163 fire_b_read_exception();
2164 start_buffer = arg->AsInt32Unchecked(); arg++;
2166 else
2167 goto fire_callback;
2169 if (arg != end) {
2170 if (!arg->IsInt32())
2171 fire_b_read_exception();
2172 leave_open = arg->AsInt32Unchecked(); arg++;
2174 else
2175 goto fire_callback;
2177 if (arg != end)
2178 message = extract_completion_message(arg);
2180 fire_callback:
2181 movable_string fname(filename);
2183 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_read_nrt_1<realtime>, index, fname,
2184 start_file, frames, start_buffer,
2185 bool(leave_open), message, endpoint));
2189 template <bool realtime>
2190 void b_readChannel_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint);
2192 template <bool realtime>
2193 void b_readChannel_nrt_1(uint32_t index, movable_string & filename, uint32_t start_file, uint32_t frames,
2194 uint32_t start_buffer, bool leave_open, movable_array<uint32_t> & channel_map,
2195 completion_message & msg, nova_endpoint const & endpoint)
2197 sc_factory->buffer_read_channel(index, filename.c_str(), start_file, frames, start_buffer, leave_open,
2198 channel_map.size(), channel_map.data());
2199 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_readChannel_rt_2<realtime>, index, msg, endpoint));
2202 const char * b_readChannel = "/b_readChannel";
2203 template <bool realtime>
2204 void b_readChannel_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2206 sc_factory->buffer_sync(index);
2207 msg.handle(endpoint);
2208 cmd_dispatcher<realtime>::fire_done_message(endpoint, b_readChannel, index);
2211 void fire_b_readChannel_exception(void)
2213 throw std::runtime_error("wrong arguments for /b_readChannel");
2216 template <bool realtime>
2217 void handle_b_readChannel(received_message const & msg, nova_endpoint const & endpoint)
2219 osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin();
2220 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2222 /* required args */
2223 osc::int32 index = arg->AsInt32(); arg++;
2224 const char * filename = arg->AsString(); arg++;
2226 /* optional args */
2227 osc::int32 start_file = 0;
2228 osc::int32 frames = -1;
2229 osc::int32 start_buffer = 0;
2230 osc::int32 leave_open = 0;
2232 sized_array<uint32_t, rt_pool_allocator<uint32_t> > channel_mapping(int32_t(msg.ArgumentCount())); /* larger than required */
2233 uint32_t channel_count = 0;
2235 completion_message message;
2237 if (arg != end) {
2238 if (!arg->IsInt32())
2239 fire_b_read_exception();
2240 start_file = arg->AsInt32Unchecked(); arg++;
2242 else
2243 goto fire_callback;
2245 if (arg != end) {
2246 if (!arg->IsInt32())
2247 fire_b_read_exception();
2248 frames = arg->AsInt32Unchecked(); arg++;
2250 else
2251 goto fire_callback;
2253 if (arg != end) {
2254 if (!arg->IsInt32())
2255 fire_b_write_exception();
2256 start_buffer = arg->AsInt32Unchecked(); arg++;
2258 else
2259 goto fire_callback;
2261 if (arg != end) {
2262 if (!arg->IsInt32())
2263 fire_b_write_exception();
2264 leave_open = arg->AsInt32Unchecked(); arg++;
2266 else
2267 goto fire_callback;
2269 while (arg != end)
2271 if (arg->IsBlob()) {
2272 message = extract_completion_message(arg);
2273 goto fire_callback;
2275 else if (arg->IsInt32()) {
2276 channel_mapping[channel_count] = arg->AsInt32Unchecked();
2277 ++arg;
2279 else
2280 fire_b_readChannel_exception();
2283 fire_callback:
2284 movable_string fname(filename);
2285 movable_array<uint32_t> channel_map(channel_count, channel_mapping.c_array());
2287 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_readChannel_nrt_1<realtime>, index, fname,
2288 start_file, frames, start_buffer,
2289 bool(leave_open), channel_map, message, endpoint));
2293 template <bool realtime>
2294 void b_zero_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint);
2296 template <bool realtime>
2297 void b_zero_nrt_1(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2299 sc_factory->buffer_zero(index);
2300 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_zero_rt_2<realtime>, index, msg, endpoint));
2303 const char * b_zero = "/b_zero";
2304 template <bool realtime>
2305 void b_zero_rt_2(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2307 sc_factory->increment_write_updates(index);
2308 msg.handle(endpoint);
2309 cmd_dispatcher<realtime>::fire_done_message(endpoint, b_zero, index);
2312 template <bool realtime>
2313 void handle_b_zero(received_message const & msg, nova_endpoint const & endpoint)
2315 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2317 osc::int32 index;
2318 args >> index;
2319 completion_message message = extract_completion_message(args);
2321 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_zero_nrt_1<realtime>, index, message, endpoint));
2324 void handle_b_set(received_message const & msg)
2326 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2327 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2328 verify_argument(it, end);
2329 osc::int32 buffer_index = it->AsInt32(); ++it;
2331 buffer_wrapper::sample_t * data = sc_factory->get_buffer(buffer_index);
2333 while (it != end) {
2334 osc::int32 index = it->AsInt32(); ++it;
2335 float value = extract_float_argument(it++);
2337 data[index] = value;
2341 void handle_b_setn(received_message const & msg)
2343 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2344 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2345 verify_argument(it, end);
2346 osc::int32 buffer_index = it->AsInt32(); ++it;
2348 buffer_wrapper::sample_t * data = sc_factory->get_buffer(buffer_index);
2350 while (it != end) {
2351 osc::int32 index = it->AsInt32(); ++it;
2352 verify_argument(it, end);
2353 osc::int32 samples = it->AsInt32(); ++it;
2355 for (int i = 0; i != samples; ++i) {
2356 verify_argument(it, end);
2357 float value = extract_float_argument(it++);
2358 data[index+i] = value;
2363 void handle_b_fill(received_message const & msg)
2365 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2366 osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd();
2367 verify_argument(it, end);
2368 osc::int32 buffer_index = it->AsInt32(); ++it;
2370 buffer_wrapper::sample_t * data = sc_factory->get_buffer(buffer_index);
2372 while (it != end) {
2373 osc::int32 index = it->AsInt32(); ++it;
2374 verify_argument(it, end);
2375 osc::int32 samples = it->AsInt32(); ++it;
2376 verify_argument(it, end);
2377 float value = extract_float_argument(it++);
2379 for (int i = 0; i != samples; ++i)
2380 data[index] = value;
2384 template <bool realtime>
2385 void handle_b_query(received_message const & msg, nova_endpoint const & endpoint)
2387 const size_t elem_size = 3*sizeof(int) * sizeof(float);
2389 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2390 size_t arg_count = msg.ArgumentCount();
2392 size_t size = elem_size * arg_count + 128; /* should be more than required */
2393 sized_array<char, rt_pool_allocator<char> > data(size);
2395 osc::OutboundPacketStream p(data.c_array(), size);
2396 p << osc::BeginMessage("/b_info");
2398 while (!args.Eos()) {
2399 osc::int32 buffer_index;
2400 args >> buffer_index;
2402 SndBuf * buf = sc_factory->get_buffer_struct(buffer_index);
2404 p << buffer_index
2405 << osc::int32(buf->frames)
2406 << osc::int32(buf->channels)
2407 << float (buf->samplerate);
2410 p << osc::EndMessage;
2412 movable_array<char> message(p.Size(), data.c_array());
2414 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2417 template <bool realtime>
2418 void b_close_rt_2(completion_message & msg, nova_endpoint const & endpoint);
2420 template <bool realtime>
2421 void b_close_nrt_1(uint32_t index, completion_message & msg, nova_endpoint const & endpoint)
2423 sc_factory->buffer_close(index);
2424 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_close_rt_2<realtime>, msg, endpoint));
2427 template <bool realtime>
2428 void b_close_rt_2(completion_message & msg, nova_endpoint const & endpoint)
2432 template <bool realtime>
2433 void handle_b_close(received_message const & msg, nova_endpoint const & endpoint)
2435 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2436 osc::int32 index;
2437 args >> index;
2439 completion_message message = extract_completion_message(args);
2440 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_close_nrt_1<realtime>, index, message, endpoint));
2443 template <bool realtime>
2444 void handle_b_get(received_message const & msg, nova_endpoint const & endpoint)
2446 const size_t elem_size = sizeof(int) * sizeof(float);
2447 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2448 const size_t index_count = msg.ArgumentCount() - 1;
2449 const size_t alloc_size = index_count * elem_size + 128; /* hopefully enough */
2451 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
2453 osc::int32 buffer_index;
2454 args >> buffer_index;
2456 const SndBuf * buf = sc_factory->get_buffer_struct(buffer_index);
2457 const sample * data = buf->data;
2458 const int max_sample = buf->frames * buf->channels;
2460 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
2461 p << osc::BeginMessage("/b_set")
2462 << buffer_index;
2464 while (!args.Eos())
2466 osc::int32 index;
2467 args >> index;
2468 p << index;
2470 if (index < max_sample)
2471 p << data[index];
2472 else
2473 p << 0.f;
2476 p << osc::EndMessage;
2478 movable_array<char> message(p.Size(), return_message.c_array());
2479 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2482 template<typename Alloc>
2483 struct getn_data
2485 getn_data(int start, int count, const float * data):
2486 start_index_(start), data_(count)
2488 data_.reserve(count);
2489 for (int i = 0; i != count; ++i)
2490 data_[i] = data[i];
2493 int start_index_;
2494 std::vector<float, Alloc> data_;
2497 template <bool realtime>
2498 void handle_b_getn(received_message const & msg, nova_endpoint const & endpoint)
2500 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2502 typedef getn_data<rt_pool_allocator<float> > getn_data;
2503 std::vector<getn_data, rt_pool_allocator<getn_data> > return_data;
2505 osc::int32 buffer_index;
2506 args >> buffer_index;
2508 const SndBuf * buf = sc_factory->get_buffer_struct(buffer_index);
2509 const sample * data = buf->data;
2510 const int max_sample = buf->frames * buf->channels;
2512 while (!args.Eos())
2514 osc::int32 index, sample_count;
2515 args >> index >> sample_count;
2517 if (index + sample_count <= max_sample)
2518 return_data.push_back(getn_data(index, sample_count, data + index));
2521 size_t alloc_size = 128;
2522 for (size_t i = 0; i != return_data.size(); ++i)
2523 alloc_size += return_data[i].data_.size() * (sizeof(float) + sizeof(int)) + 2*sizeof(int);
2525 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
2527 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
2528 p << osc::BeginMessage("/b_setn")
2529 << buffer_index;
2531 for (size_t i = 0; i != return_data.size(); ++i) {
2532 p << osc::int32(return_data[i].start_index_)
2533 << osc::int32(return_data[i].data_.size());
2535 for (size_t j = 0; j != return_data[i].data_.size(); ++j)
2536 p << return_data[i].data_[j];
2539 p << osc::EndMessage;
2541 movable_array<char> message(p.Size(), return_message.c_array());
2542 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2546 template <bool realtime>
2547 void b_gen_rt_2(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
2548 void b_gen_nrt_3(uint32_t index, sample * free_buf, nova_endpoint const & endpoint);
2550 template <bool realtime>
2551 void b_gen_nrt_1(movable_array<char> & message, nova_endpoint const & endpoint)
2553 const char * data = (char*)message.data();
2554 const char * msg_data = OSCstrskip(data); // skip address
2555 size_t diff = msg_data - data;
2557 sc_msg_iter msg(message.size() - diff, msg_data);
2559 char nextTag = msg.nextTag();
2560 if (nextTag != 'i') {
2561 printf("/b_gen handler: invalid buffer index type %c\n", nextTag);
2562 return;
2564 int index = msg.geti();
2566 const char * generator = (const char*)msg.gets4();
2567 if (!generator) {
2568 if (nextTag += 'i') {
2569 printf("/b_gen handler: invalid bufgen name\n");
2570 return;
2574 sample * free_buf = sc_factory->buffer_generate(index, generator, msg);
2575 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(b_gen_rt_2<realtime>, index, free_buf, endpoint));
2578 template <bool realtime>
2579 void b_gen_rt_2(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
2581 sc_factory->buffer_sync(index);
2582 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_gen_nrt_3, index, free_buf, endpoint));
2585 void b_gen_nrt_3(uint32_t index, sample * free_buf, nova_endpoint const & endpoint)
2587 free_aligned(free_buf);
2588 send_done_message(endpoint, "/b_gen", index);
2591 template <bool realtime>
2592 void handle_b_gen(received_message const & msg, size_t msg_size, nova_endpoint const & endpoint)
2594 movable_array<char> cmd (msg_size, msg.AddressPattern());
2595 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(b_gen_nrt_1<realtime>, cmd, endpoint));
2599 void handle_c_set(received_message const & msg)
2601 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2603 while (it != msg.ArgumentsEnd()) {
2604 osc::int32 bus_index = it->AsInt32(); ++it;
2605 float value = extract_float_argument(it++);
2607 sc_factory->controlbus_set(bus_index, value);
2611 void handle_c_setn(received_message const & msg)
2613 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2615 while (it != msg.ArgumentsEnd()) {
2616 osc::int32 bus_index, bus_count;
2617 bus_index = it->AsInt32(); ++it;
2618 bus_count = it->AsInt32(); ++it;
2620 for (int i = 0; i != bus_count; ++i) {
2621 float value = extract_float_argument(it++);
2622 sc_factory->controlbus_set(bus_index + i, value);
2627 void handle_c_fill(received_message const & msg)
2629 osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin();
2631 while (it != msg.ArgumentsEnd()) {
2632 osc::int32 bus_index, bus_count;
2633 bus_index = it->AsInt32(); ++it;
2634 bus_count = it->AsInt32(); ++it;
2635 float value = extract_float_argument(it++);
2636 sc_factory->controlbus_fill(bus_index, bus_count, value);
2640 template <bool realtime>
2641 void handle_c_get(received_message const & msg,
2642 nova_endpoint const & endpoint)
2644 const size_t elem_size = sizeof(int) + sizeof(float);
2645 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2646 const size_t index_count = msg.ArgumentCount();
2647 const size_t alloc_size = index_count * elem_size + 128; /* hopefully enough */
2649 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
2651 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
2652 p << osc::BeginMessage("/c_set");
2654 while (!args.Eos())
2656 osc::int32 index;
2657 args >> index;
2659 p << index << sc_factory->controlbus_get(index);
2662 p << osc::EndMessage;
2664 movable_array<char> message(p.Size(), return_message.c_array());
2665 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2668 template <bool realtime>
2669 void handle_c_getn(received_message const & msg, nova_endpoint const & endpoint)
2671 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2673 /* we pessimize, but better to allocate too much than too little */
2674 const size_t alloc_size = 128 +
2675 (2 * sizeof(int) + 128*sizeof(float)) * msg.ArgumentCount();
2677 sized_array<char, rt_pool_allocator<char> > return_message(alloc_size);
2679 osc::OutboundPacketStream p(return_message.c_array(), alloc_size);
2680 p << osc::BeginMessage("/c_setn");
2682 while (!args.Eos())
2684 osc::int32 bus_index, bus_count;
2685 args >> bus_index >> bus_count;
2686 p << bus_index << bus_count;
2688 for (int i = 0; i != bus_count; ++i) {
2689 float value = sc_factory->controlbus_get(bus_index + i);
2690 p << value;
2694 p << osc::EndMessage;
2696 movable_array<char> message(p.Size(), return_message.c_array());
2697 cmd_dispatcher<realtime>::fire_io_callback(boost::bind(send_udp_message, message, endpoint));
2700 #ifdef BOOST_HAS_RVALUE_REFS
2701 std::pair<sc_synth_prototype_ptr *, size_t> wrap_synthdefs(std::vector<sc_synthdef> && defs)
2703 std::vector<sc_synthdef> synthdefs(std::move(defs));
2704 size_t count = synthdefs.size();
2705 sc_synth_prototype_ptr * prototypes = new sc_synth_prototype_ptr [count];
2707 for (size_t i = 0; i != count; ++i)
2708 prototypes[i].reset(new sc_synth_prototype(std::move(synthdefs[i])));
2709 return std::make_pair(prototypes, count);
2711 #endif
2712 std::pair<sc_synth_prototype_ptr *, size_t> wrap_synthdefs(std::vector<sc_synthdef> const & defs)
2714 size_t count = defs.size();
2715 sc_synth_prototype_ptr * prototypes = new sc_synth_prototype_ptr [count];
2717 for (size_t i = 0; i != count; ++i)
2718 prototypes[i].reset(new sc_synth_prototype(defs[i]));
2719 return std::make_pair(prototypes, count);
2722 template <bool realtime>
2723 void d_recv_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2724 nova_endpoint const & endpoint);
2725 void d_recv_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint);
2727 template <bool realtime>
2728 void d_recv_nrt(movable_array<char> & def, completion_message & msg, nova_endpoint const & endpoint)
2730 size_t count;
2731 sc_synth_prototype_ptr * prototypes;
2732 std::vector<sc_synthdef> synthdefs (read_synthdefs(def.data()));
2734 #ifdef BOOST_HAS_RVALUE_REFS
2735 boost::tie(prototypes, count) = wrap_synthdefs(std::move(synthdefs));
2736 #else
2737 boost::tie(prototypes, count) = wrap_synthdefs(synthdefs);
2738 #endif
2740 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(d_recv_rt2<realtime>, prototypes, count, msg, endpoint));
2743 template <bool realtime>
2744 void d_recv_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2745 nova_endpoint const & endpoint)
2747 std::for_each(prototypes, prototypes + prototype_count,
2748 boost::bind(&synth_factory::register_prototype, instance, _1));
2750 msg.handle(endpoint);
2751 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_recv_nrt3, prototypes, endpoint));
2754 void d_recv_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint)
2756 delete[] prototypes;
2757 send_done_message(endpoint, "/d_recv");
2760 template <bool realtime>
2761 void handle_d_recv(received_message const & msg,
2762 nova_endpoint const & endpoint)
2764 const void * synthdef_data;
2765 unsigned long synthdef_size;
2767 osc::ReceivedMessageArgumentIterator args = msg.ArgumentsBegin();
2769 args->AsBlob(synthdef_data, synthdef_size); ++args;
2770 movable_array<char> def(synthdef_size, (const char*)synthdef_data);
2771 completion_message message = extract_completion_message(args);
2773 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_recv_nrt<realtime>, def, message, endpoint));
2776 template <bool realtime>
2777 void d_load_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2778 nova_endpoint const & endpoint);
2779 void d_load_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint);
2781 template <bool realtime>
2782 void d_load_nrt(movable_string & path, completion_message & msg, nova_endpoint const & endpoint)
2784 size_t count;
2785 sc_synth_prototype_ptr * prototypes;
2786 /* todo: we need to implment some file name pattern matching */
2787 boost::tie(prototypes, count) = wrap_synthdefs(sc_read_synthdefs_file(path.c_str()));
2789 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(d_load_rt2<realtime>, prototypes, count, msg, endpoint));
2792 template <bool realtime>
2793 void d_load_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2794 nova_endpoint const & endpoint)
2796 std::for_each(prototypes, prototypes + prototype_count,
2797 boost::bind(&synth_factory::register_prototype, instance, _1));
2799 msg.handle(endpoint);
2800 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_load_nrt3, prototypes, endpoint));
2803 void d_load_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint)
2805 delete[] prototypes;
2806 send_done_message(endpoint, "/d_load");
2810 template <bool realtime>
2811 void handle_d_load(received_message const & msg,
2812 nova_endpoint const & endpoint)
2814 osc::ReceivedMessageArgumentIterator args = msg.ArgumentsBegin();
2815 const char * path = args->AsString(); args++;
2816 completion_message message = extract_completion_message(args);
2818 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_load_nrt<realtime>, movable_string(path),
2819 message, endpoint));
2823 template <bool realtime>
2824 void d_loadDir_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2825 nova_endpoint const & endpoint);
2826 void d_loadDir_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint);
2828 template <bool realtime>
2829 void d_loadDir_nrt1(movable_string & path, completion_message & msg, nova_endpoint const & endpoint)
2831 size_t count;
2832 sc_synth_prototype_ptr * prototypes;
2833 boost::tie(prototypes, count) = wrap_synthdefs(sc_read_synthdefs_dir(path.c_str()));
2835 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(d_loadDir_rt2<realtime>, prototypes, count, msg, endpoint));
2838 template <bool realtime>
2839 void d_loadDir_rt2(sc_synth_prototype_ptr * prototypes, size_t prototype_count, completion_message & msg,
2840 nova_endpoint const & endpoint)
2842 std::for_each(prototypes, prototypes + prototype_count,
2843 boost::bind(&synth_factory::register_prototype, instance, _1));
2845 msg.handle(endpoint);
2846 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_loadDir_nrt3, prototypes, endpoint));
2849 void d_loadDir_nrt3(sc_synth_prototype_ptr * prototypes, nova_endpoint const & endpoint)
2851 delete[] prototypes;
2852 send_done_message(endpoint, "/d_loadDir");
2855 template <bool realtime>
2856 void handle_d_loadDir(received_message const & msg,
2857 nova_endpoint const & endpoint)
2859 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2860 const char * path;
2862 args >> path;
2863 completion_message message = extract_completion_message(args);
2865 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(d_loadDir_nrt1<realtime>,
2866 movable_string(path), message, endpoint));
2870 void handle_d_free(received_message const & msg)
2872 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2874 while(!args.Eos())
2876 const char * defname;
2877 args >> defname;
2879 instance->remove_prototype(defname);
2883 void insert_parallel_group(int node_id, int action, int target_id)
2885 if (node_id == -1)
2886 node_id = instance->generate_node_id();
2887 else if (!check_node_id(node_id))
2888 return;
2890 server_node * target = find_node(target_id);
2891 if(!target)
2892 return;
2894 node_position_constraint pos = make_pair(target, node_position(action));
2895 if (!node_position_sanity_check(pos))
2896 return;
2898 instance->add_parallel_group(node_id, pos);
2899 last_generated = node_id;
2902 void handle_p_new(received_message const & msg)
2904 osc::ReceivedMessageArgumentStream args = msg.ArgumentStream();
2906 while(!args.Eos()) {
2907 osc::int32 id, action, target;
2908 args >> id >> action >> target;
2910 insert_parallel_group(id, action, target);
2914 void handle_u_cmd(received_message const & msg, int size)
2916 sc_msg_iter args(size, msg.AddressPattern());
2918 int node_id = args.geti();
2920 server_node * target_synth = find_node(node_id);
2922 if (target_synth == NULL || target_synth->is_group())
2923 return;
2925 sc_synth * synth = static_cast<sc_synth*>(target_synth);
2927 int ugen_index = args.geti();
2928 const char * cmd_name = args.gets();
2930 synth->apply_unit_cmd(cmd_name, ugen_index, &args);
2933 void handle_cmd(received_message const & msg, int size, nova_endpoint const & endpoint, int skip_bytes)
2935 sc_msg_iter args(size, msg.AddressPattern() + skip_bytes);
2937 const char * cmd = args.gets();
2939 sc_factory->run_cmd_plugin(&sc_factory->world, cmd, &args, const_cast<nova_endpoint*>(&endpoint));
2942 } /* namespace */
2944 template <bool realtime>
2945 void sc_osc_handler::handle_message_int_address(received_message const & message,
2946 size_t msg_size, nova_endpoint const & endpoint)
2948 uint32_t address = message.AddressPatternAsUInt32();
2950 switch (address)
2952 case cmd_quit:
2953 handle_quit<realtime>(endpoint);
2954 break;
2956 case cmd_s_new:
2957 handle_s_new(message);
2958 break;
2960 case cmd_s_noid:
2961 handle_s_noid(message);
2962 break;
2964 case cmd_s_get:
2965 handle_s_get<realtime>(message, msg_size, endpoint);
2966 break;
2968 case cmd_s_getn:
2969 handle_s_getn<realtime>(message, msg_size, endpoint);
2970 break;
2972 case cmd_notify:
2973 handle_notify<realtime>(message, endpoint);
2974 break;
2976 case cmd_status:
2977 handle_status<realtime>(endpoint);
2978 break;
2980 case cmd_dumpOSC:
2981 handle_dumpOSC(message);
2982 break;
2984 case cmd_sync:
2985 handle_sync<realtime>(message, endpoint);
2986 break;
2988 case cmd_clearSched:
2989 handle_clearSched();
2990 break;
2992 case cmd_error:
2993 handle_error(message);
2994 break;
2996 case cmd_g_new:
2997 handle_g_new(message);
2998 break;
3000 case cmd_g_head:
3001 handle_g_head_or_tail<head>(message);
3002 break;
3004 case cmd_g_tail:
3005 handle_g_head_or_tail<tail>(message);
3006 break;
3008 case cmd_g_freeAll:
3009 handle_g_freeall(message);
3010 break;
3012 case cmd_g_deepFree:
3013 handle_g_deepFree(message);
3014 break;
3016 case cmd_g_queryTree:
3017 handle_g_queryTree<realtime>(message, endpoint);
3018 break;
3020 case cmd_g_dumpTree:
3021 handle_g_dumpTree(message);
3022 break;
3024 case cmd_n_free:
3025 handle_n_free(message);
3026 break;
3028 case cmd_n_set:
3029 handle_n_set(message);
3030 break;
3032 case cmd_n_setn:
3033 handle_n_setn(message);
3034 break;
3036 case cmd_n_fill:
3037 handle_n_fill(message);
3038 break;
3040 case cmd_n_map:
3041 handle_n_map(message);
3042 break;
3044 case cmd_n_mapn:
3045 handle_n_mapn(message);
3046 break;
3048 case cmd_n_mapa:
3049 handle_n_mapa(message);
3050 break;
3052 case cmd_n_mapan:
3053 handle_n_mapan(message);
3054 break;
3056 case cmd_n_query:
3057 handle_n_query(message, endpoint);
3058 break;
3060 case cmd_n_order:
3061 handle_n_order(message);
3062 break;
3064 case cmd_n_run:
3065 handle_n_run(message);
3066 break;
3068 case cmd_n_before:
3069 handle_n_before_or_after<before>(message);
3070 break;
3072 case cmd_n_after:
3073 handle_n_before_or_after<after>(message);
3074 break;
3076 case cmd_n_trace:
3077 handle_n_trace(message);
3078 break;
3080 case cmd_b_alloc:
3081 handle_b_alloc<realtime>(message, endpoint);
3082 break;
3084 case cmd_u_cmd:
3085 handle_u_cmd(message, msg_size);
3086 break;
3088 case cmd_b_free:
3089 handle_b_free<realtime>(message, endpoint);
3090 break;
3092 case cmd_b_allocRead:
3093 handle_b_allocRead<realtime>(message, endpoint);
3094 break;
3096 case cmd_b_allocReadChannel:
3097 handle_b_allocReadChannel<realtime>(message, endpoint);
3098 break;
3100 case cmd_b_read:
3101 handle_b_read<realtime>(message, endpoint);
3102 break;
3104 case cmd_b_readChannel:
3105 handle_b_readChannel<realtime>(message, endpoint);
3106 break;
3108 case cmd_b_write:
3109 handle_b_write<realtime>(message, endpoint);
3110 break;
3112 case cmd_b_zero:
3113 handle_b_zero<realtime>(message, endpoint);
3114 break;
3116 case cmd_b_set:
3117 handle_b_set(message);
3118 break;
3120 case cmd_b_setn:
3121 handle_b_setn(message);
3122 break;
3124 case cmd_b_fill:
3125 handle_b_fill(message);
3126 break;
3128 case cmd_b_query:
3129 handle_b_query<realtime>(message, endpoint);
3130 break;
3132 case cmd_b_get:
3133 handle_b_get<realtime>(message, endpoint);
3134 break;
3136 case cmd_b_getn:
3137 handle_b_getn<realtime>(message, endpoint);
3138 break;
3140 case cmd_b_gen:
3141 handle_b_gen<realtime>(message, msg_size, endpoint);
3142 break;
3144 case cmd_b_close:
3145 handle_b_close<realtime>(message, endpoint);
3146 break;
3148 case cmd_c_set:
3149 handle_c_set(message);
3150 break;
3152 case cmd_c_setn:
3153 handle_c_setn(message);
3154 break;
3156 case cmd_c_fill:
3157 handle_c_fill(message);
3158 break;
3160 case cmd_c_get:
3161 handle_c_get<realtime>(message, endpoint);
3162 break;
3164 case cmd_c_getn:
3165 handle_c_getn<realtime>(message, endpoint);
3166 break;
3168 case cmd_d_recv:
3169 handle_d_recv<realtime>(message, endpoint);
3170 break;
3172 case cmd_d_load:
3173 handle_d_load<realtime>(message, endpoint);
3174 break;
3176 case cmd_d_loadDir:
3177 handle_d_loadDir<realtime>(message, endpoint);
3178 break;
3180 case cmd_d_free:
3181 handle_d_free(message);
3182 break;
3184 case cmd_p_new:
3185 handle_p_new(message);
3186 break;
3188 case cmd_cmd:
3189 handle_cmd(message, msg_size, endpoint, 4);
3190 break;
3192 default:
3193 handle_unhandled_message(message);
3197 namespace
3200 template <bool realtime>
3201 void dispatch_group_commands(const char * address, received_message const & message,
3202 nova_endpoint const & endpoint)
3204 assert(address[1] == 'g');
3205 assert(address[2] == '_');
3207 if (strcmp(address+3, "new") == 0) {
3208 handle_g_new(message);
3209 return;
3211 if (strcmp(address+3, "head") == 0) {
3212 handle_g_head_or_tail<head>(message);
3213 return;
3215 if (strcmp(address+3, "tail") == 0) {
3216 handle_g_head_or_tail<tail>(message);
3217 return;
3219 if (strcmp(address+3, "freeAll") == 0) {
3220 handle_g_freeall(message);
3221 return;
3223 if (strcmp(address+3, "deepFree") == 0) {
3224 handle_g_deepFree(message);
3225 return;
3227 if (strcmp(address+3, "queryTree") == 0) {
3228 handle_g_queryTree<realtime>(message, endpoint);
3229 return;
3232 if (strcmp(address+3, "dumpTree") == 0) {
3233 handle_g_dumpTree(message);
3234 return;
3238 template <bool realtime>
3239 void dispatch_node_commands(const char * address, received_message const & message,
3240 nova_endpoint const & endpoint)
3242 assert(address[1] == 'n');
3243 assert(address[2] == '_');
3245 if (strcmp(address+3, "free") == 0) {
3246 handle_n_free(message);
3247 return;
3250 if (strcmp(address+3, "set") == 0) {
3251 handle_n_set(message);
3252 return;
3255 if (strcmp(address+3, "setn") == 0) {
3256 handle_n_setn(message);
3257 return;
3260 if (strcmp(address+3, "fill") == 0) {
3261 handle_n_fill(message);
3262 return;
3265 if (strcmp(address+3, "map") == 0) {
3266 handle_n_map(message);
3267 return;
3270 if (strcmp(address+3, "mapn") == 0) {
3271 handle_n_mapn(message);
3272 return;
3275 if (strcmp(address+3, "mapa") == 0) {
3276 handle_n_mapa(message);
3277 return;
3280 if (strcmp(address+3, "mapan") == 0) {
3281 handle_n_mapan(message);
3282 return;
3285 if (strcmp(address+3, "run") == 0) {
3286 handle_n_run(message);
3287 return;
3290 if (strcmp(address+3, "before") == 0) {
3291 handle_n_before_or_after<before>(message);
3292 return;
3295 if (strcmp(address+3, "after") == 0) {
3296 handle_n_before_or_after<after>(message);
3297 return;
3300 if (strcmp(address+3, "order") == 0) {
3301 handle_n_order(message);
3302 return;
3305 if (strcmp(address+3, "query") == 0) {
3306 handle_n_query(message, endpoint);
3307 return;
3310 if (strcmp(address+3, "trace") == 0) {
3311 handle_n_trace(message);
3312 return;
3316 template <bool realtime>
3317 void dispatch_buffer_commands(const char * address, received_message const & message,
3318 size_t msg_size, nova_endpoint const & endpoint)
3320 assert(address[1] == 'b');
3321 assert(address[2] == '_');
3323 if (strcmp(address+3, "alloc") == 0) {
3324 handle_b_alloc<realtime>(message, endpoint);
3325 return;
3328 if (strcmp(address+3, "free") == 0) {
3329 handle_b_free<realtime>(message, endpoint);
3330 return;
3333 if (strcmp(address+3, "allocRead") == 0) {
3334 handle_b_allocRead<realtime>(message, endpoint);
3335 return;
3337 if (strcmp(address+3, "allocReadChannel") == 0) {
3338 handle_b_allocReadChannel<realtime>(message, endpoint);
3339 return;
3342 if (strcmp(address+3, "read") == 0) {
3343 handle_b_read<realtime>(message, endpoint);
3344 return;
3347 if (strcmp(address+3, "readChannel") == 0) {
3348 handle_b_readChannel<realtime>(message, endpoint);
3349 return;
3352 if (strcmp(address+3, "write") == 0) {
3353 handle_b_write<realtime>(message, endpoint);
3354 return;
3357 if (strcmp(address+3, "zero") == 0) {
3358 handle_b_zero<realtime>(message, endpoint);
3359 return;
3362 if (strcmp(address+3, "set") == 0) {
3363 handle_b_set(message);
3364 return;
3367 if (strcmp(address+3, "setn") == 0) {
3368 handle_b_setn(message);
3369 return;
3372 if (strcmp(address+3, "fill") == 0) {
3373 handle_b_fill(message);
3374 return;
3377 if (strcmp(address+3, "query") == 0) {
3378 handle_b_query<realtime>(message, endpoint);
3379 return;
3382 if (strcmp(address+3, "get") == 0) {
3383 handle_b_get<realtime>(message, endpoint);
3384 return;
3387 if (strcmp(address+3, "getn") == 0) {
3388 handle_b_getn<realtime>(message, endpoint);
3389 return;
3392 if (strcmp(address+3, "gen") == 0) {
3393 handle_b_gen<realtime>(message, msg_size, endpoint);
3394 return;
3397 if (strcmp(address+3, "close") == 0) {
3398 handle_b_close<realtime>(message, endpoint);
3399 return;
3403 template <bool realtime>
3404 void dispatch_control_bus_commands(const char * address, received_message const & message,
3405 nova_endpoint const & endpoint)
3407 assert(address[1] == 'c');
3408 assert(address[2] == '_');
3410 if (strcmp(address+3, "set") == 0) {
3411 handle_c_set(message);
3412 return;
3415 if (strcmp(address+3, "setn") == 0) {
3416 handle_c_setn(message);
3417 return;
3420 if (strcmp(address+3, "fill") == 0) {
3421 handle_c_fill(message);
3422 return;
3425 if (strcmp(address+3, "get") == 0) {
3426 handle_c_get<realtime>(message, endpoint);
3427 return;
3430 if (strcmp(address+3, "getn") == 0) {
3431 handle_c_getn<realtime>(message, endpoint);
3432 return;
3436 template <bool realtime>
3437 void dispatch_synthdef_commands(const char * address, received_message const & message,
3438 nova_endpoint const & endpoint)
3440 assert(address[1] == 'd');
3441 assert(address[2] == '_');
3443 if (strcmp(address+3, "recv") == 0) {
3444 handle_d_recv<realtime>(message, endpoint);
3445 return;
3448 if (strcmp(address+3, "load") == 0) {
3449 handle_d_load<realtime>(message, endpoint);
3450 return;
3453 if (strcmp(address+3, "loadDir") == 0) {
3454 handle_d_loadDir<realtime>(message, endpoint);
3455 return;
3458 if (strcmp(address+3, "free") == 0) {
3459 handle_d_free(message);
3460 return;
3464 template <bool realtime>
3465 void dispatch_synth_commands(const char * address, received_message const & message, size_t msg_size,
3466 nova_endpoint const & endpoint)
3468 assert(address[1] == 's');
3469 assert(address[2] == '_');
3471 if (strcmp(address+3, "new") == 0) {
3472 handle_s_new(message);
3473 return;
3476 if (strcmp(address+3, "noid") == 0) {
3477 handle_s_noid(message);
3478 return;
3481 if (strcmp(address+3, "get") == 0) {
3482 handle_s_get<realtime>(message, msg_size, endpoint);
3483 return;
3486 if (strcmp(address+3, "getn") == 0) {
3487 handle_s_getn<realtime>(message, msg_size, endpoint);
3488 return;
3492 } /* namespace */
3494 template <bool realtime>
3495 void sc_osc_handler::handle_message_sym_address(received_message const & message,
3496 size_t msg_size, nova_endpoint const & endpoint)
3498 const char * address = message.AddressPattern();
3500 /* scsynth doesn't require the leading / */
3501 if(address[0] != '/')
3502 address -= 1;
3504 if (address[2] == '_')
3506 if (address[1] == 'g') {
3507 dispatch_group_commands<realtime>(address, message, endpoint);
3508 return;
3511 if (address[1] == 'n') {
3512 dispatch_node_commands<realtime>(address, message, endpoint);
3513 return;
3516 if (address[1] == 'b') {
3517 dispatch_buffer_commands<realtime>(address, message, msg_size, endpoint);
3518 return;
3521 if (address[1] == 'c') {
3522 dispatch_control_bus_commands<realtime>(address, message, endpoint);
3523 return;
3526 if (address[1] == 'd') {
3527 dispatch_synthdef_commands<realtime>(address, message, endpoint);
3528 return;
3531 if (address[1] == 's') {
3532 dispatch_synth_commands<realtime>(address, message, msg_size, endpoint);
3533 return;
3537 if (strcmp(address+1, "p_new") == 0) {
3538 handle_p_new(message);
3539 return;
3542 if (strcmp(address+1, "u_cmd") == 0) {
3543 handle_u_cmd(message, msg_size);
3544 return;
3547 if (strcmp(address+1, "status") == 0) {
3548 handle_status<realtime>(endpoint);
3549 return;
3552 if (strcmp(address+1, "sync") == 0) {
3553 handle_sync<realtime>(message, endpoint);
3554 return;
3557 if (strcmp(address+1, "quit") == 0) {
3558 handle_quit<realtime>(endpoint);
3559 return;
3562 if (strcmp(address+1, "notify") == 0) {
3563 handle_notify<realtime>(message, endpoint);
3564 return;
3567 if (strcmp(address+1, "dumpOSC") == 0) {
3568 handle_dumpOSC(message);
3569 return;
3572 if (strcmp(address+1, "clearSched") == 0) {
3573 handle_clearSched();
3574 return;
3577 if (strcmp(address+1, "error") == 0) {
3578 handle_error(message);
3579 return;
3582 if (strcmp(address+1, "cmd") == 0) {
3583 handle_cmd(message, msg_size, endpoint, 8);
3584 return;
3587 handle_unhandled_message(message);
3591 template <bool realtime>
3592 void handle_asynchronous_plugin_cleanup(World * world, void *cmdData,
3593 AsyncFreeFn cleanup)
3595 if (cleanup)
3596 (cleanup)(world, cmdData);
3599 template <bool realtime>
3600 void handle_asynchronous_plugin_stage4(World * world, const char * cmdName, void *cmdData, AsyncStageFn stage4,
3601 AsyncFreeFn cleanup, completion_message & msg, nova_endpoint const & endpoint)
3603 if (stage4)
3604 (stage4)(world, cmdData);
3606 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(handle_asynchronous_plugin_cleanup<realtime>, world, cmdData,
3607 cleanup));
3609 send_done_message(endpoint, cmdName);
3612 template <bool realtime>
3613 void handle_asynchronous_plugin_stage3(World * world, const char * cmdName, void *cmdData, AsyncStageFn stage3, AsyncStageFn stage4,
3614 AsyncFreeFn cleanup, completion_message & msg, nova_endpoint const & endpoint)
3616 if (stage3) {
3617 bool success = (stage3)(world, cmdData);
3618 if (success)
3619 msg.handle(endpoint);
3621 cmd_dispatcher<realtime>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage4<realtime>, world, cmdName,
3622 cmdData, stage4, cleanup, msg, endpoint));
3625 template <bool realtime>
3626 void handle_asynchronous_plugin_stage2(World * world, const char * cmdName, void *cmdData, AsyncStageFn stage2,
3627 AsyncStageFn stage3, AsyncStageFn stage4,
3628 AsyncFreeFn cleanup, completion_message & msg, nova_endpoint const & endpoint)
3630 if (stage2)
3631 (stage2)(world, cmdData);
3633 cmd_dispatcher<realtime>::fire_rt_callback(boost::bind(handle_asynchronous_plugin_stage3<realtime>, world, cmdName,
3634 cmdData, stage3, stage4,
3635 cleanup, msg, endpoint));
3638 void sc_osc_handler::do_asynchronous_command(World * world, void* replyAddr, const char* cmdName, void *cmdData,
3639 AsyncStageFn stage2, AsyncStageFn stage3, AsyncStageFn stage4, AsyncFreeFn cleanup,
3640 int completionMsgSize, void* completionMsgData)
3642 completion_message msg(completionMsgSize, completionMsgData);
3643 nova_endpoint endpoint(*static_cast<nova_endpoint*>(replyAddr));
3645 if (world->mRealTime)
3646 cmd_dispatcher<true>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage2<true>, world, cmdName,
3647 cmdData, stage2, stage3, stage4, cleanup, msg, endpoint));
3648 else
3649 cmd_dispatcher<false>::fire_system_callback(boost::bind(handle_asynchronous_plugin_stage2<false>, world, cmdName,
3650 cmdData, stage2, stage3, stage4, cleanup, msg, endpoint));
3654 } /* namespace detail */
3655 } /* namespace nova */