aboutsummaryrefslogtreecommitdiff
path: root/mp3live~
diff options
context:
space:
mode:
Diffstat (limited to 'mp3live~')
-rw-r--r--mp3live~/INSTALL21
-rw-r--r--mp3live~/Makefile88
-rw-r--r--mp3live~/README65
-rw-r--r--mp3live~/help-mp3live~.pd118
-rw-r--r--mp3live~/interface.h32
-rw-r--r--mp3live~/mp3fileout~.c553
-rw-r--r--mp3live~/mp3streamin~.c665
-rw-r--r--mp3live~/mp3streamout~.c733
-rw-r--r--mp3live~/mpg123.h136
-rw-r--r--mp3live~/mpglib.h65
-rw-r--r--mp3live~/test-streaming-mp3.pd96
11 files changed, 2572 insertions, 0 deletions
diff --git a/mp3live~/INSTALL b/mp3live~/INSTALL
new file mode 100644
index 0000000..63db4c7
--- /dev/null
+++ b/mp3live~/INSTALL
@@ -0,0 +1,21 @@
+You need to get lame > v3.90 installed first.
+libmp3lame.so is searched in /usr/local/lib
+( no time to write configure scripts ).
+if it's installed elsewhere, change the Makefile,
+you won't die from that.
+
+untar in /my/pd/dir/externs
+
+cd /my/pd/dir/externs/mp3live~
+
+make clean
+
+make
+
+make install
+
+open help-mp3live~.pd
+
+Thanx for getting here.
+
+Yves/
diff --git a/mp3live~/Makefile b/mp3live~/Makefile
new file mode 100644
index 0000000..a9d6228
--- /dev/null
+++ b/mp3live~/Makefile
@@ -0,0 +1,88 @@
+NAME=mp3streamout~
+CSYM=mp3streamout_tilde
+NAMEB=mp3streamin~
+CSYMB=mp3streamin_tilde
+NAMEC=mp3fileout~
+CSYMC=mp3fileout_tilde
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).dll $(NAMEB).dll $(NAMEC).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 $(NAMEC).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 $(NAMEC).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 $(NAMEC).pd_linux
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -g -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 -lc -lm -L/usr/local/lib -lmp3lame
+ #strip --strip-unneeded $*.pd_linux
+ rm -f $*.o ../$*.pd_linux
+ ln -s mp3live~/$*.pd_linux ..
+
+
+
+# ----------------------------------------------------------
+
+install:
+ cp help-*.pd ../../doc/5.reference
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/mp3live~/README b/mp3live~/README
new file mode 100644
index 0000000..3af0dbb
--- /dev/null
+++ b/mp3live~/README
@@ -0,0 +1,65 @@
+Version 0.01
+copyleft (c) 2001 by Yves Degoyon
+
+mp3live~ is a peer-to-peer mp3 streamer package
+consisting of three objects : mp3streamout~, mp3fileout~ and mp3streamin~.
+
+To install mp3live~, follow the steps from INSTALL
+
+This software is published under GPL terms.
+
+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.
+
+*****************************************************************************
+
+mp3live~ has been compiled for Linux using LAME 3.92.
+The newest version of LAME can be found at sourceforge.net
+
+COPYING: you may use this source under GPL terms!
+
+PLEASE NOTE: This software may contain patented alogrithm (at least
+ patented in some countries). It may be not allowed to sell/use products
+ based on this source code in these countries. Check this out first!
+
+COPYRIGHT of MP3 music:
+ Please note, that the duplicating of copyrighted music without explicit
+ permission violates the rights of the owner.
+ And remember, copyrighted music sucks [ as well as corporate ]
+
+*****************************************************************************
+
+ using mp3live~ external for Pure Data
+
+Open the help-mp3live~.pd to understand how it works.
+
+A note about MPEG encoding :
+
+ALLOWED QUALITY FACTOR :
+
+ -q <arg> <arg> = 0...9. Default -q 5
+ -q 0: Highest quality, very slow
+ -q 9: Poor quality, but fast
+ -h Same as -q 2. Recommended.
+ -f Same as -q 7. Fast, ok quality
+
+ALLOWED BITRATES :
+
+bitrates (kbps): 32 40 48 56 64 80 96 112 128 160 192 224 256 320
+
+BUGS :
+
+1.
+You cannot create more than MAX_DECODERS mp3streamin~ objects. The actual value is 100.
+
+2.
+Current version of lame ( 3.92 ) produces a lot of errors for quality < 5. Blame it on lame !!!!
+
+3.
+Mono is not supported. Some additional code should be added for mp3streamin~. Blame it on me !!!
+
+4.
+Resampling is not supported. Blame it on me !!!
diff --git a/mp3live~/help-mp3live~.pd b/mp3live~/help-mp3live~.pd
new file mode 100644
index 0000000..ac68464
--- /dev/null
+++ b/mp3live~/help-mp3live~.pd
@@ -0,0 +1,118 @@
+#N canvas 11 -3 941 684 10;
+#X msg 35 594 \; pd dsp 1;
+#X text 432 123 <-- settings for mp3 stream;
+#X text 492 177 1 = joint stereo (default);
+#X text 456 165 mode: 0 = stereo;
+#X text 492 189 2 = dual channel;
+#X msg 101 594 \; pd dsp 0;
+#X obj 551 317 dac~;
+#X msg 368 80 disconnect;
+#X floatatom 221 227 5 0 0;
+#X obj 221 199 mp3streamout~;
+#X msg 367 54 connect localhost 5000;
+#X msg 767 69 bang;
+#X obj 767 89 openpanel;
+#X obj 766 186 soundfiler;
+#X floatatom 767 210 10 0 0;
+#X obj 767 111 t s b;
+#X obj 767 148 pack s s;
+#X msg 766 169 read -resize \$1 \$2;
+#X obj 803 111 float \$0;
+#X text 755 50 Step 1 : Load a sound file;
+#X obj 767 128 route float;
+#X obj 123 149 tabplay~ \$0-sample;
+#X msg 123 120 bang;
+#X obj 114 627 table \$0-sample;
+#X obj 821 148 makefilename %d-sample;
+#X text 371 34 Step 2 : connect the streamer;
+#X text 8 100 Step 3 : emit a sound through the streamer;
+#X obj 234 276 env~;
+#X obj 67 310 timer;
+#X obj 207 276 > 0;
+#X obj 159 276 route 1;
+#X obj 122 276 t b f;
+#X floatatom 121 340 5 0 0;
+#X obj 80 276 spigot;
+#X msg 102 256 0;
+#X msg 130 256 1;
+#X text 453 135 (bitrate \, mode \, quality);
+#X text 453 227 Note : resampling is not supported for now;
+#X text 454 238 Note : see the README for allowed bitrate;
+#X text 30 9 mp3live~ : mp3streamout~ / mp3streamin~;
+#X text 30 20 peer-to-peer mp3 streaming \, written by ydegoyon@free.fr
+;
+#X msg 342 147 mpeg 32 2 9;
+#X text 492 202 3 = mono ( not supported );
+#X text 455 153 bitrate: bitrate of stream \, def. 128kbit/s;
+#X text 452 215 quality: 5 = high \, 9 = low;
+#X text 85 360 streamer latency (ms);
+#X obj 35 573 loadbang;
+#X msg 343 123 mpeg 128 0 5;
+#X obj 536 270 mp3streamin~ 5000 1;
+#X symbolatom 639 300 10 0 0;
+#X text 622 316 Incomer's address;
+#X floatatom 229 496 5 0 0;
+#X floatatom 327 498 5 0 0;
+#X text 282 366 Step 3 bis : emit a file through the streamer;
+#X msg 298 386 bang;
+#X msg 299 423 open \$1;
+#X msg 393 410 disconnect;
+#X msg 393 391 connect localhost 5000;
+#X msg 393 429 start;
+#X msg 438 430 stop;
+#X obj 298 406 openpanel;
+#X text 292 522 Number of frames emitted;
+#X text 160 515 Connection state;
+#X text 31 36 Warning : mp3fileout~ will not read ANY mp3 file \,;
+#X text 30 46 but \, at least \, those produced with mp3write~.;
+#X msg 474 430 resume;
+#X msg 524 429 seek 10000;
+#X text 391 503 A bang is emitted at the end of the file;
+#X obj 301 454 mp3fileout~;
+#X obj 389 485 print thisistheend;
+#X connect 7 0 9 0;
+#X connect 9 0 8 0;
+#X connect 10 0 9 0;
+#X connect 11 0 12 0;
+#X connect 12 0 15 0;
+#X connect 13 0 14 0;
+#X connect 15 0 16 0;
+#X connect 15 1 18 0;
+#X connect 16 0 17 0;
+#X connect 17 0 13 0;
+#X connect 18 0 20 0;
+#X connect 20 0 24 0;
+#X connect 21 0 9 0;
+#X connect 21 0 9 1;
+#X connect 22 0 21 0;
+#X connect 22 0 28 0;
+#X connect 22 0 35 0;
+#X connect 24 0 16 1;
+#X connect 27 0 29 0;
+#X connect 28 0 32 0;
+#X connect 29 0 30 0;
+#X connect 30 0 31 0;
+#X connect 31 0 33 0;
+#X connect 32 0 34 0;
+#X connect 33 0 28 1;
+#X connect 34 0 33 1;
+#X connect 35 0 33 1;
+#X connect 41 0 9 0;
+#X connect 46 0 0 0;
+#X connect 47 0 9 0;
+#X connect 48 0 6 0;
+#X connect 48 0 27 0;
+#X connect 48 1 6 1;
+#X connect 48 2 49 0;
+#X connect 54 0 60 0;
+#X connect 55 0 68 0;
+#X connect 56 0 68 0;
+#X connect 57 0 68 0;
+#X connect 58 0 68 0;
+#X connect 59 0 68 0;
+#X connect 60 0 55 0;
+#X connect 65 0 68 0;
+#X connect 66 0 68 0;
+#X connect 68 0 51 0;
+#X connect 68 1 52 0;
+#X connect 68 2 69 0;
diff --git a/mp3live~/interface.h b/mp3live~/interface.h
new file mode 100644
index 0000000..de3136a
--- /dev/null
+++ b/mp3live~/interface.h
@@ -0,0 +1,32 @@
+/*
+** Copyright (C) 2000 Albert L. Faber
+**
+** 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.
+*/
+
+#ifndef INTERFACE_H_INCLUDED
+#define INTERFACE_H_INCLUDED
+
+// #include "common.h"
+#include "interface.h"
+
+BOOL InitMP3(PMPSTR mp);
+int decodeMP3(PMPSTR mp,unsigned char *inmemory,int inmemsize,char *outmemory,int outmemsize,int *done);
+void ExitMP3(PMPSTR mp);
+
+/* added remove_buf to support mpglib seeking */
+void remove_buf(PMPSTR mp);
+
+#endif
diff --git a/mp3live~/mp3fileout~.c b/mp3live~/mp3fileout~.c
new file mode 100644
index 0000000..edadf8e
--- /dev/null
+++ b/mp3live~/mp3fileout~.c
@@ -0,0 +1,553 @@
+/* ------------------------ mp3fileout~ --------------------------------------- */
+/* */
+/* Tilde object to send an mp3 file to a peer using mp3streamin~ */
+/* 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 LAME MPEG 1 Layer 3 encoding library (lame_enc.dll) which can */
+/* be found at http://www.cdex.n3.net. */
+/* */
+/* "See mass murder on a scale you've never seen" */
+/* "And all the one who tried hard to succeed" */
+/* You know who, don't you ??? */
+/* ---------------------------------------------------------------------------- */
+
+
+#include <m_imp.h>
+#include <g_canvas.h>
+
+#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>
+#include "mpg123.h" /* mpg123 decoding library from lame 3.92 */
+#include "mpglib.h" /* mpglib decoding library from lame 3.92 */
+#include "interface.h" /* mpglib decoding library from lame 3.92 */
+#define SOCKET_ERROR -1
+#else
+#include <winsock.h>
+#endif
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+#define INPUT_BUFFER_SIZE 32768
+#define OUTPUT_BUFFER_SIZE 32768
+#define MAX_FRAME_SIZE 1152
+
+/* useful debugging functions from mpglib */
+extern int decode_header( struct frame* fr, unsigned long newhead );
+extern void print_header_compact( struct frame* fr );
+extern int head_check( unsigned long head, int check_layer );
+
+/* time-out used for select() call */
+static struct timeval ztout;
+
+static char *mp3fileout_version = "mp3fileout~: mp3 file streamer version 0.2, written by ydegoyon@free.fr";
+
+extern void sys_sockerror(char *s);
+
+void mp3fileout_closesocket(int fd)
+{
+#ifdef UNIX
+ if ( close(fd) < 0 )
+ {
+ perror( "close" );
+ }
+ else
+ {
+ post( "mp3fileout~ : closed socket : %d", fd );
+ }
+#endif
+#ifdef NT
+ closesocket(fd);
+#endif
+ sys_rmpollfn(fd);
+}
+
+/* ------------------------ mp3fileout~ ----------------------------- */
+
+static t_class *mp3fileout_class;
+
+typedef struct _mp3fileout
+{
+ t_object x_obj;
+ t_int x_socket;
+ t_int x_fd; /* file descriptor for the mp3 file */
+ t_int x_eof; /* end of file is reached */
+ t_int x_emit; /* indicates the ability to emit */
+ t_int x_nbwaitloops;/* synchronization cycles count */
+ t_int x_blocksize; /* actual blocksize */
+
+ void *x_inbuffer; /* accumulation buffer for read mp3 frames */
+ t_int x_inwriteposition;
+ t_int x_inbuffersize;
+ t_int x_framesize;
+ t_int x_offset; /* offset used for decoding */
+ t_int x_nbloops; /* number of perform loops */
+
+ void *x_outbuffer; /* buffer to be emitted */
+ t_int x_outframes; /* number of frames emitted */
+ t_int x_outbuffersize;
+ t_int x_outavable; /* number of available bytes to emit */
+
+ t_canvas *x_canvas;
+
+ t_outlet *x_connected; /* indicates state of the connection */
+ t_outlet *x_endreached;/* indicates the end of file */
+ t_outlet *x_frames; /* indicates the number of frames emitted */
+
+} t_mp3fileout;
+
+static int mp3fileout_search_header(t_mp3fileout *x)
+{
+ t_int i;
+ t_int length = 0;
+ struct frame hframe;
+ unsigned long cheader;
+ t_int ret = sizeof( unsigned long);
+ t_int foffset = 0;
+ unsigned int a,b,c,d;
+ unsigned char buf[sizeof(unsigned long)];
+ t_float nbsamplesframe = 0;
+
+ while( ret>0 )
+ {
+ ret = read( x->x_fd, (void *)buf, sizeof( unsigned long ) );
+
+ foffset+=ret;
+
+ if ( ret>0 )
+ {
+ /* check for a valid header */
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ cheader = 0;
+ cheader = a;
+ cheader <<= 8;
+ cheader |= b;
+ cheader <<= 8;
+ cheader |= c;
+ cheader <<= 8;
+ cheader |= d;
+ if ( head_check( cheader, 0 ) )
+ {
+ decode_header( &hframe, cheader );
+ // print_header_compact( &hframe );
+ x->x_framesize = hframe.framesize;
+ nbsamplesframe = ( hframe.mpeg25 ? 576 : 1152 );
+ x->x_nbwaitloops = (int)(nbsamplesframe/x->x_blocksize);
+ if ( x->x_nbwaitloops == 0 ) x->x_nbwaitloops = 1;
+ // post ( "mp3fileout~ : will wait %d loops", x->x_nbwaitloops );
+
+ // rewind file to the start of the frame
+ if ( lseek( x->x_fd, -sizeof(unsigned long), SEEK_CUR ) < 0 )
+ {
+ post( "mp3fileout~ : could not rewind file." );
+ }
+ if ( x->x_outframes == 0 )
+ {
+ post( "mp3fileout~ : found firstframe @ %d", foffset );
+ }
+ break;
+ }
+ // post( "mp3fileout~ : read %d bytes.", ret );
+ }
+ else
+ {
+ if ( ret < 0 )
+ {
+ post( "mp3fileout~ : error encountered ( ret=%d )...file reading done.", ret );
+ perror( "read" );
+ x->x_eof = 1;
+ }
+ else
+ {
+ post( "mp3fileout~ : file reading done.", ret );
+ x->x_eof = 1;
+ outlet_bang( x->x_endreached );
+ }
+ return -1;
+ }
+
+ }
+
+ return x->x_framesize;
+}
+
+static int mp3fileout_read_frame(t_mp3fileout *x)
+{
+ int size, ret;
+
+ if ( x->x_fd > 0 && !x->x_eof)
+ {
+ if ( ( size = mp3fileout_search_header( x ) ) > 0 )
+ {
+ if ( size+sizeof(unsigned long) > INPUT_BUFFER_SIZE )
+ {
+ post( "mp3fileout~ : cannot read frame : size too big : %d", size );
+ return -1;
+ }
+ // post( "mp3fileout~ : reading a frame : size : %d", size );
+ ret = read( x->x_fd, x->x_inbuffer, size+sizeof(unsigned long) );
+
+ if ( ret>0 )
+ {
+ memcpy( x->x_outbuffer, x->x_inbuffer, ret );
+ x->x_outavable += ret;
+ return ret;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+static int mp3fileout_send_frame(t_mp3fileout *x)
+{
+ int ret=0;
+
+ if ( x->x_socket > 0 && x->x_emit )
+ {
+ if ( ( ret = send( x->x_socket, x->x_outbuffer, x->x_outavable, MSG_NOSIGNAL ) ) < 0 )
+ {
+ post( "mp3fileout~ : connection lost." );
+ perror( "send" );
+ x->x_socket = -1;
+ x->x_emit = 0;
+ return -1;
+ }
+ else
+ {
+ memcpy( x->x_outbuffer, x->x_outbuffer+ret, x->x_outbuffersize-ret );
+ x->x_outavable -= ret;
+ x->x_outframes++;
+ outlet_float( x->x_frames, x->x_outframes );
+ // post( "mp3fileout~ : sent %d bytes, x->x_outavable : %d", ret, x->x_outavable );
+ }
+
+ }
+ else
+ {
+ // artificially empty buffer
+ x->x_outavable = 0;
+ }
+ return ret;
+}
+
+static void mp3fileout_free(t_mp3fileout *x)
+{
+ if (x->x_socket > 0) {
+ post( "mp3fileout~ : closing socket" );
+ mp3fileout_closesocket(x->x_socket);
+ x->x_socket = -1;
+ }
+ if ( x->x_fd > 0 )
+ {
+ if ( close( x->x_fd ) < 0 )
+ {
+ post( "mp3fileout~ : could not close file." );
+ perror( "close" );
+ }
+ }
+ if ( x->x_inbuffer ) freebytes( x->x_inbuffer, x->x_inbuffersize );
+}
+
+static t_int *mp3fileout_perform(t_int *w)
+{
+ t_mp3fileout *x = (t_mp3fileout*) (w[1]);
+ int ret;
+ int i = 0;
+
+ x->x_blocksize = (t_int)(w[2]);
+ // check new incoming data
+ if ( x->x_socket > 0 )
+ {
+ if ( x->x_nbloops % x->x_nbwaitloops == 0 )
+ {
+ /* read a frame in the file */
+ if ( mp3fileout_read_frame(x) > 0 )
+ {
+ /* send the frame to the peer */
+ mp3fileout_send_frame(x);
+ }
+ }
+ x->x_nbloops = ( x->x_nbloops+1 ) % x->x_nbwaitloops;
+ }
+ return (w+3);
+}
+
+static void mp3fileout_dsp(t_mp3fileout *x, t_signal **sp)
+{
+ dsp_add(mp3fileout_perform, 2, x, sp[0]->s_n);
+}
+
+ /* start streaming */
+static void mp3fileout_start(t_mp3fileout *x)
+{
+ x->x_emit = 1;
+ if ( x->x_fd > 0 )
+ {
+ // reset file pointer
+ if ( lseek( x->x_fd, 0, SEEK_SET ) < 0 )
+ {
+ post ( "mp3fileout~ : could not reset file pointer.");
+ x->x_eof = 1;
+ return;
+ }
+ x->x_eof = 0;
+ x->x_outframes = 0;
+ outlet_float( x->x_frames, x->x_outframes );
+ }
+}
+
+ /* resume file reading */
+static void mp3fileout_resume(t_mp3fileout *x)
+{
+ x->x_emit = 1;
+}
+
+ /* seek in file */
+static void mp3fileout_seek(t_mp3fileout *x, t_floatarg foffset)
+{
+ if ( foffset < 0 )
+ {
+ post( "mp3fileout~ : wrong offset.");
+ return;
+ }
+ if ( x->x_fd > 0 )
+ {
+ // reset file pointer
+ if ( lseek( x->x_fd, (int)foffset, SEEK_SET ) < 0 )
+ {
+ post ( "mp3fileout~ : could not reset file pointer.");
+ x->x_eof = 1;
+ return;
+ }
+ x->x_eof = 0;
+ }
+}
+
+ /* stop streaming */
+static void mp3fileout_stop(t_mp3fileout *x)
+{
+ x->x_emit = 0;
+}
+
+ /* open mp3 file */
+static void mp3fileout_open(t_mp3fileout *x, t_symbol *filename)
+{
+ // first close previous file
+ if ( x->x_fd > 0 )
+ {
+ if ( close( x->x_fd ) < 0 )
+ {
+ post( "mp3fileout~ : could not close file." );
+ perror( "close" );
+ }
+ x->x_outframes = 0;
+ outlet_float( x->x_frames, x->x_outframes );
+ }
+ if ( ( x->x_fd = open( filename->s_name, O_RDONLY ) ) < 0 )
+ {
+ post( "mp3fileout~ : could not open file : %s", filename->s_name );
+ perror( "open" );
+ x->x_eof = 1;
+ }
+ else
+ {
+ x->x_eof = 0;
+ post( "mp3fileout~ : opened file : %s ( fd = %d )", filename->s_name, x->x_fd );
+ }
+}
+
+ /* connect to the peer */
+static void mp3fileout_connect(t_mp3fileout *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 */
+ unsigned int len;
+ int sockfd;
+
+#ifndef UNIX
+ unsigned int ret;
+#else
+ int ret;
+#endif
+
+ if (x->x_socket >= 0)
+ {
+ error("mp3fileout~: already connected");
+ return;
+ }
+
+ sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sockfd < 0)
+ {
+ error("mp3fileout~: 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("mp3fileout~: 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("mp3fileout~: connecting to port %d", portno);
+ if (connect(sockfd, (struct sockaddr *) &csocket, sizeof (csocket)) < 0)
+ {
+ error("mp3fileout~: connection failed!\n");
+#ifndef UNIX
+ closesocket(sockfd);
+#else
+ close(sockfd);
+#endif
+ return;
+ }
+
+ x->x_socket = sockfd;
+ x->x_outframes = 0;
+ outlet_float( x->x_frames, x->x_outframes );
+ outlet_float( x->x_connected, 1 );
+ post( "mp3fileout~ : connected to peer" );
+
+}
+
+ /* close connection to the peer */
+static void mp3fileout_disconnect(t_mp3fileout *x)
+{
+
+ int err = -1;
+ if(x->x_socket >= 0) /* close socket */
+ {
+#ifndef UNIX
+ closesocket(x->x_socket);
+#else
+ close(x->x_socket);
+#endif
+ x->x_socket = -1;
+ outlet_float( x->x_connected, 0 );
+ x->x_outframes = 0;
+ outlet_float( x->x_frames, x->x_outframes );
+ post("mp3fileout~: connection closed");
+ }
+}
+
+static void *mp3fileout_new(void)
+{
+ t_mp3fileout *x;
+ int i;
+
+ x = (t_mp3fileout *)pd_new(mp3fileout_class);
+ x->x_connected = outlet_new( &x->x_obj, &s_float );
+ x->x_frames = outlet_new( &x->x_obj, &s_float );
+ x->x_endreached = outlet_new( &x->x_obj, &s_bang );
+
+ x->x_socket = -1;
+ x->x_fd = -1;
+ x->x_eof = 0;
+ x->x_canvas = canvas_getcurrent();
+
+ x->x_offset = 0;
+ x->x_inbuffersize = INPUT_BUFFER_SIZE;
+ x->x_inbuffer = (char*) getbytes( x->x_inbuffersize );
+ if ( !x->x_inbuffer )
+ {
+ post( "mp3fileout~ : could not allocate buffers." );
+ return NULL;
+ }
+ memset( x->x_inbuffer, 0x0, INPUT_BUFFER_SIZE );
+
+ x->x_outbuffersize = OUTPUT_BUFFER_SIZE;
+ x->x_outbuffer = (char*) getbytes( x->x_outbuffersize );
+ if ( !x->x_outbuffer )
+ {
+ post( "mp3fileout~ : could not allocate buffers." );
+ return NULL;
+ }
+ memset( x->x_outbuffer, 0x0, OUTPUT_BUFFER_SIZE );
+ x->x_outavable = 0;
+
+ x->x_inwriteposition = 0;
+ x->x_nbloops = 0;
+ x->x_nbwaitloops = 1;
+
+ return (x);
+}
+
+void mp3fileout_tilde_setup(void)
+{
+ post( mp3fileout_version );
+ mp3fileout_class = class_new(gensym("mp3fileout~"),
+ (t_newmethod) mp3fileout_new, (t_method) mp3fileout_free,
+ sizeof(t_mp3fileout), 0, A_NULL);
+
+ class_addmethod(mp3fileout_class, nullfn, gensym("signal"), 0);
+ class_addmethod(mp3fileout_class, (t_method) mp3fileout_dsp, gensym("dsp"), 0);
+ class_addmethod(mp3fileout_class, (t_method)mp3fileout_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0);
+ class_addmethod(mp3fileout_class, (t_method)mp3fileout_open, gensym("open"), A_SYMBOL, 0);
+ class_addmethod(mp3fileout_class, (t_method)mp3fileout_disconnect, gensym("disconnect"), 0);
+ class_addmethod(mp3fileout_class, (t_method)mp3fileout_start, gensym("start"), 0);
+ class_addmethod(mp3fileout_class, (t_method)mp3fileout_resume, gensym("resume"), 0);
+ class_addmethod(mp3fileout_class, (t_method)mp3fileout_seek, gensym("seek"), A_DEFFLOAT, 0);
+ class_addmethod(mp3fileout_class, (t_method)mp3fileout_stop, gensym("stop"), 0);
+ class_sethelpsymbol(mp3fileout_class, gensym("help-mp3live~.pd"));
+}
diff --git a/mp3live~/mp3streamin~.c b/mp3live~/mp3streamin~.c
new file mode 100644
index 0000000..954af64
--- /dev/null
+++ b/mp3live~/mp3streamin~.c
@@ -0,0 +1,665 @@
+/* ------------------------ mp3streamin~ -------------------------------------- */
+/* */
+/* Tilde object to receive an mp3-stream sent by a peer using mp3streamout~. */
+/* 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 LAME MPEG 1 Layer 3 encoding library (lame_enc.dll) which can */
+/* be found at http://www.cdex.n3.net. */
+/* */
+/* "Repackage sex, your interests." */
+/* "Somehow, maintain the interest." */
+/* Gang Of Four -- Natural's Not In It */
+/* ---------------------------------------------------------------------------- */
+
+
+#include <m_imp.h>
+#include <g_canvas.h>
+
+#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>
+#include "mpg123.h" /* mpg123 decoding library from lame 3.92 */
+#include "mpglib.h" /* mpglib decoding library from lame 3.92 */
+#include "interface.h" /* mpglib decoding library from lame 3.92 */
+#define SOCKET_ERROR -1
+#else
+#include <winsock.h>
+#endif
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+#define MIN_AUDIO_INPUT 8064 // we must a least have 8 chunks to play a correct sound
+#define INPUT_BUFFER_SIZE MIN_AUDIO_INPUT
+#define OUTPUT_BUFFER_SIZE 131072 /* 128k*/
+#define LAME_AUDIO_CHUNK_SIZE 1152
+#define BARHEIGHT 10
+#define MAX_DECODERS 10
+
+/* useful debugging functions from mpglib */
+extern int decode_header( struct frame* fr, unsigned long newhead );
+extern void print_header_compact( struct frame* fr );
+extern int head_check( unsigned long head, int check_layer );
+
+/* time-out used for select() call */
+static struct timeval ztout;
+
+static char *mp3streamin_version = "mp3streamin~: mp3 peer-to-peer streamer version 0.3, written by ydegoyon@free.fr";
+
+extern void sys_sockerror(char *s);
+
+void mp3streamin_closesocket(int fd)
+{
+#ifdef UNIX
+ if ( close(fd) < 0 )
+ {
+ perror( "close" );
+ }
+ else
+ {
+ post( "mp3streamin~ : 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("mp3streamin~ : setsockopt TCP_NODELAY failed");
+ perror( "setsockopt" );
+ return -1;
+ }
+ else
+ {
+ post("mp3streamin~ : TCP_NODELAY set");
+ }
+
+#ifdef UNIX
+ sockopt = 1;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) < 0)
+ {
+ post("mp3streamin~ : setsockopt SO_REUSEADDR failed");
+ perror( "setsockopt" );
+ return -1;
+ }
+ else
+ {
+ post("mp3streamin~ : setsockopt SO_REUSEADDR done.");
+ }
+#endif
+ return 0;
+}
+
+
+/* ------------------------ mp3streamin~ ----------------------------- */
+
+static t_class *mp3streamin_class;
+
+typedef struct _mp3streamin
+{
+ t_object x_obj;
+ t_int x_instance;
+ t_int x_socket;
+ t_int x_shutdown;
+ t_outlet *x_connectionip;
+ t_int x_serversocket;
+ 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 mp3 frames */
+ t_int x_inwriteposition;
+ t_int x_inbuffersize;
+
+ t_float *x_outbuffer; /* buffer to store audio decoded data */
+ t_int x_outwriteposition;
+ t_int x_outreadposition;
+ t_int x_outunread;
+ t_int x_outbuffersize;
+
+ 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_int x_bitrateindex; /* remember the bitrate index */
+
+} t_mp3streamin;
+
+/* too bad, this needs to be static,
+ handling an array to enable several decoders in pd */
+static MPSTR mp[MAX_DECODERS]; /* decoder buffer */
+int nbinstances = 0;
+
+void mp3streamin_tilde_mpglib_init(t_mp3streamin *x)
+{
+ int ret;
+
+ InitMP3(&mp[x->x_instance]);
+}
+
+static int mp3streamin_decode_input(t_mp3streamin *x)
+{
+ int i;
+ int alength = 0;
+ struct frame hframe;
+ unsigned int a,b,c,d;
+ unsigned long cheader;
+ static char out[8192];
+ signed short int *p = (signed short int *) out;
+ int pbytes;
+ int ret;
+
+ if ( !x->x_shutdown )
+ {
+ /* decode first 4 bytes as the header */
+ a = *((unsigned char*)x->x_inbuffer);
+ b = *((unsigned char*)x->x_inbuffer+1);
+ c = *((unsigned char*)x->x_inbuffer+2);
+ d = *((unsigned char*)x->x_inbuffer+3);
+
+ cheader = 0;
+ cheader = a;
+ cheader <<= 8;
+ cheader |= b;
+ cheader <<= 8;
+ cheader |= c;
+ cheader <<= 8;
+ cheader |= d;
+ if ( head_check( cheader, 0 ) )
+ {
+ // post( "mp3streamin~ : valid header ( packet=%d)", x->x_inpackets );
+ decode_header( &hframe, cheader );
+ // print_header_compact( &hframe );
+ // when the bitrate change, reinit decoder
+ if ( x->x_bitrateindex != hframe.bitrate_index )
+ {
+ ExitMP3(&mp[x->x_instance]);
+ InitMP3(&mp[x->x_instance]);
+ x->x_bitrateindex = hframe.bitrate_index;
+ }
+ }
+ else
+ {
+ post( "mp3streamin~ : error : mp3 packet received without header" );
+ // ignore data
+ x->x_inwriteposition = 0;
+ x->x_inpackets--;
+ return( -1 );
+ }
+
+ // post( "mp3streamin~ : decoding %d bytes framesize=%d", x->x_inwriteposition, hframe.framesize );
+ ret =
+ decodeMP3(&mp[x->x_instance], (unsigned char*)x->x_inbuffer,
+ x->x_inwriteposition, (char *) p, sizeof(out), &pbytes);
+
+ switch (ret) {
+ case MP3_OK:
+ switch (mp[x->x_instance].fr.stereo) {
+ case 1:
+ case 2:
+ alength = ((mp[x->x_instance].fr.stereo==1)?pbytes >> 1 : pbytes >> 2);
+ // post( "mp3streamin~ : processed %d samples", alength );
+ // update outbuffer contents
+ for ( i=0; i<alength; i++ )
+ {
+ if ( x->x_outunread >= x->x_outbuffersize-2 )
+ {
+ post( "mp3streamin~ : too much input ... ignored" );
+ continue;
+ }
+ *(x->x_outbuffer+x->x_outwriteposition) = ((t_float)(*p++))/32767.0;
+ x->x_outwriteposition = (x->x_outwriteposition + 1)%x->x_outbuffersize;
+ *(x->x_outbuffer+x->x_outwriteposition) =
+ ((mp[x->x_instance].fr.stereo==2)?((t_float)(*p++))/32767.0 : 0.0);
+ x->x_outwriteposition = (x->x_outwriteposition + 1)%x->x_outbuffersize;
+ x->x_outunread+=2;
+
+ if ( x->x_outunread > MIN_AUDIO_INPUT && !x->x_stream )
+ {
+ post( "mp3streamin~ : stream connected." );
+ x->x_stream = 1;
+ }
+ }
+
+ break;
+ default:
+ alength = -1;
+ break;
+ }
+ break;
+
+ case MP3_NEED_MORE:
+ post( "mp3streamin~ : retry lame decoding (more data needed)." );
+ alength = 0;
+ break;
+
+ case MP3_ERR:
+ post( "mp3streamin~ : lame decoding failed." );
+ alength = -1;
+ break;
+
+ }
+
+ x->x_inwriteposition = 0;
+ }
+ else
+ {
+ if ( x->x_outunread == 0 )
+ {
+ post( "mp3streamin~ : connection closed" );
+ mp3streamin_closesocket(x->x_socket);
+ x->x_stream = 0;
+ x->x_newstream = 0;
+ x->x_inpackets = 0;
+ x->x_inwriteposition = 0;
+ x->x_bitrateindex = -1;
+ x->x_socket=-1;
+ outlet_symbol( x->x_connectionip, gensym("") );
+ }
+ }
+
+ 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/LAME_AUDIO_CHUNK_SIZE )-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/LAME_AUDIO_CHUNK_SIZE)/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;
+ }
+ else
+ {
+ if ( x->x_shutdown )
+ {
+ x->x_shutdown=0;
+ 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 );
+ }
+ }
+ }
+ }
+ return alength;
+}
+
+static void mp3streamin_recv(t_mp3streamin *x)
+{
+ int ret;
+
+ if ( ( ret = recv(x->x_socket, (void*) (x->x_inbuffer + x->x_inwriteposition),
+ (size_t)((x->x_inbuffersize-x->x_inwriteposition)),
+ MSG_NOSIGNAL) ) < 0 )
+ {
+ post( "mp3_streamin~ : receive error" );
+ perror( "recv" );
+ return;
+ }
+ else
+ {
+ // post( "streamin~ : received %d bytes at %d on %d ( up to %d)",
+ // ret, x->x_inwriteposition, x->x_socket,
+ // x->x_inbuffersize-x->x_inwriteposition*sizeof( unsigned long) );
+
+ if ( ret == 0 )
+ {
+ /* initiate the shutdown phase */
+ x->x_shutdown=1;
+ }
+ else
+ {
+ // check we don't overflow input buffer
+ if ( (x->x_inpackets+1)*x->x_packetsize > x->x_inbuffersize )
+ {
+ post( "mp3streamin~ : too much input...resetting" );
+ x->x_inpackets=0;
+ x->x_inwriteposition=0;
+ return;
+ }
+ x->x_inpackets++;
+ x->x_packetsize=ret;
+ if ( x->x_inpackets % 100 == 0 )
+ {
+ // post( "mp3streamin~ : received %d packets", x->x_inpackets );
+ }
+ x->x_inwriteposition += ret;
+ }
+
+ mp3streamin_decode_input(x);
+ }
+}
+
+static void mp3streamin_acceptconnection(t_mp3streamin *x)
+{
+ struct sockaddr_in incomer_address;
+ int sockaddrl = (int) sizeof( struct sockaddr );
+
+ int fd = accept(x->x_serversocket, (struct sockaddr*)&incomer_address, &sockaddrl );
+
+ if (fd < 0) {
+ post("mp3streamin~: accept failed");
+ return;
+ }
+
+ if (x->x_socket > 0) {
+ sys_addpollfn(fd, (t_fdpollfn)mp3streamin_recv, x);
+ if ( x->x_outunread != 0 )
+ {
+ post("mp3streamin~: still have some data to decode, retry later you %s.",
+ inet_ntoa( incomer_address.sin_addr ));
+ mp3streamin_closesocket( fd );
+ return;
+ }
+ post("mp3streamin~: the source has changed to %s.",
+ inet_ntoa( incomer_address.sin_addr ));
+ mp3streamin_closesocket(x->x_socket);
+ }
+
+ x->x_socket = fd;
+ sys_addpollfn(x->x_socket, (t_fdpollfn)mp3streamin_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 mp3streamin_startservice(t_mp3streamin* 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");
+ mp3streamin_closesocket(sockfd);
+ return (0);
+ }
+
+ if (listen(sockfd, 5) < 0) {
+ sys_sockerror("listen");
+ mp3streamin_closesocket(sockfd);
+ }
+ else
+ {
+ x->x_serversocket = sockfd;
+ sys_addpollfn(x->x_serversocket, (t_fdpollfn)mp3streamin_acceptconnection, x);
+ }
+
+ return 1;
+}
+
+static void mp3streamin_free(t_mp3streamin *x)
+{
+ post( "mp3streamin~ : free %x", x );
+ if (x->x_serversocket > 0) {
+ post( "mp3streamin~ : closing server socket" );
+ mp3streamin_closesocket(x->x_serversocket);
+ x->x_serversocket = -1;
+ }
+ if (x->x_socket > 0) {
+ post( "mp3streamin~ : closing socket" );
+ mp3streamin_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_instance == nbinstances-1 )
+ {
+ nbinstances--;
+ }
+}
+
+static t_int *mp3streamin_perform(t_int *w)
+{
+ t_mp3streamin *x = (t_mp3streamin*) (w[1]);
+ t_float *out1 = (t_float *)(w[2]);
+ t_float *out2 = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ int bsize = n;
+ int ret;
+ int i = 0;
+
+ while( n-- )
+ {
+ if ( ( ( x->x_outunread > MIN_AUDIO_INPUT ) && x->x_newstream ) || // wait the buffer to load
+ ( ( x->x_shutdown ) && ( x->x_outunread >= 2 ) ) || // clean disconnection
+ ( x->x_stream ) // check that the stream provides enough data
+ )
+ {
+ if ( x->x_newstream && !x->x_shutdown )
+ {
+ x->x_newstream = 0;
+ x->x_stream = 1;
+ }
+ *out1++=*(x->x_outbuffer+x->x_outreadposition);
+ x->x_outreadposition = (x->x_outreadposition + 1)%x->x_outbuffersize;
+ *out2++=*(x->x_outbuffer+x->x_outreadposition);
+ x->x_outreadposition = (x->x_outreadposition + 1)%x->x_outbuffersize;
+ x->x_outunread-=2;
+ if ( n == 1 ) x->x_pblocks++;
+ }
+ else
+ {
+ *out1++=0.0;
+ *out2++=0.0;
+ }
+ }
+
+ if ( ( x->x_outunread <= MIN_AUDIO_INPUT/10 ) && ( x->x_stream ) )
+ {
+ post( "mp3streamin~ : stream lost (too little input)" );
+ x->x_stream = 0;
+ x->x_newstream = 1; // waiting for a new stream
+ }
+
+ if ( x->x_pblocks == LAME_AUDIO_CHUNK_SIZE/bsize )
+ {
+ x->x_inpackets--;
+ x->x_pblocks = 0;
+ }
+
+#ifdef DO_MY_OWN_SELECT
+ // check new incoming data
+ if ( x->x_socket > 0 )
+ {
+ fd_set readset;
+ fd_set exceptset;
+
+ FD_ZERO(&readset);
+ FD_ZERO(&exceptset);
+ FD_SET(x->x_socket, &readset );
+ FD_SET(x->x_socket, &exceptset );
+
+ if ( select( maxfd+1, &readset, NULL, &exceptset, &ztout ) >0 )
+ {
+ if ( FD_ISSET( x->x_socket, &readset) || FD_ISSET( x->x_socket, &exceptset ) )
+ {
+ /* receive data or error and decode it */
+ mp3streamin_recv(x);
+ }
+ }
+ }
+#endif
+ return (w+5);
+}
+
+static void mp3streamin_dsp(t_mp3streamin *x, t_signal **sp)
+{
+ dsp_add(mp3streamin_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+
+static void *mp3streamin_new(t_floatarg fportno, t_floatarg fdographics)
+{
+ t_mp3streamin *x;
+ int i;
+
+ if ( fportno < 0 || fportno > 65535 )
+ {
+ post( "mp3streamin~ : error : wrong portnumber : %d", (int)fportno );
+ return NULL;
+ }
+ if ( ((int)fdographics != 0) && ((int)fdographics != 1.) )
+ {
+ post( "mp3streamin~ : error : constructor : mp3streamin~ <portnumber> [graphic flag = 0 | 1 ] ( got = %f)", fdographics );
+ return NULL;
+ }
+
+ x = (t_mp3streamin *)pd_new(mp3streamin_class);
+ post( "mp3streamin~ : new %x (instance = %d) %d", x, nbinstances, sizeof( MPSTR ) );
+ outlet_new(&x->x_obj, &s_signal);
+ 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_shutdown = 0;
+ x->x_inpackets = 0;
+ x->x_dpacket = -1;
+
+ 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 );
+
+ if ( !x->x_inbuffer || !x->x_outbuffer )
+ {
+ post( "mp3streamin~ : could not allocate buffers." );
+ return NULL;
+ }
+
+ if ( nbinstances < MAX_DECODERS )
+ {
+ x->x_instance = nbinstances++;
+ }
+ else
+ {
+ post( "mp3streamin~ : cannot create more decoders (memory issues), sorry" );
+ return NULL;
+ }
+
+ x->x_inwriteposition = 0;
+ x->x_outreadposition = 0;
+ x->x_outwriteposition = 0;
+ x->x_outunread = 0;
+
+ ztout.tv_sec = 0;
+ ztout.tv_usec = 0;
+
+ x->x_graphic = (int)fdographics;
+
+ post( "mp3streamin~ : starting service on port %d", (int)fportno );
+ mp3streamin_startservice(x, (int)fportno);
+
+ // init lame decoder
+ mp3streamin_tilde_mpglib_init(x);
+
+ return (x);
+}
+
+
+void mp3streamin_tilde_setup(void)
+{
+ post( mp3streamin_version );
+ mp3streamin_class = class_new(gensym("mp3streamin~"),
+ (t_newmethod) mp3streamin_new, (t_method) mp3streamin_free,
+ sizeof(t_mp3streamin), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(mp3streamin_class, nullfn, gensym("signal"), 0);
+ class_addmethod(mp3streamin_class, (t_method) mp3streamin_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(mp3streamin_class, gensym("help-mp3live~.pd"));
+}
diff --git a/mp3live~/mp3streamout~.c b/mp3live~/mp3streamout~.c
new file mode 100644
index 0000000..2bf561f
--- /dev/null
+++ b/mp3live~/mp3streamout~.c
@@ -0,0 +1,733 @@
+/* ------------------------ mp3streamout~ ------------------------------------- */
+/* */
+/* Tilde object to send mp3-stream to a peer using mp3streamin~. */
+/* 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 LAME MPEG 1 Layer 3 encoding library (lame_enc.dll) which can */
+/* be found at http://www.cdex.n3.net. */
+/* */
+/* "I'd sell my soul to god" */
+/* "If it could take away the pain." */
+/* Theo Hakola -- */
+/* ---------------------------------------------------------------------------- */
+
+
+
+#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>
+#include <lame/lame.h> /* lame encoder stuff */
+#define SOCKET_ERROR -1
+#else
+#include <io.h>
+#include <windows.h>
+#include <winsock.h>
+#include <windef.h>
+#include "lame_enc.h" /* lame encoder stuff */
+#endif
+
+#include "m_pd.h" /* standard pd stuff */
+
+#include "mpg123.h" /* sub-library MPGLIB included in lame */
+/* useful debugging functions from mpglib */
+extern int decode_header( struct frame* fr, unsigned long newhead );
+extern void print_header_compact( struct frame* fr );
+extern int head_check( unsigned long head, int check_layer );
+
+#define MY_MP3_MALLOC_IN_SIZE 65536
+ /* max size taken from lame readme */
+#define MY_MP3_MALLOC_OUT_SIZE 1.25*MY_MP3_MALLOC_IN_SIZE+7200
+
+#define MAXDATARATE 320 /* maximum mp3 data rate is 320kbit/s */
+#define STRBUF_SIZE 32
+
+static char *mp3streamout_version = "mp3streamout~: mp3 peer-to-peer streamer version 0.3, written by ydegoyon@free.fr";
+
+#ifndef UNIX
+static HINSTANCE dll = NULL;
+static BEINITSTREAM initStream = NULL;
+static BEENCODECHUNK encodeChunk = NULL;
+static BEDEINITSTREAM deinitStream = NULL;
+static BECLOSESTREAM closeStream = NULL;
+static BEVERSION dllVersion = NULL;
+static BEWRITEVBRHEADER writeVBRHeader = NULL;
+#endif
+
+static t_class *mp3streamout_class;
+
+typedef struct _mp3streamout
+{
+ t_object x_obj;
+
+ /* LAME stuff */
+ int x_lame; /* info about encoder status */
+ int x_lamechunk; /* chunk size for LAME encoder */
+ int x_mp3size; /* number of returned mp3 samples */
+
+ /* buffer stuff */
+ unsigned short x_inp; /* in position for buffer */
+ unsigned short x_outp; /* out position for buffer*/
+ short *x_mp3inbuf; /* data to be sent to LAME */
+ char *x_mp3outbuf; /* data returned by LAME -> our mp3 stream */
+ short *x_buffer; /* data to be buffered */
+ int x_bytesbuffered; /* number of unprocessed bytes in buffer */
+ int x_start;
+
+ /* mp3 format stuff */
+ int x_samplerate;
+ int x_bitrate; /* bitrate of mp3 stream */
+ int x_mp3mode; /* mode (mono, joint stereo, stereo, dual mono) */
+ int x_mp3quality; /* quality of encoding */
+
+ /* connection data */
+ int x_fd; /* info about connection status */
+ int x_outpackets; /* mp3 packets sent */
+
+ t_float x_f; /* float needed for signal input */
+
+#ifdef UNIX
+ lame_global_flags* lgfp;
+#endif
+} t_mp3streamout;
+
+
+ /* encode PCM data to mp3 stream */
+static void mp3streamout_encode(t_mp3streamout *x)
+{
+ unsigned short i, wp;
+ int err = -1;
+ int n = x->x_lamechunk;
+
+#ifdef UNIX
+ if(x->x_lamechunk < (int)sizeof(x->x_mp3inbuf))
+#else
+ if(x->x_lamechunk < sizeof(x->x_mp3inbuf))
+#endif
+ {
+ error("not enough memory!");
+ return;
+ }
+
+ /* on start/reconnect set outpoint that it not interferes with inpoint */
+ if(x->x_start == -1)
+ {
+ post("mp3streamout~: initializing buffers");
+ /* we try to keep 2.5 times the data the encoder needs in the buffer */
+ if(x->x_inp > (2 * x->x_lamechunk))
+ {
+ x->x_outp = (short) x->x_inp - (2.5 * x->x_lamechunk);
+ }
+ else if(x->x_inp < (2 * x->x_lamechunk))
+ {
+ x->x_outp = (short) MY_MP3_MALLOC_IN_SIZE - (2.5 * x->x_lamechunk);
+ }
+ x->x_start = 1;
+ }
+ if((unsigned short)(x->x_outp - x->x_inp) < x->x_lamechunk)error("mp3streamout~: buffers overlap!");
+
+ i = MY_MP3_MALLOC_IN_SIZE - x->x_outp;
+
+ /* read from buffer */
+ if(x->x_lamechunk <= i)
+ {
+ /* enough data until end of buffer */
+ for(n = 0; n < x->x_lamechunk; n++) /* fill encode buffer */
+ {
+ x->x_mp3inbuf[n] = x->x_buffer[n + x->x_outp];
+ }
+ x->x_outp += x->x_lamechunk;
+ }
+ else /* split data */
+ {
+ for(wp = 0; wp < i; wp++) /* data at end of buffer */
+ {
+ x->x_mp3inbuf[wp] = x->x_buffer[wp + x->x_outp];
+ }
+
+ for(wp = i; wp < x->x_lamechunk; wp++) /* write rest of data at beginning of buffer */
+ {
+ x->x_mp3inbuf[wp] = x->x_buffer[wp - i];
+ }
+ x->x_outp = x->x_lamechunk - i;
+ }
+
+ /* encode mp3 data */
+#ifndef UNIX
+ err = encodeChunk(x->x_lame, x->x_lamechunk, x->x_mp3inbuf, x->x_mp3outbuf, &x->x_mp3size);
+#else
+ x->x_mp3size = lame_encode_buffer_interleaved(x->lgfp, x->x_mp3inbuf,
+ x->x_lamechunk/lame_get_num_channels(x->lgfp),
+ x->x_mp3outbuf, MY_MP3_MALLOC_OUT_SIZE);
+ x->x_mp3size+=lame_encode_flush( x->lgfp, x->x_mp3outbuf+x->x_mp3size, MY_MP3_MALLOC_OUT_SIZE-x->x_mp3size );
+ // post( "mp3streamout~ : encoding returned %d frames", x->x_mp3size );
+#endif
+
+ /* check result */
+#ifndef UNIX
+ if(err != BE_ERR_SUCCESSFUL)
+ {
+ closeStream(x->x_lame);
+ error("mp3streamout~: lameEncodeChunk() failed (%lu)", err);
+#else
+ if(x->x_mp3size<0)
+ {
+ lame_close( x->lgfp );
+ error("mp3streamout~: lame_encode_buffer_interleaved failed (%d)", x->x_mp3size);
+#endif
+ x->x_lame = -1;
+ }
+}
+
+ /* stream mp3 to the peer */
+static void mp3streamout_stream(t_mp3streamout *x)
+{
+ int count = -1, i;
+ struct frame hframe;
+
+ /* header needs to be included in each packet */
+
+ for( i=0; i<x->x_mp3size; i++ )
+ {
+ // track valid data
+ if ( head_check( *((unsigned long*)x->x_mp3outbuf+i), 3 ) )
+ {
+ // post( "valid header emitted @ %d (byte %d)", i, i*sizeof(unsigned long) );
+ }
+ }
+
+ count = send(x->x_fd, x->x_mp3outbuf, x->x_mp3size, MSG_NOSIGNAL);
+ if(count < 0)
+ {
+ error("mp3streamout~: could not send encoded data to the peer (%d)", count);
+#ifndef UNIX
+ closeStream(x->x_lame);
+#else
+ lame_close( x->lgfp );
+#endif
+ x->x_lame = -1;
+#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++;
+ if ( x->x_outpackets%100 == 0 )
+ {
+ // post( "mp3streamout~ : emitted %d bytes (packets = %d)", count, x->x_outpackets );
+ }
+ }
+ if((count > 0)&&(count != x->x_mp3size))
+ {
+ error("mp3streamout~: %d bytes skipped", x->x_mp3size - count);
+ }
+}
+
+
+ /* buffer data as channel interleaved PCM */
+static t_int *mp3streamout_perform(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]); /* left audio inlet */
+ t_float *in2 = (t_float *)(w[2]); /* right audio inlet */
+ t_mp3streamout *x = (t_mp3streamout *)(w[3]);
+ int n = (int)(w[4]); /* number of samples */
+ unsigned short i,wp;
+ float in;
+
+ /* copy the data into the buffer */
+ i = MY_MP3_MALLOC_IN_SIZE - x->x_inp; /* space left at the end of buffer */
+
+ n *= 2; /* two channels go into one buffer */
+
+ if( n <= i )
+ {
+ /* the place between inp and MY_MP3_MALLOC_IN_SIZE */
+ /* is big enough to hold the data */
+
+ for(wp = 0; wp < n; wp++)
+ {
+ if(wp%2)
+ {
+ in = *(in2++); /* right channel / inlet */
+ }
+ else
+ {
+ in = *(in1++); /* left channel / inlet */
+ }
+ if (in > 1.0) { in = 1.0; }
+ if (in < -1.0) { in = -1.0; }
+ x->x_buffer[wp + x->x_inp] = (short) (32767.0 * in);
+ }
+ x->x_inp += n; /* n more samples written to buffer */
+ }
+ else
+ {
+ /* the place between inp and MY_MP3_MALLOC_IN_SIZE is not */
+ /* big enough to hold the data */
+ /* writing will take place in two turns, one from */
+ /* x->x_inp -> MY_MP3_MALLOC_IN_SIZE, then from 0 on */
+
+ for(wp = 0; wp < i; wp++) /* fill up to end of buffer */
+ {
+ if(wp%2)
+ {
+ in = *(in2++);
+ }
+ else
+ {
+ in = *(in1++);
+ }
+ if (in > 1.0) { in = 1.0; }
+ if (in < -1.0) { in = -1.0; }
+ x->x_buffer[wp + x->x_inp] = (short) (32767.0 * in);
+ }
+ for(wp = i; wp < n; wp++) /* write rest at start of buffer */
+ {
+ if(wp%2)
+ {
+ in = *(in2++);
+ }
+ else
+ {
+ in = *(in1++);
+ }
+ if (in > 1.0) { in = 1.0; }
+ if (in < -1.0) { in = -1.0; }
+ x->x_buffer[wp - i] = (short) (32767.0 * in);
+ }
+ x->x_inp = n - i; /* new writeposition in buffer */
+ }
+
+ if((x->x_fd >= 0)&&(x->x_lame >= 0))
+ {
+ /* count buffered samples when things are running */
+ x->x_bytesbuffered += n;
+
+ /* encode and send to the peer */
+ if(x->x_bytesbuffered > x->x_lamechunk)
+ {
+ mp3streamout_encode(x); /* encode to mp3 */
+ mp3streamout_stream(x); /* stream mp3 to the peer */
+ x->x_bytesbuffered -= x->x_lamechunk;
+ }
+ }
+ else
+ {
+ x->x_start = -1;
+ }
+ return (w+5);
+}
+
+static void mp3streamout_dsp(t_mp3streamout *x, t_signal **sp)
+{
+ dsp_add(mp3streamout_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n);
+}
+
+ /* initialize the lame library */
+static void mp3streamout_tilde_lame_init(t_mp3streamout *x)
+{
+#ifndef UNIX
+ /* encoder related stuff (calculating buffer size) */
+ BE_VERSION lameVersion = {0,}; /* version number of LAME */
+ BE_CONFIG lameConfig = {0,}; /* config structure of LAME */
+ unsigned int ret;
+#else
+ int ret;
+ x->lgfp = lame_init(); /* set default parameters for now */
+#endif
+
+#ifndef UNIX
+ /* load lame_enc.dll library */
+
+ dll=LoadLibrary("lame_enc.dll");
+ if(dll==NULL)
+ {
+ error("mp3streamout~: error loading lame_enc.dll");
+ closesocket(x->x_fd);
+ x->x_fd = -1;
+ outlet_float(x->x_obj.ob_outlet, 0);
+ post("mp3streamout~: connection closed");
+ return;
+ }
+
+ /* get Interface functions */
+ initStream = (BEINITSTREAM) GetProcAddress(dll, TEXT_BEINITSTREAM);
+ encodeChunk = (BEENCODECHUNK) GetProcAddress(dll, TEXT_BEENCODECHUNK);
+ deinitStream = (BEDEINITSTREAM) GetProcAddress(dll, TEXT_BEDEINITSTREAM);
+ closeStream = (BECLOSESTREAM) GetProcAddress(dll, TEXT_BECLOSESTREAM);
+ dllVersion = (BEVERSION) GetProcAddress(dll, TEXT_BEVERSION);
+ writeVBRHeader = (BEWRITEVBRHEADER) GetProcAddress(dll,TEXT_BEWRITEVBRHEADER);
+
+ /* check if all interfaces are present */
+ if(!initStream || !encodeChunk || !deinitStream || !closeStream || !dllVersion || !writeVBRHeader)
+ {
+
+ error("mp3streamout~: unable to get LAME interfaces");
+ closesocket(x->x_fd);
+ x->x_fd = -1;
+ outlet_float(x->x_obj.ob_outlet, 0);
+ post("mp3streamout~: connection closed");
+ return;
+ }
+
+ /* get LAME version number */
+ dllVersion(&lameVersion);
+
+ post( "mp3streamout~: lame_enc.dll version %u.%02u (%u/%u/%u)\n"
+ " lame_enc engine %u.%02u",
+ lameVersion.byDLLMajorVersion, lameVersion.byDLLMinorVersion,
+ lameVersion.byDay, lameVersion.byMonth, lameVersion.wYear,
+ lameVersion.byMajorVersion, lameVersion.byMinorVersion);
+
+ memset(&lameConfig,0,sizeof(lameConfig)); /* clear all fields */
+#else
+ {
+ const char *lameVersion = get_lame_version();
+ post( "mp3streamout~ : using lame version : %s", lameVersion );
+ }
+#endif
+
+#ifndef UNIX
+
+ /* use the LAME config structure */
+ lameConfig.dwConfig = BE_CONFIG_LAME;
+
+ /* set the mpeg format flags */
+ lameConfig.format.LHV1.dwStructVersion = 1;
+ lameConfig.format.LHV1.dwStructSize = sizeof(lameConfig);
+ lameConfig.format.LHV1.dwSampleRate = (int)sys_getsr(); /* input frequency - pd's sample rate */
+ lameConfig.format.LHV1.dwReSampleRate = x->x_samplerate; /* output s/r - resample if necessary */
+ lameConfig.format.LHV1.nMode = x->x_mp3mode; /* output mode */
+ lameConfig.format.LHV1.dwBitrate = x->x_bitrate; /* mp3 bitrate */
+ lameConfig.format.LHV1.nPreset = x->x_mp3quality; /* mp3 encoding quality */
+ lameConfig.format.LHV1.dwMpegVersion = MPEG1; /* use MPEG1 */
+ lameConfig.format.LHV1.dwPsyModel = 0; /* USE DEFAULT PSYCHOACOUSTIC MODEL */
+ lameConfig.format.LHV1.dwEmphasis = 0; /* NO EMPHASIS TURNED ON */
+ lameConfig.format.LHV1.bOriginal = TRUE; /* SET ORIGINAL FLAG */
+ lameConfig.format.LHV1.bCopyright = TRUE; /* SET COPYRIGHT FLAG */
+ lameConfig.format.LHV1.bNoRes = TRUE; /* no bit resorvoir */
+
+ /* init the MP3 stream */
+ ret = initStream(&lameConfig, &x->x_lamechunk, &x->x_mp3size, &x->x_lame);
+
+ /* check result */
+ if(ret != BE_ERR_SUCCESSFUL)
+ {
+ post("mp3streamout~: error opening encoding stream (%lu)", ret);
+ return;
+ }
+
+#else
+ /* setting lame parameters */
+ lame_set_num_channels( x->lgfp, 2);
+ lame_set_in_samplerate( x->lgfp, sys_getsr() );
+ lame_set_out_samplerate( x->lgfp, x->x_samplerate );
+ lame_set_brate( x->lgfp, x->x_bitrate );
+ lame_set_mode( x->lgfp, x->x_mp3mode );
+ lame_set_quality( x->lgfp, x->x_mp3quality );
+ lame_set_emphasis( x->lgfp, 1 );
+ lame_set_original( x->lgfp, 1 );
+ lame_set_copyright( x->lgfp, 1 ); /* viva free music societies !!! */
+ lame_set_disable_reservoir( x->lgfp, 0 );
+ lame_set_padding_type( x->lgfp, PAD_NO );
+ ret = lame_init_params( x->lgfp );
+ if ( ret<0 ) {
+ post( "mp3streamout~ : error : lame params initialization returned : %d", ret );
+ } else {
+ x->x_lame=1;
+ /* magic formula copied from windows dll for MPEG-I */
+ x->x_lamechunk = 2*1152;
+
+ post( "mp3streamout~ : lame initialization done. (%d)", x->x_lame );
+ }
+ lame_init_bitstream( x->lgfp );
+#endif
+
+
+}
+
+ /* connect to the peer */
+static void mp3streamout_connect(t_mp3streamout *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;
+ char resp[STRBUF_SIZE];
+ unsigned int len;
+ int sockfd;
+
+#ifndef UNIX
+ unsigned int ret;
+#else
+ int ret;
+#endif
+
+ if (x->x_fd >= 0)
+ {
+ error("mp3streamout~: already connected");
+ return;
+ }
+
+ sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sockfd < 0)
+ {
+ error("mp3streamout~: 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("mp3streamout~: 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("mp3streamout~: connecting to port %d", portno);
+ if (connect(sockfd, (struct sockaddr *) &csocket, sizeof (csocket)) < 0)
+ {
+ error("mp3streamout~: 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( "mp3streamout~ : connected to peer" );
+
+ mp3streamout_tilde_lame_init(x);
+
+}
+
+ /* close connection to the peer */
+static void mp3streamout_disconnect(t_mp3streamout *x)
+{
+
+ int err = -1;
+ if(x->x_lame >= 0)
+ {
+#ifndef UNIX
+ /* deinit the stream */
+ err = deinitStream(x->x_lame, x->x_mp3outbuf, &x->x_mp3size);
+
+ /* check result */
+ if(err != BE_ERR_SUCCESSFUL)
+ {
+ error("exiting mp3 stream failed (%lu)", err);
+ }
+ closeStream(x->x_lame); /* close mp3 encoder stream */
+#else
+ /* ignore remaining bytes */
+ if ( x->x_mp3size = lame_encode_flush( x->lgfp, x->x_mp3outbuf, 0) < 0 ) {
+ post( "mp3streamout~ : warning : remaining encoded bytes" );
+ }
+ lame_close( x->lgfp );
+#endif
+ x->x_lame = -1;
+ post("mp3streamout~: encoder stream closed");
+ }
+
+ 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("mp3streamout~: connection closed");
+ }
+}
+
+ /* settings for mp3 encoding */
+static void mp3streamout_mpeg(t_mp3streamout *x, t_floatarg fbitrate,
+ t_floatarg fmode, t_floatarg fquality)
+{
+ if ( fbitrate != 32 && fbitrate != 40 && fbitrate != 48 && fbitrate != 56 &&
+ fbitrate != 64 && fbitrate != 80 && fbitrate != 96 && fbitrate != 112 &&
+ fbitrate != 128 && fbitrate != 160 && fbitrate != 192 && fbitrate != 224 &&
+ fbitrate != 256 && fbitrate != 320 ) {
+ post( "mp3streamout~ : wrong bitrate." );
+ return;
+ }
+ if ( fmode <0 || fmode>2 ) {
+ post( "mp3streamout~ : wrong mp3 mode." );
+ if ( fmode == 3 )
+ {
+ post( "mp3streamout~ : mone is not supported by streamout~ for now." );
+ }
+ return;
+ }
+ /* there is a bug in lame 3.92 and quality below 5 will not work */
+ /* WAIT FOR A FIX */
+ if ( fquality <5 || fquality>9 ) {
+ post( "mp3streamout~ : wrong quality." );
+ return;
+ }
+ x->x_bitrate = fbitrate;
+ x->x_mp3mode = fmode;
+ x->x_mp3quality = (int)fquality;
+ post("mp3streamout~: setting mp3 stream to %dHz, %dkbit/s, mode %d, quality %d",
+ x->x_samplerate, x->x_bitrate, x->x_mp3mode, x->x_mp3quality);
+ mp3streamout_tilde_lame_init(x);
+}
+
+ /* print settings */
+static void mp3streamout_print(t_mp3streamout *x)
+{
+ const char * buf = 0;
+
+ post(mp3streamout_version);
+ post(" LAME mp3 settings:\n"
+ " output sample rate: %d Hz\n"
+ " bitrate: %d kbit/s", x->x_samplerate, x->x_bitrate);
+ switch(x->x_mp3mode)
+ {
+ case 0 :
+ buf = "stereo";
+ break;
+ case 1 :
+ buf = "joint stereo";
+ break;
+ case 2 :
+ buf = "dual channel";
+ break;
+ case 3 :
+ buf = "mono";
+ break;
+ }
+ post(" mode: %s\n"
+ " quality: %d", buf, x->x_mp3quality);
+#ifndef UNIX
+ if(x->x_lamechunk!=0)post(" calculated mp3 chunk size: %d", x->x_lamechunk);
+#else
+ post(" mp3 chunk size: %d", x->x_lamechunk);
+#endif
+ if(x->x_samplerate!=sys_getsr())
+ {
+ post(" resampling from %d to %d Hz!", (int)sys_getsr(), x->x_samplerate);
+ }
+}
+
+ /* clean up */
+static void mp3streamout_free(t_mp3streamout *x)
+{
+
+ if(x->x_lame >= 0)
+#ifndef UNIX
+ closeStream(x->x_lame);
+#else
+ lame_close( x->lgfp );
+#endif
+ if(x->x_fd >= 0)
+#ifndef UNIX
+ closesocket(x->x_fd);
+#else
+ close(x->x_fd);
+#endif
+ freebytes(x->x_mp3inbuf, MY_MP3_MALLOC_IN_SIZE*sizeof(short));
+ freebytes(x->x_mp3outbuf, MY_MP3_MALLOC_OUT_SIZE);
+ freebytes(x->x_buffer, MY_MP3_MALLOC_IN_SIZE*sizeof(short));
+}
+
+static void *mp3streamout_new(void)
+{
+ t_mp3streamout *x = (t_mp3streamout *)pd_new(mp3streamout_class);
+ inlet_new (&x->x_obj, &x->x_obj.ob_pd, gensym ("signal"), gensym ("signal"));
+ outlet_new( &x->x_obj, &s_float );
+ x->lgfp = NULL;
+ x->x_fd = -1;
+ x->x_outpackets = 0;
+ x->x_lame = -1;
+ x->x_samplerate = sys_getsr();
+ x->x_bitrate = 128;
+ x->x_mp3mode = 1;
+ x->x_mp3quality = 5;
+ x->x_mp3inbuf = getbytes(MY_MP3_MALLOC_IN_SIZE*sizeof(short)); /* buffer for encoder input */
+ x->x_mp3outbuf = getbytes(MY_MP3_MALLOC_OUT_SIZE); /* our mp3 stream */
+ x->x_buffer = getbytes(MY_MP3_MALLOC_IN_SIZE*sizeof(short)); /* what we get from pd, converted to PCM */
+ if ((!x->x_buffer)||(!x->x_mp3inbuf)||(!x->x_mp3outbuf)) /* check buffers... */
+ {
+ error("out of memory!");
+ }
+ x->x_bytesbuffered = 0;
+ x->x_inp = 0;
+ x->x_outp = 0;
+ x->x_start = -1;
+ return(x);
+}
+
+void mp3streamout_tilde_setup(void)
+{
+ post(mp3streamout_version);
+ mp3streamout_class = class_new(gensym("mp3streamout~"), (t_newmethod)mp3streamout_new, (t_method)mp3streamout_free,
+ sizeof(t_mp3streamout), 0, 0);
+ CLASS_MAINSIGNALIN(mp3streamout_class, t_mp3streamout, x_f );
+ class_sethelpsymbol(mp3streamout_class, gensym("help-mp3live~.pd"));
+ class_addmethod(mp3streamout_class, (t_method)mp3streamout_dsp, gensym("dsp"), 0);
+ class_addmethod(mp3streamout_class, (t_method)mp3streamout_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0);
+ class_addmethod(mp3streamout_class, (t_method)mp3streamout_disconnect, gensym("disconnect"), 0);
+ class_addmethod(mp3streamout_class, (t_method)mp3streamout_mpeg, gensym("mpeg"), A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(mp3streamout_class, (t_method)mp3streamout_print, gensym("print"), 0);
+}
+
diff --git a/mp3live~/mpg123.h b/mp3live~/mpg123.h
new file mode 100644
index 0000000..1c530d3
--- /dev/null
+++ b/mp3live~/mpg123.h
@@ -0,0 +1,136 @@
+#ifndef MPG123_H_INCLUDED
+#define MPG123_H_INCLUDED
+
+#include <stdio.h>
+
+#define STDC_HEADERS
+
+#ifdef STDC_HEADERS
+# include <string.h>
+#else
+# ifndef HAVE_STRCHR
+# define strchr index
+# define strrchr rindex
+# endif
+char *strchr (), *strrchr ();
+# ifndef HAVE_MEMCPY
+# define memcpy(d, s, n) bcopy ((s), (d), (n))
+# define memmove(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+#include <signal.h>
+
+
+#if defined(__riscos__) && defined(FPA10)
+#include "ymath.h"
+#else
+#include <math.h>
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+
+#ifdef REAL_IS_FLOAT
+# define real float
+#elif defined(REAL_IS_LONG_DOUBLE)
+# define real long double
+#else
+# define real double
+#endif
+
+#define FALSE 0
+#define TRUE 1
+
+#define SBLIMIT 32
+#define SSLIMIT 18
+
+#define MPG_MD_STEREO 0
+#define MPG_MD_JOINT_STEREO 1
+#define MPG_MD_DUAL_CHANNEL 2
+#define MPG_MD_MONO 3
+
+#define MAXFRAMESIZE 1792
+
+/* AF: ADDED FOR LAYER1/LAYER2 */
+#define SCALE_BLOCK 12
+
+
+/* Pre Shift fo 16 to 8 bit converter table */
+#define AUSHIFT (3)
+
+struct frame {
+ int stereo;
+ int jsbound;
+ int single;
+ int lsf;
+ int mpeg25;
+ int header_change;
+ int lay;
+ int error_protection;
+ int bitrate_index;
+ int sampling_frequency;
+ int padding;
+ int extension;
+ int mode;
+ int mode_ext;
+ int copyright;
+ int original;
+ int emphasis;
+ int framesize; /* computed framesize */
+
+ /* AF: ADDED FOR LAYER1/LAYER2 */
+#if defined(USE_LAYER_2) || defined(USE_LAYER_1)
+ int II_sblimit;
+ struct al_table2 *alloc;
+ int down_sample_sblimit;
+ int down_sample;
+
+#endif
+
+};
+
+struct gr_info_s {
+ int scfsi;
+ unsigned part2_3_length;
+ unsigned big_values;
+ unsigned scalefac_compress;
+ unsigned block_type;
+ unsigned mixed_block_flag;
+ unsigned table_select[3];
+ unsigned subblock_gain[3];
+ unsigned maxband[3];
+ unsigned maxbandl;
+ unsigned maxb;
+ unsigned region1start;
+ unsigned region2start;
+ unsigned preflag;
+ unsigned scalefac_scale;
+ unsigned count1table_select;
+ real *full_gain[3];
+ real *pow2gain;
+};
+
+struct III_sideinfo
+{
+ unsigned main_data_begin;
+ unsigned private_bits;
+ struct {
+ struct gr_info_s gr[2];
+ } ch[2];
+};
+
+
+#endif
diff --git a/mp3live~/mpglib.h b/mp3live~/mpglib.h
new file mode 100644
index 0000000..1f4ef9a
--- /dev/null
+++ b/mp3live~/mpglib.h
@@ -0,0 +1,65 @@
+// #include "lame-analysis.h"
+
+#define NOANALYSIS
+
+#ifndef NOANALYSIS
+extern plotting_data *mpg123_pinfo;
+#endif
+
+struct buf {
+ unsigned char *pnt;
+ long size;
+ long pos;
+ struct buf *next;
+ struct buf *prev;
+};
+
+struct framebuf {
+ struct buf *buf;
+ long pos;
+ struct frame *next;
+ struct frame *prev;
+};
+
+typedef struct mpstr_tag {
+ struct buf *head,*tail;
+ int vbr_header; /* 1 if valid Xing vbr header detected */
+ int num_frames; /* set if vbr header present */
+ int enc_delay; /* set if vbr header present */
+ int enc_padding; /* set if vbr header present */
+ int header_parsed;
+ int side_parsed;
+ int data_parsed;
+ int free_format; /* 1 = free format frame */
+ int old_free_format; /* 1 = last frame was free format */
+ int bsize;
+ int framesize;
+ int ssize;
+ int dsize;
+ int fsizeold;
+ int fsizeold_nopadding;
+ struct frame fr;
+ unsigned char bsspace[2][MAXFRAMESIZE+512]; /* MAXFRAMESIZE */
+ real hybrid_block[2][2][SBLIMIT*SSLIMIT];
+ int hybrid_blc[2];
+ unsigned long header;
+ int bsnum;
+ real synth_buffs[2][2][0x110];
+ int synth_bo;
+ int sync_bitstream;
+
+} MPSTR, *PMPSTR;
+
+
+#if ( defined(_MSC_VER) || defined(__BORLANDC__) )
+ typedef int BOOL; /* windef.h contains the same definition */
+#else
+ #define BOOL int
+#endif
+
+#define MP3_ERR -1
+#define MP3_OK 0
+#define MP3_NEED_MORE 1
+
+
+
diff --git a/mp3live~/test-streaming-mp3.pd b/mp3live~/test-streaming-mp3.pd
new file mode 100644
index 0000000..e9e6b2e
--- /dev/null
+++ b/mp3live~/test-streaming-mp3.pd
@@ -0,0 +1,96 @@
+#N canvas 15 9 986 678 10;
+#X msg 63 58 bang;
+#X obj 63 78 openpanel;
+#X obj 63 100 t s b;
+#X obj 63 137 pack s s;
+#X obj 99 100 float \$0;
+#X text 51 39 Step 1 : Load a sound file;
+#X obj 117 137 makefilename %d-sample;
+#X msg 443 280 \; pd dsp 1;
+#X msg 509 280 \; pd dsp 0;
+#X obj 454 254 loadbang;
+#X obj 62 217 mp3streamout~;
+#X floatatom 63 240 5 0 0;
+#X obj 62 181 readsf~;
+#X msg 62 158 open \$1 \$2;
+#X msg 33 148 1;
+#X msg 265 185 disconnect;
+#X obj 63 117 route float;
+#X msg 569 47 bang;
+#X obj 569 67 openpanel;
+#X obj 569 89 t s b;
+#X obj 569 126 pack s s;
+#X obj 605 89 float \$0;
+#X text 557 28 Step 1 : Load a sound file;
+#X obj 623 126 makefilename %d-sample;
+#X obj 568 206 mp3streamout~;
+#X floatatom 569 229 5 0 0;
+#X obj 568 170 readsf~;
+#X msg 568 147 open \$1 \$2;
+#X msg 539 137 1;
+#X msg 784 177 disconnect;
+#X obj 569 106 route float;
+#X obj 364 462 dac~;
+#X obj 361 438 *~;
+#X floatatom 416 465 5 0 0;
+#X symbolatom 459 437 15 0 0;
+#X obj 407 440 / 100;
+#X obj 122 470 dac~;
+#X obj 119 446 *~;
+#X floatatom 174 473 5 0 0;
+#X symbolatom 217 445 10 0 0;
+#X obj 165 448 / 100;
+#X obj 96 419 mp3streamin~ 5001 1;
+#X obj 345 410 mp3streamin~ 5000 1;
+#X msg 777 149 connect yves 5001;
+#X msg 246 228 mpeg 32 2 5;
+#X msg 246 228 mpeg 32 2 5;
+#X msg 246 264 mpeg 224 2 5;
+#X msg 258 157 connect localhost 5000;
+#X msg 263 125 connect dregs 5000;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 2 1 4 0;
+#X connect 3 0 13 0;
+#X connect 4 0 16 0;
+#X connect 6 0 3 1;
+#X connect 9 0 7 0;
+#X connect 10 0 11 0;
+#X connect 12 0 10 0;
+#X connect 12 0 10 1;
+#X connect 13 0 12 0;
+#X connect 14 0 12 0;
+#X connect 15 0 10 0;
+#X connect 16 0 6 0;
+#X connect 17 0 18 0;
+#X connect 18 0 19 0;
+#X connect 19 0 20 0;
+#X connect 19 1 21 0;
+#X connect 20 0 27 0;
+#X connect 21 0 30 0;
+#X connect 23 0 20 1;
+#X connect 24 0 25 0;
+#X connect 26 0 24 0;
+#X connect 26 0 24 1;
+#X connect 27 0 26 0;
+#X connect 28 0 26 0;
+#X connect 29 0 24 0;
+#X connect 30 0 23 0;
+#X connect 32 0 31 0;
+#X connect 32 0 31 1;
+#X connect 33 0 35 0;
+#X connect 35 0 32 1;
+#X connect 37 0 36 0;
+#X connect 37 0 36 1;
+#X connect 38 0 40 0;
+#X connect 40 0 37 1;
+#X connect 41 0 37 0;
+#X connect 41 2 39 0;
+#X connect 42 0 32 0;
+#X connect 42 2 34 0;
+#X connect 43 0 24 0;
+#X connect 44 0 10 0;
+#X connect 46 0 10 0;
+#X connect 47 0 10 0;
+#X connect 48 0 10 0;