aboutsummaryrefslogtreecommitdiff
path: root/speex~
diff options
context:
space:
mode:
Diffstat (limited to 'speex~')
-rw-r--r--speex~/CHANGES.LOG4
-rw-r--r--speex~/INSTALL18
-rw-r--r--speex~/Makefile84
-rw-r--r--speex~/README32
-rw-r--r--speex~/help-speex~.pd68
-rw-r--r--speex~/speexin~.c607
-rw-r--r--speex~/speexout~.c450
7 files changed, 1263 insertions, 0 deletions
diff --git a/speex~/CHANGES.LOG b/speex~/CHANGES.LOG
new file mode 100644
index 0000000..2bc161f
--- /dev/null
+++ b/speex~/CHANGES.LOG
@@ -0,0 +1,4 @@
+0.2
+ check length of frames to avoid crashes
+0.1
+ first implementation
diff --git a/speex~/INSTALL b/speex~/INSTALL
new file mode 100644
index 0000000..852c774
--- /dev/null
+++ b/speex~/INSTALL
@@ -0,0 +1,18 @@
+first, you need to install Speex library,
+i used v0.6.0 available from http://speex.sourceforge.net
+
+untar in /my/pd/dir/externs
+
+cd /my/pd/dir/externs/speex~
+
+make clean
+
+make
+
+make install
+
+open help-speex~.pd
+
+Thanx for getting here.
+
+Yves/
diff --git a/speex~/Makefile b/speex~/Makefile
new file mode 100644
index 0000000..754c858
--- /dev/null
+++ b/speex~/Makefile
@@ -0,0 +1,84 @@
+NAME=speexout~
+NAMEB=speexin~
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).dll $(NAMEB).dll
+
+.SUFFIXES: .dll
+
+PDNTCFLAGS = /W3 /WX /DNT /DPD /nologo
+VC="C:\Program Files\Microsoft Visual Studio\Vc98"
+
+PDNTINCLUDE = /I. /I\tcl\include /I\ftp\pd\src /I$(VC)\include
+
+PDNTLDIR = $(VC)\lib
+PDNTLIB = $(PDNTLDIR)\libc.lib \
+ $(PDNTLDIR)\oldnames.lib \
+ $(PDNTLDIR)\kernel32.lib \
+ \ftp\pd\bin\pd.lib
+
+.c.dll:
+ cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c
+ link /dll /export:$(CSYM)_setup $*.obj $(PDNTLIB)
+
+# ----------------------- IRIX 5.x -----------------------
+
+pd_irix5: $(NAME).pd_irix5 $(NAMEB).pd_irix5
+
+.SUFFIXES: .pd_irix5
+
+SGICFLAGS5 = -o32 -DPD -DUNIX -DIRIX -O2
+
+SGIINCLUDE = -I../../src
+
+.c.pd_irix5:
+ cc $(SGICFLAGS5) $(SGIINCLUDE) -o $*.o -c $*.c
+ ld -elf -shared -rdata_shared -o $*.pd_irix5 $*.o
+ rm $*.o
+
+# ----------------------- IRIX 6.x -----------------------
+
+pd_irix6: $(NAME).pd_irix6 $(NAMEB).pd_irix6
+
+.SUFFIXES: .pd_irix6
+
+SGICFLAGS6 = -n32 -DPD -DUNIX -DIRIX -DN32 -woff 1080,1064,1185 \
+ -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \
+ -Ofast=ip32
+
+.c.pd_irix6:
+ cc $(SGICFLAGS6) $(SGIINCLUDE) -o $*.o -c $*.c
+ ld -n32 -IPA -shared -rdata_shared -o $*.pd_irix6 $*.o
+ rm $*.o
+
+# ----------------------- LINUX i386 -----------------------
+
+pd_linux: $(NAME).pd_linux $(NAMEB).pd_linux
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -g -I/usr/local/include -DPD -DUNIX -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+ -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 -L/usr/local/lib -lc -lm -lspeex
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o ../$*.pd_linux
+ ln -s speex~/$*.pd_linux ..
+
+
+
+# ----------------------------------------------------------
+
+install:
+ cp help-*.pd ../../doc/5.reference
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/speex~/README b/speex~/README
new file mode 100644
index 0000000..1c290dd
--- /dev/null
+++ b/speex~/README
@@ -0,0 +1,32 @@
+*****************************************************************************
+Version 0.01
+copyleft (c) 2001 by Yves Degoyon
+
+speex~ is a voice quality streamer using Speex library
+consisting of two objects : speexin~ and speexout~.
+
+To install speex~, follow the steps from INSTALL
+
+This software is published under GPL terms.
+
+A big thanx to Jean-Marc Valin, author of Speex
+who helped me fixing encoding/decoding problems.
+
+This is software with ABSOLUTELY NO WARRANTY.
+Use it at your OWN RISK. It's possible to damage e.g. hardware or your hearing
+due to a bug or for other reasons.
+We do not warrant that the program is free of infringement of any third-party
+patents.
+
+*****************************************************************************
+
+speex~ has been compiled for Linux using Speex library v0.6.0
+( http://speex.sourceforge.net ).
+
+COPYING: you may use this source under GPL terms!
+
+PLEASE NOTE: The speex codec is patent free unlike GSM codecs.
+ that's the main reason why it's been choosen.
+ ( + it allows very low throughputs like 8kbits/s ).
+
+*****************************************************************************
diff --git a/speex~/help-speex~.pd b/speex~/help-speex~.pd
new file mode 100644
index 0000000..d1c40d4
--- /dev/null
+++ b/speex~/help-speex~.pd
@@ -0,0 +1,68 @@
+#N canvas 52 27 918 567 10;
+#X msg 36 286 \; pd dsp 1;
+#X msg 102 286 \; pd dsp 0;
+#X msg 323 51 disconnect;
+#X floatatom 221 227 5 0 0;
+#X obj 221 199 speexout~;
+#X obj 36 265 loadbang;
+#X symbolatom 679 245 20 0 0;
+#X text 662 261 Incomer's address;
+#X text 26 8 speex~ : speexout~ / speexin~;
+#X msg 343 161 quality 3;
+#X msg 345 327 quality 10;
+#X text 432 91 <-- settings for encoding quality;
+#X obj 87 145 adc~;
+#X obj 615 206 speexin~ 5000 1;
+#X text 321 8 Step 1 : connect the emitter to the receiver;
+#X text 30 124 Step 2 : speak in your microphone;
+#X text 541 487 bugs and comments @ ydegoyon@free.fr [-_-];
+#X text 541 469 part of unauthorized PD ( http://ydegoyon.free.fr )
+;
+#X msg 344 301 quality 9;
+#X msg 344 276 quality 8;
+#X msg 344 254 quality 7;
+#X msg 344 231 quality 6;
+#X msg 343 208 quality 5;
+#X msg 343 185 quality 4;
+#X msg 343 139 quality 2;
+#X msg 343 116 quality 1;
+#X msg 343 92 quality 0;
+#X text 461 104 quality: lowest = 0 \, highest = 10 \, default = 5
+;
+#X text 497 173 constructor : speexin~ <portno> <graphics>;
+#X msg 444 356 bang;
+#X obj 445 384 tabwrite~ speex-output;
+#N canvas 0 0 450 300 graph2 0;
+#X array speex-output 100 float 1;
+#A 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0;
+#X coords 0 1 99 -1 200 140 1;
+#X restore 172 360 graph;
+#X text 26 24 speech quality encoder/decoder/streamer;
+#X obj 611 316 dac~;
+#X msg 323 70 connect localhost 5000;
+#X msg 323 29 connect 81.65.246.123 5000;
+#X connect 2 0 4 0;
+#X connect 4 0 3 0;
+#X connect 5 0 0 0;
+#X connect 9 0 4 0;
+#X connect 10 0 4 0;
+#X connect 12 0 4 0;
+#X connect 13 0 30 0;
+#X connect 13 0 33 0;
+#X connect 13 0 33 1;
+#X connect 13 1 6 0;
+#X connect 18 0 4 0;
+#X connect 19 0 4 0;
+#X connect 20 0 4 0;
+#X connect 21 0 4 0;
+#X connect 22 0 4 0;
+#X connect 23 0 4 0;
+#X connect 24 0 4 0;
+#X connect 25 0 4 0;
+#X connect 26 0 4 0;
+#X connect 29 0 30 0;
+#X connect 34 0 4 0;
+#X connect 35 0 4 0;
diff --git a/speex~/speexin~.c b/speex~/speexin~.c
new file mode 100644
index 0000000..161c9de
--- /dev/null
+++ b/speex~/speexin~.c
@@ -0,0 +1,607 @@
+/* ------------------------ speexin~ ------------------------------------------ */
+/* */
+/* Object to receive a speex encoded stream sent by a peer using speexin~. */
+/* Written by Yves Degoyon (ydegoyon@free.fr). */
+/* Tarballs and updates @ http://ydegoyon.free.fr */
+/* */
+/* 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. */
+/* Uses the Speex voice quality encoding library which can */
+/* be found at http://speex.sourceforge.net. */
+/* */
+/* ---------------------------------------------------------------------------- */
+
+
+#include <m_pd.h>
+#include <g_canvas.h>
+
+#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 <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#define SOCKET_ERROR -1
+#else
+#include <winsock.h>
+#endif
+
+#include <speex.h> /* speex decoder stuff */
+#include <speex_bits.h> /* speex decoder stuff */
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+#define MIN_AUDIO_INPUT 1024 // we must a least have 8 chunks to play a correct sound
+#define INPUT_BUFFER_SIZE 32768
+#define OUTPUT_BUFFER_SIZE 32768 /* 32k */
+#define BARHEIGHT 10
+
+#define SPEEX_NB_MODE 0 /* audio data must be 8kHz */
+#define SPEEX_WB_MODE 1 /* audio data must be 16kHz */
+
+//#define DATADEBUG
+
+typedef void (*t_fdpollfn)(void *ptr, int fd);
+extern void sys_rmpollfn(int fd);
+extern void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
+
+/* time-out used for select() call */
+static struct timeval ztout;
+
+static char *speexin_version = "speexin~: speex voice quality streamer version 0.2, written by ydegoyon@free.fr";
+
+extern void sys_sockerror(char *s);
+
+void speexin_closesocket(int fd)
+{
+#ifdef UNIX
+ if ( close(fd) < 0 )
+ {
+ perror( "close" );
+ }
+ else
+ {
+ post( "speexin~ : closed socket : %d", fd );
+ }
+#endif
+#ifdef NT
+ closesocket(fd);
+#endif
+ sys_rmpollfn(fd);
+}
+
+int setsocketoptions(int sockfd)
+{
+ int sockopt = 1;
+ if (setsockopt(sockfd, SOL_TCP, TCP_NODELAY, (const char*) &sockopt, sizeof(int)) < 0)
+ {
+ post("speexin~ : setsockopt TCP_NODELAY failed");
+ perror( "setsockopt" );
+ return -1;
+ }
+ else
+ {
+ post("speexin~ : TCP_NODELAY set");
+ }
+
+#ifdef UNIX
+ sockopt = 1;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) < 0)
+ {
+ post("speexin~ : setsockopt SO_REUSEADDR failed");
+ perror( "setsockopt" );
+ return -1;
+ }
+ else
+ {
+ post("speexin~ : setsockopt SO_REUSEADDR done.");
+ }
+#endif
+ return 0;
+}
+
+
+/* ------------------------ speexin~ ----------------------------- */
+
+static t_class *speexin_class;
+
+typedef struct _speexin
+{
+ t_object x_obj;
+ t_int x_socket;
+ t_outlet *x_connectionip;
+ t_int x_serversocket;
+ t_int x_samplerate;
+
+ /* Speex stuff */
+ SpeexBits x_bits; /* bits packing structure */
+ void *x_decstate; /* decoder state */
+ t_int x_framesize; /* frame size */
+ t_int x_mode; /* Narrow or Wide Band */
+ int x_quality; /* encoding quality ( 0 to 10 ) */
+
+ t_int x_inpackets; /* number of packets received */
+ t_int x_dpacket; /* displayed packet in status bar */
+ t_int x_packetsize; /* size of the packets */
+ t_int x_pblocks; /* processed blocks */
+ t_int x_graphic; /* indicates if we show a graphic bar */
+
+ void *x_inbuffer; /* accumulation buffer for incoming speex frames */
+ t_int x_inwritepos; /* accumulation buffer for incoming speex frames */
+ t_int x_encsize;
+ t_int x_inbuffersize;
+
+ t_float *x_outbuffer; /* buffer to store audio decoded data */
+ t_int x_oinp;
+ t_int x_ooutp;
+ t_int x_outunread;
+ t_int x_outbuffersize;
+ t_float *x_decchunk;
+
+ t_canvas *x_canvas;
+
+ t_int x_stream; /* indicates if a stream is connected ( meaning correct input flow ) */
+ t_int x_newstream; /* at first, the stream must provide enough data to start */
+
+} t_speexin;
+
+void speexin_tilde_speex_init(t_speexin *x)
+{
+ int ret;
+ int pf=1;
+
+ speex_bits_init(&x->x_bits);
+
+ switch ( x->x_mode )
+ {
+ case SPEEX_NB_MODE :
+ x->x_decstate = speex_decoder_init(&speex_nb_mode);
+ break;
+
+ case SPEEX_WB_MODE :
+ x->x_decstate = speex_decoder_init(&speex_wb_mode);
+ break;
+
+ default :
+ error( "speexin~ : severe error : decoding scheme is unknown" );
+ break;
+ }
+
+ speex_decoder_ctl(x->x_decstate, SPEEX_GET_FRAME_SIZE, (void*)&x->x_framesize);
+
+ speex_decoder_ctl(x->x_decstate, SPEEX_SET_PF, &pf);
+
+ post( "speexin~ : frame size : %d", x->x_framesize );
+
+}
+
+static void speexin_decode_input(t_speexin *x)
+{
+ int i;
+ int alength = 0;
+ static char out[8192];
+ signed short int *p = (signed short int *) out;
+ int pbytes;
+ int ret;
+ int flength = 0;
+
+ if ( x->x_encsize > 0 )
+ {
+
+ while ( x->x_encsize > *(char *)(x->x_inbuffer) )
+ {
+
+ flength = *(char *)(x->x_inbuffer );
+
+ // post( "speexin~ : reading bits from 1 to : %d", flength+1 );
+ speex_bits_read_from(&x->x_bits, x->x_inbuffer+1, flength);
+
+#ifdef DATADEBUG
+ {
+ t_int si;
+
+ printf( "speexin~ : decoding : " );
+ for ( si=0; si<flength; si++ )
+ {
+ printf( "%d ", *(char *)(x->x_inbuffer+1+si) );
+ }
+ printf( "\n" );
+ }
+#endif
+
+ {
+ t_int sp=0, rp=0;
+
+ speex_decode(x->x_decstate, &x->x_bits, x->x_decchunk);
+
+ while( sp < x->x_framesize )
+ {
+ rp=(x->x_oinp+sp)%x->x_outbuffersize;
+ // if ( rp == x->x_outbuffersize - 1 ) post( "speexin~ : write at the end of audio buffer" );
+ // post( "speexin~ : sp=%d : rp=%d", sp, rp );
+ x->x_outbuffer[ rp ] = x->x_decchunk[sp++];
+ }
+ x->x_oinp = rp+1;
+ }
+ x->x_outunread += x->x_framesize;
+ memcpy( x->x_inbuffer, x->x_inbuffer+flength+1, x->x_inbuffersize-flength-1 );
+ x->x_encsize -= flength+1;
+ x->x_inwritepos -= flength+1;
+
+ }
+
+ }
+
+ if ( x->x_graphic && glist_isvisible( x->x_canvas ) )
+ {
+ /* update graphical read status */
+ if ( x->x_inpackets != x->x_dpacket )
+ {
+ char color[32];
+ int minpackets = ( MIN_AUDIO_INPUT/x->x_framesize)-2; // audio loop has eaten some already
+
+
+ sys_vgui(".x%x.c delete rectangle %xSTATUS\n", x->x_canvas, x );
+ sys_vgui(".x%x.c delete line %xTHRESHOLD\n", x->x_canvas, x );
+ if ( x->x_outunread > 0 )
+ {
+ t_int width;
+
+ if ( x->x_inpackets < (MIN_AUDIO_INPUT/x->x_framesize)/2 )
+ {
+ strcpy( color, "red" );
+ }
+ else
+ {
+ strcpy( color, "lightgreen" );
+ }
+ width = rtext_width( glist_findrtext( (t_glist*)x->x_canvas, (t_text *)x ) );
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill %s -tags %xSTATUS\n",
+ x->x_canvas, x->x_obj.te_xpix, x->x_obj.te_ypix-BARHEIGHT-1,
+ x->x_obj.te_xpix+(x->x_inpackets*x->x_packetsize*width)/INPUT_BUFFER_SIZE,
+ x->x_obj.te_ypix - 1, color, x );
+ sys_vgui(".x%x.c create line %d %d %d %d -fill red -tags %xTHRESHOLD\n",
+ x->x_canvas, x->x_obj.te_xpix+(minpackets*x->x_packetsize*width)/INPUT_BUFFER_SIZE,
+ x->x_obj.te_ypix-BARHEIGHT-1,
+ x->x_obj.te_xpix+(minpackets*x->x_packetsize*width)/INPUT_BUFFER_SIZE,
+ x->x_obj.te_ypix-1, x );
+ x->x_dpacket = x->x_inpackets;
+ }
+ }
+
+ }
+
+}
+
+static void speexin_recv(t_speexin *x)
+{
+ int ret;
+
+ if ( x->x_inwritepos > x->x_inbuffersize - 1024 )
+ {
+ post( "speexin~ : input buffer is full" );
+ return;
+ }
+ if ( ( ret = recv(x->x_socket, (void*) x->x_inbuffer + x->x_inwritepos,
+ (size_t)x->x_inbuffersize,
+ MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "speexin~ : receive error" );
+ perror( "recv" );
+ return;
+ }
+ else
+ {
+ // post( "speexin~ : received %d bytes at %d on %d ( up to %d)",
+ // ret, x->x_inwritepos, x->x_socket,
+ // x->x_inbuffersize );
+
+ if ( ret == 0 )
+ {
+ post( "speexin~ : closing connection ( s=%d )", x->x_socket );
+ speexin_closesocket(x->x_socket);
+ x->x_socket = -1;
+ sys_vgui(".x%x.c delete rectangle %xPBAR\n", x->x_canvas, x );
+ sys_vgui(".x%x.c delete line %xTHRESHOLD\n", x->x_canvas, x );
+ sys_vgui(".x%x.c delete rectangle %xSTATUS\n", x->x_canvas, x );
+ outlet_symbol( x->x_connectionip, gensym("") );
+ }
+ else
+ {
+ x->x_inpackets++;
+ }
+
+ x->x_encsize += ret;
+ x->x_inwritepos += ret;
+
+ speexin_decode_input(x);
+ }
+}
+
+static void speexin_acceptconnection(t_speexin *x)
+{
+ struct sockaddr_in incomer_address;
+ int sockaddrl = (int) sizeof( struct sockaddr );
+
+ int fd = accept(x->x_serversocket, (struct sockaddr*)&incomer_address, &sockaddrl );
+ post("speexin~: accepted incomer : %d.", fd );
+
+ if (fd < 0) {
+ post("speexin~: accept failed");
+ return;
+ }
+
+ if (x->x_socket > 0) {
+ post("speexin~: the source has changed to %s ( new socket = %d ).",
+ inet_ntoa( incomer_address.sin_addr ), fd );
+ speexin_closesocket(x->x_socket);
+ }
+
+ x->x_socket = fd;
+ sys_addpollfn(x->x_socket, (t_fdpollfn)speexin_recv, x);
+ outlet_symbol( x->x_connectionip, gensym( inet_ntoa( incomer_address.sin_addr) ) );
+
+ if ( x->x_graphic && glist_isvisible( x->x_canvas ) )
+ {
+ t_int width;
+
+ width = rtext_width( glist_findrtext( (t_glist*)x->x_canvas, (t_text *)x ) );
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill lightblue -tags %xPBAR\n",
+ x->x_canvas, x->x_obj.te_xpix, x->x_obj.te_ypix-BARHEIGHT-1,
+ x->x_obj.te_xpix + width, x->x_obj.te_ypix - 1, x );
+ }
+ x->x_stream = 0;
+ x->x_newstream = 1;
+
+}
+
+
+static int speexin_startservice(t_speexin* x, int portno)
+{
+ struct sockaddr_in server;
+ int sockfd;
+
+ /* create a socket */
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (sockfd < 0)
+ {
+ sys_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);
+
+ setsocketoptions(sockfd);
+
+ /* name the socket */
+ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) {
+ sys_sockerror("bind");
+ speexin_closesocket(sockfd);
+ return (0);
+ }
+
+ if (listen(sockfd, 5) < 0) {
+ sys_sockerror("listen");
+ speexin_closesocket(sockfd);
+ }
+ else
+ {
+ x->x_serversocket = sockfd;
+ sys_addpollfn(x->x_serversocket, (t_fdpollfn)speexin_acceptconnection, x);
+ }
+
+ return 1;
+}
+
+static void speexin_free(t_speexin *x)
+{
+ post( "speexin~ : free %x", x );
+ if (x->x_serversocket > 0) {
+ post( "speexin~ : closing server socket" );
+ speexin_closesocket(x->x_serversocket);
+ x->x_serversocket = -1;
+ }
+ if (x->x_socket > 0) {
+ post( "speexin~ : closing socket" );
+ speexin_closesocket(x->x_socket);
+ x->x_socket = -1;
+ }
+ if ( x->x_inbuffer ) freebytes( x->x_inbuffer, x->x_inbuffersize );
+ if ( x->x_outbuffer ) freebytes( x->x_outbuffer, x->x_outbuffersize*sizeof(t_float) );
+ if ( x->x_decchunk ) freebytes(x->x_decchunk, x->x_framesize*sizeof(t_float));
+}
+
+static t_int *speexin_perform(t_int *w)
+{
+ t_speexin *x = (t_speexin*) (w[1]);
+ t_float *out = (t_float *)(w[2]);
+ t_int n = (int)(w[3]);
+ t_int bsize = n;
+ t_int ret;
+ t_int i = 0;
+ t_int j = 0;
+ t_int sp = 0;
+ t_int sratio;
+
+ // samplerate is supposed to be above 16kHz, thus sratio>1
+ if ( x->x_mode == SPEEX_NB_MODE )
+ {
+ sratio = x->x_samplerate / 8000;
+ }
+ else
+ {
+ sratio = x->x_samplerate / 16000;
+ }
+ // post( "speexin~ : ratio : %d", sratio );
+
+ memset( out, 0x0, n*sizeof(t_float ) );
+
+ sp = 0;
+ while( sp < n )
+ {
+ if ( ( ( x->x_outunread > MIN_AUDIO_INPUT ) && x->x_newstream ) || // wait the buffer to load
+ ( x->x_stream ) // check that the stream provides enough data
+ )
+ {
+ if ( x->x_newstream )
+ {
+ x->x_newstream = 0;
+ x->x_stream = 1;
+ }
+ /* resampling */
+ for ( j=0; j<sratio; j++ )
+ {
+ *(out+sp)=*(x->x_outbuffer+x->x_ooutp)/8000; // input has been scaled
+ //*(x->x_outbuffer+x->x_ooutp)=0.0; // data read, now zeroed
+ sp++;
+ if ( sp >= n ) break;
+ }
+ x->x_ooutp = (x->x_ooutp + 1)%x->x_outbuffersize;
+ // if ( x->x_ooutp == x->x_outbuffersize - 1 ) post( "speexin~ : end of audio buffer" );
+ x->x_outunread-=1;
+ }
+ else
+ {
+ for ( j=0; j<sratio; j++ )
+ {
+ *(out+sp)=0.0;
+ sp++;
+ if ( sp >= n ) break;
+ }
+ }
+ }
+ x->x_pblocks++;
+
+ if ( ( x->x_outunread <= MIN_AUDIO_INPUT/10 ) && ( x->x_stream ) )
+ {
+ // post( "speexin~ : stream lost (too little input)" );
+ x->x_stream = 0;
+ x->x_newstream = 1; // waiting for a new stream
+ }
+
+ if ( x->x_pblocks == x->x_framesize/bsize )
+ {
+ x->x_inpackets--;
+ x->x_pblocks = 0;
+ }
+
+ return (w+4);
+}
+
+static void speexin_dsp(t_speexin *x, t_signal **sp)
+{
+ dsp_add(speexin_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+
+static void *speexin_new(t_floatarg fportno, t_floatarg fdographics)
+{
+ t_speexin *x;
+ int i;
+
+ if ( fportno < 0 || fportno > 65535 )
+ {
+ post( "speexin~ : error : wrong portnumber : %d", (int)fportno );
+ return NULL;
+ }
+ if ( ((int)fdographics != 0) && ((int)fdographics != 1.) )
+ {
+ post( "speexin~ : error : constructor : speexin~ <portnumber> [graphic flag = 0 | 1 ] ( got = %f)", fdographics );
+ return NULL;
+ }
+
+ x = (t_speexin *)pd_new(speexin_class);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_connectionip = outlet_new(&x->x_obj, &s_symbol);
+
+ x->x_serversocket = -1;
+ x->x_socket = -1;
+ x->x_inpackets = 0;
+ x->x_inwritepos = 0;
+ x->x_dpacket = -1;
+ x->x_mode = SPEEX_NB_MODE;
+ x->x_samplerate = sys_getsr();
+
+ x->x_canvas = canvas_getcurrent();
+
+ x->x_inbuffersize = INPUT_BUFFER_SIZE;
+ x->x_outbuffersize = OUTPUT_BUFFER_SIZE;
+ x->x_inbuffer = (char*) getbytes( x->x_inbuffersize );
+ memset( x->x_inbuffer, 0x0, INPUT_BUFFER_SIZE );
+ x->x_outbuffer = (t_float*) getbytes( x->x_outbuffersize*sizeof(t_float) );
+ memset( x->x_outbuffer, 0x0, OUTPUT_BUFFER_SIZE*sizeof(t_float) );
+
+ if ( !x->x_inbuffer || !x->x_outbuffer )
+ {
+ post( "speexin~ : could not allocate buffers." );
+ return NULL;
+ }
+
+ x->x_encsize = 0;
+ x->x_oinp = 0;
+ x->x_ooutp = 0;
+
+ ztout.tv_sec = 0;
+ ztout.tv_usec = 0;
+
+ x->x_graphic = (int)fdographics;
+
+ post( "speexin~ : starting service on port %d", (int)fportno );
+ speexin_startservice(x, (int)fportno);
+
+ // init speex decoder
+ speexin_tilde_speex_init(x);
+
+ x->x_decchunk = (t_float*)getbytes(x->x_framesize*sizeof(t_float));
+ if (!x->x_decchunk) /* check allocation... */
+ {
+ error("speexin~ : cannot allocate chunk");
+ return NULL;
+ }
+
+ return (x);
+}
+
+
+void speexin_tilde_setup(void)
+{
+ post( speexin_version );
+ speexin_class = class_new(gensym("speexin~"),
+ (t_newmethod) speexin_new, (t_method) speexin_free,
+ sizeof(t_speexin), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(speexin_class, nullfn, gensym("signal"), 0);
+ class_addmethod(speexin_class, (t_method) speexin_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(speexin_class, gensym("help-speex~.pd"));
+}
diff --git a/speex~/speexout~.c b/speex~/speexout~.c
new file mode 100644
index 0000000..793f7ec
--- /dev/null
+++ b/speex~/speexout~.c
@@ -0,0 +1,450 @@
+/* ------------------------ speexout~ ----------------------------------------- */
+/* */
+/* Tilde object to send speex encoded data to a peer using speexin~. */
+/* Written by Yves Degoyon (ydegoyon@free.fr). */
+/* Tarballs and updates @ http://ydegoyon.free.fr */
+/* */
+/* 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. */
+/* Uses the Speex codec which can */
+/* be found at http://speex.sourceforge.net */
+/* */
+/* "Western values mean nothing to us" */
+/* "She is beyond good and evil" */
+/* Pop Group -- */
+/* ---------------------------------------------------------------------------- */
+
+
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <malloc.h>
+#include <ctype.h>
+#ifdef UNIX
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/time.h>
+#define SOCKET_ERROR -1
+#else
+#include <io.h>
+#include <windows.h>
+#include <winsock.h>
+#include <windef.h>
+#endif
+
+#include <speex.h> /* speex codec stuff */
+#include <speex_bits.h> /* speex codec stuff */
+
+#include "m_pd.h" /* standard pd stuff */
+
+#define IN_BUFFER_SIZE 65536
+#define OUT_BUFFER_SIZE 8192
+
+// #define DATADEBUG
+
+#define SPEEX_NB_MODE 0 /* audio data must be 8kHz */
+#define SPEEX_WB_MODE 1 /* audio data must be 16kHz */
+
+#define SPEEX_DEFAULT_QUALITY 5 /* default quality */
+
+static char *speexout_version = "speexout~: speex voice quality streamer version 0.2, written by ydegoyon@free.fr";
+
+static t_class *speexout_class;
+
+typedef struct _speexout
+{
+ t_object x_obj;
+ int x_samplerate; /* pd sampling rate */
+
+ /* Speex stuff */
+ SpeexBits x_bits; /* bits packing structure */
+ void *x_encstate; /* encoder state */
+ t_int x_framesize; /* frame size */
+ t_int x_mode; /* Narrow or Wide Band */
+ int x_quality; /* encoding quality ( 0 to 10 ) */
+
+ /* buffer stuff */
+ unsigned short x_inp; /* in position for buffer */
+ unsigned short x_outp; /* out position for buffer */
+ t_int x_encsize; /* size of encoded data */
+ t_float *x_inbuf; /* data to be coded by Speex */
+ char *x_outbuf; /* data returned by Speex -> our speex stream */
+ int x_bytesbuffered; /* number of unprocessed bytes in buffer */
+ int x_bytesemitted; /* number of encoded bytes emitted */
+ int x_start;
+ t_float *x_encchunk;
+
+ /* connection data */
+ int x_fd; /* info about connection status */
+ int x_outpackets; /* speex packets sent */
+
+ t_float x_f; /* float needed for signal input */
+
+} t_speexout;
+
+
+ /* encode PCM data to speex frames */
+static void speexout_encode(t_speexout *x)
+{
+ if ( x->x_bytesbuffered > x->x_framesize )
+ {
+ speex_bits_reset(&x->x_bits);
+
+ {
+ t_int sp=0, rp=0;
+
+ while( sp < x->x_framesize )
+ {
+ rp=(x->x_outp+sp)%IN_BUFFER_SIZE;
+ // post( "speexout~ : sp=%d : rp=%d", sp, rp );
+ x->x_encchunk[ sp++ ] = *(x->x_inbuf+rp);
+ }
+ speex_encode(x->x_encstate, x->x_encchunk, &x->x_bits);
+ }
+
+ x->x_outp = (x->x_outp+x->x_framesize)%IN_BUFFER_SIZE;
+ x->x_bytesbuffered -= x->x_framesize;
+ x->x_encsize = speex_bits_write(&x->x_bits, x->x_outbuf+1, OUT_BUFFER_SIZE );
+ if ( x->x_encsize < 127 )
+ {
+ *(x->x_outbuf) = (char)x->x_encsize;
+ }
+ else
+ {
+ post( "speexout~ : encoding error : frame is more than 127 bytes" );
+ x->x_encsize = -1;
+ }
+ x->x_bytesemitted += x->x_encsize;
+#ifdef DATADEBUG
+ {
+ t_int si;
+
+ printf( "speexout~ : encoded : " );
+ for ( si=0; si<x->x_encsize; si++ )
+ {
+ printf( "%d ", *(x->x_outbuf+si) );
+ }
+ printf( "\n" );
+ }
+#endif
+ }
+ else
+ {
+ x->x_encsize = -1;
+ }
+}
+
+ /* stream data to the peer */
+static void speexout_stream(t_speexout *x)
+{
+ int count = -1, i;
+
+ if ( x->x_encsize > 0 )
+ {
+ count = send(x->x_fd, x->x_outbuf, x->x_encsize+1, MSG_NOSIGNAL);
+ if(count < 0)
+ {
+ error("speexout~: could not send encoded data to the peer (%d)", count);
+#ifndef UNIX
+ closesocket(x->x_fd);
+#else
+ close(x->x_fd);
+#endif
+ x->x_fd = -1;
+ outlet_float(x->x_obj.ob_outlet, 0);
+ }
+ else
+ {
+ x->x_outpackets++;
+ // post( "speexout~ : emitted %d bytes (packets = %d)", count, x->x_outpackets );
+ if ( x->x_outpackets%100 == 0 )
+ {
+ // post( "speexout~ : emitted %d bytes (packets = %d)", x->x_bytesemitted, x->x_outpackets );
+ }
+ if(count != x->x_encsize+1)
+ {
+ error("speexout~: %d bytes skipped", x->x_encsize - count);
+ }
+ }
+ x->x_encsize = -1;
+ }
+}
+
+
+ /* buffer and downsample the data */
+static t_int *speexout_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]); /* audio inlet */
+ t_speexout *x = (t_speexout *)(w[2]);
+ int n = (int)(w[3]); /* number of samples */
+ unsigned short i,wp;
+ t_float accum = 0.;
+ int sratio;
+
+ /* samplerate is supposed to be > 16kHz, thus sratio > 1 */
+ if ( x->x_mode == SPEEX_NB_MODE )
+ {
+ sratio = x->x_samplerate / 8000;
+ }
+ else
+ {
+ sratio = x->x_samplerate / 16000;
+ }
+
+ /* copy the data into the buffer and resample audio data */
+
+ accum=0;
+ for(wp = 0; wp < n; wp++)
+ {
+ accum += *(in+wp);
+ if ( wp % sratio == sratio - 1 )
+ {
+ x->x_inbuf[x->x_inp] = ( accum / sratio ) * 8000; // scale the input for speex best efficiency
+ // post( "x->x_inp : %d", x->x_inp );
+ x->x_inp = (x->x_inp+1)%IN_BUFFER_SIZE;
+ x->x_bytesbuffered ++;
+ accum = 0;
+ }
+ }
+
+ if( ( x->x_fd >= 0 ) && ( x->x_bytesbuffered > x->x_framesize ) )
+ {
+ /* encode and send to the peer */
+ speexout_encode(x); /* speex encoding */
+ speexout_stream(x); /* stream mp3 to the peer */
+ }
+ else
+ {
+ x->x_start = -1;
+ }
+ return (w+4);
+}
+
+static void speexout_dsp(t_speexout *x, t_signal **sp)
+{
+ dsp_add(speexout_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
+}
+
+ /* initialize the speex library */
+static void speexout_tilde_speex_init(t_speexout *x)
+{
+
+ speex_bits_init(&x->x_bits);
+
+ switch ( x->x_mode )
+ {
+ case SPEEX_NB_MODE :
+ x->x_encstate = speex_encoder_init(&speex_nb_mode);
+ break;
+
+ case SPEEX_WB_MODE :
+ x->x_encstate = speex_encoder_init(&speex_wb_mode);
+ break;
+
+ default :
+ error( "speexout~ : severe error : encoding scheme is unknown" );
+ break;
+ }
+
+ speex_encoder_ctl(x->x_encstate, SPEEX_GET_FRAME_SIZE, (void*)&x->x_framesize);
+ post( "speexout~ : frame size : %d", x->x_framesize );
+
+}
+
+ /* connect to the peer */
+static void speexout_connect(t_speexout *x, t_symbol *hostname, t_floatarg fportno)
+{
+ struct sockaddr_in csocket;
+ struct hostent *hp;
+ int portno = fportno; /* get port from message box */
+
+ /* variables used for communication with the peer */
+ const char *buf = 0;
+ unsigned int len;
+ int sockfd;
+
+#ifndef UNIX
+ unsigned int ret;
+#else
+ int ret;
+#endif
+
+ if (x->x_fd >= 0)
+ {
+ error("speexout~: already connected");
+ return;
+ }
+
+ sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sockfd < 0)
+ {
+ error("speexout~: internal error while attempting to open socket");
+ return;
+ }
+
+ /* connect socket using hostname provided in command line */
+ csocket.sin_family = AF_INET;
+ hp = gethostbyname(hostname->s_name);
+ if (hp == 0)
+ {
+ post("speexout~: bad host?");
+#ifndef UNIX
+ closesocket(sockfd);
+#else
+ close(sockfd);
+#endif
+ return;
+ }
+ memcpy((char *)&csocket.sin_addr, (char *)hp->h_addr, hp->h_length);
+
+ /* assign client port number */
+ csocket.sin_port = htons((unsigned short)portno);
+
+ /* try to connect. */
+ post("speexout~: connecting to port %d", portno);
+ if (connect(sockfd, (struct sockaddr *) &csocket, sizeof (csocket)) < 0)
+ {
+ error("speexout~: connection failed!\n");
+#ifndef UNIX
+ closesocket(sockfd);
+#else
+ close(sockfd);
+#endif
+ return;
+ }
+
+ x->x_fd = sockfd;
+ x->x_outpackets = 0;
+ outlet_float( x->x_obj.ob_outlet, 1 );
+ post( "speexout~ : connected to peer" );
+
+
+}
+
+ /* close connection to the peer */
+static void speexout_disconnect(t_speexout *x)
+{
+
+ int err = -1;
+
+ if(x->x_fd >= 0) /* close socket */
+ {
+#ifndef UNIX
+ closesocket(x->x_fd);
+#else
+ close(x->x_fd);
+#endif
+ x->x_fd = -1;
+ outlet_float( x->x_obj.ob_outlet, 0 );
+ post("speexout~: connection closed");
+ }
+}
+
+ /* settings for encoding quality */
+static void speexout_quality(t_speexout *x, t_floatarg fquality )
+{
+ if ( fquality < 0 || fquality > 10 ) {
+ post( "speexout~ : wrong quality." );
+ return;
+ }
+ x->x_quality = fquality;
+ post("speexout~: setting quality to : %d", x->x_quality);
+ speex_encoder_ctl(x->x_encstate, SPEEX_SET_QUALITY, &x->x_quality);
+}
+
+ /* clean up */
+static void speexout_free(t_speexout *x)
+{
+
+ speex_bits_destroy(&x->x_bits);
+
+ speex_encoder_destroy(x->x_encstate);
+
+ post("speexout~: encoder destroyed");
+
+ if(x->x_fd >= 0)
+#ifndef UNIX
+ closesocket(x->x_fd);
+#else
+ close(x->x_fd);
+#endif
+ freebytes(x->x_inbuf, IN_BUFFER_SIZE*sizeof(t_float));
+ freebytes(x->x_outbuf, OUT_BUFFER_SIZE);
+ freebytes(x->x_encchunk, x->x_framesize*sizeof(t_float));
+}
+
+static void *speexout_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_speexout *x = (t_speexout *)pd_new(speexout_class);
+ outlet_new( &x->x_obj, &s_float );
+
+ x->x_mode = SPEEX_NB_MODE;
+ x->x_quality = SPEEX_DEFAULT_QUALITY;
+ x->x_fd = -1;
+ x->x_outpackets = 0;
+ x->x_samplerate = sys_getsr();
+ x->x_inbuf = getbytes(IN_BUFFER_SIZE*sizeof(t_float)); /* buffer for encoder input */
+ x->x_outbuf = getbytes(OUT_BUFFER_SIZE); /* our mp3 stream */
+ if ((!x->x_inbuf)||(!x->x_outbuf)) /* check buffers... */
+ {
+ error("speexout~ : cannot allocate buffers");
+ return NULL;
+ }
+ x->x_bytesbuffered = 0;
+ x->x_bytesemitted = 0;
+ x->x_inp = 0;
+ x->x_outp = 0;
+ x->x_encsize = 0;
+ x->x_start = -1;
+ speexout_tilde_speex_init(x);
+
+ x->x_encchunk = (t_float*)getbytes(x->x_framesize*sizeof(t_float));
+ if (!x->x_encchunk) /* check allocation... */
+ {
+ error("speexout~ : cannot allocate chunk");
+ return NULL;
+ }
+ return(x);
+}
+
+void speexout_tilde_setup(void)
+{
+ post(speexout_version);
+ speexout_class = class_new(gensym("speexout~"), (t_newmethod)speexout_new, (t_method)speexout_free,
+ sizeof(t_speexout), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(speexout_class, t_speexout, x_f );
+ class_sethelpsymbol(speexout_class, gensym("help-speex~.pd"));
+ class_addmethod(speexout_class, (t_method)speexout_dsp, gensym("dsp"), 0);
+ class_addmethod(speexout_class, (t_method)speexout_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0);
+ class_addmethod(speexout_class, (t_method)speexout_disconnect, gensym("disconnect"), 0);
+ class_addmethod(speexout_class, (t_method)speexout_quality, gensym("quality"), A_FLOAT, 0);
+}
+