supernova: fix for small audio vector sizes
[supercollider.git] / lang / LangPrimSource / OSCData.cpp
blob438c3f28eacb2cd4b6503410ab85da993823f35c
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "OSCData.h"
22 #include "PyrPrimitive.h"
23 #include "PyrKernel.h"
24 #include "PyrInterpreter.h"
25 #include "PyrSched.h"
26 #include "PyrSymbol.h"
27 #include "GC.h"
28 //#include "PyrOMS.h"
29 //#include "MidiQ.h"
30 #include <string.h>
31 #include <math.h>
32 #include <stdexcept>
33 #include <new>
34 #include <vector>
36 #ifdef SC_WIN32
37 # include <winsock2.h>
38 typedef int socklen_t;
39 # define bzero( ptr, count ) memset( ptr, 0, count )
40 #else
41 # include <sys/socket.h>
42 # include <netinet/tcp.h>
43 # include <netdb.h>
44 #endif
46 #include <pthread.h>
47 #include "scsynthsend.h"
48 #include "sc_msg_iter.h"
49 #include "SC_ComPort.h"
50 #include "SC_WorldOptions.h"
51 #include "SC_SndBuf.h"
52 #include "SC_Endian.h"
54 #ifndef SC_DARWIN
55 # ifndef SC_WIN32
56 # include <unistd.h>
57 # endif
58 #endif
60 #include "../../../common/server_shm.hpp"
62 struct InternalSynthServerGlobals
64 struct World *mWorld;
65 int mNumSharedControls;
66 float *mSharedControls;
69 const int kNumDefaultSharedControls = 1024;
70 float gDefaultSharedControls[kNumDefaultSharedControls];
71 bool gUseDoubles = false;
73 InternalSynthServerGlobals gInternalSynthServer = { 0, kNumDefaultSharedControls, gDefaultSharedControls };
75 SC_UdpInPort* gUDPport = 0;
77 PyrString* newPyrString(VMGlobals *g, char *s, int flags, bool collect);
79 PyrSymbol *s_call, *s_write, *s_recvoscmsg, *s_recvoscbndl, *s_netaddr;
80 const char* gPassword;
81 extern bool compiledOK;
83 std::vector<SC_UdpCustomInPort *> gCustomUdpPorts;
86 ///////////
88 inline bool IsBundle(char* ptr)
90 return strcmp(ptr, "#bundle") == 0;
93 ///////////
95 const int ivxNetAddr_Hostaddr = 0;
96 const int ivxNetAddr_PortID = 1;
97 const int ivxNetAddr_Hostname = 2;
98 const int ivxNetAddr_Socket = 3;
100 void makeSockAddr(struct sockaddr_in &toaddr, int32 addr, int32 port);
101 int sendallto(int socket, const void *msg, size_t len, struct sockaddr *toaddr, int addrlen);
102 int sendall(int socket, const void *msg, size_t len);
103 static int makeSynthMsgWithTags(big_scpacket *packet, PyrSlot *slots, int size);
104 int makeSynthBundle(big_scpacket *packet, PyrSlot *slots, int size, bool useElapsed);
106 static int addMsgSlot(big_scpacket *packet, PyrSlot *slot)
108 switch (GetTag(slot)) {
109 case tagInt :
110 packet->addi(slotRawInt(slot));
111 break;
112 case tagSym :
113 packet->adds(slotRawSymbol(slot)->name);
114 break;
115 case tagObj :
116 if (isKindOf(slotRawObject(slot), class_string)) {
117 PyrString *stringObj = slotRawString(slot);
118 packet->adds(stringObj->s, stringObj->size);
119 } else if (isKindOf(slotRawObject(slot), class_int8array)) {
120 PyrInt8Array *arrayObj = slotRawInt8Array(slot);
121 packet->addb(arrayObj->b, arrayObj->size);
122 } else if (isKindOf(slotRawObject(slot), class_array)) {
123 PyrObject *arrayObj = slotRawObject(slot);
124 big_scpacket packet2;
125 if (arrayObj->size > 1 && isKindOfSlot(arrayObj->slots+1, class_array)) {
126 makeSynthBundle(&packet2, arrayObj->slots, arrayObj->size, true);
127 } else {
128 int error = makeSynthMsgWithTags(&packet2, arrayObj->slots, arrayObj->size);
129 if (error != errNone)
130 return error;
132 packet->addb((uint8*)packet2.data(), packet2.size());
134 break;
135 case tagNil :
136 case tagTrue :
137 case tagFalse :
138 case tagChar :
139 case tagPtr :
140 break;
141 default :
142 if (gUseDoubles) packet->addd(slotRawFloat(slot));
143 else packet->addf(slotRawFloat(slot));
144 break;
146 return errNone;
149 static int addMsgSlotWithTags(big_scpacket *packet, PyrSlot *slot)
151 switch (GetTag(slot)) {
152 case tagInt :
153 packet->addtag('i');
154 packet->addi(slotRawInt(slot));
155 break;
156 case tagSym :
157 packet->addtag('s');
158 packet->adds(slotRawSymbol(slot)->name);
159 break;
160 case tagObj :
161 if (isKindOf(slotRawObject(slot), class_string)) {
162 PyrString *stringObj = slotRawString(slot);
163 packet->addtag('s');
164 packet->adds(stringObj->s, stringObj->size);
165 } else if (isKindOf(slotRawObject(slot), class_int8array)) {
166 PyrInt8Array *arrayObj = slotRawInt8Array(slot);
167 packet->addtag('b');
168 packet->addb(arrayObj->b, arrayObj->size);
169 } else if (isKindOf(slotRawObject(slot), class_array)) {
170 PyrObject *arrayObj = slotRawObject(slot);
171 if (arrayObj->size) {
172 packet->addtag('b');
173 big_scpacket packet2;
174 if (arrayObj->size > 1 && isKindOfSlot(arrayObj->slots+1, class_array)) {
175 makeSynthBundle(&packet2, arrayObj->slots, arrayObj->size, true);
176 } else {
177 int error = makeSynthMsgWithTags(&packet2, arrayObj->slots, arrayObj->size);
178 if (error != errNone)
179 return error;
181 packet->addb((uint8*)packet2.data(), packet2.size());
182 } else {
183 packet->addtag('i');
184 packet->addi(0);
187 break;
188 case tagTrue :
189 packet->addtag('i');
190 packet->addi(1);
191 break;
192 case tagChar :
193 packet->addtag(slotRawChar(slot));
194 break;
195 case tagFalse :
196 case tagNil :
197 case tagPtr :
198 packet->addtag('i');
199 packet->addi(0);
200 break;
201 default :
202 if (gUseDoubles) {
203 packet->addtag('d');
204 packet->addd(slotRawFloat(slot));
205 } else {
206 packet->addtag('f');
207 packet->addf(slotRawFloat(slot));
209 break;
211 return errNone;
214 static int makeSynthMsg(big_scpacket *packet, PyrSlot *slots, int size)
216 packet->BeginMsg();
218 for (int i=0; i<size; ++i) {
219 int error = addMsgSlot(packet, slots+i);
220 if (error != errNone)
221 return error;
224 packet->EndMsg();
225 return errNone;
228 static int makeSynthMsgWithTags(big_scpacket *packet, PyrSlot *slots, int size)
230 packet->BeginMsg();
232 // First component: OSC Address Pattern.
233 // For convenience, we allow the user to omit the initial '/', when
234 // expressing it as a symbol (e.g. \g_new) - we add it back on here, for OSC compliance.
235 if(GetTag(slots) == tagSym && slotRawSymbol(slots)->name[0]!='/'){
236 packet->adds_slpre(slotRawSymbol(slots)->name);
237 } else {
238 int error = addMsgSlot(packet, slots);
239 if (error != errNone)
240 return error;
243 // skip space for tags
244 packet->maketags(size);
246 packet->addtag(',');
248 try {
249 for (int i=1; i<size; ++i) {
250 int error = addMsgSlotWithTags(packet, slots+i);
251 if (error != errNone)
252 return error;
254 } catch (std::runtime_error & e) {
255 error("makeSynthMsgWithTags: %s\n", e.what());
256 return errFailed;
259 packet->EndMsg();
261 return errNone;
264 void PerformOSCBundle(int inSize, char *inData, PyrObject *inReply, int inPortNum);
265 void PerformOSCMessage(int inSize, char *inData, PyrObject *inReply, int inPortNum);
266 PyrObject* ConvertReplyAddress(ReplyAddress *inReply);
268 void localServerReplyFunc(struct ReplyAddress *inReplyAddr, char* inBuf, int inSize);
269 void localServerReplyFunc(struct ReplyAddress *inReplyAddr, char* inBuf, int inSize)
271 bool isBundle = IsBundle(inBuf);
273 pthread_mutex_lock (&gLangMutex);
274 if (compiledOK) {
275 PyrObject *replyObj = ConvertReplyAddress(inReplyAddr);
276 if (isBundle) {
277 PerformOSCBundle(inSize, inBuf, replyObj, gUDPport->RealPortNum());
278 } else {
279 PerformOSCMessage(inSize, inBuf, replyObj, gUDPport->RealPortNum());
282 pthread_mutex_unlock (&gLangMutex);
286 int makeSynthBundle(big_scpacket *packet, PyrSlot *slots, int size, bool useElapsed)
288 double time;
289 int err;
290 int64 oscTime;
292 err = slotDoubleVal(slots, &time);
293 if (!err) {
294 if (useElapsed) {
295 oscTime = ElapsedTimeToOSC(time);
296 } else {
297 oscTime = (int64)(time * kSecondsToOSC);
299 } else {
300 oscTime = 1; // immediate
302 packet->OpenBundle(oscTime);
304 for (int i=1; i<size; ++i) {
305 if (isKindOfSlot(slots+i, class_array)) {
306 PyrObject *obj = slotRawObject(&slots[i]);
307 int error = makeSynthMsgWithTags(packet, obj->slots, obj->size);
308 if (error != errNone)
309 return error;
312 packet->CloseBundle();
313 return errNone;
316 int netAddrSend(PyrObject *netAddrObj, int msglen, char *bufptr, bool sendMsgLen=true);
317 int netAddrSend(PyrObject *netAddrObj, int msglen, char *bufptr, bool sendMsgLen)
319 int err, port, addr;
321 if (IsPtr(netAddrObj->slots + ivxNetAddr_Socket)) {
322 SC_TcpClientPort* comPort = (SC_TcpClientPort*)slotRawPtr(netAddrObj->slots + ivxNetAddr_Socket);
324 // send TCP
325 int tcpSocket = comPort->Socket();
327 if (sendMsgLen) {
328 // send length of message in network byte-order
329 int32 sizebuf = htonl(msglen);
330 sendall(tcpSocket, &sizebuf, sizeof(int32));
333 sendall(tcpSocket, bufptr, msglen);
335 } else {
336 if (gUDPport == 0) return errFailed;
338 // send UDP
339 err = slotIntVal(netAddrObj->slots + ivxNetAddr_Hostaddr, &addr);
340 if (err) return err;
342 if (addr == 0) {
343 #ifndef NO_INTERNAL_SERVER
344 if (gInternalSynthServer.mWorld) {
345 World_SendPacket(gInternalSynthServer.mWorld, msglen, bufptr, &localServerReplyFunc);
347 #endif
348 return errNone;
351 err = slotIntVal(netAddrObj->slots + ivxNetAddr_PortID, &port);
352 if (err) return err;
354 struct sockaddr_in toaddr;
355 makeSockAddr(toaddr, addr, port);
357 sendallto(gUDPport->Socket(), bufptr, msglen, (sockaddr*)&toaddr, sizeof(toaddr));
360 return errNone;
364 ///////////
366 inline int OSCStrLen(char *str)
368 return (strlen(str) + 4) & ~3;
372 int makeSynthBundle(big_scpacket *packet, PyrSlot *slots, int size, bool useElapsed);
374 static void netAddrTcpClientNotifyFunc(void *clientData);
375 void netAddrTcpClientNotifyFunc(void *clientData)
377 extern bool compiledOK;
379 pthread_mutex_lock(&gLangMutex);
380 if (compiledOK) {
381 PyrObject* netAddrObj = (PyrObject*)clientData;
382 VMGlobals* g = gMainVMGlobals;
383 g->canCallOS = false;
384 ++g->sp; SetObject(g->sp, netAddrObj);
385 runInterpreter(g, getsym("prConnectionClosed"), 1);
386 g->canCallOS = false;
388 pthread_mutex_unlock(&gLangMutex);
391 int prNetAddr_Connect(VMGlobals *g, int numArgsPushed);
392 int prNetAddr_Connect(VMGlobals *g, int numArgsPushed)
394 PyrSlot* netAddrSlot = g->sp;
395 PyrObject* netAddrObj = slotRawObject(netAddrSlot);
397 int err, port, addr;
399 err = slotIntVal(netAddrObj->slots + ivxNetAddr_PortID, &port);
400 if (err) return err;
402 err = slotIntVal(netAddrObj->slots + ivxNetAddr_Hostaddr, &addr);
403 if (err) return err;
405 struct sockaddr_in toaddr;
406 makeSockAddr(toaddr, addr, port);
408 int aSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
409 if (aSocket == -1) {
410 //post("\nCould not create socket\n");
411 return errFailed;
414 const int on = 1;
415 #ifdef SC_WIN32
416 if (setsockopt( aSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on)) != 0) {
417 #else
418 if (setsockopt( aSocket, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) != 0) {
419 #endif
420 //post("\nCould not setsockopt TCP_NODELAY\n");
421 #ifdef SC_WIN32
422 closesocket(aSocket);
423 #else
424 close(aSocket);
425 #endif
426 return errFailed;
430 if(connect(aSocket,(struct sockaddr*)&toaddr,sizeof(toaddr)) != 0)
432 //post("\nCould not connect socket\n");
433 #ifdef SC_WIN32
434 closesocket(aSocket);
435 #else
436 close(aSocket);
437 #endif
438 return errFailed;
441 SC_TcpClientPort *comPort = new SC_TcpClientPort(aSocket, netAddrTcpClientNotifyFunc, netAddrObj);
442 SetPtr(netAddrObj->slots + ivxNetAddr_Socket, comPort);
444 return errNone;
447 int prNetAddr_Disconnect(VMGlobals *g, int numArgsPushed);
448 int prNetAddr_Disconnect(VMGlobals *g, int numArgsPushed)
450 PyrSlot* netAddrSlot = g->sp;
451 PyrObject* netAddrObj = slotRawObject(netAddrSlot);
453 SC_TcpClientPort *comPort = (SC_TcpClientPort*)slotRawPtr(netAddrObj->slots + ivxNetAddr_Socket);
454 if (comPort) comPort->Close();
456 return errNone;
460 int prNetAddr_SendMsg(VMGlobals *g, int numArgsPushed);
461 int prNetAddr_SendMsg(VMGlobals *g, int numArgsPushed)
463 PyrSlot* netAddrSlot = g->sp - numArgsPushed + 1;
464 PyrSlot* args = netAddrSlot + 1;
465 big_scpacket packet;
467 int numargs = numArgsPushed - 1;
468 int error = makeSynthMsgWithTags(&packet, args, numargs);
469 if (error != errNone)
470 return error;
472 //for (int i=0; i<packet.size()/4; i++) post("%d %p\n", i, packet.buf[i]);
474 return netAddrSend(slotRawObject(netAddrSlot), packet.size(), (char*)packet.buf);
478 int prNetAddr_SendBundle(VMGlobals *g, int numArgsPushed);
479 int prNetAddr_SendBundle(VMGlobals *g, int numArgsPushed)
481 PyrSlot* netAddrSlot = g->sp - numArgsPushed + 1;
482 PyrSlot* args = netAddrSlot + 1;
483 big_scpacket packet;
485 double time;
486 int err = slotDoubleVal(args, &time);
487 if (!err) {
488 time += slotRawFloat(&g->thread->seconds);
489 SetFloat(args, time);
491 int numargs = numArgsPushed - 1;
492 makeSynthBundle(&packet, args, numargs, true);
494 //for (int i=0; i<packet.size()/4; i++) post("%d %p\n", i, packet.buf[i]);
496 return netAddrSend(slotRawObject(netAddrSlot), packet.size(), (char*)packet.buf);
499 int prNetAddr_SendRaw(VMGlobals *g, int numArgsPushed);
500 int prNetAddr_SendRaw(VMGlobals *g, int numArgsPushed)
502 PyrSlot* netAddrSlot = g->sp - 1;
503 PyrSlot* arraySlot = g->sp;
504 PyrObject* netAddrObj = slotRawObject(netAddrSlot);
506 if (!IsObj(arraySlot) || !isKindOf(slotRawObject(arraySlot), class_rawarray)) {
507 error("sendRaw arg must be a kind of RawArray.\n");
508 return errWrongType;
510 PyrObject *array = slotRawObject(arraySlot);
512 char *bufptr = (char*)array->slots;
513 int32 msglen = array->size * gFormatElemSize[array->obj_format];
515 return netAddrSend(netAddrObj, msglen, bufptr, false);
518 int prNetAddr_GetBroadcastFlag(VMGlobals *g, int numArgsPushed);
519 int prNetAddr_GetBroadcastFlag(VMGlobals *g, int numArgsPushed)
521 if (gUDPport == 0) return errFailed;
522 int opt;
523 socklen_t optlen = sizeof(opt);
524 #ifdef SC_WIN32
525 if (getsockopt(gUDPport->Socket(), SOL_SOCKET, SO_BROADCAST, (char *)&opt, &optlen) == -1)
526 #else
527 if (getsockopt(gUDPport->Socket(), SOL_SOCKET, SO_BROADCAST, &opt, &optlen) == -1)
528 #endif
529 return errFailed;
530 SetBool(g->sp, opt);
531 return errNone;
534 int prNetAddr_SetBroadcastFlag(VMGlobals *g, int numArgsPushed);
535 int prNetAddr_SetBroadcastFlag(VMGlobals *g, int numArgsPushed)
537 if (gUDPport == 0) return errFailed;
538 int opt = IsTrue(g->sp);
539 #ifdef SC_WIN32
540 if (setsockopt(gUDPport->Socket(), SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt)) == -1)
541 #else
542 if (setsockopt(gUDPport->Socket(), SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) == -1)
543 #endif
544 return errFailed;
545 return errNone;
548 int prNetAddr_BundleSize(VMGlobals *g, int numArgsPushed);
549 int prNetAddr_BundleSize(VMGlobals *g, int numArgsPushed)
551 PyrSlot* args = g->sp;
552 big_scpacket packet;
553 int numargs = slotRawObject(args)->size;
554 if (numargs < 1) return errFailed;
555 makeSynthBundle(&packet, slotRawObject(args)->slots, numargs, true);
556 SetInt(args, packet.size());
557 return errNone;
560 int prNetAddr_MsgSize(VMGlobals *g, int numArgsPushed);
561 int prNetAddr_MsgSize(VMGlobals *g, int numArgsPushed)
563 PyrSlot* args = g->sp;
564 big_scpacket packet;
566 int numargs = slotRawObject(args)->size;
567 if (numargs < 1) return errFailed;
568 int error = makeSynthMsgWithTags(&packet, slotRawObject(args)->slots, numargs);
569 if (error != errNone)
570 return error;
572 SetInt(args, packet.size());
573 return errNone;
577 int prNetAddr_UseDoubles(VMGlobals *g, int numArgsPushed);
578 int prNetAddr_UseDoubles(VMGlobals *g, int numArgsPushed)
580 //PyrSlot* netAddrSlot = g->sp - 1;
581 PyrSlot* flag = g->sp;
583 gUseDoubles = IsTrue(flag);
585 return errNone;
588 int prArray_OSCBytes(VMGlobals *g, int numArgsPushed);
589 int prArray_OSCBytes(VMGlobals *g, int numArgsPushed)
591 PyrSlot* a = g->sp;
592 PyrObject *array = slotRawObject(a);
593 PyrSlot* args = array->slots;
594 int numargs = array->size;
595 if (numargs < 1) return errFailed;
596 big_scpacket packet;
598 if (IsFloat(args) || IsNil(args) || IsInt(args)) {
599 makeSynthBundle(&packet, args, numargs, false);
600 } else if (IsSym(args) || isKindOfSlot(args, class_string)) {
601 int error = makeSynthMsgWithTags(&packet, args, numargs);
602 if (error != errNone)
603 return error;
604 } else {
605 return errWrongType;
608 int size = packet.size();
609 PyrInt8Array* obj = newPyrInt8Array(g->gc, size, 0, true);
610 obj->size = size;
611 memcpy(obj->b, packet.data(), size);
612 SetObject(a, (PyrObject*)obj);
613 //for (int i=0; i<packet.size()/4; i++) post("%d %p\n", i, packet.buf[i]);
615 return errNone;
618 // Create a new <PyrInt8Array> object and copy data from `msg.getb'.
619 // Bytes are properly untyped, but there is no <UInt8Array> type.
621 static PyrInt8Array* MsgToInt8Array ( sc_msg_iter msg ) ;
622 static PyrInt8Array* MsgToInt8Array ( sc_msg_iter msg )
624 int size = msg.getbsize() ;
625 VMGlobals *g = gMainVMGlobals ;
626 PyrInt8Array *obj = newPyrInt8Array ( g->gc , size , 0 , true ) ;
627 obj->size = size ;
628 msg.getb ( (char *)obj->b , obj->size ) ;
629 return obj ;
632 PyrObject* ConvertOSCMessage(int inSize, char *inData)
634 char *cmdName = inData;
635 int cmdNameLen = OSCstrlen(cmdName);
636 sc_msg_iter msg(inSize - cmdNameLen, inData + cmdNameLen);
638 int numElems;
639 if (inSize == cmdNameLen) {
640 numElems = 0;
641 } else {
642 if (!msg.tags) {
643 numElems = 0;
644 error("OSC messages must have type tags. %s\n", cmdName);
645 } else {
646 numElems = strlen(msg.tags);
649 //post("tags %s %d\n", msg.tags, numElems);
651 VMGlobals *g = gMainVMGlobals;
652 PyrObject *obj = newPyrArray(g->gc, numElems + 1, 0, false);
653 PyrSlot *slots = obj->slots;
655 SetSymbol(slots+0, getsym(cmdName));
657 for (int i=0; i<numElems; ++i) {
658 char tag = msg.nextTag();
659 //post("%d %c\n", i, tag);
660 switch (tag) {
661 case 'i' :
662 SetInt(slots+i+1, msg.geti());
663 break;
664 case 'f' :
665 SetFloat(slots+i+1, msg.getf());
666 break;
667 case 'd' :
668 SetFloat(slots+i+1, msg.getd());
669 break;
670 case 's' :
671 SetSymbol(slots+i+1, getsym(msg.gets()));
672 //post("sym '%s'\n", slots[i+1].us->name);
673 break;
674 case 'b' :
675 SetObject(slots+i+1, (PyrObject*)MsgToInt8Array(msg));
676 break;
677 case 'c':
678 SetChar(slots+i+1, (char)msg.geti());
679 break;
680 // else add the type tag as a char (jrhb 2009)
681 default:
682 SetChar(slots+i+1, tag);
683 msg.gets();
686 obj->size = numElems + 1;
687 return obj;
690 PyrObject* ConvertReplyAddress(ReplyAddress *inReply)
692 VMGlobals *g = gMainVMGlobals;
693 PyrObject *obj = instantiateObject(g->gc, s_netaddr->u.classobj, 2, true, false);
694 PyrSlot *slots = obj->slots;
695 SetInt(slots+0, ntohl(inReply->mSockAddr.sin_addr.s_addr));
696 SetInt(slots+1, ntohs(inReply->mSockAddr.sin_port));
697 return obj;
700 void PerformOSCBundle(int inSize, char* inData, PyrObject *replyObj, int inPortNum)
702 // convert all data to arrays
704 int64 oscTime = OSCtime(inData + 8);
705 double seconds = OSCToElapsedTime(oscTime);
707 VMGlobals *g = gMainVMGlobals;
708 ++g->sp; SetObject(g->sp, g->process);
709 ++g->sp; SetFloat(g->sp, seconds);
710 ++g->sp; SetObject(g->sp, replyObj);
711 ++g->sp; SetInt(g->sp, inPortNum);
713 PyrSlot *stackBase = g->sp;
714 char *data = inData + 16;
715 char* dataEnd = inData + inSize;
716 while (data < dataEnd) {
717 int32 msgSize = OSCint(data);
718 data += sizeof(int32);
719 PyrObject *arrayObj = ConvertOSCMessage(msgSize, data);
720 ++g->sp; SetObject(g->sp, arrayObj);
721 data += msgSize;
724 int numMsgs = g->sp - stackBase;
726 runInterpreter(g, s_recvoscbndl, 4+numMsgs);
729 void ConvertOSCBundle(int inSize, char* inData, PyrObject *replyObj)
731 // convert all data to arrays
733 //int64 oscTime = OSCtime(inData + 8);
734 //double seconds = OSCToElapsedTime(oscTime);
736 VMGlobals *g = gMainVMGlobals;
738 int numMsgs = 0;
739 char *data = inData + 16;
740 char* dataEnd = inData + inSize;
741 while (data < dataEnd) {
742 int32 msgSize = OSCint(data);
743 data += sizeof(int32);
744 PyrObject *arrayObj = ConvertOSCMessage(msgSize, data);
745 ++g->sp; SetObject(g->sp, arrayObj);
746 numMsgs++;
747 data += msgSize;
751 void PerformOSCMessage(int inSize, char *inData, PyrObject *replyObj, int inPortNum)
754 PyrObject *arrayObj = ConvertOSCMessage(inSize, inData);
756 // call virtual machine to handle message
757 VMGlobals *g = gMainVMGlobals;
758 ++g->sp; SetObject(g->sp, g->process);
759 ++g->sp; SetFloat(g->sp, elapsedTime()); // time
760 ++g->sp; SetObject(g->sp, replyObj);
761 ++g->sp; SetInt(g->sp, inPortNum);
762 ++g->sp; SetObject(g->sp, arrayObj);
764 runInterpreter(g, s_recvoscmsg, 5);
769 void FreeOSCPacket(OSC_Packet *inPacket)
771 //post("->FreeOSCPacket %p\n", inPacket);
772 if (inPacket) {
773 free(inPacket->mData);
774 free(inPacket);
778 void ProcessOSCPacket(OSC_Packet* inPacket, int inPortNum)
780 //post("recv '%s' %d\n", inPacket->mData, inPacket->mSize);
781 inPacket->mIsBundle = IsBundle(inPacket->mData);
783 pthread_mutex_lock (&gLangMutex);
784 if (compiledOK) {
785 PyrObject *replyObj = ConvertReplyAddress(&inPacket->mReplyAddr);
786 if (compiledOK) {
787 if (inPacket->mIsBundle) {
788 PerformOSCBundle(inPacket->mSize, inPacket->mData, replyObj, inPortNum);
789 } else {
790 PerformOSCMessage(inPacket->mSize, inPacket->mData, replyObj, inPortNum);
794 pthread_mutex_unlock (&gLangMutex);
796 FreeOSCPacket(inPacket);
799 void init_OSC(int port);
800 void init_OSC(int port)
802 postfl("init_OSC\n");
804 #ifdef _WIN32
805 WSAData wsaData;
806 int nCode;
807 if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) {
808 error( "sclang: init_OSC: WSAStartup() failed with error code %d.\n", nCode );
810 #endif
812 try {
813 gUDPport = new SC_UdpInPort(port);
814 } catch (...) {
815 postfl("No networking.");
819 int prOpenUDPPort(VMGlobals *g, int numArgsPushed);
820 int prOpenUDPPort(VMGlobals *g, int numArgsPushed)
822 PyrSlot *a = g->sp - 1;
823 PyrSlot *b = g->sp;
824 int port;
825 int err = slotIntVal(b, &port);
826 if (err) return err;
828 SC_UdpCustomInPort* newUDPport;
830 try {
831 SetTrue(a);
832 newUDPport = new SC_UdpCustomInPort(port);
833 gCustomUdpPorts.push_back(newUDPport);
834 } catch (...) {
835 SetFalse(a);
836 postfl("Could not bind to requested port. This may mean it is in use already by another application.\n");
838 return errNone;
841 void closeAllCustomPorts();
842 void closeAllCustomPorts()
844 // close all custom sockets
845 if(gCustomUdpPorts.empty()) postfl("empty\n");
846 for(int i=0; i<gCustomUdpPorts.size(); i++){
847 delete gCustomUdpPorts[i];
849 gCustomUdpPorts.clear();
852 void cleanup_OSC()
854 postfl( "cleaning up OSC\n");
855 #ifdef _WIN32
856 WSACleanup();
857 #endif
860 int prGetHostByName(VMGlobals *g, int numArgsPushed);
861 int prGetHostByName(VMGlobals *g, int numArgsPushed)
863 PyrSlot *a = g->sp;
864 char hostname[256];
866 int err = slotStrVal(a, hostname, 255);
867 if (err) return err;
869 struct hostent *he = gethostbyname(hostname);
870 if (!he) {
871 #ifdef _WIN32
872 int err = WSAGetLastError();
873 error("gethostbyname(\"%s\") failed with error code %i.\n",
874 hostname, err);
875 #endif
876 return errFailed;
879 SetInt(a, ntohl(*(int*)he->h_addr));
881 return errNone;
884 int prGetLangPort(VMGlobals *g, int numArgsPushed);
885 int prGetLangPort(VMGlobals *g, int numArgsPushed)
887 PyrSlot *a = g->sp;
888 if (!gUDPport) return errFailed;
889 SetInt(a, gUDPport->RealPortNum());
890 return errNone;
893 int prExit(VMGlobals *g, int numArgsPushed);
894 int prExit(VMGlobals *g, int numArgsPushed)
896 PyrSlot *a = g->sp;
898 exit(slotRawInt(a));
900 //post("exit %d\n", slotRawInt(a));
901 //DumpBackTrace(g);
902 return errNone;
905 extern "C" {
906 int vpost(const char *fmt, va_list vargs);
909 #ifndef NO_INTERNAL_SERVER
910 int prBootInProcessServer(VMGlobals *g, int numArgsPushed);
911 int prBootInProcessServer(VMGlobals *g, int numArgsPushed)
913 PyrSlot *a = g->sp;
915 if (!gInternalSynthServer.mWorld) {
916 SetPrintFunc(&vpost);
917 WorldOptions options = kDefaultWorldOptions;
919 PyrObject *optionsObj = slotRawObject(a);
920 PyrSlot *optionsSlots = optionsObj->slots;
922 static char mInputStreamsEnabled[512], mOutputStreamsEnabled[512], mDeviceName[512];
923 int err;
925 err = slotIntVal(optionsSlots + 0, (int*)&options.mNumAudioBusChannels);
926 if (err) return err;
928 err = slotIntVal(optionsSlots + 1, (int*)&options.mNumControlBusChannels);
929 if (err) return err;
931 err = slotIntVal(optionsSlots + 2, (int*)&options.mNumInputBusChannels);
932 if (err) return err;
934 err = slotIntVal(optionsSlots + 3, (int*)&options.mNumOutputBusChannels);
935 if (err) return err;
937 err = slotIntVal(optionsSlots + 4, (int*)&options.mNumBuffers);
938 if (err) return err;
940 err = slotIntVal(optionsSlots + 5, (int*)&options.mMaxNodes);
941 if (err) return err;
943 err = slotIntVal(optionsSlots + 6, (int*)&options.mMaxGraphDefs);
944 if (err) return err;
946 err = slotIntVal(optionsSlots + 8, (int*)&options.mBufLength);
947 if (err) return err;
949 if (NotNil(optionsSlots + 9)) {
950 err = slotIntVal(optionsSlots + 9, (int*)&options.mPreferredHardwareBufferFrameSize);
951 if (err) return err;
954 err = slotIntVal(optionsSlots + 10, (int*)&options.mRealTimeMemorySize);
955 if (err) return err;
957 err = slotIntVal(optionsSlots + 11, (int*)&options.mNumRGens);
958 if (err) return err;
960 err = slotIntVal(optionsSlots + 12, (int*)&options.mMaxWireBufs);
961 if (err) return err;
963 if (NotNil(optionsSlots + 13)) {
964 err = slotIntVal(optionsSlots + 13, (int*)&options.mPreferredSampleRate);
965 if (err) return err;
968 options.mLoadGraphDefs = IsTrue(optionsSlots + 14) ? 1 : 0;
970 #ifdef SC_DARWIN
971 err = slotStrVal(optionsSlots+15, mInputStreamsEnabled, 512);
972 if(err) options.mInputStreamsEnabled = NULL;
973 else options.mInputStreamsEnabled = mInputStreamsEnabled;
975 err = slotStrVal(optionsSlots+16, mOutputStreamsEnabled, 512);
976 if(err) options.mOutputStreamsEnabled = NULL;
977 else options.mOutputStreamsEnabled = mOutputStreamsEnabled;
978 #endif
980 err = slotStrVal(optionsSlots+17, mDeviceName, 512);
981 if(err) options.mInDeviceName = options.mOutDeviceName = NULL;
982 else options.mInDeviceName = options.mOutDeviceName = mDeviceName;
984 options.mNumSharedControls = gInternalSynthServer.mNumSharedControls;
985 options.mSharedControls = gInternalSynthServer.mSharedControls;
987 // internal servers use the PID to identify the shared memory region
988 #if defined(SC_IPHONE)
989 options.mSharedMemoryID = 0;
990 #elif !defined(_WIN32)
991 options.mSharedMemoryID = getpid();
992 #else
993 options.mSharedMemoryID = GetCurrentProcessId()
994 #endif
996 gInternalSynthServer.mWorld = World_New(&options);
999 return errNone;
1002 int getScopeBuf(uint32 index, SndBuf *buf, bool& didChange)
1004 if (gInternalSynthServer.mWorld) {
1005 int serverErr = World_CopySndBuf(gInternalSynthServer.mWorld, index, buf, true, &didChange);
1006 if (serverErr) return errFailed;
1007 } else {
1008 didChange = false;
1010 return errNone;
1012 void* wait_for_quit(void* thing);
1013 void* wait_for_quit(void* thing)
1015 World *world = (World*)thing;
1016 World_WaitForQuit(world);
1017 return 0;
1020 int prQuitInProcessServer(VMGlobals *g, int numArgsPushed);
1021 int prQuitInProcessServer(VMGlobals *g, int numArgsPushed)
1023 //PyrSlot *a = g->sp;
1025 if (gInternalSynthServer.mWorld) {
1026 World *world = gInternalSynthServer.mWorld;
1027 gInternalSynthServer.mWorld = 0;
1029 pthread_t thread;
1030 pthread_create(&thread, NULL, wait_for_quit, (void*)world);
1031 pthread_detach(thread);
1034 return errNone;
1036 #else // is windows
1037 int prQuitInProcessServer(VMGlobals *g, int numArgsPushed);
1038 int prQuitInProcessServer(VMGlobals *g, int numArgsPushed)
1040 // no-op. Better to have this than to overwrite in lang.
1041 return errNone;
1043 #endif
1044 //#ifndef SC_WIN32
1046 inline int32 BUFMASK(int32 x)
1048 return (1 << (31 - CLZ(x))) - 1;
1051 int prAllocSharedControls(VMGlobals *g, int numArgsPushed);
1052 int prAllocSharedControls(VMGlobals *g, int numArgsPushed)
1054 //PyrSlot *a = g->sp - 1;
1055 PyrSlot *b = g->sp;
1057 if (gInternalSynthServer.mWorld) {
1058 post("can't allocate while internal server is running\n");
1059 return errNone;
1061 if (gInternalSynthServer.mSharedControls != gDefaultSharedControls) {
1062 free(gInternalSynthServer.mSharedControls);
1063 gInternalSynthServer.mSharedControls = gDefaultSharedControls;
1065 int numSharedControls;
1066 int err = slotIntVal(b, &numSharedControls);
1067 if (err) return err;
1068 if (numSharedControls <= 0) {
1069 gInternalSynthServer.mNumSharedControls = 0;
1070 } else if (numSharedControls < kNumDefaultSharedControls) {
1071 gInternalSynthServer.mNumSharedControls = numSharedControls;
1072 } else {
1073 gInternalSynthServer.mNumSharedControls = numSharedControls;
1074 gInternalSynthServer.mSharedControls = (float*)calloc(numSharedControls, sizeof(float));
1076 return errNone;
1080 int prGetSharedControl(VMGlobals *g, int numArgsPushed);
1081 int prGetSharedControl(VMGlobals *g, int numArgsPushed)
1083 PyrSlot *a = g->sp - 1;
1084 PyrSlot *b = g->sp;
1086 int index;
1087 int err = slotIntVal(b, &index);
1088 if (err) return err;
1089 if (index < 0 || index >= gInternalSynthServer.mNumSharedControls) {
1090 SetFloat(a, 0.);
1091 return errNone;
1093 float val = gInternalSynthServer.mSharedControls[index];
1094 SetFloat(a, val);
1095 return errNone;
1098 int prSetSharedControl(VMGlobals *g, int numArgsPushed);
1099 int prSetSharedControl(VMGlobals *g, int numArgsPushed)
1101 //PyrSlot *a = g->sp - 2;
1102 PyrSlot *b = g->sp - 1;
1103 PyrSlot *c = g->sp;
1105 int index;
1106 int err = slotIntVal(b, &index);
1107 if (err) return err;
1109 float val;
1110 err = slotFloatVal(c, &val);
1111 if (err) return err;
1113 if (index < 0 || index >= gInternalSynthServer.mNumSharedControls) {
1114 return errNone;
1116 gInternalSynthServer.mSharedControls[index] = val;
1117 return errNone;
1120 static int disconnectSharedMem(VMGlobals *g, PyrObject * object)
1122 int ptrIndex = 0;
1123 PyrSlot * ptrSlot = object->slots + ptrIndex;
1125 if (IsNil(ptrSlot))
1126 // already disconnected
1127 return errNone;
1129 assert(IsPtr(ptrSlot));
1131 server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot);
1132 delete client;
1133 SetNil(ptrSlot);
1134 return errNone;
1137 int prConnectSharedMem(VMGlobals *g, int numArgsPushed)
1139 PyrSlot *a = g->sp - 1;
1140 PyrSlot *b = g->sp;
1142 assert(IsObj(a));
1144 PyrObject * self = slotRawObject(a);
1145 int portNumber = slotRawInt(b);
1147 int ptrIndex = 0;
1148 int finalizerIndex = 1;
1150 try {
1151 server_shared_memory_client * client = new server_shared_memory_client(portNumber);
1152 SetPtr(self->slots + ptrIndex, client);
1154 InstallFinalizer(g, self, finalizerIndex, disconnectSharedMem);
1156 postfl("Shared memory server interface initialized\n");
1157 } catch (std::exception & e) {
1158 postfl("Cannot connect to shared memory: %s\n", e.what());
1159 return errFailed;
1162 return errNone;
1165 int prDisconnectSharedMem(VMGlobals *g, int numArgsPushed)
1167 PyrSlot *a = g->sp;
1169 assert(IsObj(a));
1170 PyrObject * self = slotRawObject(a);
1171 return disconnectSharedMem(g, self);
1174 int prGetControlBusValue(VMGlobals *g, int numArgsPushed)
1176 PyrSlot *a = g->sp - 1;
1177 PyrSlot *b = g->sp;
1179 assert(IsObj(a));
1180 PyrObject * self = slotRawObject(a);
1181 int ptrIndex = 0;
1182 PyrSlot * ptrSlot = self->slots + ptrIndex;
1183 if (NotPtr(ptrSlot))
1184 return errFailed;
1186 if (!IsInt(b))
1187 return errFailed;
1189 int busIndex = slotRawInt(b);
1191 if (NotPtr(ptrSlot))
1192 return errFailed;
1194 server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot);
1196 float value = client->get_control_busses()[busIndex];
1197 SetFloat(a, value);
1198 return errNone;
1201 int prGetControlBusValues(VMGlobals *g, int numArgsPushed)
1203 PyrSlot *a = g->sp - 2;
1204 PyrSlot *b = g->sp - 1;
1205 PyrSlot *c = g->sp;
1207 assert(IsObj(a));
1208 PyrObject * self = slotRawObject(a);
1209 int ptrIndex = 0;
1210 PyrSlot * ptrSlot = self->slots + ptrIndex;
1211 if (NotPtr(ptrSlot))
1212 return errFailed;
1214 if (!IsInt(b))
1215 return errFailed;
1217 int busIndex = slotRawInt(b);
1219 if (!IsInt(c))
1220 return errFailed;
1222 int numberOfChannels = slotRawInt(c);
1224 server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot);
1226 PyrObject * ret = newPyrArray(g->gc, numberOfChannels, 0, 1);
1227 ret->size = numberOfChannels;
1229 for (int i = 0; i != numberOfChannels; ++i) {
1230 float value = client->get_control_busses()[busIndex + i];
1231 SetFloat(ret->slots+i, value);
1234 SetObject(a, ret);
1235 return errNone;
1238 int prSetControlBusValue(VMGlobals *g, int numArgsPushed)
1240 PyrSlot *a = g->sp - 2;
1241 PyrSlot *b = g->sp - 1;
1242 PyrSlot *c = g->sp;
1244 assert(IsObj(a));
1245 PyrObject * self = slotRawObject(a);
1246 int ptrIndex = 0;
1247 PyrSlot * ptrSlot = self->slots + ptrIndex;
1248 if (NotPtr(ptrSlot))
1249 return errFailed;
1251 if (!IsInt(b))
1252 return errFailed;
1254 int busIndex = slotRawInt(b);
1256 if (NotPtr(ptrSlot))
1257 return errFailed;
1259 float value;
1260 int error = slotFloatVal(c, &value);
1261 if (error != errNone)
1262 return error;
1264 server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot);
1266 client->get_control_busses()[busIndex] = value;
1267 return errNone;
1270 int prSetControlBusValues(VMGlobals *g, int numArgsPushed)
1272 PyrSlot *a = g->sp - 2;
1273 PyrSlot *b = g->sp - 1;
1274 PyrSlot *c = g->sp;
1276 assert(IsObj(a));
1277 PyrObject * self = slotRawObject(a);
1278 int ptrIndex = 0;
1279 PyrSlot * ptrSlot = self->slots + ptrIndex;
1280 if (NotPtr(ptrSlot))
1281 return errFailed;
1283 if (!IsInt(b))
1284 return errFailed;
1286 int busIndex = slotRawInt(b);
1288 if (!IsObj(c))
1289 return errFailed;
1291 PyrObject * values = slotRawObject(c);
1292 server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot);
1293 float * control_busses = client->get_control_busses() + busIndex;
1295 for (int i = 0; i != values->size; ++i) {
1296 float value;
1297 int error = slotFloatVal(values->slots + i, &value);
1298 if (error != errNone)
1299 return error;
1301 control_busses[i] = value;
1303 return errNone;
1306 void init_OSC_primitives();
1307 void init_OSC_primitives()
1309 int base, index;
1311 base = nextPrimitiveIndex();
1312 index = 0;
1314 definePrimitive(base, index++, "_NetAddr_Connect", prNetAddr_Connect, 1, 0);
1315 definePrimitive(base, index++, "_NetAddr_Disconnect", prNetAddr_Disconnect, 1, 0);
1316 definePrimitive(base, index++, "_NetAddr_SendMsg", prNetAddr_SendMsg, 1, 1);
1317 definePrimitive(base, index++, "_NetAddr_SendBundle", prNetAddr_SendBundle, 2, 1);
1318 definePrimitive(base, index++, "_NetAddr_SendRaw", prNetAddr_SendRaw, 2, 0);
1319 definePrimitive(base, index++, "_NetAddr_GetBroadcastFlag", prNetAddr_GetBroadcastFlag, 1, 0);
1320 definePrimitive(base, index++, "_NetAddr_SetBroadcastFlag", prNetAddr_SetBroadcastFlag, 2, 0);
1321 definePrimitive(base, index++, "_NetAddr_BundleSize", prNetAddr_BundleSize, 1, 0);
1322 definePrimitive(base, index++, "_NetAddr_MsgSize", prNetAddr_MsgSize, 1, 0);
1324 definePrimitive(base, index++, "_NetAddr_UseDoubles", prNetAddr_UseDoubles, 2, 0);
1325 definePrimitive(base, index++, "_Array_OSCBytes", prArray_OSCBytes, 1, 0);
1326 definePrimitive(base, index++, "_GetHostByName", prGetHostByName, 1, 0);
1327 definePrimitive(base, index++, "_GetLangPort", prGetLangPort, 1, 0);
1328 definePrimitive(base, index++, "_Exit", prExit, 1, 0);
1329 #ifndef NO_INTERNAL_SERVER
1330 definePrimitive(base, index++, "_BootInProcessServer", prBootInProcessServer, 1, 0);
1331 #endif
1332 definePrimitive(base, index++, "_QuitInProcessServer", prQuitInProcessServer, 1, 0);
1333 definePrimitive(base, index++, "_AllocSharedControls", prAllocSharedControls, 2, 0);
1334 definePrimitive(base, index++, "_SetSharedControl", prSetSharedControl, 3, 0);
1335 definePrimitive(base, index++, "_GetSharedControl", prGetSharedControl, 2, 0);
1336 definePrimitive(base, index++, "_OpenUDPPort", prOpenUDPPort, 2, 0);
1338 // server shared memory interface
1339 definePrimitive(base, index++, "_ServerShmInterface_connectSharedMem", prConnectSharedMem, 2, 0);
1340 definePrimitive(base, index++, "_ServerShmInterface_disconnectSharedMem", prDisconnectSharedMem, 1, 0);
1341 definePrimitive(base, index++, "_ServerShmInterface_getControlBusValue", prGetControlBusValue, 2, 0);
1342 definePrimitive(base, index++, "_ServerShmInterface_getControlBusValues", prGetControlBusValues, 3, 0);
1344 definePrimitive(base, index++, "_ServerShmInterface_setControlBusValue", prSetControlBusValue, 2, 0);
1345 definePrimitive(base, index++, "_ServerShmInterface_setControlBusValues", prSetControlBusValues, 3, 0);
1347 //post("initOSCRecs###############\n");
1348 s_call = getsym("call");
1349 s_write = getsym("write");
1350 s_recvoscmsg = getsym("recvOSCmessage");
1351 s_recvoscbndl = getsym("recvOSCbundle");
1352 s_netaddr = getsym("NetAddr");