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
22 #include "PyrPrimitive.h"
23 #include "PyrKernel.h"
24 #include "PyrInterpreter.h"
26 #include "PyrSymbol.h"
37 # include <winsock2.h>
38 typedef int socklen_t
;
39 # define bzero( ptr, count ) memset( ptr, 0, count )
41 # include <sys/socket.h>
42 # include <netinet/tcp.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"
60 #include "../../../common/server_shm.hpp"
62 struct InternalSynthServerGlobals
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
;
88 inline bool IsBundle(char* ptr
)
90 return strcmp(ptr
, "#bundle") == 0;
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
)) {
110 packet
->addi(slotRawInt(slot
));
113 packet
->adds(slotRawSymbol(slot
)->name
);
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);
128 int error
= makeSynthMsgWithTags(&packet2
, arrayObj
->slots
, arrayObj
->size
);
129 if (error
!= errNone
)
132 packet
->addb((uint8
*)packet2
.data(), packet2
.size());
142 if (gUseDoubles
) packet
->addd(slotRawFloat(slot
));
143 else packet
->addf(slotRawFloat(slot
));
149 static int addMsgSlotWithTags(big_scpacket
*packet
, PyrSlot
*slot
)
151 switch (GetTag(slot
)) {
154 packet
->addi(slotRawInt(slot
));
158 packet
->adds(slotRawSymbol(slot
)->name
);
161 if (isKindOf(slotRawObject(slot
), class_string
)) {
162 PyrString
*stringObj
= slotRawString(slot
);
164 packet
->adds(stringObj
->s
, stringObj
->size
);
165 } else if (isKindOf(slotRawObject(slot
), class_int8array
)) {
166 PyrInt8Array
*arrayObj
= slotRawInt8Array(slot
);
168 packet
->addb(arrayObj
->b
, arrayObj
->size
);
169 } else if (isKindOf(slotRawObject(slot
), class_array
)) {
170 PyrObject
*arrayObj
= slotRawObject(slot
);
171 if (arrayObj
->size
) {
173 big_scpacket packet2
;
174 if (arrayObj
->size
> 1 && isKindOfSlot(arrayObj
->slots
+1, class_array
)) {
175 makeSynthBundle(&packet2
, arrayObj
->slots
, arrayObj
->size
, true);
177 int error
= makeSynthMsgWithTags(&packet2
, arrayObj
->slots
, arrayObj
->size
);
178 if (error
!= errNone
)
181 packet
->addb((uint8
*)packet2
.data(), packet2
.size());
193 packet
->addtag(slotRawChar(slot
));
204 packet
->addd(slotRawFloat(slot
));
207 packet
->addf(slotRawFloat(slot
));
214 static int makeSynthMsgWithTags(big_scpacket
*packet
, PyrSlot
*slots
, int size
)
218 // First component: OSC Address Pattern.
219 // For convenience, we allow the user to omit the initial '/', when
220 // expressing it as a symbol (e.g. \g_new) - we add it back on here, for OSC compliance.
221 if(GetTag(slots
) == tagSym
&& slotRawSymbol(slots
)->name
[0]!='/'){
222 packet
->adds_slpre(slotRawSymbol(slots
)->name
);
224 int error
= addMsgSlot(packet
, slots
);
225 if (error
!= errNone
)
229 // skip space for tags
230 packet
->maketags(size
);
235 for (int i
=1; i
<size
; ++i
) {
236 int error
= addMsgSlotWithTags(packet
, slots
+i
);
237 if (error
!= errNone
)
240 } catch (std::runtime_error
& e
) {
241 error("makeSynthMsgWithTags: %s\n", e
.what());
250 void PerformOSCBundle(int inSize
, char *inData
, PyrObject
*inReply
, int inPortNum
);
251 void PerformOSCMessage(int inSize
, char *inData
, PyrObject
*inReply
, int inPortNum
);
252 PyrObject
* ConvertReplyAddress(ReplyAddress
*inReply
);
254 void localServerReplyFunc(struct ReplyAddress
*inReplyAddr
, char* inBuf
, int inSize
);
255 void localServerReplyFunc(struct ReplyAddress
*inReplyAddr
, char* inBuf
, int inSize
)
257 bool isBundle
= IsBundle(inBuf
);
259 pthread_mutex_lock (&gLangMutex
);
261 PyrObject
*replyObj
= ConvertReplyAddress(inReplyAddr
);
263 PerformOSCBundle(inSize
, inBuf
, replyObj
, gUDPport
->RealPortNum());
265 PerformOSCMessage(inSize
, inBuf
, replyObj
, gUDPport
->RealPortNum());
268 pthread_mutex_unlock (&gLangMutex
);
272 int makeSynthBundle(big_scpacket
*packet
, PyrSlot
*slots
, int size
, bool useElapsed
)
278 err
= slotDoubleVal(slots
, &time
);
281 oscTime
= ElapsedTimeToOSC(time
);
283 oscTime
= (int64
)(time
* kSecondsToOSC
);
286 oscTime
= 1; // immediate
288 packet
->OpenBundle(oscTime
);
290 for (int i
=1; i
<size
; ++i
) {
291 if (isKindOfSlot(slots
+i
, class_array
)) {
292 PyrObject
*obj
= slotRawObject(&slots
[i
]);
293 int error
= makeSynthMsgWithTags(packet
, obj
->slots
, obj
->size
);
294 if (error
!= errNone
)
298 packet
->CloseBundle();
302 int netAddrSend(PyrObject
*netAddrObj
, int msglen
, char *bufptr
, bool sendMsgLen
=true);
303 int netAddrSend(PyrObject
*netAddrObj
, int msglen
, char *bufptr
, bool sendMsgLen
)
307 if (IsPtr(netAddrObj
->slots
+ ivxNetAddr_Socket
)) {
308 SC_TcpClientPort
* comPort
= (SC_TcpClientPort
*)slotRawPtr(netAddrObj
->slots
+ ivxNetAddr_Socket
);
311 int tcpSocket
= comPort
->Socket();
314 // send length of message in network byte-order
315 int32 sizebuf
= htonl(msglen
);
316 sendall(tcpSocket
, &sizebuf
, sizeof(int32
));
319 sendall(tcpSocket
, bufptr
, msglen
);
322 if (gUDPport
== 0) return errFailed
;
325 err
= slotIntVal(netAddrObj
->slots
+ ivxNetAddr_Hostaddr
, &addr
);
329 #ifndef NO_INTERNAL_SERVER
330 if (gInternalSynthServer
.mWorld
) {
331 World_SendPacket(gInternalSynthServer
.mWorld
, msglen
, bufptr
, &localServerReplyFunc
);
337 err
= slotIntVal(netAddrObj
->slots
+ ivxNetAddr_PortID
, &port
);
340 struct sockaddr_in toaddr
;
341 makeSockAddr(toaddr
, addr
, port
);
343 sendallto(gUDPport
->Socket(), bufptr
, msglen
, (sockaddr
*)&toaddr
, sizeof(toaddr
));
352 inline size_t OSCStrLen(char *str
)
354 return (strlen(str
) + 4) & ~3;
358 int makeSynthBundle(big_scpacket
*packet
, PyrSlot
*slots
, int size
, bool useElapsed
);
360 static void netAddrTcpClientNotifyFunc(void *clientData
);
361 void netAddrTcpClientNotifyFunc(void *clientData
)
363 extern bool compiledOK
;
365 pthread_mutex_lock(&gLangMutex
);
367 PyrObject
* netAddrObj
= (PyrObject
*)clientData
;
368 VMGlobals
* g
= gMainVMGlobals
;
369 g
->canCallOS
= false;
370 ++g
->sp
; SetObject(g
->sp
, netAddrObj
);
371 runInterpreter(g
, getsym("prConnectionClosed"), 1);
372 g
->canCallOS
= false;
374 pthread_mutex_unlock(&gLangMutex
);
377 int prNetAddr_Connect(VMGlobals
*g
, int numArgsPushed
);
378 int prNetAddr_Connect(VMGlobals
*g
, int numArgsPushed
)
380 PyrSlot
* netAddrSlot
= g
->sp
;
381 PyrObject
* netAddrObj
= slotRawObject(netAddrSlot
);
385 err
= slotIntVal(netAddrObj
->slots
+ ivxNetAddr_PortID
, &port
);
388 err
= slotIntVal(netAddrObj
->slots
+ ivxNetAddr_Hostaddr
, &addr
);
391 struct sockaddr_in toaddr
;
392 makeSockAddr(toaddr
, addr
, port
);
394 int aSocket
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
396 //post("\nCould not create socket\n");
402 if (setsockopt( aSocket
, IPPROTO_TCP
, TCP_NODELAY
, (const char*)&on
, sizeof(on
)) != 0) {
404 if (setsockopt( aSocket
, IPPROTO_TCP
, TCP_NODELAY
, &on
, sizeof(on
)) != 0) {
406 //post("\nCould not setsockopt TCP_NODELAY\n");
408 closesocket(aSocket
);
416 if(connect(aSocket
,(struct sockaddr
*)&toaddr
,sizeof(toaddr
)) != 0)
418 //post("\nCould not connect socket\n");
420 closesocket(aSocket
);
427 SC_TcpClientPort
*comPort
= new SC_TcpClientPort(aSocket
, netAddrTcpClientNotifyFunc
, netAddrObj
);
428 SetPtr(netAddrObj
->slots
+ ivxNetAddr_Socket
, comPort
);
433 int prNetAddr_Disconnect(VMGlobals
*g
, int numArgsPushed
);
434 int prNetAddr_Disconnect(VMGlobals
*g
, int numArgsPushed
)
436 PyrSlot
* netAddrSlot
= g
->sp
;
437 PyrObject
* netAddrObj
= slotRawObject(netAddrSlot
);
439 SC_TcpClientPort
*comPort
= (SC_TcpClientPort
*)slotRawPtr(netAddrObj
->slots
+ ivxNetAddr_Socket
);
440 if (comPort
) comPort
->Close();
446 int prNetAddr_SendMsg(VMGlobals
*g
, int numArgsPushed
);
447 int prNetAddr_SendMsg(VMGlobals
*g
, int numArgsPushed
)
449 PyrSlot
* netAddrSlot
= g
->sp
- numArgsPushed
+ 1;
450 PyrSlot
* args
= netAddrSlot
+ 1;
453 int numargs
= numArgsPushed
- 1;
454 int error
= makeSynthMsgWithTags(&packet
, args
, numargs
);
455 if (error
!= errNone
)
458 //for (int i=0; i<packet.size()/4; i++) post("%d %p\n", i, packet.buf[i]);
460 return netAddrSend(slotRawObject(netAddrSlot
), packet
.size(), (char*)packet
.buf
);
464 int prNetAddr_SendBundle(VMGlobals
*g
, int numArgsPushed
);
465 int prNetAddr_SendBundle(VMGlobals
*g
, int numArgsPushed
)
467 PyrSlot
* netAddrSlot
= g
->sp
- numArgsPushed
+ 1;
468 PyrSlot
* args
= netAddrSlot
+ 1;
472 int err
= slotDoubleVal(args
, &time
);
474 time
+= slotRawFloat(&g
->thread
->seconds
);
475 SetFloat(args
, time
);
477 int numargs
= numArgsPushed
- 1;
478 makeSynthBundle(&packet
, args
, numargs
, true);
480 //for (int i=0; i<packet.size()/4; i++) post("%d %p\n", i, packet.buf[i]);
482 return netAddrSend(slotRawObject(netAddrSlot
), packet
.size(), (char*)packet
.buf
);
485 int prNetAddr_SendRaw(VMGlobals
*g
, int numArgsPushed
);
486 int prNetAddr_SendRaw(VMGlobals
*g
, int numArgsPushed
)
488 PyrSlot
* netAddrSlot
= g
->sp
- 1;
489 PyrSlot
* arraySlot
= g
->sp
;
490 PyrObject
* netAddrObj
= slotRawObject(netAddrSlot
);
492 if (!IsObj(arraySlot
) || !isKindOf(slotRawObject(arraySlot
), class_rawarray
)) {
493 error("sendRaw arg must be a kind of RawArray.\n");
496 PyrObject
*array
= slotRawObject(arraySlot
);
498 char *bufptr
= (char*)array
->slots
;
499 int32 msglen
= array
->size
* gFormatElemSize
[array
->obj_format
];
501 return netAddrSend(netAddrObj
, msglen
, bufptr
, false);
504 int prNetAddr_GetBroadcastFlag(VMGlobals
*g
, int numArgsPushed
);
505 int prNetAddr_GetBroadcastFlag(VMGlobals
*g
, int numArgsPushed
)
507 if (gUDPport
== 0) return errFailed
;
509 socklen_t optlen
= sizeof(opt
);
511 if (getsockopt(gUDPport
->Socket(), SOL_SOCKET
, SO_BROADCAST
, (char *)&opt
, &optlen
) == -1)
513 if (getsockopt(gUDPport
->Socket(), SOL_SOCKET
, SO_BROADCAST
, &opt
, &optlen
) == -1)
520 int prNetAddr_SetBroadcastFlag(VMGlobals
*g
, int numArgsPushed
);
521 int prNetAddr_SetBroadcastFlag(VMGlobals
*g
, int numArgsPushed
)
523 if (gUDPport
== 0) return errFailed
;
524 int opt
= IsTrue(g
->sp
);
526 if (setsockopt(gUDPport
->Socket(), SOL_SOCKET
, SO_BROADCAST
, (char *)&opt
, sizeof(opt
)) == -1)
528 if (setsockopt(gUDPport
->Socket(), SOL_SOCKET
, SO_BROADCAST
, &opt
, sizeof(opt
)) == -1)
534 int prNetAddr_BundleSize(VMGlobals
*g
, int numArgsPushed
);
535 int prNetAddr_BundleSize(VMGlobals
*g
, int numArgsPushed
)
537 PyrSlot
* args
= g
->sp
;
539 int numargs
= slotRawObject(args
)->size
;
540 if (numargs
< 1) return errFailed
;
541 makeSynthBundle(&packet
, slotRawObject(args
)->slots
, numargs
, true);
542 SetInt(args
, packet
.size());
546 int prNetAddr_MsgSize(VMGlobals
*g
, int numArgsPushed
);
547 int prNetAddr_MsgSize(VMGlobals
*g
, int numArgsPushed
)
549 PyrSlot
* args
= g
->sp
;
552 int numargs
= slotRawObject(args
)->size
;
553 if (numargs
< 1) return errFailed
;
554 int error
= makeSynthMsgWithTags(&packet
, slotRawObject(args
)->slots
, numargs
);
555 if (error
!= errNone
)
558 SetInt(args
, packet
.size());
563 int prNetAddr_UseDoubles(VMGlobals
*g
, int numArgsPushed
);
564 int prNetAddr_UseDoubles(VMGlobals
*g
, int numArgsPushed
)
566 //PyrSlot* netAddrSlot = g->sp - 1;
567 PyrSlot
* flag
= g
->sp
;
569 gUseDoubles
= IsTrue(flag
);
574 int prArray_OSCBytes(VMGlobals
*g
, int numArgsPushed
);
575 int prArray_OSCBytes(VMGlobals
*g
, int numArgsPushed
)
578 PyrObject
*array
= slotRawObject(a
);
579 PyrSlot
* args
= array
->slots
;
580 int numargs
= array
->size
;
581 if (numargs
< 1) return errFailed
;
584 if (IsFloat(args
) || IsNil(args
) || IsInt(args
)) {
585 makeSynthBundle(&packet
, args
, numargs
, false);
586 } else if (IsSym(args
) || isKindOfSlot(args
, class_string
)) {
587 int error
= makeSynthMsgWithTags(&packet
, args
, numargs
);
588 if (error
!= errNone
)
594 int size
= packet
.size();
595 PyrInt8Array
* obj
= newPyrInt8Array(g
->gc
, size
, 0, true);
597 memcpy(obj
->b
, packet
.data(), size
);
598 SetObject(a
, (PyrObject
*)obj
);
599 //for (int i=0; i<packet.size()/4; i++) post("%d %p\n", i, packet.buf[i]);
604 // Create a new <PyrInt8Array> object and copy data from `msg.getb'.
605 // Bytes are properly untyped, but there is no <UInt8Array> type.
607 static PyrInt8Array
* MsgToInt8Array ( sc_msg_iter msg
) ;
608 static PyrInt8Array
* MsgToInt8Array ( sc_msg_iter msg
)
610 int size
= msg
.getbsize() ;
611 VMGlobals
*g
= gMainVMGlobals
;
612 PyrInt8Array
*obj
= newPyrInt8Array ( g
->gc
, size
, 0 , true ) ;
614 msg
.getb ( (char *)obj
->b
, obj
->size
) ;
618 PyrObject
* ConvertOSCMessage(int inSize
, char *inData
)
620 char *cmdName
= inData
;
621 int cmdNameLen
= OSCstrlen(cmdName
);
622 sc_msg_iter
msg(inSize
- cmdNameLen
, inData
+ cmdNameLen
);
625 if (inSize
== cmdNameLen
) {
630 error("OSC messages must have type tags. %s\n", cmdName
);
632 numElems
= strlen(msg
.tags
);
635 //post("tags %s %d\n", msg.tags, numElems);
637 VMGlobals
*g
= gMainVMGlobals
;
638 PyrObject
*obj
= newPyrArray(g
->gc
, numElems
+ 1, 0, false);
639 PyrSlot
*slots
= obj
->slots
;
641 SetSymbol(slots
+0, getsym(cmdName
));
643 for (int i
=0; i
<numElems
; ++i
) {
644 char tag
= msg
.nextTag();
645 //post("%d %c\n", i, tag);
648 SetInt(slots
+i
+1, msg
.geti());
651 SetFloat(slots
+i
+1, msg
.getf());
654 SetFloat(slots
+i
+1, msg
.getd());
657 SetSymbol(slots
+i
+1, getsym(msg
.gets()));
658 //post("sym '%s'\n", slots[i+1].us->name);
661 SetObject(slots
+i
+1, (PyrObject
*)MsgToInt8Array(msg
));
664 SetChar(slots
+i
+1, (char)msg
.geti());
666 // else add the type tag as a char (jrhb 2009)
668 SetChar(slots
+i
+1, tag
);
672 obj
->size
= numElems
+ 1;
676 PyrObject
* ConvertReplyAddress(ReplyAddress
*inReply
)
678 VMGlobals
*g
= gMainVMGlobals
;
679 PyrObject
*obj
= instantiateObject(g
->gc
, s_netaddr
->u
.classobj
, 2, true, false);
680 PyrSlot
*slots
= obj
->slots
;
681 SetInt(slots
+0, ntohl(inReply
->mSockAddr
.sin_addr
.s_addr
));
682 SetInt(slots
+1, ntohs(inReply
->mSockAddr
.sin_port
));
686 void PerformOSCBundle(int inSize
, char* inData
, PyrObject
*replyObj
, int inPortNum
)
688 // convert all data to arrays
690 int64 oscTime
= OSCtime(inData
+ 8);
691 double seconds
= OSCToElapsedTime(oscTime
);
693 VMGlobals
*g
= gMainVMGlobals
;
694 ++g
->sp
; SetObject(g
->sp
, g
->process
);
695 ++g
->sp
; SetFloat(g
->sp
, seconds
);
696 ++g
->sp
; SetObject(g
->sp
, replyObj
);
697 ++g
->sp
; SetInt(g
->sp
, inPortNum
);
699 PyrSlot
*stackBase
= g
->sp
;
700 char *data
= inData
+ 16;
701 char* dataEnd
= inData
+ inSize
;
702 while (data
< dataEnd
) {
703 int32 msgSize
= OSCint(data
);
704 data
+= sizeof(int32
);
705 PyrObject
*arrayObj
= ConvertOSCMessage(msgSize
, data
);
706 ++g
->sp
; SetObject(g
->sp
, arrayObj
);
710 int numMsgs
= g
->sp
- stackBase
;
712 runInterpreter(g
, s_recvoscbndl
, 4+numMsgs
);
715 void ConvertOSCBundle(int inSize
, char* inData
, PyrObject
*replyObj
)
717 // convert all data to arrays
719 //int64 oscTime = OSCtime(inData + 8);
720 //double seconds = OSCToElapsedTime(oscTime);
722 VMGlobals
*g
= gMainVMGlobals
;
725 char *data
= inData
+ 16;
726 char* dataEnd
= inData
+ inSize
;
727 while (data
< dataEnd
) {
728 int32 msgSize
= OSCint(data
);
729 data
+= sizeof(int32
);
730 PyrObject
*arrayObj
= ConvertOSCMessage(msgSize
, data
);
731 ++g
->sp
; SetObject(g
->sp
, arrayObj
);
737 void PerformOSCMessage(int inSize
, char *inData
, PyrObject
*replyObj
, int inPortNum
)
740 PyrObject
*arrayObj
= ConvertOSCMessage(inSize
, inData
);
742 // call virtual machine to handle message
743 VMGlobals
*g
= gMainVMGlobals
;
744 ++g
->sp
; SetObject(g
->sp
, g
->process
);
745 ++g
->sp
; SetFloat(g
->sp
, elapsedTime()); // time
746 ++g
->sp
; SetObject(g
->sp
, replyObj
);
747 ++g
->sp
; SetInt(g
->sp
, inPortNum
);
748 ++g
->sp
; SetObject(g
->sp
, arrayObj
);
750 runInterpreter(g
, s_recvoscmsg
, 5);
755 void FreeOSCPacket(OSC_Packet
*inPacket
)
757 //post("->FreeOSCPacket %p\n", inPacket);
759 free(inPacket
->mData
);
764 void ProcessOSCPacket(OSC_Packet
* inPacket
, int inPortNum
)
766 //post("recv '%s' %d\n", inPacket->mData, inPacket->mSize);
767 inPacket
->mIsBundle
= IsBundle(inPacket
->mData
);
769 pthread_mutex_lock (&gLangMutex
);
771 PyrObject
*replyObj
= ConvertReplyAddress(&inPacket
->mReplyAddr
);
773 if (inPacket
->mIsBundle
) {
774 PerformOSCBundle(inPacket
->mSize
, inPacket
->mData
, replyObj
, inPortNum
);
776 PerformOSCMessage(inPacket
->mSize
, inPacket
->mData
, replyObj
, inPortNum
);
780 pthread_mutex_unlock (&gLangMutex
);
782 FreeOSCPacket(inPacket
);
785 void init_OSC(int port
);
786 void init_OSC(int port
)
788 postfl("init_OSC\n");
793 if ((nCode
= WSAStartup(MAKEWORD(1, 1), &wsaData
)) != 0) {
794 error( "sclang: init_OSC: WSAStartup() failed with error code %d.\n", nCode
);
799 gUDPport
= new SC_UdpInPort(port
);
801 postfl("No networking.");
805 int prOpenUDPPort(VMGlobals
*g
, int numArgsPushed
);
806 int prOpenUDPPort(VMGlobals
*g
, int numArgsPushed
)
808 PyrSlot
*a
= g
->sp
- 1;
811 int err
= slotIntVal(b
, &port
);
814 SC_UdpCustomInPort
* newUDPport
;
818 newUDPport
= new SC_UdpCustomInPort(port
);
819 gCustomUdpPorts
.push_back(newUDPport
);
822 postfl("Could not bind to requested port. This may mean it is in use already by another application.\n");
827 void closeAllCustomPorts();
828 void closeAllCustomPorts()
830 // close all custom sockets
831 if(gCustomUdpPorts
.empty()) postfl("empty\n");
832 for(int i
=0; i
<gCustomUdpPorts
.size(); i
++){
833 delete gCustomUdpPorts
[i
];
835 gCustomUdpPorts
.clear();
840 postfl( "cleaning up OSC\n");
846 int prGetHostByName(VMGlobals
*g
, int numArgsPushed
);
847 int prGetHostByName(VMGlobals
*g
, int numArgsPushed
)
852 int err
= slotStrVal(a
, hostname
, 255);
855 struct hostent
*he
= gethostbyname(hostname
);
858 int err
= WSAGetLastError();
859 error("gethostbyname(\"%s\") failed with error code %i.\n",
865 SetInt(a
, ntohl(*(int*)he
->h_addr
));
870 int prGetLangPort(VMGlobals
*g
, int numArgsPushed
);
871 int prGetLangPort(VMGlobals
*g
, int numArgsPushed
)
874 if (!gUDPport
) return errFailed
;
875 SetInt(a
, gUDPport
->RealPortNum());
879 int prExit(VMGlobals
*g
, int numArgsPushed
);
880 int prExit(VMGlobals
*g
, int numArgsPushed
)
886 //post("exit %d\n", slotRawInt(a));
892 int vpost(const char *fmt
, va_list vargs
);
895 #ifndef NO_INTERNAL_SERVER
896 int prBootInProcessServer(VMGlobals
*g
, int numArgsPushed
);
897 int prBootInProcessServer(VMGlobals
*g
, int numArgsPushed
)
901 if (!gInternalSynthServer
.mWorld
) {
902 SetPrintFunc(&vpost
);
903 WorldOptions options
= kDefaultWorldOptions
;
905 PyrObject
*optionsObj
= slotRawObject(a
);
906 PyrSlot
*optionsSlots
= optionsObj
->slots
;
908 static char mInputStreamsEnabled
[512], mOutputStreamsEnabled
[512], mDeviceName
[512];
911 err
= slotIntVal(optionsSlots
+ 0, (int*)&options
.mNumAudioBusChannels
);
914 err
= slotIntVal(optionsSlots
+ 1, (int*)&options
.mNumControlBusChannels
);
917 err
= slotIntVal(optionsSlots
+ 2, (int*)&options
.mNumInputBusChannels
);
920 err
= slotIntVal(optionsSlots
+ 3, (int*)&options
.mNumOutputBusChannels
);
923 err
= slotIntVal(optionsSlots
+ 4, (int*)&options
.mNumBuffers
);
926 err
= slotIntVal(optionsSlots
+ 5, (int*)&options
.mMaxNodes
);
929 err
= slotIntVal(optionsSlots
+ 6, (int*)&options
.mMaxGraphDefs
);
932 err
= slotIntVal(optionsSlots
+ 8, (int*)&options
.mBufLength
);
935 if (NotNil(optionsSlots
+ 9)) {
936 err
= slotIntVal(optionsSlots
+ 9, (int*)&options
.mPreferredHardwareBufferFrameSize
);
940 err
= slotIntVal(optionsSlots
+ 10, (int*)&options
.mRealTimeMemorySize
);
943 err
= slotIntVal(optionsSlots
+ 11, (int*)&options
.mNumRGens
);
946 err
= slotIntVal(optionsSlots
+ 12, (int*)&options
.mMaxWireBufs
);
949 if (NotNil(optionsSlots
+ 13)) {
950 err
= slotIntVal(optionsSlots
+ 13, (int*)&options
.mPreferredSampleRate
);
954 options
.mLoadGraphDefs
= IsTrue(optionsSlots
+ 14) ? 1 : 0;
957 err
= slotStrVal(optionsSlots
+15, mInputStreamsEnabled
, 512);
958 if(err
) options
.mInputStreamsEnabled
= NULL
;
959 else options
.mInputStreamsEnabled
= mInputStreamsEnabled
;
961 err
= slotStrVal(optionsSlots
+16, mOutputStreamsEnabled
, 512);
962 if(err
) options
.mOutputStreamsEnabled
= NULL
;
963 else options
.mOutputStreamsEnabled
= mOutputStreamsEnabled
;
966 err
= slotStrVal(optionsSlots
+17, mDeviceName
, 512);
967 if(err
) options
.mInDeviceName
= options
.mOutDeviceName
= NULL
;
968 else options
.mInDeviceName
= options
.mOutDeviceName
= mDeviceName
;
970 options
.mNumSharedControls
= gInternalSynthServer
.mNumSharedControls
;
971 options
.mSharedControls
= gInternalSynthServer
.mSharedControls
;
973 // internal servers use the PID to identify the shared memory region
974 #if defined(SC_IPHONE)
975 options
.mSharedMemoryID
= 0;
976 #elif !defined(_WIN32)
977 options
.mSharedMemoryID
= getpid();
979 options
.mSharedMemoryID
= GetCurrentProcessId();
982 gInternalSynthServer
.mWorld
= World_New(&options
);
988 int getScopeBuf(uint32 index
, SndBuf
*buf
, bool& didChange
)
990 if (gInternalSynthServer
.mWorld
) {
991 int serverErr
= World_CopySndBuf(gInternalSynthServer
.mWorld
, index
, buf
, true, &didChange
);
992 if (serverErr
) return errFailed
;
998 void* wait_for_quit(void* thing
);
999 void* wait_for_quit(void* thing
)
1001 World
*world
= (World
*)thing
;
1002 World_WaitForQuit(world
);
1006 int prQuitInProcessServer(VMGlobals
*g
, int numArgsPushed
);
1007 int prQuitInProcessServer(VMGlobals
*g
, int numArgsPushed
)
1009 //PyrSlot *a = g->sp;
1011 if (gInternalSynthServer
.mWorld
) {
1012 World
*world
= gInternalSynthServer
.mWorld
;
1013 gInternalSynthServer
.mWorld
= 0;
1016 pthread_create(&thread
, NULL
, wait_for_quit
, (void*)world
);
1017 pthread_detach(thread
);
1023 int prQuitInProcessServer(VMGlobals
*g
, int numArgsPushed
);
1024 int prQuitInProcessServer(VMGlobals
*g
, int numArgsPushed
)
1026 // no-op. Better to have this than to overwrite in lang.
1032 inline int32
BUFMASK(int32 x
)
1034 return (1 << (31 - CLZ(x
))) - 1;
1037 int prAllocSharedControls(VMGlobals
*g
, int numArgsPushed
);
1038 int prAllocSharedControls(VMGlobals
*g
, int numArgsPushed
)
1040 //PyrSlot *a = g->sp - 1;
1043 if (gInternalSynthServer
.mWorld
) {
1044 post("can't allocate while internal server is running\n");
1047 if (gInternalSynthServer
.mSharedControls
!= gDefaultSharedControls
) {
1048 free(gInternalSynthServer
.mSharedControls
);
1049 gInternalSynthServer
.mSharedControls
= gDefaultSharedControls
;
1051 int numSharedControls
;
1052 int err
= slotIntVal(b
, &numSharedControls
);
1053 if (err
) return err
;
1054 if (numSharedControls
<= 0) {
1055 gInternalSynthServer
.mNumSharedControls
= 0;
1056 } else if (numSharedControls
< kNumDefaultSharedControls
) {
1057 gInternalSynthServer
.mNumSharedControls
= numSharedControls
;
1059 gInternalSynthServer
.mNumSharedControls
= numSharedControls
;
1060 gInternalSynthServer
.mSharedControls
= (float*)calloc(numSharedControls
, sizeof(float));
1066 int prGetSharedControl(VMGlobals
*g
, int numArgsPushed
);
1067 int prGetSharedControl(VMGlobals
*g
, int numArgsPushed
)
1069 PyrSlot
*a
= g
->sp
- 1;
1073 int err
= slotIntVal(b
, &index
);
1074 if (err
) return err
;
1075 if (index
< 0 || index
>= gInternalSynthServer
.mNumSharedControls
) {
1079 float val
= gInternalSynthServer
.mSharedControls
[index
];
1084 int prSetSharedControl(VMGlobals
*g
, int numArgsPushed
);
1085 int prSetSharedControl(VMGlobals
*g
, int numArgsPushed
)
1087 //PyrSlot *a = g->sp - 2;
1088 PyrSlot
*b
= g
->sp
- 1;
1092 int err
= slotIntVal(b
, &index
);
1093 if (err
) return err
;
1096 err
= slotFloatVal(c
, &val
);
1097 if (err
) return err
;
1099 if (index
< 0 || index
>= gInternalSynthServer
.mNumSharedControls
) {
1102 gInternalSynthServer
.mSharedControls
[index
] = val
;
1106 static int disconnectSharedMem(VMGlobals
*g
, PyrObject
* object
)
1109 PyrSlot
* ptrSlot
= object
->slots
+ ptrIndex
;
1112 // already disconnected
1115 assert(IsPtr(ptrSlot
));
1117 server_shared_memory_client
* client
= (server_shared_memory_client
*)slotRawPtr(ptrSlot
);
1123 int prConnectSharedMem(VMGlobals
*g
, int numArgsPushed
)
1125 #if !defined(SC_IPHONE)
1126 PyrSlot
*a
= g
->sp
- 1;
1131 PyrObject
* self
= slotRawObject(a
);
1132 int portNumber
= slotRawInt(b
);
1135 int finalizerIndex
= 1;
1138 server_shared_memory_client
* client
= new server_shared_memory_client(portNumber
);
1139 SetPtr(self
->slots
+ ptrIndex
, client
);
1141 InstallFinalizer(g
, self
, finalizerIndex
, disconnectSharedMem
);
1143 postfl("Shared memory server interface initialized\n");
1144 } catch (std::exception
& e
) {
1145 postfl("Cannot connect to shared memory: %s\n", e
.what());
1149 postfl("Warning: Shared memory server interface disabled on iphone\n");
1154 int prDisconnectSharedMem(VMGlobals
*g
, int numArgsPushed
)
1159 PyrObject
* self
= slotRawObject(a
);
1160 return disconnectSharedMem(g
, self
);
1163 int prGetControlBusValue(VMGlobals
*g
, int numArgsPushed
)
1165 PyrSlot
*a
= g
->sp
- 1;
1169 PyrObject
* self
= slotRawObject(a
);
1171 PyrSlot
* ptrSlot
= self
->slots
+ ptrIndex
;
1172 if (NotPtr(ptrSlot
))
1178 int busIndex
= slotRawInt(b
);
1180 if (NotPtr(ptrSlot
))
1183 server_shared_memory_client
* client
= (server_shared_memory_client
*)slotRawPtr(ptrSlot
);
1185 float value
= client
->get_control_busses()[busIndex
];
1190 int prGetControlBusValues(VMGlobals
*g
, int numArgsPushed
)
1192 PyrSlot
*a
= g
->sp
- 2;
1193 PyrSlot
*b
= g
->sp
- 1;
1197 PyrObject
* self
= slotRawObject(a
);
1199 PyrSlot
* ptrSlot
= self
->slots
+ ptrIndex
;
1200 if (NotPtr(ptrSlot
))
1206 int busIndex
= slotRawInt(b
);
1211 int numberOfChannels
= slotRawInt(c
);
1213 server_shared_memory_client
* client
= (server_shared_memory_client
*)slotRawPtr(ptrSlot
);
1215 PyrObject
* ret
= newPyrArray(g
->gc
, numberOfChannels
, 0, 1);
1216 ret
->size
= numberOfChannels
;
1218 for (int i
= 0; i
!= numberOfChannels
; ++i
) {
1219 float value
= client
->get_control_busses()[busIndex
+ i
];
1220 SetFloat(ret
->slots
+i
, value
);
1227 int prSetControlBusValue(VMGlobals
*g
, int numArgsPushed
)
1229 PyrSlot
*a
= g
->sp
- 2;
1230 PyrSlot
*b
= g
->sp
- 1;
1234 PyrObject
* self
= slotRawObject(a
);
1236 PyrSlot
* ptrSlot
= self
->slots
+ ptrIndex
;
1237 if (NotPtr(ptrSlot
))
1243 int busIndex
= slotRawInt(b
);
1245 if (NotPtr(ptrSlot
))
1249 int error
= slotFloatVal(c
, &value
);
1250 if (error
!= errNone
)
1253 server_shared_memory_client
* client
= (server_shared_memory_client
*)slotRawPtr(ptrSlot
);
1255 client
->get_control_busses()[busIndex
] = value
;
1259 int prSetControlBusValues(VMGlobals
*g
, int numArgsPushed
)
1261 PyrSlot
*a
= g
->sp
- 2;
1262 PyrSlot
*b
= g
->sp
- 1;
1266 PyrObject
* self
= slotRawObject(a
);
1268 PyrSlot
* ptrSlot
= self
->slots
+ ptrIndex
;
1269 if (NotPtr(ptrSlot
))
1275 int busIndex
= slotRawInt(b
);
1280 PyrObject
* values
= slotRawObject(c
);
1281 server_shared_memory_client
* client
= (server_shared_memory_client
*)slotRawPtr(ptrSlot
);
1282 float * control_busses
= client
->get_control_busses() + busIndex
;
1284 for (int i
= 0; i
!= values
->size
; ++i
) {
1286 int error
= slotFloatVal(values
->slots
+ i
, &value
);
1287 if (error
!= errNone
)
1290 control_busses
[i
] = value
;
1295 void init_OSC_primitives();
1296 void init_OSC_primitives()
1300 base
= nextPrimitiveIndex();
1303 definePrimitive(base
, index
++, "_NetAddr_Connect", prNetAddr_Connect
, 1, 0);
1304 definePrimitive(base
, index
++, "_NetAddr_Disconnect", prNetAddr_Disconnect
, 1, 0);
1305 definePrimitive(base
, index
++, "_NetAddr_SendMsg", prNetAddr_SendMsg
, 1, 1);
1306 definePrimitive(base
, index
++, "_NetAddr_SendBundle", prNetAddr_SendBundle
, 2, 1);
1307 definePrimitive(base
, index
++, "_NetAddr_SendRaw", prNetAddr_SendRaw
, 2, 0);
1308 definePrimitive(base
, index
++, "_NetAddr_GetBroadcastFlag", prNetAddr_GetBroadcastFlag
, 1, 0);
1309 definePrimitive(base
, index
++, "_NetAddr_SetBroadcastFlag", prNetAddr_SetBroadcastFlag
, 2, 0);
1310 definePrimitive(base
, index
++, "_NetAddr_BundleSize", prNetAddr_BundleSize
, 1, 0);
1311 definePrimitive(base
, index
++, "_NetAddr_MsgSize", prNetAddr_MsgSize
, 1, 0);
1313 definePrimitive(base
, index
++, "_NetAddr_UseDoubles", prNetAddr_UseDoubles
, 2, 0);
1314 definePrimitive(base
, index
++, "_Array_OSCBytes", prArray_OSCBytes
, 1, 0);
1315 definePrimitive(base
, index
++, "_GetHostByName", prGetHostByName
, 1, 0);
1316 definePrimitive(base
, index
++, "_GetLangPort", prGetLangPort
, 1, 0);
1317 definePrimitive(base
, index
++, "_Exit", prExit
, 1, 0);
1318 #ifndef NO_INTERNAL_SERVER
1319 definePrimitive(base
, index
++, "_BootInProcessServer", prBootInProcessServer
, 1, 0);
1321 definePrimitive(base
, index
++, "_QuitInProcessServer", prQuitInProcessServer
, 1, 0);
1322 definePrimitive(base
, index
++, "_AllocSharedControls", prAllocSharedControls
, 2, 0);
1323 definePrimitive(base
, index
++, "_SetSharedControl", prSetSharedControl
, 3, 0);
1324 definePrimitive(base
, index
++, "_GetSharedControl", prGetSharedControl
, 2, 0);
1325 definePrimitive(base
, index
++, "_OpenUDPPort", prOpenUDPPort
, 2, 0);
1327 // server shared memory interface
1328 definePrimitive(base
, index
++, "_ServerShmInterface_connectSharedMem", prConnectSharedMem
, 2, 0);
1329 definePrimitive(base
, index
++, "_ServerShmInterface_disconnectSharedMem", prDisconnectSharedMem
, 1, 0);
1330 definePrimitive(base
, index
++, "_ServerShmInterface_getControlBusValue", prGetControlBusValue
, 2, 0);
1331 definePrimitive(base
, index
++, "_ServerShmInterface_getControlBusValues", prGetControlBusValues
, 3, 0);
1333 definePrimitive(base
, index
++, "_ServerShmInterface_setControlBusValue", prSetControlBusValue
, 3, 0);
1334 definePrimitive(base
, index
++, "_ServerShmInterface_setControlBusValues", prSetControlBusValues
, 4, 0);
1336 //post("initOSCRecs###############\n");
1337 s_call
= getsym("call");
1338 s_write
= getsym("write");
1339 s_recvoscmsg
= getsym("recvOSCmessage");
1340 s_recvoscbndl
= getsym("recvOSCbundle");
1341 s_netaddr
= getsym("NetAddr");