aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans-Christoph Steiner <eighthave@users.sourceforge.net>2008-03-16 17:11:00 +0000
committerHans-Christoph Steiner <eighthave@users.sourceforge.net>2008-03-16 17:11:00 +0000
commit5707565e69d64ba3f619937906f243611eb697ab (patch)
tree839117f6157f9a09ea2c701f58897cd932698c2d
parenta4f81fd0ea345ccf2bed1e38c62b7cf6b10c76a1 (diff)
bringing netsend~1.0alpha11-pd-linux.tar.gz into trunk
svn path=/trunk/externals/olafmatt/; revision=9587
-rwxr-xr-xnetsend~/float_cast.h203
-rwxr-xr-xnetsend~/makefile89
-rw-r--r--netsend~/netreceive~.c1358
-rw-r--r--netsend~/netsend~.c1056
-rw-r--r--netsend~/netsend~.h154
-rwxr-xr-xnetsend~/test-netsend~.pd69
6 files changed, 2929 insertions, 0 deletions
diff --git a/netsend~/float_cast.h b/netsend~/float_cast.h
new file mode 100755
index 0000000..0ebc4bb
--- /dev/null
+++ b/netsend~/float_cast.h
@@ -0,0 +1,203 @@
+/*
+** Copyright (C) 2001-2003 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/* Version 1.3 */
+
+
+/*============================================================================
+** On Intel Pentium processors (especially PIII and probably P4), converting
+** from float to int is very slow. To meet the C specs, the code produced by
+** most C compilers targeting Pentium needs to change the FPU rounding mode
+** before the float to int conversion is performed.
+**
+** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
+** is this flushing of the pipeline which is so slow.
+**
+** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
+** llrint and llrintf which fix this problem as a side effect.
+**
+** On Unix-like systems, the configure process should have detected the
+** presence of these functions. If they weren't found we have to replace them
+** here with a standard C cast.
+*/
+
+/*
+** The C99 prototypes for lrint and lrintf are as follows:
+**
+** long int lrintf (float x) ;
+** long int lrint (double x) ;
+*/
+
+// #include "config.h"
+
+/*
+** The presence of the required functions are detected during the configure
+** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in
+** the config.h file.
+*/
+
+#define HAVE_LRINT_REPLACEMENT 0
+
+#if (HAVE_LRINT && HAVE_LRINTF)
+
+ /*
+ ** These defines enable functionality introduced with the 1999 ISO C
+ ** standard. They must be defined before the inclusion of math.h to
+ ** engage them. If optimisation is enabled, these functions will be
+ ** inlined. With optimisation switched off, you have to link in the
+ ** maths library using -lm.
+ */
+
+ #define _ISOC9X_SOURCE 1
+ #define _ISOC99_SOURCE 1
+
+ #define __USE_ISOC9X 1
+ #define __USE_ISOC99 1
+
+ #include <math.h>
+
+#elif (defined (WIN32) || defined (_WIN32))
+
+ #undef HAVE_LRINT_REPLACEMENT
+ #define HAVE_LRINT_REPLACEMENT 1
+ #include <math.h>
+
+ /*
+ ** Win32 doesn't seem to have these functions.
+ ** Therefore implement inline versions of these functions here.
+ */
+
+ __inline long int
+ lrint (double flt)
+ { int intgr;
+
+ _asm
+ { fld flt
+ fistp intgr
+ } ;
+
+ return intgr ;
+ }
+
+ __inline long int
+ lrintf (float flt)
+ { int intgr;
+
+ _asm
+ { fld flt
+ fistp intgr
+ } ;
+
+ return intgr ;
+ }
+
+#elif (defined (__MWERKS__) && defined (macintosh))
+
+ /* This MacOS 9 solution was provided by Stephane Letz */
+
+ #undef HAVE_LRINT_REPLACEMENT
+ #define HAVE_LRINT_REPLACEMENT 1
+ #include <math.h>
+
+ #undef lrint
+ #undef lrintf
+
+ #define lrint double2int
+ #define lrintf float2int
+
+ inline int
+ float2int (register float in)
+ { long res [2] ;
+
+ asm
+ { fctiw in,in
+ stfd in,res
+ }
+ return res [1] ;
+ } /* float2int */
+
+ inline int
+ double2int (register double in)
+ { long res [2] ;
+
+ asm
+ { fctiw in,in
+ stfd in,res
+ }
+ return res [1] ;
+ } /* double2int */
+
+#elif (defined (__MACH__) && defined (__APPLE__))
+
+ /* For Apple MacOSX. */
+
+ #undef HAVE_LRINT_REPLACEMENT
+ #define HAVE_LRINT_REPLACEMENT 1
+ #include <math.h>
+
+ #undef lrint
+ #undef lrintf
+
+ #define lrint double2int
+ #define lrintf float2int
+
+ inline static long int
+ float2int (register float in)
+ { int res [2] ;
+
+ __asm__ __volatile__
+ ( "fctiw %1, %1\n\t"
+ "stfd %1, %0"
+ : "=m" (res) /* Output */
+ : "f" (in) /* Input */
+ : "memory"
+ ) ;
+
+ return res [1] ;
+ } /* lrintf */
+
+ inline static long int
+ double2int (register double in)
+ { int res [2] ;
+
+ __asm__ __volatile__
+ ( "fctiw %1, %1\n\t"
+ "stfd %1, %0"
+ : "=m" (res) /* Output */
+ : "f" (in) /* Input */
+ : "memory"
+ ) ;
+
+ return res [1] ;
+ } /* lrint */
+
+#else
+ #ifndef __sgi
+ #warning "Don't have the functions lrint() and lrintf()."
+ #warning "Replacing these functions with a standard C cast."
+ #endif
+
+ #include <math.h>
+
+ #define lrint(dbl) ((int) (dbl))
+ #define lrintf(flt) ((int) (flt))
+
+#endif
+
+
+
diff --git a/netsend~/makefile b/netsend~/makefile
new file mode 100755
index 0000000..0f62407
--- /dev/null
+++ b/netsend~/makefile
@@ -0,0 +1,89 @@
+current:
+ echo make pd_linux, pd_nt, pd_irix, pd_darwin
+
+clean: ; rm -f *.pd_linux *.o
+
+# ----------------------- NT -----------------------
+
+pd_nt: netreceive~.dll netsend~.dll
+
+.SUFFIXES: .dll
+
+PDNTCFLAGS = /W3 /WX /DNT /D_WINDOWS /DPD /nologo
+VC="C:\Programme\Microsoft Visual Studio\VC98"
+
+PDNTINCLUDE = /I. /Ic:\pd\tcl\include /Ic:\pd\src /I$(VC)\include
+
+PDNTLDIR = $(VC)\Lib
+PDNTLIB = $(PDNTLDIR)\libc.lib \
+ $(PDNTLDIR)\oldnames.lib \
+ $(PDNTLDIR)\kernel32.lib \
+ $(PDNTLDIR)\user32.lib \
+ $(PDNTLDIR)\uuid.lib \
+ $(PDNTLDIR)\ws2_32.lib \
+ c:\pd\bin\pthreadVC.lib \
+ c:\pd\bin\pd.lib
+
+.c.dll:
+ cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c netreceive~.c
+ cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c netsend~.c
+ link /dll /export:netreceive_tilde_setup netreceive~.obj $(PDNTLIB)
+ link /dll /export:netsend_tilde_setup netsend~.obj $(PDNTLIB)
+
+
+# -------------------- IRIX 6.x (GCC) ---------------------
+
+pd_irix6: netreceive~.pd_irix6 netsend~.pd_irix6
+
+.SUFFIXES: .pd_irix6
+
+# adjust path to PD:
+SGIINCLUDE = -I../../src
+
+SGICFLAGS6 = -mabi=n32 -DPD -DUNIX -DIRIX -DN32 -O3 \
+ -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch -mips4
+
+.c.pd_irix6:
+ gcc $(SGICFLAGS6) $(SGIINCLUDE) -o $*.o -c $*.c
+ ld -n32 -IPA -shared -rdata_shared -o $*.pd_irix6 $*.o
+ rm $*.o
+
+# ----------------------- MAX OS X -------------------
+
+pd_darwin: netreceive~.pd_darwin netsend~.pd_darwin
+
+.SUFFIXES: .pd_darwin
+
+DARWINCFLAGS = -DPD -DUNIX -DMACOSX -O2 \
+ -Wall -W \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+DARWININCLUDE = -I../../src -Iinclude
+
+.c.pd_darwin:
+ cc $(DARWINCFLAGS) $(DARWININCLUDE) -o $*.o -c $*.c
+ cc -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
+ rm -f $*.o ../$*.pd_darwin
+ ln -s $*/$*.pd_darwin ..
+
+# ----------------------- LINUX i386 -----------------------
+
+pd_linux: netreceive~.pd_linux netsend~.pd_linux
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -DUNIX -DHAVE_LRINT -DHAVE_LRINTF -O2 \
+ -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+LINUXINCLUDE = -I../../src
+
+.c.pd_linux:
+ cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ ld -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm
+ strip --strip-unneeded $*.pd_linux
+ rm $*.o
+
diff --git a/netsend~/netreceive~.c b/netsend~/netreceive~.c
new file mode 100644
index 0000000..5998872
--- /dev/null
+++ b/netsend~/netreceive~.c
@@ -0,0 +1,1358 @@
+/* ------------------------ netreceive~ --------------------------------------- */
+/* */
+/* Tilde object to receive uncompressed audio data from netsend~. */
+/* Written by Olaf Matthes <olaf.matthes@gmx.de>. */
+/* Based on streamin~ by Guenter Geiger. */
+/* Get source at http://www.akustische-kunst.org/ */
+/* */
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+/* */
+/* See file LICENSE for further informations on licensing terms. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+/* */
+/* Based on PureData by Miller Puckette and others. */
+/* */
+/* This project was commissioned by the Society for Arts and Technology [SAT], */
+/* Montreal, Quebec, Canada, http://www.sat.qc.ca/. */
+/* */
+/* ---------------------------------------------------------------------------- */
+
+
+#ifdef PD
+#include "m_pd.h"
+#else
+#include "ext.h"
+#include "z_dsp.h"
+#endif
+
+#include "netsend~.h"
+
+#ifdef USE_FAAC
+#include "faad/faad.h"
+#endif
+
+#include <sys/types.h>
+#include <string.h>
+#ifdef UNIX
+#include <sys/socket.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#define SOCKET_ERROR -1
+#else
+#include <winsock.h>
+#endif
+
+#ifndef SOL_IP
+#define SOL_IP IPPROTO_IP
+#endif
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+#define DEFAULT_AUDIO_BUFFER_FRAMES 16 /* a small circ. buffer for 16 frames */
+#define DEFAULT_AVERAGE_NUMBER 10 /* number of values we store for average history */
+#define DEFAULT_NETWORK_POLLTIME 1 /* interval in ms for polling for input data (Max/MSP only) */
+#define DEFAULT_QUEUE_LENGTH 3 /* min. number of buffers that can be used reliably on your hardware */
+
+
+#ifdef UNIX
+#define CLOSESOCKET(fd) close(fd)
+#endif
+#ifdef _WINDOWS
+#define CLOSESOCKET(fd) closesocket(fd)
+#endif
+
+#ifdef PD
+/* these would require to include some headers that are different
+ between pd 0.36 and later, so it's easier to do it like this! */
+EXTERN void sys_rmpollfn(int fd);
+EXTERN void sys_addpollfn(int fd, void* fn, void *ptr);
+#endif
+
+static int netreceive_tilde_sockerror(char *s)
+{
+#ifdef NT
+ int err = WSAGetLastError();
+ if (err == 10054) return 1;
+ else if (err == 10040) post("netsend~: %s: message too long (%d)", s, err);
+ else if (err == 10053) post("netsend~: %s: software caused connection abort (%d)", s, err);
+ else if (err == 10055) post("netsend~: %s: no buffer space available (%d)", s, err);
+ else if (err == 10060) post("netsend~: %s: connection timed out (%d)", s, err);
+ else if (err == 10061) post("netsend~: %s: connection refused (%d)", s, err);
+ else post("netreceive~: %s: %s (%d)", s, strerror(err), err);
+#else
+ int err = errno;
+ post("netreceive~: %s: %s (%d)", s, strerror(err), err);
+#endif
+#ifdef NT
+ if (err == WSAEWOULDBLOCK)
+#endif
+#ifdef UNIX
+ if (err == EAGAIN)
+#endif
+ {
+ return 1; /* recoverable error */
+ }
+ return 0; /* indicate non-recoverable error */
+}
+
+
+static int netreceive_tilde_setsocketoptions(int sockfd)
+{
+ int sockopt = 1;
+ if (setsockopt(sockfd, SOL_IP, TCP_NODELAY, (const char*)&sockopt, sizeof(int)) < 0)
+ post("setsockopt NODELAY failed");
+
+ sockopt = 1;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&sockopt, sizeof(int)) < 0)
+ post("netreceive~: setsockopt REUSEADDR failed");
+ return 0;
+}
+
+
+
+/* ------------------------ netreceive~ ----------------------------- */
+
+
+static t_class *netreceive_tilde_class;
+static t_symbol *ps_format, *ps_channels, *ps_framesize, *ps_overflow, *ps_underflow,
+ *ps_queuesize, *ps_average, *ps_sf_float, *ps_sf_16bit, *ps_sf_8bit,
+ *ps_sf_mp3, *ps_sf_aac, *ps_sf_unknown, *ps_bitrate, *ps_hostname, *ps_nothing;
+
+
+typedef struct _netreceive_tilde
+{
+#ifdef PD
+ t_object x_obj;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+#else
+ t_pxobject x_obj;
+ void *x_outlet1;
+ void *x_outlet2;
+ void *x_connectpoll;
+ void *x_datapoll;
+#endif
+ int x_socket;
+ int x_connectsocket;
+ int x_nconnections;
+ int x_ndrops;
+ int x_tcp;
+ t_symbol *x_hostname;
+
+ /* buffering */
+ int x_framein;
+ int x_frameout;
+ t_frame x_frames[DEFAULT_AUDIO_BUFFER_FRAMES];
+ int x_maxframes;
+ long x_framecount;
+ int x_blocksize;
+ int x_blocksperrecv;
+ int x_blockssincerecv;
+
+ int x_nbytes;
+ int x_counter;
+ int x_average[DEFAULT_AVERAGE_NUMBER];
+ int x_averagecur;
+ int x_underflow;
+ int x_overflow;
+
+#ifdef USE_FAAC
+ faacDecHandle x_faac_decoder;
+ faacDecFrameInfo x_faac_frameInfo;
+ faacDecConfigurationPtr x_faac_config;
+ int x_faac_init;
+ unsigned char x_faac_buf[FAAD_MIN_STREAMSIZE * DEFAULT_AUDIO_CHANNELS];
+ unsigned long x_faac_bytes;
+#endif
+
+ long x_samplerate;
+ int x_noutlets;
+ int x_vecsize;
+ t_int **x_myvec; /* vector we pass on to the DSP routine */
+} t_netreceive_tilde;
+
+
+
+/* prototypes (as needed) */
+static void netreceive_tilde_kick(t_netreceive_tilde *x);
+
+
+
+#ifdef USE_FAAC
+/* open encoder and set default values */
+static void netreceive_tilde_faac_open(t_netreceive_tilde* x)
+{
+ x->x_faac_decoder = faacDecOpen();
+ x->x_faac_config = faacDecGetCurrentConfiguration(x->x_faac_decoder);
+ x->x_faac_config->defSampleRate = x->x_samplerate;
+ x->x_faac_config->defObjectType = MAIN; // LC;
+ x->x_faac_config->outputFormat = FAAD_FMT_FLOAT;
+ faacDecSetConfiguration(x->x_faac_decoder, x->x_faac_config);
+ x->x_faac_init = 0;
+ x->x_faac_bytes = 0;
+}
+
+static void netreceive_tilde_faac_close(t_netreceive_tilde* x)
+{
+ if (x->x_faac_decoder != NULL)
+ faacDecClose(x->x_faac_decoder);
+ x->x_faac_decoder = NULL;
+ x->x_faac_init = 0;
+}
+
+/* init decoder when we get a new stream */
+static int netreceive_tilde_faac_init(t_netreceive_tilde* x, int frame)
+{
+ unsigned long samplerate;
+ unsigned char channels;
+ long bytes_consumed = 0;
+
+ if ((bytes_consumed = faacDecInit(x->x_faac_decoder, x->x_faac_buf, x->x_faac_bytes, &samplerate, &channels)) < 0)
+ {
+ faacDecConfigurationPtr config;
+ error("netreceive~: faac: initializing decoder library failed");
+ netreceive_tilde_faac_close(x);
+ return -1;
+ }
+ else if (samplerate != (unsigned long)x->x_samplerate)
+ {
+ error("netreceive~: incoming stream has wrong samplerate");
+ netreceive_tilde_faac_close(x);
+ return -1;
+ }
+
+ /* adjust accumulating AAC buffer */
+ memmove(x->x_faac_buf, x->x_faac_buf + bytes_consumed, x->x_faac_bytes - bytes_consumed);
+ x->x_faac_bytes -= bytes_consumed;
+
+ x->x_faac_init = 1; /* indicate that decoder is ready */
+ return 0;
+}
+
+/* decode AAC using FAAD2 library */
+static int netreceive_tilde_faac_decode(t_netreceive_tilde* x, int frame)
+{
+ unsigned int i, ret;
+ float *sample_buffer;
+
+ /* open decoder, if not yet done */
+ if (x->x_faac_decoder == NULL)
+ {
+ netreceive_tilde_faac_open(x);
+ }
+
+ /* add new AAC data into buffer */
+ memcpy(x->x_faac_buf + x->x_faac_bytes, x->x_frames[frame].data, x->x_frames[frame].tag.framesize);
+ x->x_faac_bytes += x->x_frames[frame].tag.framesize;
+
+ /* in case we have more than FAAD_MIN_STREAMSIZE bytes per channel try decoding */
+ if (x->x_faac_bytes >= (unsigned long)(FAAD_MIN_STREAMSIZE * x->x_frames[frame].tag.channels))
+ {
+ /* init decoder, if not yet done */
+ if (!x->x_faac_init)
+ {
+ ret = netreceive_tilde_faac_init(x, frame);
+ if (ret == -1)
+ {
+ return -1;
+ }
+ }
+
+ /* decode data */
+ memset(&x->x_faac_frameInfo, 0, sizeof(faacDecFrameInfo));
+ sample_buffer = (float *)faacDecDecode(x->x_faac_decoder, &x->x_faac_frameInfo, x->x_faac_buf, x->x_faac_bytes);
+ if (x->x_faac_frameInfo.error != 0)
+ {
+ error("netreceive~: faac: %s", faacDecGetErrorMessage(x->x_faac_frameInfo.error));
+ netreceive_tilde_faac_close(x);
+ return -1;
+ }
+
+ /* adjust accumulating AAC buffer */
+ memmove(x->x_faac_buf, x->x_faac_buf + x->x_faac_frameInfo.bytesconsumed, x->x_faac_bytes - x->x_faac_frameInfo.bytesconsumed);
+ x->x_faac_bytes -= x->x_faac_frameInfo.bytesconsumed;
+
+ /* copy decoded PCM samples back to frame */
+ memcpy(x->x_frames[frame].data, sample_buffer, x->x_faac_frameInfo.samples * sizeof(float));
+
+ /* return number of decoded PCM samples */
+ return x->x_faac_frameInfo.samples * SF_SIZEOF(SF_FLOAT);
+ }
+ else
+ {
+ return 0; /* indicate we didn't get any new audio data */
+ }
+}
+#endif /* USE_FAAC */
+
+
+
+
+/* remove all pollfunctions and close socket */
+static void netreceive_tilde_closesocket(t_netreceive_tilde* x)
+{
+#ifdef PD
+ sys_rmpollfn(x->x_socket);
+ outlet_float(x->x_outlet1, 0);
+#else
+ clock_unset(x->x_datapoll);
+ outlet_int(x->x_outlet1, 0);
+#endif
+ CLOSESOCKET(x->x_socket);
+ x->x_socket = -1;
+}
+
+
+
+#ifdef PD
+static void netreceive_tilde_reset(t_netreceive_tilde* x, t_floatarg buffer)
+#else
+static void netreceive_tilde_reset(t_netreceive_tilde* x, double buffer)
+#endif
+{
+ int i;
+ x->x_counter = 0;
+ x->x_nbytes = 0;
+ x->x_framein = 0;
+ x->x_frameout = 0;
+ x->x_blockssincerecv = 0;
+ x->x_blocksperrecv = x->x_blocksize / x->x_vecsize;
+#ifdef USE_FAAC
+ x->x_faac_bytes = 0;
+#endif
+
+ for (i = 0; i < DEFAULT_AVERAGE_NUMBER; i++)
+ x->x_average[i] = x->x_maxframes;
+ x->x_averagecur = 0;
+
+ if (buffer == 0.0) /* set default */
+ x->x_maxframes = DEFAULT_QUEUE_LENGTH;
+ else
+ {
+ buffer = (float)CLIP((float)buffer, 0., 1.);
+ x->x_maxframes = (int)(DEFAULT_AUDIO_BUFFER_FRAMES * buffer);
+ x->x_maxframes = CLIP(x->x_maxframes, 1, DEFAULT_AUDIO_BUFFER_FRAMES - 1);
+ post("netreceive~: set buffer to %g (%d frames)", buffer, x->x_maxframes);
+ }
+ x->x_underflow = 0;
+ x->x_overflow = 0;
+}
+
+
+static void netreceive_tilde_datapoll(t_netreceive_tilde *x)
+{
+#ifndef PD
+ int ret;
+ struct timeval timout;
+ fd_set readset;
+ timout.tv_sec = 0;
+ timout.tv_usec = 0;
+ FD_ZERO(&readset);
+ FD_SET(x->x_socket, &readset);
+
+ ret = select(x->x_socket + 1, &readset, NULL, NULL, &timout);
+ if (ret < 0)
+ {
+ netreceive_tilde_sockerror("select");
+ return;
+ }
+
+ if (FD_ISSET(x->x_socket, &readset)) /* data available */
+#endif
+ {
+ int ret;
+ int n;
+
+ if (x->x_tcp)
+ {
+ n = x->x_nbytes;
+
+ if (x->x_nbytes == 0) /* we ate all the samples and need a new header tag */
+ {
+ /* get the new tag */
+ ret = recv(x->x_socket, (char*)&x->x_frames[x->x_framein].tag, sizeof(t_tag), MSG_PEEK);
+ if (ret == 0) /* disconnect */
+ {
+ post("netreceive~: EOF on socket %d", x->x_socket);
+ netreceive_tilde_closesocket(x);
+ x->x_socket = -1;
+ x->x_counter = 0;
+ return;
+ }
+ if (ret < 0) /* error */
+ {
+ if (netreceive_tilde_sockerror("recv tag"))
+ goto bail;
+ netreceive_tilde_closesocket(x);
+ x->x_socket = -1;
+ x->x_counter = 0;
+ return;
+ }
+ else if (ret != sizeof(t_tag))
+ {
+ /* incomplete header tag: return and try again later */
+ /* in the hope that more data will be available */
+ return;
+ }
+
+ /* receive header tag */
+ ret = recv(x->x_socket, (char*)&x->x_frames[x->x_framein].tag, sizeof(t_tag), 0);
+
+ /* adjust byte order if neccessarry */
+ if (x->x_frames[x->x_framein].tag.version != SF_BYTE_NATIVE)
+ {
+ x->x_frames[x->x_framein].tag.count = netsend_long(x->x_frames[x->x_framein].tag.count);
+ x->x_frames[x->x_framein].tag.framesize = netsend_long(x->x_frames[x->x_framein].tag.framesize);
+ }
+
+ /* get info from header tag */
+ if (x->x_frames[x->x_framein].tag.channels > x->x_noutlets)
+ {
+ error("netreceive~: incoming stream has too many channels (%d), kicking client", x->x_frames[x->x_framein].tag.channels);
+ netreceive_tilde_kick(x);
+ x->x_socket = -1;
+ x->x_counter = 0;
+ return;
+ }
+ x->x_nbytes = n = x->x_frames[x->x_framein].tag.framesize;
+
+ /* check whether the data packet has the correct count */
+ if ((x->x_framecount != x->x_frames[x->x_framein].tag.count)
+ && (x->x_frames[x->x_framein].tag.count > 2))
+ {
+ error("netreceive~: we lost %d frames", (int)(x->x_frames[x->x_framein].tag.count - x->x_framecount));
+ post("netreceive~: current package is %d, expected %d", x->x_frames[x->x_framein].tag.count, x->x_framecount);
+ }
+ x->x_framecount = x->x_frames[x->x_framein].tag.count + 1;
+ }
+ else /* we already have the header tag or some data and need more */
+ {
+ ret = recv(x->x_socket, (char*)x->x_frames[x->x_framein].data + x->x_frames[x->x_framein].tag.framesize - n, n, 0);
+ if (ret > 0)
+ {
+ n -= ret;
+ }
+ else if (ret < 0) /* error */
+ {
+ if (netreceive_tilde_sockerror("recv data"))
+ goto bail;
+ netreceive_tilde_closesocket(x);
+ x->x_socket = -1;
+ x->x_counter = 0;
+ return;
+ }
+
+ x->x_nbytes = n;
+ if (n == 0) /* a complete packet is received */
+ {
+#ifdef USE_FAAC /* decode aac data if format is SF_AAC */
+ if (x->x_frames[x->x_framein].tag.format == SF_AAC)
+ {
+ ret = netreceive_tilde_faac_decode(x, x->x_framein);
+ if (ret == -1)
+ {
+ netreceive_tilde_kick(x);
+ x->x_socket = -1;
+ x->x_counter = 0;
+ return;
+ }
+ else
+ {
+ /* update framesize */
+ x->x_frames[x->x_framein].tag.framesize = ret;
+ }
+ }
+#else
+ if (x->x_frames[x->x_framein].tag.format == SF_AAC)
+ {
+ error("netreceive~: don't know how to decode AAC format");
+ netreceive_tilde_kick(x);
+ x->x_socket = -1;
+ x->x_counter = 0;
+ return;
+ }
+#endif
+
+ x->x_counter++;
+ x->x_framein++;
+ x->x_framein %= DEFAULT_AUDIO_BUFFER_FRAMES;
+
+ /* check for buffer overflow */
+ if (x->x_framein == x->x_frameout)
+ {
+ x->x_overflow++;
+ }
+ }
+ }
+ }
+ else /* UDP */
+ {
+ n = x->x_nbytes;
+
+ if (x->x_nbytes == 0) /* we ate all the samples and need a new header tag */
+ {
+ /* receive header tag */
+ ret = recv(x->x_socket, (char*)&x->x_frames[x->x_framein].tag, sizeof(t_tag), 0);
+ if (ret <= 0) /* error */
+ {
+ if (netreceive_tilde_sockerror("recv tag"))
+ goto bail;
+ netreceive_tilde_reset(x, 0);
+ x->x_counter = 0;
+ return;
+ }
+ else if (ret != sizeof(t_tag))
+ {
+ /* incomplete header tag: return and try again later */
+ /* in the hope that more data will be available */
+ error("netreceive~: got incomplete header tag");
+ return;
+ }
+ /* adjust byte order if neccessarry */
+ if (x->x_frames[x->x_framein].tag.version != SF_BYTE_NATIVE)
+ {
+ x->x_frames[x->x_framein].tag.count = netsend_long(x->x_frames[x->x_framein].tag.count);
+ x->x_frames[x->x_framein].tag.framesize = netsend_long(x->x_frames[x->x_framein].tag.framesize);
+ }
+ /* get info from header tag */
+ if (x->x_frames[x->x_framein].tag.channels > x->x_noutlets)
+ {
+ error("netreceive~: incoming stream has too many channels (%d)", x->x_frames[x->x_framein].tag.channels);
+ x->x_counter = 0;
+ return;
+ }
+ x->x_nbytes = n = x->x_frames[x->x_framein].tag.framesize;
+ }
+ else /* we already have header tag or some data and need more */
+ {
+ ret = recv(x->x_socket, (char*)x->x_frames[x->x_framein].data + x->x_frames[x->x_framein].tag.framesize - n, n, 0);
+ if (ret > 0)
+ {
+ n -= ret;
+ }
+ else if (ret < 0) /* error */
+ {
+ if (netreceive_tilde_sockerror("recv data"))
+ goto bail;
+ netreceive_tilde_reset(x, 0);
+ x->x_counter = 0;
+ return;
+ }
+
+ x->x_nbytes = n;
+ if (n == 0) /* a complete packet is received */
+ {
+#ifdef USE_FAAC /* decode aac data if format is SF_AAC and update framesize */
+ if (x->x_frames[x->x_framein].tag.format == SF_AAC)
+ {
+ ret = netreceive_tilde_faac_decode(x, x->x_framein);
+ if (ret == -1)
+ {
+ return;
+ }
+ else
+ {
+ /* update framesize */
+ x->x_frames[x->x_framein].tag.framesize = ret;
+ }
+ }
+#else
+ if (x->x_frames[x->x_framein].tag.format == SF_AAC)
+ {
+ error("netreceive~: don't know how to decode AAC format");
+ return;
+ }
+#endif
+ x->x_counter++;
+ x->x_framein++;
+ x->x_framein %= DEFAULT_AUDIO_BUFFER_FRAMES;
+
+ /* check for buffer overflow */
+ if (x->x_framein == x->x_frameout)
+ {
+ x->x_overflow++;
+ }
+ }
+ }
+ }
+ }
+bail:
+ ;
+#ifndef PD
+ clock_delay(x->x_datapoll, DEFAULT_NETWORK_POLLTIME);
+#endif
+}
+
+
+static void netreceive_tilde_connectpoll(t_netreceive_tilde *x)
+{
+#ifndef PD
+ int ret;
+ struct timeval timout;
+ fd_set readset;
+ timout.tv_sec = 0;
+ timout.tv_usec = 0;
+ FD_ZERO(&readset);
+ FD_SET(x->x_connectsocket, &readset);
+
+ ret = select(x->x_connectsocket + 1, &readset, NULL, NULL, &timout);
+ if (ret < 0)
+ {
+ netreceive_tilde_sockerror("select");
+ return;
+ }
+
+ if (FD_ISSET(x->x_connectsocket, &readset)) /* pending connection */
+#endif
+ {
+ int sockaddrl = (int)sizeof(struct sockaddr);
+ struct sockaddr_in incomer_address;
+ int fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrl);
+ if (fd < 0)
+ {
+ post("netreceive~: accept failed");
+ return;
+ }
+#ifdef O_NONBLOCK
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+#endif
+ if (x->x_socket != -1)
+ {
+ post("netreceive~: new connection");
+ netreceive_tilde_closesocket(x);
+ }
+
+ netreceive_tilde_reset(x, 0);
+ x->x_socket = fd;
+ x->x_nbytes = 0;
+ x->x_hostname = gensym(inet_ntoa(incomer_address.sin_addr));
+#ifdef PD
+ sys_addpollfn(fd, netreceive_tilde_datapoll, x);
+ outlet_float(x->x_outlet1, 1);
+#else
+ clock_delay(x->x_datapoll, 0);
+ outlet_int(x->x_outlet1, 1);
+#endif
+ }
+#ifndef PD
+ clock_delay(x->x_connectpoll, DEFAULT_NETWORK_POLLTIME);
+#endif
+}
+
+
+static int netreceive_tilde_createsocket(t_netreceive_tilde* x, int portno)
+{
+ struct sockaddr_in server;
+ int sockfd;
+ int tcp = x->x_tcp;
+
+ /* create a socket */
+ if (!tcp)
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ else
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (sockfd < 0)
+ {
+ netreceive_tilde_sockerror("socket");
+ return 0;
+ }
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+
+ /* assign server port number */
+
+ server.sin_port = htons((u_short)portno);
+ post("listening to port number %d", portno);
+
+ netreceive_tilde_setsocketoptions(sockfd);
+
+ /* name the socket */
+ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
+ {
+ netreceive_tilde_sockerror("bind");
+ CLOSESOCKET(sockfd);
+ return 0;
+ }
+
+
+ if (!tcp)
+ {
+ x->x_socket = sockfd;
+ x->x_nbytes = 0;
+#ifdef PD
+ sys_addpollfn(sockfd, netreceive_tilde_datapoll, x);
+#else
+ clock_delay(x->x_datapoll, 0);
+#endif
+ }
+ else
+ {
+ if (listen(sockfd, 5) < 0)
+ {
+ netreceive_tilde_sockerror("listen");
+ CLOSESOCKET(sockfd);
+ return 0;
+ }
+ else
+ {
+ x->x_connectsocket = sockfd;
+ /* start polling for connection requests */
+#ifdef PD
+ sys_addpollfn(sockfd, netreceive_tilde_connectpoll, x);
+#else
+ clock_delay(x->x_connectpoll, 0);
+#endif
+ }
+ }
+ return 1;
+}
+
+
+
+/* kick connected client */
+static void netreceive_tilde_kick(t_netreceive_tilde *x)
+{
+ if (x->x_tcp)
+ {
+ if (x->x_socket != -1)
+ {
+ shutdown(x->x_socket, 1);
+ netreceive_tilde_closesocket(x);
+ post("netreceive~: kicked client!");
+ }
+ else error("netreceive~: no client to kick");
+ }
+ else error("netreceive~: kicking clients in UDP mode not possible");
+}
+
+
+#define QUEUESIZE (int)((x->x_framein + DEFAULT_AUDIO_BUFFER_FRAMES - x->x_frameout) % DEFAULT_AUDIO_BUFFER_FRAMES)
+#define BLOCKOFFSET (x->x_blockssincerecv * x->x_vecsize * x->x_frames[x->x_frameout].tag.channels)
+
+static t_int *netreceive_tilde_perform(t_int *w)
+{
+ t_netreceive_tilde *x = (t_netreceive_tilde*) (w[1]);
+ int n = (int)(w[2]);
+ t_float *out[DEFAULT_AUDIO_CHANNELS];
+ const int offset = 3;
+ const int channels = x->x_frames[x->x_frameout].tag.channels;
+ int i = 0;
+
+ for (i = 0; i < x->x_noutlets; i++)
+ {
+ out[i] = (t_float *)(w[offset + i]);
+ }
+
+ if (n != x->x_vecsize)
+ {
+ x->x_vecsize = n;
+ x->x_blocksperrecv = x->x_blocksize / x->x_vecsize;
+ x->x_blockssincerecv = 0;
+ }
+
+ /* check whether there is enough data in buffer */
+ if (x->x_counter < x->x_maxframes)
+ {
+ goto bail;
+ }
+
+ /* check for buffer underflow */
+ if (x->x_framein == x->x_frameout)
+ {
+ x->x_underflow++;
+ goto bail;
+ }
+
+
+ /* queue balancing */
+ x->x_average[x->x_averagecur] = QUEUESIZE;
+ if (++x->x_averagecur >= DEFAULT_AVERAGE_NUMBER)
+ x->x_averagecur = 0;
+
+ switch (x->x_frames[x->x_frameout].tag.format)
+ {
+ case SF_FLOAT:
+ {
+ t_float* buf = (t_float *)x->x_frames[x->x_frameout].data + BLOCKOFFSET;
+
+ if (x->x_frames[x->x_frameout].tag.version == SF_BYTE_NATIVE)
+ {
+ while (n--)
+ {
+ for (i = 0; i < channels; i++)
+ {
+ *out[i]++ = *buf++;
+ }
+ for (i = channels; i < x->x_noutlets; i++)
+ {
+ *out[i]++ = 0.;
+ }
+ }
+ }
+ else /* swap bytes */
+ {
+ while (n--)
+ {
+ for (i = 0; i < channels; i++)
+ {
+ *out[i]++ = netsend_float(*buf++);
+ }
+ for (i = channels; i < x->x_noutlets; i++)
+ {
+ *out[i]++ = 0.;
+ }
+ }
+ }
+ break;
+ }
+ case SF_16BIT:
+ {
+ short* buf = (short *)x->x_frames[x->x_frameout].data + BLOCKOFFSET;
+
+ if (x->x_frames[x->x_frameout].tag.version == SF_BYTE_NATIVE)
+ {
+ while (n--)
+ {
+ for (i = 0; i < channels; i++)
+ {
+ *out[i]++ = (t_float)(*buf++ * 3.051850e-05);
+ }
+ for (i = channels; i < x->x_noutlets; i++)
+ {
+ *out[i]++ = 0.;
+ }
+ }
+ }
+ else /* swap bytes */
+ {
+ while (n--)
+ {
+ for (i = 0; i < channels; i++)
+ {
+ *out[i]++ = (t_float)(netsend_short(*buf++) * 3.051850e-05);
+ }
+ for (i = channels; i < x->x_noutlets; i++)
+ {
+ *out[i]++ = 0.;
+ }
+ }
+ }
+ break;
+ }
+ case SF_8BIT:
+ {
+ unsigned char* buf = (char *)x->x_frames[x->x_frameout].data + BLOCKOFFSET;
+
+ while (n--)
+ {
+ for (i = 0; i < channels; i++)
+ {
+ *out[i]++ = (t_float)((0.0078125 * (*buf++)) - 1.0);
+ }
+ for (i = channels; i < x->x_noutlets; i++)
+ {
+ *out[i]++ = 0.;
+ }
+ }
+ break;
+ }
+ case SF_MP3:
+ {
+ post("netreceive~: mp3 format not supported");
+ if (x->x_tcp)
+ netreceive_tilde_kick(x);
+ break;
+ }
+ case SF_AAC:
+ {
+#ifdef USE_FAAC
+ t_float* buf = (t_float *)x->x_frames[x->x_frameout].data + BLOCKOFFSET;
+
+ while (n--)
+ {
+ for (i = 0; i < channels; i++)
+ {
+ *out[i]++ = (t_float)(*buf++);
+ }
+ for (i = channels; i < x->x_noutlets; i++)
+ {
+ *out[i]++ = 0.;
+ }
+ }
+ break;
+#else
+ post("netreceive~: aac format not supported");
+ if (x->x_tcp)
+ netreceive_tilde_kick(x);
+#endif
+ break;
+ }
+ default:
+ post("netreceive~: unknown format (%d)",x->x_frames[x->x_frameout].tag.format);
+ if (x->x_tcp)
+ netreceive_tilde_kick(x);
+ break;
+ }
+
+ if (!(x->x_blockssincerecv < x->x_blocksperrecv - 1))
+ {
+ x->x_blockssincerecv = 0;
+ x->x_frameout++;
+ x->x_frameout %= DEFAULT_AUDIO_BUFFER_FRAMES;
+ }
+ else
+ {
+ x->x_blockssincerecv++;
+ }
+
+ return (w + offset + x->x_noutlets);
+
+bail:
+ /* set output to zero */
+ while (n--)
+ {
+ for (i = 0; i < x->x_noutlets; i++)
+ {
+ *(out[i]++) = 0.;
+ }
+ }
+ return (w + offset + x->x_noutlets);
+}
+
+
+
+static void netreceive_tilde_dsp(t_netreceive_tilde *x, t_signal **sp)
+{
+ int i;
+
+ x->x_myvec[0] = (t_int*)x;
+ x->x_myvec[1] = (t_int*)sp[0]->s_n;
+
+ x->x_samplerate = (long)sp[0]->s_sr;
+
+ if (DEFAULT_AUDIO_BUFFER_SIZE % sp[0]->s_n)
+ {
+ error("netsend~: signal vector size too large (needs to be even divisor of %d)", DEFAULT_AUDIO_BUFFER_SIZE);
+ }
+ else
+ {
+#ifdef PD
+ for (i = 0; i < x->x_noutlets; i++)
+ {
+ x->x_myvec[2 + i] = (t_int*)sp[i + 1]->s_vec;
+ }
+ dsp_addv(netreceive_tilde_perform, x->x_noutlets + 2, (t_int*)x->x_myvec);
+#else
+ for (i = 0; i < x->x_noutlets; i++)
+ {
+ x->x_myvec[2 + i] = (t_int*)sp[i]->s_vec;
+ }
+ dsp_addv(netreceive_tilde_perform, x->x_noutlets + 2, (void **)x->x_myvec);
+#endif /* PD */
+ }
+}
+
+
+/* send stream info when banged */
+static void netreceive_tilde_bang(t_netreceive_tilde *x)
+{
+ t_atom list[2];
+ t_symbol *sf_format;
+ t_float bitrate;
+ int i, avg = 0;
+ for (i = 0; i < DEFAULT_AVERAGE_NUMBER; i++)
+ avg += x->x_average[i];
+
+ bitrate = (t_float)((SF_SIZEOF(x->x_frames[x->x_frameout].tag.format) * x->x_samplerate * 8 * x->x_frames[x->x_frameout].tag.channels) / 1000.);
+
+ switch (x->x_frames[x->x_frameout].tag.format)
+ {
+ case SF_FLOAT:
+ {
+ sf_format = ps_sf_float;
+ break;
+ }
+ case SF_16BIT:
+ {
+ sf_format = ps_sf_16bit;
+ break;
+ }
+ case SF_8BIT:
+ {
+ sf_format = ps_sf_8bit;
+ break;
+ }
+ case SF_MP3:
+ {
+ sf_format = ps_sf_mp3;
+ break;
+ }
+ case SF_AAC:
+ {
+ sf_format = ps_sf_aac;
+ break;
+ }
+ default:
+ {
+ sf_format = ps_sf_unknown;
+ break;
+ }
+ }
+
+#ifdef PD
+ /* --- stream information (t_tag) --- */
+ /* audio format */
+ SETSYMBOL(list, (t_symbol *)sf_format);
+ outlet_anything(x->x_outlet2, ps_format, 1, list);
+
+ /* channels */
+ SETFLOAT(list, (t_float)x->x_frames[x->x_frameout].tag.channels);
+ outlet_anything(x->x_outlet2, ps_channels, 1, list);
+
+ /* framesize */
+ SETFLOAT(list, (t_float)x->x_frames[x->x_frameout].tag.framesize);
+ outlet_anything(x->x_outlet2, ps_framesize, 1, list);
+
+ /* bitrate */
+ SETFLOAT(list, (t_float)bitrate);
+ outlet_anything(x->x_outlet2, ps_bitrate, 1, list);
+
+ /* --- internal info (buffer and network) --- */
+ /* overflow */
+ SETFLOAT(list, (t_float)x->x_overflow);
+ outlet_anything(x->x_outlet2, ps_overflow, 1, list);
+
+ /* underflow */
+ SETFLOAT(list, (t_float)x->x_underflow);
+ outlet_anything(x->x_outlet2, ps_underflow, 1, list);
+
+ /* queuesize */
+ SETFLOAT(list, (t_float)QUEUESIZE);
+ outlet_anything(x->x_outlet2, ps_queuesize, 1, list);
+
+ /* average queuesize */
+ SETFLOAT(list, (t_float)((t_float)avg / (t_float)DEFAULT_AVERAGE_NUMBER));
+ outlet_anything(x->x_outlet2, ps_average, 1, list);
+
+ if (x->x_tcp)
+ {
+ /* IP address */
+ SETSYMBOL(list, (t_symbol *)x->x_hostname);
+ outlet_anything(x->x_outlet2, ps_hostname, 1, list);
+ }
+#else
+ /* --- stream information (t_tag) --- */
+ /* audio format */
+ SETSYM(list, ps_format);
+ SETSYM(list + 1, (t_symbol *)sf_format);
+ outlet_list(x->x_outlet2, NULL, 2, list);
+
+ /* channels */
+ SETSYM(list, ps_channels);
+ SETLONG(list + 1, (int)x->x_frames[x->x_frameout].tag.channels);
+ outlet_list(x->x_outlet2, NULL, 2, list);
+
+ /* framesize */
+ SETSYM(list, ps_framesize);
+ SETLONG(list + 1, (int)x->x_frames[x->x_frameout].tag.framesize);
+ outlet_list(x->x_outlet2, NULL, 2, list);
+
+ /* bitrate */
+ SETSYM(list, ps_bitrate);
+ SETFLOAT(list + 1, (t_float)bitrate);
+ outlet_list(x->x_outlet2, NULL, 2, list);
+
+ /* --- internal info (buffer and network) --- */
+ /* overflow */
+ SETSYM(list, ps_overflow);
+ SETLONG(list + 1, (int)x->x_overflow);
+ outlet_list(x->x_outlet2, NULL, 2, list);
+
+ /* underflow */
+ SETSYM(list, ps_underflow);
+ SETLONG(list + 1, (int)x->x_underflow);
+ outlet_list(x->x_outlet2, NULL, 2, list);
+
+ /* queuesize */
+ SETSYM(list, ps_queuesize);
+ SETLONG(list + 1, (int)QUEUESIZE);
+ outlet_list(x->x_outlet2, NULL, 2, list);
+
+ /* average queuesize */
+ SETSYM(list, ps_average);
+ SETFLOAT(list + 1, (t_float)((t_float)avg / (t_float)DEFAULT_AVERAGE_NUMBER));
+ outlet_list(x->x_outlet2, NULL, 2, list);
+
+ if (x->x_tcp)
+ {
+ /* IP address */
+ SETSYM(list, (t_symbol *)ps_hostname);
+ SETSYM(list + 1, x->x_hostname);
+ outlet_list(x->x_outlet2, NULL, 2, list);
+ }
+#endif
+}
+
+
+
+static void netreceive_tilde_print(t_netreceive_tilde* x)
+{
+ int i, avg = 0;
+ for (i = 0; i < DEFAULT_AVERAGE_NUMBER; i++)
+ avg += x->x_average[i];
+ post("netreceive~: last size = %d, avg size = %g, %d underflows, %d overflows", QUEUESIZE, (float)((float)avg / (float)DEFAULT_AVERAGE_NUMBER), x->x_underflow, x->x_overflow);
+ post("netreceive~: channels = %d, framesize = %d, packets = %d", x->x_frames[x->x_framein].tag.channels, x->x_frames[x->x_framein].tag.framesize, x->x_counter);
+}
+
+
+
+#ifdef PD
+static void *netreceive_tilde_new(t_floatarg fportno, t_floatarg outlets, t_floatarg prot)
+#else
+static void *netreceive_tilde_new(long fportno, long outlets, long prot)
+#endif
+{
+ t_netreceive_tilde *x;
+ int i;
+
+ if (fportno == 0) fportno = DEFAULT_PORT;
+
+#ifdef PD
+ x = (t_netreceive_tilde *)pd_new(netreceive_tilde_class);
+ if (x)
+ {
+ for (i = sizeof(t_object); i < (int)sizeof(t_netreceive_tilde); i++)
+ ((char *)x)[i] = 0;
+ }
+
+ x->x_noutlets = CLIP((int)outlets, 1, DEFAULT_AUDIO_CHANNELS);
+ for (i = 0; i < x->x_noutlets; i++)
+ outlet_new(&x->x_obj, &s_signal);
+ if (!prot)
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_anything); /* outlet for connection state (TCP/IP) */
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_anything);
+#else
+ x = (t_netreceive_tilde *)newobject(netreceive_tilde_class);
+ if (x)
+ {
+ for (i = sizeof(t_pxobject); i < (int)sizeof(t_netreceive_tilde); i++)
+ ((char *)x)[i] = 0;
+ }
+
+ dsp_setup((t_pxobject *)x, 0); /* no signal inlets */
+ x->x_noutlets = CLIP((int)outlets, 1, DEFAULT_AUDIO_CHANNELS);
+ x->x_outlet2 = listout(x); /* outlet for info list */
+ if (!prot)
+ x->x_outlet1 = listout(x); /* outlet for connection state (TCP/IP) */
+ for (i = 0 ; i < x->x_noutlets; i++)
+ outlet_new(x, "signal");
+ x->x_connectpoll = clock_new(x, (method)netreceive_tilde_connectpoll);
+ x->x_datapoll = clock_new(x, (method)netreceive_tilde_datapoll);
+#endif
+
+ x->x_myvec = (t_int **)t_getbytes(sizeof(t_int *) * (x->x_noutlets + 3));
+ if (!x->x_myvec)
+ {
+ error("netreceive~: out of memory");
+ return NULL;
+ }
+
+#ifdef USE_FAAC
+ x->x_faac_decoder = NULL;
+ x->x_faac_init = 0;
+#endif
+
+ x->x_connectsocket = -1;
+ x->x_socket = -1;
+ x->x_tcp = 1;
+ x->x_nconnections = 0;
+ x->x_ndrops = 0;
+ x->x_underflow = 0;
+ x->x_overflow = 0;
+ x->x_hostname = ps_nothing;
+
+ for (i = 0; i < DEFAULT_AUDIO_BUFFER_FRAMES; i++)
+ {
+ x->x_frames[i].data = (char *)t_getbytes(DEFAULT_AUDIO_BUFFER_SIZE * x->x_noutlets * sizeof(t_float));
+ }
+ x->x_framein = 0;
+ x->x_frameout = 0;
+ x->x_maxframes = DEFAULT_QUEUE_LENGTH;
+ x->x_vecsize = 64; /* we'll update this later */
+ x->x_blocksize = DEFAULT_AUDIO_BUFFER_SIZE; /* LATER make this dynamic */
+ x->x_blockssincerecv = 0;
+ x->x_blocksperrecv = x->x_blocksize / x->x_vecsize;
+
+ if (prot)
+ x->x_tcp = 0;
+
+ if (!netreceive_tilde_createsocket(x, (int)fportno))
+ {
+ error("netreceive~: failed to create listening socket");
+ return (NULL);
+ }
+
+ return (x);
+}
+
+
+
+static void netreceive_tilde_free(t_netreceive_tilde *x)
+{
+ int i;
+
+ if (x->x_connectsocket != -1)
+ {
+#ifdef PD
+ sys_rmpollfn(x->x_connectsocket);
+#else
+ clock_unset(x->x_connectpoll);
+#endif
+ CLOSESOCKET(x->x_connectsocket);
+ }
+ if (x->x_socket != -1)
+ {
+#ifdef PD
+ sys_rmpollfn(x->x_socket);
+#else
+ clock_unset(x->x_datapoll);
+#endif
+ CLOSESOCKET(x->x_socket);
+ }
+
+#ifndef PD
+ dsp_free((t_pxobject *)x); /* free the object */
+ clock_free(x->x_connectpoll);
+ clock_free(x->x_datapoll);
+#endif
+
+#ifdef USE_FAAC
+ netreceive_tilde_faac_close(x);
+#endif
+
+ /* free memory */
+ t_freebytes(x->x_myvec, sizeof(t_int *) * (x->x_noutlets + 3));
+ for (i = 0; i < DEFAULT_AUDIO_BUFFER_FRAMES; i++)
+ {
+ t_freebytes(x->x_frames[i].data, DEFAULT_AUDIO_BUFFER_SIZE * x->x_noutlets * sizeof(t_float));
+ }
+}
+
+
+
+#ifdef PD
+void netreceive_tilde_setup(void)
+{
+ netreceive_tilde_class = class_new(gensym("netreceive~"),
+ (t_newmethod) netreceive_tilde_new, (t_method) netreceive_tilde_free,
+ sizeof(t_netreceive_tilde), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(netreceive_tilde_class, nullfn, gensym("signal"), 0);
+ class_addbang(netreceive_tilde_class, (t_method)netreceive_tilde_bang);
+ class_addmethod(netreceive_tilde_class, (t_method)netreceive_tilde_dsp, gensym("dsp"), 0);
+ class_addmethod(netreceive_tilde_class, (t_method)netreceive_tilde_print, gensym("print"), 0);
+ class_addmethod(netreceive_tilde_class, (t_method)netreceive_tilde_kick, gensym("kick"), 0);
+ class_addmethod(netreceive_tilde_class, (t_method)netreceive_tilde_reset, gensym("reset"), A_DEFFLOAT, 0);
+ class_addmethod(netreceive_tilde_class, (t_method)netreceive_tilde_reset, gensym("buffer"), A_DEFFLOAT, 0);
+ class_sethelpsymbol(netreceive_tilde_class, gensym("netsend~"));
+ post("netreceive~ v%s, (c) 2004 Olaf Matthes", VERSION);
+
+ ps_format = gensym("format");
+ ps_channels = gensym("channels");
+ ps_framesize = gensym("framesize");
+ ps_bitrate = gensym("bitrate");
+ ps_overflow = gensym("overflow");
+ ps_underflow = gensym("underflow");
+ ps_queuesize = gensym("queuesize");
+ ps_average = gensym("average");
+ ps_hostname = gensym("ipaddr");
+ ps_sf_float = gensym("_float_");
+ ps_sf_16bit = gensym("_16bit_");
+ ps_sf_8bit = gensym("_8bit_");
+ ps_sf_mp3 = gensym("_mp3_");
+ ps_sf_aac = gensym("_aac_");
+ ps_sf_unknown = gensym("_unknown_");
+ ps_nothing = gensym("");
+}
+
+#else
+
+void netreceive_tilde_assist(t_netreceive_tilde *x, void *b, long m, long a, char *s)
+{
+ switch (m)
+ {
+ case 1: /* inlet */
+ sprintf(s, "(Anything) Control Messages");
+ break;
+ case 2: /* outlets */
+ sprintf(s, "(Signal) Audio Channel %d", (int)(a + 1));
+ break;
+ break;
+ }
+
+}
+
+void main()
+{
+#ifdef _WINDOWS
+ short version = MAKEWORD(2, 0);
+ WSADATA nobby;
+#endif /* _WINDOWS */
+
+ setup((t_messlist **)&netreceive_tilde_class, (method)netreceive_tilde_new, (method)netreceive_tilde_free,
+ (short)sizeof(t_netreceive_tilde), 0L, A_DEFLONG, A_DEFLONG, A_DEFLONG, 0);
+ addmess((method)netreceive_tilde_dsp, "dsp", A_CANT, 0);
+ addmess((method)netreceive_tilde_assist, "assist", A_CANT, 0);
+ addmess((method)netreceive_tilde_print, "print", 0);
+ addmess((method)netreceive_tilde_kick, "kick", 0);
+ addmess((method)netreceive_tilde_reset, "reset", A_DEFFLOAT, 0);
+ addmess((method)netreceive_tilde_reset, "buffer", A_DEFFLOAT, 0);
+ addbang((method)netreceive_tilde_bang);
+ dsp_initclass();
+ finder_addclass("System", "netreceive~");
+ post("netreceive~ v%s, © 2004 Olaf Matthes", VERSION);
+
+ ps_format = gensym("format");
+ ps_channels = gensym("channels");
+ ps_framesize = gensym("framesize");
+ ps_bitrate = gensym("bitrate");
+ ps_overflow = gensym("overflow");
+ ps_underflow = gensym("underflow");
+ ps_queuesize = gensym("queuesize");
+ ps_average = gensym("average");
+ ps_hostname = gensym("ipaddr");
+ ps_sf_float = gensym("_float_");
+ ps_sf_16bit = gensym("_16bit_");
+ ps_sf_8bit = gensym("_8bit_");
+ ps_sf_mp3 = gensym("_mp3_");
+ ps_sf_aac = gensym("_aac_");
+ ps_sf_unknown = gensym("_unknown_");
+ ps_nothing = gensym("");
+
+#ifdef _WINDOWS
+ if (WSAStartup(version, &nobby)) error("netreceive~: WSAstartup failed");
+#endif /* _WINDOWS */
+}
+#endif /* PD */
diff --git a/netsend~/netsend~.c b/netsend~/netsend~.c
new file mode 100644
index 0000000..5d79018
--- /dev/null
+++ b/netsend~/netsend~.c
@@ -0,0 +1,1056 @@
+/* ------------------------ netsend~ ------------------------------------------ */
+/* */
+/* Tilde object to send uncompressed audio data to netreceive~. */
+/* Written by Olaf Matthes <olaf.matthes@gmx.de>. */
+/* Based on streamout~ by Guenter Geiger. */
+/* Get source at http://www.akustische-kunst.org/ */
+/* */
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+/* */
+/* See file LICENSE for further informations on licensing terms. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+/* */
+/* Based on PureData by Miller Puckette and others. */
+/* */
+/* This project was commissioned by the Society for Arts and Technology [SAT], */
+/* Montreal, Quebec, Canada, http://www.sat.qc.ca/. */
+/* */
+/* ---------------------------------------------------------------------------- */
+
+#ifdef PD
+#include "m_pd.h"
+#else
+#include "ext.h"
+#include "z_dsp.h"
+#endif
+
+#include "netsend~.h"
+#include "float_cast.h" /* tools for fast conversion from float to int */
+
+#ifdef USE_FAAC
+#include "faac/faac.h"
+#endif
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef UNIX
+#include <sys/socket.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <pthread.h>
+#define SOCKET_ERROR -1
+#endif
+#ifdef _WINDOWS
+#include <winsock.h>
+#include "pthread.h"
+#endif
+
+#ifdef _WINDOWS
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+#ifdef MSG_NOSIGNAL
+#define SEND_FLAGS /*MSG_DONTWAIT|*/MSG_NOSIGNAL
+#else
+#define SEND_FLAGS 0
+#endif
+
+#ifndef SOL_IP
+#define SOL_IP IPPROTO_IP
+#endif
+
+
+/* Utility functions */
+
+static int netsend_tilde_sockerror(char *s)
+{
+#ifdef _WINDOWS
+ int err = WSAGetLastError();
+ if (err == 10054) return 1;
+ else if (err == 10053) post("netsend~: %s: software caused connection abort (%d)", s, err);
+ else if (err == 10055) post("netsend~: %s: no buffer space available (%d)", s, err);
+ else if (err == 10060) post("netsend~: %s: connection timed out (%d)", s, err);
+ else if (err == 10061) post("netsend~: %s: connection refused (%d)", s, err);
+ else post("netsend~: %s: %s (%d)", s, strerror(err), err);
+#else
+ int err = errno;
+ post("netsend~: %s: %s (%d)", s, strerror(err), err);
+#endif
+#ifdef _WINDOWS
+ if (err == WSAEWOULDBLOCK)
+#endif
+#ifdef UNIX
+ if (err == EAGAIN)
+#endif
+ {
+ return 1; /* recoverable error */
+ }
+ return 0; /* indicate non-recoverable error */
+}
+
+
+
+static void netsend_tilde_closesocket(int fd)
+{
+#ifdef UNIX
+ close(fd);
+#endif
+#ifdef NT
+ closesocket(fd);
+#endif
+}
+
+
+/* ------------------------ netsend~ ----------------------------- */
+
+
+#ifdef PD
+static t_class *netsend_tilde_class;
+#else
+static void *netsend_tilde_class;
+#endif
+
+static t_symbol *ps_nothing, *ps_localhost;
+static t_symbol *ps_format, *ps_channels, *ps_framesize, *ps_overflow, *ps_underflow;
+static t_symbol *ps_queuesize, *ps_average, *ps_sf_float, *ps_sf_16bit, *ps_sf_8bit;
+static t_symbol *ps_sf_mp3, *ps_sf_aac, *ps_sf_unknown, *ps_bitrate, *ps_hostname;
+
+
+typedef struct _netsend_tilde
+{
+#ifdef PD
+ t_object x_obj;
+ t_outlet *x_outlet;
+ t_outlet *x_outlet2;
+ t_clock *x_clock;
+#else
+ t_pxobject x_obj;
+ void *x_outlet;
+ void *x_outlet2;
+ void *x_clock;
+#endif
+ int x_fd;
+ int x_protocol;
+ t_tag x_tag;
+ t_symbol* x_hostname;
+ int x_portno;
+ int x_connectstate;
+ char *x_cbuf;
+ int x_cbufsize;
+ int x_blocksize;
+ int x_blockspersend;
+ int x_blockssincesend;
+
+ long x_samplerate; /* samplerate we're running at */
+ int x_vecsize; /* current DSP signal vector size */
+ int x_ninlets; /* number of inlets */
+ int x_channels; /* number of channels we want to stream */
+ int x_format; /* format of streamed audio data */
+ int x_bitrate; /* specifies bitrate for compressed formats */
+ int x_count; /* total number of audio frames */
+ t_int **x_myvec; /* vector we pass on in the DSP routine */
+
+#ifdef USE_FAAC
+ unsigned char *x_faacbuf; /* data returned by encoder */
+ faacEncHandle x_faac;
+#endif
+
+ pthread_mutex_t x_mutex;
+ pthread_cond_t x_requestcondition;
+ pthread_cond_t x_answercondition;
+ pthread_t x_childthread;
+} t_netsend_tilde;
+
+
+
+static void netsend_tilde_notify(t_netsend_tilde *x)
+{
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_childthread = 0;
+ outlet_float(x->x_outlet, x->x_connectstate);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+
+static void netsend_tilde_disconnect(t_netsend_tilde *x)
+{
+ pthread_mutex_lock(&x->x_mutex);
+ if (x->x_fd != -1)
+ {
+ netsend_tilde_closesocket(x->x_fd);
+ x->x_fd = -1;
+ x->x_connectstate = 0;
+ outlet_float(x->x_outlet, 0);
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+
+static void *netsend_tilde_doconnect(void *zz)
+{
+ t_netsend_tilde *x = (t_netsend_tilde *)zz;
+ struct sockaddr_in server;
+ struct hostent *hp;
+ int intarg = 1;
+ int sockfd;
+ int portno;
+ t_symbol *hostname;
+
+ pthread_mutex_lock(&x->x_mutex);
+ hostname = x->x_hostname;
+ portno = x->x_portno;
+ pthread_mutex_unlock(&x->x_mutex);
+
+ /* create a socket */
+ sockfd = socket(AF_INET, x->x_protocol, 0);
+ if (sockfd < 0)
+ {
+ post("netsend~: connection to %s on port %d failed", hostname->s_name,portno);
+ netsend_tilde_sockerror("socket");
+ x->x_childthread = 0;
+ return (0);
+ }
+
+ /* connect socket using hostname provided in command line */
+ server.sin_family = AF_INET;
+ hp = gethostbyname(x->x_hostname->s_name);
+ if (hp == 0)
+ {
+ post("netsend~: bad host?");
+ x->x_childthread = 0;
+ return (0);
+ }
+
+ /* for stream (TCP) sockets, specify "nodelay" */
+ if (x->x_protocol == SOCK_STREAM)
+ {
+ intarg = 1;
+ if (setsockopt(sockfd, SOL_IP, TCP_NODELAY, (const char *)&intarg, sizeof(intarg)) < 0)
+ error("netsend~: setsockopt(TCP_NODELAY) failed");
+ }
+
+#ifdef SO_PRIORITY
+ /* set high priority, LINUX only */
+ intarg = 6; /* select a priority between 0 and 7 */
+ if (setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, (const char*)&intarg, sizeof(int)) < 0)
+ {
+ error("netsend~: setsockopt(SO_PRIORITY) failed");
+ }
+#endif
+
+ memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
+
+ /* assign client port number */
+ server.sin_port = htons((unsigned short)portno);
+
+ /* try to connect */
+ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
+ {
+ netsend_tilde_sockerror("connecting stream socket");
+ netsend_tilde_closesocket(sockfd);
+ x->x_childthread = 0;
+ return (0);
+ }
+
+ post("netsend~: connected host %s on port %d", hostname->s_name, portno);
+
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = sockfd;
+ x->x_connectstate = 1;
+ clock_delay(x->x_clock, 0);
+ pthread_mutex_unlock(&x->x_mutex);
+ return (0);
+}
+
+
+
+#ifdef PD
+static void netsend_tilde_connect(t_netsend_tilde *x, t_symbol *host, t_floatarg fportno)
+#else
+static void netsend_tilde_connect(t_netsend_tilde *x, t_symbol *host, long fportno)
+#endif
+{
+ pthread_mutex_lock(&x->x_mutex);
+ if (x->x_childthread != 0)
+ {
+ pthread_mutex_unlock(&x->x_mutex);
+ post("netsend~: already trying to connect");
+ return;
+ }
+ if (x->x_fd != -1)
+ {
+ pthread_mutex_unlock(&x->x_mutex);
+ post("netsend~: already connected");
+ return;
+ }
+
+ if (host != ps_nothing)
+ x->x_hostname = host;
+ else
+ x->x_hostname = ps_localhost;
+
+ if (!fportno)
+ x->x_portno = DEFAULT_PORT;
+ else
+ x->x_portno = (int)fportno;
+ x->x_count = 0;
+
+ /* start child thread to connect */
+ pthread_create(&x->x_childthread, 0, netsend_tilde_doconnect, x);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+
+
+#ifdef USE_FAAC
+static void netsend_tilde_faac_deinit(t_netsend_tilde *x)
+{
+ if (x->x_faac)
+ faacEncClose(x->x_faac);
+ x->x_faac = NULL;
+}
+
+
+static int netsend_tilde_faac_init(t_netsend_tilde *x)
+{
+ faacEncConfigurationPtr faac_format;
+ char *faac_id_string;
+ char *faac_copyright_string;
+ unsigned long samplesInput, maxBytesOutput;
+ unsigned int mpegVersion = MPEG2;
+ unsigned int channels = x->x_channels;
+
+ if (!faacEncGetVersion(&faac_id_string, &faac_copyright_string) == FAAC_CFG_VERSION)
+ return -1;
+
+ /* open the encoder library */
+ x->x_faac = faacEncOpen(x->x_samplerate, channels, &samplesInput, &maxBytesOutput);
+
+ /* put the options in the configuration struct */
+ faac_format = faacEncGetCurrentConfiguration(x->x_faac);
+ faac_format->aacObjectType = MAIN; // LOW; /* MAIN, LOW or LTP */
+ faac_format->mpegVersion = MPEG2;
+ faac_format->useTns = 1;
+ if (channels >= 6)
+ {
+ faac_format->useLfe = 1;
+ faac_format->allowMidside = 0;
+ }
+ else
+ {
+ faac_format->useLfe = 0;
+ faac_format->allowMidside = 1;
+ }
+ if (x->x_bitrate)
+ faac_format->bitRate = (x->x_bitrate * 1000) / channels;
+ faac_format->bandWidth = 0;
+ faac_format->outputFormat = 1; /* 0 = Raw; 1 = ADTS */
+ faac_format->inputFormat = FAAC_INPUT_FLOAT; /* input is float but scaled by 32768 */
+ if (!faacEncSetConfiguration(x->x_faac, faac_format))
+ {
+ error("netsend~: faac: unsupported format settings");
+ faacEncClose(x->x_faac);
+ x->x_faac = NULL;
+ return -1;
+ }
+ return 0;
+}
+
+
+static int netsend_tilde_faac_encode(t_netsend_tilde *x)
+{
+ static const int encbufsize = 1.25 * DEFAULT_AUDIO_BUFFER_SIZE + 7200;
+ unsigned int samples = x->x_blocksize * x->x_tag.channels;
+ float *bp = (float *)x->x_cbuf;
+
+ /* encode AAC */
+ int ret = faacEncEncode(x->x_faac, (int32_t *)bp, samples, x->x_faacbuf, encbufsize);
+
+ /* check result */
+ if (ret < 0)
+ {
+ error("netsend~: faac: encoding failed (%d)", ret);
+ faacEncClose(x->x_faac);
+ x->x_faac = NULL;
+ return -1;
+ }
+
+ return ret; /* return total number of AAC samples (bytes) we got */
+}
+#endif
+
+static t_int *netsend_tilde_perform(t_int *w)
+{
+ t_netsend_tilde* x = (t_netsend_tilde*) (w[1]);
+ int n = (int)(w[2]);
+ t_float *in[DEFAULT_AUDIO_CHANNELS];
+ const int offset = 3;
+ char* bp = NULL;
+ int i, length = x->x_blocksize * SF_SIZEOF(x->x_tag.format) * x->x_tag.channels;
+ int sent = 0;
+
+ pthread_mutex_lock(&x->x_mutex);
+
+ for (i = 0; i < x->x_ninlets; i++)
+ in[i] = (t_float *)(w[offset + i]);
+
+ if (n != x->x_vecsize) /* resize buffer */
+ {
+ x->x_vecsize = n;
+ x->x_blockspersend = x->x_blocksize / x->x_vecsize;
+ x->x_blockssincesend = 0;
+ length = x->x_blocksize * SF_SIZEOF(x->x_tag.format) * x->x_tag.channels;
+ }
+
+ /* format the buffer */
+ switch (x->x_tag.format)
+ {
+ case SF_FLOAT:
+ {
+ t_float* fbuf = (t_float *)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels);
+ while (n--)
+ for (i = 0; i < x->x_tag.channels; i++)
+ *fbuf++ = *(in[i]++);
+ break;
+ }
+ case SF_16BIT:
+ {
+ short* cibuf = (short *)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels);
+ while (n--)
+ for (i = 0; i < x->x_tag.channels; i++)
+ *cibuf++ = (short)lrint(32767.0 * *(in[i]++));
+ break;
+ }
+ case SF_8BIT:
+ {
+ unsigned char* cbuf = (unsigned char*)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels);
+ while (n--)
+ for (i = 0; i < x->x_tag.channels; i++)
+ *cbuf++ = (unsigned char)(128. * (1.0 + *(in[i]++)));
+ break;
+ }
+#ifdef USE_FAAC
+ case SF_AAC:
+ {
+ /* same as SF_FLOAT but * 32767 and no byteswapping required */
+ t_float* fbuf = (t_float *)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels);
+ while (n--)
+ for (i = 0; i < x->x_tag.channels; i++)
+ *fbuf++ = 32767.0 * *(in[i]++);
+ break;
+ }
+#endif
+ default:
+ break;
+ }
+
+ if (!(x->x_blockssincesend < x->x_blockspersend - 1)) /* time to send the buffer */
+ {
+ x->x_blockssincesend = 0;
+ x->x_count++; /* count data packet we're going to send */
+
+ if (x->x_fd != -1)
+ {
+#ifdef USE_FAAC
+ if (x->x_tag.format == SF_AAC)
+ {
+ /* encode PCM to AAC and return new framesize */
+ length = netsend_tilde_faac_encode(x);
+ if (length <= 0)
+ {
+ if (length == 0) error("netsend~: skipping empty aac data frame");
+ else error("netsend~: error encoding AAC");
+ x->x_count--;
+ goto bail;
+ }
+ bp = (char *)x->x_faacbuf;
+ }
+ else
+#endif
+ bp = (char *)x->x_cbuf;
+
+ /* fill in the header tag */
+ x->x_tag.framesize = length;
+ x->x_tag.count = x->x_count;
+
+ /* send the format tag */
+ if (send(x->x_fd, (char*)&x->x_tag, sizeof(t_tag), SEND_FLAGS) < 0)
+ {
+ netsend_tilde_sockerror("send tag");
+ pthread_mutex_unlock(&x->x_mutex);
+ netsend_tilde_disconnect(x);
+ return (w + offset + x->x_ninlets);
+ }
+
+ if (x->x_protocol == SOCK_STREAM) /* TCP: send all the data at once */
+ {
+ /* send the buffer */
+ for (sent = 0; sent < length;)
+ {
+ int ret = 0;
+ ret = send(x->x_fd, bp, length - sent, SEND_FLAGS);
+ if (ret <= 0)
+ {
+ netsend_tilde_sockerror("send data");
+ pthread_mutex_unlock(&x->x_mutex);
+ netsend_tilde_disconnect(x);
+ return (w + offset + x->x_ninlets);
+ }
+ else
+ {
+ sent += ret;
+ bp += ret;
+ }
+ }
+ }
+ else /* UDP: max. packet size is 64k (incl. headers) so we have to split */
+ {
+#ifdef __APPLE__
+ /* WARING: due to a 'bug' (maybe Apple would call it a feature?) in OS X
+ send calls with data packets larger than 16k fail with error number 40!
+ Thus we have to split the data packets into several packets that are
+ 16k in size. The other side will reassemble them again. */
+
+ int size = DEFAULT_UDP_PACKT_SIZE;
+ if (length < size) /* maybe data fits into one packet? */
+ size = length;
+
+ /* send the buffer */
+ for (sent = 0; sent < length;)
+ {
+ int ret = 0;
+ ret = send(x->x_fd, bp, size, SEND_FLAGS);
+ if (ret <= 0)
+ {
+ netsend_tilde_sockerror("send data");
+ pthread_mutex_unlock(&x->x_mutex);
+ netsend_tilde_disconnect(x);
+ return (w + offset + x->x_ninlets);
+ }
+ else
+ {
+ bp += ret;
+ sent += ret;
+ if ((length - sent) < size)
+ size = length - sent;
+ }
+ }
+#else
+ /* send the buffer, the OS might segment it into smaller packets */
+ int ret = send(x->x_fd, bp, length, SEND_FLAGS);
+ if (ret <= 0)
+ {
+ netsend_tilde_sockerror("send data");
+ pthread_mutex_unlock(&x->x_mutex);
+ netsend_tilde_disconnect(x);
+ return (w + offset + x->x_ninlets);
+ }
+#endif
+ }
+ }
+
+#ifdef USE_FAAC
+bail:
+#endif
+ /* check whether user has updated any parameters */
+ if (x->x_tag.channels != x->x_channels)
+ {
+#ifdef USE_FAAC
+ /* reinit FAAC if format is SF_AAC */
+ if (x->x_tag.format == SF_AAC)
+ {
+ netsend_tilde_faac_deinit(x);
+ netsend_tilde_faac_init(x);
+ }
+#endif
+ x->x_tag.channels = x->x_channels;
+ }
+ if (x->x_tag.format != x->x_format)
+ {
+#ifdef USE_FAAC
+ /* deinit FAAC if format was SF_AAC */
+ if ((x->x_format != SF_AAC) && (x->x_tag.format == SF_AAC))
+ {
+ netsend_tilde_faac_deinit(x);
+ }
+#endif
+ x->x_tag.format = x->x_format;
+ }
+ }
+ else
+ {
+ x->x_blockssincesend++;
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ return (w + offset + x->x_ninlets);
+}
+
+
+
+static void netsend_tilde_dsp(t_netsend_tilde *x, t_signal **sp)
+{
+ int i;
+
+ pthread_mutex_lock(&x->x_mutex);
+
+ x->x_myvec[0] = (t_int*)x;
+ x->x_myvec[1] = (t_int*)sp[0]->s_n;
+
+ x->x_samplerate = sp[0]->s_sr;
+
+ for (i = 0; i < x->x_ninlets; i++)
+ {
+ x->x_myvec[2 + i] = (t_int*)sp[i]->s_vec;
+ }
+
+ pthread_mutex_unlock(&x->x_mutex);
+
+ if (DEFAULT_AUDIO_BUFFER_SIZE % sp[0]->s_n)
+ {
+ error("netsend~: signal vector size too large (needs to be even divisor of %d)", DEFAULT_AUDIO_BUFFER_SIZE);
+ }
+ else
+ {
+#ifdef PD
+ dsp_addv(netsend_tilde_perform, x->x_ninlets + 2, (t_int*)x->x_myvec);
+#else
+ dsp_addv(netsend_tilde_perform, x->x_ninlets + 2, (void**)x->x_myvec);
+#endif
+ }
+}
+
+
+#ifdef PD
+static void netsend_tilde_channels(t_netsend_tilde *x, t_floatarg channels)
+#else
+static void netsend_tilde_channels(t_netsend_tilde *x, long channels)
+#endif
+{
+ pthread_mutex_lock(&x->x_mutex);
+ if (channels >= 0 && channels <= DEFAULT_AUDIO_CHANNELS)
+ {
+ x->x_channels = (int)channels;
+ post("netsend~: channels set to %d", (int)channels);
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+
+
+#ifdef PD
+static void netsend_tilde_format(t_netsend_tilde *x, t_symbol* form, t_floatarg bitrate)
+#else
+static void netsend_tilde_format(t_netsend_tilde *x, t_symbol* form, long bitrate)
+#endif
+{
+ pthread_mutex_lock(&x->x_mutex);
+ if (!strncmp(form->s_name,"float", 5) && x->x_tag.format != SF_FLOAT)
+ {
+ x->x_format = (int)SF_FLOAT;
+ }
+ else if (!strncmp(form->s_name,"16bit", 5) && x->x_tag.format != SF_16BIT)
+ {
+ x->x_format = (int)SF_16BIT;
+ }
+ else if (!strncmp(form->s_name,"8bit", 4) && x->x_tag.format != SF_8BIT)
+ {
+ x->x_format = (int)SF_8BIT;
+ }
+ else if (!strncmp(form->s_name,"mp3", 3) && x->x_tag.format != SF_MP3)
+ {
+ error("netsend~: not compiled with mp3 support");
+ pthread_mutex_unlock(&x->x_mutex);
+ return;
+ }
+ else if (!strncmp(form->s_name,"aac", 3) && x->x_tag.format != SF_AAC)
+ {
+#ifdef USE_FAAC
+ x->x_bitrate = (int)bitrate;
+ if (netsend_tilde_faac_init(x) < 0)
+ {
+ pthread_mutex_unlock(&x->x_mutex);
+ return;
+ }
+ x->x_format = (int)SF_AAC;
+#else
+ error("netsend~: not compiled with aac support");
+ pthread_mutex_unlock(&x->x_mutex);
+ return;
+#endif
+ }
+
+ post("netsend~: format set to %s", form->s_name);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+
+/* set hostname to send to */
+static void netsend_tilde_host(t_netsend_tilde *x, t_symbol* host)
+{
+ pthread_mutex_lock(&x->x_mutex);
+ if (host != ps_nothing)
+ x->x_hostname = host;
+ else
+ x->x_hostname = ps_localhost;
+
+ if (x->x_fd != -1)
+ {
+ pthread_mutex_unlock(&x->x_mutex);
+ netsend_tilde_connect(x,x->x_hostname, (float)x->x_portno);
+ return;
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+
+
+#ifdef PD
+static void netsend_tilde_float(t_netsend_tilde* x, t_floatarg arg)
+#else
+static void netsend_tilde_float(t_netsend_tilde* x, double arg)
+#endif
+{
+ if (arg == 0.0)
+ netsend_tilde_disconnect(x);
+ else
+ netsend_tilde_connect(x,x->x_hostname,(float) x->x_portno);
+}
+
+
+/* send stream info when banged */
+static void netsend_tilde_bang(t_netsend_tilde *x)
+{
+ t_atom list[2];
+ t_symbol *sf_format;
+ t_float bitrate;
+
+ bitrate = (t_float)((SF_SIZEOF(x->x_tag.format) * x->x_samplerate * 8 * x->x_tag.channels) / 1000.);
+
+ switch (x->x_tag.format)
+ {
+ case SF_FLOAT:
+ {
+ sf_format = ps_sf_float;
+ break;
+ }
+ case SF_16BIT:
+ {
+ sf_format = ps_sf_16bit;
+ break;
+ }
+ case SF_8BIT:
+ {
+ sf_format = ps_sf_8bit;
+ break;
+ }
+ case SF_MP3:
+ {
+ sf_format = ps_sf_mp3;
+ break;
+ }
+ case SF_AAC:
+ {
+ sf_format = ps_sf_aac;
+ break;
+ }
+ default:
+ {
+ sf_format = ps_sf_unknown;
+ break;
+ }
+ }
+
+#ifdef PD
+ /* --- stream information (t_tag) --- */
+ /* audio format */
+ SETSYMBOL(list, (t_symbol *)sf_format);
+ outlet_anything(x->x_outlet2, ps_format, 1, list);
+
+ /* channels */
+ SETFLOAT(list, (t_float)x->x_tag.channels);
+ outlet_anything(x->x_outlet2, ps_channels, 1, list);
+
+ /* framesize */
+ SETFLOAT(list, (t_float)x->x_tag.framesize);
+ outlet_anything(x->x_outlet2, ps_framesize, 1, list);
+
+ /* bitrate */
+ SETFLOAT(list, (t_float)bitrate);
+ outlet_anything(x->x_outlet2, ps_bitrate, 1, list);
+
+ /* IP address */
+ SETSYMBOL(list, (t_symbol *)x->x_hostname);
+ outlet_anything(x->x_outlet2, ps_hostname, 1, list);
+#else
+ /* --- stream information (t_tag) --- */
+ /* audio format */
+ SETSYM(list, ps_format);
+ SETSYM(list + 1, (t_symbol *)sf_format);
+ outlet_list(x->x_outlet2, NULL, 2, list);
+
+ /* channels */
+ SETSYM(list, ps_channels);
+ SETLONG(list + 1, (int)x->x_tag.channels);
+ outlet_list(x->x_outlet2, NULL, 2, list);
+
+ /* framesize */
+ SETSYM(list, ps_framesize);
+ SETLONG(list + 1, (int)x->x_tag.framesize);
+ outlet_list(x->x_outlet2, NULL, 2, list);
+
+ /* bitrate */
+ SETSYM(list, ps_bitrate);
+ SETFLOAT(list + 1, (t_float)bitrate);
+ outlet_list(x->x_outlet2, NULL, 2, list);
+
+ /* IP address */
+ SETSYM(list, (t_symbol *)ps_hostname);
+ SETSYM(list + 1, x->x_hostname);
+ outlet_list(x->x_outlet2, NULL, 2, list);
+#endif
+}
+
+
+#ifdef PD
+static void *netsend_tilde_new(t_floatarg inlets, t_floatarg prot)
+#else
+static void *netsend_tilde_new(long inlets, long prot)
+#endif
+{
+ int i;
+
+#ifdef PD
+ t_netsend_tilde *x = (t_netsend_tilde *)pd_new(netsend_tilde_class);
+ if (x)
+ {
+ for (i = sizeof(t_object); i < (int)sizeof(t_netsend_tilde); i++)
+ ((char *)x)[i] = 0;
+ }
+
+ x->x_ninlets = CLIP((int)inlets, 1, DEFAULT_AUDIO_CHANNELS);
+ for (i = 1; i < x->x_ninlets; i++)
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+
+ x->x_outlet = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_list);
+ x->x_clock = clock_new(x, (t_method)netsend_tilde_notify);
+#else
+ t_netsend_tilde *x = (t_netsend_tilde *)newobject(netsend_tilde_class);
+ if (x)
+ {
+ for (i = sizeof(t_pxobject); i < sizeof(t_netsend_tilde); i++)
+ ((char *)x)[i] = 0;
+ }
+
+ x->x_ninlets = CLIP((int)inlets, 1, DEFAULT_AUDIO_CHANNELS);
+ dsp_setup((t_pxobject *)x, x->x_ninlets);
+ x->x_outlet2 = outlet_new(x, "list");
+ x->x_outlet = outlet_new(x, "int");
+ x->x_clock = clock_new(x, (method)netsend_tilde_notify);
+#endif
+
+ x->x_myvec = (t_int **)t_getbytes(sizeof(t_int *) * (x->x_ninlets + 3));
+ if (!x->x_myvec)
+ {
+ error("netsend~: out of memory");
+ return NULL;
+ }
+
+#ifdef USE_FAAC
+ /* allocate a buffer for encoded data */
+ x->x_faacbuf = (unsigned char *)t_getbytes(sizeof(char *) * (1.25 * DEFAULT_AUDIO_BUFFER_SIZE + 7200));
+ if (!x->x_faacbuf)
+ {
+ error("netsend~: out of memory");
+ return NULL;
+ }
+ x->x_faac = NULL; /* encoder not yet nitialized */
+#endif
+
+ pthread_mutex_init(&x->x_mutex, 0);
+ pthread_cond_init(&x->x_requestcondition, 0);
+ pthread_cond_init(&x->x_answercondition, 0);
+
+ x->x_hostname = ps_localhost;
+ x->x_portno = 3000;
+ x->x_connectstate = 0;
+ x->x_childthread = 0;
+ x->x_fd = -1;
+ x->x_protocol = SOCK_STREAM;
+
+ if (prot) /* user wants UDP */
+ {
+ x->x_protocol = SOCK_DGRAM;
+ }
+
+ x->x_tag.format = x->x_format = SF_FLOAT;
+ x->x_tag.channels = x->x_channels = x->x_ninlets;
+ x->x_tag.version = SF_BYTE_NATIVE; /* native endianness */
+ x->x_vecsize = 64; /* we'll update this later */
+ x->x_bitrate = 0; /* not specified, use default */
+ x->x_cbuf = NULL;
+ x->x_blocksize = DEFAULT_AUDIO_BUFFER_SIZE;
+ x->x_blockspersend = x->x_blocksize / x->x_vecsize;
+ x->x_blockssincesend = 0;
+ x->x_cbufsize = x->x_blocksize * sizeof(t_float) * x->x_ninlets;
+ x->x_cbuf = (char *)t_getbytes(x->x_cbufsize);
+
+#ifdef UNIX
+ /* we don't want to get signaled in case send() fails */
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ return (x);
+}
+
+
+
+static void netsend_tilde_free(t_netsend_tilde* x)
+{
+ netsend_tilde_disconnect(x);
+
+#ifndef PD
+ dsp_free((t_pxobject *)x); /* free the object */
+#endif
+
+ /* free the memory */
+ if (x->x_cbuf)t_freebytes(x->x_cbuf, x->x_cbufsize);
+ if (x->x_myvec)t_freebytes(x->x_myvec, sizeof(t_int) * (x->x_ninlets + 3));
+
+#ifdef USE_FAAC
+ if (x->x_faacbuf)t_freebytes(x->x_faacbuf, sizeof(char *) * (1.25 * DEFAULT_AUDIO_BUFFER_SIZE + 7200));
+ netsend_tilde_faac_deinit(x);
+#endif
+
+ clock_free(x->x_clock);
+
+ pthread_cond_destroy(&x->x_requestcondition);
+ pthread_cond_destroy(&x->x_answercondition);
+ pthread_mutex_destroy(&x->x_mutex);
+}
+
+
+#ifdef PD
+
+void netsend_tilde_setup(void)
+{
+ netsend_tilde_class = class_new(gensym("netsend~"), (t_newmethod)netsend_tilde_new, (t_method)netsend_tilde_free,
+ sizeof(t_netsend_tilde), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+ class_addmethod(netsend_tilde_class, nullfn, gensym("signal"), 0);
+ class_addmethod(netsend_tilde_class, (t_method)netsend_tilde_dsp, gensym("dsp"), 0);
+ class_addfloat(netsend_tilde_class, netsend_tilde_float);
+ class_addbang(netsend_tilde_class, netsend_tilde_bang);
+ class_addmethod(netsend_tilde_class, (t_method)netsend_tilde_connect, gensym("connect"), A_DEFSYM, A_DEFFLOAT, 0);
+ class_addmethod(netsend_tilde_class, (t_method)netsend_tilde_disconnect, gensym("disconnect"), 0);
+ class_addmethod(netsend_tilde_class, (t_method)netsend_tilde_channels, gensym("channels"), A_FLOAT, 0);
+ class_addmethod(netsend_tilde_class, (t_method)netsend_tilde_format, gensym("format"), A_SYMBOL, A_DEFFLOAT, 0);
+ class_addmethod(netsend_tilde_class, (t_method)netsend_tilde_host, gensym("host"), A_DEFSYM, 0);
+ class_sethelpsymbol(netsend_tilde_class, gensym("netsend~"));
+ post("netsend~ v%s, (c) 2004-2005 Olaf Matthes", VERSION);
+
+ ps_nothing = gensym("");
+ ps_localhost = gensym("localhost");
+ ps_hostname = gensym("ipaddr");
+ ps_format = gensym("format");
+ ps_channels = gensym("channels");
+ ps_framesize = gensym("framesize");
+ ps_bitrate = gensym("bitrate");
+ ps_sf_float = gensym("_float_");
+ ps_sf_16bit = gensym("_16bit_");
+ ps_sf_8bit = gensym("_8bit_");
+ ps_sf_mp3 = gensym("_mp3_");
+ ps_sf_aac = gensym("_aac_");
+ ps_sf_unknown = gensym("_unknown_");
+}
+
+#else
+
+void netsend_tilde_assist(t_netsend_tilde *x, void *b, long m, long a, char *s)
+{
+ switch(m)
+ {
+ case 1: // inlet
+ switch(a)
+ {
+ case 0:
+ sprintf(s, "Control Messages & Audio Channel 1");
+ break;
+ default:
+ sprintf(s, "Audio Channel %d", (int)a + 1);
+ break;
+ }
+ break;
+ case 2: // outlet
+ switch(a)
+ {
+ case 0:
+ sprintf(s, "(Int) State of Connection");
+ break;
+ }
+ break;
+ }
+
+}
+
+void main()
+{
+#ifdef _WINDOWS
+ short version = MAKEWORD(2, 0);
+ WSADATA nobby;
+#endif /* _WINDOWS */
+
+ setup((t_messlist **)&netsend_tilde_class, (method)netsend_tilde_new, (method)netsend_tilde_free,
+ (short)sizeof(t_netsend_tilde), 0L, A_DEFLONG, A_DEFLONG, 0);
+
+ addmess((method)netsend_tilde_dsp, "dsp", A_CANT, 0);
+ addmess((method)netsend_tilde_connect, "connect", A_DEFSYM, A_DEFLONG, 0);
+ addmess((method)netsend_tilde_disconnect, "disconnect", 0);
+ addmess((method)netsend_tilde_format, "format", A_SYM, A_DEFLONG, 0);
+ addmess((method)netsend_tilde_channels, "channels", A_LONG, 0);
+ addmess((method)netsend_tilde_host, "host", A_DEFSYM, 0);
+ addmess((method)netsend_tilde_assist, "assist", A_CANT, 0);
+ addbang((method)netsend_tilde_bang);
+ dsp_initclass();
+ finder_addclass("System", "netsend~");
+ post("netsend~ v%s, © 2004-2005 Olaf Matthes", VERSION);
+ ps_nothing = gensym("");
+ ps_localhost = gensym("localhost");
+ ps_hostname = gensym("ipaddr");
+ ps_format = gensym("format");
+ ps_channels = gensym("channels");
+ ps_framesize = gensym("framesize");
+ ps_bitrate = gensym("bitrate");
+ ps_sf_float = gensym("_float_");
+ ps_sf_16bit = gensym("_16bit_");
+ ps_sf_8bit = gensym("_8bit_");
+ ps_sf_mp3 = gensym("_mp3_");
+ ps_sf_aac = gensym("_aac_");
+ ps_sf_unknown = gensym("_unknown_");
+
+#ifdef _WINDOWS
+ if (WSAStartup(version, &nobby)) error("netsend~: WSAstartup failed");
+#endif /* _WINDOWS */
+}
+
+#endif /* PD */
diff --git a/netsend~/netsend~.h b/netsend~/netsend~.h
new file mode 100644
index 0000000..874b63f
--- /dev/null
+++ b/netsend~/netsend~.h
@@ -0,0 +1,154 @@
+/* ------------------------ netsend~ ------------------------------------------ */
+/* */
+/* Tilde object to send uncompressed audio data to netreceive~. */
+/* Written by Olaf Matthes <olaf.matthes@gmx.de>. */
+/* Based on streamout~ by Guenter Geiger. */
+/* Get source at http://www.akustische-kunst.org/ */
+/* */
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+/* */
+/* See file LICENSE for further informations on licensing terms. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+/* */
+/* Based on PureData by Miller Puckette and others. */
+/* */
+/* This project was commissioned by the Society for Arts and Technology [SAT], */
+/* Montreal, Quebec, Canada, http://www.sat.qc.ca/. */
+/* */
+/* ---------------------------------------------------------------------------- */
+
+
+/* This file is based on and inspired by stream.h (C) Guenter Geiger 1999. */
+/* Some enhancements have been made with the goal of keeping compatibility */
+/* between the stream formats of streamout~/in~ and netsend~/receive~. */
+
+#define VERSION "1.0alpha11"
+
+#define DEFAULT_AUDIO_CHANNELS 32 /* nax. number of audio channels we support */
+#define DEFAULT_AUDIO_BUFFER_SIZE 1024 /* number of samples in one audio block */
+#define DEFAULT_UDP_PACKT_SIZE 8192 /* number of bytes we send in one UDP datagram (OS X only) */
+#define DEFAULT_PORT 8000 /* default network port number */
+
+#ifdef _WINDOWS
+#ifndef HAVE_INT32_T
+typedef int int32_t;
+#define HAVE_INT32_T
+#endif
+#ifndef HAVE_INT16_T
+typedef short int16_t;
+#define HAVE_INT16_T
+#endif
+#ifndef HAVE_U_INT32_T
+typedef unsigned int u_int32_t;
+#define HAVE_U_INT32_T
+#endif
+#ifndef HAVE_U_INT16_T
+typedef unsigned short u_int16_t;
+#define HAVE_U_INT16_T
+#endif
+#endif
+
+#ifndef CLIP
+#define CLIP(a, lo, hi) ( (a)>(lo)?( (a)<(hi)?(a):(hi) ):(lo) )
+#endif
+
+
+/* swap 32bit t_float. Is there a better way to do that???? */
+#ifdef _WINDOWS
+__inline static float netsend_float(float f)
+#else
+inline static float netsend_float(float f)
+#endif
+{
+ union
+ {
+ float f;
+ unsigned char b[4];
+ } dat1, dat2;
+
+ dat1.f = f;
+ dat2.b[0] = dat1.b[3];
+ dat2.b[1] = dat1.b[2];
+ dat2.b[2] = dat1.b[1];
+ dat2.b[3] = dat1.b[0];
+ return dat2.f;
+}
+
+/* swap 32bit long int */
+#ifdef _WINDOWS
+__inline static long netsend_long(long n)
+#else
+inline static long netsend_long(long n)
+#endif
+{
+ return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
+ ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
+}
+
+/* swap 16bit short int */
+#ifdef _WINDOWS
+__inline static long netsend_short(long n)
+#else
+inline static short netsend_short(short n)
+#endif
+{
+ return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
+}
+
+
+/* format specific stuff */
+
+#define SF_FLOAT 1
+#define SF_DOUBLE 2 /* not implemented */
+#define SF_8BIT 10
+#define SF_16BIT 11
+#define SF_32BIT 12 /* not implemented */
+#define SF_ALAW 20 /* not implemented */
+#define SF_MP3 30 /* not implemented */
+#define SF_AAC 31 /* AAC encoding using FAAC */
+#define SF_VORBIS 40 /* not implemented */
+#define SF_FLAC 50 /* not implemented */
+
+#define SF_SIZEOF(a) (a == SF_FLOAT ? sizeof(t_float) : \
+ a == SF_16BIT ? sizeof(short) : 1)
+
+
+/* version / byte-endian specific stuff */
+
+#define SF_BYTE_LE 1 /* little endian */
+#define SF_BYTE_BE 2 /* big endian */
+
+#if defined(_WINDOWS) || defined(__linux__) || defined(IRIX)
+#define SF_BYTE_NATIVE SF_BYTE_LE
+#else /* must be __APPLE__ */
+#define SF_BYTE_NATIVE SF_BYTE_BE
+#endif
+
+
+typedef struct _tag { /* size (bytes) */
+ char version; /* 1 */
+ char format; /* 1 */
+ long count; /* 4 */
+ char channels; /* 1 */
+ long framesize; /* 4 */
+ char extension[5]; /* 5 */
+} t_tag; /*--------------*/
+ /* 16 */
+
+
+typedef struct _frame {
+ t_tag tag;
+ char *data;
+} t_frame;
+
diff --git a/netsend~/test-netsend~.pd b/netsend~/test-netsend~.pd
new file mode 100755
index 0000000..424c0d9
--- /dev/null
+++ b/netsend~/test-netsend~.pd
@@ -0,0 +1,69 @@
+#N canvas 435 202 642 596 10;
+#X obj 18 178 netreceive~ 8008 4;
+#X obj 19 514 netsend~ 4;
+#X obj 18 221 dac~ 1;
+#X obj 68 221 dac~ 2;
+#X obj 121 221 dac~ 3;
+#X obj 175 222 dac~ 4;
+#X obj 74 480 osc~ 440;
+#X obj 145 481 osc~ 880;
+#X obj 214 480 osc~ 990;
+#X obj 281 481 osc~ 220;
+#X text 245 515 sends 4 dsp-channels to localhost:8008;
+#X msg 62 325 disconnect;
+#X msg 76 350 format float;
+#X msg 86 374 format 16bit;
+#X msg 102 398 format 8bit;
+#X text 189 358 format defines the resolution of the sent signal;
+#X text 347 480 the signals to send;
+#X floatatom 19 558 5 0 0 0 - - -;
+#X text 63 559 status: 1 = connected 0 = disconnected;
+#X msg 19 273 connect localhost 8008;
+#X text 15 13 netreceive~/netsend~;
+#X text 15 31 written by Olaf Matthes <olaf.matthes@gmx.de>;
+#X text 161 181 receives 4 channels on port 8808;
+#X text 175 274 connect to <hostname> <port>;
+#X text 203 421 change number of channels;
+#X text 200 376 float is the most expensive with the best resolution
+(32bit) \, default is 16bit;
+#X msg 109 422 channels 2;
+#X msg 38 298 connect 255.255.255.255 8008;
+#X text 14 50 commissioned by the Society for Arts and Technology [SAT]
+\, Montreal \, Quebec \, Canada \, http://www.sat.qc.at/;
+#X obj 269 222 print;
+#X obj 18 96 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 46 97 kick;
+#X msg 51 122 buffer 0.25;
+#X msg 62 149 print;
+#X obj 87 539 print;
+#X floatatom 224 224 5 0 0 0 - - -;
+#X text 220 298 broadcast to everybody on your local subnet listening
+on the specified port (in UDP mode only!);
+#X obj 112 448 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 137 448 get info;
+#X connect 0 0 2 0;
+#X connect 0 1 3 0;
+#X connect 0 2 4 0;
+#X connect 0 3 5 0;
+#X connect 0 4 35 0;
+#X connect 0 5 29 0;
+#X connect 1 0 17 0;
+#X connect 1 1 34 0;
+#X connect 6 0 1 0;
+#X connect 7 0 1 1;
+#X connect 8 0 1 2;
+#X connect 9 0 1 3;
+#X connect 11 0 1 0;
+#X connect 12 0 1 0;
+#X connect 13 0 1 0;
+#X connect 14 0 1 0;
+#X connect 19 0 1 0;
+#X connect 26 0 1 0;
+#X connect 27 0 1 0;
+#X connect 30 0 0 0;
+#X connect 31 0 0 0;
+#X connect 32 0 0 0;
+#X connect 33 0 0 0;
+#X connect 37 0 1 0;