aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--countund/INSTALL7
-rw-r--r--countund/Makefile82
-rw-r--r--countund/countund.c117
-rw-r--r--countund/help-countund.pd17
-rw-r--r--disto~/CHANGES.LOG2
-rw-r--r--disto~/COPYING280
-rw-r--r--disto~/INSTALL15
-rw-r--r--disto~/Makefile82
-rw-r--r--disto~/README24
-rw-r--r--disto~/distort3.txt54
-rw-r--r--disto~/disto~.c491
-rw-r--r--disto~/help-disto~.pd73
-rw-r--r--disto~/rs-disto~.pd349
-rw-r--r--formant~/INSTALL9
-rw-r--r--formant~/Makefile82
-rw-r--r--formant~/README21
-rw-r--r--formant~/formant~.c252
-rw-r--r--formant~/help-formant~.pd56
-rw-r--r--mp3amp~/CHANGES.LOG15
-rw-r--r--mp3amp~/INSTALL19
-rw-r--r--mp3amp~/Makefile82
-rw-r--r--mp3amp~/README45
-rw-r--r--mp3amp~/help-graphic-mp3amp~.pd52
-rw-r--r--mp3amp~/help-mp3amp~.pd53
-rw-r--r--mp3amp~/interface.h32
-rw-r--r--mp3amp~/mp3amp~.c1255
-rw-r--r--mp3amp~/mpg123.h136
-rw-r--r--mp3amp~/mpglib.h65
-rw-r--r--mp3amp~/punjabi-2.pls3
-rw-r--r--mp3amp~/punjabi-3.pls3
-rw-r--r--mp3amp~/punjabi-4.pls3
-rw-r--r--mp3amp~/punjabi.pls3
-rw-r--r--mp3cast~/CHANGES.LOG6
-rw-r--r--mp3cast~/INSTALL15
-rw-r--r--mp3cast~/Makefile82
-rw-r--r--mp3cast~/Makefile.linux82
-rw-r--r--mp3cast~/README108
-rw-r--r--mp3cast~/help-mp3cast~.pd50
-rw-r--r--mp3cast~/interface.h32
-rw-r--r--mp3cast~/mp3cast~.c916
-rw-r--r--mp3cast~/mpg123.h136
-rw-r--r--mp3cast~/mpglib.h65
-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
-rw-r--r--mp3write~/CHANGES.LOG8
-rw-r--r--mp3write~/INSTALL15
-rw-r--r--mp3write~/Makefile82
-rw-r--r--mp3write~/README94
-rw-r--r--mp3write~/help-mp3write~.pd43
-rw-r--r--mp3write~/interface.h32
-rw-r--r--mp3write~/mp3write~.c721
-rw-r--r--mp3write~/mpg123.h136
-rw-r--r--mp3write~/mpglib.h65
-rw-r--r--randomblock~/INSTALL7
-rw-r--r--randomblock~/Makefile82
-rw-r--r--randomblock~/help-randomblock~.pd15
-rw-r--r--randomblock~/mrandtab.pd6
-rw-r--r--randomblock~/randomblock~.c117
-rw-r--r--randomblock~/randtab.pd43
-rw-r--r--samplebox~/CHANGES.LOG6
-rw-r--r--samplebox~/INSTALL9
-rw-r--r--samplebox~/Makefile97
-rw-r--r--samplebox~/README19
-rw-r--r--samplebox~/help-samplebox~.pd145
-rw-r--r--samplebox~/samplebox~.c529
-rw-r--r--sonogram~/CHANGES.LOG23
-rw-r--r--sonogram~/INSTALL15
-rw-r--r--sonogram~/Makefile82
-rw-r--r--sonogram~/README25
-rw-r--r--sonogram~/help-sonogram~.pd10
-rw-r--r--sonogram~/help-sonograph~.pd10
-rw-r--r--sonogram~/rs-sonogram~.pd307
-rw-r--r--sonogram~/rs-sonograph~.pd217
-rw-r--r--sonogram~/sonogram~-joge.c2024
-rw-r--r--sonogram~/sonogram~-yves.c1995
-rw-r--r--sonogram~/sonogram~.c2061
-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
-rw-r--r--spigot~/CHANGES.LOG2
-rw-r--r--spigot~/INSTALL15
-rw-r--r--spigot~/Makefile97
-rw-r--r--spigot~/README21
-rw-r--r--spigot~/help-spigot~.pd14
-rw-r--r--spigot~/spigot~.c75
-rw-r--r--stkdrone~/INSTALL13
-rw-r--r--stkdrone~/Makefile33
-rw-r--r--stkdrone~/README20
-rw-r--r--stkdrone~/drone-freqs46
-rw-r--r--stkdrone~/drone.cc77
-rw-r--r--stkdrone~/drone.h40
-rw-r--r--stkdrone~/help-stkdrone~.pd75
-rw-r--r--stkdrone~/stkdrone~.cc119
-rw-r--r--stksitar~/INSTALL13
-rw-r--r--stksitar~/Makefile37
-rw-r--r--stksitar~/README22
-rw-r--r--stksitar~/help-stksitar~.pd73
-rw-r--r--stksitar~/mstksitar~.cc39
-rw-r--r--stksitar~/sitar-freqs166
-rw-r--r--stksitar~/sitar.cc105
-rw-r--r--stksitar~/sitar.h44
-rw-r--r--stksitar~/stksitar~.cc119
-rw-r--r--vocoder~/CHANGES.LOG2
-rw-r--r--vocoder~/INSTALL15
-rw-r--r--vocoder~/Makefile86
-rw-r--r--vocoder~/README22
-rw-r--r--vocoder~/filters.c49
-rw-r--r--vocoder~/filters.h27
-rw-r--r--vocoder~/filters.obin0 -> 1163 bytes
-rw-r--r--vocoder~/help-vocoder~.pd55
-rw-r--r--vocoder~/lpc.c252
-rw-r--r--vocoder~/lpc.h33
-rw-r--r--vocoder~/lpc.obin0 -> 5500 bytes
-rw-r--r--vocoder~/rs-vocoder~.pd13
-rw-r--r--vocoder~/tables.c311
-rw-r--r--vocoder~/tables.h24
-rw-r--r--vocoder~/tables.obin0 -> 6168 bytes
-rw-r--r--vocoder~/vocoder~.c163
-rw-r--r--wahwah~/CHANGES.LOG2
-rw-r--r--wahwah~/COPYING280
-rw-r--r--wahwah~/INSTALL15
-rw-r--r--wahwah~/Makefile82
-rw-r--r--wahwah~/README24
-rw-r--r--wahwah~/help-wahwah~.pd48
-rw-r--r--wahwah~/rs-wahwah~.pd348
-rw-r--r--wahwah~/wahwah~.c409
139 files changed, 21671 insertions, 0 deletions
diff --git a/countund/INSTALL b/countund/INSTALL
new file mode 100644
index 0000000..f2488de
--- /dev/null
+++ b/countund/INSTALL
@@ -0,0 +1,7 @@
+untar in /my/pd/dir/externs
+
+cd /my/pd/dir/extra/countund~
+
+make
+
+you're set !!
diff --git a/countund/Makefile b/countund/Makefile
new file mode 100644
index 0000000..1deb17b
--- /dev/null
+++ b/countund/Makefile
@@ -0,0 +1,82 @@
+NAME=countund
+CSYM=countund
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).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
+
+.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
+
+.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
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -DUNIX -DICECAST -O2 -funroll-loops -fomit-frame-pointer \
+ -Wshadow -Wstrict-prototypes\
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+LINUXINCLUDE = -I../../src
+
+.c.pd_linux:
+ cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ ld -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm -L/usr/local/lib
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o ../$*.pd_linux
+ ln -s $*/$*.pd_linux ..
+
+# ----------------------------------------------------------
+
+clean:
+ rm -f *.o *.pd_* so_locations
+
+install:
+ cp help-* ../../doc/5.reference
diff --git a/countund/countund.c b/countund/countund.c
new file mode 100644
index 0000000..709ffd0
--- /dev/null
+++ b/countund/countund.c
@@ -0,0 +1,117 @@
+/* ------------------------ countund~ -------------------------------------- */
+/* */
+/* Count up to a value and then down to zero */
+/* Written by Yves Degoyon (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. */
+/* */
+/* ---------------------------------------------------------------------------- */
+
+
+
+#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>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "m_pd.h" /* standard pd stuff */
+
+static char *countund_version = "countund~: count up to a value and then down to zero : author : ydegoyon@free.fr";
+
+static t_class *countund_class;
+
+typedef struct _countund
+{
+ t_object x_obj;
+ t_int x_limit;
+ t_int x_value;
+ t_int x_up;
+} t_countund;
+
+ /* clean up */
+static void countund_free(t_countund *x)
+{
+}
+
+static void *countund_new(t_float flimit)
+{
+ t_countund *x = (t_countund *)pd_new(countund_class);
+ outlet_new(&x->x_obj, &s_float);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("limit"));
+ if ( flimit < 0 ) {
+ post( "countund~: wrong creation argument" );
+ return NULL;
+ }
+ x->x_limit = (int) flimit;
+ x->x_value = 0;
+ x->x_up = 1;
+ return(x);
+}
+
+static void *countund_limit(t_countund* x, t_float flimit)
+{
+ if ( flimit < 0 ) {
+ post( "countund~: wrong count limit" );
+ return;
+ } else {
+ x->x_limit=(int)flimit;
+ }
+}
+
+static void *countund_bang(t_countund *x)
+{
+
+ if ( x->x_up ) {
+ x->x_value+=1;
+ if (x->x_value>x->x_limit) {
+ x->x_value=x->x_limit-1;
+ x->x_up=0;
+ }
+ } else {
+ x->x_value-=1;
+ if (x->x_value<0) {
+ x->x_value=1;
+ x->x_up=1;
+ }
+ }
+ outlet_float( x->x_obj.ob_outlet, x->x_value );
+ return;
+}
+
+void countund_setup(void)
+{
+ post(countund_version);
+ countund_class = class_new(gensym("countund"), (t_newmethod)countund_new,
+ (t_method)countund_free,
+ sizeof(t_countund), 0, A_DEFFLOAT, 0);
+ class_addmethod( countund_class, (t_method)countund_bang, &s_bang, 0);
+ class_addmethod( countund_class, (t_method)countund_limit, gensym("limit"), A_FLOAT, 0);
+ class_sethelpsymbol( countund_class, gensym("help-countund.pd"));
+}
diff --git a/countund/help-countund.pd b/countund/help-countund.pd
new file mode 100644
index 0000000..89c1207
--- /dev/null
+++ b/countund/help-countund.pd
@@ -0,0 +1,17 @@
+#N canvas 194 211 575 337 10;
+#X floatatom 192 112 5 0 0;
+#X msg 76 156 bang;
+#X text 161 29 Count up to a limit and then down to zero;
+#X text 160 41 Bugs and comments @ ydegoyon@free.fr;
+#X text 194 88 Set upper limit;
+#X obj 121 143 countund 100;
+#X obj 118 113 metro 100;
+#X msg 115 82 bang;
+#X obj 121 179 print countund;
+#X floatatom 223 179 5 0 0;
+#X connect 0 0 5 1;
+#X connect 1 0 8 0;
+#X connect 5 0 8 0;
+#X connect 5 0 9 0;
+#X connect 6 0 5 0;
+#X connect 7 0 6 0;
diff --git a/disto~/CHANGES.LOG b/disto~/CHANGES.LOG
new file mode 100644
index 0000000..d376c58
--- /dev/null
+++ b/disto~/CHANGES.LOG
@@ -0,0 +1,2 @@
+0.1
+ initial disto~ implementation
diff --git a/disto~/COPYING b/disto~/COPYING
new file mode 100644
index 0000000..2128a66
--- /dev/null
+++ b/disto~/COPYING
@@ -0,0 +1,280 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/disto~/INSTALL b/disto~/INSTALL
new file mode 100644
index 0000000..319f22a
--- /dev/null
+++ b/disto~/INSTALL
@@ -0,0 +1,15 @@
+untar in /my/pd/dir/externs
+
+cd /my/pd/dir/externs/disto~
+
+make clean
+
+make
+
+make install
+
+open help-disto~.pd
+
+Thanx for getting here.
+Yves/
+comments and bugs @ ydegoyon@free.fr
diff --git a/disto~/Makefile b/disto~/Makefile
new file mode 100644
index 0000000..faaaa24
--- /dev/null
+++ b/disto~/Makefile
@@ -0,0 +1,82 @@
+NAME=disto~
+CSYM=disto~
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).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
+
+.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
+
+.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
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -DUNIX -DICECAST -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wno-shadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch #-Werror
+
+LINUXINCLUDE = -I../../src
+
+.c.pd_linux:
+ cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ ld -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o ../$*.pd_linux
+ ln -s $*/$*.pd_linux ..
+
+# ----------------------------------------------------------
+
+install:
+ cp help-*.pd rs-*.pd ../../doc/5.reference
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/disto~/README b/disto~/README
new file mode 100644
index 0000000..68b1d93
--- /dev/null
+++ b/disto~/README
@@ -0,0 +1,24 @@
+Version 0.01
+copyleft 2002 by Yves Degoyon.
+
+tarballs and updates available @ http://ydegoyon.free.fr
+
+disto~ : a kind of effect used in pop music, use it elsewhere
+
+the algorithm was taken from Digital Effects (DISTORT3),
+a guitar effects software for DOS which rocks, written by Alexey Smoli
+( http://st.karelia.ru/~smlalx/ )
+
+To install disto~, follow the steps from INSTALL
+
+This software is published under GPL terms, see COPYING
+for rights restrictions.
+
+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.
+
+*****************************************************************************
+
diff --git a/disto~/distort3.txt b/disto~/distort3.txt
new file mode 100644
index 0000000..e25d857
--- /dev/null
+++ b/disto~/distort3.txt
@@ -0,0 +1,54 @@
+Distortion (algorithm 3)
+þþþþþþþþþþþþþþþþþþþþþþþþ
+
+Similar to Distortion (algorithm 1) but uses Hi & Low Pass Filters from
+Filters. Algorithm is HPF -> Distortion -> LPF. There are parameters for
+Hi & Low Pass Filters : hipassfreq & lowpassfreq is the cutoff frequencies,
+and the hipassQ & lowpassQ in the EE kinda definition for bandwidth. The
+larger the Q, the wider the band, and vice versa. The drive controls the
+amount of overdrive. The volume to balance the effect volume with the
+bypassed level. The dry_mix is the volume of input signal & the wet_mix is
+the volume of distorted signal. The feedback sets feedback of distortion.
+
+Controls:
+
+ drive - distortion drive
+ (0<= <=5)
+ dry_mix - dry (unaffected) signal mix
+ (-5<= <=5)
+ wet_mix - wet (affected) signal mix
+ (-5<= <=5)
+ feedback - feedback
+ (-1<= <=1)
+ volume - distortion volume
+ (0=< <=2)
+ hipassfreq - cutoff frequency for hi pass filter
+ (0< <RATE/2)
+ hipassQ - the EE kinda definition for hi pass filter
+ (0< <=1)
+ lowpassfreq - cutoff frequency for low pass filter
+ (0< <RATE/2)
+ lowpassQ - the EE kinda definition for low pass filter
+ (0< <=1)
+
+Work formula implemented in this distortion algorithm is
+out[i] = in[i] * dry + sign(in[i] - in[i-1]) * exp(abs(in[i]) * drive) * wet.
+See. Its do next wave:
+ Normal Sin Wave Wave distorted by algorithm
+ *
+ * *
+ **** * *
+ * * * * *
+ * * * * * *
+ * * * * * *
+* * * * * *
+* * * * *
+------------*------------- ------------*-------------
+ * * * * *
+ * * * * * *
+ * * * * * *
+ * * * * * *
+ * * * * *
+ **** * *
+ * *
+ *
diff --git a/disto~/disto~.c b/disto~/disto~.c
new file mode 100644
index 0000000..4f3b81f
--- /dev/null
+++ b/disto~/disto~.c
@@ -0,0 +1,491 @@
+/* Copyleft (c) 2002 Yves Degoyon. */
+/* Copyright (c) 2001 Alexei Smoli */
+/* For information on usage and redistribution, and for a DISCLAIMER OF ALL */
+/* WARRANTIES, see the file, "COPYING" in this distribution. */
+/* */
+/* disto~ -- a kind of effect used in pop music */
+/* the algorithm was taken from Digital Effects (DISTORT3), */
+/* a guitar effects software for DOS which rocks, written by Alexey Smoli */
+/* ( http://st.karelia.ru/~smlalx/ ) */
+/* */
+/* 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. */
+/* */
+/* Made while listening to : */
+/* */
+/* Bruce Gilbert -- Ab Ovo */
+/* Poison Girls -- Promenade Immortelle */
+/* */
+/* Special message for the french : */
+/* "Delay all your work...and go vote against national front" */
+/* ---------------------------------------------------------------------------- */
+
+#include "m_pd.h"
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef NT
+#define M_PI 3.14159265358979323846
+#endif
+
+#define BFSZ 4096 /* main delay buffer */
+#define BLOCK_DELAY 10 /* number of blocks to delay */
+#define NA 0.0 /* param not applicable */
+#define NBEXPS 129
+
+static char *disto_version = "disto~: distortion, version 0.1 (ydegoyon@free.fr)";
+
+struct hipass {
+ /* few intermediate variables */
+ double omega;
+ double sn,cs;
+ double alpha;
+ /* filter coefficients */
+ double a0,a1,a2,b0,b1,b2;
+ double k0,k1,k2,k3,k4;
+ /* amplitudes */
+ double x0,x1,x2;
+ double y0,y1,y2;
+} hipass;
+
+struct lowpass {
+ /* few intermediate variables */
+ double omega;
+ double sn,cs;
+ double alpha;
+ /* filter coefficients */
+ double a0,a1,a2,b0,b1,b2;
+ double k0,k1,k2,k3,k4;
+ /* amplitudes */
+ double x0,x1,x2;
+ double y0,y1,y2;
+} lowpass;
+
+typedef struct _disto
+{
+ t_object x_obj;
+ double *x_buf;
+ t_int x_samplerate;
+ double x_drive; /* distortion drive */ /* 0<= <=25 */
+ double x_drymix; /* dry (unaffected) signal mix */ /* -5<= <=5 */
+ double x_wetmix; /* wet (affected) signal mix */ /* -5<= <=5 */
+ double x_feedback; /* feedback */ /* -10<= <=10 */
+ double x_volume; /* distortion volume */ /* 0=< <=5 */
+ double x_hipassfreq; /* cutoff frequency for hi pass filter */ /* 0< <RATE/2 */
+ double x_lowpassfreq; /* cutoff frequency for low pass filter */ /* 0< <RATE/2 */
+ double x_hipassQ; /* the EE kinda definition for hi pass filter */ /* 0.1< <=1 */
+ double x_lowpassQ; /* the EE kinda definition for low pass filter */ /* 0.1< <=1 */
+
+ /* audio processing data ( not setable ) */
+ double data,pred;
+ double outval,outvol;
+ double exps[NBEXPS];
+
+ /* filters data ( not setable ) */
+ struct hipass HPF;
+ struct lowpass LPF;
+
+ t_float x_f;
+} t_disto;
+
+static t_class *disto_class;
+
+static void disto_init_filters (t_disto *x)
+{
+ t_int i;
+
+ for (i=0; i<130; i++)
+ {
+ x->exps[i]=exp((double)i*x->x_drive)*x->x_wetmix;
+ }
+
+ x->HPF.omega = 2.0*M_PI*x->x_hipassfreq/(double)x->x_samplerate;
+ x->HPF.sn = sin(x->HPF.omega);
+ x->HPF.cs = cos(x->HPF.omega);
+ x->HPF.alpha = x->HPF.sn/(2.0*x->x_hipassQ);
+ x->HPF.b0 = (1.0 + x->HPF.cs)/2.0;
+ x->HPF.b1 = -(1.0 + x->HPF.cs) ;
+ x->HPF.b2 = (1.0 + x->HPF.cs)/2.0;
+ x->HPF.a0 = 1.0 + x->HPF.alpha ;
+ x->HPF.a1 = -2.0*x->HPF.cs ;
+ x->HPF.a2 = 1.0 - x->HPF.alpha ;
+ x->HPF.k0 = (x->HPF.b0/x->HPF.a0);
+ x->HPF.k1 = (x->HPF.b1/x->HPF.a0);
+ x->HPF.k2 = (x->HPF.b2/x->HPF.a0);
+ x->HPF.k3 = (x->HPF.a1/x->HPF.a0);
+ x->HPF.k4 = (x->HPF.a2/x->HPF.a0);
+
+ x->LPF.omega = 2.0*M_PI*x->x_lowpassfreq/(double)x->x_samplerate;
+ x->LPF.sn = sin(x->LPF.omega);
+ x->LPF.cs = cos(x->LPF.omega);
+ x->LPF.alpha = x->LPF.sn/(2.0*x->x_lowpassQ);
+ x->LPF.b0 = (1.0 - x->LPF.cs)/2.0;
+ x->LPF.b1 = 1.0 - x->LPF.cs ;
+ x->LPF.b2 = (1.0 - x->LPF.cs)/2.0;
+ x->LPF.a0 = 1.0 + x->LPF.alpha ;
+ x->LPF.a1 = -2.0*x->LPF.cs ;
+ x->LPF.a2 = 1.0 - x->LPF.alpha ;
+ x->LPF.k0 = (x->LPF.b0/x->LPF.a0);
+ x->LPF.k1 = (x->LPF.b1/x->LPF.a0);
+ x->LPF.k2 = (x->LPF.b2/x->LPF.a0);
+ x->LPF.k3 = (x->LPF.a1/x->LPF.a0);
+ x->LPF.k4 = (x->LPF.a2/x->LPF.a0);
+}
+
+static void disto_drive(t_disto *x, t_floatarg fdrive )
+{
+ if ( fdrive > 25.0 )
+ {
+ fdrive = 25.0;
+ }
+ if ( fdrive < 0.0 )
+ {
+ fdrive = 0.0;
+ }
+ x->x_drive = fdrive;
+ // post( "disto~ : drive: %f", x->x_drive );
+ disto_init_filters( x );
+}
+
+static void disto_drymix(t_disto *x, t_floatarg fdrymix )
+{
+ if ( fdrymix > 5.0 )
+ {
+ fdrymix = 5.0;
+ }
+ if ( fdrymix < -5.0 )
+ {
+ fdrymix = -5.0;
+ }
+ x->x_drymix = fdrymix;
+ // post( "disto~ : drymix: %f", x->x_drymix );
+ disto_init_filters( x );
+}
+
+static void disto_wetmix(t_disto *x, t_floatarg fwetmix )
+{
+ if ( fwetmix > 5.0 )
+ {
+ fwetmix = 5.0;
+ }
+ if ( fwetmix < -5.0 )
+ {
+ fwetmix = -5.0;
+ }
+ x->x_wetmix = fwetmix;
+ // post( "disto~ : wetmix: %f", x->x_wetmix );
+ disto_init_filters( x );
+}
+
+static void disto_feedback(t_disto *x, t_floatarg ffeedback )
+{
+ if ( ffeedback > 10.0 )
+ {
+ ffeedback = 10.0;
+ }
+ if ( ffeedback < -10.0 )
+ {
+ ffeedback = -10.0;
+ }
+ x->x_feedback = ffeedback;
+ // post( "disto~ : feedback: %f", x->x_feedback );
+ disto_init_filters( x );
+}
+
+static void disto_volume(t_disto *x, t_floatarg fvolume )
+{
+ if ( fvolume > 5.0 )
+ {
+ fvolume = 5.0;
+ }
+ if ( fvolume < 0.0 )
+ {
+ fvolume = 0.0;
+ }
+ x->x_volume = fvolume;
+ // post( "disto~ : volume: %f", x->x_volume );
+ disto_init_filters( x );
+}
+
+static void disto_hipassfreq(t_disto *x, t_floatarg fhipassfreq )
+{
+ if ( fhipassfreq > x->x_samplerate/2 )
+ {
+ fhipassfreq = x->x_samplerate/2;
+ }
+ if ( fhipassfreq < 0.0 )
+ {
+ fhipassfreq = 0.0;
+ }
+ x->x_hipassfreq = fhipassfreq;
+ // post( "disto~ : hipassfreq: %f", x->x_hipassfreq );
+ disto_init_filters( x );
+}
+
+static void disto_hipassQ(t_disto *x, t_floatarg fhipassQ )
+{
+ if ( fhipassQ > 1.0 )
+ {
+ fhipassQ = 1.0;
+ }
+ if ( fhipassQ < 0.1 )
+ {
+ fhipassQ = 0.1;
+ }
+ x->x_hipassQ = fhipassQ;
+ // post( "disto~ : hipassQ: %f", x->x_hipassQ );
+ disto_init_filters( x );
+}
+
+static void disto_lowpassfreq(t_disto *x, t_floatarg flowpassfreq )
+{
+ if ( flowpassfreq > x->x_samplerate/2 )
+ {
+ flowpassfreq = x->x_samplerate/2;
+ }
+ if ( flowpassfreq < 0.0 )
+ {
+ flowpassfreq = 0.0;
+ }
+ x->x_lowpassfreq = flowpassfreq;
+ // post( "disto~ : lowpassfreq: %f", x->x_lowpassfreq );
+ disto_init_filters( x );
+}
+
+static void disto_lowpassQ(t_disto *x, t_floatarg flowpassQ )
+{
+ if ( flowpassQ > 1.0 )
+ {
+ flowpassQ = 1.0;
+ }
+ if ( flowpassQ < 0.1 )
+ {
+ flowpassQ = 0.1;
+ }
+ x->x_lowpassQ = flowpassQ;
+ // post( "disto~ : lowpassQ: %f", x->x_lowpassQ );
+ disto_init_filters( x );
+}
+
+static t_int *disto_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ t_int n = (int)(w[3]);
+ t_disto *x = (t_disto*)(w[4]);
+ t_int i;
+
+ for (i = 0; i < n; i++)
+ {
+
+ x->HPF.x0 = *(in++);
+ x->HPF.y0 = (x->HPF.k0*x->HPF.x0+x->HPF.k1*x->HPF.x1+x->HPF.k2*x->HPF.x2-x->HPF.k3*x->HPF.y1-x->HPF.k4*x->HPF.y2);
+ x->HPF.y2 = x->HPF.y1;
+ x->HPF.y1 = x->HPF.y0;
+ x->HPF.x2 = x->HPF.x1;
+ x->HPF.x1 = x->HPF.x0;
+ x->data = (int)x->HPF.y0;
+
+ if ((x->data-x->pred)>0)
+ x->outval += (x->data*x->x_drymix+ x->exps[abs(x->data)]);
+ else
+ if ((x->data-x->pred)<0)
+ x->outval += (x->data*x->x_drymix- x->exps[abs(x->data)]);
+ x->pred = x->data;
+
+ x->LPF.x0 = *(out);
+ x->LPF.y0 = (x->LPF.k0*x->LPF.x0+x->LPF.k1*x->LPF.x1+x->LPF.k2*x->LPF.x2-x->LPF.k3*x->LPF.y1-x->LPF.k4*x->LPF.y2);
+ x->LPF.y2 = x->LPF.y1;
+ x->LPF.y1 = x->LPF.y0;
+ x->LPF.x2 = x->LPF.x1;
+ x->LPF.x1 = x->LPF.x0;
+
+ x->outvol = x->LPF.y0*x->x_volume;
+
+ if(x->outvol > 1.0)
+ x->data = 1.0;
+ else if(x->outvol < -1.0)
+ x->data = -1.0;
+ else
+ x->data = x->outvol;
+
+ *(out++) = x->data;
+
+ x->outval *= x->x_feedback;
+
+ }
+
+ return (w+5);
+}
+
+static void disto_preset(t_disto *x, t_float pnumber)
+{
+ switch ( (int)pnumber )
+ {
+ /* "Hard Distortion 100-10000Hz" */
+ case 1:
+ x->x_drive = 1.5;
+ x->x_drymix = 1.0;
+ x->x_wetmix = 0.5;
+ x->x_feedback = 0.0;
+ x->x_volume = 1.0;
+ x->x_hipassfreq = 100.0;
+ x->x_hipassQ = 0.5;
+ x->x_lowpassfreq = 10000.0;
+ x->x_lowpassQ = 0.5;
+ break;
+
+ /* "Hard Distortion 100-6000Hz" */
+ case 2:
+ x->x_drive = 1.5;
+ x->x_drymix = 1.0;
+ x->x_wetmix = 0.5;
+ x->x_feedback = 0.0;
+ x->x_volume = 1.0;
+ x->x_hipassfreq = 100.0;
+ x->x_hipassQ = 0.5;
+ x->x_lowpassfreq = 2000.0;
+ x->x_lowpassQ = 0.5;
+ break;
+
+ /* "Very Hard Distortion" */
+ case 3:
+ x->x_drive = 2.0;
+ x->x_drymix = 0.0;
+ x->x_wetmix = 1.0;
+ x->x_feedback = 1.0;
+ x->x_volume = 5.0;
+ x->x_hipassfreq = 100.0;
+ x->x_hipassQ = 0.5;
+ x->x_lowpassfreq = 6000.0;
+ x->x_lowpassQ = 0.5;
+ break;
+
+ /* "Medium Distortion 0.2" */
+ case 4:
+ x->x_drive = 0.2;
+ x->x_drymix = 1.0;
+ x->x_wetmix = 1.0;
+ x->x_feedback = 0.1;
+ x->x_volume = 1.0;
+ x->x_hipassfreq = 100.0;
+ x->x_hipassQ = 0.5;
+ x->x_lowpassfreq = 6000.0;
+ x->x_lowpassQ = 0.5;
+ break;
+
+ /* "Medium Distortion 0.8" */
+ case 5:
+ x->x_drive = 0.8;
+ x->x_drymix = 1.0;
+ x->x_wetmix = 1.0;
+ x->x_feedback = 0.1;
+ x->x_volume = 1.0;
+ x->x_hipassfreq = 100.0;
+ x->x_hipassQ = 1.0;
+ x->x_lowpassfreq = 6000.0;
+ x->x_lowpassQ = 0.5;
+ break;
+
+ /* "Soft Distortion 0.8" */
+ case 6:
+ x->x_drive = 0.8;
+ x->x_drymix = 0.4;
+ x->x_wetmix = 0.8;
+ x->x_feedback = 0.0;
+ x->x_volume = 0.5;
+ x->x_hipassfreq = 100.0;
+ x->x_hipassQ = 1.0;
+ x->x_lowpassfreq = 10000.0;
+ x->x_lowpassQ = 0.5;
+ break;
+
+ default:
+ post( "disto~ : unknown preset requested : %d", pnumber );
+ return;
+ break;
+ }
+ disto_init_filters( x );
+}
+
+static void disto_dsp(t_disto *x, t_signal **sp)
+{
+ dsp_add(disto_perform, 4, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n, x );
+}
+
+ /* clean up */
+static void disto_free(t_disto *x)
+{
+ if ( x->x_buf != NULL ) {
+ freebytes(x->x_buf, BFSZ*sizeof( double ) );
+ post( "Freed %d bytes", BFSZ*sizeof( double ) );
+ x->x_buf = NULL;
+ }
+}
+
+static void *disto_new(void)
+{
+ t_disto *x = (t_disto *)pd_new(disto_class);
+ outlet_new(&x->x_obj, &s_signal);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("drive"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("drymix"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("wetmix"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("feedback"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("volume"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("hipassfreq"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("hipassQ"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("lowpassfreq"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("lowpassQ"));
+
+ x->x_samplerate = (int)sys_getsr();
+ x->pred = 0.0;
+ x->data = 0.0;
+
+ if ( !( x->x_buf = ( double* ) getbytes( BFSZ*sizeof( double ) ) ) )
+ {
+ post ("disto~ : could not allocate buffer" );
+ return NULL;
+ }
+
+ // set default parameters
+ disto_preset( x, 3 );
+ disto_init_filters( x );
+
+ return (x);
+}
+
+void disto_tilde_setup(void)
+{
+ post( disto_version );
+ disto_class = class_new(gensym("disto~"), (t_newmethod)disto_new, (t_method)disto_free,
+ sizeof(t_disto), 0, 0);
+
+ CLASS_MAINSIGNALIN( disto_class, t_disto, x_f );
+ class_sethelpsymbol( disto_class, gensym("help-disto~.pd") );
+ class_addmethod(disto_class, (t_method)disto_drive, gensym("drive"), A_FLOAT, 0);
+ class_addmethod(disto_class, (t_method)disto_drymix, gensym("drymix"), A_FLOAT, 0);
+ class_addmethod(disto_class, (t_method)disto_wetmix, gensym("wetmix"), A_FLOAT, 0);
+ class_addmethod(disto_class, (t_method)disto_feedback, gensym("feedback"), A_FLOAT, 0);
+ class_addmethod(disto_class, (t_method)disto_volume, gensym("volume"), A_FLOAT, 0);
+ class_addmethod(disto_class, (t_method)disto_hipassfreq, gensym("hipassfreq"), A_FLOAT, 0);
+ class_addmethod(disto_class, (t_method)disto_hipassQ, gensym("hipassQ"), A_FLOAT, 0);
+ class_addmethod(disto_class, (t_method)disto_lowpassfreq, gensym("lowpassfreq"), A_FLOAT, 0);
+ class_addmethod(disto_class, (t_method)disto_lowpassQ, gensym("lowpassQ"), A_FLOAT, 0);
+ class_addmethod(disto_class, (t_method)disto_dsp, gensym("dsp"), 0);
+ class_addmethod(disto_class, (t_method)disto_preset, gensym("preset"), A_FLOAT, 0);
+}
diff --git a/disto~/help-disto~.pd b/disto~/help-disto~.pd
new file mode 100644
index 0000000..593702b
--- /dev/null
+++ b/disto~/help-disto~.pd
@@ -0,0 +1,73 @@
+#N canvas 45 57 817 573 10;
+#X text 389 525 comments & bugs @ ydegoyon.free.fr;
+#X obj 125 503 dac~;
+#X obj 146 432 rs-disto~;
+#X msg 94 62 bang;
+#X obj 93 84 openpanel;
+#X obj 93 104 t s b;
+#X obj 150 106 float \$0;
+#X text 101 39 Step 1 : Load a sound file;
+#X obj 93 127 route float;
+#X obj 94 219 soundfiler;
+#X text 151 55 ( maybe \, a guitar sound ? );
+#X obj 582 374 table \$0-sample;
+#X msg 94 197 read -resize \$1 \$2;
+#X obj 95 176 pack s s;
+#X msg 146 307 bang;
+#X text 191 307 Step 2 : Start playing;
+#X obj 59 288 adc~;
+#X text 226 433 Step 3 : Modify parameters;
+#X text 584 510 ( http://st.karelia.ru/~smlalx );
+#X text 391 496 a DOS guitar effects software that rocks;
+#X obj 606 263 loadbang;
+#X msg 608 293 \; pd dsp 1;
+#X text 390 482 the algorithm is borrowed from Digital Effects \,;
+#X text 35 266 Plug a guitar ??;
+#X msg 228 330 stop;
+#X obj 146 330 metro 250;
+#X text 431 111 Disto~ : distortion with highpass and lowpass filters
+;
+#X obj 93 150 makefilename %d-sample;
+#X obj 80 423 *~ 0;
+#X obj 154 461 *~ 0;
+#X msg 172 380 1;
+#X msg 207 379 0;
+#X text 287 382 Normal sound;
+#X msg 242 380 bang;
+#X msg 178 404 1;
+#X msg 213 403 0;
+#X msg 248 404 bang;
+#X text 355 405 Distorted sound;
+#X text 392 510 written by (c) Alexei Smoli;
+#X obj 146 354 tabplay~ \$0-sample;
+#X obj 287 404 loadbang;
+#X connect 2 0 29 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 5 0 13 0;
+#X connect 5 1 6 0;
+#X connect 6 0 8 0;
+#X connect 8 0 27 0;
+#X connect 12 0 9 0;
+#X connect 13 0 12 0;
+#X connect 14 0 25 0;
+#X connect 16 0 2 0;
+#X connect 20 0 21 0;
+#X connect 24 0 25 0;
+#X connect 25 0 39 0;
+#X connect 27 0 13 1;
+#X connect 28 0 1 0;
+#X connect 28 0 1 1;
+#X connect 29 0 1 0;
+#X connect 29 0 1 1;
+#X connect 30 0 28 1;
+#X connect 31 0 29 1;
+#X connect 33 0 31 0;
+#X connect 33 0 30 0;
+#X connect 34 0 29 1;
+#X connect 35 0 28 1;
+#X connect 36 0 35 0;
+#X connect 36 0 34 0;
+#X connect 39 0 2 0;
+#X connect 39 0 28 0;
+#X connect 40 0 36 0;
diff --git a/disto~/rs-disto~.pd b/disto~/rs-disto~.pd
new file mode 100644
index 0000000..981d235
--- /dev/null
+++ b/disto~/rs-disto~.pd
@@ -0,0 +1,349 @@
+#N canvas 97 16 837 658 10;
+#X obj 87 469 outlet~;
+#X msg 149 9 preset 1;
+#X msg 149 31 preset 2;
+#X msg 149 56 preset 3;
+#X msg 149 80 preset 4;
+#X msg 149 103 preset 5;
+#X obj 53 307 inlet~;
+#X obj 177 468 tabwrite~ odisto;
+#N canvas 0 0 450 300 graph1 0;
+#X array odisto 2000 float 1;
+#A 0 -0.26708 -0.267659 -0.267773 -0.267663 -0.268063 -0.268941 -0.269679
+-0.269954 -0.270085 -0.270558 -0.27125 -0.271575 -0.271187 -0.270388
+-0.269913 -0.269957 -0.270104 -0.269923 -0.269085 -0.267836 -0.266711
+-0.265669 -0.264553 -0.263606 -0.263061 -0.262861 -0.262675 -0.262145
+-0.261336 -0.260573 -0.26004 -0.25979 -0.259776 -0.260007 -0.260453
+-0.260904 -0.261228 -0.261418 -0.261567 -0.261693 -0.261452 -0.260715
+-0.259912 -0.259345 -0.258913 -0.258407 -0.257621 -0.256502 -0.255412
+-0.255096 -0.255742 -0.256443 -0.256694 -0.257092 -0.257969 -0.259069
+-0.260196 -0.26123 -0.262196 -0.263298 -0.264522 -0.265454 -0.265789
+-0.265929 -0.266428 -0.26689 -0.266694 -0.266317 -0.266395 -0.266645
+-0.266675 -0.266611 -0.266736 -0.266962 -0.267 -0.266981 -0.267214
+-0.267815 -0.268747 -0.2696 -0.269911 -0.269677 -0.269176 -0.268851
+-0.268912 -0.268914 -0.268561 -0.26814 -0.267891 -0.267844 -0.267773
+-0.267341 -0.266582 -0.265804 -0.265366 -0.265358 -0.265496 -0.265834
+-0.26651 -0.267089 -0.267197 -0.266909 -0.266797 -0.267527 -0.268878
+-0.270185 -0.27116 -0.271915 -0.272759 -0.273667 -0.274412 -0.275001
+-0.27547 -0.275987 -0.276591 -0.276781 -0.276323 -0.275748 -0.275574
+-0.275727 -0.275897 -0.275912 -0.275895 -0.276327 -0.277313 -0.277979
+-0.277727 -0.277282 -0.277164 -0.276969 -0.276543 -0.276015 -0.2754
+-0.274914 -0.274748 -0.274519 -0.273811 -0.2729 -0.272283 -0.272013
+-0.271746 -0.271213 -0.270507 -0.269961 -0.269673 -0.269341 -0.268877
+-0.268414 -0.267891 -0.267352 -0.266763 -0.266064 -0.265647 -0.265566
+-0.265281 -0.264396 -0.262932 -0.261595 -0.260885 -0.260293 -0.25929
+-0.257585 -0.255305 -0.253139 -0.251284 -0.249837 -0.249084 -0.248607
+-0.247805 -0.246543 -0.245069 -0.243764 -0.242475 -0.240633 -0.237989
+-0.234818 -0.231719 -0.229045 -0.226673 -0.224494 -0.222467 -0.220525
+-0.218764 -0.217348 -0.216235 -0.214923 -0.212796 -0.209895 -0.206839
+-0.204027 -0.201527 -0.199378 -0.197445 -0.19561 -0.193997 -0.192592
+-0.191229 -0.189718 -0.187899 -0.185764 -0.183251 -0.180503 -0.177968
+-0.175848 -0.173948 -0.171912 -0.16965 -0.167457 -0.165405 -0.163236
+-0.160912 -0.158465 -0.155786 -0.153114 -0.150846 -0.148812 -0.146713
+-0.144673 -0.142764 -0.140666 -0.13805 -0.135212 -0.132744 -0.130552
+-0.128217 -0.1258 -0.123439 -0.120903 -0.117935 -0.114675 -0.111333
+-0.107887 -0.10454 -0.101492 -0.0985705 -0.0956639 -0.092911 -0.0906006
+-0.0887248 -0.0867019 -0.0840825 -0.0809534 -0.0775766 -0.0740247 -0.070271
+-0.0665755 -0.0632598 -0.0602591 -0.0572601 -0.0539264 -0.0501022 -0.0462753
+-0.0432218 -0.0408681 -0.0384562 -0.0356554 -0.0326975 -0.0297458 -0.0264714
+-0.0226953 -0.0189905 -0.0158314 -0.0129583 -0.00992077 -0.006587 -0.00317483
+-0.000170271 0.00229779 0.00464803 0.00721599 0.0100859 0.0130355 0.0159059
+0.0189153 0.022138 0.0254052 0.028593 0.0318781 0.0354225 0.0388125
+0.041718 0.0444737 0.0475818 0.0510936 0.054507 0.057465 0.0602617
+0.0631991 0.0661021 0.0689534 0.0719189 0.0750332 0.0784235 0.0819329
+0.0854564 0.0890724 0.0924396 0.0954562 0.098226 0.100836 0.103648
+0.106636 0.109676 0.112982 0.116417 0.119893 0.123406 0.126536 0.129097
+0.131271 0.133429 0.135833 0.138202 0.140347 0.14245 0.144688 0.147011
+0.149205 0.15138 0.153773 0.156286 0.158841 0.161446 0.164034 0.166742
+0.169614 0.172283 0.174349 0.17591 0.177754 0.180279 0.182867 0.185162
+0.187412 0.189872 0.192601 0.195232 0.197485 0.199546 0.201768 0.204144
+0.206174 0.207815 0.209428 0.211006 0.212441 0.213705 0.214928 0.216237
+0.217766 0.219741 0.221722 0.223089 0.224116 0.225337 0.226729 0.227758
+0.228216 0.228675 0.22939 0.230035 0.230542 0.231047 0.231827 0.233027
+0.234295 0.235417 0.236317 0.23679 0.236896 0.23694 0.237237 0.237881
+0.238629 0.239307 0.239995 0.240721 0.24144 0.242192 0.243171 0.244484
+0.245695 0.24654 0.247529 0.248852 0.250142 0.251325 0.252652 0.254384
+0.256341 0.25797 0.259165 0.260237 0.261247 0.262037 0.262577 0.263105
+0.263864 0.264588 0.264886 0.265002 0.265396 0.266151 0.267097 0.268057
+0.268906 0.269509 0.269879 0.270139 0.270324 0.270709 0.271559 0.272587
+0.273495 0.274237 0.274801 0.275454 0.276392 0.277454 0.278621 0.279744
+0.280669 0.281482 0.281956 0.282112 0.282319 0.28269 0.283387 0.28435
+0.285342 0.286491 0.287864 0.289279 0.290437 0.291215 0.291987 0.292999
+0.294054 0.29496 0.295644 0.296266 0.297002 0.297657 0.298119 0.298521
+0.299077 0.300061 0.301543 0.303172 0.304387 0.30505 0.305493 0.305954
+0.306373 0.306843 0.307805 0.309191 0.310435 0.311297 0.31185 0.312321
+0.312821 0.313274 0.313723 0.31416 0.314671 0.315332 0.315916 0.316495
+0.317263 0.318092 0.318635 0.318368 0.31737 0.316202 0.31487 0.313304
+0.311569 0.309675 0.307999 0.306836 0.306097 0.30543 0.304414 0.303255
+0.302409 0.301928 0.301785 0.301895 0.302158 0.30259 0.302976 0.302958
+0.302395 0.301419 0.300219 0.298894 0.297635 0.296575 0.29564 0.294797
+0.294115 0.293699 0.293627 0.293838 0.294015 0.293818 0.293335 0.292805
+0.292195 0.291567 0.290985 0.290239 0.289184 0.287888 0.286705 0.285863
+0.285138 0.28429 0.283133 0.281738 0.280465 0.279229 0.277755 0.276089
+0.274151 0.271899 0.269585 0.267458 0.265824 0.264746 0.263793 0.262516
+0.260886 0.259367 0.258111 0.256866 0.255784 0.25474 0.253198 0.251293
+0.249632 0.248461 0.247448 0.246263 0.244935 0.243536 0.242133 0.240709
+0.239106 0.237425 0.23605 0.235135 0.23424 0.232885 0.231229 0.229657
+0.228392 0.227415 0.226439 0.225406 0.224468 0.223602 0.222691 0.221352
+0.219332 0.216988 0.214684 0.212667 0.210812 0.208681 0.206372 0.203835
+0.200758 0.197397 0.194213 0.191612 0.189638 0.187898 0.186069 0.183983
+0.182057 0.180838 0.180003 0.179099 0.17805 0.176769 0.175117 0.172857
+0.169997 0.167006 0.164326 0.162073 0.160094 0.158136 0.156023 0.153598
+0.150921 0.148421 0.146236 0.144047 0.142044 0.140806 0.140162 0.139427
+0.138327 0.136841 0.134884 0.132719 0.130705 0.128635 0.126181 0.123419
+0.12071 0.11838 0.11634 0.114367 0.112656 0.111487 0.110742 0.109904
+0.108587 0.107225 0.106379 0.1059 0.10524 0.104039 0.102601 0.101234
+0.0994895 0.0971318 0.0944816 0.0916963 0.0888986 0.0859872 0.0826179
+0.0789733 0.0755323 0.072549 0.069849 0.0669985 0.0642158 0.062126
+0.0608327 0.0598513 0.0585596 0.0569368 0.0554447 0.0543066 0.0532107
+0.0514894 0.0489487 0.0463233 0.044406 0.0430643 0.0415634 0.0397923
+0.038182 0.0364309 0.0341317 0.0317625 0.0296438 0.027509 0.025305
+0.0233969 0.0219949 0.0207145 0.0191473 0.0172301 0.0151133 0.013269
+0.0119967 0.0109929 0.00987112 0.00847854 0.00662015 0.00422399 0.00178499
+-4.51909e-05 -0.00127923 -0.00244447 -0.00409475 -0.00660254 -0.00976168
+-0.0128603 -0.015249 -0.0169854 -0.0187953 -0.021044 -0.0235007 -0.0259382
+-0.028343 -0.0309557 -0.0339662 -0.0371732 -0.0403194 -0.0434447 -0.0467169
+-0.04999 -0.0529932 -0.055748 -0.0583544 -0.0609852 -0.0637931 -0.0666124
+-0.0692497 -0.0717844 -0.0745041 -0.0774464 -0.0801579 -0.0823805 -0.0843732
+-0.0864587 -0.0887887 -0.0912798 -0.0939585 -0.0971554 -0.100665 -0.103826
+-0.106431 -0.108576 -0.110698 -0.113375 -0.1165 -0.119544 -0.122029
+-0.124057 -0.126174 -0.128125 -0.12965 -0.13144 -0.133778 -0.136296
+-0.138863 -0.141337 -0.143518 -0.14551 -0.14751 -0.149549 -0.151428
+-0.153072 -0.15461 -0.155989 -0.157365 -0.159025 -0.160831 -0.162686
+-0.164618 -0.166511 -0.168361 -0.170065 -0.171328 -0.172153 -0.172704
+-0.173265 -0.174136 -0.175203 -0.176386 -0.177682 -0.178703 -0.179222
+-0.179609 -0.180324 -0.181603 -0.183362 -0.185256 -0.187043 -0.188578
+-0.189993 -0.191608 -0.193295 -0.19481 -0.196331 -0.198017 -0.199753
+-0.20136 -0.202718 -0.203864 -0.204768 -0.205365 -0.205876 -0.206719
+-0.20814 -0.209633 -0.210398 -0.210418 -0.210391 -0.211039 -0.212329
+-0.213633 -0.214896 -0.21649 -0.21832 -0.220031 -0.221472 -0.222763
+-0.224144 -0.225502 -0.226554 -0.227404 -0.228308 -0.229294 -0.230278
+-0.231077 -0.23163 -0.232241 -0.232997 -0.233798 -0.234634 -0.23527
+-0.235657 -0.236139 -0.236958 -0.238334 -0.240207 -0.241985 -0.243241
+-0.243839 -0.244195 -0.244781 -0.245094 -0.245249 -0.245878 -0.24671
+-0.247417 -0.247736 -0.247701 -0.247682 -0.247737 -0.248194 -0.249232
+-0.250298 -0.251199 -0.252196 -0.25324 -0.253831 -0.253895 -0.254209
+-0.254853 -0.255181 -0.255042 -0.254884 -0.254926 -0.254162 -0.252799
+-0.252477 -0.252702 -0.252552 -0.25226 -0.251876 -0.25148 -0.251157
+-0.251159 -0.25156 -0.251571 -0.251431 -0.252436 -0.253917 -0.254709
+-0.255157 -0.25613 -0.25763 -0.258282 -0.258523 -0.259267 -0.259174
+-0.258407 -0.257889 -0.257675 -0.257922 -0.257931 -0.257996 -0.258264
+-0.25892 -0.261883 -0.26463 -0.264138 -0.26376 -0.264575 -0.265184
+-0.266336 -0.267409 -0.267822 -0.266942 -0.266393 -0.267595 -0.266748
+-0.264757 -0.263944 -0.263262 -0.265041 -0.268545 -0.269239 -0.266784
+-0.264549 -0.264479 -0.263802 -0.26211 -0.263582 -0.267065 -0.269475
+-0.270978 -0.270394 -0.269201 -0.270115 -0.271682 -0.272462 -0.270975
+-0.268228 -0.267972 -0.268954 -0.269215 -0.267879 -0.265538 -0.265747
+-0.26695 -0.265722 -0.262704 -0.261184 -0.262661 -0.263738 -0.262378
+-0.261077 -0.261745 -0.26286 -0.262206 -0.260193 -0.256853 -0.253664
+-0.254292 -0.254887 -0.253113 -0.252455 -0.252185 -0.252083 -0.251636
+-0.250378 -0.250429 -0.251083 -0.251245 -0.250197 -0.248311 -0.248316
+-0.250481 -0.25172 -0.25036 -0.248913 -0.24947 -0.250491 -0.249688
+-0.247323 -0.246362 -0.246909 -0.247081 -0.247627 -0.248639 -0.249174
+-0.248585 -0.246874 -0.245746 -0.246146 -0.247087 -0.247831 -0.247248
+-0.244618 -0.242451 -0.24337 -0.24585 -0.246548 -0.24485 -0.242945
+-0.242916 -0.244928 -0.246121 -0.243898 -0.241685 -0.241076 -0.239409
+-0.238542 -0.239267 -0.23968 -0.239633 -0.238391 -0.238028 -0.239167
+-0.238772 -0.239485 -0.241619 -0.240941 -0.239006 -0.23768 -0.237419
+-0.238752 -0.23857 -0.236359 -0.234628 -0.234589 -0.236239 -0.236151
+-0.234007;
+#A 1000 -0.233151 -0.232566 -0.231177 -0.229258 -0.227183 -0.227228
+-0.227617 -0.225116 -0.222538 -0.222347 -0.223857 -0.223895 -0.219827
+-0.216547 -0.216368 -0.216054 -0.215722 -0.214559 -0.212003 -0.20963
+-0.207424 -0.206119 -0.204874 -0.202757 -0.202116 -0.201593 -0.197969
+-0.194809 -0.195558 -0.196154 -0.194239 -0.191265 -0.187853 -0.185618
+-0.184496 -0.183492 -0.182305 -0.179041 -0.174603 -0.17044 -0.166358
+-0.163546 -0.161854 -0.160624 -0.158786 -0.155308 -0.152192 -0.151414
+-0.15124 -0.148396 -0.142697 -0.137792 -0.137038 -0.137641 -0.135005
+-0.130929 -0.128258 -0.126764 -0.12501 -0.121357 -0.117967 -0.117197
+-0.116285 -0.11336 -0.109174 -0.10519 -0.102996 -0.101146 -0.0986079
+-0.096028 -0.0935584 -0.092103 -0.0909516 -0.0880864 -0.083206 -0.0781496
+-0.0753894 -0.0735017 -0.0700775 -0.0666747 -0.06456 -0.0628634 -0.0596906
+-0.05453 -0.0506355 -0.049393 -0.0486083 -0.0470291 -0.04386 -0.0400564
+-0.0375559 -0.0354427 -0.0326462 -0.0284579 -0.0241831 -0.0231869 -0.0228954
+-0.0193918 -0.0151974 -0.0131444 -0.0120789 -0.00885181 -0.00334882
+-0.000488049 -0.00124724 -0.000826269 0.00269577 0.00816899 0.0125972
+0.0139505 0.015662 0.0197424 0.0238507 0.0261824 0.0274073 0.0296689
+0.0327018 0.0354039 0.0381678 0.0418735 0.0471356 0.0513068 0.0524804
+0.052739 0.0542056 0.0578076 0.0615656 0.0639498 0.0670369 0.0705633
+0.0735998 0.0770429 0.0802246 0.0831852 0.0858242 0.0876192 0.0902116
+0.0936297 0.0971528 0.10107 0.103717 0.104464 0.104406 0.10519 0.108577
+0.11268 0.11614 0.119239 0.121048 0.122739 0.124522 0.125989 0.128996
+0.133007 0.136894 0.140435 0.143467 0.146747 0.149152 0.150424 0.152439
+0.155326 0.158756 0.162286 0.165548 0.168342 0.169027 0.168369 0.169249
+0.171925 0.175741 0.180513 0.184524 0.186305 0.187594 0.191185 0.195745
+0.197635 0.198124 0.200597 0.204669 0.208345 0.211098 0.213641 0.216164
+0.217733 0.218783 0.220983 0.224042 0.227037 0.230287 0.233653 0.235084
+0.234313 0.235109 0.239012 0.242701 0.244361 0.246525 0.250272 0.25411
+0.255897 0.25524 0.255541 0.258263 0.262457 0.266652 0.269534 0.272847
+0.277157 0.279705 0.279503 0.278611 0.279129 0.281444 0.284939 0.288047
+0.289756 0.291121 0.292858 0.294858 0.297389 0.300696 0.304043 0.306559
+0.309312 0.313112 0.316137 0.317521 0.318532 0.319404 0.320956 0.323932
+0.326422 0.327967 0.328359 0.328234 0.330002 0.331075 0.330502 0.331551
+0.334164 0.336528 0.337502 0.339519 0.343138 0.343385 0.341942 0.345137
+0.350613 0.353263 0.355074 0.357987 0.360278 0.361003 0.360899 0.359697
+0.357073 0.357094 0.3612 0.364872 0.366239 0.367065 0.367359 0.367487
+0.370281 0.374995 0.377113 0.375402 0.373893 0.375784 0.378692 0.379707
+0.378632 0.376485 0.376255 0.378171 0.379984 0.381831 0.382382 0.38122
+0.380453 0.380165 0.38094 0.382664 0.382666 0.380171 0.377955 0.378977
+0.381425 0.382074 0.381313 0.380389 0.380109 0.380732 0.381984 0.383034
+0.382157 0.380766 0.380922 0.379459 0.375111 0.371841 0.370545 0.36898
+0.367916 0.369126 0.37053 0.36945 0.366917 0.364824 0.362867 0.361097
+0.360896 0.361417 0.360585 0.358882 0.357184 0.353876 0.348368 0.344413
+0.345112 0.345563 0.341402 0.337921 0.337485 0.336197 0.334123 0.332985
+0.331907 0.32895 0.325206 0.324924 0.326902 0.325753 0.321737 0.317587
+0.313514 0.310824 0.311441 0.31337 0.312221 0.308256 0.30576 0.305427
+0.304981 0.303626 0.300351 0.295198 0.291245 0.290881 0.293548 0.295234
+0.292051 0.285143 0.278155 0.273595 0.27235 0.273075 0.273481 0.27107
+0.26558 0.260761 0.258523 0.258636 0.259687 0.258633 0.255704 0.253178
+0.251565 0.250427 0.248592 0.244545 0.240821 0.238358 0.234409 0.232209
+0.232456 0.23026 0.225788 0.221606 0.218641 0.216768 0.216123 0.217035
+0.21832 0.217213 0.212238 0.206817 0.203371 0.201033 0.199994 0.199282
+0.197333 0.194419 0.191874 0.189577 0.186936 0.184725 0.182973 0.180792
+0.178151 0.176717 0.176135 0.173983 0.169511 0.163987 0.16068 0.161077
+0.162289 0.161645 0.159045 0.155913 0.153192 0.149358 0.144425 0.140544
+0.13728 0.13542 0.135981 0.13323 0.125881 0.122486 0.124123 0.12313
+0.118366 0.115432 0.115196 0.113423 0.109305 0.105931 0.104971 0.102352
+0.0964158 0.0939342 0.0956731 0.0938349 0.0886857 0.086643 0.0860824
+0.0835724 0.0809018 0.0784262 0.074743 0.0699358 0.0654743 0.0644693
+0.0670738 0.0667907 0.0608345 0.0560668 0.0550274 0.0517716 0.0470288
+0.0461094 0.0464903 0.0437995 0.0394189 0.0369743 0.035492 0.0316002
+0.0277853 0.0261807 0.0236398 0.0198325 0.0167765 0.0148441 0.0128608
+0.00970296 0.00703723 0.00583368 0.00380263 0.000473064 -0.00252255
+-0.00541019 -0.00864094 -0.0111409 -0.0125186 -0.0135007 -0.0143205
+-0.0146019 -0.0148482 -0.0171466 -0.020987 -0.0229116 -0.0231064 -0.0245996
+-0.0276884 -0.0305513 -0.0327162 -0.0351196 -0.0376646 -0.0401182 -0.0426596
+-0.0444322 -0.0457675 -0.0478584 -0.0497565 -0.0506464 -0.0513157 -0.052159
+-0.0539484 -0.0561167 -0.0568429 -0.0573337 -0.0587494 -0.0603145 -0.0619514
+-0.0639226 -0.0669022 -0.0707158 -0.0739696 -0.0772074 -0.0811309 -0.0844747
+-0.0873654 -0.0907039 -0.0933156 -0.0941001 -0.0943444 -0.095617 -0.0974344
+-0.099484 -0.1018 -0.102882 -0.103321 -0.105848 -0.110255 -0.114038
+-0.115846 -0.116748 -0.118123 -0.119961 -0.122312 -0.124746 -0.126659
+-0.128236 -0.127689 -0.125448 -0.126103 -0.12984 -0.133319 -0.134342
+-0.133867 -0.135798 -0.139161 -0.141429 -0.144191 -0.145866 -0.145907
+-0.147306 -0.149892 -0.153489 -0.155841 -0.155249 -0.15612 -0.158146
+-0.157869 -0.156883 -0.157486 -0.159411 -0.160146 -0.160931 -0.164545
+-0.167303 -0.166925 -0.167136 -0.170044 -0.17438 -0.177245 -0.177154
+-0.176848 -0.177855 -0.179501 -0.182723 -0.187023 -0.189608 -0.189674
+-0.188992 -0.189324 -0.191281 -0.193741 -0.195296 -0.195369 -0.193301
+-0.191879 -0.194567 -0.198013 -0.199268 -0.199752 -0.199488 -0.199473
+-0.201463 -0.204911 -0.208248 -0.208627 -0.205791 -0.203813 -0.205502
+-0.209768 -0.213233 -0.213537 -0.211242 -0.209762 -0.210589 -0.212065
+-0.214414 -0.217509 -0.218825 -0.21755 -0.216575 -0.218297 -0.220953
+-0.221919 -0.222 -0.222716 -0.223324 -0.224083 -0.225504 -0.225747
+-0.22421 -0.223129 -0.22334 -0.223363 -0.223819 -0.226083 -0.228188
+-0.228343 -0.227315 -0.22695 -0.228393 -0.230022 -0.230815 -0.232001
+-0.232692 -0.231958 -0.231828 -0.233017 -0.234158 -0.234324 -0.234582
+-0.236492 -0.23755 -0.236831 -0.238344 -0.24147 -0.243434 -0.244738
+-0.245636 -0.246112 -0.245377 -0.244503 -0.246052 -0.248095 -0.248097
+-0.246671 -0.245189 -0.245102 -0.246481 -0.247893 -0.248335 -0.247514
+-0.246449 -0.245922 -0.245682 -0.246598 -0.248263 -0.248967 -0.248829
+-0.24816 -0.24748 -0.246923 -0.24558 -0.245254 -0.246168 -0.245029
+-0.242549 -0.241186 -0.241762 -0.24368 -0.244018 -0.243866 -0.245271
+-0.244062 -0.239965 -0.238904 -0.241356 -0.242091 -0.239899 -0.23877
+-0.238927 -0.237334 -0.236052 -0.237747 -0.238291 -0.233767 -0.228659
+-0.227553 -0.227043 -0.225269 -0.225544 -0.227385 -0.226236 -0.22154
+-0.218968 -0.221037 -0.222556 -0.220614 -0.219152 -0.220012 -0.219519
+-0.217602 -0.218801 -0.220957 -0.218647 -0.214792 -0.214112 -0.21522
+-0.213766 -0.210293 -0.210031 -0.209338 -0.203426 -0.199947 -0.202385
+-0.204352 -0.203511 -0.20268 -0.203071 -0.201417 -0.197239 -0.196734
+-0.200169 -0.201207 -0.198635 -0.195482 -0.193122 -0.190594 -0.188472
+-0.1884 -0.189048 -0.188209 -0.186508 -0.186198 -0.186368 -0.184437
+-0.181724 -0.180083 -0.178512 -0.177677 -0.179502 -0.1818 -0.18054
+-0.176895 -0.175291 -0.175508 -0.175358 -0.175918 -0.177403 -0.177107
+-0.174243 -0.171687 -0.170536 -0.169344 -0.168906 -0.169992 -0.170334
+-0.168262 -0.165975 -0.16621 -0.166189 -0.162635 -0.158982 -0.157627
+-0.156921 -0.156462 -0.156192 -0.155766 -0.153264 -0.14937 -0.1486
+-0.149288 -0.148866 -0.149764 -0.151418 -0.150841 -0.146987 -0.143179
+-0.142844 -0.142361 -0.140405 -0.140584 -0.14176 -0.141941 -0.141421
+-0.140756 -0.140163 -0.138007 -0.136409 -0.138076 -0.139307 -0.13895
+-0.139289 -0.139026 -0.137142 -0.136061 -0.138299 -0.142194 -0.143127
+-0.14174 -0.142156 -0.143001 -0.14211 -0.141021 -0.14012 -0.13871 -0.137428
+-0.138223 -0.140831 -0.140916 -0.137712 -0.134516 -0.131997 -0.130671
+-0.13108 -0.132343 -0.133538 -0.1325 -0.129983 -0.128205 -0.126336
+-0.124934 -0.124084 -0.123517 -0.124253 -0.124134 -0.121727 -0.11916
+-0.118518 -0.119372 -0.119263 -0.11808 -0.118028 -0.118947 -0.119155
+-0.119376 -0.120386 -0.120797 -0.119504 -0.117742 -0.117604 -0.118196
+-0.117564 -0.116427 -0.115047 -0.112277 -0.109151 -0.107823 -0.108153
+-0.108001 -0.106851 -0.106133 -0.105341 -0.103449 -0.10225 -0.102543
+-0.102643 -0.101744 -0.100163 -0.0989409 -0.0985816 -0.0983467 -0.0977372
+-0.0962336 -0.0939372 -0.0920292 -0.0910775 -0.0912255 -0.0922101 -0.0922327
+-0.0905764 -0.088414 -0.0861316 -0.0849861 -0.0859358 -0.0866984 -0.085469
+-0.082363 -0.0791981 -0.0784002 -0.0789486 -0.0792314 -0.0791902 -0.0784253
+-0.0780597 -0.0787439 -0.0790283 -0.0785446 -0.0774918 -0.0761877 -0.074771
+-0.0732108 -0.0728679 -0.0734066 -0.0736221 -0.0735405 -0.0728323 -0.0720006
+-0.0711169 -0.0703422 -0.0706587 -0.0712593 -0.0715813 -0.0713705 -0.0696971
+-0.067587 -0.065892 -0.0648743 -0.0655384 -0.0659984 -0.0640801 -0.0604196
+-0.0561824 -0.0529379 -0.051625 -0.0522934 -0.0530088 -0.0504143 -0.0461285
+-0.0434267 -0.0418044 -0.0416196 -0.0432084 -0.0442318 -0.0422415 -0.0370414
+-0.0328587 -0.0324699 -0.0334087 -0.0345388 -0.035246 -0.0336549 -0.0303687
+-0.0274198 -0.0264446 -0.0272249 -0.0270482 -0.0256714 -0.0251707 -0.0246116
+-0.0231644 -0.0228445 -0.024125 -0.0244141 -0.0223641 -0.0202823 -0.0195197
+-0.0189773 -0.019408 -0.0209408 -0.0204265 -0.0171791 -0.0140059 -0.0129334
+-0.0139812 -0.0153043 -0.0155131 -0.0147108 -0.012386 -0.00872585 -0.00597713
+-0.00589554 -0.00785846 -0.00965299 -0.0102252 -0.00991027 -0.00770097
+-0.00405239 -0.00314322 -0.00636492 -0.008773 -0.00656921 -0.00314961
+-0.00142149 0.000355286 0.00157009 0.000652503 0.000665672 0.00507241
+0.0103608 0.0112021 0.00941616 0.00791777 0.00581629 0.00400531 0.00527335
+0.00874362 0.00976684 0.00734871 0.00608535;
+#X coords 0 2 1999 -2 200 140 1;
+#X restore 596 461 graph;
+#X msg 177 446 bang;
+#X obj 192 229 hsl 128 15 0 25 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 0;
+#X obj 213 263 hsl 128 15 -5 5 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 0;
+#X obj 256 330 hsl 128 15 -10 10 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 0;
+#X obj 380 229 hsl 128 15 0 5 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 0;
+#X obj 407 270 hsl 128 15 0 22500 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 0;
+#X text 256 168 Note : setting a parameter overrides presets;
+#X msg 152 128 preset 6;
+#X text 216 7 hard distortion 100-10000Hz;
+#X text 217 31 hard distortion 100-6000Hz;
+#X text 221 80 medium distortion 0.2;
+#X text 221 104 medium distortion 0.8;
+#X text 223 126 soft distortion 0.8;
+#X text 208 247 Dry mix [ -5 - 5 ];
+#X obj 242 297 hsl 128 15 -5 5 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 0;
+#X text 237 279 Wet mix [ -5 - 5 ];
+#X text 402 253 Low pass frequency [ 0 - 22500 ];
+#X obj 441 307 hsl 128 15 0.1 1 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 0;
+#X obj 482 344 hsl 128 15 0 22500 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 0;
+#X obj 517 379 hsl 128 15 0.1 1 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 0;
+#X text 477 327 High pass frequency [ 0 - 22500 ];
+#X text 133 543 Note : see file "distort3.txt" which explains parameters
+;
+#X text 375 212 Volume [ 0 - 5 ];
+#X text 193 208 Drive [ 0 - 25 ];
+#X text 512 362 High pass Q [ 0.1 - 1 ];
+#X text 436 290 Low pass Q [ 0.1 - 1 ];
+#X text 253 312 Feedback [ -10 - 10 ];
+#X text 218 56 very hard distortion ( default );
+#X obj 87 414 disto~ --------------------------------------------------
+;
+#X connect 1 0 37 0;
+#X connect 2 0 37 0;
+#X connect 3 0 37 0;
+#X connect 4 0 37 0;
+#X connect 5 0 37 0;
+#X connect 6 0 37 0;
+#X connect 9 0 7 0;
+#X connect 10 0 37 1;
+#X connect 11 0 37 2;
+#X connect 12 0 37 4;
+#X connect 13 0 37 5;
+#X connect 14 0 37 6;
+#X connect 16 0 37 0;
+#X connect 23 0 37 3;
+#X connect 26 0 37 7;
+#X connect 27 0 37 8;
+#X connect 28 0 37 9;
+#X connect 37 0 0 0;
+#X connect 37 0 7 0;
diff --git a/formant~/INSTALL b/formant~/INSTALL
new file mode 100644
index 0000000..bcbc08b
--- /dev/null
+++ b/formant~/INSTALL
@@ -0,0 +1,9 @@
+untar in /my/pd/dir/externs
+
+cd /my/pd/dir/externs/formant~
+
+make
+
+make install
+
+you're set !!
diff --git a/formant~/Makefile b/formant~/Makefile
new file mode 100644
index 0000000..6ebad5a
--- /dev/null
+++ b/formant~/Makefile
@@ -0,0 +1,82 @@
+NAME=formant~
+CSYM=formant_tilde
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).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
+
+.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
+
+.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
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -DUNIX -DICECAST -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
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o ../$*.pd_linux
+ ln -s $*/$*.pd_linux ..
+
+# ----------------------------------------------------------
+
+install:
+ cp help-*.pd ../../doc/5.reference
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/formant~/README b/formant~/README
new file mode 100644
index 0000000..41526cb
--- /dev/null
+++ b/formant~/README
@@ -0,0 +1,21 @@
+Version 0.01
+copyleft 2001 by Yves Degoyon
+
+formant~.dll is a formant synthesis generator external for pd (by Miller
+Puckette).
+
+To install formant~, 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.
+
+*****************************************************************************
+
+thruth is here.
+trust is in another world.
+
diff --git a/formant~/formant~.c b/formant~/formant~.c
new file mode 100644
index 0000000..eba7db5
--- /dev/null
+++ b/formant~/formant~.c
@@ -0,0 +1,252 @@
+/* ------------------------ formant~ ------------------------------------------ */
+/* */
+/* Tilde object to produce formant synthesis. */
+/* By using several ones, you should be able to generate voice sounds. */
+/* Written by Yves Degoyon ( 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. */
+/* Also inspired by an article by Jean-Paul Smets - Solanes */
+/* */
+/* ---------------------------------------------------------------------------- */
+
+
+
+#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>
+#endif
+#ifdef NT
+#define M_PI 3.14159265358979323846
+#endif
+#include <math.h>
+
+#include "m_pd.h" /* standard pd stuff */
+
+static char *formant_version = "formant~: formant synthesis version 0.1, written by Yves Degoyon";
+
+
+static t_class *formant_class;
+
+typedef struct _formant
+{
+ t_object x_obj;
+
+ t_int x_size; /* size of the sample */
+ t_float x_central_freq; /* central frequency of the filter */
+ t_float x_filter_width; /* width of the filter */
+ t_float x_skirt_width; /* width of the skirt */
+ t_float x_samplerate; /* sample rate */
+ t_float x_time_stretch; /* time stretch */
+ t_int x_readpos; /* data's reading position */
+ t_int x_play; /* playing on/off flag */
+ t_outlet *x_end; /* outlet for outputing a bang at the end */
+ t_float x_gendata; /* flag to avoid reading data during generation ( might be null )*/
+ t_float* x_data; /* sample containing formant synthesis*/
+
+} t_formant;
+
+ /* clean up */
+static void formant_free(t_formant *x)
+{
+ if ( x->x_data != NULL ) {
+ freebytes(x->x_data, x->x_size*sizeof(float) );
+ x->x_data = NULL;
+ }
+}
+
+ /* generate sample data */
+static t_int formant_gendata(t_formant *x)
+{
+ t_float t, b, fs;
+
+ if ( x->x_size <= 0 || x->x_central_freq <= 0 || x->x_filter_width <= 0 || x->x_skirt_width <= 0 ) {
+ error( "formant~ : error generating data : negative or null parameter(s)" );
+ return -1;
+ }
+
+ x->x_gendata = 1;
+
+ /* freeing data */
+ formant_free( x );
+ if ( !( x->x_data = (float*) getbytes( x->x_size*sizeof(float) ) ) ) {
+ post( "formant~ : error generating data : cannot allocate table" );
+ return -1;
+ }
+
+ fs = 0;
+ while( fs < x->x_size-1 ) {
+ t = (fs/x->x_samplerate) * x->x_time_stretch; /* time taken from zero */
+ b = M_PI / x->x_skirt_width ;
+ if ( t < b ) {
+ *(x->x_data+(int)fs) = 0.5*(1-cos(x->x_skirt_width*t))*exp(- x->x_filter_width*t )*sin( x->x_central_freq*t);
+ } else {
+ *(x->x_data+(int)fs) = exp(- x->x_filter_width*t )*sin( x->x_central_freq*t);
+ }
+ fs++;
+ }
+
+ /* everything went fine */
+ x->x_gendata = 0;
+ return 0;
+}
+
+ /* generates a formant */
+static t_int *formant_perform(t_int *w)
+{
+ t_formant *x = (t_formant *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]); /* number of samples */
+
+ while (n--) {
+ if ( !x->x_gendata && x->x_play) {
+ *out=*(x->x_data+x->x_readpos);
+ x->x_readpos = (x->x_readpos+1)%x->x_size;
+ if ( x->x_readpos == 0 ) {
+ x->x_play=0;
+ outlet_bang(x->x_end);
+ }
+ } else {
+ *out=0.0;
+ }
+ out++;
+ }
+ return (w+4);
+}
+
+static void formant_dsp(t_formant *x, t_signal **sp)
+{
+ dsp_add(formant_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+ /* replay the sample */
+static void formant_bang(t_formant *x, t_floatarg fsize)
+{
+ x->x_play=1;
+ x->x_readpos=0;
+}
+
+ /* set size of the sample */
+static void formant_size(t_formant *x, t_floatarg fsize)
+{
+ if ( fsize <= 0 ) {
+ post( "formant~ : error : sample size should be >0" );
+ return;
+ }
+ x->x_size = fsize;
+ formant_gendata( x );
+}
+
+ /* set central frequency of the formant */
+static void formant_central_freq(t_formant *x, t_floatarg ffreq)
+{
+ if ( ffreq <= 0 ) {
+ post( "formant~ : error : filter central frequency should be >0" );
+ return;
+ }
+ x->x_central_freq = ffreq;
+ formant_gendata( x );
+}
+
+ /* set filter width of the formant */
+static void formant_filter_width(t_formant *x, t_floatarg fwidth)
+{
+ if ( fwidth <= 0 ) {
+ post( "formant~ : error : filter width should be >0" );
+ return;
+ }
+ x->x_filter_width = fwidth;
+ formant_gendata( x );
+}
+
+ /* set skirt width of the formant */
+static void formant_skirt_width(t_formant *x, t_floatarg swidth)
+{
+ if ( swidth <= 0 ) {
+ post( "formant~ : error : skirt width should be >0" );
+ return;
+ }
+ x->x_skirt_width = swidth;
+ formant_gendata( x );
+}
+
+ /* set time stretch factor */
+static void formant_time_stretch(t_formant *x, t_floatarg fstretch)
+{
+ if ( fstretch <= 0 ) {
+ post( "formant~ : error : time stretch should be >0" );
+ return;
+ }
+ x->x_time_stretch = fstretch;
+ formant_gendata( x );
+}
+
+static void *formant_new(t_floatarg fsize, t_floatarg ffreq, t_floatarg ffwidth, t_floatarg fswidth)
+{
+ t_formant *x = (t_formant *)pd_new(formant_class);
+ outlet_new(&x->x_obj, &s_signal);
+
+ if ( fsize <= 0 || ffreq <= 0 || ffwidth <= 0 || fswidth <= 0 ) {
+ error( "formant~ : missing or negative creation arguments" );
+ return NULL;
+ }
+
+ x->x_size = fsize;
+ x->x_central_freq = ffreq;
+ x->x_filter_width = ffwidth;
+ x->x_skirt_width = fswidth;
+ x->x_readpos = 0;
+ x->x_data = NULL;
+ x->x_time_stretch = 1.0;
+ x->x_samplerate = sys_getsr();
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("size"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("freq"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("fwidth"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("swidth"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("stretch"));
+ x->x_end = outlet_new( &x->x_obj, &s_bang );
+ if ( formant_gendata( x ) ) {
+ post( "formant~ : error generating data" );
+ return NULL;
+ } else {
+ return(x);
+ }
+}
+
+void formant_tilde_setup(void)
+{
+ post(formant_version);
+ formant_class = class_new(gensym("formant~"), (t_newmethod)formant_new, (t_method)formant_free,
+ sizeof(t_formant), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_sethelpsymbol( formant_class, gensym("help-formant~") );
+ class_addmethod(formant_class, (t_method)formant_dsp, gensym("dsp"), 0);
+ class_addmethod(formant_class, (t_method)formant_size, gensym("size"), A_FLOAT, 0);
+ class_addmethod(formant_class, (t_method)formant_bang, gensym("bang"), 0);
+ class_addmethod(formant_class, (t_method)formant_central_freq, gensym("freq"), A_FLOAT, 0);
+ class_addmethod(formant_class, (t_method)formant_filter_width, gensym("fwidth"), A_FLOAT, 0);
+ class_addmethod(formant_class, (t_method)formant_skirt_width, gensym("swidth"), A_FLOAT, 0);
+ class_addmethod(formant_class, (t_method)formant_time_stretch, gensym("stretch"), A_FLOAT, 0);
+}
diff --git a/formant~/help-formant~.pd b/formant~/help-formant~.pd
new file mode 100644
index 0000000..c8102b4
--- /dev/null
+++ b/formant~/help-formant~.pd
@@ -0,0 +1,56 @@
+#N canvas 190 63 711 524 10;
+#X msg 172 385 \; pd dsp 1;
+#X msg 238 385 \; pd dsp 0;
+#X floatatom 150 58 10 0 0;
+#X floatatom 232 121 5 0 0;
+#X floatatom 190 93 5 0 0;
+#X floatatom 295 140 5 0 0;
+#X text 149 42 Size of the synthetized sound;
+#X text 189 78 Central frequency;
+#X text 232 104 Filter width;
+#X text 294 125 Skirt width ( "largeur de jupe" in french );
+#X msg 114 136 bang;
+#X text 99 13 Formant synthesis as described by JP Smets;
+#X floatatom 340 159 5 0 0;
+#X text 382 158 Time Stretch;
+#X obj 333 390 dac~;
+#X obj 303 244 delay 200;
+#X floatatom 364 244 5 0 0;
+#X obj 368 298 f;
+#X floatatom 367 343 5 0 0;
+#X obj 446 297 loadbang;
+#X text 323 217 Theoretically \, a singing voice is a combination of
+formants but you have to set right frequencies;
+#X msg 406 298 2500;
+#X obj 367 320 + 100;
+#X obj 121 263 formant~ 10000 2600 50 25;
+#X obj 303 263 formant~ 10000 1750 70 25;
+#X obj 199 319 formant~ 20000 4500 60 25;
+#X obj 466 263 formant~ 10000 1200 30 45;
+#X connect 2 0 23 1;
+#X connect 3 0 23 3;
+#X connect 4 0 23 2;
+#X connect 5 0 23 4;
+#X connect 10 0 15 0;
+#X connect 10 0 23 0;
+#X connect 10 0 26 0;
+#X connect 12 0 23 5;
+#X connect 15 0 24 0;
+#X connect 16 0 15 1;
+#X connect 17 0 22 0;
+#X connect 17 0 25 2;
+#X connect 19 0 21 0;
+#X connect 21 0 17 1;
+#X connect 22 0 17 1;
+#X connect 22 0 18 0;
+#X connect 23 0 14 0;
+#X connect 23 0 14 1;
+#X connect 23 1 17 0;
+#X connect 23 1 25 0;
+#X connect 24 0 14 1;
+#X connect 24 0 14 0;
+#X connect 25 0 14 1;
+#X connect 25 0 14 0;
+#X connect 25 1 10 0;
+#X connect 26 0 14 1;
+#X connect 26 0 14 0;
diff --git a/mp3amp~/CHANGES.LOG b/mp3amp~/CHANGES.LOG
new file mode 100644
index 0000000..ba7fb54
--- /dev/null
+++ b/mp3amp~/CHANGES.LOG
@@ -0,0 +1,15 @@
+0.12
+ suppress useless warnings
+0.11
+ read all headers before proceeding -- this fixes incomplete relocation too
+0.10
+ fixed a bug/crash when the relocation is incomplete
+0.9
+ fixed handling of frames ( never ignore any, silly me!!! )
+0.8
+ rename it from shoutamp~ to mp3amp~
+0.7y
+ fixed resampling
+ fixed urls parsing
+0.6y and before
+ sorry N/A
diff --git a/mp3amp~/INSTALL b/mp3amp~/INSTALL
new file mode 100644
index 0000000..8260a98
--- /dev/null
+++ b/mp3amp~/INSTALL
@@ -0,0 +1,19 @@
+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/mp3amp~
+
+make clean
+
+make
+
+make install
+
+thanks for getting here.
+
+Yves/
diff --git a/mp3amp~/Makefile b/mp3amp~/Makefile
new file mode 100644
index 0000000..dda8e3c
--- /dev/null
+++ b/mp3amp~/Makefile
@@ -0,0 +1,82 @@
+NAME=mp3amp~
+CSYM=mp3amp_tilde
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).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
+
+.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
+
+.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
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -DUNIX -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch -g
+
+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 $*/$*.pd_linux ..
+
+# ----------------------------------------------------------
+
+install:
+ cp help-*.pd ../../doc/5.reference
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/mp3amp~/README b/mp3amp~/README
new file mode 100644
index 0000000..4ab73ee
--- /dev/null
+++ b/mp3amp~/README
@@ -0,0 +1,45 @@
+Version 0.01
+copyright (c) 2001 by Olaf Matthes & Yves Degoyon
+
+mp3amp~ is a MPEG I Layer III (mp3) icecast/shoutcast client for Pure Data
+
+To install mp3amp~, 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.
+
+*****************************************************************************
+
+mp3amp~ 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.
+
+*****************************************************************************
+
+ using mp3amp~ external for Pure Data
+
+Open the help-mp3amp~.pd to understand how it works.
+Open the help-graphic-mp3amp~.pd if you want to see the status of the incoming stream.
+
+BUGS :
+
+a/ certainly, not all bitrates will work,
+that's too tedious to test, 128, 256, 320 are ok.
+
+b/ cannot instantiate more than 10 decoders, if needed change MAX_DECODERS in the code
+
+c/ this is beta, be patient !!! bugs report welcome !!!
diff --git a/mp3amp~/help-graphic-mp3amp~.pd b/mp3amp~/help-graphic-mp3amp~.pd
new file mode 100644
index 0000000..241a607
--- /dev/null
+++ b/mp3amp~/help-graphic-mp3amp~.pd
@@ -0,0 +1,52 @@
+#N canvas 171 33 789 555 10;
+#X obj 115 265 dac~;
+#X floatatom 164 265 5 0 0;
+#X msg 29 150 disconnect;
+#X text 208 267 connection status;
+#X obj 458 48 loadbang;
+#X msg 458 71 \; pd dsp 1;
+#X msg 99 76 connect yves puredata 8000;
+#X text 96 55 connect <host> <mountpoint> <port>;
+#X text 38 18 constructor : mp3amp~ <graphic flag = 0 | 1>;
+#X text 151 127 connect to SHOUTcast server;
+#X msg 157 145 connect localhost listen.pls 8000;
+#X msg 176 165 connect localhost content/scpromo.mp3 8000;
+#X text 399 141 <-- play livestream;
+#X text 479 165 <-- play file;
+#X msg 121 99 connect localhost kas 8000;
+#X text 97 44 connect to ICEcast server;
+#X text 38 7 mp3amp~ : an icecast/shoucast client for PD;
+#X text 226 186 Another way of connecting;
+#X msg 226 205 connecturl http://localhost:8000/kas;
+#X msg 31 374 standby 0;
+#X text 114 380 for CPU load reasons \,;
+#X text 115 392 ability to freeze decoding;
+#X text 114 405 ( packets are read and ignored );
+#X msg 31 399 standby 1;
+#X obj 115 196 mp3amp~ 1;
+#X msg 353 230 connecturl http://216.235.81.7:20690/play?session=panjabiradio:0&amp\;lid=-1-fra&amp\;SaneID=212.198.0.97-1030988754258
+;
+#X msg 352 280 connecturl http://213.197.144.44:8000/;
+#X msg 352 334 connecturl http://24.207.26.60:8000/;
+#X msg 354 307 connecturl http://64.113.197.158:8000/;
+#X msg 352 361 connecturl http://liveice.agria.hu:8000/radioeger-hq
+;
+#X text 406 511 Authors : Yves Degoyon ( ydegoyon@free.fr );
+#X connect 2 0 24 0;
+#X connect 4 0 5 0;
+#X connect 6 0 24 0;
+#X connect 10 0 24 0;
+#X connect 11 0 24 0;
+#X connect 14 0 24 0;
+#X connect 18 0 24 0;
+#X connect 19 0 24 0;
+#X connect 23 0 24 0;
+#X connect 24 0 0 0;
+#X connect 24 0 0 1;
+#X connect 24 1 0 1;
+#X connect 24 2 1 0;
+#X connect 25 0 24 0;
+#X connect 26 0 24 0;
+#X connect 27 0 24 0;
+#X connect 28 0 24 0;
+#X connect 29 0 24 0;
diff --git a/mp3amp~/help-mp3amp~.pd b/mp3amp~/help-mp3amp~.pd
new file mode 100644
index 0000000..47249b7
--- /dev/null
+++ b/mp3amp~/help-mp3amp~.pd
@@ -0,0 +1,53 @@
+#N canvas 125 102 789 555 10;
+#X obj 115 265 dac~;
+#X floatatom 164 265 5 0 0;
+#X msg 29 150 disconnect;
+#X text 208 267 connection status;
+#X obj 458 48 loadbang;
+#X msg 458 71 \; pd dsp 1;
+#X msg 99 76 connect yves puredata 8000;
+#X text 96 55 connect <host> <mountpoint> <port>;
+#X text 38 18 constructor : mp3amp~ <graphic flag = 0 | 1>;
+#X text 151 127 connect to SHOUTcast server;
+#X msg 157 145 connect localhost listen.pls 8000;
+#X msg 176 165 connect localhost content/scpromo.mp3 8000;
+#X text 399 141 <-- play livestream;
+#X text 479 165 <-- play file;
+#X msg 121 99 connect localhost kas 8000;
+#X text 97 44 connect to ICEcast server;
+#X text 38 7 mp3amp~ : an icecast/shoucast client for PD;
+#X text 226 186 Another way of connecting;
+#X msg 226 205 connecturl http://localhost:8000/kas;
+#X msg 31 374 standby 0;
+#X text 114 380 for CPU load reasons \,;
+#X text 115 392 ability to freeze decoding;
+#X text 114 405 ( packets are read and ignored );
+#X msg 31 399 standby 1;
+#X msg 353 230 connecturl http://216.235.81.7:20690/play?session=panjabiradio:0&amp\;lid=-1-fra&amp\;SaneID=212.198.0.97-1030988754258
+;
+#X msg 352 280 connecturl http://213.197.144.44:8000/;
+#X msg 352 334 connecturl http://24.207.26.60:8000/;
+#X msg 354 307 connecturl http://64.113.197.158:8000/;
+#X msg 352 361 connecturl http://liveice.agria.hu:8000/radioeger-hq
+;
+#X text 406 511 Authors : Yves Degoyon ( ydegoyon@free.fr );
+#X obj 115 196 mp3amp~;
+#X msg 354 384 connecturl http://www.deliciound.net:8000/;
+#X connect 2 0 30 0;
+#X connect 4 0 5 0;
+#X connect 6 0 30 0;
+#X connect 10 0 30 0;
+#X connect 11 0 30 0;
+#X connect 14 0 30 0;
+#X connect 18 0 30 0;
+#X connect 19 0 30 0;
+#X connect 23 0 30 0;
+#X connect 24 0 30 0;
+#X connect 25 0 30 0;
+#X connect 26 0 30 0;
+#X connect 27 0 30 0;
+#X connect 28 0 30 0;
+#X connect 30 0 0 0;
+#X connect 30 1 0 1;
+#X connect 30 2 1 0;
+#X connect 31 0 30 0;
diff --git a/mp3amp~/interface.h b/mp3amp~/interface.h
new file mode 100644
index 0000000..de3136a
--- /dev/null
+++ b/mp3amp~/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/mp3amp~/mp3amp~.c b/mp3amp~/mp3amp~.c
new file mode 100644
index 0000000..e29c240
--- /dev/null
+++ b/mp3amp~/mp3amp~.c
@@ -0,0 +1,1255 @@
+/* ------------------------- mp3amp~ ------------------------------------------ */
+/* */
+/* Tilde object to receive an mp3-stream from a shoutcast/icecast server. */
+/* Written by Yves Degoyon (ydegoyon@free.fr). */
+/* Get source at http://ydegoyon.free.fr */
+/* */
+/* This library is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU Lesser General Public */
+/* License as published by the Free Software Foundation; either */
+/* version 2 of the License, or (at your option) any later version. */
+/* */
+/* This library 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 */
+/* Lesser General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU Lesser General Public */
+/* License along with this library; 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 which can be found at */
+/* http://www.mp3dev.org */
+/* */
+/* ---------------------------------------------------------------------------- */
+
+
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "pthread.h"
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.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 */
+#ifdef UNIX
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#define SOCKET_ERROR -1
+#else
+#include <winsock.h>
+#endif
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+#ifdef UNIX
+#define STRDUP strdup
+#endif
+#ifdef NT
+#define STRDUP _strdup
+#endif
+
+#define LAME_AUDIO_CHUNK_SIZE 1152
+#define MIN_AUDIO_INPUT 2*LAME_AUDIO_CHUNK_SIZE /* we must have at least n chunks to play a steady sound */
+#define INPUT_BUFFER_SIZE 131072 /* data received on the socket : 128k */
+#define OUTPUT_BUFFER_SIZE 131072 /* audio output buffer : 128k */
+#define DECODE_PACKET_SIZE 131072 /* size of the data returned by mpglib : 128k */
+#define STRBUF_SIZE 4096 /* char received from server on startup */
+#define MAX_DECODERS 50
+#define BARHEIGHT 10
+
+static int guidebug=0;
+
+#define SYS_VGUI2(a,b) if (guidebug) \
+ post(a,b);\
+ sys_vgui(a,b)
+
+#define SYS_VGUI3(a,b,c) if (guidebug) \
+ post(a,b,c);\
+ sys_vgui(a,b,c)
+
+#define SYS_VGUI4(a,b,c,d) if (guidebug) \
+ post(a,b,c,d);\
+ sys_vgui(a,b,c,d)
+
+#define SYS_VGUI5(a,b,c,d,e) if (guidebug) \
+ post(a,b,c,d,e);\
+ sys_vgui(a,b,c,d,e)
+
+#define SYS_VGUI6(a,b,c,d,e,f) if (guidebug) \
+ post(a,b,c,d,e,f);\
+ sys_vgui(a,b,c,d,e,f)
+
+#define SYS_VGUI7(a,b,c,d,e,f,g) if (guidebug) \
+ post(a,b,c,d,e,f,g );\
+ sys_vgui(a,b,c,d,e,f,g)
+
+#define SYS_VGUI8(a,b,c,d,e,f,g,h) if (guidebug) \
+ post(a,b,c,d,e,f,g,h );\
+ sys_vgui(a,b,c,d,e,f,g,h)
+
+#define SYS_VGUI9(a,b,c,d,e,f,g,h,i) if (guidebug) \
+ post(a,b,c,d,e,f,g,h,i );\
+ sys_vgui(a,b,c,d,e,f,g,h,i)
+
+
+ /* 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 );
+
+static char *mp3amp_version = "mp3amp~: mp3 streaming client v0.12, written by Yves Degoyon";
+
+/* ------------------------ mp3amp~ ----------------------------- */
+
+static t_class *mp3amp_class;
+
+/* too bad, this needs to be static,
+ handling an array to enable several decoders in pd */
+static MPSTR mps[MAX_DECODERS]; /* decoder buffer */
+static int nbinstances = 0;
+
+extern const long freqs[9];
+
+/* time-out used for select() call */
+static struct timeval ztout;
+
+typedef struct _mp3amp
+{
+ t_object x_obj;
+ t_int x_instance; /* instance of the object */
+ t_outlet *x_connection;
+ t_int x_fd; /* the socket number */
+ t_int x_inframes; /* number of waiting frames */
+ t_int x_dframes; /* displayed frames 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 */
+ t_canvas *x_canvas; /* remember canvas */
+ t_int x_nbwaitloops; /* number of loops to wait */
+ t_int x_nbloops; /* number of loops processed */
+ t_int x_blocksize; /* size of a dsp block */
+ t_int x_resample; /* resampling factor (pd's sr / stream sr) */
+ t_int x_dsp; /* number of dsp calls, used to measure time */
+ t_int x_standby; /* flag to freeze decoding */
+ t_int x_nooutput; /* flag to avoid output of connection state */
+
+#ifdef UNIX
+ unsigned char *x_inbuffer; /* accumulation buffer for incoming mp3 frames */
+#else
+ char *x_inbuffer; /* accumulation buffer for incoming mp3 frames */
+#endif
+
+ t_int x_inwriteposition;
+ t_int x_inbuffersize;
+ t_int x_offset; /* offset used for start of decoding */
+
+ 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;
+ char x_out[DECODE_PACKET_SIZE];
+
+ /* mp3 stuff */
+ t_int x_samplerate;
+ t_int x_bitrate; /* bitrate of mp3 stream read at connection time */
+ t_int x_bitrateindex; /* bitrate index for each frame, might change dynamically */
+ t_int x_mp3mode; /* mode (mono, joint stereo, stereo, dual mono) */
+ char* x_bcname; /* name of broadcast */
+ char* x_bcurl; /* url of broadcast */
+ char* x_bcgenre; /* genre of broadcast */
+ char* x_bcaim; /* aim of broadcast */
+ char* x_mountpoint; /* mountpoint for IceCast server */
+ char* x_hostname; /* hostname to connect to */
+ t_int x_port; /* port number to connect to */
+
+ t_int x_stream; /* indicates if a stream is connected ( meaning correct input flow ) */
+} t_mp3amp;
+
+static void mp3amp_recv(t_mp3amp *x);
+static void mp3amp_disconnect(t_mp3amp *x);
+static void mp3amp_connect_url(t_mp3amp *x, t_symbol *url);
+
+static int strip_shout_header(char *head, int n)
+{
+ int i;
+ for (i = 0; i < (n - 2); i++)
+ {
+ if (head[i] == 10 && head[i + 1] == 13)
+ break;
+ if (head[i] == '\n' && head[i + 1] == '\n')
+ break;
+ }
+ head[i + 1] = '\0';
+ return n - (i + 1);
+}
+
+static int strip_ice_header(char *head, int n)
+{
+ int i;
+ for (i = 0; i < (n - 2); i++)
+ {
+ if ((head[i] == '\n') && (head[i + 1] == '\n'))
+ break;
+ }
+ head[i + 1] = '\0';
+ return n - (i + 1);
+}
+
+static void mp3amp_tilde_mpglib_init(t_mp3amp *x)
+{
+ int ret;
+
+ InitMP3(&mps[x->x_instance]);
+}
+
+static int mp3amp_decode_input(t_mp3amp *x)
+{
+ t_int i;
+ t_int alength = 0;
+ float resample = 0;
+ struct frame hframe;
+ unsigned int a,b,c,d;
+ unsigned long cheader;
+ signed short int *p = (signed short int *) x->x_out;
+ t_int pbytes;
+ t_int ret, totlength=0;
+ t_int pframes = 0;
+
+ x->x_offset=0;
+ // search for an header to check dynamic bitrate
+ while ( x->x_offset < x->x_inwriteposition )
+ {
+ /* decode first 4 bytes as the header */
+ a = *((unsigned char*)x->x_inbuffer+x->x_offset);
+ b = *((unsigned char*)x->x_inbuffer+x->x_offset+1);
+ c = *((unsigned char*)x->x_inbuffer+x->x_offset+2);
+ d = *((unsigned char*)x->x_inbuffer+x->x_offset+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 );
+ if ( hframe.framesize == 0 )
+ {
+ post( "mp3amp~: weird header ( frame size = 0 ) .... ignored" );
+ x->x_offset++;
+ continue;
+ }
+ x->x_packetsize = hframe.framesize;
+ // print_header_compact( &hframe );
+ // when the bitrate change, reinit decoder
+ if ( x->x_bitrateindex != hframe.bitrate_index )
+ {
+ post( "mp3amp~: bitrate has changed, reinitialize decoder" );
+ ExitMP3(&mps[x->x_instance]);
+ InitMP3(&mps[x->x_instance]);
+ x->x_bitrateindex = hframe.bitrate_index;
+ }
+ break;
+ }
+ x->x_offset++;
+ }
+
+ if ( x->x_inframes > 0 )
+ {
+
+ ret = decodeMP3(&mps[x->x_instance], (unsigned char*)(x->x_inbuffer+x->x_offset),
+ hframe.framesize+sizeof( unsigned long), (char *) p, sizeof(x->x_out), &pbytes);
+
+ switch (ret)
+ {
+ case MP3_OK:
+ switch (mps[x->x_instance].fr.stereo) {
+ case 1:
+ case 2:
+ alength = ((mps[x->x_instance].fr.stereo==1)?pbytes >> 1 : pbytes >> 2);
+ // post( "mp3amp~: stereo : %d", mps[x->x_instance].fr.stereo );
+ // update outbuffer contents
+ for ( i=0; i<alength; i++ )
+ {
+ if ( x->x_outunread >= x->x_outbuffersize-2 )
+ {
+ // post( "mp3amp~: decode : 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) =
+ ((mps[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("mp3amp~: stream connected" );
+ x->x_resample = x->x_samplerate / freqs[hframe.sampling_frequency];
+ if ( x->x_resample == 0 ) x->x_resample=1;
+ post("mp3amp~: resampling stream from %d to %d Hz (r=%d)",
+ freqs[hframe.sampling_frequency], x->x_samplerate, x->x_resample );
+ x->x_stream = 1;
+ }
+ }
+ break;
+ default:
+ alength = -1;
+ break;
+ }
+ // roll buffer
+ if ( x->x_inwriteposition > hframe.framesize+ (int) sizeof( unsigned long ) + x->x_offset )
+ // ^----- maybe the frame is not complete
+ {
+ x->x_inwriteposition -= hframe.framesize+sizeof( unsigned long )+x->x_offset;
+ memcpy( (void *)(x->x_inbuffer),
+ (void *)(x->x_inbuffer+x->x_offset+hframe.framesize+sizeof( unsigned long )),
+ x->x_inwriteposition);
+ x->x_offset = 0;
+ // post ( "mp3amp~: decoded frame %d", x->x_inframes );
+ x->x_inframes--;
+ pframes++;
+ }
+ else // sorry, it will be ignored
+ {
+ // error( "mp3amp~: incomplete frame...ignored");
+ // x->x_offset = 0;
+ // x->x_inwriteposition = 0;
+ // x->x_inframes = 0;
+ }
+
+ totlength += alength;
+ break;
+
+ case MP3_NEED_MORE:
+ if ( mps[x->x_instance].framesize == 0 && mps[x->x_instance].fsizeold != 0 )
+ {
+ post( "mp3amp~: decoding done (totlength=%d).", totlength );
+ }
+ else
+ {
+ post( "mp3amp~: retry lame decoding (more data needed)." );
+ return -1;
+ }
+ break;
+
+ case MP3_ERR:
+ post( "mp3amp~: lame decoding failed." );
+ return ret;
+ break;
+
+ }
+
+ }
+
+ if ( x->x_graphic && glist_isvisible( x->x_canvas ) )
+ {
+ /* update graphical read status */
+ if ( x->x_inframes != x->x_dframes )
+ {
+ char color[32];
+ t_int width;
+
+ width = rtext_width( glist_findrtext( (t_glist*)x->x_canvas, (t_text *)x ) );
+ SYS_VGUI3(".x%x.c delete rectangle %xSTATUS\n", x->x_canvas, x );
+ if ( x->x_inframes < (MIN_AUDIO_INPUT/LAME_AUDIO_CHUNK_SIZE) )
+ {
+ strcpy( color, "red" );
+ }
+ else
+ {
+ strcpy( color, "lightgreen" );
+ }
+ SYS_VGUI8(".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_inwriteposition*width)/INPUT_BUFFER_SIZE,
+ x->x_obj.te_ypix - 1, color, x );
+ x->x_dframes = x->x_inframes;
+ }
+ }
+ return totlength;
+}
+
+static void mp3amp_recv(t_mp3amp *x)
+{
+ int ret, i;
+ float resample = 0;
+ struct frame hframe;
+ unsigned int a,b,c,d;
+ unsigned long cheader;
+
+#ifdef UNIX
+ if ( ( ret = recv(x->x_fd, (void*) (x->x_inbuffer + x->x_inwriteposition),
+ (size_t)((x->x_inbuffersize-x->x_inwriteposition)),
+ MSG_NOSIGNAL) ) < 0 )
+#else
+ if(( ret = recv(x->x_fd, (char*)x->x_inbuffer + x->x_inwriteposition,
+ (x->x_inbuffersize-x->x_inwriteposition), 0)) < 0)
+#endif
+ {
+ post( "mp3amp~: receive error" );
+#ifdef UNIX
+ perror( "recv" );
+#endif
+ mp3amp_disconnect(x);
+ return;
+ }
+ else
+ {
+
+ // post( "mp3amp~: received %d bytes at %d on %d ( up to %d)",
+ // ret, x->x_inwriteposition, x->x_fd,
+ // x->x_inbuffersize-x->x_inwriteposition );
+
+ if ( ret == 0 && ( x->x_inbuffersize-x->x_inwriteposition != 0 ) )
+ {
+ error("mp3amp~: stream lost...");
+ mp3amp_disconnect(x);
+ }
+ else
+ {
+ // check if we should decode those packets
+ if ( x->x_standby )
+ {
+ return;
+ }
+ // check we don't overflow input buffer
+ if ( ( x->x_inwriteposition + ret ) > x->x_inbuffersize*0.9 )
+ {
+ post( "mp3streamin~ : too much input...resetting" );
+ x->x_inwriteposition=0;
+ x->x_offset = 0;
+ x->x_inframes = 0;
+ return;
+ }
+ x->x_inwriteposition += ret;
+ x->x_offset = 0;
+ // check some parameters in the stream
+ while ( x->x_offset < x->x_inwriteposition )
+ {
+ /* decode first 4 bytes as the header */
+ a = *((unsigned char*)x->x_inbuffer+x->x_offset);
+ b = *((unsigned char*)x->x_inbuffer+x->x_offset+1);
+ c = *((unsigned char*)x->x_inbuffer+x->x_offset+2);
+ d = *((unsigned char*)x->x_inbuffer+x->x_offset+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_packetsize = hframe.framesize;
+ if ( hframe.framesize == 0 )
+ {
+ post( "mp3amp~: weird header ( frame size = 0 ) .... ignored" );
+ x->x_inwriteposition -= ret;
+ return;
+ }
+ x->x_inframes += ret/x->x_packetsize;
+ // post( "mp3amp~: nb frames %d", x->x_inframes );
+ break;
+ }
+ x->x_offset++;
+ }
+ }
+ }
+}
+
+static t_int *mp3amp_perform(t_int *w)
+{
+ t_mp3amp *x = (t_mp3amp*) (w[1]);
+ t_float *out1 = (t_float *)(w[2]);
+ t_float *out2 = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ int ret;
+ int i = 0;
+
+ x->x_blocksize = n;
+ x->x_nbwaitloops = LAME_AUDIO_CHUNK_SIZE/x->x_blocksize;
+ // post( "mp3mp3amp~ : will wait %d loops", x->x_nbwaitloops );
+ x->x_dsp++;
+
+ while( n-- )
+ {
+ if(x->x_stream && !x->x_standby ) // check that the stream provides enough data
+ {
+ if(x->x_resample == 1) /* don't need to resample */
+ {
+ *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;
+ }
+ else
+ { /* we just use the same sample x->x_resample times */
+ *out1++=*(x->x_outbuffer+x->x_outreadposition);
+ *out2++=*(x->x_outbuffer+((x->x_outreadposition + 1)%x->x_outbuffersize));
+ if((n%x->x_resample)== 0)
+ {
+ x->x_outreadposition = (x->x_outreadposition + 2)%x->x_outbuffersize;
+ x->x_outunread-=2;
+ }
+ }
+ if ( n == 1 ) x->x_pblocks++;
+ }
+ else
+ {
+ *out1++=0.0;
+ *out2++=0.0;
+ }
+ }
+
+ if ( x->x_pblocks == LAME_AUDIO_CHUNK_SIZE/x->x_blocksize )
+ {
+ x->x_pblocks = 0;
+ }
+
+ /* check for readability, then fill the input buffer */
+ if(( x->x_fd > 0 )&&(x->x_dsp >= 16)) /* determine how often we try to read */
+ {
+ fd_set readset;
+ fd_set exceptset;
+
+ FD_ZERO(&readset);
+ FD_ZERO(&exceptset);
+ FD_SET(x->x_fd, &readset );
+ FD_SET(x->x_fd, &exceptset );
+
+ x->x_dsp = 0;
+
+ if ( select( x->x_fd+1, &readset, NULL, &exceptset, &ztout ) >0 )
+ {
+ if ( FD_ISSET( x->x_fd, &readset) || FD_ISSET( x->x_fd, &exceptset ) )
+ {
+ /* receive data or error */
+ mp3amp_recv(x);
+ }
+ }
+ }
+
+ // check new incoming data
+ if ( x->x_fd > 0 && ( x->x_nbloops == 0 ) && ( x->x_inframes > 0 ) && ( !x->x_standby ) )
+ {
+ mp3amp_decode_input(x);
+ }
+ if ( x->x_nbwaitloops != 0 )
+ {
+ x->x_nbloops = (x->x_nbloops+1 ) % x->x_nbwaitloops;
+ }
+ return (w+5);
+}
+
+static void mp3amp_dsp(t_mp3amp *x, t_signal **sp)
+{
+ dsp_add(mp3amp_perform, 4, x, sp[1]->s_vec, sp[2]->s_vec, sp[1]->s_n);
+}
+
+
+ /* freeze decoding */
+static void mp3amp_standby(t_mp3amp *x, t_floatarg fstandby )
+{
+ if ( fstandby == 0. )
+ {
+ x->x_standby = 0;
+ }
+ else
+ {
+ x->x_standby = 1;
+ }
+}
+
+ /* connection main procedure executed by a thread */
+static void *mp3amp_do_connect(void *tdata )
+{
+ t_mp3amp *x = (t_mp3amp*) tdata;
+ struct sockaddr_in server;
+ struct hostent *hp;
+ t_int portno = x->x_port; /* get port from message box */
+
+ /* variables used for communication with server */
+ char *sptr = NULL;
+ char request[STRBUF_SIZE]; /* string to be send to server */
+ char *url; /* used for relocation */
+ fd_set fdset;
+ struct timeval tv;
+ t_int sockfd; /* socket to server */
+ t_int relocate, numrelocs = 0;
+ t_int i, ret, rest, nanswers=0;
+ char *cpoint = NULL;
+ t_int offset = 0, endofheaders = 0;
+
+ if (x->x_fd >= 0)
+ {
+ error("mp3amp~: already connected");
+ return NULL;
+ }
+
+ sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sockfd < 0)
+ {
+ error("mp3amp~: internal error while attempting to open socket");
+ return NULL;
+ }
+
+ /* connect socket using hostname provided in command line */
+ server.sin_family = AF_INET;
+ hp = gethostbyname(x->x_hostname);
+ if (hp == 0)
+ {
+ post("mp3amp~: bad host?");
+ sys_closesocket(sockfd);
+ return NULL;
+ }
+ memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
+
+ /* assign client port number */
+ server.sin_port = htons((unsigned short)portno);
+
+ /* try to connect. */
+ post("mp3amp~: connecting to http:/%s:%d/%s", x->x_hostname, x->x_port, x->x_mountpoint );
+ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
+ {
+ error("mp3amp~: connection failed!\n");
+ sys_closesocket(sockfd);
+ return NULL;
+ }
+ post("mp3amp~: connected : socket opened" );
+
+ /* sheck if we can read/write from/to the socket */
+ FD_ZERO( &fdset);
+ FD_SET( sockfd, &fdset);
+ tv.tv_sec = 0; /* seconds */
+ tv.tv_usec = 500; /* microseconds */
+
+ ret = select(sockfd + 1, &fdset, NULL, NULL, &tv);
+ if(ret != 0)
+ {
+ error("mp3amp~: can not read from socket");
+ sys_closesocket(sockfd);
+ return NULL;
+ }
+ post("mp3amp~: select done" );
+
+ /* check mountpoint */
+ if( strstr(x->x_mountpoint, "listen.pls") )
+ { /* SHOUTcast playlist -> get / */
+ x->x_mountpoint = "";
+ }
+
+ /* build up stuff we need to send to server */
+ sprintf(request, "GET /%s HTTP/1.0 \r\nHost: %s\r\nUser-Agent: mp3amp~ 0.11\r\nAccept: */*\r\n\r\n",
+ x->x_mountpoint, x->x_hostname);
+
+ if ( send(sockfd, request, strlen(request), 0) < 0 ) /* say hello to server */
+ {
+ post( "mp3amp~: could not contact server... " );
+#ifdef UNIX
+ perror( "send" );
+#endif
+ return NULL;
+ }
+ post("mp3amp~: send done" );
+
+ relocate = FALSE;
+ memset( request, 0x00, STRBUF_SIZE );
+
+ // read all the answer
+ endofheaders=0;
+ while ( !endofheaders )
+ {
+ if( ( ret = recv(sockfd, request+offset, STRBUF_SIZE, MSG_NOSIGNAL) ) <0)
+ {
+ error("mp3amp~: no response from server");
+#ifdef UNIX
+ perror( "recv" );
+#endif
+ return NULL;
+ }
+ post ( "mp3amp~ : received %d bytes at %d", ret, offset );
+ for ( i=offset; i<offset+ret-1; i++ )
+ {
+ if ( ( request[i] == '\n' && request[i+1] == '\n' ) ||
+ ( request[i] == 10 && request[i+1] == 13 ) )
+ {
+ endofheaders=1;
+ }
+ }
+ offset+=ret;
+ }
+
+ // time to parse content of the response...
+ if ( strstr(request, "audio/x-scpls") ) /* SHOUTcast playlist */
+ {
+ /* playlist playing not supported */
+ post("mp3amp~: SHOUTcast server returned a playlist, quitting");
+ sys_closesocket(sockfd);
+ return NULL;
+ }
+ if ( strstr(request, "HTTP") ) /* seems to be IceCast server */
+ {
+ strip_ice_header(request, STRBUF_SIZE);
+ if(sptr = strstr(request, "302"))
+ {
+ cpoint = NULL;
+ cpoint = strstr(request, "Location:");
+ if ( cpoint == NULL )
+ {
+ post( "mp3amp~ : stream has moved but couldn't find new location out of this :" );
+ post("mp3amp~: %s", request );
+ return NULL;
+ }
+ url = STRDUP(cpoint + 10);
+ post("mp3amp~: relocating to %s", url);
+ sys_closesocket(sockfd);
+ x->x_nooutput = 1;
+ mp3amp_connect_url(x, gensym(url));
+ x->x_nooutput = 0;
+ return NULL;
+ // relocate = TRUE;
+ }
+ if( !(sptr = strstr(request, "200")) && !relocate )
+ {
+ error("mp3amp~: cannot connect to the (default) stream");
+ return NULL;
+ }
+
+ post("mp3amp~: IceCast server detected");
+
+ // post("mp3amp~: server's header : %s", request );
+
+ // check what we got
+ if( cpoint = strstr(request, "x-audiocast-mount:"))
+ {
+ x->x_mountpoint = STRDUP(cpoint + 18);
+ for ( i=0; i<(int)strlen(x->x_mountpoint); i++ )
+ {
+ if ( x->x_mountpoint[i] == '\n' )
+ {
+ x->x_mountpoint[i] = '\0';
+ break;
+ }
+ }
+ post(" mountpoint: %s", x->x_mountpoint);
+ }
+ if( cpoint = strstr(request, "x-audiocast-server-url:"))
+ {
+ sptr = STRDUP( cpoint + 24);
+ for ( i=0; i<(int)strlen(sptr); i++ )
+ {
+ if ( sptr[i] == '\n' )
+ {
+ sptr[i] = '\0';
+ break;
+ }
+ }
+ post(" server-url: %s", sptr);
+ }
+ if( cpoint = strstr(request, "x-audiocast-location:"))
+ {
+ sptr = STRDUP( cpoint + 22);
+ for ( i=0; i<(int)strlen(sptr); i++ )
+ {
+ if ( sptr[i] == '\n' )
+ {
+ sptr[i] = '\0';
+ break;
+ }
+ }
+ post(" location: %s", sptr);
+ }
+ if( cpoint = strstr(request, "x-audiocast-admin:"))
+ {
+ sptr = STRDUP( cpoint + 19);
+ for ( i=0; i<(int)strlen(sptr); i++ )
+ {
+ if ( sptr[i] == '\n' )
+ {
+ sptr[i] = '\0';
+ break;
+ }
+ }
+ post(" admin: %s", sptr);
+ }
+ if( cpoint = strstr(request, "x-audiocast-name:"))
+ {
+ x->x_bcname = STRDUP( cpoint + 17);
+ for ( i=0; i<(int)strlen(x->x_bcname); i++ )
+ {
+ if ( x->x_bcname[i] == '\n' )
+ {
+ x->x_bcname[i] = '\0';
+ break;
+ }
+ }
+ post(" name: %s", x->x_bcname);
+ }
+ if( cpoint = strstr(request, "x-audiocast-genre:"))
+ {
+ x->x_bcgenre = STRDUP( cpoint + 18);
+ for ( i=0; i<(int)strlen(x->x_bcgenre); i++ )
+ {
+ if ( x->x_bcgenre[i] == '\n' )
+ {
+ x->x_bcgenre[i] = '\0';
+ break;
+ }
+ }
+ post(" genre: %s", x->x_bcgenre);
+ }
+ if( cpoint = strstr(request, "x-audiocast-url:"))
+ {
+ x->x_bcurl = STRDUP( cpoint + 16);
+ for ( i=0; i<(int)strlen(x->x_bcurl); i++ )
+ {
+ if ( x->x_bcurl[i] == '\n' )
+ {
+ x->x_bcurl[i] = '\0';
+ break;
+ }
+ }
+ post(" url: %s", x->x_bcurl);
+ }
+ if( cpoint = strstr(request, "x-audiocast-public:1"))
+ {
+ post(" broadcast is public");
+ }
+ else if( cpoint = strstr(request, "x-audiocast-public:0"))
+ {
+ post(" broadcast is NOT public");
+ }
+ if( cpoint = strstr(request, "x-audiocast-bitrate:"))
+ {
+ sptr = STRDUP( cpoint + 20);
+ for ( i=0; i<(int)strlen(sptr); i++ )
+ {
+ if ( sptr[i] == '\n' )
+ {
+ sptr[i] = '\0';
+ break;
+ }
+ }
+ if(!strncmp(sptr, "320", 3))x->x_bitrate = 320;
+ else if(!strncmp(sptr, "256", 3))x->x_bitrate = 256;
+ else if(!strncmp(sptr, "224", 3))x->x_bitrate = 224;
+ else if(!strncmp(sptr, "192", 3))x->x_bitrate = 192;
+ else if(!strncmp(sptr, "160", 3))x->x_bitrate = 160;
+ else if(!strncmp(sptr, "144", 3))x->x_bitrate = 144;
+ else if(!strncmp(sptr, "128", 3))x->x_bitrate = 128;
+ else if(!strncmp(sptr, "112", 3))x->x_bitrate = 112;
+ else if(!strncmp(sptr, "96", 2))x->x_bitrate = 96;
+ else if(!strncmp(sptr, "80", 2))x->x_bitrate = 80;
+ else if(!strncmp(sptr, "64", 2))x->x_bitrate = 64;
+ else if(!strncmp(sptr, "56", 2))x->x_bitrate = 56;
+ else if(!strncmp(sptr, "48", 2))x->x_bitrate = 48;
+ else if(!strncmp(sptr, "40", 2))x->x_bitrate = 40;
+ else if(!strncmp(sptr, "32", 2))x->x_bitrate = 32;
+ else if(!strncmp(sptr, "24", 2))x->x_bitrate = 24;
+ else if(!strncmp(sptr, "16", 2))x->x_bitrate = 16;
+ else if(!strncmp(sptr, "8", 1))x->x_bitrate = 8;
+ else
+ {
+ post("mp3amp~: unsupported bitrate! : %s", sptr);
+ return NULL;
+ }
+ post(" bitrate: %d", x->x_bitrate);
+ }
+ if( cpoint = strstr(request, "x-audiocast-udpport:"))
+ {
+ post("mp3amp~: sorry, server wants UDP connection!");
+ return NULL;
+ }
+ }
+ else /* it is a SHOUTcast server */
+ {
+ strip_shout_header (request, STRBUF_SIZE);
+ post("mp3amp~: SHOUTcast server detected");
+ if(strstr(request, "ICY 401") != 0)
+ {
+ post("mp3amp~: ICY 401 Service Unavailable");
+ return NULL;
+ }
+ if (strstr(request, "ICY 200 OK"))
+ {
+ /* recv and decode info about broadcast line by line */
+ post("mp3amp~: connecting to stream...");
+ i = ret;
+ /* check what we got */
+
+ if( cpoint = strstr(request, "icy-name:"))
+ {
+ x->x_bcname = STRDUP( cpoint + 10);
+ for ( i=0; i<(int)strlen(x->x_bcname); i++ )
+ {
+ if ( x->x_bcname[i] == '\n' )
+ {
+ x->x_bcname[i] = '\0';
+ break;
+ }
+ }
+ post(" name: %s", x->x_bcname);
+ }
+ if( cpoint = strstr(request, "x-audiocast-name:"))
+ {
+ x->x_bcname = STRDUP( cpoint + 18);
+ for ( i=0; i<(int)strlen(x->x_bcname); i++ )
+ {
+ if ( x->x_bcname[i] == '\n' )
+ {
+ x->x_bcname[i] = '\0';
+ break;
+ }
+ }
+ post(" name: %s", x->x_bcname);
+ }
+ if( cpoint = strstr(request, "icy-genre:"))
+ {
+ x->x_bcgenre = STRDUP( cpoint + 10);
+ for ( i=0; i<(int)strlen(x->x_bcgenre); i++ )
+ {
+ if ( x->x_bcgenre[i] == '\n' )
+ {
+ x->x_bcgenre[i] = '\0';
+ break;
+ }
+ }
+ post(" name: %s", x->x_bcname);
+ }
+ if( cpoint = strstr(request, "icy-aim:"))
+ {
+ x->x_bcaim = STRDUP( cpoint + 8);
+ for ( i=0; i<(int)strlen(x->x_bcaim); i++ )
+ {
+ if ( x->x_bcaim[i] == '\n' )
+ {
+ x->x_bcaim[i] = '\0';
+ break;
+ }
+ }
+ post(" name: %s", x->x_bcname);
+ }
+ if( cpoint = strstr(request, "icy-url:"))
+ {
+ x->x_bcurl = STRDUP( cpoint + 8);
+ for ( i=0; i<(int)strlen(x->x_bcurl); i++ )
+ {
+ if ( x->x_bcurl[i] == '\n' )
+ {
+ x->x_bcurl[i] = '\0';
+ break;
+ }
+ }
+ post(" name: %s", x->x_bcname);
+ }
+ if(strstr(request, "icy-pub:1"))
+ {
+ post(" broadcast is public");
+ }
+ else if(strstr(request, "icy-pub:0"))
+ {
+ post(" broadcast is NOT public");
+ }
+ if( cpoint = strstr(request, "icy-br:"))
+ {
+ sptr = STRDUP( cpoint + 7);
+ if(!strncmp(sptr, "320", 3))x->x_bitrate = 320;
+ else if(!strncmp(sptr, "256", 3))x->x_bitrate = 256;
+ else if(!strncmp(sptr, "224", 3))x->x_bitrate = 224;
+ else if(!strncmp(sptr, "192", 3))x->x_bitrate = 192;
+ else if(!strncmp(sptr, "160", 3))x->x_bitrate = 160;
+ else if(!strncmp(sptr, "144", 3))x->x_bitrate = 144;
+ else if(!strncmp(sptr, "128", 3))x->x_bitrate = 128;
+ else if(!strncmp(sptr, "112", 3))x->x_bitrate = 112;
+ else if(!strncmp(sptr, "96", 2))x->x_bitrate = 96;
+ else if(!strncmp(sptr, "80", 2))x->x_bitrate = 80;
+ else if(!strncmp(sptr, "64", 2))x->x_bitrate = 64;
+ else if(!strncmp(sptr, "56", 2))x->x_bitrate = 56;
+ else if(!strncmp(sptr, "48", 2))x->x_bitrate = 48;
+ else if(!strncmp(sptr, "40", 2))x->x_bitrate = 40;
+ else if(!strncmp(sptr, "32", 2))x->x_bitrate = 32;
+ else if(!strncmp(sptr, "24", 2))x->x_bitrate = 24;
+ else if(!strncmp(sptr, "16", 2))x->x_bitrate = 16;
+ else if(!strncmp(sptr, "8", 2))x->x_bitrate = 8;
+ else
+ {
+ post("mp3amp~: unsupported bitrate! (%s)", sptr);
+ return NULL;
+ }
+ post(" bitrate: %d", x->x_bitrate);
+ }
+ if(strstr(request, "x-audiocast-udpport:"))
+ {
+ post("mp3amp~: sorry, server wants UDP connection!");
+ return NULL;
+ }
+ }
+ else
+ {
+ post("mp3amp~: unknown response from server");
+ return NULL;
+ }
+ relocate = FALSE;
+ }
+ if (relocate) {
+ error("mp3amp~: too many HTTP relocations");
+ return NULL;
+ }
+ post("mp3amp~: connected to http://%s:%d/%s", hp->h_name, portno, x->x_mountpoint);
+ x->x_fd = sockfd;
+ 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_VGUI3(".x%x.c delete rectangle %xPBAR\n", x->x_canvas, x );
+ SYS_VGUI7(".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 );
+ }
+
+ return NULL;
+}
+
+ /* launch the connection thread */
+static void mp3amp_connect(t_mp3amp *x, t_symbol *hostname, t_symbol *mountpoint, t_floatarg fportno )
+{
+ pthread_attr_t update_child_attr;
+ pthread_t connectchild;
+
+ // store data
+ x->x_hostname = (char*) getbytes( strlen( hostname->s_name ) + 1 ); // there's a memory leak here
+ strcpy( x->x_hostname, hostname->s_name );
+
+ x->x_mountpoint = (char*) getbytes( strlen( mountpoint->s_name ) + 1 ); // there's a memory leak here
+ strcpy( x->x_mountpoint, mountpoint->s_name );
+
+ x->x_port = fportno;
+
+ // launch connection thread
+ if ( pthread_attr_init( &update_child_attr ) < 0 ) {
+ post( "mp3amp~ : could not launch connection thread" );
+ perror( "pthread_attr_init" );
+ return;
+ }
+ if ( pthread_attr_setdetachstate( &update_child_attr, PTHREAD_CREATE_DETACHED ) < 0 ) {
+ post( "mp3amp~ : could not launch connection thread" );
+ perror( "pthread_attr_setdetachstate" );
+ return;
+ }
+ if ( pthread_create( &connectchild, &update_child_attr, mp3amp_do_connect, x ) < 0 ) {
+ post( "mp3amp~ : could not launch connection thread" );
+ perror( "pthread_create" );
+ return;
+ }
+ else
+ {
+ // post( "cooled~ : drawing thread %d launched", (int)x->x_updatechild );
+ }
+
+ if ( !x->x_nooutput ) outlet_float(x->x_connection, 1);
+}
+
+ /* connect using url like "http://localhost:8000/mountpoint" */
+static void mp3amp_connect_url(t_mp3amp *x, t_symbol *url)
+{
+ char *hostptr = NULL, *p, *endhost = NULL, *hostname = NULL;
+ char *pathptr = NULL;
+ t_int portno = 8000;
+
+ post( "mp3amp~ : connect url : %s", url->s_name );
+
+ /* strip http:// or ftp:// */
+ p = url->s_name;
+ if (strncmp(p, "http://", 7) == 0)
+ p += 7;
+
+ if (strncmp(p, "ftp://", 6) == 0)
+ p += 6;
+
+ hostptr = p;
+ while (*p && *p != '/' && *p != ':') /* look for end of hostname: */
+ p++;
+
+ endhost = p;
+ switch ( *p )
+ {
+ case ':' :
+ portno = atoi( p+1 );
+ while (*p && *p != '/') p++;
+ pathptr = p+1;
+ break;
+ case '/' :
+ portno = 8000;
+ pathptr = p+1;
+ break;
+ default :
+ if ( ( p - url->s_name ) != (int)strlen( url->s_name ) )
+ {
+ post( "mp3amp~ : wrong url : %s", hostptr );
+ return;
+ }
+ pathptr = "";
+ break;
+ }
+
+ hostname=(char*)getbytes( (int)(endhost - hostptr) + 1);
+ strncpy( hostname, hostptr, (int)(endhost - hostptr) );
+ hostname[ endhost - hostptr ] = '\0';
+
+ post ("mp3amp~ : connecting to host=%s port=%d path=%s", hostname, portno, pathptr );
+
+ /* call the 'normal' connection routine */
+ mp3amp_connect(x, gensym(hostname), gensym(pathptr), portno);
+}
+
+ /* close connection to SHOUTcast server */
+static void mp3amp_disconnect(t_mp3amp *x)
+{
+ x->x_stream = 0;
+ x->x_inframes = 0;
+ x->x_dframes = 0;
+ x->x_inwriteposition = 0;
+ x->x_offset = 0;
+ if(x->x_fd >= 0) /* close socket */
+ {
+ sys_closesocket(x->x_fd);
+ x->x_fd = -1;
+ }
+ ExitMP3(&mps[x->x_instance]);
+ InitMP3(&mps[x->x_instance]);
+ if ( x->x_graphic )
+ {
+ SYS_VGUI3(".x%x.c delete rectangle %xPBAR\n", x->x_canvas, x );
+ SYS_VGUI3(".x%x.c delete rectangle %xSTATUS\n", x->x_canvas, x );
+ }
+ post("mp3amp~: connection closed");
+ outlet_float(x->x_connection, 0);
+}
+
+static void mp3amp_free(t_mp3amp *x)
+{
+ if (x->x_fd > 0) {
+ post( "mp3amp~: closing socket" );
+ sys_closesocket(x->x_fd);
+ x->x_fd = -1;
+ }
+ freebytes(x->x_inbuffer, INPUT_BUFFER_SIZE);
+ freebytes(x->x_outbuffer, OUTPUT_BUFFER_SIZE*sizeof(t_float));
+}
+
+static void *mp3amp_new(t_floatarg fdographics)
+{
+ t_mp3amp *x = NULL;
+
+ if ( ((int)fdographics != 0) && ((int)fdographics != 1.) )
+ {
+ post( "mp3amp~: error : constructor : mp3amp~ [graphic flag = 0 | 1 ] ( got = %f)", fdographics );
+ return NULL;
+ }
+
+ x = (t_mp3amp *)pd_new(mp3amp_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_connection = outlet_new(&x->x_obj, gensym("float"));
+
+ if ( nbinstances < MAX_DECODERS )
+ {
+ x->x_instance = nbinstances++;
+ }
+ else
+ {
+ post( "mp3amp~: cannot create more decoders (memory issues), sorry" );
+ return NULL;
+ }
+
+ x->x_fd = -1;
+ x->x_stream = 0;
+ x->x_inframes = 0;
+ x->x_samplerate = sys_getsr();
+ x->x_nbwaitloops = 1;
+ x->x_nbloops = 0;
+ x->x_dsp = 0;
+
+ x->x_inbuffersize = INPUT_BUFFER_SIZE;
+ x->x_outbuffersize = OUTPUT_BUFFER_SIZE;
+ x->x_inbuffer = (unsigned char*) getbytes(INPUT_BUFFER_SIZE);
+ x->x_offset = 0;
+ x->x_outbuffer = (t_float*) getbytes(OUTPUT_BUFFER_SIZE*sizeof(t_float));
+
+ if ( !x->x_inbuffer || !x->x_outbuffer )
+ {
+ post( "mp3amp~: could not allocate buffers" );
+ return NULL;
+ }
+ memset( x->x_inbuffer, 0x0, INPUT_BUFFER_SIZE );
+ memset( x->x_outbuffer, 0x0, OUTPUT_BUFFER_SIZE );
+
+ x->x_inwriteposition = 0;
+ x->x_outreadposition = 0;
+ x->x_outwriteposition = 0;
+ x->x_outunread = 0;
+ x->x_standby = 0;
+ x->x_resample = -1;
+ x->x_nooutput = 0;
+
+ ztout.tv_sec = 0;
+ ztout.tv_usec = 0;
+
+ x->x_graphic = (int)fdographics;
+ post( "mp3amp~: getting canvas" );
+ x->x_canvas = canvas_getcurrent();
+
+ post( "mp3amp~: initializing decoder..." );
+ /* init mpg123 decoder */
+ mp3amp_tilde_mpglib_init(x);
+
+ post(mp3amp_version);
+
+ return (x);
+}
+
+
+void mp3amp_tilde_setup(void)
+{
+ mp3amp_class = class_new(gensym("mp3amp~"),
+ (t_newmethod) mp3amp_new, (t_method) mp3amp_free,
+ sizeof(t_mp3amp), 0, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(mp3amp_class, nullfn, gensym("signal"), 0);
+ class_addmethod(mp3amp_class, (t_method)mp3amp_dsp, gensym("dsp"), 0);
+ class_addmethod(mp3amp_class, (t_method)mp3amp_connect, gensym("connect"), A_SYMBOL, A_SYMBOL, A_FLOAT, 0);
+ class_addmethod(mp3amp_class, (t_method)mp3amp_connect_url, gensym("connecturl"), A_SYMBOL, 0);
+ class_addmethod(mp3amp_class, (t_method)mp3amp_standby, gensym("standby"), A_DEFFLOAT, 0);
+ class_addmethod(mp3amp_class, (t_method)mp3amp_disconnect, gensym("disconnect"), 0);
+ class_sethelpsymbol(mp3amp_class, gensym("help-mp3amp~.pd"));
+}
diff --git a/mp3amp~/mpg123.h b/mp3amp~/mpg123.h
new file mode 100644
index 0000000..1c530d3
--- /dev/null
+++ b/mp3amp~/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/mp3amp~/mpglib.h b/mp3amp~/mpglib.h
new file mode 100644
index 0000000..1f4ef9a
--- /dev/null
+++ b/mp3amp~/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/mp3amp~/punjabi-2.pls b/mp3amp~/punjabi-2.pls
new file mode 100644
index 0000000..6db94ea
--- /dev/null
+++ b/mp3amp~/punjabi-2.pls
@@ -0,0 +1,3 @@
+[playlist]
+NumberOfEntries=1
+File1=http://www.live365.com/play/295522?membername=&session=punjabicity02%3A0&pid=&SaneID=212.198.0.97-1030988754258&lid=-1-fra
diff --git a/mp3amp~/punjabi-3.pls b/mp3amp~/punjabi-3.pls
new file mode 100644
index 0000000..507f782
--- /dev/null
+++ b/mp3amp~/punjabi-3.pls
@@ -0,0 +1,3 @@
+[playlist]
+NumberOfEntries=1
+File1=http://www.live365.com/play/152468?membername=&session=indianmp3%3A0&pid=&SaneID=212.198.0.97-1030988754258&lid=-1-fra
diff --git a/mp3amp~/punjabi-4.pls b/mp3amp~/punjabi-4.pls
new file mode 100644
index 0000000..24fb8ff
--- /dev/null
+++ b/mp3amp~/punjabi-4.pls
@@ -0,0 +1,3 @@
+[playlist]
+NumberOfEntries=1
+File1=http://www.live365.com/play/159295?membername=&session=panjabiradio%3A0&pid=&SaneID=212.198.0.97-1030988754258&lid=-1-fra
diff --git a/mp3amp~/punjabi.pls b/mp3amp~/punjabi.pls
new file mode 100644
index 0000000..24fb8ff
--- /dev/null
+++ b/mp3amp~/punjabi.pls
@@ -0,0 +1,3 @@
+[playlist]
+NumberOfEntries=1
+File1=http://www.live365.com/play/159295?membername=&session=panjabiradio%3A0&pid=&SaneID=212.198.0.97-1030988754258&lid=-1-fra
diff --git a/mp3cast~/CHANGES.LOG b/mp3cast~/CHANGES.LOG
new file mode 100644
index 0000000..7418ad7
--- /dev/null
+++ b/mp3cast~/CHANGES.LOG
@@ -0,0 +1,6 @@
+0.3
+ renamed it to mp3cast
+0.2
+ fixed multi-encoding problem
+0.1
+ first implementation
diff --git a/mp3cast~/INSTALL b/mp3cast~/INSTALL
new file mode 100644
index 0000000..769e78e
--- /dev/null
+++ b/mp3cast~/INSTALL
@@ -0,0 +1,15 @@
+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/mp3cast~
+
+make -f Makefile.linux
+
+make -f Makefile.linux install
+
+you're set !!
diff --git a/mp3cast~/Makefile b/mp3cast~/Makefile
new file mode 100644
index 0000000..799788e
--- /dev/null
+++ b/mp3cast~/Makefile
@@ -0,0 +1,82 @@
+NAME=mp3cast~
+CSYM=mp3cast_tilde
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).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
+
+.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
+
+.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
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -DUNIX -DICECAST -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) -DHAVE_STRCHR -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 $*/$*.pd_linux ..
+
+# ----------------------------------------------------------
+
+install:
+ cp help-*.pd ../../doc/5.reference
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/mp3cast~/Makefile.linux b/mp3cast~/Makefile.linux
new file mode 100644
index 0000000..b2f9cfa
--- /dev/null
+++ b/mp3cast~/Makefile.linux
@@ -0,0 +1,82 @@
+NAME=mp3cast~
+CSYM=mp3cast_tilde
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).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
+
+.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
+
+.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
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -DUNIX -DICECAST -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 $*/$*.pd_linux ..
+
+# ----------------------------------------------------------
+
+install:
+ cp test-*.pd ../../doc/5.reference
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/mp3cast~/README b/mp3cast~/README
new file mode 100644
index 0000000..99c2bbc
--- /dev/null
+++ b/mp3cast~/README
@@ -0,0 +1,108 @@
+Version 0.01
+copyright (c) 2001 by Olaf Matthes
+ported to Linux by Yves Degoyon
+
+mp3cast~.dll is a MPEG I Layer III (mp3) streaming external for pd (by Miller
+Puckette) that connects to a SHOUTcast or IceCast server.
+
+To install mp3cast~, 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.
+
+*****************************************************************************
+
+mp3cast~ 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.
+
+*****************************************************************************
+
+ using mp3cast~ external for Pure Data
+
+Open the test-mp3cast~.pd to understand how it works.
+In this patch, you must send the messages to mp3cast~
+in the following order :
+
+1/ password *****
+2/ icecast | mp3cast
+3/ connect host port
+4/ pd dsp 1
+
+Parameters sent to mp3cast~ object :
+
+ Sampling Rate (Hz):
+Possible values are 48000, 44100 and 32000. If Pd runs at a different sampling
+rate, LAME will resample the signal. Default value for mp3 sampling rate is Pd's
+sampling rate.
+
+ Bitrate (kbit/s):
+Possible values are 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256
+and 320. Default is 224.
+
+ Mode:
+Possible values are 0 (stereo), 1 (joint stereo, the default), 2 (dual channel)
+and 3 (mono).
+
+ Password:
+The default is 'pd', can be changed with a message "passwd yourpassword".
+
+ Server:
+Use message "connect name_of_your_server.com port" to connect (same as with
+Pd's netsend). 'port' is the number specified in the server's config file.
+Attention (for SHOUTcast users): The actual port number used is one higher!
+Standard would be 8000 resulting in a socket at port 8001!!! Bare this in mind
+when configuring proxys or using mp3cast~ in connection with netsend /
+netreceive. For IceCast, the port number used is the same as specified.
+
+ Outlet:
+The outlet outputs an int, 1 if connected to SHOUTcast server, 0 if not. This could
+be used to build an automatic reconnect mechanism.
+
+ Other things:
+mp3cast~ prints the current status (connection, login, LAME status) to the pd
+window. To see the current settings, send it a message "print" and mp3 settings
+will be displayed.
+Note that changing any mp3 settings will require to disconnect and reconnect again!
+This has to be done manually.
+
+ Known problems:
+If you turn off audio processing when you are connected with the server, no data will
+be sent to it. This will make the server disconnect after a certain time ('no data'
+error in server log). mp3cast~ does not recongnise this and attempts to keep on
+streaming. To avoid this set 'AutoDumpSourceTime' in the servers config file to a
+fairly high value preventing the server from closing the socket to fast.
+
+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 SAMPLERATE/BITRATES
+
+MPEG-1 layer III sample frequencies (kHz): 32 48 44.1
+bitrates (kbps): 32 40 48 56 64 80 96 112 128 160 192 224 256 320
+
+MPEG-2 layer III sample frequencies (kHz): 16 24 22.05
+bitrates (kbps): 8 16 24 32 40 48 56 64 80 96 112 128 144 160
+
+MPEG-2.5 layer III sample frequencies (kHz): 8 12 11.025
+bitrates (kbps): 8 16 24 32 40 48 56 64 80 96 112 128 144 160
+
diff --git a/mp3cast~/help-mp3cast~.pd b/mp3cast~/help-mp3cast~.pd
new file mode 100644
index 0000000..c7d8e72
--- /dev/null
+++ b/mp3cast~/help-mp3cast~.pd
@@ -0,0 +1,50 @@
+#N canvas 52 75 741 425 10;
+#X floatatom 53 24 0 40 16000;
+#X msg 30 378 \; pd dsp 1;
+#X obj 61 242 mp3cast~;
+#X floatatom 61 280 0 0 0;
+#X msg 181 88 disconnect;
+#X msg 151 44 connect localhost 8000;
+#X text 266 63 <-- your password for the server;
+#X text 317 75 (default passwd is "pd");
+#X text 257 87 <-- close connection;
+#X text 411 21 <-- host and port;
+#X text 292 215 <-- settings for mp3 stream;
+#X text 315 245 bitrate: bitrate of stream \, def. 224kbit/s;
+#X text 352 269 1 = joint stereo (default);
+#X text 312 307 quality: 1 = high \, 9 = low;
+#X text 313 227 (samplerate \, bitrate \, mode \, quality);
+#X text 316 257 mode: 0 = stereo;
+#X text 352 281 2 = dual channel;
+#X text 352 294 3 = mono;
+#X msg 13 145 print;
+#X msg 96 378 \; pd dsp 0;
+#X msg 203 141 icecast;
+#X text 259 116 <-- choose type of server;
+#X obj 53 51 osc~ 440;
+#X msg 163 66 passwd letmein;
+#X msg 154 239 mpeg 8000 8 3 5;
+#X msg 155 215 mpeg 44100 128 1 4;
+#X msg 209 170 mountpoint pd;
+#X obj 29 349 loadbang;
+#X text 293 374 Author : Yves Degoyon ( ydegoyon@free.fr );
+#X msg 190 118 shoutcast;
+#X msg 116 23 connect college-invisible.dyndns.org 8000;
+#X msg 212 194 name mystream;
+#X text 322 195 name of the stream;
+#X connect 0 0 22 0;
+#X connect 2 0 3 0;
+#X connect 4 0 2 0;
+#X connect 5 0 2 0;
+#X connect 18 0 2 0;
+#X connect 20 0 2 0;
+#X connect 22 0 2 0;
+#X connect 22 0 2 1;
+#X connect 23 0 2 0;
+#X connect 24 0 2 0;
+#X connect 25 0 2 0;
+#X connect 26 0 2 0;
+#X connect 27 0 1 0;
+#X connect 29 0 2 0;
+#X connect 30 0 2 0;
+#X connect 31 0 2 0;
diff --git a/mp3cast~/interface.h b/mp3cast~/interface.h
new file mode 100644
index 0000000..de3136a
--- /dev/null
+++ b/mp3cast~/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/mp3cast~/mp3cast~.c b/mp3cast~/mp3cast~.c
new file mode 100644
index 0000000..5c881c3
--- /dev/null
+++ b/mp3cast~/mp3cast~.c
@@ -0,0 +1,916 @@
+/* ------------------------ mp3cast~ ---------------------------------------- */
+/* */
+/* Tilde object to send mp3-stream to shoutcast/icecast server. */
+/* Written by Olaf Matthes (olaf.matthes@gmx.de). */
+/* Get source at http://www.akustische-kunst.de/puredata/ */
+/* */
+/* 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. */
+/* */
+/* ---------------------------------------------------------------------------- */
+
+
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+#include "m_pd.h" /* standard pd stuff */
+
+#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 */
+#include "mpg123.h"
+#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
+
+
+#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 *mp3cast_version = "mp3cast~: mp3 streamer version 0.3, written by Yves Degoyon";
+
+#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 *mp3cast_class;
+
+typedef struct _mp3cast
+{
+ 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 */
+
+ /* SHOUTcast server stuff */
+ int x_fd; /* info about connection status */
+ char* x_passwd; /* password for server */
+ int x_icecast; /* tells if we use a IceCast server or SHOUTcast */
+ /* special IceCast server stuff */
+ char* x_mountpoint;
+ char* x_name;
+
+ t_float x_f; /* float needed for signal input */
+
+#ifdef UNIX
+ lame_global_flags *lgfp; /* lame encoder configuration */
+#endif
+
+} t_mp3cast;
+
+
+ /* encode PCM data to mp3 stream */
+static void mp3cast_encode(t_mp3cast *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("mp3cast~: initialising 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("mp3cast~: 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);
+ // post( "mp3cast~ : encoding returned %d frames", x->x_mp3size );
+#endif
+
+ /* check result */
+#ifndef UNIX
+ if(err != BE_ERR_SUCCESSFUL)
+ {
+ closeStream(x->x_lame);
+ error("mp3cast~: lameEncodeChunk() failed (%lu)", err);
+#else
+ if(x->x_mp3size<0)
+ {
+ lame_close( x->lgfp );
+ error("mp3cast~: lame_encode_buffer_interleaved failed (%d)", x->x_mp3size);
+#endif
+ x->x_lame = -1;
+ }
+}
+
+
+ /* stream mp3 to SHOUTcast server */
+static void mp3cast_stream(t_mp3cast *x)
+{
+ int err = -1, i; /* error return code */
+ struct frame hframe;
+
+ err = send(x->x_fd, x->x_mp3outbuf, x->x_mp3size, 0);
+ if(err < 0)
+ {
+ error("mp3cast~: could not send encoded data to server (%d)", err);
+#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);
+ }
+ if((err > 0)&&(err != x->x_mp3size))error("mp3cast~: %d bytes skipped", x->x_mp3size - err);
+}
+
+
+ /* buffer data as channel interleaved PCM */
+static t_int *mp3cast_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_mp3cast *x = (t_mp3cast *)(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 server */
+ if(x->x_bytesbuffered > x->x_lamechunk)
+ {
+ mp3cast_encode(x); /* encode to mp3 */
+ mp3cast_stream(x); /* stream mp3 to server */
+ x->x_bytesbuffered -= x->x_lamechunk;
+ }
+ }
+ else
+ {
+ x->x_start = -1;
+ }
+ return (w+5);
+}
+
+static void mp3cast_dsp(t_mp3cast *x, t_signal **sp)
+{
+ dsp_add(mp3cast_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n);
+}
+
+ /* initialize the lame library */
+static void mp3cast_tilde_lame_init(t_mp3cast *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("mp3cast~: error loading lame_enc.dll");
+ closesocket(x->x_fd);
+ x->x_fd = -1;
+ outlet_float(x->x_obj.ob_outlet, 0);
+ post("mp3cast~: 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("mp3cast~: unable to get LAME interfaces");
+ closesocket(x->x_fd);
+ x->x_fd = -1;
+ outlet_float(x->x_obj.ob_outlet, 0);
+ post("mp3cast~: connection closed");
+ return;
+ }
+
+ /* get LAME version number */
+ dllVersion(&lameVersion);
+
+ post( "mp3cast~: 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( "mp3cast~ : 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("mp3cast~: 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( "mp3cast~ : 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( "mp3cast~ : lame initialization done. (%d)", x->x_lame );
+ }
+ lame_init_bitstream( x->lgfp );
+#endif
+
+
+}
+
+ /* connect to SHOUTcast server */
+static void mp3cast_connect(t_mp3cast *x, t_symbol *hostname, t_floatarg fportno)
+{
+ struct sockaddr_in server;
+ struct hostent *hp;
+ int portno = fportno; /* get port from message box */
+
+ /* information about this broadcast to be send to the server */
+ const char *name = x->x_name; /* name of broadcast */
+ const char *url = "http://guess.where.i.am"; /* url of broadcast */
+ const char *genre = "abstract break"; /* genre of broadcast */
+ const char *aim = "N/A"; /* aim of broadcast */
+ const char *irc = "#mp3cast"; /* ??? what's this ??? */
+ const char *icq = ""; /* icq id of broadcaster */
+ const char *mountpoint = x->x_mountpoint; /* mountpoint for IceCast server */
+ int isPublic = 0; /* don't publish broadcast on www.shoutcast.com */
+
+ /* variables used for communication with server */
+ const char * buf = 0;
+ char resp[STRBUF_SIZE];
+ unsigned int len;
+ fd_set fdset;
+ struct timeval tv;
+ int sockfd;
+
+#ifndef UNIX
+ unsigned int ret;
+#else
+ int ret;
+#endif
+
+ if(x->x_icecast == 0)portno++; /* use SHOUTcast, portno is one higher */
+
+ if (x->x_fd >= 0)
+ {
+ error("mp3cast~: already connected");
+ return;
+ }
+
+ sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sockfd < 0)
+ {
+ error("mp3cast~: internal error while attempting to open socket");
+ return;
+ }
+
+ /* connect socket using hostname provided in command line */
+ server.sin_family = AF_INET;
+ hp = gethostbyname(hostname->s_name);
+ if (hp == 0)
+ {
+ post("mp3cast~: bad host?");
+#ifndef UNIX
+ closesocket(sockfd);
+#else
+ close(sockfd);
+#endif
+ return;
+ }
+ memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
+
+ /* assign client port number */
+ server.sin_port = htons((unsigned short)portno);
+
+ /* try to connect. */
+ post("mp3cast~: connecting to port %d", portno);
+ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
+ {
+ error("mp3cast~: connection failed!\n");
+#ifndef UNIX
+ closesocket(sockfd);
+#else
+ close(sockfd);
+#endif
+ return;
+ }
+
+ /* sheck if we can read/write from/to the socket */
+ FD_ZERO( &fdset);
+ FD_SET( sockfd, &fdset);
+ tv.tv_sec = 0; /* seconds */
+ tv.tv_usec = 500; /* microseconds */
+
+ ret = select(sockfd + 1, &fdset, NULL, NULL, &tv);
+ if(ret < 0)
+ {
+ error("mp3cast~: can not read from socket");
+#ifndef UNIX
+ closesocket(sockfd);
+#else
+ close(sockfd);
+#endif
+ return;
+ }
+ ret = select(sockfd + 1, NULL, &fdset, NULL, &tv);
+ if(ret < 0)
+ {
+ error("mp3cast~: can not write to socket");
+#ifndef UNIX
+ closesocket(sockfd);
+#else
+ close(sockfd);
+#endif
+ return;
+ }
+
+ if(x->x_icecast == 0) /* SHOUTCAST */
+ {
+ /* now try to log in at SHOUTcast server */
+ post("mp3cast~: logging in to SHOUTcast server...");
+
+ /* first line is the passwd */
+ buf = x->x_passwd;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\n";
+ send(sockfd, buf, strlen(buf), 0);
+
+ /* header for SHOUTcast server */
+ buf = "icy-name:"; /* name of broadcast */
+ send(sockfd, buf, strlen(buf), 0);
+ buf = name;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\nicy-url:"; /* URL of broadcast */
+ send(sockfd, buf, strlen(buf), 0);
+ buf = url;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\nicy-genre:"; /* genre of broadcast */
+ send(sockfd, buf, strlen(buf), 0);
+ buf = genre;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\nicy-irc:";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = irc;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\nicy-aim:";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = aim;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\nicy-icq:";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = icq;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\nicy-br:";
+ send(sockfd, buf, strlen(buf), 0);
+ if(sprintf(resp, "%d", x->x_bitrate) == -1) /* convert int to a string */
+ {
+ error("mp3cast~: wrong bitrate");
+ }
+ send(sockfd, resp, strlen(resp), 0);
+ buf = "\nicy-pub:";
+ send(sockfd, buf, strlen(buf), 0);
+ if(isPublic==0) /* set the public flag for broadcast */
+ {
+ buf = "no";
+ }
+ else
+ {
+ buf ="yes";
+ }
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\n\n";
+ send(sockfd, buf, strlen(buf), 0);
+ }
+ else /* IceCast */
+ {
+ /* now try to log in at IceCast server */
+ post("mp3cast~: logging in to IceCast server...");
+
+ /* send the request, a string like:
+ * "SOURCE <password> /<mountpoint>\n" */
+ buf = "SOURCE ";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = x->x_passwd;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = " /";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = mountpoint;
+ send(sockfd, buf, strlen(buf), 0);
+
+ /* send the x-audiocast headers */
+ buf = "\nx-audiocast-bitrate: ";
+ send(sockfd, buf, strlen(buf), 0);
+ if(sprintf(resp, "%d", x->x_bitrate) == -1) /* convert int to a string */
+ {
+ error("mp3cast~: wrong bitrate");
+ }
+ send(sockfd, resp, strlen(resp), 0);
+
+ buf = "\nx-audiocast-public: ";
+ send(sockfd, buf, strlen(buf), 0);
+ if(isPublic==0) /* set the public flag for broadcast */
+ {
+ buf = "no";
+ }
+ else
+ {
+ buf ="yes";
+ }
+ send(sockfd, buf, strlen(buf), 0);
+
+ buf = "\nx-audiocast-name: ";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = name;
+ send(sockfd, buf, strlen(buf), 0);
+
+ buf = "\nx-audiocast-url: ";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = url;
+ send(sockfd, buf, strlen(buf), 0);
+
+ buf = "\nx-audiocast-genre: ";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = genre;
+ send(sockfd, buf, strlen(buf), 0);
+
+ buf = "\n\n";
+ send(sockfd, buf, strlen(buf), 0);
+ /* end login for IceCast */
+ }
+
+ /* read the anticipated response: "OK" */
+ len = recv(sockfd, resp, STRBUF_SIZE, 0);
+ if ( len < 2 || resp[0] != 'O' || resp[1] != 'K' )
+ {
+ post("mp3cast~: login failed!");
+#ifndef UNIX
+ closesocket(sockfd);
+#else
+ close(sockfd);
+#endif
+ return;
+ }
+
+ /* suck anything that the other side has to say */
+ // while (len = recv(sockfd, resp, STRBUF_SIZE,0))
+ // {
+ ; /* do nothing, just wait ! */
+ // }
+
+ x->x_fd = sockfd;
+ outlet_float(x->x_obj.ob_outlet, 1);
+ post("mp3cast~: logged in to %s", hp->h_name);
+
+ mp3cast_tilde_lame_init(x);
+
+}
+
+ /* close connection to SHOUTcast server */
+static void mp3cast_disconnect(t_mp3cast *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( "mp3cast~ : warning : remaining encoded bytes" );
+ }
+ lame_close( x->lgfp );
+#endif
+ x->x_lame = -1;
+ post("mp3cast~: 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("mp3cast~: connection closed");
+ }
+}
+
+ /* set password for SHOUTcast server */
+static void mp3cast_password(t_mp3cast *x, t_symbol *password)
+{
+ post("mp3cast~ : setting password to %s", password->s_name );
+ x->x_passwd = password->s_name;
+}
+
+ /* settings for mp3 encoding */
+static void mp3cast_mpeg(t_mp3cast *x, t_floatarg fsamplerate, t_floatarg fbitrate,
+ t_floatarg fmode, t_floatarg fquality)
+{
+ x->x_samplerate = fsamplerate;
+ if(fbitrate > MAXDATARATE)
+ {
+ fbitrate = MAXDATARATE;
+ }
+ x->x_bitrate = fbitrate;
+ x->x_mp3mode = fmode;
+ x->x_mp3quality = fquality;
+ post("mp3cast~: setting mp3 stream to %dHz, %dkbit/s, mode %d, quality %d",
+ x->x_samplerate, x->x_bitrate, x->x_mp3mode, x->x_mp3quality);
+ if(x->x_fd>=0)post("mp3cast~ : reconnect to make changes take effect! ");
+}
+
+ /* print settings */
+static void mp3cast_print(t_mp3cast *x)
+{
+ const char * buf = 0;
+ post(mp3cast_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);
+ }
+ if(x->x_icecast == 0)
+ {
+ post(" server type is SHOUTcast");
+ }
+ else
+ {
+ post(" server type is IceCast");
+ }
+}
+
+ /* we use iceCast server */
+static void mp3cast_icecast(t_mp3cast *x)
+{
+ x->x_icecast = 1;
+ post("mp3cast~: set server type to IceCast");
+}
+
+ /* we use SHOUTcast server (default) */
+static void mp3cast_shoutcast(t_mp3cast *x)
+{
+ x->x_icecast = 0;
+ post("mp3cast~: set server type to SHOUTcast");
+}
+
+ /* set mountpoint for IceCast server */
+static void mp3cast_mountpoint(t_mp3cast *x, t_symbol *mount)
+{
+ x->x_mountpoint = mount->s_name;
+ post("mp3cast~: mountpoint set to %s", x->x_mountpoint);
+}
+
+ /* set namle for IceCast server */
+static void mp3cast_name(t_mp3cast *x, t_symbol *name)
+{
+ x->x_name = name->s_name;
+ post("mp3cast~: name set to %s", x->x_name);
+}
+
+ /* clean up */
+static void mp3cast_free(t_mp3cast *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 *mp3cast_new(void)
+{
+ t_mp3cast *x = (t_mp3cast *)pd_new(mp3cast_class);
+ inlet_new (&x->x_obj, &x->x_obj.ob_pd, gensym ("signal"), gensym ("signal"));
+ outlet_new(&x->x_obj, gensym("float"));
+ x->x_fd = -1;
+ x->x_lame = -1;
+ x->x_passwd = "pd";
+ x->x_samplerate = sys_getsr();
+ x->x_bitrate = 224;
+ 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*sizeof(char)); /* 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->lgfp = NULL;
+ x->x_start = -1;
+ x->x_icecast = 0;
+ x->x_mountpoint = "puredata";
+ x->x_name = "puredata";
+ return(x);
+}
+
+void mp3cast_tilde_setup(void)
+{
+ post(mp3cast_version);
+ mp3cast_class = class_new(gensym("mp3cast~"), (t_newmethod)mp3cast_new, (t_method)mp3cast_free,
+ sizeof(t_mp3cast), 0, 0);
+ CLASS_MAINSIGNALIN(mp3cast_class, t_mp3cast, x_f );
+ class_sethelpsymbol(mp3cast_class, gensym("help-mp3cast~.pd"));
+ class_addmethod(mp3cast_class, (t_method)mp3cast_dsp, gensym("dsp"), 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_disconnect, gensym("disconnect"), 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_password, gensym("passwd"), A_SYMBOL, 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_mpeg, gensym("mpeg"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_print, gensym("print"), 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_icecast, gensym("icecast"), 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_shoutcast, gensym("shoutcast"), 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_mountpoint, gensym("mountpoint"), A_SYMBOL, 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_name, gensym("name"), A_SYMBOL, 0);
+}
+
diff --git a/mp3cast~/mpg123.h b/mp3cast~/mpg123.h
new file mode 100644
index 0000000..1c530d3
--- /dev/null
+++ b/mp3cast~/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/mp3cast~/mpglib.h b/mp3cast~/mpglib.h
new file mode 100644
index 0000000..1f4ef9a
--- /dev/null
+++ b/mp3cast~/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~/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;
diff --git a/mp3write~/CHANGES.LOG b/mp3write~/CHANGES.LOG
new file mode 100644
index 0000000..0071e2a
--- /dev/null
+++ b/mp3write~/CHANGES.LOG
@@ -0,0 +1,8 @@
+0.4
+ fixed title memory leak
+0.3
+ fixed includes to compile with lame > 0.90
+0.2
+ fixed multi-encoding problem
+0.1
+ first implementation
diff --git a/mp3write~/INSTALL b/mp3write~/INSTALL
new file mode 100644
index 0000000..75f5f91
--- /dev/null
+++ b/mp3write~/INSTALL
@@ -0,0 +1,15 @@
+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/mp3write~
+
+make
+
+make install
+
+you're set !!
diff --git a/mp3write~/Makefile b/mp3write~/Makefile
new file mode 100644
index 0000000..d5d082e
--- /dev/null
+++ b/mp3write~/Makefile
@@ -0,0 +1,82 @@
+NAME=mp3write~
+CSYM=mp3write_tilde
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).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
+
+.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
+
+.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
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -DUNIX -DICECAST -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 $*/$*.pd_linux ..
+
+# ----------------------------------------------------------
+
+install:
+ cp help-*.pd ../../doc/5.reference
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/mp3write~/README b/mp3write~/README
new file mode 100644
index 0000000..3b43bbe
--- /dev/null
+++ b/mp3write~/README
@@ -0,0 +1,94 @@
+Version 0.01
+copyright (c) 2001 by Yves Degoyon
+
+mp3write~.dll is a MPEG I Layer III (mp3) file writer.
+
+To install mp3write~, 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.
+
+*****************************************************************************
+
+mp3write~ has been compiled for Linux using LAME 3.92.
+The newest version of LAME can be found via freshmeat.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.
+
+*****************************************************************************
+
+ using mp3write~ external for Pure Data
+
+Open the test-mp3write~.pd to understand how it works.
+In this patch, you must send the messages to mp3write~
+in the following order :
+
+1/ append|truncate if you wish to change file creation options ( default is append )
+2/ open /my/file
+3/ start
+5/ pd dsp 1
+4/ stop : the tag is written at this stage
+
+Parameters sent to mp3write~ object :
+
+ Sampling Rate (Hz):
+Possible values are 48000, 44100 and 32000. If Pd runs at a different sampling
+rate, LAME will resample the signal. Default value for mp3 sampling rate is Pd's
+sampling rate.
+
+ Bitrate (kbit/s):
+Possible values are 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256
+and 320. Default is 224.
+
+ Mode:
+Possible values are 0 (stereo), 1 (joint stereo, the default), 2 (dual channel)
+and 3 (mono).
+
+ Outlet:
+The outlet outputs an int, which the number of bytes written in this session.
+this might be different from file size if you're using append mode.
+
+
+ Known Problems :
+
+All combinations of samplerate, bitrate, quality factor will not be accepted.
+
+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 SAMPLERATE/BITRATES
+
+MPEG-1 layer III sample frequencies (kHz): 32 48 44.1
+bitrates (kbps): 32 40 48 56 64 80 96 112 128 160 192 224 256 320
+
+MPEG-2 layer III sample frequencies (kHz): 16 24 22.05
+bitrates (kbps): 8 16 24 32 40 48 56 64 80 96 112 128 144 160
+
+MPEG-2.5 layer III sample frequencies (kHz): 8 12 11.025
+bitrates (kbps): 8 16 24 32 40 48 56 64 80 96 112 128 144 160
+
+Furthermore, it seems that high quality factors will not work
+with this release of lame ( 3.92 ).
+The same errors can be obtained with the command line :
+lame -q 1 file.wav
+outputs errors and mp3write can't do better.
+
+
diff --git a/mp3write~/help-mp3write~.pd b/mp3write~/help-mp3write~.pd
new file mode 100644
index 0000000..0e575ba
--- /dev/null
+++ b/mp3write~/help-mp3write~.pd
@@ -0,0 +1,43 @@
+#N canvas 168 244 736 325 10;
+#X floatatom 53 24 0 40 16000;
+#X msg 168 278 \; pd dsp 1;
+#X text 287 196 <-- settings for mp3 stream;
+#X text 310 226 bitrate: bitrate of stream \, def. 224kbit/s;
+#X text 347 250 1 = joint stereo (default);
+#X text 307 288 quality: 1 = high \, 9 = low;
+#X text 308 208 (samplerate \, bitrate \, mode \, quality);
+#X text 311 238 mode: 0 = stereo;
+#X text 347 262 2 = dual channel;
+#X text 347 275 3 = mono;
+#X msg 171 143 print;
+#X msg 234 278 \; pd dsp 0;
+#X obj 51 59 osc~ 440;
+#X msg 169 174 mpeg 44100 128 1 4;
+#X msg 171 121 truncate;
+#X msg 171 98 append;
+#X msg 170 72 stop;
+#X msg 170 49 start;
+#X text 370 24 Open a file before any operations;
+#X text 228 95 Set recording mode to append ( which is the default
+);
+#X text 208 48 Start recording;
+#X text 231 118 Set recording mode to truncate;
+#X text 218 142 Print settings;
+#X floatatom 116 258 10 0 0;
+#X text 10 254 Bytes written;
+#X text 208 71 Stop recording ( this also writes a tag );
+#X msg 169 198 mpeg 44100 8 3 5;
+#X msg 170 25 open /tmp/track1.mp3;
+#X obj 116 234 mp3write~;
+#X connect 0 0 12 0;
+#X connect 10 0 28 0;
+#X connect 12 0 28 0;
+#X connect 12 0 28 1;
+#X connect 13 0 28 0;
+#X connect 14 0 28 0;
+#X connect 15 0 28 0;
+#X connect 16 0 28 0;
+#X connect 17 0 28 0;
+#X connect 26 0 28 0;
+#X connect 27 0 28 0;
+#X connect 28 0 23 0;
diff --git a/mp3write~/interface.h b/mp3write~/interface.h
new file mode 100644
index 0000000..de3136a
--- /dev/null
+++ b/mp3write~/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/mp3write~/mp3write~.c b/mp3write~/mp3write~.c
new file mode 100644
index 0000000..fe8cb47
--- /dev/null
+++ b/mp3write~/mp3write~.c
@@ -0,0 +1,721 @@
+/* ------------------------ mp3write~ ----------------------------------------- */
+/* */
+/* Tilde object to record audio in mp3 format */
+/* Note that it is, in no way, related to mp3play~ */
+/* Written by Yves Degoyon (ydegoyon@free.fr). */
+/* Tarballs and updates at 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 version 3.92 */
+/* Get it via http://www.freshmeat.net */
+/* */
+/* "All this talk of blood and iron is the cause of all my kicking" */
+/* Gang Of Four - "Guns Before Butter" */
+/* ---------------------------------------------------------------------------- */
+
+
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+#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 <sys/types.h>
+#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 */
+
+#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 *mp3write_version = "mp3write~: mp3 file recorder version 0.4, written by Yves Degoyon";
+static int sockfd;
+
+#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 *mp3write_class;
+
+typedef struct _mp3write
+{
+ t_object x_obj;
+
+ /* LAME stuff */
+ int x_lame; /* info about encoder status */
+ int x_lamechunk; /* chunk size for LAME encoder */
+
+ /* 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 */
+ int x_mp3size; /* number of returned mp3 samples */
+ 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 */
+
+ /* recording stuff */
+ int x_fd; /* file descriptor of the mp3 output */
+ int x_file_open_mode; /* file opening mode */
+ int x_byteswritten; /* number of bytes written */
+ int x_recflag; /* recording flag toggled by messages "start" and "stop" */
+
+ t_float x_f; /* float needed for signal input */
+ char *x_title; /* title of the mp3 */
+
+#ifdef UNIX
+ lame_global_flags *lgfp; /* lame encoder configuration */
+#endif
+} t_mp3write;
+
+
+ /* encode PCM data to mp3 stream */
+static void mp3write_encode(t_mp3write *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 so that it won't interfere with inpoint */
+ if(x->x_start == -1)
+ {
+ post("mp3write~: reseting buffer positions");
+ /* 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("mp3write~: 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);
+ // post( "mp3write~ : encoding returned %d frames", x->x_mp3size );
+#endif
+
+ /* check result */
+#ifndef UNIX
+ if(err != BE_ERR_SUCCESSFUL)
+ {
+ closeStream(x->x_lame);
+ error("mp3write~: lameEncodeChunk() failed (%lu)", err);
+#else
+ if(x->x_mp3size<0)
+ {
+ lame_close( x->lgfp );
+ error("mp3write~: lame_encode_buffer_interleaved failed (%d)", x->x_mp3size);
+#endif
+ x->x_lame = -1;
+ }
+}
+
+ /* store mp3 frames in the file */
+static void mp3write_writeframes(t_mp3write *x)
+{
+ int err = -1; /* error return code */
+
+ if ( x->x_fd < 0 ) {
+ post( "mp3write~ : error : trying to write frames but no valid file is opened" );
+ return;
+ }
+
+#ifndef UNIX
+ err = _write(x->x_fd, x->x_mp3outbuf, x->x_mp3size);
+#else
+ err = write(x->x_fd, x->x_mp3outbuf, x->x_mp3size);
+#endif
+
+ if(err < 0)
+ {
+ error("mp3write~: could not write encoded data to file (%d)", err);
+#ifndef UNIX
+ closeStream(x->x_lame);
+#else
+ lame_close( x->lgfp );
+#endif
+ x->x_lame = -1;
+#ifndef UNIX
+ error("mp3write~: writing data");
+ _close(x->x_fd);
+#else
+ perror("mp3write~: writing data");
+ close(x->x_fd);
+#endif
+ x->x_fd = -1;
+ }
+ else
+ {
+ x->x_byteswritten += err;
+ outlet_float( x->x_obj.ob_outlet, x->x_byteswritten );
+ }
+ if((err > 0)&&(err != x->x_mp3size))error("mp3write~: %d bytes skipped", x->x_mp3size - err);
+}
+
+
+ /* buffer data as channel interleaved PCM */
+static t_int *mp3write_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_mp3write *x = (t_mp3write *)(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)&&(x->x_recflag))
+ {
+ /* count buffered samples when things are running */
+ x->x_bytesbuffered += n;
+
+ /* encode and send to server */
+ if(x->x_bytesbuffered > x->x_lamechunk)
+ {
+ mp3write_encode(x); /* encode to mp3 */
+ mp3write_writeframes(x); /* write mp3 to file */
+ x->x_bytesbuffered -= x->x_lamechunk;
+ }
+ }
+ else
+ {
+ x->x_start = -1;
+ }
+ return (w+5);
+}
+
+static void mp3write_dsp(t_mp3write *x, t_signal **sp)
+{
+ dsp_add(mp3write_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n);
+}
+
+ /* initialize the lame library */
+static int mp3write_tilde_lame_init(t_mp3write *x)
+{
+ time_t now;
+
+#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("mp3write~: error loading lame_enc.dll");
+ closesocket(x->x_fd);
+ x->x_fd = -1;
+ post("mp3write~: connection closed");
+ return -1;
+ }
+
+ /* 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("mp3write~: unable to get LAME interfaces");
+ closesocket(x->x_fd);
+ x->x_fd = -1;
+ post("mp3write~: connection closed");
+ return -1;
+ }
+
+ /* get LAME version number */
+ dllVersion(&lameVersion);
+
+ post( "mp3write~: 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( "mp3write~ : 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("mp3write~: error opening encoding stream (%lu)", ret);
+ return -1;
+ }
+
+#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( "mp3write~ : error : lame params initialization returned : %d", ret );
+ return -1;
+ } else {
+ x->x_lame=1;
+ /* magic formula copied from windows dll for MPEG-I */
+ x->x_lamechunk = 2*1152;
+
+ post( "mp3write~ : lame initialization done. (%d)", x->x_lame );
+ }
+ lame_init_bitstream( x->lgfp );
+
+ /* setting tag information */
+ id3tag_init(x->lgfp);
+ id3tag_v1_only(x->lgfp);
+ id3tag_space_v1(x->lgfp);
+ id3tag_set_artist(x->lgfp, "Pd Session");
+ now=time(NULL);
+ sprintf( x->x_title, "Started at %s", ctime(&now) );
+ id3tag_set_title(x->lgfp, x->x_title );
+
+#endif
+ return 0;
+
+}
+
+ /* open file and initialize lame */
+static void mp3write_open(t_mp3write *x, t_symbol *sfile)
+{
+ if ( mp3write_tilde_lame_init(x) < 0 ) {
+ error( "mp3write~ : lame initialization failed ... check parameters.");
+ return;
+ }
+
+ /* closing previous file descriptor */
+ if ( x->x_fd > 0 ) {
+#ifndef UNIX
+ if(_close(x->x_fd) < 0 )
+#else
+ if(close(x->x_fd) < 0)
+#endif
+ {
+ perror( "mp3write~ : closing file" );
+ }
+ }
+
+ if ( x->x_recflag ) {
+ x->x_recflag = 0;
+ }
+
+#ifndef UNIX
+ if ( ( x->x_fd = _open( sfile->s_name, x->x_file_open_mode, _S_IREAD|_S_IWRITE) ) < 0 )
+#else
+ if ( ( x->x_fd = open( sfile->s_name, x->x_file_open_mode, S_IRWXU|S_IRWXG|S_IRWXO ) ) < 0 )
+#endif
+ {
+ error( "mp3write~ : cannot open >%s<", sfile->s_name);
+ x->x_fd=-1;
+ return;
+ }
+ x->x_byteswritten = 0;
+ post( "mp3write~ : opened >%s< fd=%d", sfile->s_name, x->x_fd);
+}
+
+ /* setting file write mode to append */
+static void mp3write_append(t_mp3write *x)
+{
+#ifndef UNIX
+ x->x_file_open_mode = _O_CREAT|_O_WRONLY|_O_APPEND|_O_BINARY;
+#else
+ x->x_file_open_mode = O_CREAT|O_WRONLY|O_APPEND|O_NONBLOCK;
+#endif
+ if(x->x_fd>=0)post("mp3write~ : mode set to append : open a new file to make changes take effect! ");
+}
+
+ /* setting file write mode to truncate */
+static void mp3write_truncate(t_mp3write *x)
+{
+#ifndef UNIX
+ x->x_file_open_mode = _O_CREAT|_O_WRONLY|_O_TRUNC|_O_BINARY;
+#else
+ x->x_file_open_mode = O_CREAT|O_WRONLY|O_TRUNC|O_NONBLOCK;
+#endif
+ if(x->x_fd>=0)post("mp3write~ : mode set to truncate : open a new file to make changes take effect! ");
+}
+
+ /* settings for mp3 encoding */
+static void mp3write_mpeg(t_mp3write *x, t_floatarg fsamplerate, t_floatarg fbitrate,
+ t_floatarg fmode, t_floatarg fquality)
+{
+ x->x_samplerate = fsamplerate;
+ if(fbitrate > MAXDATARATE)
+ {
+ fbitrate = MAXDATARATE;
+ }
+ x->x_bitrate = fbitrate;
+ x->x_mp3mode = fmode;
+ x->x_mp3quality = fquality;
+ post("mp3write~: setting mp3 stream to %dHz, %dkbit/s, mode %d, quality %d",
+ x->x_samplerate, x->x_bitrate, x->x_mp3mode, x->x_mp3quality);
+ if(x->x_fd>=0)post("mp3write~ : restart recording to make changes take effect! ");
+}
+
+ /* print settings */
+static void mp3write_print(t_mp3write *x)
+{
+ const char * buf = 0;
+ post(mp3write_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);
+ }
+}
+
+ /* start recording */
+static void mp3write_start(t_mp3write *x)
+{
+ if ( x->x_fd < 0 ) {
+ post("mp3write~: start received but no file has been set ... ignored.");
+ return;
+ }
+
+ if ( x->x_recflag == 1 ) {
+ post("mp3write~: start received but recording is started ... ignored.");
+ return;
+ }
+
+ x->x_recflag = 1;
+ post("mp3write~: start recording");
+}
+
+ /* stop recording */
+static void mp3write_stop(t_mp3write *x)
+{
+ int err = -1;
+
+ if ( x->x_fd < 0 ) {
+ post("mp3write~: stop received but no file has been set ... ignored.");
+ return;
+ }
+
+ if ( x->x_recflag == 0 ) {
+ post("mp3write~: stop received but recording is stopped ... ignored.");
+ return;
+ }
+ /* first stop recording / buffering and so on, than do the rest */
+ x->x_recflag = 0;
+
+ /* flushing remaining frames and tag */
+#ifndef UNIX
+ deinitStream(x->x_lame, x->x_mp3outbuf, &x->x_mp3size);
+#else
+ x->x_mp3size = lame_encode_flush( x->lgfp, x->x_mp3outbuf, MY_MP3_MALLOC_OUT_SIZE );
+#endif
+
+ mp3write_writeframes(x); /* write mp3 to file */
+
+ x->x_recflag = 0;
+ post("mp3write~: stop recording, flushed %d bytes", x->x_mp3size);
+}
+
+ /* clean up */
+static void mp3write_free(t_mp3write *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
+ _close(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));
+ freebytes( x->x_title, 255 );
+}
+
+static void *mp3write_new(void)
+{
+ t_mp3write *x = (t_mp3write *)pd_new(mp3write_class);
+ inlet_new (&x->x_obj, &x->x_obj.ob_pd, gensym ("signal"), gensym ("signal"));
+ outlet_new (&x->x_obj, &s_float);
+ x->x_fd = -1;
+#ifndef UNIX
+ x->x_file_open_mode = _O_CREAT|_O_WRONLY|_O_APPEND|_O_BINARY;
+#else
+ x->x_file_open_mode = O_CREAT|O_WRONLY|O_APPEND|O_NONBLOCK;
+#endif
+ x->x_lame = -1;
+ x->x_samplerate = sys_getsr();
+ x->x_bitrate = 128;
+ x->x_byteswritten = 0;
+ x->x_mp3mode = 1;
+ x->lgfp = NULL;
+ x->x_title = getbytes( 255 );
+ 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*sizeof(char)); /* 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("mp3write~ : cannot allocate internal buffers");
+ return NULL;
+ }
+ x->x_bytesbuffered = 0;
+ x->x_inp = 0;
+ x->x_outp = 0;
+ x->x_start = -1;
+ return(x);
+}
+
+void mp3write_tilde_setup(void)
+{
+ post(mp3write_version);
+ mp3write_class = class_new(gensym("mp3write~"), (t_newmethod)mp3write_new, (t_method)mp3write_free,
+ sizeof(t_mp3write), 0, 0);
+ CLASS_MAINSIGNALIN(mp3write_class, t_mp3write, x_f );
+ class_sethelpsymbol(mp3write_class, gensym("help-mp3write~.pd"));
+ class_addmethod(mp3write_class, (t_method)mp3write_dsp, gensym("dsp"), 0);
+ class_addmethod(mp3write_class, (t_method)mp3write_open, gensym("open"), A_SYMBOL, 0);
+ class_addmethod(mp3write_class, (t_method)mp3write_mpeg, gensym("mpeg"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(mp3write_class, (t_method)mp3write_start, gensym("start"), 0);
+ class_addmethod(mp3write_class, (t_method)mp3write_stop, gensym("stop"), 0);
+ class_addmethod(mp3write_class, (t_method)mp3write_print, gensym("print"), 0);
+ class_addmethod(mp3write_class, (t_method)mp3write_append, gensym("append"), 0);
+ class_addmethod(mp3write_class, (t_method)mp3write_truncate, gensym("truncate"), 0);
+}
diff --git a/mp3write~/mpg123.h b/mp3write~/mpg123.h
new file mode 100644
index 0000000..1c530d3
--- /dev/null
+++ b/mp3write~/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/mp3write~/mpglib.h b/mp3write~/mpglib.h
new file mode 100644
index 0000000..1f4ef9a
--- /dev/null
+++ b/mp3write~/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/randomblock~/INSTALL b/randomblock~/INSTALL
new file mode 100644
index 0000000..ae90f70
--- /dev/null
+++ b/randomblock~/INSTALL
@@ -0,0 +1,7 @@
+untar in /my/pd/dir/extra
+
+cd /my/pd/dir/extra/randomblock~
+
+make
+
+you're set !!
diff --git a/randomblock~/Makefile b/randomblock~/Makefile
new file mode 100644
index 0000000..de2ce94
--- /dev/null
+++ b/randomblock~/Makefile
@@ -0,0 +1,82 @@
+NAME=randomblock~
+CSYM=randomblock_tilde
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).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
+
+.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
+
+.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
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -DUNIX -DICECAST -O2 -funroll-loops -fomit-frame-pointer \
+ -Wshadow -Wstrict-prototypes\
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+LINUXINCLUDE = -I../../src
+
+.c.pd_linux:
+ cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ ld -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm -L/usr/local/lib
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o ../$*.pd_linux
+ ln -s $*/$*.pd_linux ..
+
+# ----------------------------------------------------------
+
+clean:
+ rm -f *.o *.pd_* so_locations
+
+install:
+ cp help-* ../../doc/5.reference
diff --git a/randomblock~/help-randomblock~.pd b/randomblock~/help-randomblock~.pd
new file mode 100644
index 0000000..d4b2e5d
--- /dev/null
+++ b/randomblock~/help-randomblock~.pd
@@ -0,0 +1,15 @@
+#N canvas 194 211 575 337 10;
+#X msg 361 263 \; pd dsp 1;
+#X floatatom 192 112 5 0 0;
+#X text 191 88 Set upper limit of random values;
+#X text 107 123 Not used;
+#X obj 121 179 print~;
+#X msg 76 156 bang;
+#X text 160 29 Generates an audio block starting at a random value
+;
+#X obj 121 143 randomblock~ 100;
+#X text 161 42 This can be used to read a table randomly.;
+#X text 161 54 This is illustrated in "mrandtab.pd".;
+#X connect 1 0 7 1;
+#X connect 5 0 4 0;
+#X connect 7 0 4 0;
diff --git a/randomblock~/mrandtab.pd b/randomblock~/mrandtab.pd
new file mode 100644
index 0000000..157111c
--- /dev/null
+++ b/randomblock~/mrandtab.pd
@@ -0,0 +1,6 @@
+#N canvas 187 22 737 487 10;
+#X obj 138 151 dac~;
+#X obj 136 114 randtab;
+#X text 174 86 Everything is in the subpatch;
+#X connect 1 0 0 0;
+#X connect 1 0 0 1;
diff --git a/randomblock~/randomblock~.c b/randomblock~/randomblock~.c
new file mode 100644
index 0000000..69f4da5
--- /dev/null
+++ b/randomblock~/randomblock~.c
@@ -0,0 +1,117 @@
+/* ------------------------ randomblock~ -------------------------------------- */
+/* */
+/* Generates a random signal block */
+/* Written by Yves Degoyon (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. */
+/* */
+/* ---------------------------------------------------------------------------- */
+
+
+
+#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>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "m_pd.h" /* standard pd stuff */
+
+static char *randomblock_version = "randomblock~: generates a random audio block : author : ydegoyon@free.fr";
+
+static t_class *randomblock_class;
+
+typedef struct _randomblock
+{
+ t_object x_obj;
+ t_int x_limit;
+} t_randomblock;
+
+ /* clean up */
+static void randomblock_free(t_randomblock *x)
+{
+}
+
+static void *randomblock_new(t_float flimit)
+{
+ t_randomblock *x = (t_randomblock *)pd_new(randomblock_class);
+ outlet_new(&x->x_obj, &s_signal);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("limit"));
+ if ( flimit <= 0 || flimit > RAND_MAX ) {
+ post( "randomblock~: wrong creation argument" );
+ return NULL;
+ }
+ x->x_limit = (int) flimit;
+ return(x);
+}
+
+static void *randomblock_limit(t_randomblock* x, t_float flimit)
+{
+ if ( flimit < 0 || flimit > RAND_MAX ) {
+ post( "randomblock~: wrong random limit" );
+ return;
+ } else {
+ x->x_limit=(int)flimit;
+ }
+}
+
+static t_int *randomblock_perform(t_int *w)
+{
+ t_float *out = (t_float*) w[1];
+ int n = (int)(w[2]);
+ t_randomblock *x = (t_randomblock*) w[3];
+
+ int rvalue = rand();
+ // post("random value : %d", rvalue );
+ rvalue = rvalue%(x->x_limit-n);
+ // post("modulated by %d : %d", (x->x_limit-n), rvalue );
+ if ( rvalue < 0 ) rvalue=0;
+
+ while (n--) {
+ *(out)++=(float)rvalue++;
+ }
+
+ return (w+4);
+}
+
+static void randomblock_dsp(t_randomblock *x, t_signal **sp)
+{
+ dsp_add( randomblock_perform, 3, sp[0]->s_vec, sp[0]->s_n, x ) ;
+}
+
+void randomblock_tilde_setup(void)
+{
+ post(randomblock_version);
+ randomblock_class = class_new(gensym("randomblock~"), (t_newmethod)randomblock_new,
+ (t_method)randomblock_free,
+ sizeof(t_randomblock), 0, A_DEFFLOAT, 0);
+ class_addmethod( randomblock_class, (t_method)randomblock_dsp, gensym("dsp"), 0);
+ class_addmethod( randomblock_class, (t_method)randomblock_limit, gensym("limit"), A_FLOAT, 0);
+ class_sethelpsymbol( randomblock_class, gensym("help-randomblock~.pd"));
+}
diff --git a/randomblock~/randtab.pd b/randomblock~/randtab.pd
new file mode 100644
index 0000000..089a86e
--- /dev/null
+++ b/randomblock~/randtab.pd
@@ -0,0 +1,43 @@
+#N canvas 187 22 737 487 10;
+#X obj 143 114 soundfiler;
+#X obj 110 354 *~;
+#X msg 138 3 bang;
+#X msg 142 92 read -resize \$1 \$2;
+#X msg 215 12 bang;
+#X obj 515 47 table \$0-music;
+#X obj 144 66 pack s s;
+#X obj 215 35 f \$0;
+#X obj 231 56 makefilename %d-music;
+#X symbolatom 247 35 40 0 0;
+#X floatatom 163 244 10 0 0;
+#X floatatom 142 353 5 0 0;
+#X obj 110 303 tabread4~ \$0-music;
+#X obj 20 331 print~;
+#X msg 19 307 bang;
+#X obj 138 29 opanel;
+#X obj 109 330 /~ 100;
+#X obj 34 235 randomblock~ 1000;
+#X obj 241 325 print~;
+#X msg 240 301 bang;
+#X obj 110 401 outlet~;
+#X obj 402 206 block~ 32768 1;
+#X connect 0 0 10 0;
+#X connect 0 0 17 1;
+#X connect 1 0 20 0;
+#X connect 2 0 15 0;
+#X connect 3 0 0 0;
+#X connect 4 0 7 0;
+#X connect 6 0 3 0;
+#X connect 7 0 8 0;
+#X connect 8 0 6 1;
+#X connect 11 0 1 1;
+#X connect 12 0 16 0;
+#X connect 12 0 18 0;
+#X connect 14 0 13 0;
+#X connect 15 0 4 0;
+#X connect 15 0 6 0;
+#X connect 15 0 9 0;
+#X connect 16 0 1 0;
+#X connect 17 0 12 0;
+#X connect 17 0 13 0;
+#X connect 19 0 18 0;
diff --git a/samplebox~/CHANGES.LOG b/samplebox~/CHANGES.LOG
new file mode 100644
index 0000000..e83144d
--- /dev/null
+++ b/samplebox~/CHANGES.LOG
@@ -0,0 +1,6 @@
+0.3
+ Reworked allocation
+0.2
+ Reworked interpolation
+0.1
+ First implementation
diff --git a/samplebox~/INSTALL b/samplebox~/INSTALL
new file mode 100644
index 0000000..c0dc546
--- /dev/null
+++ b/samplebox~/INSTALL
@@ -0,0 +1,9 @@
+untar in /my/pd/dir/externs
+
+cd /my/pd/dir/externs/samplebox~
+
+make
+
+make install
+
+you're set !!
diff --git a/samplebox~/Makefile b/samplebox~/Makefile
new file mode 100644
index 0000000..72194fe
--- /dev/null
+++ b/samplebox~/Makefile
@@ -0,0 +1,97 @@
+NAME=samplebox~
+CSYM=samplebox_tilde
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).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
+
+.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
+
+.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
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -DUNIX -DICECAST -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
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o ../$*.pd_linux
+ ln -s $*/$*.pd_linux ..
+
+# ----------------------- Mac OSX -----------------------
+
+pd_darwin: $(NAME).pd_darwin
+
+.SUFFIXES: .pd_darwin
+
+DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+.c.pd_darwin:
+ cc $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ cc -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
+ rm -f $*.o ../$*.pd_darwin
+ ln -s $*/$*.pd_darwin ..
+
+# ----------------------------------------------------------
+
+install:
+ cp help-*.pd ../../doc/5.reference
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/samplebox~/README b/samplebox~/README
new file mode 100644
index 0000000..06bb14c
--- /dev/null
+++ b/samplebox~/README
@@ -0,0 +1,19 @@
+Version 0.01
+copyleft 2001 by Yves Degoyon
+tarballs and updates available @ http://ydegoyon.free.fr
+
+samplebox~.dll : an opaque box to record and playback a sound ( with speed variations )
+
+To install sonograph~, 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.
+
+*****************************************************************************
+
+
diff --git a/samplebox~/help-samplebox~.pd b/samplebox~/help-samplebox~.pd
new file mode 100644
index 0000000..9b5b6f5
--- /dev/null
+++ b/samplebox~/help-samplebox~.pd
@@ -0,0 +1,145 @@
+#N canvas 19 6 986 684 10;
+#X obj 126 505 dac~;
+#X msg 183 318 record;
+#X msg 271 39 play;
+#X obj 342 252 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 1;
+#X text 309 250 0 %;
+#X text 476 251 100 %;
+#X obj 343 270 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 12700 1;
+#X text 310 271 0 %;
+#X text 478 269 100 %;
+#X msg 352 504 \; pd dsp 1;
+#X msg 414 505 \; pd dsp 0;
+#X text 606 251 Start Point;
+#X text 608 269 End Point;
+#X msg 19 21 bang;
+#X obj 19 41 openpanel;
+#X obj 19 187 soundfiler;
+#X msg 15 306 bang;
+#X msg 512 271 100;
+#X obj 544 270 loadbang;
+#X text 19 546 3s * samplerate / blocksize ( 3*44100/64 = 2067 );
+#X floatatom 49 207 10 0 0;
+#X obj 18 207 / 64;
+#X msg 122 207 resize \$1;
+#X obj 19 63 t s b;
+#X text 35 592 Comments and bugs @ ydegoyon@free.fr;
+#X obj 65 63 float \$0;
+#X obj 19 80 route float;
+#X msg 339 318 flipblocks;
+#X text 410 318 Flip blocks ( reverse effect );
+#X msg 338 294 swapblocks 0 50 20;
+#X text 23 5 Step 1 : Load a sound file;
+#X msg 274 132 phase \$1;
+#X obj 365 130 hsl 128 15 0 90 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 1;
+#X obj 273 62 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 1;
+#X text 247 63 0 %;
+#X text 407 62 100 %;
+#X obj 274 81 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 12700 1;
+#X text 248 84 0 %;
+#X text 409 80 100 %;
+#X text 551 61 Start Point;
+#X text 552 80 End Point;
+#X msg 443 78 100;
+#X obj 470 78 loadbang;
+#X text 630 69 Playback positions;
+#X msg 268 103 readspeed \$1;
+#X floatatom 399 103 5 0 0;
+#X text 553 101 Reading speed;
+#X obj 358 103 / 100;
+#X msg 448 104 100;
+#X obj 477 104 loadbang;
+#X obj 223 447 samplebox~ 2067;
+#X text 16 282 Step 2 : Record the sound;
+#X text 276 15 Step 3 : Play back recorded sound;
+#X text 341 222 Step 4 : modify parts of the sound;
+#X text 474 293 Swap sections [0% \, 20%] and [50% \, 70%] of [start
+\, end];
+#X text 21 533 Note : initially \, this is a 3 seconds samplebox~ :
+;
+#X text 34 581 Samplebox records and plays back a sound;
+#X text 342 235 Set portions of the sound to modify;
+#X text 500 132 100%;
+#X text 341 131 0%;
+#X obj 44 100 makefilename %d-leftsample;
+#X obj 511 512 table \$0-leftsample;
+#X obj 650 511 table \$0-rightsample;
+#X obj 45 123 makefilename %d-rightsample;
+#X obj 20 149 pack s s s;
+#X msg 19 170 read -resize \$1 \$2 \$3;
+#X obj 16 343 tabplay~ \$0-leftsample;
+#X obj 80 363 tabplay~ \$0-rightsample;
+#X obj 278 474 print recordend;
+#X obj 399 472 print playend;
+#X text 552 127 Switch channels ( use as pan for mono input );
+#X msg 456 159 bang;
+#X text 557 161 Ping-pong ( requires countund object );
+#X obj 305 160 countund 90;
+#X obj 113 481 *~;
+#X obj 144 479 / 100;
+#X floatatom 74 447 5 0 0;
+#X obj 184 478 *~;
+#X obj 211 477 / 100;
+#X obj 384 159 metro 100;
+#X obj 28 423 loadbang;
+#X msg 28 449 100;
+#X connect 1 0 50 0;
+#X connect 2 0 50 0;
+#X connect 3 0 50 4;
+#X connect 6 0 50 5;
+#X connect 13 0 14 0;
+#X connect 14 0 23 0;
+#X connect 15 0 21 0;
+#X connect 16 0 1 0;
+#X connect 16 0 66 0;
+#X connect 16 0 67 0;
+#X connect 17 0 6 0;
+#X connect 18 0 17 0;
+#X connect 20 0 22 0;
+#X connect 21 0 20 0;
+#X connect 22 0 50 0;
+#X connect 23 0 64 0;
+#X connect 23 1 25 0;
+#X connect 25 0 26 0;
+#X connect 26 0 60 0;
+#X connect 26 0 63 0;
+#X connect 27 0 50 0;
+#X connect 29 0 50 0;
+#X connect 31 0 50 0;
+#X connect 32 0 31 0;
+#X connect 33 0 50 2;
+#X connect 36 0 50 3;
+#X connect 41 0 36 0;
+#X connect 42 0 41 0;
+#X connect 44 0 50 0;
+#X connect 45 0 47 0;
+#X connect 47 0 44 0;
+#X connect 48 0 45 0;
+#X connect 49 0 48 0;
+#X connect 50 0 74 0;
+#X connect 50 1 77 0;
+#X connect 50 2 68 0;
+#X connect 50 3 69 0;
+#X connect 50 3 2 0;
+#X connect 60 0 64 1;
+#X connect 63 0 64 2;
+#X connect 64 0 65 0;
+#X connect 65 0 15 0;
+#X connect 66 0 50 0;
+#X connect 67 0 50 1;
+#X connect 71 0 79 0;
+#X connect 73 0 31 0;
+#X connect 74 0 0 0;
+#X connect 75 0 74 1;
+#X connect 76 0 75 0;
+#X connect 76 0 78 0;
+#X connect 77 0 0 1;
+#X connect 78 0 77 1;
+#X connect 79 0 73 0;
+#X connect 80 0 81 0;
+#X connect 81 0 76 0;
diff --git a/samplebox~/samplebox~.c b/samplebox~/samplebox~.c
new file mode 100644
index 0000000..e276df5
--- /dev/null
+++ b/samplebox~/samplebox~.c
@@ -0,0 +1,529 @@
+/*------------------------ samplebox~ ----------------------------------------- */
+/* */
+/* samplebox~ : records and plays back a sound */
+/* Written by Yves Degoyon ( 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. */
+/* */
+/* All i wanted is your time */
+/* All you gave me was tomorrow */
+/* But, tomorrow never comes, tomorrow never comes */
+/* Vini Reilly -- "Tomorrow" */
+/* ---------------------------------------------------------------------------- */
+
+
+
+#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>
+#endif
+#ifdef NT
+#define M_PI 3.14159265358979323846
+#endif
+#include <math.h>
+
+#include "m_pd.h" /* standard pd stuff */
+
+static char *samplebox_version = "samplebox~: stores and plays back a sound version 0.3, written by Yves Degoyon (ydegoyon@free.fr)";
+
+
+static t_class *samplebox_class;
+
+typedef struct _samplebox
+{
+ t_object x_obj;
+
+ t_int x_size; /* size of the stored sound ( in blocks~ ) */
+ t_float x_samplerate; /* sample rate */
+ t_int x_blocksize; /* current block size ( might be modified by block~ object ) */
+ t_float x_readpos; /* data's playing position */
+ t_int x_writepos; /* data's recording position */
+ t_int x_readstart; /* data's starting position for reading */
+ t_int x_readend; /* data's ending position for reading */
+ t_int x_modstart; /* data's starting position for modifications */
+ t_int x_modend; /* data's ending position for modifications */
+ t_int x_play; /* playing on/off flag */
+ t_float x_readspeed; /* number of grouped blocks for reading */
+ t_float x_record; /* flag to start recording process */
+ t_float x_allocate; /* flag to avoid reading data during generation */
+ t_float *x_rdata; /* table containing left channel of the sound */
+ t_float *x_idata; /* table containing right channel of the sound */
+ t_float *x_rootsquares; /* sum of the root squares of a block ( energy ) */
+ t_float x_phase; /* phase to apply on output */
+ t_outlet *x_recordend; /* outlet for end of recording */
+ t_outlet *x_playend; /* outlet for end of playing back */
+ t_float x_f; /* float needed for signal input */
+
+} t_samplebox;
+
+ /* clean up */
+static void samplebox_free(t_samplebox *x)
+{
+ if ( x->x_rdata != NULL ) {
+ freebytes(x->x_rdata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_rdata = NULL;
+ }
+ if ( x->x_idata != NULL ) {
+ freebytes(x->x_idata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_idata = NULL;
+ }
+ if ( x->x_rootsquares != NULL ) {
+ freebytes(x->x_rootsquares, x->x_size*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*sizeof(float) );
+ x->x_rootsquares = NULL;
+ }
+}
+
+ /* allocate tables for storing sound */
+static t_int samplebox_allocate(t_samplebox *x)
+{
+ if ( !(x->x_rdata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ return -1;
+ } else {
+ post( "samplebox~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_idata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ return -1;
+ } else {
+ post( "samplebox~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_rootsquares = getbytes( x->x_size*sizeof(float) ) ) ) {
+ return -1;
+ } else {
+ post( "samplebox~ : allocated %d bytes", x->x_size*sizeof(float) );
+ }
+ return 0;
+}
+
+ /* reallocate tables for storing sound */
+static t_int samplebox_reallocate(t_samplebox *x, t_int ioldsize, t_int inewsize)
+{
+ t_float *prdata=x->x_rdata, *pidata=x->x_idata, *prootsquares=x->x_rootsquares;
+
+ if ( !(x->x_rdata = getbytes( inewsize*x->x_blocksize*sizeof(float) ) ) ) {
+ return -1;
+ } else {
+ post( "samplebox~ : allocated %d bytes", inewsize*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_idata = getbytes( inewsize*x->x_blocksize*sizeof(float) ) ) ) {
+ return -1;
+ } else {
+ post( "samplebox~ : allocated %d bytes", inewsize*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_rootsquares = getbytes( inewsize*sizeof(float) ) ) ) {
+ return -1;
+ } else {
+ post( "samplebox~ : allocated %d bytes", inewsize*sizeof(float) );
+ }
+ if ( prdata != NULL ) {
+ freebytes(prdata, ioldsize*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", ioldsize*x->x_blocksize*sizeof(float) );
+ }
+ if ( pidata != NULL ) {
+ freebytes(pidata, ioldsize*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", ioldsize*x->x_blocksize*sizeof(float) );
+ }
+ if ( prootsquares != NULL ) {
+ freebytes(prootsquares, ioldsize*sizeof(float) );
+ post( "Freed %d bytes", ioldsize*sizeof(float) );
+ }
+ return 0;
+}
+
+ /* records or playback the sonogram */
+static t_int *samplebox_perform(t_int *w)
+{
+ t_float *rin = (t_float *)(w[1]);
+ t_float *iin = (t_float *)(w[2]);
+ t_float *rout = (t_float *)(w[3]);
+ t_float *iout = (t_float *)(w[4]);
+ t_float fspectrum = 0.0;
+ t_float fphase = 0.0;
+ t_int rpoint;
+ t_int n = (int)(w[5]); /* number of samples */
+ t_samplebox *x = (t_samplebox *)(w[6]);
+ t_int bi;
+ t_float v[4];
+ t_float z[4];
+
+ // reallocate tables if blocksize has been changed
+ if ( n != x->x_blocksize ) {
+ post( "samplebox~ : reallocating tables" );
+ x->x_allocate = 1;
+ samplebox_free(x);
+ x->x_blocksize = n;
+ samplebox_allocate(x);
+ x->x_allocate = 0;
+ }
+
+ // new block : energy is set to zero
+ // if ( x->x_record ) {
+ // *(x->x_rootsquares+x->x_writepos) = 0.0;
+ // }
+
+ if ( x->x_play || x->x_record ) {
+ bi = 0;
+ while (bi<n) {
+ // eventually records input
+ if ( !x->x_allocate && x->x_record) {
+ *(x->x_rdata+(x->x_writepos*x->x_blocksize)+bi)=*rin;
+ *(x->x_idata+(x->x_writepos*x->x_blocksize)+bi)=*iin;
+ // *(x->x_rootsquares+x->x_writepos) += sqrt( pow((*rin),2) + pow((*iin),2) );
+ }
+ // set outputs
+ if ( !x->x_allocate && x->x_play) {
+ *rout = 0.;
+ *iout = 0.;
+ // interpolates 4 points like tabread4
+ rpoint = ((int)x->x_readpos*x->x_blocksize)+bi;
+
+ if ( rpoint == 0 ) {
+ v[0]=0.0;
+ v[1]=*(x->x_rdata+rpoint);
+ v[2]=*(x->x_rdata+rpoint+1);
+ v[3]=*(x->x_rdata+rpoint+2);
+ z[0]=0.0;
+ z[1]=*(x->x_idata+rpoint);
+ z[2]=*(x->x_idata+rpoint+1);
+ z[3]=*(x->x_idata+rpoint+2);
+ } else if ( rpoint == (x->x_size*x->x_blocksize-1) ) {
+ v[0]=*(x->x_rdata+rpoint-1);
+ v[1]=*(x->x_rdata+rpoint);
+ v[2]=*(x->x_rdata+rpoint+1);
+ v[3]=0.0;
+ z[0]=*(x->x_idata+rpoint-1);
+ z[1]=*(x->x_idata+rpoint);
+ z[2]=*(x->x_idata+rpoint+1);
+ z[3]=0.0;
+ } else if ( rpoint == (x->x_size*x->x_blocksize) ) {
+ v[0]=*(x->x_rdata+rpoint-1);
+ v[1]=*(x->x_rdata+rpoint);
+ v[2]=0.0;
+ v[3]=0.0;
+ z[0]=*(x->x_idata+rpoint-1);
+ z[1]=*(x->x_idata+rpoint);
+ z[2]=0.0;
+ z[3]=0.0;
+ } else {
+ v[0]=*(x->x_rdata+rpoint-1);
+ v[1]=*(x->x_rdata+rpoint);
+ v[2]=*(x->x_rdata+rpoint+1);
+ v[3]=*(x->x_rdata+rpoint+2);
+ z[0]=*(x->x_idata+rpoint-1);
+ z[1]=*(x->x_idata+rpoint);
+ z[2]=*(x->x_idata+rpoint+1);
+ z[3]=*(x->x_idata+rpoint+2);
+ }
+
+ {
+ t_float frac = rpoint-(int)rpoint;
+
+ // taken from tabread4_tilde
+ *rout = v[1]+frac*((v[2]-v[1])-0.5f*(frac-1.)*((v[0]-v[3]+3.0f*(v[2]-v[1]))*frac+(2.0f*v[1]-v[0]-v[2])));
+ *iout = z[1]+frac*((z[2]-z[1])-0.5f*(frac-1.)*((z[0]-z[3]+3.0f*(z[2]-z[1]))*frac+(2.0f*z[1]-z[0]-z[2])));
+ }
+
+ // add phase argument
+ fspectrum = sqrt( pow( *rout, 2) + pow( *iout, 2) );
+ fphase = atan2( *iout, *rout );
+ fphase += (x->x_phase/180.0)*(M_PI);
+ *rout = fspectrum*cos( fphase );
+ *iout = fspectrum*sin( fphase );
+ } else {
+ *rout=0.0;
+ *iout=0.0;
+ }
+ rout++;iout++;
+ rin++;iin++;
+ bi++;
+ }
+ // reset playing position until next play
+ if ( x->x_play ) {
+ x->x_readpos+=x->x_readspeed;
+ // post( "xreadpos : %f (added %f)", x->x_readpos, x->x_readspeed );
+ if ( x->x_readpos >= (x->x_readend*x->x_size)/100 ) {
+ x->x_play=0;
+ x->x_readpos=(x->x_readstart*x->x_size)/100;
+ // post( "samplebox~ : stopped playing (readpos=%d)", x->x_readpos );
+ outlet_bang(x->x_playend);
+ }
+ }
+ // reset recording position until next record
+ if ( x->x_record ) {
+ x->x_writepos++;
+ if ( x->x_writepos >= x->x_size ) {
+ x->x_record=0;
+ x->x_writepos=0;
+ outlet_bang(x->x_recordend);
+ // post( "samplebox~ : stopped recording" );
+ }
+ }
+ }
+ return (w+7);
+}
+
+static void samplebox_dsp(t_samplebox *x, t_signal **sp)
+{
+ dsp_add(samplebox_perform, 6, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n, x);
+}
+
+ /* record the sonogram */
+static void samplebox_record(t_samplebox *x)
+{
+ x->x_record=1;
+ x->x_writepos=0;
+}
+
+ /* play the sonogram */
+static void samplebox_play(t_samplebox *x)
+{
+ x->x_play=1;
+ // reset read position
+ x->x_readpos=(x->x_readstart*x->x_size)/100;
+}
+
+ /* setting the starting point for reading ( in percent ) */
+static void samplebox_readstart(t_samplebox *x, t_floatarg fstart)
+{
+ t_float startpoint = fstart;
+
+ if (startpoint < 0) startpoint = 0;
+ if (startpoint > 100) startpoint = 100;
+ if ( startpoint > x->x_readend ) {
+ x->x_readstart = x->x_readend;
+ post( "samplebox~ : warning : range for reading is null" );
+ } else {
+ x->x_readstart=startpoint;
+ }
+}
+
+ /* setting the starting point for modification ( in percent ) */
+static void samplebox_modstart(t_samplebox *x, t_floatarg fstart)
+{
+ t_float startpoint = fstart;
+
+ if (startpoint < 0) startpoint = 0;
+ if (startpoint > 100) startpoint = 100;
+ if ( startpoint > x->x_modend ) {
+ x->x_modstart = x->x_modend;
+ post( "samplebox~ : warning : range for modifications is null" );
+ } else {
+ x->x_modstart=startpoint;
+ }
+}
+
+ /* setting the ending point for reading ( in percent ) */
+static void samplebox_readend(t_samplebox *x, t_floatarg fend)
+{
+ t_float endpoint = fend;
+
+ if (endpoint < 0) endpoint = 0;
+ if (endpoint > 100) endpoint = 100;
+ if ( endpoint < x->x_readstart ) {
+ x->x_readend = x->x_readstart;
+ post( "samplebox~ : warning : range for reading is null" );
+ } else {
+ x->x_readend=endpoint;
+ }
+}
+
+ /* setting the ending point for modification ( in percent ) */
+static void samplebox_modend(t_samplebox *x, t_floatarg fend)
+{
+ t_float endpoint = fend;
+
+ if (endpoint < 0) endpoint = 0;
+ if (endpoint > 100) endpoint = 100;
+ if ( endpoint < x->x_modstart ) {
+ x->x_modend = x->x_modstart;
+ post( "samplebox~ : warning : range for modifications is null" );
+ } else {
+ x->x_modend=endpoint;
+ }
+}
+
+ /* sets the reading speed */
+static void samplebox_readspeed(t_samplebox *x, t_floatarg freadspeed)
+{
+ if ((int)freadspeed < 0 ) {
+ post( "samplebox~ : wrong readspeed argument" );
+ }
+ x->x_readspeed=freadspeed;
+}
+
+ /* resize sonogram */
+static void samplebox_resize(t_samplebox *x, t_floatarg fnewsize )
+{
+ if (fnewsize <= 0) {
+ post( "samplebox~ : error : wrong size" );
+ return;
+ }
+ post( "samplebox~ : reallocating tables" );
+ x->x_record = 0;
+ x->x_play = 0;
+ x->x_allocate = 1;
+ samplebox_reallocate(x, x->x_size, fnewsize);
+ x->x_size = fnewsize;
+ x->x_allocate = 0;
+}
+
+ /* flip blocks */
+static void samplebox_flipblocks(t_samplebox *x)
+{
+ t_int samplestart, sampleend, middlesample, fi, si;
+ t_float fvalue;
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ middlesample = ( sampleend+samplestart+1 ) / 2;
+ post( "flip blocks [%d,%d] and [%d,%d]", samplestart, middlesample, middlesample, sampleend );
+
+ for ( si=samplestart; si<=middlesample; si++ ) {
+ for ( fi=0; fi<x->x_blocksize; fi++ ) {
+ fvalue = *(x->x_rdata+((si)*x->x_blocksize)+fi);
+ *(x->x_rdata+((si)*x->x_blocksize)+fi) = *(x->x_rdata+((sampleend+samplestart-si)*x->x_blocksize)+fi);
+ *(x->x_rdata+((sampleend+samplestart-si)*x->x_blocksize)+fi) = fvalue;
+ fvalue = *(x->x_idata+((si)*x->x_blocksize)+fi);
+ *(x->x_idata+((si)*x->x_blocksize)+fi) = *(x->x_idata+((sampleend+samplestart-si)*x->x_blocksize)+fi);
+ *(x->x_idata+((sampleend+samplestart-si)*x->x_blocksize)+fi) = fvalue;
+ }
+ }
+}
+
+ /* change the phase */
+static void samplebox_phase(t_samplebox *x, t_floatarg fincphase)
+{
+ if (fincphase < 0 || fincphase > 90) {
+ post( "samplebox~ : error : wrong phase in phase function : out of [0,90]" );
+ return;
+ }
+ x->x_phase = fincphase;
+}
+
+ /* swap blocks */
+static void samplebox_swapblocks(t_samplebox *x, t_floatarg fperstart, t_floatarg fperend, t_floatarg fpersize)
+{
+ t_int samplestart, samplestartb, samplesize, sp, sf;
+ t_int iperstart, iperend, ipersize;
+ t_float s1, s2;
+ t_float fvalue;
+
+ iperstart = fperstart;
+ iperend = fperend;
+ ipersize = fpersize;
+
+ if (iperstart < 0 || iperstart > iperend ||
+ iperend <= 0 || iperend+ipersize > 100 ||
+ ipersize < 0 || fpersize > 100 ) {
+ post( "samplebox~ : error : wrong interval [%d%%, %d%%] <-> [%d%%, %d%%]",
+ iperstart, iperstart+ipersize, iperend, iperend+ipersize );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ samplestartb=(x->x_modend*(x->x_size-1))/100;
+ samplesize=((samplestartb-samplestart)*ipersize)/100;
+ samplestart=samplestart+((samplestartb-samplestart)*iperstart)/100;
+ samplestartb=samplestart+((samplestartb-samplestart)*iperend)/100;
+
+ // post( "swap blocks [%d,%d] and [%d,%d]", samplestart, samplestart+samplesize, samplestartb, samplestartb+samplesize );
+
+ for ( sp=samplesize; sp>=0; sp-- ) {
+ for ( sf=0; sf<x->x_blocksize; sf++) {
+ fvalue = *(x->x_rdata+((int)(samplestart+sp)*x->x_blocksize)+sf);
+ *(x->x_rdata+((int)(samplestart+sp)*x->x_blocksize)+sf) = *(x->x_rdata+((int)(samplestartb+sp)*x->x_blocksize)+sf);
+ *(x->x_rdata+((int)(samplestartb+sp)*x->x_blocksize)+sf) = fvalue;
+ fvalue = *(x->x_idata+((int)(samplestart+sp)*x->x_blocksize)+sf);
+ *(x->x_idata+((int)(samplestart+sp)*x->x_blocksize)+sf) = *(x->x_idata+((int)(samplestartb+sp)*x->x_blocksize)+sf);
+ *(x->x_idata+((int)(samplestartb+sp)*x->x_blocksize)+sf) = fvalue;
+ }
+ }
+}
+
+static void *samplebox_new(t_floatarg fsize)
+{
+ t_samplebox *x = (t_samplebox *)pd_new(samplebox_class);
+ outlet_new(&x->x_obj, &s_signal);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_recordend = outlet_new(&x->x_obj, &s_bang );
+ x->x_playend = outlet_new(&x->x_obj, &s_bang );
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("readstart"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("readend"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("modstart"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("modend"));
+
+ if ( fsize <= 0 ) {
+ error( "samplebox~ : missing or negative creation arguments" );
+ return NULL;
+ }
+
+ x->x_size = fsize;
+ x->x_blocksize = sys_getblksize();
+ x->x_play = 0;
+ x->x_readspeed = 1.;
+ x->x_record = 0;
+ x->x_readpos = 0.;
+ x->x_writepos = 0;
+ x->x_modstart = 0;
+ x->x_readstart = 0;
+ x->x_modend = 100;
+ x->x_readend = 100;
+ x->x_allocate = 0;
+ x->x_rdata = NULL;
+ x->x_idata = NULL;
+ x->x_rootsquares = NULL;
+ x->x_phase = 0.0;
+ x->x_samplerate = sys_getsr();
+ if ( samplebox_allocate(x) <0 ) {
+ return NULL;
+ } else {
+ return(x);
+ }
+}
+
+void samplebox_tilde_setup(void)
+{
+ post(samplebox_version);
+ samplebox_class = class_new(gensym("samplebox~"), (t_newmethod)samplebox_new, (t_method)samplebox_free,
+ sizeof(t_samplebox), 0, A_DEFFLOAT, 0);
+ class_sethelpsymbol( samplebox_class, gensym("help-samplebox~.pd") );
+ CLASS_MAINSIGNALIN( samplebox_class, t_samplebox, x_f );
+ class_addmethod(samplebox_class, (t_method)samplebox_dsp, gensym("dsp"), 0);
+ class_addmethod(samplebox_class, (t_method)samplebox_record, gensym("record"), 0);
+ class_addmethod(samplebox_class, (t_method)samplebox_resize, gensym("resize"), A_FLOAT, 0);
+ class_addmethod(samplebox_class, (t_method)samplebox_swapblocks, gensym("swapblocks"), A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(samplebox_class, (t_method)samplebox_flipblocks, gensym("flipblocks"), 0);
+ class_addmethod(samplebox_class, (t_method)samplebox_play, gensym("play"), 0);
+ class_addmethod(samplebox_class, (t_method)samplebox_phase, gensym("phase"), A_FLOAT, 0);
+ class_addmethod(samplebox_class, (t_method)samplebox_modstart, gensym("modstart"), A_FLOAT, 0);
+ class_addmethod(samplebox_class, (t_method)samplebox_modend, gensym("modend"), A_FLOAT, 0);
+ class_addmethod(samplebox_class, (t_method)samplebox_readstart, gensym("readstart"), A_FLOAT, 0);
+ class_addmethod(samplebox_class, (t_method)samplebox_readend, gensym("readend"), A_FLOAT, 0);
+ class_addmethod(samplebox_class, (t_method)samplebox_readspeed, gensym("readspeed"), A_FLOAT, 0);
+}
diff --git a/sonogram~/CHANGES.LOG b/sonogram~/CHANGES.LOG
new file mode 100644
index 0000000..64161e7
--- /dev/null
+++ b/sonogram~/CHANGES.LOG
@@ -0,0 +1,23 @@
+0.11
+ allow backwards reading
+0.10
+ change allocation algorithm
+0.9
+ use copy buffers for cut and paste
+ one level undo on sonogram part with 'undo' message
+0.8
+ check boundaries before updating
+0.7
+ use static buffers to avoid some crashes
+0.6
+ fixed simultaneous record/play to use it in a real-time chain
+0.5
+ even safer cut and paste code !!!
+0.4
+ safer cut and paste code
+0.3
+ added phasogram
+0.2
+ added transfroamtions
+0.1
+ first implementation
diff --git a/sonogram~/INSTALL b/sonogram~/INSTALL
new file mode 100644
index 0000000..d69da45
--- /dev/null
+++ b/sonogram~/INSTALL
@@ -0,0 +1,15 @@
+untar in /my/pd/dir/externs
+
+cd /my/pd/dir/externs/sonogram~
+
+make clean
+
+make
+
+make install
+
+open help-sonogram~.pd
+
+Thanx for getting here.
+Yves/
+comments and bugs @ ydegoyon@free.fr
diff --git a/sonogram~/Makefile b/sonogram~/Makefile
new file mode 100644
index 0000000..b3d37a1
--- /dev/null
+++ b/sonogram~/Makefile
@@ -0,0 +1,82 @@
+NAME=sonogram~
+CSYM=sonogram_tilde
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).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
+
+.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
+
+.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
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -DUNIX -DICECAST -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wno-shadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch -g #-Werror
+
+LINUXINCLUDE = -I../../src
+
+.c.pd_linux:
+ cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ ld -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o ../$*.pd_linux
+ ln -s $*/$*.pd_linux ..
+
+# ----------------------------------------------------------
+
+install:
+ cp help-*.pd rs-*.pd ../../doc/5.reference
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/sonogram~/README b/sonogram~/README
new file mode 100644
index 0000000..2d8b212
--- /dev/null
+++ b/sonogram~/README
@@ -0,0 +1,25 @@
+Version 0.01
+copyleft 2001 by Yves Degoyon
+tarballs and updates available @ http://ydegoyon.free.fr
+
+sonogram~.dll : displays, plays back and lets you modify a recorded sonogram.
+
+The real and imaginery part of an fft~ is stored in a sonogram~
+and, then, you can apply modifications to it
+or do mouse-based graphic modifications.
+The set of modifications provided for now consists of
+matrix operations but it will be improved soon.
+
+To install sonogram~, 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.
+
+*****************************************************************************
+
+
diff --git a/sonogram~/help-sonogram~.pd b/sonogram~/help-sonogram~.pd
new file mode 100644
index 0000000..ab00898
--- /dev/null
+++ b/sonogram~/help-sonogram~.pd
@@ -0,0 +1,10 @@
+#N canvas 0 1 450 300 10;
+#X obj 134 93 rs-sonogram~;
+#X text 193 27 To work properly \, the block size;
+#X text 193 39 has to be redefined.;
+#X msg 291 89 \; pd dsp 1;
+#X msg 356 90 \; pd dsp 0;
+#X text 193 51 that's why everything is in the subpatch.;
+#X obj 132 130 dac~;
+#X connect 0 0 6 0;
+#X connect 0 0 6 1;
diff --git a/sonogram~/help-sonograph~.pd b/sonogram~/help-sonograph~.pd
new file mode 100644
index 0000000..4352c3d
--- /dev/null
+++ b/sonogram~/help-sonograph~.pd
@@ -0,0 +1,10 @@
+#N canvas 0 0 450 300 10;
+#X obj 134 93 rs-sonograph~;
+#X text 193 27 To work properly \, the block size;
+#X text 193 39 has to be redefined.;
+#X obj 132 130 dac~;
+#X msg 291 89 \; pd dsp 1;
+#X msg 356 90 \; pd dsp 0;
+#X text 193 51 that's why everything is in the subpatch.;
+#X connect 0 0 3 0;
+#X connect 0 0 3 1;
diff --git a/sonogram~/rs-sonogram~.pd b/sonogram~/rs-sonogram~.pd
new file mode 100644
index 0000000..864666f
--- /dev/null
+++ b/sonogram~/rs-sonogram~.pd
@@ -0,0 +1,307 @@
+#N canvas 43 28 986 681 10;
+#X msg 306 57 record;
+#X msg 19 34 bang;
+#X obj 19 54 openpanel;
+#X obj 21 152 soundfiler;
+#X msg 259 42 bang;
+#X obj 262 101 rfft~;
+#X floatatom 59 171 10 0 0;
+#X msg 20 211 resize \$1;
+#X obj 19 74 t s b;
+#X obj 22 114 pack s s;
+#X msg 21 135 read -resize \$1 \$2;
+#X obj 68 74 float \$0;
+#X text 21 9 Step 1 : Load a sound file;
+#X obj 775 595 table \$0-sonosample;
+#X msg 927 588 \; pd dsp 1;
+#X msg 484 36 play;
+#X obj 262 195 outlet~;
+#X text 491 10 Step 3 : Play the recorded sonogram;
+#X msg 992 589 \; pd dsp 0;
+#X obj 21 171 / 256;
+#X obj 486 59 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 1;
+#X text 460 59 0 %;
+#X text 620 58 100 %;
+#X obj 487 77 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 12700 1;
+#X text 461 80 0 %;
+#X text 622 76 100 %;
+#X msg 661 74 100;
+#X obj 691 74 loadbang;
+#X text 640 40 Playback positions;
+#X obj 783 93 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 1;
+#X text 756 94 0 %;
+#X text 917 92 100 %;
+#X obj 784 111 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 12700 1;
+#X text 756 114 0 %;
+#X text 919 110 100 %;
+#X text 783 76 Set portion of the sonogram to modify;
+#X msg 953 108 100;
+#N canvas 309 22 600 544 modifications 0;
+#X text 234 236 Filter a frequency;
+#X text 254 190 Enhance a frequency by 10% ( might be a range of frequencies
+with message 'enhance f1 f2 x' );
+#X text 180 309 Flip frequencies ( dogs love it );
+#X msg 108 265 swappoints 1000;
+#X obj 181 134 hdl 8 1 0 128 empty empty empty 20 8 0 8 -260818 -24198
+-128992 0;
+#X msg 108 153 swapfreqs \$1 \$2;
+#X obj 224 152 pack f f;
+#X text 220 267 Swap 1000 points ( rain effect );
+#X msg 153 131 \$1;
+#X obj 108 131 change;
+#X obj 181 114 hdl 8 1 0 128 empty empty empty 20 8 0 8 -260818 -24198
+-128992 0;
+#X msg 153 111 \$1;
+#X obj 108 111 change;
+#X obj 180 182 hdl 8 1 0 128 empty empty empty 20 8 0 8 -260818 -24198
+-128992 0;
+#X obj 180 223 hdl 8 1 0 128 empty empty empty 20 8 0 8 -260818 -24198
+-128992 0;
+#X text 285 152 Swap two frequencies ( set 2nd \, click 1st );
+#X msg 110 308 flipfreqs;
+#X msg 110 330 flipblocks;
+#X text 243 286 Swap section [0% \, 20%] and [50% \, 70%] of [start
+\, end];
+#X text 188 328 Flip blocks ( reverse effect );
+#X msg 110 287 swapblocks 0 50 20;
+#X text 228 66 Move frequencies up or down;
+#X msg 110 91 roll 2;
+#X msg 112 350 zswap;
+#X text 364 374 Change the phase;
+#X text 180 350 Exchange real and imaginery parts ( noisy filter )
+;
+#X msg 113 374 phase \$1;
+#X obj 200 373 hsl 128 15 0 90 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 1;
+#X text 184 373 0;
+#X text 339 374 90;
+#X obj 187 415 hdl 8 1 0 128 empty empty empty 20 8 0 8 -260818 -24198
+-128992 0;
+#X msg 113 429 add \$1 \$1 0.5;
+#X text 216 429 Add a constant to a frequency;
+#X obj 189 451 hdl 8 1 0 128 empty empty empty 20 8 0 8 -260818 -24198
+-128992 0;
+#X msg 115 466 add \$1 \$1 -0.5;
+#X text 218 465 Sub a constant from a frequency;
+#X msg 113 395 average 100;
+#X text 198 393 Average over 100 blocks ( smooth with some sounds )
+;
+#X obj 16 454 outlet;
+#X msg 109 69 goup 1;
+#X msg 159 69 godown 5;
+#X msg 107 198 enhance \$1 \$1 1.1 0;
+#X msg 116 488 threshold \$1;
+#X floatatom 208 489 5 0 0;
+#X msg 107 239 enhance \$1 \$1 0 0;
+#X text 249 488 Suppress all points below the threshold;
+#X text 159 91 Roll frequencies : same as above but without loss;
+#X connect 3 0 38 0;
+#X connect 4 0 8 0;
+#X connect 5 0 38 0;
+#X connect 6 0 5 0;
+#X connect 8 0 9 0;
+#X connect 9 0 6 1;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 12 0 6 0;
+#X connect 13 0 41 0;
+#X connect 14 0 44 0;
+#X connect 16 0 38 0;
+#X connect 17 0 38 0;
+#X connect 20 0 38 0;
+#X connect 22 0 38 0;
+#X connect 23 0 38 0;
+#X connect 26 0 38 0;
+#X connect 27 0 26 0;
+#X connect 30 0 31 0;
+#X connect 31 0 38 0;
+#X connect 33 0 34 0;
+#X connect 34 0 38 0;
+#X connect 36 0 38 0;
+#X connect 39 0 38 0;
+#X connect 40 0 38 0;
+#X connect 41 0 38 0;
+#X connect 42 0 38 0;
+#X connect 43 0 42 0;
+#X connect 44 0 38 0;
+#X restore 861 131 pd modifications;
+#X text 513 609 Zoom factor (>1);
+#X msg 418 608 zoom 2;
+#X obj 256 79 tabplay~ \$0-sonosample;
+#X obj 80 275 sonogram~ 463 1 1 1;
+#X msg 467 608 zoom 1;
+#X msg 484 99 readspeed \$1;
+#X floatatom 617 99 5 0 0;
+#X text 487 121 Reading speed;
+#X obj 576 99 / 100;
+#X msg 661 99 100;
+#X obj 692 99 loadbang;
+#X msg 779 167 play;
+#X msg 780 186 open /tmp/sonogram.wav;
+#X obj 779 229 writesf~ 2;
+#X msg 780 207 start;
+#X msg 822 207 stop;
+#X msg 418 652 modstep \$1;
+#X floatatom 499 652 5 0 0;
+#X obj 525 36 spigot;
+#X obj 573 36 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1
+;
+#X text 600 37 Loop;
+#X text 70 547 Mouse modifications :;
+#X text 557 656 ( default = 1.1 );
+#X text 558 646 Value added or multiplied ( can be < 0 );
+#X obj 527 588 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0
+1;
+#X obj 19 93 route float;
+#X msg 418 587 enhancemode \$1;
+#X text 821 166 Record;
+#X text 89 562 Normal mode;
+#X text 30 579 <shift>click :;
+#X text 128 579 add modstep to the selected data;
+#X text 43 590 <alt>click :;
+#X text 161 590 erase selected data;
+#X text 154 645 erase selected data;
+#X text 88 615 Enhanced mode;
+#X text 2 600 <shift><alt>click :;
+#X text 162 601 paste selected data;
+#X text 129 656 add selected data at the new location;
+#X text 483 546 Graphic actions;
+#X text 128 632 multiply the selected data by modstep;
+#X obj 980 109 loadbang;
+#X text 73 21 ( a small one );
+#X text 417 569 Activate enhance mode;
+#X text 785 57 Step 4 : modify parts of the sonogram;
+#X obj 260 126 rifft~;
+#X msg 418 630 refresh;
+#X obj 829 571 block~ 256;
+#X text 239 10 Step 2 : Record the sonogram;
+#X obj 927 565 loadbang;
+#N canvas 0 1 682 488 envelop 0;
+#X obj 33 400 outlet;
+#X obj 46 327 tabread envelop;
+#X msg 23 263 bang;
+#X floatatom 23 299 5 0 0;
+#X obj 71 280 + 1;
+#X msg 23 281 0;
+#X text 25 239 Apply envelop;
+#X obj 68 300 delay 1000;
+#X obj 136 300 f;
+#X obj 34 354 pack f f;
+#X obj 368 349 loadbang;
+#X msg 425 349 bang;
+#X msg 370 374 \; envelop const 1;
+#X msg 203 381 refresh;
+#X floatatom 160 280 5 0 0;
+#X msg 163 300 bang;
+#X obj 98 280 moses 127;
+#X msg 485 347 bang;
+#X msg 486 372 \; envelop const 0.001;
+#X msg 33 377 enhance \$1 \$1 \$2 1;
+#X obj 202 358 delay 1000;
+#N canvas 0 0 450 300 graph2 0;
+#X array envelop 64 float 1;
+#A 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
+#X coords 0 10 63 0 300 200 1;
+#X restore 151 12 graph;
+#X connect 1 0 9 1;
+#X connect 2 0 5 0;
+#X connect 3 0 1 0;
+#X connect 3 0 8 1;
+#X connect 3 0 7 0;
+#X connect 3 0 9 0;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 7 0 8 0;
+#X connect 8 0 16 0;
+#X connect 9 0 19 0;
+#X connect 10 0 12 0;
+#X connect 11 0 12 0;
+#X connect 13 0 0 0;
+#X connect 14 0 15 0;
+#X connect 15 0 20 0;
+#X connect 16 0 4 0;
+#X connect 16 1 14 0;
+#X connect 17 0 18 0;
+#X connect 19 0 0 0;
+#X connect 20 0 13 0;
+#X restore 780 131 pd envelop;
+#X obj 310 174 / 100;
+#X floatatom 309 147 5 0 0;
+#X obj 263 174 *~ 1;
+#X obj 261 149 /~ 256;
+#X text 332 129 Volume;
+#X text 31 631 <shift>click :;
+#X text 44 642 <alt>click :;
+#X text 3 652 <shift><alt>click :;
+#X msg 488 630 undo;
+#X text 526 630 One level undo;
+#X obj 21 192 makefilename %d-sonosample;
+#X connect 0 0 41 0;
+#X connect 1 0 2 0;
+#X connect 2 0 8 0;
+#X connect 3 0 19 0;
+#X connect 4 0 0 0;
+#X connect 4 0 40 0;
+#X connect 5 0 41 0;
+#X connect 5 1 41 1;
+#X connect 6 0 7 0;
+#X connect 7 0 41 0;
+#X connect 8 0 9 0;
+#X connect 8 1 11 0;
+#X connect 9 0 10 0;
+#X connect 10 0 3 0;
+#X connect 11 0 63 0;
+#X connect 15 0 41 0;
+#X connect 19 0 6 0;
+#X connect 20 0 41 2;
+#X connect 23 0 41 3;
+#X connect 26 0 23 0;
+#X connect 27 0 26 0;
+#X connect 29 0 41 4;
+#X connect 32 0 41 5;
+#X connect 36 0 32 0;
+#X connect 37 0 41 0;
+#X connect 39 0 41 0;
+#X connect 40 0 5 0;
+#X connect 40 0 90 0;
+#X connect 41 0 82 0;
+#X connect 41 1 82 1;
+#X connect 41 3 53 0;
+#X connect 41 3 56 0;
+#X connect 42 0 41 0;
+#X connect 43 0 41 0;
+#X connect 44 0 46 0;
+#X connect 46 0 43 0;
+#X connect 47 0 44 0;
+#X connect 48 0 47 0;
+#X connect 49 0 41 0;
+#X connect 49 0 50 0;
+#X connect 49 0 52 0;
+#X connect 50 0 51 0;
+#X connect 52 0 51 0;
+#X connect 53 0 51 0;
+#X connect 54 0 41 0;
+#X connect 55 0 54 0;
+#X connect 56 0 15 0;
+#X connect 57 0 56 1;
+#X connect 62 0 64 0;
+#X connect 63 0 98 0;
+#X connect 64 0 41 0;
+#X connect 78 0 36 0;
+#X connect 82 0 91 0;
+#X connect 83 0 41 0;
+#X connect 86 0 14 0;
+#X connect 87 0 41 0;
+#X connect 88 0 90 1;
+#X connect 89 0 88 0;
+#X connect 90 0 16 0;
+#X connect 90 0 51 0;
+#X connect 90 0 51 1;
+#X connect 91 0 90 0;
+#X connect 96 0 41 0;
+#X connect 98 0 9 1;
diff --git a/sonogram~/rs-sonograph~.pd b/sonogram~/rs-sonograph~.pd
new file mode 100644
index 0000000..c8795ec
--- /dev/null
+++ b/sonogram~/rs-sonograph~.pd
@@ -0,0 +1,217 @@
+#N canvas 0 1 986 654 10;
+#X msg 344 51 record;
+#X msg 53 30 bang;
+#X obj 53 50 openpanel;
+#X obj 52 167 soundfiler;
+#X msg 297 36 bang;
+#X obj 298 99 rfft~;
+#X floatatom 90 186 10 0 0;
+#X msg 168 185 resize \$1;
+#X obj 53 72 t s b;
+#X obj 53 129 pack s s;
+#X msg 52 150 read -resize \$1 \$2;
+#X obj 99 71 float \$0;
+#X obj 54 95 route float;
+#X obj 52 207 makefilename %d-sonosample;
+#X text 57 14 Step 1 : Load a sound file;
+#X obj 820 17 table \$0-sonosample;
+#X msg 822 43 \; pd dsp 1;
+#X obj 121 580 rifft~;
+#X msg 340 158 play;
+#X obj 822 82 block~ 256;
+#X obj 27 607 outlet~;
+#X text 346 135 Step 3 : Play the recorded sonogram;
+#X msg 887 44 \; pd dsp 0;
+#X obj 52 186 / 256;
+#X obj 121 607 /~ 256;
+#X obj 342 181 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 1;
+#X text 316 181 0 %;
+#X text 476 180 100 %;
+#X obj 343 199 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 12700 1;
+#X text 317 202 0 %;
+#X text 478 198 100 %;
+#X msg 512 196 100;
+#X obj 539 196 loadbang;
+#X text 339 217 Playback positions;
+#X obj 697 184 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 1;
+#X text 671 184 0 %;
+#X text 831 183 100 %;
+#X obj 698 202 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 12700 1;
+#X text 672 205 0 %;
+#X text 833 201 100 %;
+#X text 697 167 Set portion of the sonogram to modify;
+#X text 883 183 Start Point;
+#X text 883 198 End Point;
+#X msg 695 220 100;
+#X obj 722 220 loadbang;
+#X text 242 15 Step 2 : Record the sonogram;
+#N canvas 309 22 600 544 modifications 1;
+#X text 234 236 Filter a frequency;
+#X msg 107 239 filter \$1 \$1;
+#X msg 105 161 enhance \$1 \$1 1.1;
+#X msg 106 198 dim \$1 \$1 1.1;
+#X text 236 155 Enhance a frequency by 10% ( might be a range of frequencies
+with message 'enhance f1 f2 x' );
+#X text 234 198 Dim a frequency by 10 %;
+#X text 180 309 Flip frequencies ( dogs love it );
+#X msg 108 265 swappoints 1000;
+#X obj 179 97 hdl 8 1 0 128 empty empty empty 20 8 0 8 -260818 -24198
+-128992 0;
+#X msg 106 116 swapfreqs \$1 \$2;
+#X obj 223 116 pack f f;
+#X text 218 264 Swap 1000 points ( rain effect );
+#X msg 151 94 \$1;
+#X obj 106 94 change;
+#X obj 179 77 hdl 8 1 0 128 empty empty empty 20 8 0 8 -260818 -24198
+-128992 0;
+#X msg 151 74 \$1;
+#X obj 106 74 change;
+#X obj 178 145 hdl 8 1 0 128 empty empty empty 20 8 0 8 -260818 -24198
+-128992 0;
+#X obj 179 183 hdl 8 1 0 128 empty empty empty 20 8 0 8 -260818 -24198
+-128992 0;
+#X obj 180 223 hdl 8 1 0 128 empty empty empty 20 8 0 8 -260818 -24198
+-128992 0;
+#X text 285 115 Swap two frequencies ( set 2nd \, click 1st );
+#X msg 110 308 flipfreqs;
+#X msg 110 330 flipblocks;
+#X text 244 286 Swap section [0% \, 20%] and [50% \, 70%] of [start
+\, end];
+#X text 185 330 Flip blocks ( reverse effect );
+#X msg 110 287 swapblocks 0 50 20;
+#X msg 152 32 godown 1;
+#X msg 107 32 goup 2;
+#X text 218 32 Move frequencies up or down;
+#X msg 108 54 roll 2;
+#X text 210 45 Roll frequencies : same as above but without loss (
+circular );
+#X msg 112 350 zswap;
+#X text 364 374 Change the phase;
+#X text 180 350 Exchange real and imaginery parts ( noisy filter )
+;
+#X msg 113 374 phase \$1;
+#X obj 200 373 hsl 128 15 0 90 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 1;
+#X text 184 373 0;
+#X text 339 374 90;
+#X obj 187 415 hdl 8 1 0 128 empty empty empty 20 8 0 8 -260818 -24198
+-128992 0;
+#X msg 113 429 add \$1 \$1 0.5;
+#X text 216 429 Add a constant to a frequency;
+#X obj 189 451 hdl 8 1 0 128 empty empty empty 20 8 0 8 -260818 -24198
+-128992 0;
+#X msg 115 466 add \$1 \$1 -0.5;
+#X text 218 465 Sub a constant from a frequency;
+#X msg 113 395 average 100;
+#X text 190 395 Average over 100 blocks ( smooth with some sounds )
+;
+#X obj 16 454 outlet;
+#X connect 1 0 46 0;
+#X connect 2 0 46 0;
+#X connect 3 0 46 0;
+#X connect 7 0 46 0;
+#X connect 8 0 12 0;
+#X connect 9 0 46 0;
+#X connect 10 0 9 0;
+#X connect 12 0 13 0;
+#X connect 13 0 10 1;
+#X connect 14 0 15 0;
+#X connect 15 0 16 0;
+#X connect 16 0 10 0;
+#X connect 17 0 2 0;
+#X connect 18 0 3 0;
+#X connect 19 0 1 0;
+#X connect 21 0 46 0;
+#X connect 22 0 46 0;
+#X connect 25 0 46 0;
+#X connect 26 0 46 0;
+#X connect 27 0 46 0;
+#X connect 29 0 46 0;
+#X connect 31 0 46 0;
+#X connect 34 0 46 0;
+#X connect 35 0 34 0;
+#X connect 38 0 39 0;
+#X connect 39 0 46 0;
+#X connect 41 0 42 0;
+#X connect 42 0 46 0;
+#X connect 44 0 46 0;
+#X restore 694 150 pd modifications;
+#X obj 298 73 tabplay~ \$0-sonosample;
+#X obj 106 329 sonogram~ 215 0;
+#X text 538 54 When the sonogram is RED (updating) \,;
+#X text 537 43 VERY IMPORTANT NOTE :;
+#X text 591 116 Step 4 : modify parts of the sonogram ... and send
+a refresh message;
+#X msg 337 234 readspeed \$1;
+#X floatatom 468 234 5 0 0;
+#X text 337 252 Reading speed;
+#X obj 428 234 / 100;
+#X msg 515 234 100;
+#X obj 549 234 loadbang;
+#X text 538 66 no update is possible;
+#X msg 221 525 play;
+#X msg 217 555 open /tmp/sonogram.wav;
+#X obj 246 603 writesf~ 2;
+#X msg 276 576 start;
+#X msg 320 576 stop;
+#X floatatom 172 609 5 0 0;
+#X obj 436 158 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1
+1;
+#X text 464 160 Loop;
+#X obj 381 159 spigot;
+#X connect 0 0 48 0;
+#X connect 1 0 2 0;
+#X connect 2 0 8 0;
+#X connect 3 0 23 0;
+#X connect 4 0 0 0;
+#X connect 4 0 47 0;
+#X connect 5 0 48 0;
+#X connect 5 1 48 1;
+#X connect 6 0 7 0;
+#X connect 7 0 48 0;
+#X connect 8 0 9 0;
+#X connect 8 1 11 0;
+#X connect 9 0 10 0;
+#X connect 10 0 3 0;
+#X connect 11 0 12 0;
+#X connect 12 0 13 0;
+#X connect 13 0 9 1;
+#X connect 17 0 24 0;
+#X connect 18 0 48 0;
+#X connect 23 0 6 0;
+#X connect 24 0 20 0;
+#X connect 24 0 61 0;
+#X connect 24 0 61 1;
+#X connect 25 0 48 2;
+#X connect 28 0 48 3;
+#X connect 31 0 28 0;
+#X connect 32 0 31 0;
+#X connect 34 0 48 4;
+#X connect 37 0 48 5;
+#X connect 43 0 37 0;
+#X connect 44 0 43 0;
+#X connect 46 0 48 0;
+#X connect 47 0 5 0;
+#X connect 47 0 20 0;
+#X connect 48 0 17 0;
+#X connect 48 1 17 1;
+#X connect 48 3 63 0;
+#X connect 48 3 67 0;
+#X connect 52 0 48 0;
+#X connect 53 0 55 0;
+#X connect 55 0 52 0;
+#X connect 56 0 53 0;
+#X connect 57 0 56 0;
+#X connect 59 0 48 0;
+#X connect 59 0 60 0;
+#X connect 59 0 62 0;
+#X connect 60 0 61 0;
+#X connect 62 0 61 0;
+#X connect 63 0 61 0;
+#X connect 64 0 24 1;
+#X connect 65 0 67 1;
+#X connect 67 0 18 0;
diff --git a/sonogram~/sonogram~-joge.c b/sonogram~/sonogram~-joge.c
new file mode 100644
index 0000000..6fc2153
--- /dev/null
+++ b/sonogram~/sonogram~-joge.c
@@ -0,0 +1,2024 @@
+/*------------------------ sonogram~ ------------------------------------------ */
+/* */
+/* sonogram~ : lets you record, play back and modify a sonogram */
+/* constructor : sonogram <size> <graphical=0|1> <phasogram=0|1> */
+/* */
+/* Copyleft Yves Degoyon ( 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. */
+/* */
+/* "Living at night" */
+/* "Doesn't help for my complexion" */
+/* David Thomas - Final Solution */
+/* ---------------------------------------------------------------------------- */
+
+
+
+#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 <pthread.h>
+#endif
+#ifdef NT
+#define M_PI 3.14159265358979323846
+#include "pthread.h"
+#include <windows.h>
+#endif
+#include <math.h>
+
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+
+static int guidebug=0;
+static int ignorevisible=1; // ignore visible test
+ // because this seems to lead to bad refresh
+ // wait for a fix
+
+#define SYS_VGUI2(a,b) if (guidebug) \
+ post(a,b);\
+ sys_vgui(a,b)
+
+#define SYS_VGUI3(a,b,c) if (guidebug) \
+ post(a,b,c);\
+ sys_vgui(a,b,c)
+
+#define SYS_VGUI4(a,b,c,d) if (guidebug) \
+ post(a,b,c,d);\
+ sys_vgui(a,b,c,d)
+
+#define SYS_VGUI5(a,b,c,d,e) if (guidebug) \
+ post(a,b,c,d,e);\
+ sys_vgui(a,b,c,d,e)
+
+#define SYS_VGUI6(a,b,c,d,e,f) if (guidebug) \
+ post(a,b,c,d,e,f);\
+ sys_vgui(a,b,c,d,e,f)
+
+#define SYS_VGUI7(a,b,c,d,e,f,g) if (guidebug) \
+ post(a,b,c,d,e,f,g );\
+ sys_vgui(a,b,c,d,e,f,g)
+
+#define SYS_VGUI9(a,b,c,d,e,f,g,h,i) if (guidebug) \
+ post(a,b,c,d,e,f,g,h,i );\
+ sys_vgui(a,b,c,d,e,f,g,h,i)
+
+#define SYS_VGUI10(a,b,c,d,e,f,g,h,i,j) if (guidebug) \
+ post(a,b,c,d,e,f,g,h,i,j );\
+ sys_vgui(a,b,c,d,e,f,g,h,i,j)
+
+#define SYS_VGUI11(a,b,c,d,e,f,g,h,i,j,k) if (guidebug) \
+ post(a,b,c,d,e,f,g,h,i,j,k );\
+ sys_vgui(a,b,c,d,e,f,g,h,i,j,k)
+
+#define THREAD_SLEEP_TIME 100000 // 100000 us = 100 ms
+
+static char *sonogram_version = "sonogram~: version 0.9, written by Yves Degoyon (ydegoyon@free.fr)";
+
+static t_class *sonogram_class;
+t_widgetbehavior sonogram_widgetbehavior;
+
+
+typedef struct _sonogram
+{
+ t_object x_obj;
+
+ t_int x_size; /* size of the stored fft ( in blocks~ ) */
+ t_float x_samplerate; /* sample rate */
+ t_int x_blocksize; /* current block size ( might be modified by block~ object ) */
+ t_float x_readpos; /* data's playing position */
+ t_int x_writepos; /* data's recording position */
+ t_int x_readstart; /* data's starting position for reading */
+ t_int x_readend; /* data's ending position for reading */
+ t_int x_modstart; /* data's starting position for modifications */
+ t_int x_modend; /* data's ending position for modifications */
+ t_int x_play; /* playing on/off flag */
+ t_float x_readspeed; /* number of grouped blocks for reading */
+ t_float x_record; /* flag to start recording process */
+ t_float x_empty; /* flag to indicate it's a brand new sonogram */
+ t_float *x_rdata; /* table containing real part of the fft */
+ t_float *x_rudata; /* undo real data */
+ t_float *x_idata; /* table containing imaginery part of the fft */
+ t_float *x_iudata; /* undo imaginery data */
+ t_float x_phase; /* phase to apply on output */
+ t_outlet *x_end; /* outlet for end of restitution */
+ t_outlet *x_recend; /* outlet for end of recording */
+ t_int *x_multfreq; /* array of multiplicative factor */
+ char *x_gifdata; /* buffer for graphical data */
+ char *x_guicommand; /* buffer for graphical command */
+ t_int x_uxs; /* starting x position for undo */
+ t_int x_uxe; /* ending x position for undo */
+ t_int x_uys; /* starting y position for undo */
+ t_int x_uye; /* ending y position for undo */
+
+ /* graphical data block */
+ t_int x_enhancemode; /* flag to set enhance mode */
+ t_int x_graphic; /* flag to set graphic mode */
+ t_int x_phaso; /* flag to indicate if phasogram is shown */
+ t_int x_selected; /* flag to remember if we are seleted or not */
+ t_int x_erase; /* flag used when an erase is needed */
+ t_int x_redraw; /* flag used when drawing is needed */
+ t_int x_nbupdated; /* number of points updated */
+ t_glist *x_glist; /* keep graphic context for various operations */
+ t_int x_zoom; /* zoom factor */
+ pthread_t x_updatechild; /* thread id for the update child */
+ t_int x_updatestart; /* starting position for update */
+ t_int x_updateend; /* ending position for update */
+ t_int x_xpos; /* stuck x position */
+ t_int x_ypos; /* stuck y position */
+ t_int x_shifted; /* remember shift state from last click */
+ t_int x_alted; /* remember alt state from last click */
+ t_int x_aftermousedown; /* indicates the mousedown event */
+ t_int x_xstartcapture; /* x of the start of the capture */
+ t_int x_ystartcapture; /* y of the start of the capture */
+ t_int x_xendcapture; /* x of the start of the capture */
+ t_int x_yendcapture; /* y of the start of the capture */
+ t_int x_xdraw; /* x drawing position */
+ t_int x_ydraw; /* y drawing position */
+ t_float x_modstep; /* step for graphical modifications */
+
+ t_float x_f; /* float needed for signal input */
+
+} t_sonogram;
+
+/* ------------------------ drawing functions ---------------------------- */
+static char* sonogram_get_fill_color( t_float fspectrum )
+{
+ if ( fspectrum < 0.01 ) {
+ return "#EEEEEE";
+ } else if ( fspectrum < 0.1 ) {
+ return "#DDDDDD";
+ } else if ( fspectrum < 0.5 ) {
+ return "#CCCCCC";
+ } else if ( fspectrum < 1 ) {
+ return "#BBBBBB";
+ } else if ( fspectrum < 2 ) {
+ return "#AAAAAA";
+ } else if ( fspectrum < 5 ) {
+ return "#999999";
+ } else if ( fspectrum < 10 ) {
+ return "#888888";
+ } else if ( fspectrum < 20 ) {
+ return "#777777";
+ } else if ( fspectrum < 30 ) {
+ return "#666666";
+ } else if ( fspectrum < 40 ) {
+ return "#555555";
+ } else if ( fspectrum < 50 ) {
+ return "#444444";
+ } else if ( fspectrum < 60 ) {
+ return "#333333";
+ } else if ( fspectrum < 80 ) {
+ return "#222222";
+ } else if ( fspectrum < 100 ) {
+ return "#111111";
+ } else {
+ return "#000000";
+ }
+}
+
+static char* phasogram_get_fill_color( t_int phase )
+{
+ if ( phase < 0 )
+ {
+ if ( phase > -10 ) {
+ return "#111111";
+ } else if ( phase > -20 ) {
+ return "#222222";
+ } else if ( phase > -30 ) {
+ return "#333333";
+ } else if ( phase > -40 ) {
+ return "#444444";
+ } else if ( phase > -50 ) {
+ return "#555555";
+ } else if ( phase > -60 ) {
+ return "#666666";
+ } else if ( phase > -70 ) {
+ return "#777777";
+ } else if ( phase > -80 ) {
+ return "#888888";
+ } else {
+ return "#999999";
+ }
+ }
+ else
+ {
+ if ( phase == 0 ) {
+ return "#FFFFFF";
+ } else if ( phase < 10 ) {
+ return "#111111";
+ } else if ( phase < 20 ) {
+ return "#222222";
+ } else if ( phase < 30 ) {
+ return "#333333";
+ } else if ( phase < 40 ) {
+ return "#444444";
+ } else if ( phase < 50 ) {
+ return "#555555";
+ } else if ( phase < 60 ) {
+ return "#666666";
+ } else if ( phase < 70 ) {
+ return "#777777";
+ } else if ( phase < 80 ) {
+ return "#888888";
+ } else {
+ return "#999999";
+ }
+ }
+ // normally never reached
+ return "";
+}
+
+static void sonogram_update_point(t_sonogram *x, t_glist *glist, t_int sample, t_int frequency)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ t_float fspectrum=0.0;
+ t_int phase=0.0;
+ char newColor[ 8 ], olColor[8];
+ int i;
+
+ post("sonogram~ : joge : updating a point");
+
+ fspectrum =
+ sqrt( pow( *(x->x_rdata+sample*x->x_blocksize+frequency), 2) +
+ pow( *(x->x_idata+sample*x->x_blocksize+frequency), 2) );
+ phase = (int) ( atan2( *(x->x_idata+(sample*x->x_blocksize)+frequency),
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) )*180/M_PI );
+ if ( x->x_empty && ( fspectrum != 0 ))
+ {
+ x->x_empty = 0;
+ }
+ strcpy( newColor, sonogram_get_fill_color( fspectrum ) );
+
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ sprintf( x->x_gifdata, "%s", strcat( newColor, " ") );
+ }
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ SYS_VGUI5("SONIMAGE%x put {%s} -to %d %d\n", x, x->x_gifdata,
+ sample*x->x_zoom+i, (x->x_blocksize/2-frequency)*x->x_zoom );
+ }
+
+ if ( x->x_phaso )
+ {
+ strcpy( newColor, phasogram_get_fill_color( phase ) );
+ strcpy( x->x_gifdata, "" );
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ sprintf( x->x_gifdata, "%s", strcat( newColor, " ") );
+ }
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ SYS_VGUI5("FAZIMAGE%x put {%s} -to %d %d\n", x, x->x_gifdata,
+ sample*x->x_zoom+i, (x->x_blocksize/2-frequency)*x->x_zoom );
+ }
+ }
+
+ x->x_nbupdated++;
+}
+
+static void sonogram_update_block(t_sonogram *x, t_glist *glist, t_int bnumber)
+{
+ t_int fi, i=0;
+ t_float fspectrum=0.0;
+ t_int phase=0;
+ char color[8];
+
+ // update sonogram
+ for ( fi=x->x_blocksize/2-1; fi>=0; fi-- )
+ {
+ fspectrum =
+ sqrt( pow( *(x->x_rdata+bnumber*x->x_blocksize+fi), 2) +
+ pow( *(x->x_idata+bnumber*x->x_blocksize+fi), 2) );
+ strcpy( color, sonogram_get_fill_color( fspectrum ) );
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ strncpy( x->x_gifdata+((x->x_blocksize/2-fi-1)*x->x_zoom+i)*8, strcat( color, " "), 8 );
+ }
+ }
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ sprintf( x->x_guicommand, "SONIMAGE%x put {%s} -to %d 0\n", (unsigned int)x, x->x_gifdata, (bnumber*x->x_zoom)+i );
+ sys_gui( x->x_guicommand );
+ }
+
+ // update phasogram
+ if ( x->x_phaso )
+ {
+ strcpy( x->x_gifdata, "" );
+ for ( fi=x->x_blocksize/2-1; fi>=0; fi-- )
+ {
+ phase = (int) ( atan2( *(x->x_idata+bnumber*x->x_blocksize+fi),
+ *(x->x_rdata+bnumber*x->x_blocksize+fi) )*180/M_PI );
+ strcpy( color, phasogram_get_fill_color( phase ) );
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ strncpy( x->x_gifdata+((x->x_blocksize/2-fi-1)*x->x_zoom+i)*8, strcat( color, " "), 8 );
+ }
+ }
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ sprintf( x->x_guicommand, "FAZIMAGE%x put {%s} -to %d 0\n", (unsigned int)x, x->x_gifdata, (bnumber*x->x_zoom)+i );
+ sys_gui( x->x_guicommand );
+ }
+ }
+
+ post("sonogram~ : joge in update_block : update phasogram");
+
+}
+
+static void sonogram_erase_block(t_sonogram *x, t_glist *glist, t_int bnumber )
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ t_int fi;
+ t_float fspectrum=0.0;
+ char fillColor[ 16 ];
+
+ for ( fi=0; fi<x->x_blocksize/2; fi++)
+ {
+ {
+ int i;
+
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ strcpy( x->x_gifdata+i*sizeof("#FFFFFF "), "#FFFFFF " );
+ }
+ SYS_VGUI5("SONIMAGE%x put {%s} -to %d %d\n", x, x->x_gifdata,
+ bnumber*x->x_zoom, (x->x_blocksize/2-fi)*x->x_zoom );
+ }
+ }
+}
+
+static void *sonogram_do_update_part(void *tdata)
+{
+ t_sonogram *x = (t_sonogram*) tdata;
+ t_int si;
+ t_int nbpoints = 0;
+ t_float percentage = 0, opercentage = 0;
+
+ // loose synchro
+#ifdef NT
+ // usleep's argument is in microseconds while
+ // Sleep's argument is in miliseconds therefore
+ // need a convertion from micro to mili
+ Sleep( THREAD_SLEEP_TIME / 1000 );
+
+ // OR jsut use the pd defined sleep function
+ //sys_microsleep(THREAD_SLEEP_TIME / 1000);
+#else
+ usleep( THREAD_SLEEP_TIME );
+#endif
+
+ // check boundaries
+ if ( x->x_updateend > x->x_size-1 ) x->x_updateend = x->x_size-1;
+ if ( x->x_updatestart < 0 ) x->x_updatestart = 0;
+
+ post("sonogram~ : ok, let's go [updating %d, %d]", x->x_updatestart, x->x_updateend );
+
+ if ( x->x_erase )
+ {
+ for ( si=x->x_updatestart; si<=x->x_updateend; si++ )
+ {
+ sonogram_erase_block(x, x->x_glist, si);
+ nbpoints++;
+ percentage = (nbpoints*100/(x->x_updateend-x->x_updatestart+1));
+ if ( (percentage == (int) percentage) && ((int)percentage%5 == 0) && ( percentage != opercentage ) )
+ {
+ // post( "sonogram~ : erase part : %d %% completed", (int)percentage );
+ opercentage = percentage;
+ }
+ }
+ }
+
+ percentage = opercentage = nbpoints = 0;
+
+ if ( x->x_redraw )
+ {
+ for ( si=x->x_updatestart; si<=x->x_updateend; si++ )
+ {
+ sonogram_update_block(x, x->x_glist, si);
+
+ // post("sonogram~ : joge check point : after sonogram_update_block");
+
+ nbpoints++;
+ percentage = (nbpoints*100/(x->x_updateend-x->x_updatestart+1));
+
+ post("sonogram~ : joge : percentage=%d completed", (int)percentage);
+
+ if ( (percentage == (int) percentage) && ((int)percentage%5 == 0) && ( percentage != opercentage ) )
+ {
+ post( "sonogram~ : update part : %d %% completed", (int)percentage );
+ opercentage = percentage;
+ }
+ }
+ }
+
+ // set borders in black
+ SYS_VGUI3(".x%x.c itemconfigure %xSONOGRAM -outline #000000\n", glist_getcanvas(x->x_glist), x);
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xPHASOGRAM -outline #000000\n", glist_getcanvas(x->x_glist), x);
+ }
+
+ post("sonogram~ : child thread %d ended (nb_updated=%d)", (int)x->x_updatechild, x->x_nbupdated );
+ x->x_updatechild = 0;
+ return NULL;
+}
+
+static void sonogram_update_part(t_sonogram *x, t_glist *glist, t_int bstart, t_int bend,
+ t_int erase, t_int redraw, t_int keepframe)
+{
+ pthread_attr_t update_child_attr;
+
+ if ( x->x_graphic )
+ {
+ if ( x->x_updatechild != 0 )
+ {
+ post( "sonogram~ : error : no update is possible for now" );
+ return;
+ }
+ x->x_updatestart = bstart;
+ x->x_updateend = bend;
+ if ( !keepframe )
+ {
+ x->x_erase = 0;
+ }
+ else
+ {
+ x->x_erase = erase;
+ }
+ x->x_redraw = redraw;
+ x->x_nbupdated = 0;
+ // recreate the square if needed
+ if ( ( bstart == 0 ) && ( bend == x->x_size-1 ) && !keepframe )
+ {
+ SYS_VGUI3(".x%x.c delete %xSONOGRAM\n", glist_getcanvas(glist), x );
+ SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill #FFFFFF -tags %xSONOGRAM\n",
+ glist_getcanvas(glist), x->x_xpos-1, x->x_ypos-1,
+ x->x_xpos + x->x_size*x->x_zoom+1,
+ x->x_ypos + x->x_blocksize/2*x->x_zoom+1,
+ x);
+ SYS_VGUI2("image delete SONIMAGE%x\n", x );
+ SYS_VGUI3(".x%x.c delete ISONIMAGE%x\n", glist_getcanvas(glist), x );
+ SYS_VGUI4("image create photo SONIMAGE%x -format gif -width %d -height %d\n",
+ x, x->x_size*x->x_zoom, x->x_blocksize/2*x->x_zoom );
+ SYS_VGUI2("SONIMAGE%x blank\n", x);
+ SYS_VGUI6(".x%x.c create image %d %d -image SONIMAGE%x -tags ISONIMAGE%x\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+((x->x_size*x->x_zoom)/2),
+ (x->x_ypos+((x->x_blocksize/2*x->x_zoom)/2)), x, x );
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c delete %xPHASOGRAM\n", glist_getcanvas(glist), x );
+ SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill #FFFFFF -tags %xPHASOGRAM\n",
+ glist_getcanvas(glist), x->x_xpos-1, x->x_ypos+x->x_blocksize/2*x->x_zoom+2,
+ x->x_xpos + x->x_size*x->x_zoom +1,
+ x->x_ypos + x->x_blocksize*x->x_zoom + 3,
+ x);
+ SYS_VGUI2("image delete FAZIMAGE%x\n", x );
+ SYS_VGUI3(".x%x.c delete IFAZIMAGE%x\n", glist_getcanvas(glist), x );
+ SYS_VGUI4("image create photo FAZIMAGE%x -format gif -width %d -height %d\n",
+ x, x->x_size*x->x_zoom, x->x_blocksize/2*x->x_zoom );
+ SYS_VGUI2("FAZIMAGE%x blank\n", x);
+ SYS_VGUI6(".x%x.c create image %d %d -image FAZIMAGE%x -tags IFAZIMAGE%x\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+((x->x_size*x->x_zoom)/2),
+ x->x_ypos+3*((x->x_blocksize/2*x->x_zoom)/2)+2, x, x );
+ }
+ canvas_fixlinesfor( glist_getcanvas(x->x_glist), (t_text*)x );
+ }
+ // set borders in red
+ SYS_VGUI3(".x%x.c itemconfigure %xSONOGRAM -outline #FF0000\n", glist_getcanvas(glist), x);
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xPHASOGRAM -outline #FF0000\n", glist_getcanvas(glist), x);
+ }
+
+ // launch update thread
+ if ( pthread_attr_init( &update_child_attr ) < 0 ) {
+ post( "sonogram~ : could not launch update thread" );
+ perror( "pthread_attr_init" );
+ return;
+ }
+ if ( pthread_attr_setdetachstate( &update_child_attr, PTHREAD_CREATE_DETACHED ) < 0 ) {
+ post( "sonogram~ : could not launch update thread" );
+ perror( "pthread_attr_setdetachstate" );
+ return;
+ }
+ if ( pthread_create( &x->x_updatechild, &update_child_attr, sonogram_do_update_part, x ) < 0 ) {
+ post( "sonogram~ : could not launch update thread" );
+ perror( "pthread_create" );
+ return;
+ }
+ else
+ {
+ post( "sonogram~ : drawing thread %d launched", (int)x->x_updatechild );
+ }
+ }
+}
+
+ /* paste selection at the drawing point */
+static void sonogram_paste( t_sonogram* x)
+{
+ t_int pxstart = (x->x_xdraw-x->x_xpos)/x->x_zoom;
+ t_int pystart = (x->x_ypos-x->x_ydraw)/x->x_zoom+x->x_blocksize/2;
+ t_int cxs,cxe,cys,cye,si=0,fi=0;
+ t_float *icopy;
+ t_float *rcopy;
+ t_int copynd;
+
+ if ( x->x_xstartcapture > x->x_xendcapture ) {
+ fi = x->x_xstartcapture;
+ x->x_xstartcapture = x->x_xendcapture;
+ x->x_xendcapture = fi;
+ }
+ if ( x->x_ystartcapture > x->x_yendcapture ) {
+ fi = x->x_ystartcapture;
+ x->x_ystartcapture = x->x_yendcapture;
+ x->x_yendcapture = fi;
+ }
+ cxs=(x->x_xstartcapture-x->x_xpos)/x->x_zoom;
+ cxe=(x->x_xendcapture-x->x_xpos)/x->x_zoom;
+ cys=(x->x_ypos-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ cye=(x->x_ypos-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2;
+ if ( cye < 0 ) cye=0;
+ if ( cys < 0 ) cys=0;
+ if ( cye >= x->x_blocksize/2 ) cye=x->x_blocksize/2-1;
+ if ( cys >= x->x_blocksize/2 ) cys=x->x_blocksize/2-1;
+ if ( cxe >= x->x_size ) cxe=x->x_size-1;
+ if ( cxs >= x->x_size ) cxs=x->x_size-1;
+
+ // make a copy first
+ icopy = ( t_float* ) getbytes( ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ rcopy = ( t_float* ) getbytes( ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ if ( !icopy || !rcopy )
+ {
+ post( "sonogram~ : cannot allocate buffers for pasting" );
+ return;
+ }
+ // copy initial data
+ copynd = 0;
+ for ( si=cxs; si<=cxe; si++) {
+ for ( fi=cys; fi<=cye; fi++) {
+ *(rcopy+copynd) = *(x->x_rdata+(si)*x->x_blocksize+fi);
+ *(icopy+copynd) = *(x->x_idata+(si)*x->x_blocksize+fi);
+ copynd++;
+ }
+ }
+
+ post( "sonogram~ : paste from [%d,%d,%d,%d] to [%d,%d]", cxs, cys, cxe, cye, pxstart, pystart );
+
+ for ( si=cxs; si<=cxe; si++) {
+ if ( pxstart+si-cxs >= x->x_size ) break;
+ copynd = (si-cxs)*(cye-cys+1);
+ for ( fi=cys; fi<=cye; fi++) {
+ // post ( "sonogram~ : si : %d : fi : %d : copynd : %d", si, fi, copynd );
+ if ( pystart+fi-cys >= x->x_blocksize/2 ) break;
+ *(x->x_rudata+((si-cxs)*x->x_blocksize)+(fi-cys)) = *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys));
+ *(x->x_iudata+((si-cxs)*x->x_blocksize)+(fi-cys)) = *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys));
+ if ( x->x_enhancemode )
+ {
+ // save data for undo
+ *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) += *(rcopy+copynd);
+ *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) += *(icopy+copynd);
+ }
+ else
+ {
+ *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) = *(rcopy+copynd);
+ *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) = *(icopy+copynd);
+ }
+ copynd++;
+ }
+ }
+
+ x->x_uxs = pxstart;
+ x->x_uxe = pxstart+(si-1)-cxs;
+ x->x_uys = pystart;
+ x->x_uye = pystart+(fi-1)-cys;;
+
+ freebytes( rcopy, ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ freebytes( icopy, ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+}
+
+ /* paste phase at the drawing point */
+static void sonogram_paste_phase( t_sonogram* x)
+{
+ t_int pxstart = (x->x_xdraw-x->x_xpos)/x->x_zoom;
+ t_int pystart = (x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_ydraw)/x->x_zoom+x->x_blocksize/2;
+ t_int cxs,cxe,cys,cye,si,fi;
+ t_float fspectrum, fdestspectrum;
+ t_float fphase, fdestphase;
+ t_float *icopy;
+ t_float *rcopy;
+ t_int copynd;
+
+ if ( x->x_xstartcapture > x->x_xendcapture ) {
+ fi = x->x_xstartcapture;
+ x->x_xstartcapture = x->x_xendcapture;
+ x->x_xendcapture = fi;
+ }
+ if ( x->x_ystartcapture > x->x_yendcapture ) {
+ fi = x->x_ystartcapture;
+ x->x_ystartcapture = x->x_yendcapture;
+ x->x_yendcapture = fi;
+ }
+ cxs=(x->x_xstartcapture-x->x_xpos)/x->x_zoom;
+ cxe=(x->x_xendcapture-x->x_xpos)/x->x_zoom;
+ cys=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ cye=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2;
+ if ( cye < 0 ) cye=0;
+ if ( cys < 0 ) cys=0;
+ if ( cye >= x->x_blocksize/2 ) cye=x->x_blocksize/2-1;
+ if ( cys >= x->x_blocksize/2 ) cys=x->x_blocksize/2-1;
+ if ( cxe >= x->x_size ) cxe=x->x_size-1;
+ if ( cxs >= x->x_size ) cxs=x->x_size-1;
+
+ // make a copy first
+ icopy = ( t_float* ) getbytes( ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ rcopy = ( t_float* ) getbytes( ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ if ( !icopy || !rcopy )
+ {
+ post( "sonogram~ : cannot allocate buffers for pasting" );
+ return;
+ }
+ // copy initial data
+ copynd = 0;
+ for ( si=cxs; si<=cxe; si++) {
+ for ( fi=cys; fi<=cye; fi++) {
+ *(rcopy+copynd) = *(x->x_rdata+(si)*x->x_blocksize+fi);
+ *(icopy+copynd) = *(x->x_idata+(si)*x->x_blocksize+fi);
+ copynd++;
+ }
+ }
+
+ post( "sonogram~ : paste phase from [%d,%d,%d,%d] to [%d,%d]", cxs, cys, cxe, cye, pxstart, pystart );
+
+ for ( si=cxs; si<=cxe; si++) {
+ if ( pxstart+si-cxs >= x->x_size ) break;
+ copynd = (si-cxs)*(cye-cys+1);
+ for ( fi=cys; fi<=cye; fi++) {
+ if ( pystart+fi-cys > x->x_blocksize+1 ) break;
+ fphase = atan2( *(icopy+copynd), *(rcopy+copynd) );
+ fdestspectrum =
+ sqrt( pow( *(x->x_rdata+(pxstart+si-cxs)*x->x_blocksize+(pystart+fi-cys)), 2) +
+ pow( *(x->x_idata+(pxstart+si-cxs)*x->x_blocksize+(pystart+fi-cys)), 2) );
+ fdestphase = atan2( *(x->x_idata+(pxstart+si-cxs)*x->x_blocksize+(pystart+fi-cys)),
+ *(x->x_rdata+(pxstart+si-cxs)*x->x_blocksize+(pystart+fi-cys)) );
+ if ( x->x_enhancemode )
+ {
+ *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) +=
+ fdestspectrum*cos( fdestphase + fphase );
+ *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) +=
+ fdestspectrum*sin( fdestphase + fphase );
+ }
+ else
+ {
+ *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) =
+ fdestspectrum*cos( fphase );
+ *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) =
+ fdestspectrum*sin( fphase );
+ }
+ copynd++;
+ }
+ }
+
+ freebytes( rcopy, ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ freebytes( icopy, ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+
+ sonogram_update_part(x, x->x_glist, pxstart, pxstart+(si-1)-cxs, 0, 1, 1);
+ // start a new capture
+ SYS_VGUI3( ".x%x.c delete %xCAPTURE\n", glist_getcanvas( x->x_glist ), x );
+ x->x_xstartcapture = x->x_xdraw;
+ x->x_ystartcapture = x->x_ydraw;
+ x->x_xendcapture = x->x_xdraw;
+ x->x_yendcapture = x->x_ydraw;
+
+}
+
+static void sonogram_draw_new(t_sonogram *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if ( x->x_xpos == -1 )
+ {
+ x->x_xpos=x->x_obj.te_xpix;
+ x->x_ypos=x->x_obj.te_ypix;
+ }
+ if ( x->x_graphic )
+ {
+ SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill #FFFFFF -tags %xSONOGRAM\n",
+ canvas, x->x_xpos-1, x->x_ypos-1,
+ x->x_xpos + x->x_size*x->x_zoom+1,
+ x->x_ypos + x->x_blocksize/2*x->x_zoom+1,
+ x);
+ SYS_VGUI4("image create photo SONIMAGE%x -format gif -width %d -height %d\n",
+ x, x->x_size*x->x_zoom, x->x_blocksize/2*x->x_zoom );
+ SYS_VGUI2("SONIMAGE%x blank\n", x);
+ SYS_VGUI6(".x%x.c create image %d %d -image SONIMAGE%x -tags ISONIMAGE%x\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+((x->x_size*x->x_zoom)/2),
+ (x->x_ypos+((x->x_blocksize/2*x->x_zoom)/2)), x, x );
+ if ( x->x_phaso )
+ {
+ SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill #FFFFFF -tags %xPHASOGRAM\n",
+ glist_getcanvas(glist), x->x_xpos-1, x->x_ypos+x->x_blocksize/2*x->x_zoom+2,
+ x->x_xpos + x->x_size*x->x_zoom +1,
+ x->x_ypos + x->x_blocksize*x->x_zoom + 3,
+ x);
+ SYS_VGUI4("image create photo FAZIMAGE%x -format gif -width %d -height %d\n",
+ x, x->x_size*x->x_zoom, x->x_blocksize/2*x->x_zoom );
+ SYS_VGUI2("FAZIMAGE%x blank\n", x);
+ SYS_VGUI6(".x%x.c create image %d %d -image FAZIMAGE%x -tags IFAZIMAGE%x\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+((x->x_size*x->x_zoom)/2),
+ x->x_ypos+3*((x->x_blocksize/2*x->x_zoom)/2)+2, x, x );
+ }
+ canvas_fixlinesfor( canvas, (t_text*)x );
+ }
+}
+
+static void sonogram_draw_delete(t_sonogram *x, t_glist *glist)
+{
+ if ( x->x_graphic && glist_isvisible( glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete %xCAPTURE\n", glist_getcanvas( glist ), x );
+ SYS_VGUI3( ".x%x.c delete line %xREADSTART\n", glist_getcanvas( glist ), x);
+ SYS_VGUI3( ".x%x.c delete line %xREADEND\n", glist_getcanvas( glist ), x);
+ SYS_VGUI3( ".x%x.c delete line %xMODSTART\n", glist_getcanvas( glist ), x);
+ SYS_VGUI3( ".x%x.c delete line %xMODEND\n", glist_getcanvas( glist ), x);
+ SYS_VGUI3(".x%x.c delete %xSONOGRAM\n", glist_getcanvas( glist ), x );
+ SYS_VGUI3(".x%x.c delete %xPHASOGRAM\n", glist_getcanvas( glist ), x );
+ SYS_VGUI3(".x%x.c delete %xISONIMAGE\n", glist_getcanvas( glist ), x );
+ SYS_VGUI2("image delete SONIMAGE%x\n", x );
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c delete %xIFAZIMAGE\n", glist_getcanvas( glist ), x );
+ SYS_VGUI2("image delete FAZIMAGE%x\n", x );
+ }
+ }
+}
+
+static void sonogram_draw_move(t_sonogram *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI7(".x%x.c coords %xSONOGRAM %d %d %d %d\n",
+ canvas, x,
+ x->x_xpos-1, x->x_ypos-1,
+ x->x_xpos+x->x_size*x->x_zoom+1,
+ x->x_ypos+x->x_blocksize/2*x->x_zoom+1);
+ SYS_VGUI5(".x%x.c coords ISONIMAGE%x %d %d\n",
+ canvas, x,
+ x->x_xpos+((x->x_size*x->x_zoom)/2),
+ (x->x_ypos+((x->x_blocksize/2*x->x_zoom)/2)) );
+ if ( x->x_phaso )
+ {
+ SYS_VGUI7(".x%x.c coords %xPHASOGRAM %d %d %d %d\n",
+ canvas, x,
+ x->x_xpos-1, x->x_ypos+(x->x_blocksize/2*x->x_zoom)+1,
+ x->x_xpos+x->x_size*x->x_zoom+1,
+ x->x_ypos+x->x_blocksize*x->x_zoom+3);
+ SYS_VGUI5(".x%x.c coords IFAZIMAGE%x %d %d\n",
+ canvas, x,
+ x->x_xpos+((x->x_size*x->x_zoom)/2),
+ x->x_ypos+3*((x->x_blocksize/2*x->x_zoom)/2)+2 );
+ }
+ canvas_fixlinesfor( canvas, (t_text*)x );
+ }
+}
+
+static void sonogram_draw_select(t_sonogram* x,t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ if(x->x_selected)
+ {
+ /* sets the item in blue */
+ SYS_VGUI3(".x%x.c itemconfigure %xSONOGRAM -outline #0000FF\n", canvas, x);
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xPHASOGRAM -outline #0000FF\n", canvas, x);
+ }
+ }
+ else
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xSONOGRAM -outline #000000\n", canvas, x);
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xPHASOGRAM -outline #000000\n", canvas, x);
+ }
+ }
+ }
+}
+
+/* ------------------------ widget callbacks ----------------------------- */
+
+
+static void sonogram_getrect(t_gobj *z, t_glist *owner,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_sonogram* x = (t_sonogram*)z;
+
+ *xp1 = x->x_xpos;
+ *yp1 = x->x_ypos;
+ if ( !x->x_phaso )
+ {
+ *xp2 = x->x_xpos+x->x_size*x->x_zoom;
+ *yp2 = x->x_ypos+x->x_blocksize/2*x->x_zoom+1;
+ }
+ else
+ {
+ *xp2 = x->x_xpos+x->x_size*x->x_zoom;
+ *yp2 = x->x_ypos+x->x_blocksize*x->x_zoom+3;
+ }
+}
+
+static void sonogram_save(t_gobj *z, t_binbuf *b)
+{
+ t_sonogram *x = (t_sonogram *)z;
+
+ binbuf_addv(b, "ssiisiii", gensym("#X"),gensym("obj"),
+ (t_int)x->x_xpos, (t_int)x->x_ypos,
+ gensym("sonogram~"), x->x_size, x->x_graphic, x->x_phaso );
+ binbuf_addv(b, ";");
+}
+
+static void sonogram_select(t_gobj *z, t_glist *glist, int selected)
+{
+ t_sonogram *x = (t_sonogram *)z;
+
+ x->x_selected = selected;
+ sonogram_draw_select( x, glist );
+}
+
+static void sonogram_vis(t_gobj *z, t_glist *glist, int vis)
+{
+ t_sonogram *x = (t_sonogram *)z;
+ t_rtext *y;
+
+ if (vis)
+ {
+ sonogram_draw_new( x, glist );
+ }
+ else
+ {
+ // erase all points
+ sonogram_draw_delete( x, glist );
+ }
+}
+
+static void sonogram_delete(t_gobj *z, t_glist *glist)
+{
+ canvas_deletelinesfor( glist_getcanvas(glist), (t_text *)z);
+}
+
+static void sonogram_displace(t_gobj *z, t_glist *glist, int dx, int dy)
+{
+ t_sonogram *x = (t_sonogram *)z;
+ int xold = x->x_xpos;
+ int yold = x->x_ypos;
+
+ x->x_xpos += dx;
+ x->x_ypos += dy;
+
+ if ( ( x->x_xpos != xold ) || ( x->x_ypos != yold ) )
+ {
+ sonogram_draw_move( x, glist );
+ }
+
+}
+
+static void sonogram_modify_point( t_sonogram* x, t_int sample, t_int frequency, t_int alted )
+{
+ if ( alted )
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) = 0;
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) = 0;
+ }
+ else
+ {
+ if ( x->x_enhancemode )
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) *= x->x_modstep;
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) *= x->x_modstep;
+ }
+ else
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) += x->x_modstep;
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) += x->x_modstep;
+ }
+ }
+}
+
+static void sonogram_modify_point_phase( t_sonogram* x, t_int sample, t_int frequency, t_int alted )
+{
+ t_float fspectrum;
+ t_float fphase;
+
+ fspectrum =
+ sqrt( pow( *(x->x_rdata+sample*x->x_blocksize+frequency), 2) +
+ pow( *(x->x_idata+sample*x->x_blocksize+frequency), 2) );
+ fphase = atan2( *(x->x_idata+sample*x->x_blocksize+frequency),
+ *(x->x_rdata+sample*x->x_blocksize+frequency) );
+ if ( alted==4 )
+ {
+ // setting phase to 0
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) = fspectrum;
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) = 0;
+ }
+ else
+ {
+ if ( x->x_enhancemode )
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) = fspectrum*cos( fphase*x->x_modstep );
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) = fspectrum*sin( fphase*x->x_modstep );
+ }
+ else
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) = fspectrum*cos( fphase+x->x_modstep );
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) = fspectrum*sin( fphase+x->x_modstep );
+ }
+ }
+}
+
+static void sonogram_motion(t_sonogram *x, t_floatarg dx, t_floatarg dy)
+{
+ int fdraw=0, sdraw=0;
+
+ // post( "sonogram_motion @ [%d,%d] dx=%f dy=%f alt=%d", x->x_xdraw, x->x_ydraw, dx, dy, x->x_alted );
+ if ( ( x->x_shifted || (x->x_alted==4) ) )
+ {
+ if ( (x->x_xdraw+dx) >= x->x_xpos &&
+ (x->x_xdraw+dx) <= x->x_xpos+x->x_size*x->x_zoom ) {
+ x->x_xdraw += dx;
+ }
+ if ( (x->x_ydraw+dy) >= x->x_ypos &&
+ (x->x_ydraw+dy) <= x->x_ypos+x->x_blocksize*x->x_zoom ) {
+ x->x_ydraw += dy;
+ }
+ sdraw=(x->x_xdraw-x->x_xpos)/x->x_zoom;
+ if ( x->x_ydraw <= x->x_ypos+x->x_blocksize/2*x->x_zoom )
+ {
+ fdraw=(x->x_ypos-x->x_ydraw)/x->x_zoom+x->x_blocksize/2;
+ // post( "modify point @ [%d, %d] alted=%d", sdraw, fdraw, x->x_alted );
+ sonogram_modify_point( x, sdraw, fdraw, x->x_alted );
+ }
+ if ( x->x_ydraw >= x->x_ypos+x->x_blocksize/2*x->x_zoom+1 )
+ {
+ fdraw=(x->x_ypos+x->x_blocksize*x->x_zoom/2+1-x->x_ydraw)/x->x_zoom+x->x_blocksize/2;
+ // post( "modify phase @ [%d, %d]", sdraw, fdraw );
+ sonogram_modify_point_phase( x, sdraw, fdraw, x->x_alted );
+ }
+ sonogram_update_point( x, x->x_glist, sdraw, fdraw );
+ }
+ else
+ {
+ if ( (x->x_xendcapture+dx) >= x->x_xpos &&
+ (x->x_xendcapture+dx) <= x->x_xpos+x->x_size*x->x_zoom ) {
+ x->x_xendcapture += dx;
+ }
+ if ( (x->x_yendcapture+dy) >= x->x_ypos &&
+ (x->x_yendcapture+dy) <= x->x_ypos+x->x_blocksize*x->x_zoom ) {
+ x->x_yendcapture += dy;
+ }
+ SYS_VGUI3( ".x%x.c delete %xCAPTURE\n", glist_getcanvas( x->x_glist ), x );
+ SYS_VGUI7( ".x%x.c create rectangle %d %d %d %d -outline #0000FF -tags %xCAPTURE\n",
+ glist_getcanvas( x->x_glist ), x->x_xstartcapture,
+ x->x_ystartcapture, x->x_xendcapture, x->x_yendcapture, x );
+ }
+}
+
+static int sonogram_click(t_gobj *z, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_sonogram* x = (t_sonogram *)z;
+ int si,fi;
+
+ // post( "sonogram_click : x=%d y=%d doit=%d alt=%d, shift=%d", xpix, ypix, doit, alt, shift );
+ if ( x->x_aftermousedown == 1 && doit == 0)
+ {
+ x->x_aftermousedown = 1;
+ }
+ else
+ {
+ x->x_aftermousedown = 0;
+ }
+ if ( doit )
+ {
+ x->x_xdraw = xpix;
+ x->x_ydraw = ypix;
+ x->x_shifted = shift;
+ x->x_alted = alt;
+ // activate motion callback
+ glist_grab( glist, &x->x_obj.te_g, (t_glistmotionfn)sonogram_motion,
+ 0, xpix, ypix );
+
+ if ( shift && alt && (x->x_xstartcapture != x->x_xendcapture ) )
+ {
+ sonogram_paste(x);
+ sonogram_paste_phase(x);
+ }
+ else if ( shift && (x->x_xstartcapture != x->x_xendcapture ) )
+ {
+ // add or multiply modstep
+ if ( x->x_xstartcapture > x->x_xendcapture ) {
+ fi = x->x_xstartcapture;
+ x->x_xstartcapture = x->x_xendcapture;
+ x->x_xendcapture = fi;
+ }
+ if ( x->x_ystartcapture > x->x_yendcapture ) {
+ fi = x->x_ystartcapture;
+ x->x_ystartcapture = x->x_yendcapture;
+ x->x_yendcapture = fi;
+ }
+ for ( si=(x->x_xstartcapture-x->x_xpos)/x->x_zoom;
+ si<=(x->x_xendcapture-x->x_xpos)/x->x_zoom; si++) {
+ for ( fi=(x->x_ypos-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ fi<=(x->x_ypos-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2; fi++) {
+ sonogram_modify_point( x, si, fi, alt );
+ }
+ for ( fi=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ fi<=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2; fi++) {
+ sonogram_modify_point_phase( x, si, fi, alt );
+ }
+ }
+ // post( "modified y from %d to %d", (x->x_ypos-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2,
+ // (x->x_ypos-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2 );
+ sonogram_update_part(x, x->x_glist, (x->x_xstartcapture-x->x_xpos)/x->x_zoom,
+ (x->x_xendcapture-x->x_xpos)/x->x_zoom, 0, 1, 1);
+ }
+ else if ( (alt==4) && (x->x_xstartcapture != x->x_xendcapture ) )
+ {
+ // clean up area
+ if ( x->x_xstartcapture > x->x_xendcapture ) {
+ fi = x->x_xstartcapture;
+ x->x_xstartcapture = x->x_xendcapture;
+ x->x_xendcapture = fi;
+ }
+ if ( x->x_ystartcapture > x->x_yendcapture ) {
+ fi = x->x_ystartcapture;
+ x->x_ystartcapture = x->x_yendcapture;
+ x->x_yendcapture = fi;
+ }
+ for ( si=(x->x_xstartcapture-x->x_xpos)/x->x_zoom;
+ si<=(x->x_xendcapture-x->x_xpos)/x->x_zoom; si++) {
+ for ( fi=(x->x_ypos-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ fi<=(x->x_ypos-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2; fi++) {
+ sonogram_modify_point( x, si, fi, alt );
+ }
+ for ( fi=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ fi<=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2; fi++) {
+ sonogram_modify_point_phase( x, si, fi, alt );
+ }
+ }
+ sonogram_update_part(x, x->x_glist, (x->x_xstartcapture-x->x_xpos)/x->x_zoom,
+ (x->x_xendcapture-x->x_xpos)/x->x_zoom, 0, 1, 1);
+ }
+ // start a new capture
+ SYS_VGUI3( ".x%x.c delete %xCAPTURE\n", glist_getcanvas( x->x_glist ), x );
+ x->x_xstartcapture = xpix;
+ x->x_ystartcapture = ypix;
+ x->x_xendcapture = xpix;
+ x->x_yendcapture = ypix;
+ }
+ else
+ {
+ // nothing
+ }
+ x->x_aftermousedown = doit;
+ return (1);
+}
+
+ /* clean up */
+static void sonogram_free(t_sonogram *x)
+{
+ if ( x->x_rdata != NULL ) {
+ freebytes(x->x_rdata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_rdata = NULL;
+ }
+ if ( x->x_idata != NULL ) {
+ freebytes(x->x_idata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_idata = NULL;
+ }
+ if ( x->x_rudata != NULL ) {
+ freebytes(x->x_rudata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_rdata = NULL;
+ }
+ if ( x->x_iudata != NULL ) {
+ freebytes(x->x_iudata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_idata = NULL;
+ }
+ if ( x->x_gifdata != NULL ) {
+ freebytes(x->x_gifdata, (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ post( "Freed %d bytes", (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ x->x_gifdata = NULL;
+ }
+ if ( x->x_guicommand != NULL ) {
+ freebytes(x->x_guicommand, 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ post( "Freed %d bytes", 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ x->x_guicommand = NULL;
+ }
+}
+
+ /* allocate tables for storing ffts */
+static t_int sonogram_allocate(t_sonogram *x)
+{
+ t_int fi;
+
+ if ( !(x->x_rdata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_idata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_multfreq = getbytes( x->x_blocksize*sizeof(t_int) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_blocksize*sizeof(t_int) );
+ }
+ for ( fi=0; fi<x->x_blocksize; fi++ )
+ {
+ *(x->x_multfreq+fi)=1;
+ }
+ // no undo is available
+ x->x_uxs = x->x_uxe = x->x_uys = x->x_uye = -1;
+ if ( !(x->x_rudata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_iudata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !( x->x_gifdata = ( char* ) getbytes( (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ }
+ if ( !( x->x_guicommand = ( char* ) getbytes( 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ }
+
+ return 0;
+}
+
+ /* records or playback the sonogram */
+static t_int *sonogram_perform(t_int *w)
+{
+ t_float *rin = (t_float *)(w[1]);
+ t_float *iin = (t_float *)(w[2]);
+ t_float *rout = (t_float *)(w[3]);
+ t_float *iout = (t_float *)(w[4]);
+ t_float fspectrum = 0.0;
+ t_float fphase = 0.0;
+ t_int is;
+ t_int n = (int)(w[5]); /* number of samples */
+ t_sonogram *x = (t_sonogram *)(w[6]);
+ t_int bi;
+
+ // reallocate tables if blocksize has been changed
+ if ( n != x->x_blocksize && x->x_updatechild == 0 ) {
+ post( "sonogram~ : reallocating tables" );
+ // erase all points
+ sonogram_free(x);
+ x->x_blocksize = n;
+ sonogram_allocate(x);
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, !x->x_empty, 0, 0);
+ canvas_fixlinesfor( glist_getcanvas(x->x_glist), (t_text*)x );
+ }
+
+ bi = 0;
+ while (bi<n)
+ {
+ // eventually records input
+ if ( x->x_record) {
+ *(x->x_rdata+(x->x_writepos*x->x_blocksize)+bi)=(*(rin))*(*(x->x_multfreq+bi));
+ *(x->x_idata+(x->x_writepos*x->x_blocksize)+bi)=(*(iin))*(*(x->x_multfreq+bi));
+ }
+ // set outputs
+ *rout = 0.0;
+ *iout = 0.0;
+ if ( x->x_play) {
+ is=0;
+ fspectrum =
+ sqrt( pow( *(x->x_rdata+(((int)x->x_readpos+is)*x->x_blocksize)+bi), 2) +
+ pow( *(x->x_idata+(((int)x->x_readpos+is)*x->x_blocksize)+bi), 2) );
+ fphase = atan2( *(x->x_idata+(((int)x->x_readpos+is)*x->x_blocksize)+bi),
+ *(x->x_rdata+(((int)x->x_readpos+is)*x->x_blocksize)+bi) );
+ fphase += (x->x_phase/180.0)*(M_PI);
+ *rout += fspectrum*cos( fphase );
+ *iout += fspectrum*sin( fphase );
+ }
+ rout++;iout++;
+ rin++;iin++;
+ bi++;
+
+ }
+ // reset playing position until next play
+ if ( x->x_play ) {
+ x->x_readpos+=x->x_readspeed;
+ // post( "xreadpos : %f (added %f)", x->x_readpos, x->x_readspeed );
+ if ( x->x_readpos >= (x->x_readend*x->x_size)/100 ) {
+ x->x_play=0;
+ x->x_readpos=(x->x_readstart*x->x_size)/100;
+ // post( "sonogram~ : stopped playing (readpos=%d)", x->x_readpos );
+ outlet_bang(x->x_end);
+ }
+ }
+ // reset recording position until next record
+ if ( x->x_record ) {
+ x->x_writepos++;
+ if ( x->x_writepos >= x->x_size ) {
+ x->x_record=0;
+ x->x_writepos=0;
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, 0, 1, 0);
+ outlet_bang(x->x_recend);
+ if ( x->x_empty ) x->x_empty = 0;
+ post( "sonogram~ : stopped recording" );
+ }
+ }
+ // post( "sonogram~ : read : %f:%d : write: %d:%d", x->x_readpos, x->x_play, x->x_writepos, x->x_record );
+ return (w+7);
+}
+
+static void sonogram_dsp(t_sonogram *x, t_signal **sp)
+{
+ dsp_add(sonogram_perform, 6, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n, x);
+}
+
+ /* record the sonogram */
+static void sonogram_record(t_sonogram *x)
+{
+ x->x_record=1;
+ x->x_writepos=0;
+ post( "sonogram~ : recording on" );
+}
+
+ /* play the sonogram */
+static void sonogram_play(t_sonogram *x)
+{
+ x->x_play=1;
+ x->x_readpos=(x->x_readstart*x->x_size)/100;
+ post( "sonogram~ : playing on" );
+}
+
+ /* setting the starting point for reading ( in percent ) */
+static void sonogram_readstart(t_sonogram *x, t_floatarg fstart)
+{
+ t_float startpoint = fstart;
+
+ if (startpoint < 0) startpoint = 0;
+ if (startpoint > 100) startpoint = 100;
+ if ( startpoint > x->x_readend ) {
+ x->x_readstart = x->x_readend;
+ post( "sonogram~ : warning : range for reading is null" );
+ } else {
+ x->x_readstart=startpoint;
+ }
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete line %xREADSTART\n",
+ glist_getcanvas( x->x_glist ), x);
+ SYS_VGUI7( ".x%x.c create line %d %d %d %d -fill #FF0000 -tags %xREADSTART -width 3\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+(x->x_readstart*(x->x_size)/100 ),
+ x->x_ypos, x->x_xpos+(x->x_readstart*(x->x_size)/100 ),
+ x->x_ypos+x->x_blocksize*x->x_zoom, x );
+ }
+}
+
+ /* setting the starting point for modification ( in percent ) */
+static void sonogram_modstart(t_sonogram *x, t_floatarg fstart)
+{
+ t_float startpoint = fstart;
+
+ if (startpoint < 0) startpoint = 0;
+ if (startpoint > 100) startpoint = 100;
+ if ( startpoint > x->x_modend ) {
+ x->x_modstart = x->x_modend;
+ post( "sonogram~ : warning : range for modifications is null" );
+ } else {
+ x->x_modstart=startpoint;
+ }
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete line %xMODSTART\n",
+ glist_getcanvas( x->x_glist ), x);
+ SYS_VGUI7( ".x%x.c create line %d %d %d %d -fill #11E834 -tags %xMODSTART -width 3\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+(x->x_modstart*(x->x_size)/100 ),
+ x->x_ypos, x->x_xpos+(x->x_modstart*(x->x_size)/100 ),
+ x->x_ypos+x->x_blocksize*x->x_zoom, x );
+ }
+}
+
+ /* setting the modification step for graphical mode */
+static void sonogram_modstep(t_sonogram *x, t_floatarg fmodstep)
+{
+ if ( x->x_graphic )
+ {
+ x->x_modstep = fmodstep;
+ }
+}
+
+ /* setting enhance mode */
+static void sonogram_enhancemode(t_sonogram *x, t_floatarg fenhancemode)
+{
+ if ( x->x_graphic )
+ {
+ x->x_enhancemode = fenhancemode;
+ }
+}
+
+ /* setting the ending point for reading ( in percent ) */
+static void sonogram_readend(t_sonogram *x, t_floatarg fend)
+{
+ t_float endpoint = fend;
+
+ if (endpoint < 0) endpoint = 0;
+ if (endpoint > 100) endpoint = 100;
+ if ( endpoint < x->x_readstart ) {
+ x->x_readend = x->x_readstart;
+ post( "sonogram~ : warning : range for reading is null" );
+ } else {
+ x->x_readend=endpoint;
+ }
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete line %xREADEND\n",
+ glist_getcanvas( x->x_glist ), x);
+ SYS_VGUI7( ".x%x.c create line %d %d %d %d -fill #FF0000 -tags %xREADEND -width 3\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+(x->x_readend*(x->x_size)/100 ),
+ x->x_ypos, x->x_xpos+(x->x_readend*(x->x_size)/100 ),
+ x->x_ypos+x->x_blocksize*x->x_zoom, x );
+ }
+}
+
+ /* setting the ending point for modification ( in percent ) */
+static void sonogram_modend(t_sonogram *x, t_floatarg fend)
+{
+ t_float endpoint = fend;
+
+ if (endpoint < 0) endpoint = 0;
+ if (endpoint > 100) endpoint = 100;
+ if ( endpoint < x->x_modstart ) {
+ x->x_modend = x->x_modstart;
+ post( "sonogram~ : warning : range for modifications is null" );
+ } else {
+ x->x_modend=endpoint;
+ }
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete line %xMODEND\n",
+ glist_getcanvas( x->x_glist ), x);
+ SYS_VGUI7( ".x%x.c create line %d %d %d %d -fill #11E834 -tags %xMODEND -width 3\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+(x->x_modend*(x->x_size)/100 ),
+ x->x_ypos, x->x_xpos+(x->x_modend*(x->x_size)/100 ),
+ x->x_ypos+x->x_blocksize*x->x_zoom, x );
+ }
+}
+
+ /* sets the reading speed */
+static void sonogram_readspeed(t_sonogram *x, t_floatarg freadspeed)
+{
+ if (freadspeed <= 0 ) {
+ post( "sonogram~ : wrong readspeed argument" );
+ return;
+ }
+ x->x_readspeed=freadspeed;
+}
+
+ /* enhance frequencies */
+static void sonogram_enhance(t_sonogram *x, t_floatarg fstartfreq, t_floatarg fendfreq, t_floatarg fenhance, t_floatarg fnoupdate )
+{
+ t_int samplestart, sampleend, si, fi=0, ffi=0;
+ t_float oldenergy;
+
+ if (fstartfreq < 0 || fendfreq < 0 ||
+ fstartfreq > x->x_blocksize || fendfreq > x->x_blocksize ||
+ fstartfreq > fendfreq ) {
+ post( "sonogram~ : error : wrong frequencies range" );
+ return;
+ }
+ if ( fenhance < 0 ) {
+ post( "sonogram~ : error : wrong multiplicating factor" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ // post("enhancing portion [%d,%d]", samplestart, sampleend );
+ for ( si=samplestart; si<=sampleend; si++ ) {
+ for ( fi=(int)fstartfreq; fi<=(int)fendfreq; fi++ ) {
+ *(x->x_multfreq+fi) = fenhance;
+ if ( (fi != 0) && (fi != x->x_blocksize/2-1) )
+ {
+ /* multiply both r*sin(a) and r*cos(a) to mutiply r */
+ *(x->x_rdata+(si*x->x_blocksize)+fi) *= fenhance;
+ *(x->x_idata+(si*x->x_blocksize)+fi) *= fenhance;
+ }
+ }
+ }
+ // post( "sonogram~ : enhanced %d,%d", fi, ffi );
+ if ( !(int)fnoupdate )
+ {
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+ }
+}
+
+ /* add a constant to frequencies */
+static void sonogram_add(t_sonogram *x, t_floatarg fstartfreq, t_floatarg fendfreq, t_floatarg fadd)
+{
+ t_int samplestart, sampleend, si, fi;
+ t_float oldenergy;
+
+ if (fstartfreq < 0 || fendfreq < 0 ||
+ fstartfreq > x->x_blocksize || fendfreq > x->x_blocksize ||
+ fstartfreq > fendfreq ) {
+ post( "sonogram~ : error : wrong frequencies range" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ // post("enhancing portion [%d,%d]", samplestart, sampleend );
+ for ( si=samplestart; si<=sampleend; si++ ) {
+ for ( fi=(int)fstartfreq; fi<=(int)fendfreq; fi++ ) {
+ /* multiply both r*sin(a) and r*cos(a) to mutiply r */
+ *(x->x_rdata+(si*x->x_blocksize)+fi) += fadd;
+ *(x->x_idata+(si*x->x_blocksize)+fi) += fadd;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* resize sonogram */
+static void sonogram_resize(t_sonogram *x, t_floatarg fnewsize )
+{
+ if (fnewsize <= 0) {
+ post( "sonogram~ : error : wrong size" );
+ return;
+ }
+ if (x->x_updatechild > 0) {
+ post( "sonogram~ : can't resize now, an update is pending." );
+ return;
+ }
+ post( "sonogram~ : reallocating tables" );
+ x->x_record = 0;
+ x->x_play = 0;
+ sonogram_free(x);
+ x->x_size = fnewsize;
+ sonogram_allocate(x);
+ // erase all points, as data is zero no drawing is needed
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, 0, 0, 0);
+}
+
+ /* set zoom factor */
+static void sonogram_zoom(t_sonogram *x, t_floatarg fzoom )
+{
+ post( "sonogram~: warning : zoom and big block factors might lead to a crash" );
+ if (fzoom < 1) {
+ post( "sonogram~ : error : wrong zoom factor" );
+ return;
+ }
+ if ( x->x_gifdata != NULL ) {
+ freebytes(x->x_gifdata, (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ post( "Freed %d bytes", (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ x->x_gifdata = NULL;
+ }
+ if ( x->x_guicommand != NULL ) {
+ freebytes(x->x_guicommand, 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ post( "Freed %d bytes", 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ x->x_guicommand = NULL;
+ }
+ x->x_zoom = (int)fzoom;
+ if ( !( x->x_gifdata = ( char* ) getbytes( (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return;
+ } else {
+ post( "sonogram~ : allocated %d bytes", (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ }
+ if ( !( x->x_guicommand = ( char* ) getbytes( 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return;
+ } else {
+ post( "sonogram~ : allocated %d bytes", 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ }
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, !x->x_empty, !x->x_empty, 0);
+ canvas_fixlinesfor( glist_getcanvas( x->x_glist ), (t_text*)x );
+}
+
+ /* refresh data */
+static void sonogram_refresh(t_sonogram *x)
+{
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, 0, 1, 1);
+}
+
+ /* flip frequencies */
+static void sonogram_flipfreqs(t_sonogram *x)
+{
+ t_int samplestart, sampleend, si, fi;
+ t_float fvalue;
+ t_int ioperon;
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ ioperon=x->x_blocksize/2;
+ for ( si=samplestart; si<=sampleend; si++ ) {
+ for ( fi=0; fi<=ioperon/2; fi++ ) {
+ fvalue = *(x->x_rdata+(si*x->x_blocksize)+fi);
+ *(x->x_rdata+(si*x->x_blocksize)+fi) = *(x->x_rdata+(si*x->x_blocksize)+(ioperon-fi-1));
+ *(x->x_rdata+(si*x->x_blocksize)+(ioperon-fi-1)) = fvalue;
+ fvalue = *(x->x_idata+(si*x->x_blocksize)+fi);
+ *(x->x_idata+(si*x->x_blocksize)+fi) = *(x->x_idata+(si*x->x_blocksize)+(ioperon-fi-1));
+ *(x->x_idata+(si*x->x_blocksize)+(ioperon-fi-1)) = fvalue;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* flip blocks */
+static void sonogram_flipblocks(t_sonogram *x)
+{
+ t_int samplestart, sampleend, middlesample, fi, si;
+ t_float fvalue;
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ middlesample = ( sampleend+samplestart+1 ) / 2;
+ for ( si=samplestart; si<=middlesample; si++ ) {
+ for ( fi=0; fi<x->x_blocksize; fi++ ) {
+ fvalue = *(x->x_rdata+((si)*x->x_blocksize)+fi);
+ *(x->x_rdata+((si)*x->x_blocksize)+fi) = *(x->x_rdata+((sampleend+samplestart-si)*x->x_blocksize)+fi);
+ *(x->x_rdata+((sampleend+samplestart-si)*x->x_blocksize)+fi) = fvalue;
+ fvalue = *(x->x_idata+((si)*x->x_blocksize)+fi);
+ *(x->x_idata+((si)*x->x_blocksize)+fi) = *(x->x_idata+((sampleend+samplestart-si)*x->x_blocksize)+fi);
+ *(x->x_idata+((sampleend+samplestart-si)*x->x_blocksize)+fi) = fvalue;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* undo if available */
+static void sonogram_undo(t_sonogram *x)
+{
+ t_int si,fi;
+
+ if ( x->x_uxs == -1 )
+ {
+ post( "sonogram~ : nothing to undo, man" );
+ return;
+ }
+
+ post( "sonogram~ : restoring region [%d,%d,%d,%d]", x->x_uxs, x->x_uys, x->x_uxe, x->x_uye );
+ for ( si=x->x_uxs; si<=x->x_uxe; si++ ) {
+ for ( fi=x->x_uys; fi<=x->x_uye; fi++ ) {
+ *(x->x_rdata+((si)*x->x_blocksize)+fi) = *(x->x_rudata+(si-x->x_uxs)*x->x_blocksize+(fi-x->x_uys));
+ *(x->x_idata+((si)*x->x_blocksize)+fi) = *(x->x_iudata+(si-x->x_uxs)*x->x_blocksize+(fi-x->x_uys));
+ }
+ }
+ sonogram_update_part(x, x->x_glist, x->x_uxs, x->x_uxe, 0, 1, 1);
+}
+
+ /* zswap exchanges real and imaginery part */
+static void sonogram_zswap(t_sonogram *x)
+{
+ t_int samplestart, sampleend, fi, si;
+ t_float fvalue;
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ for ( si=samplestart; si<=sampleend; si++ ) {
+ for ( fi=0; fi<x->x_blocksize; fi++ ) {
+ fvalue = *(x->x_rdata+(si*x->x_blocksize)+fi);
+ *(x->x_rdata+(si*x->x_blocksize)+fi) = *(x->x_idata+(si*x->x_blocksize)+fi);
+ *(x->x_idata+(si*x->x_blocksize)+fi) = fvalue;
+ }
+ }
+}
+
+ /* swap points */
+static void sonogram_swappoints(t_sonogram *x, t_floatarg fnbpoints)
+{
+ t_int samplestart, sampleend, sp;
+ t_float s1, s2, f1, f2;
+ t_float fvalue;
+
+ if (fnbpoints <= 0) {
+ post( "sonogram~ : error : bad number of points" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=0; sp<fnbpoints; sp++ ) {
+#ifdef NT
+ s1 = samplestart + (rand()%(sampleend-samplestart));
+ s2 = samplestart + (rand()%(sampleend-samplestart));
+ f1 = rand()%( x->x_blocksize/2-1 );
+ f2 = rand()%( x->x_blocksize/2-1 );
+#else
+ s1 = samplestart + (random()%(sampleend-samplestart));
+ s2 = samplestart + (random()%(sampleend-samplestart));
+ f1 = random()%( x->x_blocksize/2-1 );
+ f2 = random()%( x->x_blocksize/2-1 );
+#endif
+ fvalue = *(x->x_rdata+((int)s1*x->x_blocksize)+(int)f1);
+ *(x->x_rdata+((int)s1*x->x_blocksize)+(int)f1) = *(x->x_rdata+((int)s2*x->x_blocksize)+(int)f2);
+ *(x->x_rdata+((int)s2*x->x_blocksize)+(int)f2) = fvalue;
+ fvalue = *(x->x_idata+((int)s1*x->x_blocksize)+(int)f1);
+ *(x->x_idata+((int)s1*x->x_blocksize)+(int)f1) = *(x->x_idata+((int)s2*x->x_blocksize)+(int)f2);
+ *(x->x_idata+((int)s2*x->x_blocksize)+(int)f2) = fvalue;
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* average blocks according to a factor */
+static void sonogram_average(t_sonogram *x, t_floatarg fnbblocks)
+{
+ t_int samplestart, sampleend, fi, si, ssi;
+ t_float fraverage, fiaverage;
+
+ if (fnbblocks < 1) {
+ post( "sonogram~ : error : bad average factor" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ fraverage=fiaverage=0.0;
+ for ( fi=0; fi<x->x_blocksize; fi++ ) {
+ for ( si=samplestart; si<=sampleend-fnbblocks; si+=fnbblocks ) {
+ fraverage=fiaverage=0.0;
+ for ( ssi=0; ssi<fnbblocks; ssi++ ) {
+ fraverage += *(x->x_rdata+((int)(si+ssi)*x->x_blocksize)+fi);
+ fiaverage += *(x->x_idata+((int)(si+ssi)*x->x_blocksize)+fi);
+ }
+ fraverage /= fnbblocks;
+ fiaverage /= fnbblocks;
+ for ( ssi=0; ssi<fnbblocks; ssi++ ) {
+ *(x->x_rdata+((int)(si+ssi)*x->x_blocksize)+fi)=fraverage;
+ *(x->x_idata+((int)(si+ssi)*x->x_blocksize)+fi)=fiaverage;
+ }
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* go up by the given number */
+static void sonogram_goup(t_sonogram *x, t_floatarg fgoup)
+{
+ t_int samplestart, sampleend, sp, sf;
+
+ if (fgoup <= 0 || fgoup > x->x_blocksize/2) {
+ post( "sonogram~ : error : wrong offset in goup function" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+ for (sf=(x->x_blocksize/2)-fgoup-1; sf>=0; sf-- ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(sf+(int)fgoup)) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+sf);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(sf+(int)fgoup)) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+sf);
+
+ }
+ for (sf=0; sf<fgoup; sf++ ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)sf) = 0.0;
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)sf) = 0.0;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* roll up by the given number */
+static void sonogram_roll(t_sonogram *x, t_floatarg froll)
+{
+ t_int samplestart, sampleend, sp, sf;
+ t_float *fprvalues;
+ t_float *fpivalues;
+
+ if (froll <= 0 || froll > x->x_blocksize/2) {
+ post( "sonogram~ : error : wrong offset in roll function" );
+ return;
+ }
+ fprvalues = (t_float*)getbytes( ((int)froll)*sizeof( float ) );
+ if ( !fprvalues ) {
+ post( "sonogram~ : error : could not allocate %d bytes", ((int)froll)*sizeof(float) );
+ return;
+ }
+ fpivalues = (t_float*)getbytes( ((int)froll)*sizeof( float ) );
+ if ( !fpivalues ) {
+ post( "sonogram~ : error : could not allocate %d bytes", ((int)froll)*sizeof(float) );
+ return;
+ }
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+
+ // saving values
+ for (sf=0; sf<froll; sf++ ) {
+ *(fprvalues+sf) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(x->x_blocksize/2-(int)froll+sf));
+ *(fpivalues+sf) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+(x->x_blocksize/2-(int)froll+sf));
+ }
+ for (sf=(x->x_blocksize/2)-froll-1; sf>=0; sf-- ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(sf+(int)froll)) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+sf);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(sf+(int)froll)) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+sf);
+ }
+ for (sf=0; sf<froll; sf++ ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)sf) = *(fprvalues+sf);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)sf) = *(fpivalues+sf);
+ }
+ }
+ freebytes( fprvalues, (int)froll*sizeof(float) );
+ freebytes( fpivalues, (int)froll*sizeof(float) );
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* suppress point below the threshold */
+static void sonogram_threshold(t_sonogram *x, t_floatarg fthreshold)
+{
+ t_int samplestart, sampleend, sp, sf;
+ t_float fspectrum;
+
+ if (fthreshold <= 0) {
+ post( "sonogram~ : error : wrong threshold" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+ for (sf=0; sf<=(x->x_blocksize/2)-1; sf++ ) {
+ fspectrum = sqrt( pow( *(x->x_rdata+sp*x->x_blocksize+sf), 2) +
+ pow( *(x->x_idata+sp*x->x_blocksize+sf), 2) );
+ if ( fspectrum < fthreshold )
+ {
+ *(x->x_rdata+sp*x->x_blocksize+sf) = 0.0;
+ *(x->x_idata+sp*x->x_blocksize+sf) = 0.0;
+ }
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* change the phase */
+static void sonogram_phase(t_sonogram *x, t_floatarg fincphase)
+{
+ if (fincphase < 0 || fincphase > 90) {
+ post( "sonogram~ : error : wrong phase in phase function : out of [0,90]" );
+ return;
+ }
+ x->x_phase = fincphase;
+}
+
+ /* go down by the given number */
+static void sonogram_godown(t_sonogram *x, t_floatarg fgodown)
+{
+ t_int samplestart, sampleend, sp, sf;
+
+ if (fgodown <= 0 || fgodown > x->x_blocksize/2) {
+ post( "sonogram~ : error : wrong offset in godown function" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+ for (sf=0; sf<=(x->x_blocksize/2)-fgodown-1; sf++ ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+sf) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(sf+(int)fgodown));
+ *(x->x_idata+((int)sp*x->x_blocksize)+sf) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+(sf+(int)fgodown));
+ }
+ for (sf=(x->x_blocksize/2)-fgodown; sf<(x->x_blocksize/2); sf++ ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)sf) = 0.0;
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)sf) = 0.0;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* swap blocks */
+static void sonogram_swapblocks(t_sonogram *x, t_floatarg fperstart, t_floatarg fperend, t_floatarg fpersize)
+{
+ t_int samplestart, samplestartb, samplesize, sp, sf;
+ t_int iperstart, iperend, ipersize;
+ t_float s1, s2;
+ t_float fvalue;
+
+ iperstart = fperstart;
+ iperend = fperend;
+ ipersize = fpersize;
+
+ if (iperstart < 0 || iperstart > iperend ||
+ iperend <= 0 || iperend+ipersize > 100 ||
+ ipersize < 0 || fpersize > 100 ) {
+ post( "sonogram~ : error : wrong interval [%d%%, %d%%] <-> [%d%%, %d%%]",
+ iperstart, iperstart+ipersize, iperend, iperend+ipersize );
+ return;
+ }
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ samplestartb=(x->x_modend*(x->x_size-1))/100;
+ samplesize=((samplestartb-samplestart)*ipersize)/100;
+ samplestart=samplestart+((samplestartb-samplestart)*iperstart)/100;
+ samplestartb=samplestart+((samplestartb-samplestart)*iperend)/100;
+
+ post( "swap blocks [%d,%d] and [%d,%d]", samplestart, samplestart+samplesize, samplestartb, samplestartb+samplesize );
+
+ for ( sp=samplesize; sp>=0; sp-- ) {
+ for ( sf=0; sf<x->x_blocksize; sf++) {
+ fvalue = *(x->x_rdata+((int)(samplestart+sp)*x->x_blocksize)+sf);
+ *(x->x_rdata+((int)(samplestart+sp)*x->x_blocksize)+sf) = *(x->x_rdata+((int)(samplestartb+sp)*x->x_blocksize)+sf);
+ *(x->x_rdata+((int)(samplestartb+sp)*x->x_blocksize)+sf) = fvalue;
+ fvalue = *(x->x_idata+((int)(samplestart+sp)*x->x_blocksize)+sf);
+ *(x->x_idata+((int)(samplestart+sp)*x->x_blocksize)+sf) = *(x->x_idata+((int)(samplestartb+sp)*x->x_blocksize)+sf);
+ *(x->x_idata+((int)(samplestartb+sp)*x->x_blocksize)+sf) = fvalue;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, 0, 1, 1);
+}
+
+ /* swap frequencies */
+static void sonogram_swapfreqs(t_sonogram *x, t_floatarg ffirstfreq, t_floatarg fsecondfreq)
+{
+ t_int samplestart, sampleend, sp;
+ t_float fvalue;
+
+ if (ffirstfreq < 0 || fsecondfreq <0) {
+ post( "sonogram~ : error : wrong frequencies" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+ fvalue = *(x->x_rdata+((int)sp*x->x_blocksize)+(int)ffirstfreq);
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)ffirstfreq) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)fsecondfreq);
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)fsecondfreq) = fvalue;
+ fvalue = *(x->x_idata+((int)sp*x->x_blocksize)+(int)ffirstfreq);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)ffirstfreq) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)fsecondfreq);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)fsecondfreq) = fvalue;
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+static void *sonogram_new(t_floatarg fsize, t_floatarg fgraphic, t_floatarg fphaso)
+{
+ t_sonogram *x = (t_sonogram *)pd_new(sonogram_class);
+ outlet_new(&x->x_obj, &s_signal);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_recend = outlet_new(&x->x_obj, &s_bang );
+ x->x_end = outlet_new(&x->x_obj, &s_bang );
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("readstart"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("readend"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("modstart"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("modend"));
+
+ if ( fsize <= 0 || ( fgraphic != 0 && fgraphic != 1 ) || ( fphaso != 0 && fphaso != 1 ) ) {
+ error( "sonogram~ : missing or negative creation arguments" );
+ return NULL;
+ }
+
+ // activate graphical callbacks
+ if ( fgraphic != 0 )
+ {
+ class_setwidget(sonogram_class, &sonogram_widgetbehavior);
+ }
+ x->x_graphic = (int) fgraphic;
+ x->x_phaso = (int) fphaso;
+
+ x->x_size = fsize;
+ x->x_blocksize = sys_getblksize();
+ x->x_play = 0;
+ x->x_readspeed = 1.;
+ x->x_record = 0;
+ x->x_readpos = 0.;
+ x->x_writepos = 0;
+ x->x_modstart = 0;
+ x->x_readstart = 0;
+ x->x_modend = 100;
+ x->x_readend = 100;
+ x->x_rdata = NULL;
+ x->x_idata = NULL;
+ x->x_phase = 0.0;
+ x->x_empty = 1;
+ x->x_xpos = -1;
+ x->x_ypos = -1;
+ x->x_samplerate = sys_getsr();
+ /* graphic data */
+ x->x_selected = 0;
+ x->x_zoom = 1;
+ x->x_updatechild = 0;
+ x->x_modstep = 1.1;
+ x->x_enhancemode = 0;
+ x->x_glist = (t_glist*)canvas_getcurrent();
+
+ if ( sonogram_allocate(x) <0 ) {
+ return NULL;
+ } else {
+ return(x);
+ }
+
+}
+
+void sonogram_tilde_setup(void)
+{
+ post(sonogram_version);
+ sonogram_class = class_new(gensym("sonogram~"), (t_newmethod)sonogram_new, (t_method)sonogram_free,
+ sizeof(t_sonogram), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_sethelpsymbol( sonogram_class, gensym("help-sonogram~.pd") );
+
+ // set callbacks
+ sonogram_widgetbehavior.w_getrectfn = sonogram_getrect;
+ sonogram_widgetbehavior.w_displacefn = sonogram_displace;
+ sonogram_widgetbehavior.w_selectfn = sonogram_select;
+ sonogram_widgetbehavior.w_activatefn = NULL;
+ sonogram_widgetbehavior.w_deletefn = sonogram_delete;
+ sonogram_widgetbehavior.w_visfn = sonogram_vis;
+ sonogram_widgetbehavior.w_clickfn = sonogram_click;
+ sonogram_widgetbehavior.w_propertiesfn = NULL;
+ sonogram_widgetbehavior.w_savefn = sonogram_save;
+
+ CLASS_MAINSIGNALIN( sonogram_class, t_sonogram, x_f );
+ class_addmethod(sonogram_class, (t_method)sonogram_dsp, gensym("dsp"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_record, gensym("record"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_enhance, gensym("enhance"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_add, gensym("add"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_resize, gensym("resize"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_zoom, gensym("zoom"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_swappoints, gensym("swappoints"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_average, gensym("average"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_swapblocks, gensym("swapblocks"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_swapfreqs, gensym("swapfreqs"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_flipfreqs, gensym("flipfreqs"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_flipblocks, gensym("flipblocks"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_play, gensym("play"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_refresh, gensym("refresh"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_enhancemode, gensym("enhancemode"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_goup, gensym("goup"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_godown, gensym("godown"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_roll, gensym("roll"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_threshold, gensym("threshold"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_phase, gensym("phase"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_zswap, gensym("zswap"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_modstep, gensym("modstep"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_modstart, gensym("modstart"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_modend, gensym("modend"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_readstart, gensym("readstart"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_readend, gensym("readend"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_readspeed, gensym("readspeed"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_undo, gensym("undo"), A_NULL);
+}
diff --git a/sonogram~/sonogram~-yves.c b/sonogram~/sonogram~-yves.c
new file mode 100644
index 0000000..0d2a721
--- /dev/null
+++ b/sonogram~/sonogram~-yves.c
@@ -0,0 +1,1995 @@
+/*------------------------ sonogram~ ------------------------------------------ */
+/* */
+/* sonogram~ : lets you record, play back and modify a sonogram */
+/* constructor : sonogram <size> <graphical=0|1> <phasogram=0|1> */
+/* */
+/* Copyleft Yves Degoyon ( 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. */
+/* */
+/* "Living at night" */
+/* "Doesn't help for my complexion" */
+/* David Thomas - Final Solution */
+/* ---------------------------------------------------------------------------- */
+
+
+
+#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>
+#include <pthread.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#ifdef NT
+#define M_PI 3.14159265358979323846
+#endif
+#include <math.h>
+
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+
+static int guidebug=0;
+static int ignorevisible=1; // ignore visible test
+ // because this seems to lead to bad refresh
+ // wait for a fix
+
+#define SYS_VGUI2(a,b) if (guidebug) \
+ post(a,b);\
+ sys_vgui(a,b)
+
+#define SYS_VGUI3(a,b,c) if (guidebug) \
+ post(a,b,c);\
+ sys_vgui(a,b,c)
+
+#define SYS_VGUI4(a,b,c,d) if (guidebug) \
+ post(a,b,c,d);\
+ sys_vgui(a,b,c,d)
+
+#define SYS_VGUI5(a,b,c,d,e) if (guidebug) \
+ post(a,b,c,d,e);\
+ sys_vgui(a,b,c,d,e)
+
+#define SYS_VGUI6(a,b,c,d,e,f) if (guidebug) \
+ post(a,b,c,d,e,f);\
+ sys_vgui(a,b,c,d,e,f)
+
+#define SYS_VGUI7(a,b,c,d,e,f,g) if (guidebug) \
+ post(a,b,c,d,e,f,g );\
+ sys_vgui(a,b,c,d,e,f,g)
+
+#define SYS_VGUI9(a,b,c,d,e,f,g,h,i) if (guidebug) \
+ post(a,b,c,d,e,f,g,h,i );\
+ sys_vgui(a,b,c,d,e,f,g,h,i)
+
+#define SYS_VGUI10(a,b,c,d,e,f,g,h,i,j) if (guidebug) \
+ post(a,b,c,d,e,f,g,h,i,j );\
+ sys_vgui(a,b,c,d,e,f,g,h,i,j)
+
+#define SYS_VGUI11(a,b,c,d,e,f,g,h,i,j,k) if (guidebug) \
+ post(a,b,c,d,e,f,g,h,i,j,k );\
+ sys_vgui(a,b,c,d,e,f,g,h,i,j,k)
+
+#define THREAD_SLEEP_TIME 100000 // 100000 us = 100 ms
+
+static char *sonogram_version = "sonogram~: version 0.9, written by Yves Degoyon (ydegoyon@free.fr)";
+
+static t_class *sonogram_class;
+t_widgetbehavior sonogram_widgetbehavior;
+
+
+typedef struct _sonogram
+{
+ t_object x_obj;
+
+ t_int x_size; /* size of the stored fft ( in blocks~ ) */
+ t_float x_samplerate; /* sample rate */
+ t_int x_blocksize; /* current block size ( might be modified by block~ object ) */
+ t_float x_readpos; /* data's playing position */
+ t_int x_writepos; /* data's recording position */
+ t_int x_readstart; /* data's starting position for reading */
+ t_int x_readend; /* data's ending position for reading */
+ t_int x_modstart; /* data's starting position for modifications */
+ t_int x_modend; /* data's ending position for modifications */
+ t_int x_play; /* playing on/off flag */
+ t_float x_readspeed; /* number of grouped blocks for reading */
+ t_float x_record; /* flag to start recording process */
+ t_float x_empty; /* flag to indicate it's a brand new sonogram */
+ t_float *x_rdata; /* table containing real part of the fft */
+ t_float *x_rudata; /* undo real data */
+ t_float *x_idata; /* table containing imaginery part of the fft */
+ t_float *x_iudata; /* undo imaginery data */
+ t_float x_phase; /* phase to apply on output */
+ t_outlet *x_end; /* outlet for end of restitution */
+ t_outlet *x_recend; /* outlet for end of recording */
+ t_int *x_multfreq; /* array of multiplicative factor */
+ char *x_gifdata; /* buffer for graphical data */
+ char *x_guicommand; /* buffer for graphical command */
+ t_int x_uxs; /* starting x position for undo */
+ t_int x_uxe; /* ending x position for undo */
+ t_int x_uys; /* starting y position for undo */
+ t_int x_uye; /* ending y position for undo */
+
+ /* graphical data block */
+ t_int x_enhancemode; /* flag to set enhance mode */
+ t_int x_graphic; /* flag to set graphic mode */
+ t_int x_phaso; /* flag to indicate if phasogram is shown */
+ t_int x_selected; /* flag to remember if we are seleted or not */
+ t_int x_erase; /* flag used when an erase is needed */
+ t_int x_redraw; /* flag used when drawing is needed */
+ t_int x_nbupdated; /* number of points updated */
+ t_glist *x_glist; /* keep graphic context for various operations */
+ t_int x_zoom; /* zoom factor */
+ pthread_t x_updatechild; /* thread id for the update child */
+ t_int x_updatestart; /* starting position for update */
+ t_int x_updateend; /* ending position for update */
+ t_int x_xpos; /* stuck x position */
+ t_int x_ypos; /* stuck y position */
+ t_int x_shifted; /* remember shift state from last click */
+ t_int x_alted; /* remember alt state from last click */
+ t_int x_aftermousedown; /* indicates the mousedown event */
+ t_int x_xstartcapture; /* x of the start of the capture */
+ t_int x_ystartcapture; /* y of the start of the capture */
+ t_int x_xendcapture; /* x of the start of the capture */
+ t_int x_yendcapture; /* y of the start of the capture */
+ t_int x_xdraw; /* x drawing position */
+ t_int x_ydraw; /* y drawing position */
+ t_float x_modstep; /* step for graphical modifications */
+
+ t_float x_f; /* float needed for signal input */
+
+} t_sonogram;
+
+/* ------------------------ drawing functions ---------------------------- */
+static char* sonogram_get_fill_color( t_float fspectrum )
+{
+ if ( fspectrum < 0.01 ) {
+ return "#EEEEEE";
+ } else if ( fspectrum < 0.1 ) {
+ return "#DDDDDD";
+ } else if ( fspectrum < 0.5 ) {
+ return "#CCCCCC";
+ } else if ( fspectrum < 1 ) {
+ return "#BBBBBB";
+ } else if ( fspectrum < 2 ) {
+ return "#AAAAAA";
+ } else if ( fspectrum < 5 ) {
+ return "#999999";
+ } else if ( fspectrum < 10 ) {
+ return "#888888";
+ } else if ( fspectrum < 20 ) {
+ return "#777777";
+ } else if ( fspectrum < 30 ) {
+ return "#666666";
+ } else if ( fspectrum < 40 ) {
+ return "#555555";
+ } else if ( fspectrum < 50 ) {
+ return "#444444";
+ } else if ( fspectrum < 60 ) {
+ return "#333333";
+ } else if ( fspectrum < 80 ) {
+ return "#222222";
+ } else if ( fspectrum < 100 ) {
+ return "#111111";
+ } else {
+ return "#000000";
+ }
+}
+
+static char* phasogram_get_fill_color( t_int phase )
+{
+ if ( phase < 0 )
+ {
+ if ( phase > -10 ) {
+ return "#111111";
+ } else if ( phase > -20 ) {
+ return "#222222";
+ } else if ( phase > -30 ) {
+ return "#333333";
+ } else if ( phase > -40 ) {
+ return "#444444";
+ } else if ( phase > -50 ) {
+ return "#555555";
+ } else if ( phase > -60 ) {
+ return "#666666";
+ } else if ( phase > -70 ) {
+ return "#777777";
+ } else if ( phase > -80 ) {
+ return "#888888";
+ } else {
+ return "#999999";
+ }
+ }
+ else
+ {
+ if ( phase == 0 ) {
+ return "#FFFFFF";
+ } else if ( phase < 10 ) {
+ return "#111111";
+ } else if ( phase < 20 ) {
+ return "#222222";
+ } else if ( phase < 30 ) {
+ return "#333333";
+ } else if ( phase < 40 ) {
+ return "#444444";
+ } else if ( phase < 50 ) {
+ return "#555555";
+ } else if ( phase < 60 ) {
+ return "#666666";
+ } else if ( phase < 70 ) {
+ return "#777777";
+ } else if ( phase < 80 ) {
+ return "#888888";
+ } else {
+ return "#999999";
+ }
+ }
+ // normally never reached
+ return "";
+}
+
+static void sonogram_update_point(t_sonogram *x, t_glist *glist, t_int sample, t_int frequency)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ t_float fspectrum=0.0;
+ t_int phase=0.0;
+ char newColor[ 8 ], olColor[8];
+ int i;
+
+ fspectrum =
+ sqrt( pow( *(x->x_rdata+sample*x->x_blocksize+frequency), 2) +
+ pow( *(x->x_idata+sample*x->x_blocksize+frequency), 2) );
+ phase = (int) ( atan2( *(x->x_idata+(sample*x->x_blocksize)+frequency),
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) )*180/M_PI );
+ if ( x->x_empty && ( fspectrum != 0 ))
+ {
+ x->x_empty = 0;
+ }
+ strcpy( newColor, sonogram_get_fill_color( fspectrum ) );
+
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ sprintf( x->x_gifdata, "%s", strcat( newColor, " ") );
+ }
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ SYS_VGUI5("SONIMAGE%x put {%s} -to %d %d\n", x, x->x_gifdata,
+ sample*x->x_zoom+i, (x->x_blocksize/2-frequency)*x->x_zoom );
+ }
+
+ if ( x->x_phaso )
+ {
+ strcpy( newColor, phasogram_get_fill_color( phase ) );
+ strcpy( x->x_gifdata, "" );
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ sprintf( x->x_gifdata, "%s", strcat( newColor, " ") );
+ }
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ SYS_VGUI5("FAZIMAGE%x put {%s} -to %d %d\n", x, x->x_gifdata,
+ sample*x->x_zoom+i, (x->x_blocksize/2-frequency)*x->x_zoom );
+ }
+ }
+
+ x->x_nbupdated++;
+}
+
+static void sonogram_update_block(t_sonogram *x, t_glist *glist, t_int bnumber)
+{
+ t_int fi, i=0;
+ t_float fspectrum=0.0;
+ t_int phase=0;
+ char color[8];
+
+ // update sonogram
+ for ( fi=x->x_blocksize/2-1; fi>=0; fi-- )
+ {
+ fspectrum =
+ sqrt( pow( *(x->x_rdata+bnumber*x->x_blocksize+fi), 2) +
+ pow( *(x->x_idata+bnumber*x->x_blocksize+fi), 2) );
+ strcpy( color, sonogram_get_fill_color( fspectrum ) );
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ strncpy( x->x_gifdata+((x->x_blocksize/2-fi-1)*x->x_zoom+i)*8, strcat( color, " "), 8 );
+ }
+ }
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ sprintf( x->x_guicommand, "SONIMAGE%x put {%s} -to %d 0\n", (unsigned int)x, x->x_gifdata, (bnumber*x->x_zoom)+i );
+ sys_gui( x->x_guicommand );
+ }
+
+ // update phasogram
+ if ( x->x_phaso )
+ {
+ strcpy( x->x_gifdata, "" );
+ for ( fi=x->x_blocksize/2-1; fi>=0; fi-- )
+ {
+ phase = (int) ( atan2( *(x->x_idata+bnumber*x->x_blocksize+fi),
+ *(x->x_rdata+bnumber*x->x_blocksize+fi) )*180/M_PI );
+ strcpy( color, phasogram_get_fill_color( phase ) );
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ strncpy( x->x_gifdata+((x->x_blocksize/2-fi-1)*x->x_zoom+i)*8, strcat( color, " "), 8 );
+ }
+ }
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ sprintf( x->x_guicommand, "FAZIMAGE%x put {%s} -to %d 0\n", (unsigned int)x, x->x_gifdata, (bnumber*x->x_zoom)+i );
+ sys_gui( x->x_guicommand );
+ }
+ }
+
+}
+
+static void sonogram_erase_block(t_sonogram *x, t_glist *glist, t_int bnumber )
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ t_int fi;
+ t_float fspectrum=0.0;
+ char fillColor[ 16 ];
+
+ for ( fi=0; fi<x->x_blocksize/2; fi++)
+ {
+ {
+ int i;
+
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ strcpy( x->x_gifdata+i*sizeof("#FFFFFF "), "#FFFFFF " );
+ }
+ SYS_VGUI5("SONIMAGE%x put {%s} -to %d %d\n", x, x->x_gifdata,
+ bnumber*x->x_zoom, (x->x_blocksize/2-fi)*x->x_zoom );
+ }
+ }
+}
+
+static void *sonogram_do_update_part(void *tdata)
+{
+ t_sonogram *x = (t_sonogram*) tdata;
+ t_int si;
+ t_int nbpoints = 0;
+ t_float percentage = 0, opercentage = 0;
+
+ // loose synchro
+ usleep( THREAD_SLEEP_TIME );
+
+ // check boundaries
+ if ( x->x_updateend > x->x_size-1 ) x->x_updateend = x->x_size-1;
+ if ( x->x_updatestart < 0 ) x->x_updatestart = 0;
+
+ // post("sonogram~ : ok, let's go [updating %d, %d]", x->x_updatestart, x->x_updateend );
+
+ if ( x->x_erase )
+ {
+ for ( si=x->x_updatestart; si<=x->x_updateend; si++ )
+ {
+ sonogram_erase_block(x, x->x_glist, si);
+ nbpoints++;
+ percentage = (nbpoints*100/(x->x_updateend-x->x_updatestart+1));
+ if ( (percentage == (int) percentage) && ((int)percentage%5 == 0) && ( percentage != opercentage ) )
+ {
+ // post( "sonogram~ : erase part : %d %% completed", (int)percentage );
+ opercentage = percentage;
+ }
+ }
+ }
+
+ percentage = opercentage = nbpoints = 0;
+
+ if ( x->x_redraw )
+ {
+ for ( si=x->x_updatestart; si<=x->x_updateend; si++ )
+ {
+ sonogram_update_block(x, x->x_glist, si);
+ nbpoints++;
+ percentage = (nbpoints*100/(x->x_updateend-x->x_updatestart+1));
+ if ( (percentage == (int) percentage) && ((int)percentage%5 == 0) && ( percentage != opercentage ) )
+ {
+ // post( "sonogram~ : update part : %d %% completed", (int)percentage );
+ opercentage = percentage;
+ }
+ }
+ }
+
+ // set borders in black
+ SYS_VGUI3(".x%x.c itemconfigure %xSONOGRAM -outline #000000\n", glist_getcanvas(x->x_glist), x);
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xPHASOGRAM -outline #000000\n", glist_getcanvas(x->x_glist), x);
+ }
+
+ // post("sonogram~ : child thread %d ended (nb_updated=%d)", (int)x->x_updatechild, x->x_nbupdated );
+ x->x_updatechild = 0;
+ return NULL;
+}
+
+static void sonogram_update_part(t_sonogram *x, t_glist *glist, t_int bstart, t_int bend,
+ t_int erase, t_int redraw, t_int keepframe)
+{
+ pthread_attr_t update_child_attr;
+
+ if ( x->x_graphic )
+ {
+ if ( x->x_updatechild != 0 )
+ {
+ // post( "sonogram~ : error : no update is possible for now" );
+ return;
+ }
+ x->x_updatestart = bstart;
+ x->x_updateend = bend;
+ if ( !keepframe )
+ {
+ x->x_erase = 0;
+ }
+ else
+ {
+ x->x_erase = erase;
+ }
+ x->x_redraw = redraw;
+ x->x_nbupdated = 0;
+ // recreate the square if needed
+ if ( ( bstart == 0 ) && ( bend == x->x_size-1 ) && !keepframe )
+ {
+ SYS_VGUI3(".x%x.c delete %xSONOGRAM\n", glist_getcanvas(glist), x );
+ SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill #FFFFFF -tags %xSONOGRAM\n",
+ glist_getcanvas(glist), x->x_xpos-1, x->x_ypos-1,
+ x->x_xpos + x->x_size*x->x_zoom+1,
+ x->x_ypos + x->x_blocksize/2*x->x_zoom+1,
+ x);
+ SYS_VGUI2("image delete SONIMAGE%x\n", x );
+ SYS_VGUI3(".x%x.c delete ISONIMAGE%x\n", glist_getcanvas(glist), x );
+ SYS_VGUI4("image create photo SONIMAGE%x -format gif -width %d -height %d\n",
+ x, x->x_size*x->x_zoom, x->x_blocksize/2*x->x_zoom );
+ SYS_VGUI2("SONIMAGE%x blank\n", x);
+ SYS_VGUI6(".x%x.c create image %d %d -image SONIMAGE%x -tags ISONIMAGE%x\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+((x->x_size*x->x_zoom)/2),
+ (x->x_ypos+((x->x_blocksize/2*x->x_zoom)/2)), x, x );
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c delete %xPHASOGRAM\n", glist_getcanvas(glist), x );
+ SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill #FFFFFF -tags %xPHASOGRAM\n",
+ glist_getcanvas(glist), x->x_xpos-1, x->x_ypos+x->x_blocksize/2*x->x_zoom+2,
+ x->x_xpos + x->x_size*x->x_zoom +1,
+ x->x_ypos + x->x_blocksize*x->x_zoom + 3,
+ x);
+ SYS_VGUI2("image delete FAZIMAGE%x\n", x );
+ SYS_VGUI3(".x%x.c delete IFAZIMAGE%x\n", glist_getcanvas(glist), x );
+ SYS_VGUI4("image create photo FAZIMAGE%x -format gif -width %d -height %d\n",
+ x, x->x_size*x->x_zoom, x->x_blocksize/2*x->x_zoom );
+ SYS_VGUI2("FAZIMAGE%x blank\n", x);
+ SYS_VGUI6(".x%x.c create image %d %d -image FAZIMAGE%x -tags IFAZIMAGE%x\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+((x->x_size*x->x_zoom)/2),
+ x->x_ypos+3*((x->x_blocksize/2*x->x_zoom)/2)+2, x, x );
+ }
+ canvas_fixlinesfor( glist_getcanvas(x->x_glist), (t_text*)x );
+ }
+ // set borders in red
+ SYS_VGUI3(".x%x.c itemconfigure %xSONOGRAM -outline #FF0000\n", glist_getcanvas(glist), x);
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xPHASOGRAM -outline #FF0000\n", glist_getcanvas(glist), x);
+ }
+
+ // launch update thread
+ if ( pthread_attr_init( &update_child_attr ) < 0 ) {
+ post( "sonogram~ : could not launch update thread" );
+ perror( "pthread_attr_init" );
+ return;
+ }
+ if ( pthread_attr_setdetachstate( &update_child_attr, PTHREAD_CREATE_DETACHED ) < 0 ) {
+ post( "sonogram~ : could not launch update thread" );
+ perror( "pthread_attr_setdetachstate" );
+ return;
+ }
+ if ( pthread_create( &x->x_updatechild, &update_child_attr, sonogram_do_update_part, x ) < 0 ) {
+ post( "sonogram~ : could not launch update thread" );
+ perror( "pthread_create" );
+ return;
+ }
+ else
+ {
+ // post( "sonogram~ : drawing thread %d launched", (int)x->x_updatechild );
+ }
+ }
+}
+
+ /* paste selection at the drawing point */
+static void sonogram_paste( t_sonogram* x)
+{
+ t_int pxstart = (x->x_xdraw-x->x_xpos)/x->x_zoom;
+ t_int pystart = (x->x_ypos-x->x_ydraw)/x->x_zoom+x->x_blocksize/2;
+ t_int cxs,cxe,cys,cye,si=0,fi=0;
+ t_float *icopy;
+ t_float *rcopy;
+ t_int copynd;
+
+ if ( x->x_xstartcapture > x->x_xendcapture ) {
+ fi = x->x_xstartcapture;
+ x->x_xstartcapture = x->x_xendcapture;
+ x->x_xendcapture = fi;
+ }
+ if ( x->x_ystartcapture > x->x_yendcapture ) {
+ fi = x->x_ystartcapture;
+ x->x_ystartcapture = x->x_yendcapture;
+ x->x_yendcapture = fi;
+ }
+ cxs=(x->x_xstartcapture-x->x_xpos)/x->x_zoom;
+ cxe=(x->x_xendcapture-x->x_xpos)/x->x_zoom;
+ cys=(x->x_ypos-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ cye=(x->x_ypos-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2;
+ if ( cye < 0 ) cye=0;
+ if ( cys < 0 ) cys=0;
+ if ( cye >= x->x_blocksize/2 ) cye=x->x_blocksize/2-1;
+ if ( cys >= x->x_blocksize/2 ) cys=x->x_blocksize/2-1;
+ if ( cxe >= x->x_size ) cxe=x->x_size-1;
+ if ( cxs >= x->x_size ) cxs=x->x_size-1;
+
+ // make a copy first
+ icopy = ( t_float* ) getbytes( ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ rcopy = ( t_float* ) getbytes( ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ if ( !icopy || !rcopy )
+ {
+ post( "sonogram~ : cannot allocate buffers for pasting" );
+ return;
+ }
+ // copy initial data
+ copynd = 0;
+ for ( si=cxs; si<=cxe; si++) {
+ for ( fi=cys; fi<=cye; fi++) {
+ *(rcopy+copynd) = *(x->x_rdata+(si)*x->x_blocksize+fi);
+ *(icopy+copynd) = *(x->x_idata+(si)*x->x_blocksize+fi);
+ copynd++;
+ }
+ }
+
+ post( "sonogram~ : paste from [%d,%d,%d,%d] to [%d,%d]", cxs, cys, cxe, cye, pxstart, pystart );
+
+ for ( si=cxs; si<=cxe; si++) {
+ if ( pxstart+si-cxs >= x->x_size ) break;
+ copynd = (si-cxs)*(cye-cys+1);
+ for ( fi=cys; fi<=cye; fi++) {
+ // post ( "sonogram~ : si : %d : fi : %d : copynd : %d", si, fi, copynd );
+ if ( pystart+fi-cys >= x->x_blocksize/2 ) break;
+ *(x->x_rudata+((si-cxs)*x->x_blocksize)+(fi-cys)) = *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys));
+ *(x->x_iudata+((si-cxs)*x->x_blocksize)+(fi-cys)) = *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys));
+ if ( x->x_enhancemode )
+ {
+ // save data for undo
+ *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) += *(rcopy+copynd);
+ *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) += *(icopy+copynd);
+ }
+ else
+ {
+ *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) = *(rcopy+copynd);
+ *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) = *(icopy+copynd);
+ }
+ copynd++;
+ }
+ }
+
+ x->x_uxs = pxstart;
+ x->x_uxe = pxstart+(si-1)-cxs;
+ x->x_uys = pystart;
+ x->x_uye = pystart+(fi-1)-cys;;
+
+ freebytes( rcopy, ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ freebytes( icopy, ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+}
+
+ /* paste phase at the drawing point */
+static void sonogram_paste_phase( t_sonogram* x)
+{
+ t_int pxstart = (x->x_xdraw-x->x_xpos)/x->x_zoom;
+ t_int pystart = (x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_ydraw)/x->x_zoom+x->x_blocksize/2;
+ t_int cxs,cxe,cys,cye,si,fi;
+ t_float fspectrum, fdestspectrum;
+ t_float fphase, fdestphase;
+ t_float *icopy;
+ t_float *rcopy;
+ t_int copynd;
+
+ if ( x->x_xstartcapture > x->x_xendcapture ) {
+ fi = x->x_xstartcapture;
+ x->x_xstartcapture = x->x_xendcapture;
+ x->x_xendcapture = fi;
+ }
+ if ( x->x_ystartcapture > x->x_yendcapture ) {
+ fi = x->x_ystartcapture;
+ x->x_ystartcapture = x->x_yendcapture;
+ x->x_yendcapture = fi;
+ }
+ cxs=(x->x_xstartcapture-x->x_xpos)/x->x_zoom;
+ cxe=(x->x_xendcapture-x->x_xpos)/x->x_zoom;
+ cys=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ cye=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2;
+ if ( cye < 0 ) cye=0;
+ if ( cys < 0 ) cys=0;
+ if ( cye >= x->x_blocksize/2 ) cye=x->x_blocksize/2-1;
+ if ( cys >= x->x_blocksize/2 ) cys=x->x_blocksize/2-1;
+ if ( cxe >= x->x_size ) cxe=x->x_size-1;
+ if ( cxs >= x->x_size ) cxs=x->x_size-1;
+
+ // make a copy first
+ icopy = ( t_float* ) getbytes( ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ rcopy = ( t_float* ) getbytes( ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ if ( !icopy || !rcopy )
+ {
+ post( "sonogram~ : cannot allocate buffers for pasting" );
+ return;
+ }
+ // copy initial data
+ copynd = 0;
+ for ( si=cxs; si<=cxe; si++) {
+ for ( fi=cys; fi<=cye; fi++) {
+ *(rcopy+copynd) = *(x->x_rdata+(si)*x->x_blocksize+fi);
+ *(icopy+copynd) = *(x->x_idata+(si)*x->x_blocksize+fi);
+ copynd++;
+ }
+ }
+
+ post( "sonogram~ : paste phase from [%d,%d,%d,%d] to [%d,%d]", cxs, cys, cxe, cye, pxstart, pystart );
+
+ for ( si=cxs; si<=cxe; si++) {
+ if ( pxstart+si-cxs >= x->x_size ) break;
+ copynd = (si-cxs)*(cye-cys+1);
+ for ( fi=cys; fi<=cye; fi++) {
+ if ( pystart+fi-cys > x->x_blocksize+1 ) break;
+ fphase = atan2( *(icopy+copynd), *(rcopy+copynd) );
+ fdestspectrum =
+ sqrt( pow( *(x->x_rdata+(pxstart+si-cxs)*x->x_blocksize+(pystart+fi-cys)), 2) +
+ pow( *(x->x_idata+(pxstart+si-cxs)*x->x_blocksize+(pystart+fi-cys)), 2) );
+ fdestphase = atan2( *(x->x_idata+(pxstart+si-cxs)*x->x_blocksize+(pystart+fi-cys)),
+ *(x->x_rdata+(pxstart+si-cxs)*x->x_blocksize+(pystart+fi-cys)) );
+ if ( x->x_enhancemode )
+ {
+ *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) +=
+ fdestspectrum*cos( fdestphase + fphase );
+ *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) +=
+ fdestspectrum*sin( fdestphase + fphase );
+ }
+ else
+ {
+ *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) =
+ fdestspectrum*cos( fphase );
+ *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) =
+ fdestspectrum*sin( fphase );
+ }
+ copynd++;
+ }
+ }
+
+ freebytes( rcopy, ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ freebytes( icopy, ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+
+ sonogram_update_part(x, x->x_glist, pxstart, pxstart+(si-1)-cxs, 0, 1, 1);
+ // start a new capture
+ SYS_VGUI3( ".x%x.c delete %xCAPTURE\n", glist_getcanvas( x->x_glist ), x );
+ x->x_xstartcapture = x->x_xdraw;
+ x->x_ystartcapture = x->x_ydraw;
+ x->x_xendcapture = x->x_xdraw;
+ x->x_yendcapture = x->x_ydraw;
+
+}
+
+static void sonogram_draw_new(t_sonogram *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if ( x->x_xpos == -1 )
+ {
+ x->x_xpos=x->x_obj.te_xpix;
+ x->x_ypos=x->x_obj.te_ypix;
+ }
+ if ( x->x_graphic )
+ {
+ SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill #FFFFFF -tags %xSONOGRAM\n",
+ canvas, x->x_xpos-1, x->x_ypos-1,
+ x->x_xpos + x->x_size*x->x_zoom+1,
+ x->x_ypos + x->x_blocksize/2*x->x_zoom+1,
+ x);
+ SYS_VGUI4("image create photo SONIMAGE%x -format gif -width %d -height %d\n",
+ x, x->x_size*x->x_zoom, x->x_blocksize/2*x->x_zoom );
+ SYS_VGUI2("SONIMAGE%x blank\n", x);
+ SYS_VGUI6(".x%x.c create image %d %d -image SONIMAGE%x -tags ISONIMAGE%x\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+((x->x_size*x->x_zoom)/2),
+ (x->x_ypos+((x->x_blocksize/2*x->x_zoom)/2)), x, x );
+ if ( x->x_phaso )
+ {
+ SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill #FFFFFF -tags %xPHASOGRAM\n",
+ glist_getcanvas(glist), x->x_xpos-1, x->x_ypos+x->x_blocksize/2*x->x_zoom+2,
+ x->x_xpos + x->x_size*x->x_zoom +1,
+ x->x_ypos + x->x_blocksize*x->x_zoom + 3,
+ x);
+ SYS_VGUI4("image create photo FAZIMAGE%x -format gif -width %d -height %d\n",
+ x, x->x_size*x->x_zoom, x->x_blocksize/2*x->x_zoom );
+ SYS_VGUI2("FAZIMAGE%x blank\n", x);
+ SYS_VGUI6(".x%x.c create image %d %d -image FAZIMAGE%x -tags IFAZIMAGE%x\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+((x->x_size*x->x_zoom)/2),
+ x->x_ypos+3*((x->x_blocksize/2*x->x_zoom)/2)+2, x, x );
+ }
+ canvas_fixlinesfor( canvas, (t_text*)x );
+ }
+}
+
+static void sonogram_draw_delete(t_sonogram *x, t_glist *glist)
+{
+ if ( x->x_graphic && glist_isvisible( glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete %xCAPTURE\n", glist_getcanvas( glist ), x );
+ SYS_VGUI3( ".x%x.c delete line %xREADSTART\n", glist_getcanvas( glist ), x);
+ SYS_VGUI3( ".x%x.c delete line %xREADEND\n", glist_getcanvas( glist ), x);
+ SYS_VGUI3( ".x%x.c delete line %xMODSTART\n", glist_getcanvas( glist ), x);
+ SYS_VGUI3( ".x%x.c delete line %xMODEND\n", glist_getcanvas( glist ), x);
+ SYS_VGUI3(".x%x.c delete %xSONOGRAM\n", glist_getcanvas( glist ), x );
+ SYS_VGUI3(".x%x.c delete %xPHASOGRAM\n", glist_getcanvas( glist ), x );
+ SYS_VGUI3(".x%x.c delete %xISONIMAGE\n", glist_getcanvas( glist ), x );
+ SYS_VGUI2("image delete SONIMAGE%x\n", x );
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c delete %xIFAZIMAGE\n", glist_getcanvas( glist ), x );
+ SYS_VGUI2("image delete FAZIMAGE%x\n", x );
+ }
+ }
+}
+
+static void sonogram_draw_move(t_sonogram *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI7(".x%x.c coords %xSONOGRAM %d %d %d %d\n",
+ canvas, x,
+ x->x_xpos-1, x->x_ypos-1,
+ x->x_xpos+x->x_size*x->x_zoom+1,
+ x->x_ypos+x->x_blocksize/2*x->x_zoom+1);
+ SYS_VGUI5(".x%x.c coords ISONIMAGE%x %d %d\n",
+ canvas, x,
+ x->x_xpos+((x->x_size*x->x_zoom)/2),
+ (x->x_ypos+((x->x_blocksize/2*x->x_zoom)/2)) );
+ if ( x->x_phaso )
+ {
+ SYS_VGUI7(".x%x.c coords %xPHASOGRAM %d %d %d %d\n",
+ canvas, x,
+ x->x_xpos-1, x->x_ypos+(x->x_blocksize/2*x->x_zoom)+1,
+ x->x_xpos+x->x_size*x->x_zoom+1,
+ x->x_ypos+x->x_blocksize*x->x_zoom+3);
+ SYS_VGUI5(".x%x.c coords IFAZIMAGE%x %d %d\n",
+ canvas, x,
+ x->x_xpos+((x->x_size*x->x_zoom)/2),
+ x->x_ypos+3*((x->x_blocksize/2*x->x_zoom)/2)+2 );
+ }
+ canvas_fixlinesfor( canvas, (t_text*)x );
+ }
+}
+
+static void sonogram_draw_select(t_sonogram* x,t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ if(x->x_selected)
+ {
+ /* sets the item in blue */
+ SYS_VGUI3(".x%x.c itemconfigure %xSONOGRAM -outline #0000FF\n", canvas, x);
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xPHASOGRAM -outline #0000FF\n", canvas, x);
+ }
+ }
+ else
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xSONOGRAM -outline #000000\n", canvas, x);
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xPHASOGRAM -outline #000000\n", canvas, x);
+ }
+ }
+ }
+}
+
+/* ------------------------ widget callbacks ----------------------------- */
+
+
+static void sonogram_getrect(t_gobj *z, t_glist *owner,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_sonogram* x = (t_sonogram*)z;
+
+ *xp1 = x->x_xpos;
+ *yp1 = x->x_ypos;
+ if ( !x->x_phaso )
+ {
+ *xp2 = x->x_xpos+x->x_size*x->x_zoom;
+ *yp2 = x->x_ypos+x->x_blocksize/2*x->x_zoom+1;
+ }
+ else
+ {
+ *xp2 = x->x_xpos+x->x_size*x->x_zoom;
+ *yp2 = x->x_ypos+x->x_blocksize*x->x_zoom+3;
+ }
+}
+
+static void sonogram_save(t_gobj *z, t_binbuf *b)
+{
+ t_sonogram *x = (t_sonogram *)z;
+
+ binbuf_addv(b, "ssiisiii", gensym("#X"),gensym("obj"),
+ (t_int)x->x_xpos, (t_int)x->x_ypos,
+ gensym("sonogram~"), x->x_size, x->x_graphic, x->x_phaso );
+ binbuf_addv(b, ";");
+}
+
+static void sonogram_select(t_gobj *z, t_glist *glist, int selected)
+{
+ t_sonogram *x = (t_sonogram *)z;
+
+ x->x_selected = selected;
+ sonogram_draw_select( x, glist );
+}
+
+static void sonogram_vis(t_gobj *z, t_glist *glist, int vis)
+{
+ t_sonogram *x = (t_sonogram *)z;
+ t_rtext *y;
+
+ if (vis)
+ {
+ sonogram_draw_new( x, glist );
+ }
+ else
+ {
+ // erase all points
+ sonogram_draw_delete( x, glist );
+ }
+}
+
+static void sonogram_delete(t_gobj *z, t_glist *glist)
+{
+ canvas_deletelinesfor( glist_getcanvas(glist), (t_text *)z);
+}
+
+static void sonogram_displace(t_gobj *z, t_glist *glist, int dx, int dy)
+{
+ t_sonogram *x = (t_sonogram *)z;
+ int xold = x->x_xpos;
+ int yold = x->x_ypos;
+
+ x->x_xpos += dx;
+ x->x_ypos += dy;
+
+ if ( ( x->x_xpos != xold ) || ( x->x_ypos != yold ) )
+ {
+ sonogram_draw_move( x, glist );
+ }
+
+}
+
+static void sonogram_modify_point( t_sonogram* x, t_int sample, t_int frequency, t_int alted )
+{
+ if ( alted )
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) = 0;
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) = 0;
+ }
+ else
+ {
+ if ( x->x_enhancemode )
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) *= x->x_modstep;
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) *= x->x_modstep;
+ }
+ else
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) += x->x_modstep;
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) += x->x_modstep;
+ }
+ }
+}
+
+static void sonogram_modify_point_phase( t_sonogram* x, t_int sample, t_int frequency, t_int alted )
+{
+ t_float fspectrum;
+ t_float fphase;
+
+ fspectrum =
+ sqrt( pow( *(x->x_rdata+sample*x->x_blocksize+frequency), 2) +
+ pow( *(x->x_idata+sample*x->x_blocksize+frequency), 2) );
+ fphase = atan2( *(x->x_idata+sample*x->x_blocksize+frequency),
+ *(x->x_rdata+sample*x->x_blocksize+frequency) );
+ if ( alted==4 )
+ {
+ // setting phase to 0
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) = fspectrum;
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) = 0;
+ }
+ else
+ {
+ if ( x->x_enhancemode )
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) = fspectrum*cos( fphase*x->x_modstep );
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) = fspectrum*sin( fphase*x->x_modstep );
+ }
+ else
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) = fspectrum*cos( fphase+x->x_modstep );
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) = fspectrum*sin( fphase+x->x_modstep );
+ }
+ }
+}
+
+static void sonogram_motion(t_sonogram *x, t_floatarg dx, t_floatarg dy)
+{
+ int fdraw=0, sdraw=0;
+
+ // post( "sonogram_motion @ [%d,%d] dx=%f dy=%f alt=%d", x->x_xdraw, x->x_ydraw, dx, dy, x->x_alted );
+ if ( ( x->x_shifted || (x->x_alted==4) ) )
+ {
+ if ( (x->x_xdraw+dx) >= x->x_xpos &&
+ (x->x_xdraw+dx) <= x->x_xpos+x->x_size*x->x_zoom ) {
+ x->x_xdraw += dx;
+ }
+ if ( (x->x_ydraw+dy) >= x->x_ypos &&
+ (x->x_ydraw+dy) <= x->x_ypos+x->x_blocksize*x->x_zoom ) {
+ x->x_ydraw += dy;
+ }
+ sdraw=(x->x_xdraw-x->x_xpos)/x->x_zoom;
+ if ( x->x_ydraw <= x->x_ypos+x->x_blocksize/2*x->x_zoom )
+ {
+ fdraw=(x->x_ypos-x->x_ydraw)/x->x_zoom+x->x_blocksize/2;
+ // post( "modify point @ [%d, %d] alted=%d", sdraw, fdraw, x->x_alted );
+ sonogram_modify_point( x, sdraw, fdraw, x->x_alted );
+ }
+ if ( x->x_ydraw >= x->x_ypos+x->x_blocksize/2*x->x_zoom+1 )
+ {
+ fdraw=(x->x_ypos+x->x_blocksize*x->x_zoom/2+1-x->x_ydraw)/x->x_zoom+x->x_blocksize/2;
+ // post( "modify phase @ [%d, %d]", sdraw, fdraw );
+ sonogram_modify_point_phase( x, sdraw, fdraw, x->x_alted );
+ }
+ sonogram_update_point( x, x->x_glist, sdraw, fdraw );
+ }
+ else
+ {
+ if ( (x->x_xendcapture+dx) >= x->x_xpos &&
+ (x->x_xendcapture+dx) <= x->x_xpos+x->x_size*x->x_zoom ) {
+ x->x_xendcapture += dx;
+ }
+ if ( (x->x_yendcapture+dy) >= x->x_ypos &&
+ (x->x_yendcapture+dy) <= x->x_ypos+x->x_blocksize*x->x_zoom ) {
+ x->x_yendcapture += dy;
+ }
+ SYS_VGUI3( ".x%x.c delete %xCAPTURE\n", glist_getcanvas( x->x_glist ), x );
+ SYS_VGUI7( ".x%x.c create rectangle %d %d %d %d -outline #0000FF -tags %xCAPTURE\n",
+ glist_getcanvas( x->x_glist ), x->x_xstartcapture,
+ x->x_ystartcapture, x->x_xendcapture, x->x_yendcapture, x );
+ }
+}
+
+static int sonogram_click(t_gobj *z, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_sonogram* x = (t_sonogram *)z;
+ int si,fi;
+
+ // post( "sonogram_click : x=%d y=%d doit=%d alt=%d, shift=%d", xpix, ypix, doit, alt, shift );
+ if ( x->x_aftermousedown == 1 && doit == 0)
+ {
+ x->x_aftermousedown = 1;
+ }
+ else
+ {
+ x->x_aftermousedown = 0;
+ }
+ if ( doit )
+ {
+ x->x_xdraw = xpix;
+ x->x_ydraw = ypix;
+ x->x_shifted = shift;
+ x->x_alted = alt;
+ // activate motion callback
+ glist_grab( glist, &x->x_obj.te_g, (t_glistmotionfn)sonogram_motion,
+ 0, xpix, ypix );
+
+ if ( shift && alt && (x->x_xstartcapture != x->x_xendcapture ) )
+ {
+ sonogram_paste(x);
+ sonogram_paste_phase(x);
+ }
+ else if ( shift && (x->x_xstartcapture != x->x_xendcapture ) )
+ {
+ // add or multiply modstep
+ if ( x->x_xstartcapture > x->x_xendcapture ) {
+ fi = x->x_xstartcapture;
+ x->x_xstartcapture = x->x_xendcapture;
+ x->x_xendcapture = fi;
+ }
+ if ( x->x_ystartcapture > x->x_yendcapture ) {
+ fi = x->x_ystartcapture;
+ x->x_ystartcapture = x->x_yendcapture;
+ x->x_yendcapture = fi;
+ }
+ for ( si=(x->x_xstartcapture-x->x_xpos)/x->x_zoom;
+ si<=(x->x_xendcapture-x->x_xpos)/x->x_zoom; si++) {
+ for ( fi=(x->x_ypos-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ fi<=(x->x_ypos-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2; fi++) {
+ sonogram_modify_point( x, si, fi, alt );
+ }
+ for ( fi=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ fi<=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2; fi++) {
+ sonogram_modify_point_phase( x, si, fi, alt );
+ }
+ }
+ // post( "modified y from %d to %d", (x->x_ypos-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2,
+ // (x->x_ypos-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2 );
+ sonogram_update_part(x, x->x_glist, (x->x_xstartcapture-x->x_xpos)/x->x_zoom,
+ (x->x_xendcapture-x->x_xpos)/x->x_zoom, 0, 1, 1);
+ }
+ else if ( (alt==4) && (x->x_xstartcapture != x->x_xendcapture ) )
+ {
+ // clean up area
+ if ( x->x_xstartcapture > x->x_xendcapture ) {
+ fi = x->x_xstartcapture;
+ x->x_xstartcapture = x->x_xendcapture;
+ x->x_xendcapture = fi;
+ }
+ if ( x->x_ystartcapture > x->x_yendcapture ) {
+ fi = x->x_ystartcapture;
+ x->x_ystartcapture = x->x_yendcapture;
+ x->x_yendcapture = fi;
+ }
+ for ( si=(x->x_xstartcapture-x->x_xpos)/x->x_zoom;
+ si<=(x->x_xendcapture-x->x_xpos)/x->x_zoom; si++) {
+ for ( fi=(x->x_ypos-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ fi<=(x->x_ypos-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2; fi++) {
+ sonogram_modify_point( x, si, fi, alt );
+ }
+ for ( fi=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ fi<=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2; fi++) {
+ sonogram_modify_point_phase( x, si, fi, alt );
+ }
+ }
+ sonogram_update_part(x, x->x_glist, (x->x_xstartcapture-x->x_xpos)/x->x_zoom,
+ (x->x_xendcapture-x->x_xpos)/x->x_zoom, 0, 1, 1);
+ }
+ // start a new capture
+ SYS_VGUI3( ".x%x.c delete %xCAPTURE\n", glist_getcanvas( x->x_glist ), x );
+ x->x_xstartcapture = xpix;
+ x->x_ystartcapture = ypix;
+ x->x_xendcapture = xpix;
+ x->x_yendcapture = ypix;
+ }
+ else
+ {
+ // nothing
+ }
+ x->x_aftermousedown = doit;
+ return (1);
+}
+
+ /* clean up */
+static void sonogram_free(t_sonogram *x)
+{
+ if ( x->x_rdata != NULL ) {
+ freebytes(x->x_rdata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_rdata = NULL;
+ }
+ if ( x->x_idata != NULL ) {
+ freebytes(x->x_idata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_idata = NULL;
+ }
+ if ( x->x_rudata != NULL ) {
+ freebytes(x->x_rudata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_rdata = NULL;
+ }
+ if ( x->x_iudata != NULL ) {
+ freebytes(x->x_iudata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_idata = NULL;
+ }
+ if ( x->x_gifdata != NULL ) {
+ freebytes(x->x_gifdata, (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ post( "Freed %d bytes", (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ x->x_gifdata = NULL;
+ }
+ if ( x->x_guicommand != NULL ) {
+ freebytes(x->x_guicommand, 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ post( "Freed %d bytes", 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ x->x_guicommand = NULL;
+ }
+}
+
+ /* allocate tables for storing ffts */
+static t_int sonogram_allocate(t_sonogram *x)
+{
+ t_int fi;
+
+ if ( !(x->x_rdata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_idata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_multfreq = getbytes( x->x_blocksize*sizeof(t_int) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_blocksize*sizeof(t_int) );
+ }
+ for ( fi=0; fi<x->x_blocksize; fi++ )
+ {
+ *(x->x_multfreq+fi)=1;
+ }
+ // no undo is available
+ x->x_uxs = x->x_uxe = x->x_uys = x->x_uye = -1;
+ if ( !(x->x_rudata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_iudata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !( x->x_gifdata = ( char* ) getbytes( (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ }
+ if ( !( x->x_guicommand = ( char* ) getbytes( 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ }
+
+ return 0;
+}
+
+ /* records or playback the sonogram */
+static t_int *sonogram_perform(t_int *w)
+{
+ t_float *rin = (t_float *)(w[1]);
+ t_float *iin = (t_float *)(w[2]);
+ t_float *rout = (t_float *)(w[3]);
+ t_float *iout = (t_float *)(w[4]);
+ t_float fspectrum = 0.0;
+ t_float fphase = 0.0;
+ t_int is;
+ t_int n = (int)(w[5]); /* number of samples */
+ t_sonogram *x = (t_sonogram *)(w[6]);
+ t_int bi;
+
+ // reallocate tables if blocksize has been changed
+ if ( n != x->x_blocksize && x->x_updatechild == 0 ) {
+ post( "sonogram~ : reallocating tables" );
+ // erase all points
+ sonogram_free(x);
+ x->x_blocksize = n;
+ sonogram_allocate(x);
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, !x->x_empty, 0, 0);
+ canvas_fixlinesfor( glist_getcanvas(x->x_glist), (t_text*)x );
+ }
+
+ bi = 0;
+ while (bi<n)
+ {
+ // eventually records input
+ if ( x->x_record) {
+ *(x->x_rdata+(x->x_writepos*x->x_blocksize)+bi)=(*(rin))*(*(x->x_multfreq+bi));
+ *(x->x_idata+(x->x_writepos*x->x_blocksize)+bi)=(*(iin))*(*(x->x_multfreq+bi));
+ }
+ // set outputs
+ *rout = 0.0;
+ *iout = 0.0;
+ if ( x->x_play) {
+ is=0;
+ fspectrum =
+ sqrt( pow( *(x->x_rdata+(((int)x->x_readpos+is)*x->x_blocksize)+bi), 2) +
+ pow( *(x->x_idata+(((int)x->x_readpos+is)*x->x_blocksize)+bi), 2) );
+ fphase = atan2( *(x->x_idata+(((int)x->x_readpos+is)*x->x_blocksize)+bi),
+ *(x->x_rdata+(((int)x->x_readpos+is)*x->x_blocksize)+bi) );
+ fphase += (x->x_phase/180.0)*(M_PI);
+ *rout += fspectrum*cos( fphase );
+ *iout += fspectrum*sin( fphase );
+ }
+ rout++;iout++;
+ rin++;iin++;
+ bi++;
+
+ }
+ // reset playing position until next play
+ if ( x->x_play ) {
+ x->x_readpos+=x->x_readspeed;
+ // post( "xreadpos : %f (added %f)", x->x_readpos, x->x_readspeed );
+ if ( x->x_readpos >= (x->x_readend*x->x_size)/100 ) {
+ x->x_play=0;
+ x->x_readpos=(x->x_readstart*x->x_size)/100;
+ // post( "sonogram~ : stopped playing (readpos=%d)", x->x_readpos );
+ outlet_bang(x->x_end);
+ }
+ }
+ // reset recording position until next record
+ if ( x->x_record ) {
+ x->x_writepos++;
+ if ( x->x_writepos >= x->x_size ) {
+ x->x_record=0;
+ x->x_writepos=0;
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, 0, 1, 0);
+ outlet_bang(x->x_recend);
+ if ( x->x_empty ) x->x_empty = 0;
+ // post( "sonogram~ : stopped recording" );
+ }
+ }
+ // post( "sonogram~ : read : %f:%d : write: %d:%d", x->x_readpos, x->x_play, x->x_writepos, x->x_record );
+ return (w+7);
+}
+
+static void sonogram_dsp(t_sonogram *x, t_signal **sp)
+{
+ dsp_add(sonogram_perform, 6, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n, x);
+}
+
+ /* record the sonogram */
+static void sonogram_record(t_sonogram *x)
+{
+ x->x_record=1;
+ x->x_writepos=0;
+ // post( "sonogram~ : recording on" );
+}
+
+ /* play the sonogram */
+static void sonogram_play(t_sonogram *x)
+{
+ x->x_play=1;
+ x->x_readpos=(x->x_readstart*x->x_size)/100;
+ // post( "sonogram~ : playing on" );
+}
+
+ /* setting the starting point for reading ( in percent ) */
+static void sonogram_readstart(t_sonogram *x, t_floatarg fstart)
+{
+ t_float startpoint = fstart;
+
+ if (startpoint < 0) startpoint = 0;
+ if (startpoint > 100) startpoint = 100;
+ if ( startpoint > x->x_readend ) {
+ x->x_readstart = x->x_readend;
+ post( "sonogram~ : warning : range for reading is null" );
+ } else {
+ x->x_readstart=startpoint;
+ }
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete line %xREADSTART\n",
+ glist_getcanvas( x->x_glist ), x);
+ SYS_VGUI7( ".x%x.c create line %d %d %d %d -fill #FF0000 -tags %xREADSTART -width 3\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+(x->x_readstart*(x->x_size)/100 ),
+ x->x_ypos, x->x_xpos+(x->x_readstart*(x->x_size)/100 ),
+ x->x_ypos+x->x_blocksize*x->x_zoom, x );
+ }
+}
+
+ /* setting the starting point for modification ( in percent ) */
+static void sonogram_modstart(t_sonogram *x, t_floatarg fstart)
+{
+ t_float startpoint = fstart;
+
+ if (startpoint < 0) startpoint = 0;
+ if (startpoint > 100) startpoint = 100;
+ if ( startpoint > x->x_modend ) {
+ x->x_modstart = x->x_modend;
+ post( "sonogram~ : warning : range for modifications is null" );
+ } else {
+ x->x_modstart=startpoint;
+ }
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete line %xMODSTART\n",
+ glist_getcanvas( x->x_glist ), x);
+ SYS_VGUI7( ".x%x.c create line %d %d %d %d -fill #11E834 -tags %xMODSTART -width 3\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+(x->x_modstart*(x->x_size)/100 ),
+ x->x_ypos, x->x_xpos+(x->x_modstart*(x->x_size)/100 ),
+ x->x_ypos+x->x_blocksize*x->x_zoom, x );
+ }
+}
+
+ /* setting the modification step for graphical mode */
+static void sonogram_modstep(t_sonogram *x, t_floatarg fmodstep)
+{
+ if ( x->x_graphic )
+ {
+ x->x_modstep = fmodstep;
+ }
+}
+
+ /* setting enhance mode */
+static void sonogram_enhancemode(t_sonogram *x, t_floatarg fenhancemode)
+{
+ if ( x->x_graphic )
+ {
+ x->x_enhancemode = fenhancemode;
+ }
+}
+
+ /* setting the ending point for reading ( in percent ) */
+static void sonogram_readend(t_sonogram *x, t_floatarg fend)
+{
+ t_float endpoint = fend;
+
+ if (endpoint < 0) endpoint = 0;
+ if (endpoint > 100) endpoint = 100;
+ if ( endpoint < x->x_readstart ) {
+ x->x_readend = x->x_readstart;
+ post( "sonogram~ : warning : range for reading is null" );
+ } else {
+ x->x_readend=endpoint;
+ }
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete line %xREADEND\n",
+ glist_getcanvas( x->x_glist ), x);
+ SYS_VGUI7( ".x%x.c create line %d %d %d %d -fill #FF0000 -tags %xREADEND -width 3\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+(x->x_readend*(x->x_size)/100 ),
+ x->x_ypos, x->x_xpos+(x->x_readend*(x->x_size)/100 ),
+ x->x_ypos+x->x_blocksize*x->x_zoom, x );
+ }
+}
+
+ /* setting the ending point for modification ( in percent ) */
+static void sonogram_modend(t_sonogram *x, t_floatarg fend)
+{
+ t_float endpoint = fend;
+
+ if (endpoint < 0) endpoint = 0;
+ if (endpoint > 100) endpoint = 100;
+ if ( endpoint < x->x_modstart ) {
+ x->x_modend = x->x_modstart;
+ post( "sonogram~ : warning : range for modifications is null" );
+ } else {
+ x->x_modend=endpoint;
+ }
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete line %xMODEND\n",
+ glist_getcanvas( x->x_glist ), x);
+ SYS_VGUI7( ".x%x.c create line %d %d %d %d -fill #11E834 -tags %xMODEND -width 3\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+(x->x_modend*(x->x_size)/100 ),
+ x->x_ypos, x->x_xpos+(x->x_modend*(x->x_size)/100 ),
+ x->x_ypos+x->x_blocksize*x->x_zoom, x );
+ }
+}
+
+ /* sets the reading speed */
+static void sonogram_readspeed(t_sonogram *x, t_floatarg freadspeed)
+{
+ if (freadspeed <= 0 ) {
+ post( "sonogram~ : wrong readspeed argument" );
+ return;
+ }
+ x->x_readspeed=freadspeed;
+}
+
+ /* enhance frequencies */
+static void sonogram_enhance(t_sonogram *x, t_floatarg fstartfreq, t_floatarg fendfreq, t_floatarg fenhance, t_floatarg fnoupdate )
+{
+ t_int samplestart, sampleend, si, fi=0, ffi=0;
+ t_float oldenergy;
+
+ if (fstartfreq < 0 || fendfreq < 0 ||
+ fstartfreq > x->x_blocksize || fendfreq > x->x_blocksize ||
+ fstartfreq > fendfreq ) {
+ post( "sonogram~ : error : wrong frequencies range" );
+ return;
+ }
+ if ( fenhance < 0 ) {
+ post( "sonogram~ : error : wrong multiplicating factor" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ // post("enhancing portion [%d,%d]", samplestart, sampleend );
+ for ( si=samplestart; si<=sampleend; si++ ) {
+ for ( fi=(int)fstartfreq; fi<=(int)fendfreq; fi++ ) {
+ *(x->x_multfreq+fi) = fenhance;
+ if ( (fi != 0) && (fi != x->x_blocksize/2-1) )
+ {
+ /* multiply both r*sin(a) and r*cos(a) to mutiply r */
+ *(x->x_rdata+(si*x->x_blocksize)+fi) *= fenhance;
+ *(x->x_idata+(si*x->x_blocksize)+fi) *= fenhance;
+ }
+ }
+ }
+ // post( "sonogram~ : enhanced %d,%d", fi, ffi );
+ if ( !(int)fnoupdate )
+ {
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+ }
+}
+
+ /* add a constant to frequencies */
+static void sonogram_add(t_sonogram *x, t_floatarg fstartfreq, t_floatarg fendfreq, t_floatarg fadd)
+{
+ t_int samplestart, sampleend, si, fi;
+ t_float oldenergy;
+
+ if (fstartfreq < 0 || fendfreq < 0 ||
+ fstartfreq > x->x_blocksize || fendfreq > x->x_blocksize ||
+ fstartfreq > fendfreq ) {
+ post( "sonogram~ : error : wrong frequencies range" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ // post("enhancing portion [%d,%d]", samplestart, sampleend );
+ for ( si=samplestart; si<=sampleend; si++ ) {
+ for ( fi=(int)fstartfreq; fi<=(int)fendfreq; fi++ ) {
+ /* multiply both r*sin(a) and r*cos(a) to mutiply r */
+ *(x->x_rdata+(si*x->x_blocksize)+fi) += fadd;
+ *(x->x_idata+(si*x->x_blocksize)+fi) += fadd;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* resize sonogram */
+static void sonogram_resize(t_sonogram *x, t_floatarg fnewsize )
+{
+ if (fnewsize <= 0) {
+ post( "sonogram~ : error : wrong size" );
+ return;
+ }
+ if (x->x_updatechild > 0) {
+ post( "sonogram~ : can't resize now, an update is pending." );
+ return;
+ }
+ post( "sonogram~ : reallocating tables" );
+ x->x_record = 0;
+ x->x_play = 0;
+ sonogram_free(x);
+ x->x_size = fnewsize;
+ sonogram_allocate(x);
+ // erase all points, as data is zero no drawing is needed
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, 0, 0, 0);
+}
+
+ /* set zoom factor */
+static void sonogram_zoom(t_sonogram *x, t_floatarg fzoom )
+{
+ post( "sonogram~: warning : zoom and big block factors might lead to a crash" );
+ if (fzoom < 1) {
+ post( "sonogram~ : error : wrong zoom factor" );
+ return;
+ }
+ if ( x->x_gifdata != NULL ) {
+ freebytes(x->x_gifdata, (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ post( "Freed %d bytes", (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ x->x_gifdata = NULL;
+ }
+ if ( x->x_guicommand != NULL ) {
+ freebytes(x->x_guicommand, 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ post( "Freed %d bytes", 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ x->x_guicommand = NULL;
+ }
+ x->x_zoom = (int)fzoom;
+ if ( !( x->x_gifdata = ( char* ) getbytes( (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return;
+ } else {
+ post( "sonogram~ : allocated %d bytes", (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ }
+ if ( !( x->x_guicommand = ( char* ) getbytes( 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return;
+ } else {
+ post( "sonogram~ : allocated %d bytes", 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ }
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, !x->x_empty, !x->x_empty, 0);
+ canvas_fixlinesfor( glist_getcanvas( x->x_glist ), (t_text*)x );
+}
+
+ /* refresh data */
+static void sonogram_refresh(t_sonogram *x)
+{
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, 0, 1, 1);
+}
+
+ /* flip frequencies */
+static void sonogram_flipfreqs(t_sonogram *x)
+{
+ t_int samplestart, sampleend, si, fi;
+ t_float fvalue;
+ t_int ioperon;
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ ioperon=x->x_blocksize/2;
+ for ( si=samplestart; si<=sampleend; si++ ) {
+ for ( fi=0; fi<=ioperon/2; fi++ ) {
+ fvalue = *(x->x_rdata+(si*x->x_blocksize)+fi);
+ *(x->x_rdata+(si*x->x_blocksize)+fi) = *(x->x_rdata+(si*x->x_blocksize)+(ioperon-fi-1));
+ *(x->x_rdata+(si*x->x_blocksize)+(ioperon-fi-1)) = fvalue;
+ fvalue = *(x->x_idata+(si*x->x_blocksize)+fi);
+ *(x->x_idata+(si*x->x_blocksize)+fi) = *(x->x_idata+(si*x->x_blocksize)+(ioperon-fi-1));
+ *(x->x_idata+(si*x->x_blocksize)+(ioperon-fi-1)) = fvalue;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* flip blocks */
+static void sonogram_flipblocks(t_sonogram *x)
+{
+ t_int samplestart, sampleend, middlesample, fi, si;
+ t_float fvalue;
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ middlesample = ( sampleend+samplestart+1 ) / 2;
+ for ( si=samplestart; si<=middlesample; si++ ) {
+ for ( fi=0; fi<x->x_blocksize; fi++ ) {
+ fvalue = *(x->x_rdata+((si)*x->x_blocksize)+fi);
+ *(x->x_rdata+((si)*x->x_blocksize)+fi) = *(x->x_rdata+((sampleend+samplestart-si)*x->x_blocksize)+fi);
+ *(x->x_rdata+((sampleend+samplestart-si)*x->x_blocksize)+fi) = fvalue;
+ fvalue = *(x->x_idata+((si)*x->x_blocksize)+fi);
+ *(x->x_idata+((si)*x->x_blocksize)+fi) = *(x->x_idata+((sampleend+samplestart-si)*x->x_blocksize)+fi);
+ *(x->x_idata+((sampleend+samplestart-si)*x->x_blocksize)+fi) = fvalue;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* undo if available */
+static void sonogram_undo(t_sonogram *x)
+{
+ t_int si,fi;
+
+ if ( x->x_uxs == -1 )
+ {
+ post( "sonogram~ : nothing to undo, man" );
+ return;
+ }
+
+ post( "sonogram~ : restoring region [%d,%d,%d,%d]", x->x_uxs, x->x_uys, x->x_uxe, x->x_uye );
+ for ( si=x->x_uxs; si<=x->x_uxe; si++ ) {
+ for ( fi=x->x_uys; fi<=x->x_uye; fi++ ) {
+ *(x->x_rdata+((si)*x->x_blocksize)+fi) = *(x->x_rudata+(si-x->x_uxs)*x->x_blocksize+(fi-x->x_uys));
+ *(x->x_idata+((si)*x->x_blocksize)+fi) = *(x->x_iudata+(si-x->x_uxs)*x->x_blocksize+(fi-x->x_uys));
+ }
+ }
+ sonogram_update_part(x, x->x_glist, x->x_uxs, x->x_uxe, 0, 1, 1);
+}
+
+ /* zswap exchanges real and imaginery part */
+static void sonogram_zswap(t_sonogram *x)
+{
+ t_int samplestart, sampleend, fi, si;
+ t_float fvalue;
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ for ( si=samplestart; si<=sampleend; si++ ) {
+ for ( fi=0; fi<x->x_blocksize; fi++ ) {
+ fvalue = *(x->x_rdata+(si*x->x_blocksize)+fi);
+ *(x->x_rdata+(si*x->x_blocksize)+fi) = *(x->x_idata+(si*x->x_blocksize)+fi);
+ *(x->x_idata+(si*x->x_blocksize)+fi) = fvalue;
+ }
+ }
+}
+
+ /* swap points */
+static void sonogram_swappoints(t_sonogram *x, t_floatarg fnbpoints)
+{
+ t_int samplestart, sampleend, sp;
+ t_float s1, s2, f1, f2;
+ t_float fvalue;
+
+ if (fnbpoints <= 0) {
+ post( "sonogram~ : error : bad number of points" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=0; sp<fnbpoints; sp++ ) {
+ s1 = samplestart + (random()%(sampleend-samplestart));
+ s2 = samplestart + (random()%(sampleend-samplestart));
+ f1 = random()%( x->x_blocksize/2-1 );
+ f2 = random()%( x->x_blocksize/2-1 );
+ fvalue = *(x->x_rdata+((int)s1*x->x_blocksize)+(int)f1);
+ *(x->x_rdata+((int)s1*x->x_blocksize)+(int)f1) = *(x->x_rdata+((int)s2*x->x_blocksize)+(int)f2);
+ *(x->x_rdata+((int)s2*x->x_blocksize)+(int)f2) = fvalue;
+ fvalue = *(x->x_idata+((int)s1*x->x_blocksize)+(int)f1);
+ *(x->x_idata+((int)s1*x->x_blocksize)+(int)f1) = *(x->x_idata+((int)s2*x->x_blocksize)+(int)f2);
+ *(x->x_idata+((int)s2*x->x_blocksize)+(int)f2) = fvalue;
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* average blocks according to a factor */
+static void sonogram_average(t_sonogram *x, t_floatarg fnbblocks)
+{
+ t_int samplestart, sampleend, fi, si, ssi;
+ t_float fraverage, fiaverage;
+
+ if (fnbblocks < 1) {
+ post( "sonogram~ : error : bad average factor" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ fraverage=fiaverage=0.0;
+ for ( fi=0; fi<x->x_blocksize; fi++ ) {
+ for ( si=samplestart; si<=sampleend-fnbblocks; si+=fnbblocks ) {
+ fraverage=fiaverage=0.0;
+ for ( ssi=0; ssi<fnbblocks; ssi++ ) {
+ fraverage += *(x->x_rdata+((int)(si+ssi)*x->x_blocksize)+fi);
+ fiaverage += *(x->x_idata+((int)(si+ssi)*x->x_blocksize)+fi);
+ }
+ fraverage /= fnbblocks;
+ fiaverage /= fnbblocks;
+ for ( ssi=0; ssi<fnbblocks; ssi++ ) {
+ *(x->x_rdata+((int)(si+ssi)*x->x_blocksize)+fi)=fraverage;
+ *(x->x_idata+((int)(si+ssi)*x->x_blocksize)+fi)=fiaverage;
+ }
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* go up by the given number */
+static void sonogram_goup(t_sonogram *x, t_floatarg fgoup)
+{
+ t_int samplestart, sampleend, sp, sf;
+
+ if (fgoup <= 0 || fgoup > x->x_blocksize/2) {
+ post( "sonogram~ : error : wrong offset in goup function" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+ for (sf=(x->x_blocksize/2)-fgoup-1; sf>=0; sf-- ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(sf+(int)fgoup)) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+sf);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(sf+(int)fgoup)) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+sf);
+
+ }
+ for (sf=0; sf<fgoup; sf++ ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)sf) = 0.0;
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)sf) = 0.0;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* roll up by the given number */
+static void sonogram_roll(t_sonogram *x, t_floatarg froll)
+{
+ t_int samplestart, sampleend, sp, sf;
+ t_float *fprvalues;
+ t_float *fpivalues;
+
+ if (froll <= 0 || froll > x->x_blocksize/2) {
+ post( "sonogram~ : error : wrong offset in roll function" );
+ return;
+ }
+ fprvalues = (t_float*)getbytes( ((int)froll)*sizeof( float ) );
+ if ( !fprvalues ) {
+ post( "sonogram~ : error : could not allocate %d bytes", ((int)froll)*sizeof(float) );
+ return;
+ }
+ fpivalues = (t_float*)getbytes( ((int)froll)*sizeof( float ) );
+ if ( !fpivalues ) {
+ post( "sonogram~ : error : could not allocate %d bytes", ((int)froll)*sizeof(float) );
+ return;
+ }
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+
+ // saving values
+ for (sf=0; sf<froll; sf++ ) {
+ *(fprvalues+sf) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(x->x_blocksize/2-(int)froll+sf));
+ *(fpivalues+sf) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+(x->x_blocksize/2-(int)froll+sf));
+ }
+ for (sf=(x->x_blocksize/2)-froll-1; sf>=0; sf-- ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(sf+(int)froll)) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+sf);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(sf+(int)froll)) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+sf);
+ }
+ for (sf=0; sf<froll; sf++ ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)sf) = *(fprvalues+sf);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)sf) = *(fpivalues+sf);
+ }
+ }
+ freebytes( fprvalues, (int)froll*sizeof(float) );
+ freebytes( fpivalues, (int)froll*sizeof(float) );
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* suppress point below the threshold */
+static void sonogram_threshold(t_sonogram *x, t_floatarg fthreshold)
+{
+ t_int samplestart, sampleend, sp, sf;
+ t_float fspectrum;
+
+ if (fthreshold <= 0) {
+ post( "sonogram~ : error : wrong threshold" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+ for (sf=0; sf<=(x->x_blocksize/2)-1; sf++ ) {
+ fspectrum = sqrt( pow( *(x->x_rdata+sp*x->x_blocksize+sf), 2) +
+ pow( *(x->x_idata+sp*x->x_blocksize+sf), 2) );
+ if ( fspectrum < fthreshold )
+ {
+ *(x->x_rdata+sp*x->x_blocksize+sf) = 0.0;
+ *(x->x_idata+sp*x->x_blocksize+sf) = 0.0;
+ }
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* change the phase */
+static void sonogram_phase(t_sonogram *x, t_floatarg fincphase)
+{
+ if (fincphase < 0 || fincphase > 90) {
+ post( "sonogram~ : error : wrong phase in phase function : out of [0,90]" );
+ return;
+ }
+ x->x_phase = fincphase;
+}
+
+ /* go down by the given number */
+static void sonogram_godown(t_sonogram *x, t_floatarg fgodown)
+{
+ t_int samplestart, sampleend, sp, sf;
+
+ if (fgodown <= 0 || fgodown > x->x_blocksize/2) {
+ post( "sonogram~ : error : wrong offset in godown function" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+ for (sf=0; sf<=(x->x_blocksize/2)-fgodown-1; sf++ ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+sf) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(sf+(int)fgodown));
+ *(x->x_idata+((int)sp*x->x_blocksize)+sf) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+(sf+(int)fgodown));
+ }
+ for (sf=(x->x_blocksize/2)-fgodown; sf<(x->x_blocksize/2); sf++ ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)sf) = 0.0;
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)sf) = 0.0;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* swap blocks */
+static void sonogram_swapblocks(t_sonogram *x, t_floatarg fperstart, t_floatarg fperend, t_floatarg fpersize)
+{
+ t_int samplestart, samplestartb, samplesize, sp, sf;
+ t_int iperstart, iperend, ipersize;
+ t_float s1, s2;
+ t_float fvalue;
+
+ iperstart = fperstart;
+ iperend = fperend;
+ ipersize = fpersize;
+
+ if (iperstart < 0 || iperstart > iperend ||
+ iperend <= 0 || iperend+ipersize > 100 ||
+ ipersize < 0 || fpersize > 100 ) {
+ post( "sonogram~ : error : wrong interval [%d%%, %d%%] <-> [%d%%, %d%%]",
+ iperstart, iperstart+ipersize, iperend, iperend+ipersize );
+ return;
+ }
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ samplestartb=(x->x_modend*(x->x_size-1))/100;
+ samplesize=((samplestartb-samplestart)*ipersize)/100;
+ samplestart=samplestart+((samplestartb-samplestart)*iperstart)/100;
+ samplestartb=samplestart+((samplestartb-samplestart)*iperend)/100;
+
+ post( "swap blocks [%d,%d] and [%d,%d]", samplestart, samplestart+samplesize, samplestartb, samplestartb+samplesize );
+
+ for ( sp=samplesize; sp>=0; sp-- ) {
+ for ( sf=0; sf<x->x_blocksize; sf++) {
+ fvalue = *(x->x_rdata+((int)(samplestart+sp)*x->x_blocksize)+sf);
+ *(x->x_rdata+((int)(samplestart+sp)*x->x_blocksize)+sf) = *(x->x_rdata+((int)(samplestartb+sp)*x->x_blocksize)+sf);
+ *(x->x_rdata+((int)(samplestartb+sp)*x->x_blocksize)+sf) = fvalue;
+ fvalue = *(x->x_idata+((int)(samplestart+sp)*x->x_blocksize)+sf);
+ *(x->x_idata+((int)(samplestart+sp)*x->x_blocksize)+sf) = *(x->x_idata+((int)(samplestartb+sp)*x->x_blocksize)+sf);
+ *(x->x_idata+((int)(samplestartb+sp)*x->x_blocksize)+sf) = fvalue;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, 0, 1, 1);
+}
+
+ /* swap frequencies */
+static void sonogram_swapfreqs(t_sonogram *x, t_floatarg ffirstfreq, t_floatarg fsecondfreq)
+{
+ t_int samplestart, sampleend, sp;
+ t_float fvalue;
+
+ if (ffirstfreq < 0 || fsecondfreq <0) {
+ post( "sonogram~ : error : wrong frequencies" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+ fvalue = *(x->x_rdata+((int)sp*x->x_blocksize)+(int)ffirstfreq);
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)ffirstfreq) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)fsecondfreq);
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)fsecondfreq) = fvalue;
+ fvalue = *(x->x_idata+((int)sp*x->x_blocksize)+(int)ffirstfreq);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)ffirstfreq) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)fsecondfreq);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)fsecondfreq) = fvalue;
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+static void *sonogram_new(t_floatarg fsize, t_floatarg fgraphic, t_floatarg fphaso)
+{
+ t_sonogram *x = (t_sonogram *)pd_new(sonogram_class);
+ outlet_new(&x->x_obj, &s_signal);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_recend = outlet_new(&x->x_obj, &s_bang );
+ x->x_end = outlet_new(&x->x_obj, &s_bang );
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("readstart"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("readend"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("modstart"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("modend"));
+
+ if ( fsize <= 0 || ( fgraphic != 0 && fgraphic != 1 ) || ( fphaso != 0 && fphaso != 1 ) ) {
+ error( "sonogram~ : missing or negative creation arguments" );
+ return NULL;
+ }
+
+ // activate graphical callbacks
+ if ( fgraphic != 0 )
+ {
+ class_setwidget(sonogram_class, &sonogram_widgetbehavior);
+ }
+ x->x_graphic = (int) fgraphic;
+ x->x_phaso = (int) fphaso;
+
+ x->x_size = fsize;
+ x->x_blocksize = sys_getblksize();
+ x->x_play = 0;
+ x->x_readspeed = 1.;
+ x->x_record = 0;
+ x->x_readpos = 0.;
+ x->x_writepos = 0;
+ x->x_modstart = 0;
+ x->x_readstart = 0;
+ x->x_modend = 100;
+ x->x_readend = 100;
+ x->x_rdata = NULL;
+ x->x_idata = NULL;
+ x->x_phase = 0.0;
+ x->x_empty = 1;
+ x->x_xpos = -1;
+ x->x_ypos = -1;
+ x->x_samplerate = sys_getsr();
+ /* graphic data */
+ x->x_selected = 0;
+ x->x_zoom = 1;
+ x->x_updatechild = 0;
+ x->x_modstep = 1.1;
+ x->x_enhancemode = 0;
+ x->x_glist = (t_glist*)canvas_getcurrent();
+
+ if ( sonogram_allocate(x) <0 ) {
+ return NULL;
+ } else {
+ return(x);
+ }
+
+}
+
+void sonogram_tilde_setup(void)
+{
+ post(sonogram_version);
+ sonogram_class = class_new(gensym("sonogram~"), (t_newmethod)sonogram_new, (t_method)sonogram_free,
+ sizeof(t_sonogram), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_sethelpsymbol( sonogram_class, gensym("help-sonogram~.pd") );
+
+ // set callbacks
+ sonogram_widgetbehavior.w_getrectfn = sonogram_getrect;
+ sonogram_widgetbehavior.w_displacefn = sonogram_displace;
+ sonogram_widgetbehavior.w_selectfn = sonogram_select;
+ sonogram_widgetbehavior.w_activatefn = NULL;
+ sonogram_widgetbehavior.w_deletefn = sonogram_delete;
+ sonogram_widgetbehavior.w_visfn = sonogram_vis;
+ sonogram_widgetbehavior.w_clickfn = sonogram_click;
+ sonogram_widgetbehavior.w_propertiesfn = NULL;
+ sonogram_widgetbehavior.w_savefn = sonogram_save;
+
+ CLASS_MAINSIGNALIN( sonogram_class, t_sonogram, x_f );
+ class_addmethod(sonogram_class, (t_method)sonogram_dsp, gensym("dsp"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_record, gensym("record"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_enhance, gensym("enhance"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_add, gensym("add"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_resize, gensym("resize"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_zoom, gensym("zoom"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_swappoints, gensym("swappoints"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_average, gensym("average"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_swapblocks, gensym("swapblocks"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_swapfreqs, gensym("swapfreqs"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_flipfreqs, gensym("flipfreqs"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_flipblocks, gensym("flipblocks"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_play, gensym("play"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_refresh, gensym("refresh"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_enhancemode, gensym("enhancemode"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_goup, gensym("goup"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_godown, gensym("godown"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_roll, gensym("roll"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_threshold, gensym("threshold"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_phase, gensym("phase"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_zswap, gensym("zswap"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_modstep, gensym("modstep"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_modstart, gensym("modstart"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_modend, gensym("modend"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_readstart, gensym("readstart"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_readend, gensym("readend"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_readspeed, gensym("readspeed"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_undo, gensym("undo"), A_NULL);
+}
diff --git a/sonogram~/sonogram~.c b/sonogram~/sonogram~.c
new file mode 100644
index 0000000..d16f6ca
--- /dev/null
+++ b/sonogram~/sonogram~.c
@@ -0,0 +1,2061 @@
+/*------------------------ sonogram~ ------------------------------------------ */
+/* */
+/* sonogram~ : lets you record, play back and modify a sonogram */
+/* constructor : sonogram <size> <graphical=0|1> <phasogram=0|1> */
+/* */
+/* Copyleft Yves Degoyon ( 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. */
+/* */
+/* "Living at night" */
+/* "Doesn't help for my complexion" */
+/* David Thomas - Final Solution */
+/* ---------------------------------------------------------------------------- */
+
+
+
+#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>
+#include <pthread.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#ifdef NT
+#define M_PI 3.14159265358979323846
+#endif
+#include <math.h>
+
+#include "m_pd.h"
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+
+static int guidebug=0;
+static int ignorevisible=1; // ignore visible test
+ // because this seems to lead to bad refresh
+ // wait for a fix
+
+#define SYS_VGUI2(a,b) if (guidebug) \
+ post(a,b);\
+ sys_vgui(a,b)
+
+#define SYS_VGUI3(a,b,c) if (guidebug) \
+ post(a,b,c);\
+ sys_vgui(a,b,c)
+
+#define SYS_VGUI4(a,b,c,d) if (guidebug) \
+ post(a,b,c,d);\
+ sys_vgui(a,b,c,d)
+
+#define SYS_VGUI5(a,b,c,d,e) if (guidebug) \
+ post(a,b,c,d,e);\
+ sys_vgui(a,b,c,d,e)
+
+#define SYS_VGUI6(a,b,c,d,e,f) if (guidebug) \
+ post(a,b,c,d,e,f);\
+ sys_vgui(a,b,c,d,e,f)
+
+#define SYS_VGUI7(a,b,c,d,e,f,g) if (guidebug) \
+ post(a,b,c,d,e,f,g );\
+ sys_vgui(a,b,c,d,e,f,g)
+
+#define SYS_VGUI9(a,b,c,d,e,f,g,h,i) if (guidebug) \
+ post(a,b,c,d,e,f,g,h,i );\
+ sys_vgui(a,b,c,d,e,f,g,h,i)
+
+#define SYS_VGUI10(a,b,c,d,e,f,g,h,i,j) if (guidebug) \
+ post(a,b,c,d,e,f,g,h,i,j );\
+ sys_vgui(a,b,c,d,e,f,g,h,i,j)
+
+#define SYS_VGUI11(a,b,c,d,e,f,g,h,i,j,k) if (guidebug) \
+ post(a,b,c,d,e,f,g,h,i,j,k );\
+ sys_vgui(a,b,c,d,e,f,g,h,i,j,k)
+
+#define THREAD_SLEEP_TIME 100000 // 100000 us = 100 ms
+
+static char *sonogram_version = "sonogram~: version 0.11, written by Yves Degoyon (ydegoyon@free.fr)";
+
+static t_class *sonogram_class;
+t_widgetbehavior sonogram_widgetbehavior;
+
+
+typedef struct _sonogram
+{
+ t_object x_obj;
+
+ t_int x_size; /* size of the stored fft ( in blocks~ ) */
+ t_float x_samplerate; /* sample rate */
+ t_int x_blocksize; /* current block size ( might be modified by block~ object ) */
+ t_float x_readpos; /* data's playing position */
+ t_int x_writepos; /* data's recording position */
+ t_int x_readstart; /* data's starting position for reading */
+ t_int x_readend; /* data's ending position for reading */
+ t_int x_modstart; /* data's starting position for modifications */
+ t_int x_modend; /* data's ending position for modifications */
+ t_int x_play; /* playing on/off flag */
+ t_float x_readspeed; /* number of grouped blocks for reading */
+ t_float x_record; /* flag to start recording process */
+ t_float x_empty; /* flag to indicate it's a brand new sonogram */
+ t_float *x_rdata; /* table containing real part of the fft */
+ t_float *x_rudata; /* undo real data */
+ t_float *x_idata; /* table containing imaginery part of the fft */
+ t_float *x_iudata; /* undo imaginery data */
+ t_float x_phase; /* phase to apply on output */
+ t_outlet *x_end; /* outlet for end of restitution */
+ t_outlet *x_recend; /* outlet for end of recording */
+ t_int *x_multfreq; /* array of multiplicative factor */
+ char *x_gifdata; /* buffer for graphical data */
+ char *x_guicommand; /* buffer for graphical command */
+ t_int x_uxs; /* starting x position for undo */
+ t_int x_uxe; /* ending x position for undo */
+ t_int x_uys; /* starting y position for undo */
+ t_int x_uye; /* ending y position for undo */
+
+ /* graphical data block */
+ t_int x_enhancemode; /* flag to set enhance mode */
+ t_int x_graphic; /* flag to set graphic mode */
+ t_int x_phaso; /* flag to indicate if phasogram is shown */
+ t_int x_selected; /* flag to remember if we are seleted or not */
+ t_int x_erase; /* flag used when an erase is needed */
+ t_int x_redraw; /* flag used when drawing is needed */
+ t_int x_nbupdated; /* number of points updated */
+ t_glist *x_glist; /* keep graphic context for various operations */
+ t_int x_zoom; /* zoom factor */
+ pthread_t x_updatechild; /* thread id for the update child */
+ t_int x_updatestart; /* starting position for update */
+ t_int x_updateend; /* ending position for update */
+ t_int x_xpos; /* stuck x position */
+ t_int x_ypos; /* stuck y position */
+ t_int x_shifted; /* remember shift state from last click */
+ t_int x_alted; /* remember alt state from last click */
+ t_int x_aftermousedown; /* indicates the mousedown event */
+ t_int x_xstartcapture; /* x of the start of the capture */
+ t_int x_ystartcapture; /* y of the start of the capture */
+ t_int x_xendcapture; /* x of the start of the capture */
+ t_int x_yendcapture; /* y of the start of the capture */
+ t_int x_xdraw; /* x drawing position */
+ t_int x_ydraw; /* y drawing position */
+ t_float x_modstep; /* step for graphical modifications */
+
+ t_float x_f; /* float needed for signal input */
+
+} t_sonogram;
+
+/* ------------------------ drawing functions ---------------------------- */
+static char* sonogram_get_fill_color( t_float fspectrum )
+{
+ if ( fspectrum < 0.01 ) {
+ return "#EEEEEE";
+ } else if ( fspectrum < 0.1 ) {
+ return "#DDDDDD";
+ } else if ( fspectrum < 0.5 ) {
+ return "#CCCCCC";
+ } else if ( fspectrum < 1 ) {
+ return "#BBBBBB";
+ } else if ( fspectrum < 2 ) {
+ return "#AAAAAA";
+ } else if ( fspectrum < 5 ) {
+ return "#999999";
+ } else if ( fspectrum < 10 ) {
+ return "#888888";
+ } else if ( fspectrum < 20 ) {
+ return "#777777";
+ } else if ( fspectrum < 30 ) {
+ return "#666666";
+ } else if ( fspectrum < 40 ) {
+ return "#555555";
+ } else if ( fspectrum < 50 ) {
+ return "#444444";
+ } else if ( fspectrum < 60 ) {
+ return "#333333";
+ } else if ( fspectrum < 80 ) {
+ return "#222222";
+ } else if ( fspectrum < 100 ) {
+ return "#111111";
+ } else {
+ return "#000000";
+ }
+}
+
+static char* phasogram_get_fill_color( t_int phase )
+{
+ if ( phase < 0 )
+ {
+ if ( phase > -10 ) {
+ return "#111111";
+ } else if ( phase > -20 ) {
+ return "#222222";
+ } else if ( phase > -30 ) {
+ return "#333333";
+ } else if ( phase > -40 ) {
+ return "#444444";
+ } else if ( phase > -50 ) {
+ return "#555555";
+ } else if ( phase > -60 ) {
+ return "#666666";
+ } else if ( phase > -70 ) {
+ return "#777777";
+ } else if ( phase > -80 ) {
+ return "#888888";
+ } else {
+ return "#999999";
+ }
+ }
+ else
+ {
+ if ( phase == 0 ) {
+ return "#FFFFFF";
+ } else if ( phase < 10 ) {
+ return "#111111";
+ } else if ( phase < 20 ) {
+ return "#222222";
+ } else if ( phase < 30 ) {
+ return "#333333";
+ } else if ( phase < 40 ) {
+ return "#444444";
+ } else if ( phase < 50 ) {
+ return "#555555";
+ } else if ( phase < 60 ) {
+ return "#666666";
+ } else if ( phase < 70 ) {
+ return "#777777";
+ } else if ( phase < 80 ) {
+ return "#888888";
+ } else {
+ return "#999999";
+ }
+ }
+ // normally never reached
+ return "";
+}
+
+static void sonogram_update_point(t_sonogram *x, t_glist *glist, t_int sample, t_int frequency)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ t_float fspectrum=0.0;
+ t_int phase=0.0;
+ char newColor[ 8 ], olColor[8];
+ int i;
+
+ fspectrum =
+ sqrt( pow( *(x->x_rdata+sample*x->x_blocksize+frequency), 2) +
+ pow( *(x->x_idata+sample*x->x_blocksize+frequency), 2) );
+ phase = (int) ( atan2( *(x->x_idata+(sample*x->x_blocksize)+frequency),
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) )*180/M_PI );
+ if ( x->x_empty && ( fspectrum != 0 ))
+ {
+ x->x_empty = 0;
+ }
+ strcpy( newColor, sonogram_get_fill_color( fspectrum ) );
+
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ sprintf( x->x_gifdata, "%s", strcat( newColor, " ") );
+ }
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ SYS_VGUI5("SONIMAGE%x put {%s} -to %d %d\n", x, x->x_gifdata,
+ sample*x->x_zoom+i, (x->x_blocksize/2-frequency)*x->x_zoom );
+ }
+
+ if ( x->x_phaso )
+ {
+ strcpy( newColor, phasogram_get_fill_color( phase ) );
+ strcpy( x->x_gifdata, "" );
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ sprintf( x->x_gifdata, "%s", strcat( newColor, " ") );
+ }
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ SYS_VGUI5("FAZIMAGE%x put {%s} -to %d %d\n", x, x->x_gifdata,
+ sample*x->x_zoom+i, (x->x_blocksize/2-frequency)*x->x_zoom );
+ }
+ }
+
+ x->x_nbupdated++;
+}
+
+static void sonogram_update_block(t_sonogram *x, t_glist *glist, t_int bnumber)
+{
+ t_int fi, i=0;
+ t_float fspectrum=0.0;
+ t_int phase=0;
+ char color[8];
+
+ // update sonogram
+ for ( fi=x->x_blocksize/2-1; fi>=0; fi-- )
+ {
+ fspectrum =
+ sqrt( pow( *(x->x_rdata+bnumber*x->x_blocksize+fi), 2) +
+ pow( *(x->x_idata+bnumber*x->x_blocksize+fi), 2) );
+ strcpy( color, sonogram_get_fill_color( fspectrum ) );
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ strncpy( x->x_gifdata+((x->x_blocksize/2-fi-1)*x->x_zoom+i)*8, strcat( color, " "), 8 );
+ }
+ }
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ sprintf( x->x_guicommand, "SONIMAGE%x put {%s} -to %d 0\n", (unsigned int)x, x->x_gifdata, (bnumber*x->x_zoom)+i );
+ sys_gui( x->x_guicommand );
+ }
+
+ // update phasogram
+ if ( x->x_phaso )
+ {
+ strcpy( x->x_gifdata, "" );
+ for ( fi=x->x_blocksize/2-1; fi>=0; fi-- )
+ {
+ phase = (int) ( atan2( *(x->x_idata+bnumber*x->x_blocksize+fi),
+ *(x->x_rdata+bnumber*x->x_blocksize+fi) )*180/M_PI );
+ strcpy( color, phasogram_get_fill_color( phase ) );
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ strncpy( x->x_gifdata+((x->x_blocksize/2-fi-1)*x->x_zoom+i)*8, strcat( color, " "), 8 );
+ }
+ }
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ sprintf( x->x_guicommand, "FAZIMAGE%x put {%s} -to %d 0\n", (unsigned int)x, x->x_gifdata, (bnumber*x->x_zoom)+i );
+ sys_gui( x->x_guicommand );
+ }
+ }
+
+}
+
+static void sonogram_erase_block(t_sonogram *x, t_glist *glist, t_int bnumber )
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ t_int fi;
+ t_float fspectrum=0.0;
+ char fillColor[ 16 ];
+
+ for ( fi=0; fi<x->x_blocksize/2; fi++)
+ {
+ {
+ int i;
+
+ for ( i=0; i<x->x_zoom; i++ )
+ {
+ strcpy( x->x_gifdata+i*sizeof("#FFFFFF "), "#FFFFFF " );
+ }
+ SYS_VGUI5("SONIMAGE%x put {%s} -to %d %d\n", x, x->x_gifdata,
+ bnumber*x->x_zoom, (x->x_blocksize/2-fi)*x->x_zoom );
+ }
+ }
+}
+
+static void *sonogram_do_update_part(void *tdata)
+{
+ t_sonogram *x = (t_sonogram*) tdata;
+ t_int si;
+ t_int nbpoints = 0;
+ t_float percentage = 0, opercentage = 0;
+
+ // loose synchro
+ usleep( THREAD_SLEEP_TIME );
+
+ // check boundaries
+ if ( x->x_updateend > x->x_size-1 ) x->x_updateend = x->x_size-1;
+ if ( x->x_updatestart < 0 ) x->x_updatestart = 0;
+
+ // post("sonogram~ : ok, let's go [updating %d, %d]", x->x_updatestart, x->x_updateend );
+
+ if ( x->x_erase )
+ {
+ for ( si=x->x_updatestart; si<=x->x_updateend; si++ )
+ {
+ sonogram_erase_block(x, x->x_glist, si);
+ nbpoints++;
+ percentage = (nbpoints*100/(x->x_updateend-x->x_updatestart+1));
+ if ( (percentage == (int) percentage) && ((int)percentage%5 == 0) && ( percentage != opercentage ) )
+ {
+ // post( "sonogram~ : erase part : %d %% completed", (int)percentage );
+ opercentage = percentage;
+ }
+ }
+ }
+
+ percentage = opercentage = nbpoints = 0;
+
+ if ( x->x_redraw )
+ {
+ for ( si=x->x_updatestart; si<=x->x_updateend; si++ )
+ {
+ sonogram_update_block(x, x->x_glist, si);
+ nbpoints++;
+ percentage = (nbpoints*100/(x->x_updateend-x->x_updatestart+1));
+ if ( (percentage == (int) percentage) && ((int)percentage%5 == 0) && ( percentage != opercentage ) )
+ {
+ // post( "sonogram~ : update part : %d %% completed", (int)percentage );
+ opercentage = percentage;
+ }
+ }
+ }
+
+ // set borders in black
+ SYS_VGUI3(".x%x.c itemconfigure %xSONOGRAM -outline #000000\n", glist_getcanvas(x->x_glist), x);
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xPHASOGRAM -outline #000000\n", glist_getcanvas(x->x_glist), x);
+ }
+
+ // post("sonogram~ : child thread %d ended (nb_updated=%d)", (int)x->x_updatechild, x->x_nbupdated );
+ x->x_updatechild = 0;
+ return NULL;
+}
+
+static void sonogram_update_part(t_sonogram *x, t_glist *glist, t_int bstart, t_int bend,
+ t_int erase, t_int redraw, t_int keepframe)
+{
+ pthread_attr_t update_child_attr;
+
+ if ( x->x_graphic )
+ {
+ if ( x->x_updatechild != 0 )
+ {
+ // post( "sonogram~ : error : no update is possible for now" );
+ return;
+ }
+ x->x_updatestart = bstart;
+ x->x_updateend = bend;
+ if ( !keepframe )
+ {
+ x->x_erase = 0;
+ }
+ else
+ {
+ x->x_erase = erase;
+ }
+ x->x_redraw = redraw;
+ x->x_nbupdated = 0;
+ // recreate the square if needed
+ if ( ( bstart == 0 ) && ( bend == x->x_size-1 ) && !keepframe )
+ {
+ SYS_VGUI3(".x%x.c delete %xSONOGRAM\n", glist_getcanvas(glist), x );
+ SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill #FFFFFF -tags %xSONOGRAM\n",
+ glist_getcanvas(glist), x->x_xpos-1, x->x_ypos-1,
+ x->x_xpos + x->x_size*x->x_zoom+1,
+ x->x_ypos + x->x_blocksize/2*x->x_zoom+1,
+ x);
+ SYS_VGUI2("image delete SONIMAGE%x\n", x );
+ SYS_VGUI3(".x%x.c delete ISONIMAGE%x\n", glist_getcanvas(glist), x );
+ SYS_VGUI4("image create photo SONIMAGE%x -format gif -width %d -height %d\n",
+ x, x->x_size*x->x_zoom, x->x_blocksize/2*x->x_zoom );
+ SYS_VGUI2("SONIMAGE%x blank\n", x);
+ SYS_VGUI6(".x%x.c create image %d %d -image SONIMAGE%x -tags ISONIMAGE%x\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+((x->x_size*x->x_zoom)/2),
+ (x->x_ypos+((x->x_blocksize/2*x->x_zoom)/2)), x, x );
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c delete %xPHASOGRAM\n", glist_getcanvas(glist), x );
+ SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill #FFFFFF -tags %xPHASOGRAM\n",
+ glist_getcanvas(glist), x->x_xpos-1, x->x_ypos+x->x_blocksize/2*x->x_zoom+2,
+ x->x_xpos + x->x_size*x->x_zoom +1,
+ x->x_ypos + x->x_blocksize*x->x_zoom + 3,
+ x);
+ SYS_VGUI2("image delete FAZIMAGE%x\n", x );
+ SYS_VGUI3(".x%x.c delete IFAZIMAGE%x\n", glist_getcanvas(glist), x );
+ SYS_VGUI4("image create photo FAZIMAGE%x -format gif -width %d -height %d\n",
+ x, x->x_size*x->x_zoom, x->x_blocksize/2*x->x_zoom );
+ SYS_VGUI2("FAZIMAGE%x blank\n", x);
+ SYS_VGUI6(".x%x.c create image %d %d -image FAZIMAGE%x -tags IFAZIMAGE%x\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+((x->x_size*x->x_zoom)/2),
+ x->x_ypos+3*((x->x_blocksize/2*x->x_zoom)/2)+2, x, x );
+ }
+ canvas_fixlinesfor( glist_getcanvas(x->x_glist), (t_text*)x );
+ }
+ // set borders in red
+ SYS_VGUI3(".x%x.c itemconfigure %xSONOGRAM -outline #FF0000\n", glist_getcanvas(glist), x);
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xPHASOGRAM -outline #FF0000\n", glist_getcanvas(glist), x);
+ }
+
+ // launch update thread
+ if ( pthread_attr_init( &update_child_attr ) < 0 ) {
+ post( "sonogram~ : could not launch update thread" );
+ perror( "pthread_attr_init" );
+ return;
+ }
+ if ( pthread_attr_setdetachstate( &update_child_attr, PTHREAD_CREATE_DETACHED ) < 0 ) {
+ post( "sonogram~ : could not launch update thread" );
+ perror( "pthread_attr_setdetachstate" );
+ return;
+ }
+ if ( pthread_create( &x->x_updatechild, &update_child_attr, sonogram_do_update_part, x ) < 0 ) {
+ post( "sonogram~ : could not launch update thread" );
+ perror( "pthread_create" );
+ return;
+ }
+ else
+ {
+ // post( "sonogram~ : drawing thread %d launched", (int)x->x_updatechild );
+ }
+ }
+}
+
+ /* paste selection at the drawing point */
+static void sonogram_paste( t_sonogram* x)
+{
+ t_int pxstart = (x->x_xdraw-x->x_xpos)/x->x_zoom;
+ t_int pystart = (x->x_ypos-x->x_ydraw)/x->x_zoom+x->x_blocksize/2;
+ t_int cxs,cxe,cys,cye,si=0,fi=0;
+ t_float *icopy;
+ t_float *rcopy;
+ t_int copynd;
+
+ if ( x->x_xstartcapture > x->x_xendcapture ) {
+ fi = x->x_xstartcapture;
+ x->x_xstartcapture = x->x_xendcapture;
+ x->x_xendcapture = fi;
+ }
+ if ( x->x_ystartcapture > x->x_yendcapture ) {
+ fi = x->x_ystartcapture;
+ x->x_ystartcapture = x->x_yendcapture;
+ x->x_yendcapture = fi;
+ }
+ cxs=(x->x_xstartcapture-x->x_xpos)/x->x_zoom;
+ cxe=(x->x_xendcapture-x->x_xpos)/x->x_zoom;
+ cys=(x->x_ypos-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ cye=(x->x_ypos-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2;
+ if ( cye < 0 ) cye=0;
+ if ( cys < 0 ) cys=0;
+ if ( cye >= x->x_blocksize/2 ) cye=x->x_blocksize/2-1;
+ if ( cys >= x->x_blocksize/2 ) cys=x->x_blocksize/2-1;
+ if ( cxe >= x->x_size ) cxe=x->x_size-1;
+ if ( cxs >= x->x_size ) cxs=x->x_size-1;
+
+ // make a copy first
+ icopy = ( t_float* ) getbytes( ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ rcopy = ( t_float* ) getbytes( ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ if ( !icopy || !rcopy )
+ {
+ post( "sonogram~ : cannot allocate buffers for pasting" );
+ return;
+ }
+ // copy initial data
+ copynd = 0;
+ for ( si=cxs; si<=cxe; si++) {
+ for ( fi=cys; fi<=cye; fi++) {
+ *(rcopy+copynd) = *(x->x_rdata+(si)*x->x_blocksize+fi);
+ *(icopy+copynd) = *(x->x_idata+(si)*x->x_blocksize+fi);
+ copynd++;
+ }
+ }
+
+ post( "sonogram~ : paste from [%d,%d,%d,%d] to [%d,%d]", cxs, cys, cxe, cye, pxstart, pystart );
+
+ for ( si=cxs; si<=cxe; si++) {
+ if ( pxstart+si-cxs >= x->x_size ) break;
+ copynd = (si-cxs)*(cye-cys+1);
+ for ( fi=cys; fi<=cye; fi++) {
+ // post ( "sonogram~ : si : %d : fi : %d : copynd : %d", si, fi, copynd );
+ if ( pystart+fi-cys >= x->x_blocksize/2 ) break;
+ *(x->x_rudata+((si-cxs)*x->x_blocksize)+(fi-cys)) = *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys));
+ *(x->x_iudata+((si-cxs)*x->x_blocksize)+(fi-cys)) = *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys));
+ if ( x->x_enhancemode )
+ {
+ // save data for undo
+ *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) += *(rcopy+copynd);
+ *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) += *(icopy+copynd);
+ }
+ else
+ {
+ *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) = *(rcopy+copynd);
+ *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) = *(icopy+copynd);
+ }
+ copynd++;
+ }
+ }
+
+ x->x_uxs = pxstart;
+ x->x_uxe = pxstart+(si-1)-cxs;
+ x->x_uys = pystart;
+ x->x_uye = pystart+(fi-1)-cys;;
+
+ freebytes( rcopy, ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ freebytes( icopy, ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+}
+
+ /* paste phase at the drawing point */
+static void sonogram_paste_phase( t_sonogram* x)
+{
+ t_int pxstart = (x->x_xdraw-x->x_xpos)/x->x_zoom;
+ t_int pystart = (x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_ydraw)/x->x_zoom+x->x_blocksize/2;
+ t_int cxs,cxe,cys,cye,si,fi;
+ t_float fspectrum, fdestspectrum;
+ t_float fphase, fdestphase;
+ t_float *icopy;
+ t_float *rcopy;
+ t_int copynd;
+
+ if ( x->x_xstartcapture > x->x_xendcapture ) {
+ fi = x->x_xstartcapture;
+ x->x_xstartcapture = x->x_xendcapture;
+ x->x_xendcapture = fi;
+ }
+ if ( x->x_ystartcapture > x->x_yendcapture ) {
+ fi = x->x_ystartcapture;
+ x->x_ystartcapture = x->x_yendcapture;
+ x->x_yendcapture = fi;
+ }
+ cxs=(x->x_xstartcapture-x->x_xpos)/x->x_zoom;
+ cxe=(x->x_xendcapture-x->x_xpos)/x->x_zoom;
+ cys=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ cye=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2;
+ if ( cye < 0 ) cye=0;
+ if ( cys < 0 ) cys=0;
+ if ( cye >= x->x_blocksize/2 ) cye=x->x_blocksize/2-1;
+ if ( cys >= x->x_blocksize/2 ) cys=x->x_blocksize/2-1;
+ if ( cxe >= x->x_size ) cxe=x->x_size-1;
+ if ( cxs >= x->x_size ) cxs=x->x_size-1;
+
+ // make a copy first
+ icopy = ( t_float* ) getbytes( ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ rcopy = ( t_float* ) getbytes( ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ if ( !icopy || !rcopy )
+ {
+ post( "sonogram~ : cannot allocate buffers for pasting" );
+ return;
+ }
+ // copy initial data
+ copynd = 0;
+ for ( si=cxs; si<=cxe; si++) {
+ for ( fi=cys; fi<=cye; fi++) {
+ *(rcopy+copynd) = *(x->x_rdata+(si)*x->x_blocksize+fi);
+ *(icopy+copynd) = *(x->x_idata+(si)*x->x_blocksize+fi);
+ copynd++;
+ }
+ }
+
+ post( "sonogram~ : paste phase from [%d,%d,%d,%d] to [%d,%d]", cxs, cys, cxe, cye, pxstart, pystart );
+
+ for ( si=cxs; si<=cxe; si++) {
+ if ( pxstart+si-cxs >= x->x_size ) break;
+ copynd = (si-cxs)*(cye-cys+1);
+ for ( fi=cys; fi<=cye; fi++) {
+ if ( pystart+fi-cys > x->x_blocksize+1 ) break;
+ fphase = atan2( *(icopy+copynd), *(rcopy+copynd) );
+ fdestspectrum =
+ sqrt( pow( *(x->x_rdata+(pxstart+si-cxs)*x->x_blocksize+(pystart+fi-cys)), 2) +
+ pow( *(x->x_idata+(pxstart+si-cxs)*x->x_blocksize+(pystart+fi-cys)), 2) );
+ fdestphase = atan2( *(x->x_idata+(pxstart+si-cxs)*x->x_blocksize+(pystart+fi-cys)),
+ *(x->x_rdata+(pxstart+si-cxs)*x->x_blocksize+(pystart+fi-cys)) );
+ if ( x->x_enhancemode )
+ {
+ *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) +=
+ fdestspectrum*cos( fdestphase + fphase );
+ *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) +=
+ fdestspectrum*sin( fdestphase + fphase );
+ }
+ else
+ {
+ *(x->x_rdata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) =
+ fdestspectrum*cos( fphase );
+ *(x->x_idata+((pxstart+si-cxs)*x->x_blocksize)+(pystart+fi-cys)) =
+ fdestspectrum*sin( fphase );
+ }
+ copynd++;
+ }
+ }
+
+ freebytes( rcopy, ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+ freebytes( icopy, ( cxe-cxs+1 )*( cye-cys+1 )*sizeof( t_float ) );
+
+ sonogram_update_part(x, x->x_glist, pxstart, pxstart+(si-1)-cxs, 0, 1, 1);
+ // start a new capture
+ SYS_VGUI3( ".x%x.c delete %xCAPTURE\n", glist_getcanvas( x->x_glist ), x );
+ x->x_xstartcapture = x->x_xdraw;
+ x->x_ystartcapture = x->x_ydraw;
+ x->x_xendcapture = x->x_xdraw;
+ x->x_yendcapture = x->x_ydraw;
+
+}
+
+static void sonogram_draw_new(t_sonogram *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if ( x->x_xpos == -1 )
+ {
+ x->x_xpos=x->x_obj.te_xpix;
+ x->x_ypos=x->x_obj.te_ypix;
+ }
+ if ( x->x_graphic )
+ {
+ SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill #FFFFFF -tags %xSONOGRAM\n",
+ canvas, x->x_xpos-1, x->x_ypos-1,
+ x->x_xpos + x->x_size*x->x_zoom+1,
+ x->x_ypos + x->x_blocksize/2*x->x_zoom+1,
+ x);
+ SYS_VGUI4("image create photo SONIMAGE%x -format gif -width %d -height %d\n",
+ x, x->x_size*x->x_zoom, x->x_blocksize/2*x->x_zoom );
+ SYS_VGUI2("SONIMAGE%x blank\n", x);
+ SYS_VGUI6(".x%x.c create image %d %d -image SONIMAGE%x -tags ISONIMAGE%x\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+((x->x_size*x->x_zoom)/2),
+ (x->x_ypos+((x->x_blocksize/2*x->x_zoom)/2)), x, x );
+ if ( x->x_phaso )
+ {
+ SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill #FFFFFF -tags %xPHASOGRAM\n",
+ glist_getcanvas(glist), x->x_xpos-1, x->x_ypos+x->x_blocksize/2*x->x_zoom+2,
+ x->x_xpos + x->x_size*x->x_zoom +1,
+ x->x_ypos + x->x_blocksize*x->x_zoom + 3,
+ x);
+ SYS_VGUI4("image create photo FAZIMAGE%x -format gif -width %d -height %d\n",
+ x, x->x_size*x->x_zoom, x->x_blocksize/2*x->x_zoom );
+ SYS_VGUI2("FAZIMAGE%x blank\n", x);
+ SYS_VGUI6(".x%x.c create image %d %d -image FAZIMAGE%x -tags IFAZIMAGE%x\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+((x->x_size*x->x_zoom)/2),
+ x->x_ypos+3*((x->x_blocksize/2*x->x_zoom)/2)+2, x, x );
+ }
+ canvas_fixlinesfor( canvas, (t_text*)x );
+ }
+}
+
+static void sonogram_draw_delete(t_sonogram *x, t_glist *glist)
+{
+ if ( x->x_graphic && glist_isvisible( glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete %xCAPTURE\n", glist_getcanvas( glist ), x );
+ SYS_VGUI3( ".x%x.c delete line %xREADSTART\n", glist_getcanvas( glist ), x);
+ SYS_VGUI3( ".x%x.c delete line %xREADEND\n", glist_getcanvas( glist ), x);
+ SYS_VGUI3( ".x%x.c delete line %xMODSTART\n", glist_getcanvas( glist ), x);
+ SYS_VGUI3( ".x%x.c delete line %xMODEND\n", glist_getcanvas( glist ), x);
+ SYS_VGUI3(".x%x.c delete %xSONOGRAM\n", glist_getcanvas( glist ), x );
+ SYS_VGUI3(".x%x.c delete %xPHASOGRAM\n", glist_getcanvas( glist ), x );
+ SYS_VGUI3(".x%x.c delete %xISONIMAGE\n", glist_getcanvas( glist ), x );
+ SYS_VGUI2("image delete SONIMAGE%x\n", x );
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c delete %xIFAZIMAGE\n", glist_getcanvas( glist ), x );
+ SYS_VGUI2("image delete FAZIMAGE%x\n", x );
+ }
+ }
+}
+
+static void sonogram_draw_move(t_sonogram *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI7(".x%x.c coords %xSONOGRAM %d %d %d %d\n",
+ canvas, x,
+ x->x_xpos-1, x->x_ypos-1,
+ x->x_xpos+x->x_size*x->x_zoom+1,
+ x->x_ypos+x->x_blocksize/2*x->x_zoom+1);
+ SYS_VGUI5(".x%x.c coords ISONIMAGE%x %d %d\n",
+ canvas, x,
+ x->x_xpos+((x->x_size*x->x_zoom)/2),
+ (x->x_ypos+((x->x_blocksize/2*x->x_zoom)/2)) );
+ if ( x->x_phaso )
+ {
+ SYS_VGUI7(".x%x.c coords %xPHASOGRAM %d %d %d %d\n",
+ canvas, x,
+ x->x_xpos-1, x->x_ypos+(x->x_blocksize/2*x->x_zoom)+1,
+ x->x_xpos+x->x_size*x->x_zoom+1,
+ x->x_ypos+x->x_blocksize*x->x_zoom+3);
+ SYS_VGUI5(".x%x.c coords IFAZIMAGE%x %d %d\n",
+ canvas, x,
+ x->x_xpos+((x->x_size*x->x_zoom)/2),
+ x->x_ypos+3*((x->x_blocksize/2*x->x_zoom)/2)+2 );
+ }
+ canvas_fixlinesfor( canvas, (t_text*)x );
+ }
+}
+
+static void sonogram_draw_select(t_sonogram* x,t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ if(x->x_selected)
+ {
+ /* sets the item in blue */
+ SYS_VGUI3(".x%x.c itemconfigure %xSONOGRAM -outline #0000FF\n", canvas, x);
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xPHASOGRAM -outline #0000FF\n", canvas, x);
+ }
+ }
+ else
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xSONOGRAM -outline #000000\n", canvas, x);
+ if ( x->x_phaso )
+ {
+ SYS_VGUI3(".x%x.c itemconfigure %xPHASOGRAM -outline #000000\n", canvas, x);
+ }
+ }
+ }
+}
+
+/* ------------------------ widget callbacks ----------------------------- */
+
+
+static void sonogram_getrect(t_gobj *z, t_glist *owner,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_sonogram* x = (t_sonogram*)z;
+
+ *xp1 = x->x_xpos;
+ *yp1 = x->x_ypos;
+ if ( !x->x_phaso )
+ {
+ *xp2 = x->x_xpos+x->x_size*x->x_zoom;
+ *yp2 = x->x_ypos+x->x_blocksize/2*x->x_zoom+1;
+ }
+ else
+ {
+ *xp2 = x->x_xpos+x->x_size*x->x_zoom;
+ *yp2 = x->x_ypos+x->x_blocksize*x->x_zoom+3;
+ }
+}
+
+static void sonogram_save(t_gobj *z, t_binbuf *b)
+{
+ t_sonogram *x = (t_sonogram *)z;
+
+ binbuf_addv(b, "ssiisiii", gensym("#X"),gensym("obj"),
+ (t_int)x->x_xpos, (t_int)x->x_ypos,
+ gensym("sonogram~"), x->x_size, x->x_graphic, x->x_phaso );
+ binbuf_addv(b, ";");
+}
+
+static void sonogram_select(t_gobj *z, t_glist *glist, int selected)
+{
+ t_sonogram *x = (t_sonogram *)z;
+
+ x->x_selected = selected;
+ sonogram_draw_select( x, glist );
+}
+
+static void sonogram_vis(t_gobj *z, t_glist *glist, int vis)
+{
+ t_sonogram *x = (t_sonogram *)z;
+ t_rtext *y;
+
+ if (vis)
+ {
+ sonogram_draw_new( x, glist );
+ }
+ else
+ {
+ // erase all points
+ sonogram_draw_delete( x, glist );
+ }
+}
+
+static void sonogram_delete(t_gobj *z, t_glist *glist)
+{
+ canvas_deletelinesfor( glist_getcanvas(glist), (t_text *)z);
+}
+
+static void sonogram_displace(t_gobj *z, t_glist *glist, int dx, int dy)
+{
+ t_sonogram *x = (t_sonogram *)z;
+ int xold = x->x_xpos;
+ int yold = x->x_ypos;
+
+ x->x_xpos += dx;
+ x->x_ypos += dy;
+
+ if ( ( x->x_xpos != xold ) || ( x->x_ypos != yold ) )
+ {
+ sonogram_draw_move( x, glist );
+ }
+
+}
+
+static void sonogram_modify_point( t_sonogram* x, t_int sample, t_int frequency, t_int alted )
+{
+ if ( alted )
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) = 0;
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) = 0;
+ }
+ else
+ {
+ if ( x->x_enhancemode )
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) *= x->x_modstep;
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) *= x->x_modstep;
+ }
+ else
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) += x->x_modstep;
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) += x->x_modstep;
+ }
+ }
+}
+
+static void sonogram_modify_point_phase( t_sonogram* x, t_int sample, t_int frequency, t_int alted )
+{
+ t_float fspectrum;
+ t_float fphase;
+
+ fspectrum =
+ sqrt( pow( *(x->x_rdata+sample*x->x_blocksize+frequency), 2) +
+ pow( *(x->x_idata+sample*x->x_blocksize+frequency), 2) );
+ fphase = atan2( *(x->x_idata+sample*x->x_blocksize+frequency),
+ *(x->x_rdata+sample*x->x_blocksize+frequency) );
+ if ( alted==4 )
+ {
+ // setting phase to 0
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) = fspectrum;
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) = 0;
+ }
+ else
+ {
+ if ( x->x_enhancemode )
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) = fspectrum*cos( fphase*x->x_modstep );
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) = fspectrum*sin( fphase*x->x_modstep );
+ }
+ else
+ {
+ *(x->x_rdata+(sample*x->x_blocksize)+frequency) = fspectrum*cos( fphase+x->x_modstep );
+ *(x->x_idata+(sample*x->x_blocksize)+frequency) = fspectrum*sin( fphase+x->x_modstep );
+ }
+ }
+}
+
+static void sonogram_motion(t_sonogram *x, t_floatarg dx, t_floatarg dy)
+{
+ int fdraw=0, sdraw=0;
+
+ // post( "sonogram_motion @ [%d,%d] dx=%f dy=%f alt=%d", x->x_xdraw, x->x_ydraw, dx, dy, x->x_alted );
+ if ( ( x->x_shifted || (x->x_alted==4) ) )
+ {
+ if ( (x->x_xdraw+dx) >= x->x_xpos &&
+ (x->x_xdraw+dx) <= x->x_xpos+x->x_size*x->x_zoom ) {
+ x->x_xdraw += dx;
+ }
+ if ( (x->x_ydraw+dy) >= x->x_ypos &&
+ (x->x_ydraw+dy) <= x->x_ypos+x->x_blocksize*x->x_zoom ) {
+ x->x_ydraw += dy;
+ }
+ sdraw=(x->x_xdraw-x->x_xpos)/x->x_zoom;
+ if ( x->x_ydraw <= x->x_ypos+x->x_blocksize/2*x->x_zoom )
+ {
+ fdraw=(x->x_ypos-x->x_ydraw)/x->x_zoom+x->x_blocksize/2;
+ // post( "modify point @ [%d, %d] alted=%d", sdraw, fdraw, x->x_alted );
+ sonogram_modify_point( x, sdraw, fdraw, x->x_alted );
+ }
+ if ( x->x_ydraw >= x->x_ypos+x->x_blocksize/2*x->x_zoom+1 )
+ {
+ fdraw=(x->x_ypos+x->x_blocksize*x->x_zoom/2+1-x->x_ydraw)/x->x_zoom+x->x_blocksize/2;
+ // post( "modify phase @ [%d, %d]", sdraw, fdraw );
+ sonogram_modify_point_phase( x, sdraw, fdraw, x->x_alted );
+ }
+ sonogram_update_point( x, x->x_glist, sdraw, fdraw );
+ }
+ else
+ {
+ if ( (x->x_xendcapture+dx) >= x->x_xpos &&
+ (x->x_xendcapture+dx) <= x->x_xpos+x->x_size*x->x_zoom ) {
+ x->x_xendcapture += dx;
+ }
+ if ( (x->x_yendcapture+dy) >= x->x_ypos &&
+ (x->x_yendcapture+dy) <= x->x_ypos+x->x_blocksize*x->x_zoom ) {
+ x->x_yendcapture += dy;
+ }
+ SYS_VGUI3( ".x%x.c delete %xCAPTURE\n", glist_getcanvas( x->x_glist ), x );
+ SYS_VGUI7( ".x%x.c create rectangle %d %d %d %d -outline #0000FF -tags %xCAPTURE\n",
+ glist_getcanvas( x->x_glist ), x->x_xstartcapture,
+ x->x_ystartcapture, x->x_xendcapture, x->x_yendcapture, x );
+ }
+}
+
+static int sonogram_click(t_gobj *z, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_sonogram* x = (t_sonogram *)z;
+ int si,fi;
+
+ // post( "sonogram_click : x=%d y=%d doit=%d alt=%d, shift=%d", xpix, ypix, doit, alt, shift );
+ if ( x->x_aftermousedown == 1 && doit == 0)
+ {
+ x->x_aftermousedown = 1;
+ }
+ else
+ {
+ x->x_aftermousedown = 0;
+ }
+ if ( doit )
+ {
+ x->x_xdraw = xpix;
+ x->x_ydraw = ypix;
+ x->x_shifted = shift;
+ x->x_alted = alt;
+ // activate motion callback
+ glist_grab( glist, &x->x_obj.te_g, (t_glistmotionfn)sonogram_motion,
+ 0, xpix, ypix );
+
+ if ( shift && alt && (x->x_xstartcapture != x->x_xendcapture ) )
+ {
+ sonogram_paste(x);
+ sonogram_paste_phase(x);
+ }
+ else if ( shift && (x->x_xstartcapture != x->x_xendcapture ) )
+ {
+ // add or multiply modstep
+ if ( x->x_xstartcapture > x->x_xendcapture ) {
+ fi = x->x_xstartcapture;
+ x->x_xstartcapture = x->x_xendcapture;
+ x->x_xendcapture = fi;
+ }
+ if ( x->x_ystartcapture > x->x_yendcapture ) {
+ fi = x->x_ystartcapture;
+ x->x_ystartcapture = x->x_yendcapture;
+ x->x_yendcapture = fi;
+ }
+ for ( si=(x->x_xstartcapture-x->x_xpos)/x->x_zoom;
+ si<=(x->x_xendcapture-x->x_xpos)/x->x_zoom; si++) {
+ for ( fi=(x->x_ypos-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ fi<=(x->x_ypos-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2; fi++) {
+ sonogram_modify_point( x, si, fi, alt );
+ }
+ for ( fi=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ fi<=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2; fi++) {
+ sonogram_modify_point_phase( x, si, fi, alt );
+ }
+ }
+ // post( "modified y from %d to %d", (x->x_ypos-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2,
+ // (x->x_ypos-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2 );
+ sonogram_update_part(x, x->x_glist, (x->x_xstartcapture-x->x_xpos)/x->x_zoom,
+ (x->x_xendcapture-x->x_xpos)/x->x_zoom, 0, 1, 1);
+ }
+ else if ( (alt==4) && (x->x_xstartcapture != x->x_xendcapture ) )
+ {
+ // clean up area
+ if ( x->x_xstartcapture > x->x_xendcapture ) {
+ fi = x->x_xstartcapture;
+ x->x_xstartcapture = x->x_xendcapture;
+ x->x_xendcapture = fi;
+ }
+ if ( x->x_ystartcapture > x->x_yendcapture ) {
+ fi = x->x_ystartcapture;
+ x->x_ystartcapture = x->x_yendcapture;
+ x->x_yendcapture = fi;
+ }
+ for ( si=(x->x_xstartcapture-x->x_xpos)/x->x_zoom;
+ si<=(x->x_xendcapture-x->x_xpos)/x->x_zoom; si++) {
+ for ( fi=(x->x_ypos-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ fi<=(x->x_ypos-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2; fi++) {
+ sonogram_modify_point( x, si, fi, alt );
+ }
+ for ( fi=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_yendcapture)/x->x_zoom+x->x_blocksize/2;
+ fi<=(x->x_ypos+x->x_blocksize/2*x->x_zoom+1-x->x_ystartcapture)/x->x_zoom+x->x_blocksize/2; fi++) {
+ sonogram_modify_point_phase( x, si, fi, alt );
+ }
+ }
+ sonogram_update_part(x, x->x_glist, (x->x_xstartcapture-x->x_xpos)/x->x_zoom,
+ (x->x_xendcapture-x->x_xpos)/x->x_zoom, 0, 1, 1);
+ }
+ // start a new capture
+ SYS_VGUI3( ".x%x.c delete %xCAPTURE\n", glist_getcanvas( x->x_glist ), x );
+ x->x_xstartcapture = xpix;
+ x->x_ystartcapture = ypix;
+ x->x_xendcapture = xpix;
+ x->x_yendcapture = ypix;
+ }
+ else
+ {
+ // nothing
+ }
+ x->x_aftermousedown = doit;
+ return (1);
+}
+
+ /* clean up */
+static void sonogram_free(t_sonogram *x)
+{
+ if ( x->x_rdata != NULL ) {
+ freebytes(x->x_rdata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_rdata = NULL;
+ }
+ if ( x->x_idata != NULL ) {
+ freebytes(x->x_idata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_idata = NULL;
+ }
+ if ( x->x_rudata != NULL ) {
+ freebytes(x->x_rudata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_rdata = NULL;
+ }
+ if ( x->x_iudata != NULL ) {
+ freebytes(x->x_iudata, x->x_size*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ x->x_idata = NULL;
+ }
+ if ( x->x_gifdata != NULL ) {
+ freebytes(x->x_gifdata, (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ post( "Freed %d bytes", (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ x->x_gifdata = NULL;
+ }
+ if ( x->x_guicommand != NULL ) {
+ freebytes(x->x_guicommand, 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ post( "Freed %d bytes", 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ x->x_guicommand = NULL;
+ }
+}
+
+ /* allocate tables for storing ffts */
+static t_int sonogram_allocate(t_sonogram *x)
+{
+ t_int fi;
+
+ if ( !(x->x_rdata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_idata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_multfreq = getbytes( x->x_blocksize*sizeof(t_int) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_blocksize*sizeof(t_int) );
+ }
+ for ( fi=0; fi<x->x_blocksize; fi++ )
+ {
+ *(x->x_multfreq+fi)=1;
+ }
+ // no undo is available
+ x->x_uxs = x->x_uxe = x->x_uys = x->x_uye = -1;
+ if ( !(x->x_rudata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_iudata = getbytes( x->x_size*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", x->x_size*x->x_blocksize*sizeof(float) );
+ }
+ if ( !( x->x_gifdata = ( char* ) getbytes( (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ }
+ if ( !( x->x_guicommand = ( char* ) getbytes( 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ }
+
+ return 0;
+}
+
+ /* reallocate tables for storing ffts */
+static t_int sonogram_reallocate(t_sonogram *x, t_int ioldsize, t_int inewsize)
+{
+ t_int fi;
+ t_float *prdata=x->x_rdata, *pidata=x->x_idata;
+ t_float *prudata=x->x_rudata, *piudata=x->x_iudata;
+
+ if ( !(x->x_rdata = getbytes( inewsize*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", inewsize*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_idata = getbytes( inewsize*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", inewsize*x->x_blocksize*sizeof(float) );
+ }
+ // no undo is available
+ x->x_uxs = x->x_uxe = x->x_uys = x->x_uye = -1;
+ if ( !(x->x_rudata = getbytes( inewsize*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", inewsize*x->x_blocksize*sizeof(float) );
+ }
+ if ( !(x->x_iudata = getbytes( inewsize*x->x_blocksize*sizeof(float) ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return -1;
+ } else {
+ post( "sonogram~ : allocated %d bytes", inewsize*x->x_blocksize*sizeof(float) );
+ }
+ if ( prdata != NULL ) {
+ freebytes(prdata, ioldsize*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", ioldsize*x->x_blocksize*sizeof(float) );
+ }
+ if ( pidata != NULL ) {
+ freebytes(pidata, ioldsize*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", ioldsize*x->x_blocksize*sizeof(float) );
+ }
+ if ( prudata != NULL ) {
+ freebytes(prudata, ioldsize*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", ioldsize*x->x_blocksize*sizeof(float) );
+ }
+ if ( piudata != NULL ) {
+ freebytes(piudata, ioldsize*x->x_blocksize*sizeof(float) );
+ post( "Freed %d bytes", ioldsize*x->x_blocksize*sizeof(float) );
+ }
+
+ return 0;
+}
+ /* records or playback the sonogram */
+static t_int *sonogram_perform(t_int *w)
+{
+ t_float *rin = (t_float *)(w[1]);
+ t_float *iin = (t_float *)(w[2]);
+ t_float *rout = (t_float *)(w[3]);
+ t_float *iout = (t_float *)(w[4]);
+ t_float fspectrum = 0.0;
+ t_float fphase = 0.0;
+ t_int is;
+ t_int n = (int)(w[5]); /* number of samples */
+ t_sonogram *x = (t_sonogram *)(w[6]);
+ t_int bi;
+ t_int startsamp, endsamp;
+
+ if ( x->x_readstart <= x->x_readend )
+ {
+ startsamp = (x->x_readstart*x->x_size)/100;
+ endsamp = (x->x_readend*x->x_size)/100;
+ }
+ else
+ {
+ startsamp = (x->x_readend*x->x_size)/100;
+ endsamp = (x->x_readstart*x->x_size)/100;
+ }
+
+ // reallocate tables if blocksize has been changed
+ if ( n != x->x_blocksize && x->x_updatechild == 0 ) {
+ post( "sonogram~ : reallocating tables" );
+ // erase all points
+ sonogram_free(x);
+ x->x_blocksize = n;
+ sonogram_allocate(x);
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, !x->x_empty, 0, 0);
+ canvas_fixlinesfor( glist_getcanvas(x->x_glist), (t_text*)x );
+ }
+
+ bi = 0;
+ while (bi<n)
+ {
+ // eventually records input
+ if ( x->x_record) {
+ *(x->x_rdata+(x->x_writepos*x->x_blocksize)+bi)=(*(rin))*(*(x->x_multfreq+bi));
+ *(x->x_idata+(x->x_writepos*x->x_blocksize)+bi)=(*(iin))*(*(x->x_multfreq+bi));
+ }
+ // set outputs
+ *rout = 0.0;
+ *iout = 0.0;
+ if ( x->x_play) {
+ is=0;
+ fspectrum =
+ sqrt( pow( *(x->x_rdata+(((int)x->x_readpos+is)*x->x_blocksize)+bi), 2) +
+ pow( *(x->x_idata+(((int)x->x_readpos+is)*x->x_blocksize)+bi), 2) );
+ fphase = atan2( *(x->x_idata+(((int)x->x_readpos+is)*x->x_blocksize)+bi),
+ *(x->x_rdata+(((int)x->x_readpos+is)*x->x_blocksize)+bi) );
+ fphase += (x->x_phase/180.0)*(M_PI);
+ *rout += fspectrum*cos( fphase );
+ *iout += fspectrum*sin( fphase );
+ }
+ rout++;iout++;
+ rin++;iin++;
+ bi++;
+
+ }
+ // reset playing position until next play
+ if ( x->x_play ) {
+ x->x_readpos+=x->x_readspeed;
+ // post( "xreadpos : %f (added %f) %d", x->x_readpos, x->x_readspeed, x->x_readend );
+ if ( ( x->x_readspeed >= 0 ) && ( x->x_readpos >= endsamp ) ) {
+ x->x_play=0;
+ x->x_readpos=(float)(startsamp);
+ // post( "cooled~ : stopped playing (readpos=%d)", x->x_readpos );
+ outlet_bang(x->x_end);
+ }
+ if ( ( x->x_readspeed < 0 ) && ( x->x_readpos <= startsamp ) ) {
+ x->x_play=0;
+ x->x_readpos = (float)(endsamp);
+ // post( "cooled~ : stopped playing (readpos=%d)", x->x_readpos );
+ outlet_bang(x->x_end);
+ }
+ }
+ // reset recording position until next record
+ if ( x->x_record ) {
+ x->x_writepos++;
+ if ( x->x_writepos >= x->x_size ) {
+ x->x_record=0;
+ x->x_writepos=0;
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, 0, 1, 0);
+ outlet_bang(x->x_recend);
+ if ( x->x_empty ) x->x_empty = 0;
+ // post( "sonogram~ : stopped recording" );
+ }
+ }
+ // post( "sonogram~ : read : %f:%d : write: %d:%d", x->x_readpos, x->x_play, x->x_writepos, x->x_record );
+ return (w+7);
+}
+
+static void sonogram_dsp(t_sonogram *x, t_signal **sp)
+{
+ dsp_add(sonogram_perform, 6, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n, x);
+}
+
+ /* record the sonogram */
+static void sonogram_record(t_sonogram *x)
+{
+ x->x_record=1;
+ x->x_writepos=0;
+ // post( "sonogram~ : recording on" );
+}
+
+ /* play the sonogram */
+static void sonogram_play(t_sonogram *x)
+{
+ x->x_play=1;
+ x->x_readpos=(x->x_readstart*x->x_size)/100;
+ // post( "sonogram~ : playing on" );
+}
+
+ /* setting the starting point for reading ( in percent ) */
+static void sonogram_readstart(t_sonogram *x, t_floatarg fstart)
+{
+ t_float startpoint = fstart;
+
+ if (startpoint < 0) startpoint = 0;
+ if (startpoint > 100) startpoint = 100;
+ x->x_readstart=startpoint;
+ // set readspeed sign
+ if ( ( x->x_readstart > x->x_readend ) && ( x->x_readspeed > 0 ) ) x->x_readspeed = -x->x_readspeed;
+ if ( ( x->x_readstart < x->x_readend ) && ( x->x_readspeed < 0 ) ) x->x_readspeed = -x->x_readspeed;
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete line %xREADSTART\n",
+ glist_getcanvas( x->x_glist ), x);
+ SYS_VGUI7( ".x%x.c create line %d %d %d %d -fill #FF0000 -tags %xREADSTART -width 3\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+(x->x_readstart*(x->x_size)/100 ),
+ x->x_ypos, x->x_xpos+(x->x_readstart*(x->x_size)/100 ),
+ x->x_ypos+x->x_blocksize*x->x_zoom, x );
+ }
+}
+
+ /* setting the starting point for modification ( in percent ) */
+static void sonogram_modstart(t_sonogram *x, t_floatarg fstart)
+{
+ t_float startpoint = fstart;
+
+ if (startpoint < 0) startpoint = 0;
+ if (startpoint > 100) startpoint = 100;
+ if ( startpoint > x->x_modend ) {
+ x->x_modstart = x->x_modend;
+ post( "sonogram~ : warning : range for modifications is null" );
+ } else {
+ x->x_modstart=startpoint;
+ }
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete line %xMODSTART\n",
+ glist_getcanvas( x->x_glist ), x);
+ SYS_VGUI7( ".x%x.c create line %d %d %d %d -fill #11E834 -tags %xMODSTART -width 3\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+(x->x_modstart*(x->x_size)/100 ),
+ x->x_ypos, x->x_xpos+(x->x_modstart*(x->x_size)/100 ),
+ x->x_ypos+x->x_blocksize*x->x_zoom, x );
+ }
+}
+
+ /* setting the modification step for graphical mode */
+static void sonogram_modstep(t_sonogram *x, t_floatarg fmodstep)
+{
+ if ( x->x_graphic )
+ {
+ x->x_modstep = fmodstep;
+ }
+}
+
+ /* setting enhance mode */
+static void sonogram_enhancemode(t_sonogram *x, t_floatarg fenhancemode)
+{
+ if ( x->x_graphic )
+ {
+ x->x_enhancemode = fenhancemode;
+ }
+}
+
+ /* setting the ending point for reading ( in percent ) */
+static void sonogram_readend(t_sonogram *x, t_floatarg fend)
+{
+ t_float endpoint = fend;
+
+ if (endpoint < 0) endpoint = 0;
+ if (endpoint > 100) endpoint = 100;
+ x->x_readend=endpoint;
+ // set readspeed sign
+ if ( ( x->x_readstart > x->x_readend ) && ( x->x_readspeed > 0 ) ) x->x_readspeed = -x->x_readspeed;
+ if ( ( x->x_readstart < x->x_readend ) && ( x->x_readspeed < 0 ) ) x->x_readspeed = -x->x_readspeed;
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete line %xREADEND\n",
+ glist_getcanvas( x->x_glist ), x);
+ SYS_VGUI7( ".x%x.c create line %d %d %d %d -fill #FF0000 -tags %xREADEND -width 3\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+(x->x_readend*(x->x_size)/100 ),
+ x->x_ypos, x->x_xpos+(x->x_readend*(x->x_size)/100 ),
+ x->x_ypos+x->x_blocksize*x->x_zoom, x );
+ }
+}
+
+ /* setting the ending point for modification ( in percent ) */
+static void sonogram_modend(t_sonogram *x, t_floatarg fend)
+{
+ t_float endpoint = fend;
+
+ if (endpoint < 0) endpoint = 0;
+ if (endpoint > 100) endpoint = 100;
+ if ( endpoint < x->x_modstart ) {
+ x->x_modend = x->x_modstart;
+ post( "sonogram~ : warning : range for modifications is null" );
+ } else {
+ x->x_modend=endpoint;
+ }
+ if ( x->x_graphic && glist_isvisible( x->x_glist ) )
+ {
+ SYS_VGUI3( ".x%x.c delete line %xMODEND\n",
+ glist_getcanvas( x->x_glist ), x);
+ SYS_VGUI7( ".x%x.c create line %d %d %d %d -fill #11E834 -tags %xMODEND -width 3\n",
+ glist_getcanvas( x->x_glist ), x->x_xpos+(x->x_modend*(x->x_size)/100 ),
+ x->x_ypos, x->x_xpos+(x->x_modend*(x->x_size)/100 ),
+ x->x_ypos+x->x_blocksize*x->x_zoom, x );
+ }
+}
+
+ /* sets the reading speed */
+static void sonogram_readspeed(t_sonogram *x, t_floatarg freadspeed)
+{
+ if (freadspeed <= 0 ) {
+ post( "sonogram~ : wrong readspeed argument" );
+ return;
+ }
+ x->x_readspeed=freadspeed;
+}
+
+ /* enhance frequencies */
+static void sonogram_enhance(t_sonogram *x, t_floatarg fstartfreq, t_floatarg fendfreq, t_floatarg fenhance, t_floatarg fnoupdate )
+{
+ t_int samplestart, sampleend, si, fi=0, ffi=0;
+ t_float oldenergy;
+
+ if (fstartfreq < 0 || fendfreq < 0 ||
+ fstartfreq > x->x_blocksize || fendfreq > x->x_blocksize ||
+ fstartfreq > fendfreq ) {
+ post( "sonogram~ : error : wrong frequencies range" );
+ return;
+ }
+ if ( fenhance < 0 ) {
+ post( "sonogram~ : error : wrong multiplicating factor" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ // post("enhancing portion [%d,%d]", samplestart, sampleend );
+ for ( si=samplestart; si<=sampleend; si++ ) {
+ for ( fi=(int)fstartfreq; fi<=(int)fendfreq; fi++ ) {
+ *(x->x_multfreq+fi) = fenhance;
+ if ( (fi != 0) && (fi != x->x_blocksize/2-1) )
+ {
+ /* multiply both r*sin(a) and r*cos(a) to mutiply r */
+ *(x->x_rdata+(si*x->x_blocksize)+fi) *= fenhance;
+ *(x->x_idata+(si*x->x_blocksize)+fi) *= fenhance;
+ }
+ }
+ }
+ // post( "sonogram~ : enhanced %d,%d", fi, ffi );
+ if ( !(int)fnoupdate )
+ {
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+ }
+}
+
+ /* add a constant to frequencies */
+static void sonogram_add(t_sonogram *x, t_floatarg fstartfreq, t_floatarg fendfreq, t_floatarg fadd)
+{
+ t_int samplestart, sampleend, si, fi;
+ t_float oldenergy;
+
+ if (fstartfreq < 0 || fendfreq < 0 ||
+ fstartfreq > x->x_blocksize || fendfreq > x->x_blocksize ||
+ fstartfreq > fendfreq ) {
+ post( "sonogram~ : error : wrong frequencies range" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ // post("enhancing portion [%d,%d]", samplestart, sampleend );
+ for ( si=samplestart; si<=sampleend; si++ ) {
+ for ( fi=(int)fstartfreq; fi<=(int)fendfreq; fi++ ) {
+ /* multiply both r*sin(a) and r*cos(a) to mutiply r */
+ *(x->x_rdata+(si*x->x_blocksize)+fi) += fadd;
+ *(x->x_idata+(si*x->x_blocksize)+fi) += fadd;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* resize sonogram */
+static void sonogram_resize(t_sonogram *x, t_floatarg fnewsize )
+{
+ if (fnewsize <= 0) {
+ post( "sonogram~ : error : wrong size" );
+ return;
+ }
+ if (x->x_updatechild > 0) {
+ post( "sonogram~ : can't resize now, an update is pending." );
+ return;
+ }
+ post( "sonogram~ : reallocating tables" );
+ x->x_record=0;
+ x->x_play=0;
+ sonogram_reallocate(x, x->x_size, fnewsize);
+ x->x_size = fnewsize;
+ // erase all points, as data is zero no drawing is needed
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, 0, 0, 0);
+}
+
+ /* set zoom factor */
+static void sonogram_zoom(t_sonogram *x, t_floatarg fzoom )
+{
+ post( "sonogram~: warning : zoom and big block factors might lead to a crash" );
+ if (fzoom < 1) {
+ post( "sonogram~ : error : wrong zoom factor" );
+ return;
+ }
+ if ( x->x_gifdata != NULL ) {
+ freebytes(x->x_gifdata, (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ post( "Freed %d bytes", (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ x->x_gifdata = NULL;
+ }
+ if ( x->x_guicommand != NULL ) {
+ freebytes(x->x_guicommand, 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ post( "Freed %d bytes", 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ x->x_guicommand = NULL;
+ }
+ x->x_zoom = (int)fzoom;
+ if ( !( x->x_gifdata = ( char* ) getbytes( (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return;
+ } else {
+ post( "sonogram~ : allocated %d bytes", (x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ }
+ if ( !( x->x_guicommand = ( char* ) getbytes( 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") ) ) ) {
+ post( "sonogram~ : error : could not allocate buffers" );
+ return;
+ } else {
+ post( "sonogram~ : allocated %d bytes", 128+(x->x_blocksize/2)*x->x_zoom*sizeof("#FFFFFF ") );
+ }
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, !x->x_empty, !x->x_empty, 0);
+ canvas_fixlinesfor( glist_getcanvas( x->x_glist ), (t_text*)x );
+}
+
+ /* refresh data */
+static void sonogram_refresh(t_sonogram *x)
+{
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, 0, 1, 1);
+}
+
+ /* flip frequencies */
+static void sonogram_flipfreqs(t_sonogram *x)
+{
+ t_int samplestart, sampleend, si, fi;
+ t_float fvalue;
+ t_int ioperon;
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ ioperon=x->x_blocksize/2;
+ for ( si=samplestart; si<=sampleend; si++ ) {
+ for ( fi=0; fi<=ioperon/2; fi++ ) {
+ fvalue = *(x->x_rdata+(si*x->x_blocksize)+fi);
+ *(x->x_rdata+(si*x->x_blocksize)+fi) = *(x->x_rdata+(si*x->x_blocksize)+(ioperon-fi-1));
+ *(x->x_rdata+(si*x->x_blocksize)+(ioperon-fi-1)) = fvalue;
+ fvalue = *(x->x_idata+(si*x->x_blocksize)+fi);
+ *(x->x_idata+(si*x->x_blocksize)+fi) = *(x->x_idata+(si*x->x_blocksize)+(ioperon-fi-1));
+ *(x->x_idata+(si*x->x_blocksize)+(ioperon-fi-1)) = fvalue;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* flip blocks */
+static void sonogram_flipblocks(t_sonogram *x)
+{
+ t_int samplestart, sampleend, middlesample, fi, si;
+ t_float fvalue;
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ middlesample = ( sampleend+samplestart+1 ) / 2;
+ for ( si=samplestart; si<=middlesample; si++ ) {
+ for ( fi=0; fi<x->x_blocksize; fi++ ) {
+ fvalue = *(x->x_rdata+((si)*x->x_blocksize)+fi);
+ *(x->x_rdata+((si)*x->x_blocksize)+fi) = *(x->x_rdata+((sampleend+samplestart-si)*x->x_blocksize)+fi);
+ *(x->x_rdata+((sampleend+samplestart-si)*x->x_blocksize)+fi) = fvalue;
+ fvalue = *(x->x_idata+((si)*x->x_blocksize)+fi);
+ *(x->x_idata+((si)*x->x_blocksize)+fi) = *(x->x_idata+((sampleend+samplestart-si)*x->x_blocksize)+fi);
+ *(x->x_idata+((sampleend+samplestart-si)*x->x_blocksize)+fi) = fvalue;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* undo if available */
+static void sonogram_undo(t_sonogram *x)
+{
+ t_int si,fi;
+
+ if ( x->x_uxs == -1 )
+ {
+ post( "sonogram~ : nothing to undo, man" );
+ return;
+ }
+
+ post( "sonogram~ : restoring region [%d,%d,%d,%d]", x->x_uxs, x->x_uys, x->x_uxe, x->x_uye );
+ for ( si=x->x_uxs; si<=x->x_uxe; si++ ) {
+ for ( fi=x->x_uys; fi<=x->x_uye; fi++ ) {
+ *(x->x_rdata+((si)*x->x_blocksize)+fi) = *(x->x_rudata+(si-x->x_uxs)*x->x_blocksize+(fi-x->x_uys));
+ *(x->x_idata+((si)*x->x_blocksize)+fi) = *(x->x_iudata+(si-x->x_uxs)*x->x_blocksize+(fi-x->x_uys));
+ }
+ }
+ sonogram_update_part(x, x->x_glist, x->x_uxs, x->x_uxe, 0, 1, 1);
+}
+
+ /* zswap exchanges real and imaginery part */
+static void sonogram_zswap(t_sonogram *x)
+{
+ t_int samplestart, sampleend, fi, si;
+ t_float fvalue;
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+ for ( si=samplestart; si<=sampleend; si++ ) {
+ for ( fi=0; fi<x->x_blocksize; fi++ ) {
+ fvalue = *(x->x_rdata+(si*x->x_blocksize)+fi);
+ *(x->x_rdata+(si*x->x_blocksize)+fi) = *(x->x_idata+(si*x->x_blocksize)+fi);
+ *(x->x_idata+(si*x->x_blocksize)+fi) = fvalue;
+ }
+ }
+}
+
+ /* swap points */
+static void sonogram_swappoints(t_sonogram *x, t_floatarg fnbpoints)
+{
+ t_int samplestart, sampleend, sp;
+ t_float s1, s2, f1, f2;
+ t_float fvalue;
+
+ if (fnbpoints <= 0) {
+ post( "sonogram~ : error : bad number of points" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=0; sp<fnbpoints; sp++ ) {
+ s1 = samplestart + (random()%(sampleend-samplestart));
+ s2 = samplestart + (random()%(sampleend-samplestart));
+ f1 = random()%( x->x_blocksize/2-1 );
+ f2 = random()%( x->x_blocksize/2-1 );
+ fvalue = *(x->x_rdata+((int)s1*x->x_blocksize)+(int)f1);
+ *(x->x_rdata+((int)s1*x->x_blocksize)+(int)f1) = *(x->x_rdata+((int)s2*x->x_blocksize)+(int)f2);
+ *(x->x_rdata+((int)s2*x->x_blocksize)+(int)f2) = fvalue;
+ fvalue = *(x->x_idata+((int)s1*x->x_blocksize)+(int)f1);
+ *(x->x_idata+((int)s1*x->x_blocksize)+(int)f1) = *(x->x_idata+((int)s2*x->x_blocksize)+(int)f2);
+ *(x->x_idata+((int)s2*x->x_blocksize)+(int)f2) = fvalue;
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* average blocks according to a factor */
+static void sonogram_average(t_sonogram *x, t_floatarg fnbblocks)
+{
+ t_int samplestart, sampleend, fi, si, ssi;
+ t_float fraverage, fiaverage;
+
+ if (fnbblocks < 1) {
+ post( "sonogram~ : error : bad average factor" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ fraverage=fiaverage=0.0;
+ for ( fi=0; fi<x->x_blocksize; fi++ ) {
+ for ( si=samplestart; si<=sampleend-fnbblocks; si+=fnbblocks ) {
+ fraverage=fiaverage=0.0;
+ for ( ssi=0; ssi<fnbblocks; ssi++ ) {
+ fraverage += *(x->x_rdata+((int)(si+ssi)*x->x_blocksize)+fi);
+ fiaverage += *(x->x_idata+((int)(si+ssi)*x->x_blocksize)+fi);
+ }
+ fraverage /= fnbblocks;
+ fiaverage /= fnbblocks;
+ for ( ssi=0; ssi<fnbblocks; ssi++ ) {
+ *(x->x_rdata+((int)(si+ssi)*x->x_blocksize)+fi)=fraverage;
+ *(x->x_idata+((int)(si+ssi)*x->x_blocksize)+fi)=fiaverage;
+ }
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* go up by the given number */
+static void sonogram_goup(t_sonogram *x, t_floatarg fgoup)
+{
+ t_int samplestart, sampleend, sp, sf;
+
+ if (fgoup <= 0 || fgoup > x->x_blocksize/2) {
+ post( "sonogram~ : error : wrong offset in goup function" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+ for (sf=(x->x_blocksize/2)-fgoup-1; sf>=0; sf-- ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(sf+(int)fgoup)) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+sf);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(sf+(int)fgoup)) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+sf);
+
+ }
+ for (sf=0; sf<fgoup; sf++ ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)sf) = 0.0;
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)sf) = 0.0;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* roll up by the given number */
+static void sonogram_roll(t_sonogram *x, t_floatarg froll)
+{
+ t_int samplestart, sampleend, sp, sf;
+ t_float *fprvalues;
+ t_float *fpivalues;
+
+ if (froll <= 0 || froll > x->x_blocksize/2) {
+ post( "sonogram~ : error : wrong offset in roll function" );
+ return;
+ }
+ fprvalues = (t_float*)getbytes( ((int)froll)*sizeof( float ) );
+ if ( !fprvalues ) {
+ post( "sonogram~ : error : could not allocate %d bytes", ((int)froll)*sizeof(float) );
+ return;
+ }
+ fpivalues = (t_float*)getbytes( ((int)froll)*sizeof( float ) );
+ if ( !fpivalues ) {
+ post( "sonogram~ : error : could not allocate %d bytes", ((int)froll)*sizeof(float) );
+ return;
+ }
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+
+ // saving values
+ for (sf=0; sf<froll; sf++ ) {
+ *(fprvalues+sf) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(x->x_blocksize/2-(int)froll+sf));
+ *(fpivalues+sf) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+(x->x_blocksize/2-(int)froll+sf));
+ }
+ for (sf=(x->x_blocksize/2)-froll-1; sf>=0; sf-- ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(sf+(int)froll)) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+sf);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(sf+(int)froll)) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+sf);
+ }
+ for (sf=0; sf<froll; sf++ ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)sf) = *(fprvalues+sf);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)sf) = *(fpivalues+sf);
+ }
+ }
+ freebytes( fprvalues, (int)froll*sizeof(float) );
+ freebytes( fpivalues, (int)froll*sizeof(float) );
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* suppress point below the threshold */
+static void sonogram_threshold(t_sonogram *x, t_floatarg fthreshold)
+{
+ t_int samplestart, sampleend, sp, sf;
+ t_float fspectrum;
+
+ if (fthreshold <= 0) {
+ post( "sonogram~ : error : wrong threshold" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+ for (sf=0; sf<=(x->x_blocksize/2)-1; sf++ ) {
+ fspectrum = sqrt( pow( *(x->x_rdata+sp*x->x_blocksize+sf), 2) +
+ pow( *(x->x_idata+sp*x->x_blocksize+sf), 2) );
+ if ( fspectrum < fthreshold )
+ {
+ *(x->x_rdata+sp*x->x_blocksize+sf) = 0.0;
+ *(x->x_idata+sp*x->x_blocksize+sf) = 0.0;
+ }
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* change the phase */
+static void sonogram_phase(t_sonogram *x, t_floatarg fincphase)
+{
+ if (fincphase < 0 || fincphase > 90) {
+ post( "sonogram~ : error : wrong phase in phase function : out of [0,90]" );
+ return;
+ }
+ x->x_phase = fincphase;
+}
+
+ /* go down by the given number */
+static void sonogram_godown(t_sonogram *x, t_floatarg fgodown)
+{
+ t_int samplestart, sampleend, sp, sf;
+
+ if (fgodown <= 0 || fgodown > x->x_blocksize/2) {
+ post( "sonogram~ : error : wrong offset in godown function" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+ for (sf=0; sf<=(x->x_blocksize/2)-fgodown-1; sf++ ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+sf) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(sf+(int)fgodown));
+ *(x->x_idata+((int)sp*x->x_blocksize)+sf) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+(sf+(int)fgodown));
+ }
+ for (sf=(x->x_blocksize/2)-fgodown; sf<(x->x_blocksize/2); sf++ ) {
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)sf) = 0.0;
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)sf) = 0.0;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+ /* swap blocks */
+static void sonogram_swapblocks(t_sonogram *x, t_floatarg fperstart, t_floatarg fperend, t_floatarg fpersize)
+{
+ t_int samplestart, samplestartb, samplesize, sp, sf;
+ t_int iperstart, iperend, ipersize;
+ t_float s1, s2;
+ t_float fvalue;
+
+ iperstart = fperstart;
+ iperend = fperend;
+ ipersize = fpersize;
+
+ if (iperstart < 0 || iperstart > iperend ||
+ iperend <= 0 || iperend+ipersize > 100 ||
+ ipersize < 0 || fpersize > 100 ) {
+ post( "sonogram~ : error : wrong interval [%d%%, %d%%] <-> [%d%%, %d%%]",
+ iperstart, iperstart+ipersize, iperend, iperend+ipersize );
+ return;
+ }
+
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ samplestartb=(x->x_modend*(x->x_size-1))/100;
+ samplesize=((samplestartb-samplestart)*ipersize)/100;
+ samplestart=samplestart+((samplestartb-samplestart)*iperstart)/100;
+ samplestartb=samplestart+((samplestartb-samplestart)*iperend)/100;
+
+ post( "swap blocks [%d,%d] and [%d,%d]", samplestart, samplestart+samplesize, samplestartb, samplestartb+samplesize );
+
+ for ( sp=samplesize; sp>=0; sp-- ) {
+ for ( sf=0; sf<x->x_blocksize; sf++) {
+ fvalue = *(x->x_rdata+((int)(samplestart+sp)*x->x_blocksize)+sf);
+ *(x->x_rdata+((int)(samplestart+sp)*x->x_blocksize)+sf) = *(x->x_rdata+((int)(samplestartb+sp)*x->x_blocksize)+sf);
+ *(x->x_rdata+((int)(samplestartb+sp)*x->x_blocksize)+sf) = fvalue;
+ fvalue = *(x->x_idata+((int)(samplestart+sp)*x->x_blocksize)+sf);
+ *(x->x_idata+((int)(samplestart+sp)*x->x_blocksize)+sf) = *(x->x_idata+((int)(samplestartb+sp)*x->x_blocksize)+sf);
+ *(x->x_idata+((int)(samplestartb+sp)*x->x_blocksize)+sf) = fvalue;
+ }
+ }
+ sonogram_update_part(x, x->x_glist, 0, x->x_size-1, 0, 1, 1);
+}
+
+ /* swap frequencies */
+static void sonogram_swapfreqs(t_sonogram *x, t_floatarg ffirstfreq, t_floatarg fsecondfreq)
+{
+ t_int samplestart, sampleend, sp;
+ t_float fvalue;
+
+ if (ffirstfreq < 0 || fsecondfreq <0) {
+ post( "sonogram~ : error : wrong frequencies" );
+ return;
+ }
+ samplestart=(x->x_modstart*(x->x_size-1))/100;
+ sampleend=(x->x_modend*(x->x_size-1))/100;
+
+ for ( sp=samplestart; sp<=sampleend; sp++ ) {
+ fvalue = *(x->x_rdata+((int)sp*x->x_blocksize)+(int)ffirstfreq);
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)ffirstfreq) =
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)fsecondfreq);
+ *(x->x_rdata+((int)sp*x->x_blocksize)+(int)fsecondfreq) = fvalue;
+ fvalue = *(x->x_idata+((int)sp*x->x_blocksize)+(int)ffirstfreq);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)ffirstfreq) =
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)fsecondfreq);
+ *(x->x_idata+((int)sp*x->x_blocksize)+(int)fsecondfreq) = fvalue;
+ }
+ sonogram_update_part(x, x->x_glist, samplestart, sampleend, 0, 1, 1);
+}
+
+static void *sonogram_new(t_floatarg fsize, t_floatarg fgraphic, t_floatarg fphaso)
+{
+ t_sonogram *x = (t_sonogram *)pd_new(sonogram_class);
+ outlet_new(&x->x_obj, &s_signal);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_recend = outlet_new(&x->x_obj, &s_bang );
+ x->x_end = outlet_new(&x->x_obj, &s_bang );
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("readstart"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("readend"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("modstart"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("modend"));
+
+ if ( fsize <= 0 || ( fgraphic != 0 && fgraphic != 1 ) || ( fphaso != 0 && fphaso != 1 ) ) {
+ error( "sonogram~ : missing or negative creation arguments" );
+ return NULL;
+ }
+
+ // activate graphical callbacks
+ if ( fgraphic != 0 )
+ {
+ class_setwidget(sonogram_class, &sonogram_widgetbehavior);
+ }
+ x->x_graphic = (int) fgraphic;
+ x->x_phaso = (int) fphaso;
+
+ x->x_size = fsize;
+ x->x_blocksize = sys_getblksize();
+ x->x_play = 0;
+ x->x_readspeed = 1.;
+ x->x_record = 0;
+ x->x_readpos = 0.;
+ x->x_writepos = 0;
+ x->x_modstart = 0;
+ x->x_readstart = 0;
+ x->x_modend = 100;
+ x->x_readend = 100;
+ x->x_rdata = NULL;
+ x->x_idata = NULL;
+ x->x_phase = 0.0;
+ x->x_empty = 1;
+ x->x_xpos = -1;
+ x->x_ypos = -1;
+ x->x_samplerate = sys_getsr();
+ /* graphic data */
+ x->x_selected = 0;
+ x->x_zoom = 1;
+ x->x_updatechild = 0;
+ x->x_modstep = 1.1;
+ x->x_enhancemode = 0;
+ x->x_glist = (t_glist*)canvas_getcurrent();
+
+ if ( sonogram_allocate(x) <0 ) {
+ return NULL;
+ } else {
+ return(x);
+ }
+
+}
+
+void sonogram_tilde_setup(void)
+{
+ post(sonogram_version);
+ sonogram_class = class_new(gensym("sonogram~"), (t_newmethod)sonogram_new, (t_method)sonogram_free,
+ sizeof(t_sonogram), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_sethelpsymbol( sonogram_class, gensym("help-sonogram~.pd") );
+
+ // set callbacks
+ sonogram_widgetbehavior.w_getrectfn = sonogram_getrect;
+ sonogram_widgetbehavior.w_displacefn = sonogram_displace;
+ sonogram_widgetbehavior.w_selectfn = sonogram_select;
+ sonogram_widgetbehavior.w_activatefn = NULL;
+ sonogram_widgetbehavior.w_deletefn = sonogram_delete;
+ sonogram_widgetbehavior.w_visfn = sonogram_vis;
+ sonogram_widgetbehavior.w_clickfn = sonogram_click;
+ sonogram_widgetbehavior.w_propertiesfn = NULL;
+ sonogram_widgetbehavior.w_savefn = sonogram_save;
+
+ CLASS_MAINSIGNALIN( sonogram_class, t_sonogram, x_f );
+ class_addmethod(sonogram_class, (t_method)sonogram_dsp, gensym("dsp"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_record, gensym("record"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_enhance, gensym("enhance"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_add, gensym("add"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_resize, gensym("resize"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_zoom, gensym("zoom"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_swappoints, gensym("swappoints"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_average, gensym("average"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_swapblocks, gensym("swapblocks"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_swapfreqs, gensym("swapfreqs"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_flipfreqs, gensym("flipfreqs"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_flipblocks, gensym("flipblocks"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_play, gensym("play"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_refresh, gensym("refresh"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_enhancemode, gensym("enhancemode"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_goup, gensym("goup"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_godown, gensym("godown"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_roll, gensym("roll"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_threshold, gensym("threshold"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_phase, gensym("phase"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_zswap, gensym("zswap"), A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_modstep, gensym("modstep"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_modstart, gensym("modstart"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_modend, gensym("modend"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_readstart, gensym("readstart"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_readend, gensym("readend"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_readspeed, gensym("readspeed"), A_FLOAT, A_NULL);
+ class_addmethod(sonogram_class, (t_method)sonogram_undo, gensym("undo"), A_NULL);
+}
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);
+}
+
diff --git a/spigot~/CHANGES.LOG b/spigot~/CHANGES.LOG
new file mode 100644
index 0000000..153fb0a
--- /dev/null
+++ b/spigot~/CHANGES.LOG
@@ -0,0 +1,2 @@
+0.1
+ First implementation
diff --git a/spigot~/INSTALL b/spigot~/INSTALL
new file mode 100644
index 0000000..d8c07c9
--- /dev/null
+++ b/spigot~/INSTALL
@@ -0,0 +1,15 @@
+untar in /my/pd/dir/externs
+
+cd /my/pd/dir/externs/spigot~
+
+make clean
+
+make
+
+make install
+
+open help-spigot~.pd
+
+Thanx for getting here.
+Yves/
+comments and bugs @ ydegoyon@free.fr
diff --git a/spigot~/Makefile b/spigot~/Makefile
new file mode 100644
index 0000000..72ac0eb
--- /dev/null
+++ b/spigot~/Makefile
@@ -0,0 +1,97 @@
+NAME=spigot~
+CSYM=spigot_tilde
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).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
+
+.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
+
+.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
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -DUNIX -DICECAST -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
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o ../$*.pd_linux
+ ln -s $*/$*.pd_linux ..
+
+# ----------------------- Mac OSX -----------------------
+
+pd_darwin: $(NAME).pd_darwin
+
+.SUFFIXES: .pd_darwin
+
+DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+.c.pd_darwin:
+ cc $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ cc -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
+ rm -f $*.o ../$*.pd_darwin
+ ln -s $*/$*.pd_darwin ..
+
+# ----------------------------------------------------------
+
+install:
+ cp help-*.pd ../../doc/5.reference
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/spigot~/README b/spigot~/README
new file mode 100644
index 0000000..5de8d8d
--- /dev/null
+++ b/spigot~/README
@@ -0,0 +1,21 @@
+*****************************************************************************
+
+Version 0.1
+copyleft 2001 by Yves Degoyon
+tarballs and updates available @ http://ydegoyon.free.fr
+
+spigot~ : a signal router.
+
+To install spigot~, 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.
+
+*****************************************************************************
+
+
diff --git a/spigot~/help-spigot~.pd b/spigot~/help-spigot~.pd
new file mode 100644
index 0000000..eb7f0eb
--- /dev/null
+++ b/spigot~/help-spigot~.pd
@@ -0,0 +1,14 @@
+#N canvas 172 55 627 444 10;
+#X obj 151 163 dac~;
+#X obj 150 127 spigot~;
+#X text 232 50 spigot~ sends its signal to its right or left outlet
+;
+#X text 232 65 according to the state of the toggle;
+#X obj 199 101 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0
+1;
+#X obj 108 74 osc~ 233;
+#X text 237 148 bugs and comments @ ydegoyon@free.fr;
+#X connect 1 0 0 0;
+#X connect 1 1 0 1;
+#X connect 4 0 1 1;
+#X connect 5 0 1 0;
diff --git a/spigot~/spigot~.c b/spigot~/spigot~.c
new file mode 100644
index 0000000..934db00
--- /dev/null
+++ b/spigot~/spigot~.c
@@ -0,0 +1,75 @@
+/* spigot~ -- route a signal to its right or left output */
+
+/* Copyleft 2001 Yves Degoyon.
+Permission is granted to use this software for any purpose provided you
+keep this copyright notice intact.
+
+THE AUTHOR AND HIS EXPLOITERS MAKE NO WARRANTY, EXPRESS OR IMPLIED,
+IN CONNECTION WITH THIS SOFTWARE.
+
+*/
+
+#include "m_pd.h"
+
+typedef struct _spigot
+{
+ t_object x_obj;
+ t_int x_on;
+ t_float x_f;
+} t_spigot;
+
+static t_class *spigot_class;
+
+static char *spigot_version = "spigot~: a signal router : version 0.1, written by Yves Degoyon (ydegoyon@free.fr)";
+
+static void *spigot_new(void)
+{
+ t_spigot *x = (t_spigot *)pd_new(spigot_class);
+ x->x_on = 0;
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("seton") );
+ outlet_new(&x->x_obj, &s_signal);
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+static t_int *spigot_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *outr = (t_float *)(w[2]);
+ t_float *outl = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ t_spigot* x = (t_spigot*)(w[5]);
+ while (n--) {
+ if ( (x->x_on)==0.0 ) {
+ *(outl)=0.0;
+ *(outr)=*(in);
+ } else {
+ *(outl)=*(in);
+ *(outr)=0.0;
+ }
+ in++;outl++;outr++;
+ }
+ return (w+6);
+}
+
+static void spigot_dsp(t_spigot *x, t_signal **sp)
+{
+ dsp_add(spigot_perform, 5, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
+ sp[0]->s_n, x);
+}
+
+static void spigot_set(t_spigot *x, t_float f)
+{
+ x->x_on=f;
+}
+
+void spigot_tilde_setup(void)
+{
+ post ( spigot_version );
+ spigot_class = class_new(gensym("spigot~"), (t_newmethod)spigot_new, 0,
+ sizeof(t_spigot), 0, 0);
+ CLASS_MAINSIGNALIN( spigot_class, t_spigot, x_f );
+ class_sethelpsymbol(spigot_class, gensym("help-spigot~.pd"));
+ class_addmethod(spigot_class, (t_method)spigot_dsp, gensym("dsp"), 0);
+ class_addmethod(spigot_class, (t_method)spigot_set, gensym("seton"), A_FLOAT, 0);
+}
diff --git a/stkdrone~/INSTALL b/stkdrone~/INSTALL
new file mode 100644
index 0000000..6eaaff0
--- /dev/null
+++ b/stkdrone~/INSTALL
@@ -0,0 +1,13 @@
+install STK in /usr/local/stk
+or change STK paths in the makefile
+to your STK's location.
+
+untar in /my/pd/dir/externs
+
+cd /my/pd/dir/externs/stkdrone~
+
+make
+
+make install
+
+open help-stkdrone~.pd
diff --git a/stkdrone~/Makefile b/stkdrone~/Makefile
new file mode 100644
index 0000000..5e621b0
--- /dev/null
+++ b/stkdrone~/Makefile
@@ -0,0 +1,33 @@
+NAME=stkdrone~
+CSYM=stkdrone_tilde
+STK_HOME=/usr/local/stk-3.2
+
+current: pd_linux
+
+pd_linux: $(NAME).pd_linux
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+LINUXCCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch -g
+
+LINUXINCLUDE = -I../../src -I/usr/local/include
+
+.cc.pd_linux: drone.o
+ g++ -O3 -Wall -D__OS_Linux_ -g -I$(STK_HOME)/include -c drone.cc
+ g++ $(LINUXCCFLAGS) $(LINUXINCLUDE) -I$(STK_HOME)/include -o $*.o -c $*.cc
+ ld -export_dynamic -shared -o $*.pd_linux *.o $(STK_HOME)/src/stklib.a -lc -lm -lstdc++ -lg++
+ strip --strip-unneeded $*.pd_linux
+ rm -f *.o ../$*.pd_linux
+ ln -s $*/$*.pd_linux ..
+
+clean:
+ rm -f *.o *.pd_* so_locations
+
+install:
+ cp help-*.pd *-freqs ../../doc/5.reference
diff --git a/stkdrone~/README b/stkdrone~/README
new file mode 100644
index 0000000..8ccb16c
--- /dev/null
+++ b/stkdrone~/README
@@ -0,0 +1,20 @@
+*****************************************************************************
+Version 0.01
+embedding Perry Cook's ragamatic in Pure Data
+copyright 2001 by Perry Cook
+copyleft 2001 by Yves Degoyon
+tarballs and updates available @ http://ydegoyon.free.fr
+
+stkdrone~ : embeds STK drone simulation in Pure Data.
+
+To install stkdrone~, 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.
+
+*****************************************************************************
diff --git a/stkdrone~/drone-freqs b/stkdrone~/drone-freqs
new file mode 100644
index 0000000..12f1a85
--- /dev/null
+++ b/stkdrone~/drone-freqs
@@ -0,0 +1,46 @@
+55.0;
+82.5;
+55.0;
+220.0;
+82.5;
+82.5;
+82.5;
+220.0;
+220.0;
+82.5;
+220.0;
+220.0;
+55.0;
+82.5;
+55.0;
+55.0;
+220.0;
+220.0;
+220.0;
+55.0;
+82.5;
+82.5;
+220.0;
+55.0;
+55.0;
+220.0;
+82.5;
+82.5;
+55.0;
+82.5;
+82.5;
+220.0;
+220.0;
+82.5;
+55.0;
+55.0;
+55.0;
+220.0;
+220.0;
+82.5;
+220.0;
+82.5;
+82.5;
+82.5;
+82.5;
+82.5;
diff --git a/stkdrone~/drone.cc b/stkdrone~/drone.cc
new file mode 100644
index 0000000..ba065ad
--- /dev/null
+++ b/stkdrone~/drone.cc
@@ -0,0 +1,77 @@
+ /******************************************/
+/* Karplus-Strong drone string model */
+/* by Perry Cook, 1995-96 */
+/* */
+/* There exist at least two patents, */
+/* assigned to Stanford, bearing the */
+/* names of Karplus and/or Strong. */
+/******************************************/
+
+#include "drone.h"
+
+drone :: drone(MY_FLOAT lowestFreq)
+{
+ length = (long) (SRATE / lowestFreq + 1);
+ loopGain = (MY_FLOAT) 0.999;
+ loopFilt = new OneZero();
+ delayLine = new DLineA(length);
+ envelope = new ADSR();
+ noise = new Noise;
+ envelope->setAllTimes(2.0,0.5,0.0,0.5);
+ this->clear();
+}
+
+drone :: ~drone()
+{
+ delete loopFilt;
+ delete delayLine;
+ delete envelope;
+ delete noise;
+}
+
+void drone :: clear()
+{
+ loopFilt->clear();
+ delayLine->clear();
+}
+
+void drone :: setFreq(MY_FLOAT frequency)
+{
+ MY_FLOAT delay;
+ delay = (SRATE / frequency);
+ delayLine->setDelay(delay - 0.5);
+ loopGain = (MY_FLOAT) 0.997 + (frequency * (MY_FLOAT) 0.000002);
+ if (loopGain>1.0) loopGain = (MY_FLOAT) 0.99999;
+}
+
+void drone :: pluck(MY_FLOAT amplitude)
+{
+ envelope->keyOn();
+}
+
+void drone :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
+{
+ this->setFreq(freq);
+ this->pluck(amp);
+#if defined(_debug_)
+ printf("drone : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
+#endif
+}
+
+void drone :: noteOff(MY_FLOAT amp)
+{
+ loopGain = (MY_FLOAT) 1.0 - amp;
+#if defined(_debug_)
+ printf("drone : NoteOff: Amp=%lf\n",amp);
+#endif
+}
+
+MY_FLOAT drone :: tick()
+{
+ /* check this out */
+ /* here's the whole inner loop of the instrument!! */
+ lastOutput = delayLine->tick(loopFilt->tick((delayLine->lastOut() * loopGain))
+ + (0.005 * envelope->tick() * noise->tick()));
+ return lastOutput;
+}
+
diff --git a/stkdrone~/drone.h b/stkdrone~/drone.h
new file mode 100644
index 0000000..c5f7a0d
--- /dev/null
+++ b/stkdrone~/drone.h
@@ -0,0 +1,40 @@
+/******************************************/
+/* Karplus-Strong drone string model */
+/* by Perry Cook, 1995-96 */
+/* */
+/* There exist at least two patents, */
+/* assigned to Stanford, bearing the */
+/* names of Karplus and/or Strong. */
+/******************************************/
+
+#if !defined(__drone_h)
+#define __drone_h
+
+#include "Instrmnt.h"
+#include "DLineA.h"
+#include "OneZero.h"
+#include "ADSR.h"
+#include "Noise.h"
+
+class drone : public Instrmnt
+{
+protected:
+ DLineA *delayLine;
+ ADSR *envelope;
+ Noise *noise;
+ OneZero *loopFilt;
+ long length;
+ MY_FLOAT loopGain;
+public:
+ drone(MY_FLOAT lowestFreq);
+ ~drone();
+ void clear();
+ virtual void setFreq(MY_FLOAT frequency);
+ void pluck(MY_FLOAT amplitude);
+ virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
+ virtual void noteOff(MY_FLOAT amp);
+ virtual MY_FLOAT tick();
+};
+
+#endif
+
diff --git a/stkdrone~/help-stkdrone~.pd b/stkdrone~/help-stkdrone~.pd
new file mode 100644
index 0000000..a65624b
--- /dev/null
+++ b/stkdrone~/help-stkdrone~.pd
@@ -0,0 +1,75 @@
+#N canvas 168 23 784 529 10;
+#X obj 112 311 dac~;
+#X obj 115 248 stkdrone~;
+#X obj 114 278 *~;
+#X floatatom 147 278 5 0 0;
+#X msg 162 172 stop;
+#X floatatom 197 201 5 0 0;
+#X floatatom 238 248 5 5 35;
+#X text 247 335 stkdrone~ : Object to embed stk-based drone synthesis
+;
+#X text 247 360 Comments and bugs @ ydegoyon@free.fr;
+#X msg 113 346 \; pd dsp 1;
+#X msg 179 346 \; pd dsp 0;
+#X msg 24 34 bang;
+#X msg 93 99 play;
+#X msg 113 173 play;
+#X obj 195 248 / 100;
+#X text 276 279 Master level;
+#X obj 23 99 metro 2000;
+#X floatatom 52 75 5 0 0;
+#X obj 134 78 / 1000;
+#X obj 134 98 + 0.05;
+#X floatatom 182 98 5 0 0;
+#X obj 217 278 loadbang;
+#X text 301 258 ( min=0.05 \, max=0.35 \, default = 0.25 );
+#X text 303 248 Strength of plucking;
+#X text 241 195 Frequency;
+#X obj 231 77 qlist;
+#X msg 274 76 read drone-freqs;
+#X msg 231 55 next;
+#X msg 274 55 rewind;
+#X text 247 348 Originally written by Perry Cook for STK/ragamatic
+;
+#X obj 386 76 loadbang;
+#X msg 189 278 40;
+#X obj 24 75 + 0;
+#X text 21 12 Ready for meditation ??;
+#X text 240 398 And now another message from Nancy Reagan : "Drugs
+destroy your brain";
+#X text 239 205 ( min=50Hz \, default=250 Hz );
+#X obj 134 59 random 100;
+#X obj 24 56 random 1000;
+#X floatatom 98 27 5 0 0;
+#X connect 1 0 2 0;
+#X connect 2 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 2 1;
+#X connect 4 0 1 0;
+#X connect 5 0 1 1;
+#X connect 6 0 14 0;
+#X connect 11 0 16 0;
+#X connect 11 0 37 0;
+#X connect 12 0 1 0;
+#X connect 13 0 1 0;
+#X connect 14 0 1 2;
+#X connect 16 0 12 0;
+#X connect 16 0 27 0;
+#X connect 16 0 36 0;
+#X connect 16 0 37 0;
+#X connect 17 0 16 1;
+#X connect 18 0 19 0;
+#X connect 19 0 20 0;
+#X connect 19 0 1 2;
+#X connect 21 0 31 0;
+#X connect 25 0 5 0;
+#X connect 25 1 28 0;
+#X connect 26 0 25 0;
+#X connect 27 0 25 0;
+#X connect 28 0 25 0;
+#X connect 30 0 26 0;
+#X connect 31 0 3 0;
+#X connect 32 0 17 0;
+#X connect 36 0 18 0;
+#X connect 37 0 32 0;
+#X connect 38 0 37 1;
diff --git a/stkdrone~/stkdrone~.cc b/stkdrone~/stkdrone~.cc
new file mode 100644
index 0000000..75ddafc
--- /dev/null
+++ b/stkdrone~/stkdrone~.cc
@@ -0,0 +1,119 @@
+/* stkdrone~ -- STK-based drone synthesis
+ * requires STK library
+ * Copyleft 2001 Yves Degoyon.
+ * Permission is granted to use this software for any purpose provided you
+ * keep this copyright notice intact.
+ *
+ * THE AUTHOR AND HIS EXPLOITERS MAKE NO WARRANTY, EXPRESS OR IMPLIED,
+ * IN CONNECTION WITH THIS SOFTWARE.
+ *
+*/
+
+#include "m_pd.h"
+#include "drone.h"
+
+#define DEFAULT_FREQ 250.0
+#define DEFAULT_PLUCK 0.25
+
+typedef struct _stkdrone
+{
+ t_object x_obj;
+ drone *x_stkdrone;
+ t_int x_on;
+ t_float x_freq;
+ t_float x_pluck;
+} t_stkdrone;
+
+static t_class *stkdrone_class;
+
+static void *stkdrone_new(void)
+{
+ t_stkdrone *x = (t_stkdrone *)pd_new(stkdrone_class);
+ x->x_freq = DEFAULT_FREQ;
+ x->x_pluck = DEFAULT_PLUCK;
+ outlet_new(&x->x_obj, &s_signal);
+ inlet_new( &x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("freq") );
+ inlet_new( &x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("pluck") );
+ if( (x->x_stkdrone = new drone( 50.0 )) == NULL ) {
+ post( "stkdrone~: cannot build drone instrument from STK" );
+ return NULL;
+ } else {
+ return (x);
+ }
+}
+
+static void stkdrone_freq(t_stkdrone* x, t_float ffreq)
+{
+ if ( ffreq < 50.0 )
+ {
+ post("stkdrone~ : wrong frequency" );
+ return;
+ }
+ x->x_stkdrone->setFreq( (MY_FLOAT) ffreq );
+ x->x_freq = ffreq;
+}
+
+static void stkdrone_pluck(t_stkdrone* x, t_float fpluck)
+{
+ if ( fpluck < 0.05 || fpluck > 0.35 )
+ {
+ post("stkdrone~ : wrong pluck argument" );
+ return;
+ }
+ x->x_stkdrone->pluck( (MY_FLOAT) fpluck );
+ x->x_pluck = fpluck;
+}
+
+static void stkdrone_play(t_stkdrone* x)
+{
+ x->x_on = 1; // activate sound
+ x->x_stkdrone->noteOn( x->x_freq, x->x_pluck ); // start sound
+}
+
+static void stkdrone_stop(t_stkdrone* x)
+{
+ x->x_on = 0; // deactivate sound
+}
+
+static t_int *stkdrone_perform(t_int *w)
+{
+ t_float *out = (t_float *)(w[1]);
+ int n = (int)(w[2]);
+ t_stkdrone* x = (t_stkdrone*)(w[3]);
+
+ while ( n-- )
+ {
+ if ( x->x_on )
+ {
+ double dare;
+
+ dare = (float)x->x_stkdrone->tick();
+ // post( "synthesis : %f", dare );
+ *out=dare;
+ }
+ else
+ {
+ *(out) = 0.0;
+ }
+ out++;
+ }
+
+ return (w+4);
+}
+
+static void stkdrone_dsp(t_stkdrone *x, t_signal **sp)
+{
+ dsp_add(stkdrone_perform, 3, sp[0]->s_vec, sp[0]->s_n, x);
+}
+
+extern "C" void stkdrone_tilde_setup(void)
+{
+ stkdrone_class = class_new(gensym("stkdrone~"), (t_newmethod)stkdrone_new, 0,
+ sizeof(t_stkdrone), 0, A_NULL);
+ class_sethelpsymbol(stkdrone_class, gensym("help-stkdrone~.pd") );
+ class_addmethod(stkdrone_class, (t_method)stkdrone_dsp, gensym("dsp"), A_NULL);
+ class_addmethod(stkdrone_class, (t_method)stkdrone_play, gensym("play") , A_NULL);
+ class_addmethod(stkdrone_class, (t_method)stkdrone_stop, gensym("stop") , A_NULL);
+ class_addmethod(stkdrone_class, (t_method)stkdrone_freq, gensym("freq") , A_DEFFLOAT, A_NULL);
+ class_addmethod(stkdrone_class, (t_method)stkdrone_pluck, gensym("pluck") , A_DEFFLOAT, A_NULL);
+}
diff --git a/stksitar~/INSTALL b/stksitar~/INSTALL
new file mode 100644
index 0000000..09c76b3
--- /dev/null
+++ b/stksitar~/INSTALL
@@ -0,0 +1,13 @@
+install STK in /usr/local/stk
+or change STK paths in the makefile
+to your STK's location.
+
+untar in /my/pd/dir/externs
+
+cd /my/pd/dir/externs/stksitar~
+
+make
+
+make install
+
+open help-stksitar~.pd
diff --git a/stksitar~/Makefile b/stksitar~/Makefile
new file mode 100644
index 0000000..5314a78
--- /dev/null
+++ b/stksitar~/Makefile
@@ -0,0 +1,37 @@
+NAME=stksitar~
+CSYM=stksitar_tilde
+STK_HOME=/usr/local/stk
+
+current: pd_linux
+
+pd_linux: $(NAME).pd_linux
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+LINUXCCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch -g
+
+LINUXINCLUDE = -I../../src -I/usr/local/include
+
+.cc.pd_linux: sitar.o
+ g++ -O3 -Wall -D__OS_Linux_ -g -I$(STK_HOME)/include -c sitar.cc
+ g++ $(LINUXCCFLAGS) $(LINUXINCLUDE) -I$(STK_HOME)/include -o $*.o -c $*.cc
+ ld -export_dynamic -shared -o $*.pd_linux *.o $(STK_HOME)/src/stklib.a -lc -lm -lstdc++ -lg++
+ #strip --strip-unneeded $*.pd_linux
+ rm -f *.o ../$*.pd_linux
+ ln -s $*/$*.pd_linux ..
+
+test:
+ g++ -O3 -Wall -D__OS_Linux_ -g -I$(STK_HOME)/include -c sitar.cc
+ g++ -O3 -Wall -D__OS_Linux_ -g -I$(STK_HOME)/include -o mstksitar~ sitar.o $(STK_HOME)/src/stklib.a mstksitar~.cc
+
+clean:
+ rm -f *.o *.pd_* so_locations
+
+install:
+ cp help-*.pd *-freqs ../../doc/5.reference
diff --git a/stksitar~/README b/stksitar~/README
new file mode 100644
index 0000000..bb3db3d
--- /dev/null
+++ b/stksitar~/README
@@ -0,0 +1,22 @@
+*****************************************************************************
+Version 0.01
+embedding Perry Cook's ragamatic in Pure Data
+copyright 2001 by Perry Cook
+copyleft 2001 by Yves Degoyon
+tarballs and updates available @ http://ydegoyon.free.fr
+
+stksitar~ : embeds STK sitar simulation in Pure Data.
+
+To install stksitar~, 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.
+
+*****************************************************************************
+
+
diff --git a/stksitar~/help-stksitar~.pd b/stksitar~/help-stksitar~.pd
new file mode 100644
index 0000000..986edd0
--- /dev/null
+++ b/stksitar~/help-stksitar~.pd
@@ -0,0 +1,73 @@
+#N canvas 33 1 784 529 10;
+#X obj 112 311 dac~;
+#X obj 115 248 stksitar~;
+#X obj 114 278 *~;
+#X floatatom 147 278 5 0 0;
+#X msg 162 172 stop;
+#X floatatom 196 200 5 52 100000;
+#X floatatom 238 248 5 5 35;
+#X text 247 335 stksitar~ : Object to embed stk-based sitar synthesis
+;
+#X text 247 360 Comments and bugs @ ydegoyon@free.fr;
+#X msg 113 346 \; pd dsp 1;
+#X msg 179 346 \; pd dsp 0;
+#X msg 24 34 bang;
+#X msg 93 99 play;
+#X msg 113 173 play;
+#X obj 195 248 / 100;
+#X text 276 279 Master level;
+#X obj 23 99 metro 2000;
+#X floatatom 52 75 5 0 0;
+#X obj 134 78 / 1000;
+#X obj 134 98 + 0.05;
+#X floatatom 182 98 5 0 0;
+#X obj 217 278 loadbang;
+#X text 301 258 ( min=0.05 \, max=0.35 \, default = 0.25 );
+#X text 303 248 Strength of plucking;
+#X text 239 205 ( min=52Hz \, default=250 Hz );
+#X text 241 195 Frequency;
+#X obj 231 77 qlist;
+#X msg 274 76 read sitar-freqs;
+#X msg 231 55 next;
+#X msg 274 55 rewind;
+#X text 247 348 Originally written by Perry Cook for STK/ragamatic
+;
+#X obj 386 76 loadbang;
+#X msg 189 278 40;
+#X obj 24 75 + 0;
+#X text 21 12 Ready for meditation ??;
+#X text 240 398 And now another message from Nancy Reagan : "Drugs
+destroy your brain";
+#X obj 134 59 random 200;
+#X obj 24 57 random 1000;
+#X connect 1 0 2 0;
+#X connect 2 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 2 1;
+#X connect 4 0 1 0;
+#X connect 5 0 1 1;
+#X connect 6 0 14 0;
+#X connect 11 0 16 0;
+#X connect 11 0 37 0;
+#X connect 12 0 1 0;
+#X connect 13 0 1 0;
+#X connect 14 0 1 2;
+#X connect 16 0 12 0;
+#X connect 16 0 28 0;
+#X connect 16 0 36 0;
+#X connect 16 0 37 0;
+#X connect 17 0 16 1;
+#X connect 18 0 19 0;
+#X connect 19 0 20 0;
+#X connect 19 0 1 2;
+#X connect 21 0 32 0;
+#X connect 26 0 5 0;
+#X connect 26 1 29 0;
+#X connect 27 0 26 0;
+#X connect 28 0 26 0;
+#X connect 29 0 26 0;
+#X connect 31 0 27 0;
+#X connect 32 0 3 0;
+#X connect 33 0 17 0;
+#X connect 36 0 18 0;
+#X connect 37 0 33 0;
diff --git a/stksitar~/mstksitar~.cc b/stksitar~/mstksitar~.cc
new file mode 100644
index 0000000..62edef6
--- /dev/null
+++ b/stksitar~/mstksitar~.cc
@@ -0,0 +1,39 @@
+/* stksitar~ -- apply a stksitar effect
+ * requires libDSP library
+ * Copyleft 2001 Yves Degoyon.
+ * Permission is granted to use this software for any purpose provided you
+ * keep this copyright notice intact.
+ *
+ * THE AUTHOR AND HIS EXPLOITERS MAKE NO WARRANTY, EXPRESS OR IMPLIED,
+ * IN CONNECTION WITH THIS SOFTWARE.
+ *
+*/
+
+#include "sitar.h"
+#include "unistd.h"
+#include "RtWvOut.h"
+
+sitar *x_stksitar = NULL;
+
+int main( int argc, char** argv )
+{
+
+ // int count=0;
+
+ x_stksitar = new sitar( 50.0 );
+ if ( x_stksitar == NULL )
+ {
+ printf( "mstksitar~: cannot build sitar instrument from STK" );
+ exit(-1);
+ }
+
+ x_stksitar->noteOn( 400.0, 0.25 ); // start sound
+ while (1)
+ {
+ double dare;
+
+ dare = (float) x_stksitar->tick();
+ printf( "%f\n", dare );
+ fwrite( (void*)&dare, sizeof(float), 1, stderr );
+ }
+}
diff --git a/stksitar~/sitar-freqs b/stksitar~/sitar-freqs
new file mode 100644
index 0000000..d8c6fd8
--- /dev/null
+++ b/stksitar~/sitar-freqs
@@ -0,0 +1,166 @@
+329.630000;
+349.230000;
+415.300000;
+440.000000;
+329.630000;
+329.630000;
+293.660000;
+293.660000;
+329.630000;
+261.630000;
+261.630000;
+261.630000;
+293.660000;
+329.630000;
+329.630000;
+293.660000;
+261.630000;
+293.660000;
+329.630000;
+349.230000;
+329.630000;
+293.660000;
+329.630000;
+329.630000;
+349.230000;
+349.230000;
+415.300000;
+415.300000;
+349.230000;
+329.630000;
+349.230000;
+415.300000;
+440.000000;
+440.000000;
+493.880000;
+349.230000;
+261.630000;
+293.660000;
+329.630000;
+349.230000;
+329.630000;
+329.630000;
+329.630000;
+329.630000;
+293.660000;
+261.630000;
+293.660000;
+261.630000;
+293.660000;
+261.630000;
+293.660000;
+329.630000;
+349.230000;
+415.300000;
+349.230000;
+415.300000;
+415.300000;
+440.000000;
+493.880000;
+440.000000;
+349.230000;
+415.300000;
+440.000000;
+440.000000;
+415.300000;
+415.300000;
+440.000000;
+293.660000;
+329.630000;
+329.630000;
+349.230000;
+415.300000;
+440.000000;
+415.300000;
+440.000000;
+440.000000;
+493.880000;
+493.880000;
+440.000000;
+493.880000;
+523.250000;
+493.880000;
+523.250000;
+659.260000;
+659.260000;
+698.460000;
+880.000000;
+880.000000;
+880.000000;
+880.000000;
+659.260000;
+698.460000;
+659.260000;
+698.460000;
+659.260000;
+659.260000;
+659.260000;
+523.250000;
+659.260000;
+698.460000;
+880.000000;
+440.000000;
+493.880000;
+415.300000;
+440.000000;
+415.300000;
+440.000000;
+493.880000;
+329.630000;
+329.630000;
+349.230000;
+415.300000;
+349.230000;
+415.300000;
+415.300000;
+440.000000;
+349.230000;
+293.660000;
+293.660000;
+329.630000;
+293.660000;
+261.630000;
+261.630000;
+261.630000;
+261.630000;
+293.660000;
+261.630000;
+261.630000;
+293.660000;
+329.630000;
+349.230000;
+329.630000;
+293.660000;
+293.660000;
+293.660000;
+329.630000;
+329.630000;
+329.630000;
+349.230000;
+415.300000;
+440.000000;
+415.300000;
+415.300000;
+440.000000;
+493.880000;
+523.250000;
+493.880000;
+523.250000;
+493.880000;
+440.000000;
+493.880000;
+415.300000;
+440.000000;
+493.880000;
+523.250000;
+523.250000;
+523.250000;
+523.250000;
+659.260000;
+698.460000;
+880.000000;
+880.000000;
+880.000000;
+880.000000;
+880.000000;
+880.000000;
diff --git a/stksitar~/sitar.cc b/stksitar~/sitar.cc
new file mode 100644
index 0000000..11cf35b
--- /dev/null
+++ b/stksitar~/sitar.cc
@@ -0,0 +1,105 @@
+ /******************************************/
+/* Karplus-Strong sitar string model */
+/* by Perry Cook, 1995-96 */
+/* */
+/* There exist at least two patents, */
+/* assigned to Stanford, bearing the */
+/* names of Karplus and/or Strong. */
+/******************************************/
+
+#include "sitar.h"
+
+#ifndef MY_FLOAT
+#warning "weird : MY_FLOAT undefined"
+#define MY_FLOAT double
+#endif
+
+sitar :: sitar(MY_FLOAT lowestFreq)
+{
+ length = (long) (SRATE / lowestFreq + 1);
+ loopGain = (MY_FLOAT) 0.999;
+ loopFilt = new OneZero();
+ loopFilt->setCoeff(0.01);
+ delayLine = new DLineA(length);
+ delay = length/2;
+ delayTarg = delay;
+ envelope = new ADSR();
+ noise = new Noise;
+ envelope->setAllTimes(0.001,0.04,0.0,0.5);
+ this->clear();
+}
+
+sitar :: ~sitar()
+{
+ delete loopFilt;
+ delete delayLine;
+ delete envelope;
+ delete noise;
+}
+
+void sitar :: clear()
+{
+ loopFilt->clear();
+ delayLine->clear();
+}
+
+void sitar :: setFreq(MY_FLOAT frequency)
+{
+ delayTarg = (SRATE / frequency);
+ delay = delayTarg * (1.0 + (0.05 * noise->tick()));
+ delayLine->setDelay(delay);
+ loopGain = (MY_FLOAT) 0.995 + (frequency * (MY_FLOAT) 0.000001);
+ if (loopGain>1.0) loopGain = (MY_FLOAT) 0.9995;
+}
+
+void sitar :: pluck(MY_FLOAT amplitude)
+{
+ envelope->keyOn();
+}
+
+void sitar :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
+{
+ this->setFreq(freq);
+ this->pluck(amp);
+ amPluck = 0.05 * amp;
+#if defined(_debug_)
+ printf("sitar : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
+#endif
+}
+
+void sitar :: noteOff(MY_FLOAT amp)
+{
+ loopGain = (MY_FLOAT) 1.0 - amp;
+#if defined(_debug_)
+ printf("sitar : NoteOff: Amp=%lf\n",amp);
+#endif
+}
+
+MY_FLOAT sitar :: tick()
+{
+ MY_FLOAT temp;
+
+ temp = delayLine->lastOut();
+ if (fabs(temp) > 1.0) {
+ loopGain = 0.1;
+ this->noteOff(0.9);
+ delay = delayTarg;
+ delayLine->setDelay(delay);
+ }
+
+ temp *= loopGain;
+
+ if (fabs(delayTarg - delay) > 0.001) {
+ if (delayTarg < delay)
+ delay *= 0.99999;
+ else
+ delay *= 1.00001;
+ delayLine->setDelay(delay);
+ }
+
+ lastOutput = delayLine->tick(loopFilt->tick(temp)
+ + (amPluck * envelope->tick() * noise->tick()));
+
+ return lastOutput;
+}
+
diff --git a/stksitar~/sitar.h b/stksitar~/sitar.h
new file mode 100644
index 0000000..d787211
--- /dev/null
+++ b/stksitar~/sitar.h
@@ -0,0 +1,44 @@
+/******************************************/
+/* Karplus-Strong Sitar1 string model */
+/* by Perry Cook, 1995-96 */
+/* */
+/* There exist at least two patents, */
+/* assigned to Stanford, bearing the */
+/* names of Karplus and/or Strong. */
+/******************************************/
+
+#if !defined(__sitar_h)
+#define __sitar_h
+
+#include "Instrmnt.h"
+#include "DLineA.h"
+#include "OneZero.h"
+#include "ADSR.h"
+#include "Noise.h"
+#include "Object.h"
+
+class sitar : public Instrmnt
+{
+protected:
+ DLineA *delayLine;
+ OneZero *loopFilt;
+ ADSR *envelope;
+ Noise *noise;
+ long length;
+ MY_FLOAT loopGain;
+ MY_FLOAT amPluck;
+ MY_FLOAT delay;
+ MY_FLOAT delayTarg;
+public:
+ sitar(MY_FLOAT lowestFreq);
+ ~sitar();
+ void clear();
+ virtual void setFreq(MY_FLOAT frequency);
+ void pluck(MY_FLOAT amplitude);
+ virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
+ virtual void noteOff(MY_FLOAT amp);
+ virtual MY_FLOAT tick();
+};
+
+#endif
+
diff --git a/stksitar~/stksitar~.cc b/stksitar~/stksitar~.cc
new file mode 100644
index 0000000..bd47817
--- /dev/null
+++ b/stksitar~/stksitar~.cc
@@ -0,0 +1,119 @@
+/* stksitar~ -- STK-based sitar synthesis
+ * requires STK library
+ * Copyleft 2001 Yves Degoyon.
+ * Permission is granted to use this software for any purpose provided you
+ * keep this copyright notice intact.
+ *
+ * THE AUTHOR AND HIS EXPLOITERS MAKE NO WARRANTY, EXPRESS OR IMPLIED,
+ * IN CONNECTION WITH THIS SOFTWARE.
+ *
+*/
+
+#include "m_pd.h"
+#include "sitar.h"
+
+#define DEFAULT_FREQ 250.0
+#define DEFAULT_PLUCK 0.25
+
+typedef struct _stksitar
+{
+ t_object x_obj;
+ sitar *x_stksitar;
+ t_int x_on;
+ t_float x_freq;
+ t_float x_pluck;
+} t_stksitar;
+
+static t_class *stksitar_class;
+
+static void *stksitar_new(void)
+{
+ t_stksitar *x = (t_stksitar *)pd_new(stksitar_class);
+ x->x_freq = DEFAULT_FREQ;
+ x->x_pluck = DEFAULT_PLUCK;
+ outlet_new(&x->x_obj, &s_signal);
+ inlet_new( &x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("freq") );
+ inlet_new( &x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("pluck") );
+ if( (x->x_stksitar = new sitar( 50.0 )) == NULL ) {
+ post( "stksitar~: cannot build sitar instrument from STK" );
+ return NULL;
+ } else {
+ return (x);
+ }
+}
+
+static void stksitar_freq(t_stksitar* x, t_float ffreq)
+{
+ if ( ffreq < 50.0 )
+ {
+ post("stksitar~ : wrong frequency" );
+ return;
+ }
+ x->x_stksitar->setFreq( (MY_FLOAT) ffreq );
+ x->x_freq = ffreq;
+}
+
+static void stksitar_pluck(t_stksitar* x, t_float fpluck)
+{
+ if ( fpluck < 0.05 || fpluck > 0.35 )
+ {
+ post("stksitar~ : wrong pluck argument" );
+ return;
+ }
+ x->x_stksitar->pluck( (MY_FLOAT) fpluck );
+ x->x_pluck = fpluck;
+}
+
+static void stksitar_play(t_stksitar* x)
+{
+ x->x_on = 1; // activate sound
+ x->x_stksitar->noteOn( x->x_freq, x->x_pluck ); // start sound
+}
+
+static void stksitar_stop(t_stksitar* x)
+{
+ x->x_on = 0; // deactivate sound
+}
+
+static t_int *stksitar_perform(t_int *w)
+{
+ t_float *out = (t_float *)(w[1]);
+ int n = (int)(w[2]);
+ t_stksitar* x = (t_stksitar*)(w[3]);
+
+ while ( n-- )
+ {
+ if ( x->x_on )
+ {
+ double dare;
+
+ dare = (float)x->x_stksitar->tick();
+ // post( "synthesis : %f", dare );
+ *out=dare;
+ }
+ else
+ {
+ *(out) = 0.0;
+ }
+ out++;
+ }
+
+ return (w+4);
+}
+
+static void stksitar_dsp(t_stksitar *x, t_signal **sp)
+{
+ dsp_add(stksitar_perform, 3, sp[0]->s_vec, sp[0]->s_n, x);
+}
+
+extern "C" void stksitar_tilde_setup(void)
+{
+ stksitar_class = class_new(gensym("stksitar~"), (t_newmethod)stksitar_new, 0,
+ sizeof(t_stksitar), 0, A_NULL);
+ class_sethelpsymbol(stksitar_class, gensym("help-stksitar~.pd"));
+ class_addmethod(stksitar_class, (t_method)stksitar_dsp, gensym("dsp"), A_NULL);
+ class_addmethod(stksitar_class, (t_method)stksitar_play, gensym("play") , A_NULL);
+ class_addmethod(stksitar_class, (t_method)stksitar_stop, gensym("stop") , A_NULL);
+ class_addmethod(stksitar_class, (t_method)stksitar_freq, gensym("freq") , A_DEFFLOAT, A_NULL);
+ class_addmethod(stksitar_class, (t_method)stksitar_pluck, gensym("pluck") , A_DEFFLOAT, A_NULL);
+}
diff --git a/vocoder~/CHANGES.LOG b/vocoder~/CHANGES.LOG
new file mode 100644
index 0000000..6f7036d
--- /dev/null
+++ b/vocoder~/CHANGES.LOG
@@ -0,0 +1,2 @@
+0.1
+ first implementation
diff --git a/vocoder~/INSTALL b/vocoder~/INSTALL
new file mode 100644
index 0000000..37c9567
--- /dev/null
+++ b/vocoder~/INSTALL
@@ -0,0 +1,15 @@
+untar in /my/pd/dir/externs
+
+cd /my/pd/dir/externs/vocoder~
+
+make clean
+
+make
+
+make install
+
+open help-vocoder~.pd
+
+Thanx for getting here.
+Yves/
+comments and bugs @ ydegoyon@free.fr
diff --git a/vocoder~/Makefile b/vocoder~/Makefile
new file mode 100644
index 0000000..857530b
--- /dev/null
+++ b/vocoder~/Makefile
@@ -0,0 +1,86 @@
+NAME=vocoder~
+CSYM=vocoder_tilde
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).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
+
+.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
+
+.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
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -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 filters.o -c filters.c
+ cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o lpc.o -c lpc.c
+ cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o tables.o -c tables.c
+ cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ ld -export_dynamic -shared -o $*.pd_linux *.o -lc -lm
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o ../$*.pd_linux
+ ln -s $*/$*.pd_linux ..
+
+# ----------------------------------------------------------
+
+clean:
+ rm -f *.o *.pd_* so_locations
+
+install:
+ cp *.pd ../../doc/5.reference
+
diff --git a/vocoder~/README b/vocoder~/README
new file mode 100644
index 0000000..767151c
--- /dev/null
+++ b/vocoder~/README
@@ -0,0 +1,22 @@
+*****************************************************************************
+Version 0.1
+copyleft 2002 by Yves Degoyon
+tarballs and updates available @ http://ydegoyon.free.fr
+
+vocoder~ : vocoder filter for PD inspired by xvox ( http://simon.morlat.free.fr )
+i used xvox version 0.2.1, but you don't need to install it,
+everything needed is bundled here.
+
+To install cooled~, 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.
+
+*****************************************************************************
+
+
diff --git a/vocoder~/filters.c b/vocoder~/filters.c
new file mode 100644
index 0000000..2bf9253
--- /dev/null
+++ b/vocoder~/filters.c
@@ -0,0 +1,49 @@
+/*
+vox - a musical real-time vocoder. version 1.0
+Copyright (C) 2000 Simon MORLAT (simon.morlat@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.
+
+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.
+*/
+
+
+
+void lpc_filter(double *buf_ppf, double *lpc_coef, double *buf_sy, int n)
+{
+ int i,j;
+ double acc;
+
+ for(i=0;i<n;i++)
+ {
+ acc=buf_ppf[i]*lpc_coef[0];
+ for(j=1;j<11;j++)
+ {
+ acc=acc-lpc_coef[j]*buf_sy[i-j];
+ };
+ buf_sy[i]=acc;
+ };
+}
+
+void hp_filter(double *in,double cut,int n)
+{
+ int i;
+ double prev_e,s_out;
+ prev_e=s_out=0;
+ for(i=0;i<n;i++)
+ {
+ s_out=in[i]-prev_e+cut*s_out;
+ prev_e=in[i];
+ in[i]=s_out;
+ };
+}
diff --git a/vocoder~/filters.h b/vocoder~/filters.h
new file mode 100644
index 0000000..534f881
--- /dev/null
+++ b/vocoder~/filters.h
@@ -0,0 +1,27 @@
+/*
+vox - a musical real-time vocoder. version 1.0
+Copyright (C) 2000 Simon MORLAT (simon.morlat@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.
+
+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 __FILTERS_H__
+#define __FILTERS_H__
+
+void lpc_filter(double *buf_ppf, double *lpc_coef, double *buf_sy,int n);
+void hp_filter(double *in,double cut,int n);
+
+#endif
diff --git a/vocoder~/filters.o b/vocoder~/filters.o
new file mode 100644
index 0000000..c0a0e89
--- /dev/null
+++ b/vocoder~/filters.o
Binary files differ
diff --git a/vocoder~/help-vocoder~.pd b/vocoder~/help-vocoder~.pd
new file mode 100644
index 0000000..7bbf3b2
--- /dev/null
+++ b/vocoder~/help-vocoder~.pd
@@ -0,0 +1,55 @@
+#N canvas 123 129 764 525 10;
+#X obj 201 393 dac~;
+#X obj 153 330 adc~;
+#X obj 204 355 rs-vocoder~;
+#X text 356 457 vocoder~ : vocoder effect;
+#X text 356 469 inspired by xvox written by;
+#X text 357 483 Simon Morlat ( http://simon.morlat.free.fr );
+#X text 357 497 Part of unauthorized PD ( http://ydegoyon.free.fr )
+;
+#X obj 125 406 env~;
+#X floatatom 124 435 5 0 0;
+#X obj 265 301 hsl 128 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 11500 1;
+#X text 409 299 Cutoff Frequency;
+#X obj 295 327 hsl 128 15 0 100 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 10500 1;
+#X text 439 325 Voice Feedback [ 0 - 100 ];
+#X msg 49 39 bang;
+#X obj 48 61 openpanel;
+#X obj 48 81 t s b;
+#X obj 105 83 float \$0;
+#X text 56 16 Step 1 : Load a sound file;
+#X obj 48 104 route float;
+#X obj 49 196 soundfiler;
+#X text 106 32 ( maybe \, a guitar sound ? );
+#X obj 48 127 makefilename %d-sample;
+#X msg 49 174 read -resize \$1 \$2;
+#X obj 50 153 pack s s;
+#X msg 237 207 bang;
+#X text 282 207 Step 2 : Start playing;
+#X obj 237 254 tabplay~ \$0-sample;
+#X msg 308 230 stop;
+#X obj 237 230 metro 250;
+#X text 49 300 Step 3 : Grab the mike !!!;
+#X obj 333 90 table \$0-sample;
+#X connect 1 0 2 0;
+#X connect 2 0 0 0;
+#X connect 2 0 0 1;
+#X connect 2 0 7 0;
+#X connect 7 0 8 0;
+#X connect 9 0 2 2;
+#X connect 11 0 2 3;
+#X connect 13 0 14 0;
+#X connect 14 0 15 0;
+#X connect 15 0 23 0;
+#X connect 15 1 16 0;
+#X connect 16 0 18 0;
+#X connect 18 0 21 0;
+#X connect 21 0 23 1;
+#X connect 22 0 19 0;
+#X connect 23 0 22 0;
+#X connect 24 0 28 0;
+#X connect 26 0 2 1;
+#X connect 27 0 28 0;
+#X connect 28 0 26 0;
diff --git a/vocoder~/lpc.c b/vocoder~/lpc.c
new file mode 100644
index 0000000..33159d4
--- /dev/null
+++ b/vocoder~/lpc.c
@@ -0,0 +1,252 @@
+/*
+vox - a musical real-time vocoder. version 1.0
+Copyright (C) 2000 Simon MORLAT (simon.morlat@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.
+
+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.
+*/
+
+#include "tables.h"
+#include "lpc.h"
+#define THRES 0.06
+#define Dmin 10.81e-3
+
+/* Levinson Durbin algorithm for computing LPC coefficients using
+autocorrelation fonction */
+void lev_durb(double *corr,double *lpc_coef)
+{
+ double k[11],tab[11];
+ double err,acc;
+ int i,j;
+ double *a=tab;
+ double *prev_a=lpc_coef;
+ double *exch;
+
+
+ /*init vectors*/
+ for (i=0;i<11;i++)
+ {
+ prev_a[i]=0;
+ a[i]=0;
+ };
+ err=corr[0];
+ for(i=1;i<11;i++)
+ {
+ prev_a[0]=1;
+ acc=0;
+ for(j=0;j<i;j++)
+ {
+ acc=acc+prev_a[j]*corr[i-j];
+ };
+ a[i]=k[i]=-acc/err;
+ for(j=1;j<i;j++)
+ {
+ a[j]=prev_a[j]+k[i]*prev_a[i-j];
+ };
+ err=(1-k[i]*k[i])*err;
+ exch=prev_a;
+ prev_a=a;
+ a=exch;
+ };
+}
+
+void comp_lpc(double *buf_x,double *corr,double *lpc_coef,int n)
+{
+ double buffer[n*3];
+ double acc,max=0;
+ int i,j;
+ /* computes LPC analysis for one subframe */
+ /* hamming windowing*/
+ acc=0;
+ for(i=0;i<2*n;i++)
+ {
+ acc+=buf_x[i]*buf_x[i];
+ };
+ if (acc>THRES)
+ {
+ for(i=0;i<3*n;i++)
+ {
+ buffer[i]=buf_x[i-n]*HammingWindowTable[i];
+ };
+ /* autocorrelation computation*/
+ for(i=0;i<11;i++)
+ {
+ acc=0;
+ for(j=i;j<n*3;j++)
+ {
+ acc=acc+buffer[j]*buffer[j-i];
+ };
+ /* correction with binomial coeffs */
+ corr[i]=acc;//*BinomialWindowTable[i];
+ };
+ corr[0]=corr[0]*(1.0+1.0/1024.0);
+ lev_durb(corr,lpc_coef);
+ }
+ else
+ {
+ for(i=0;i<11;i++)
+ {
+ lpc_coef[i]=0;
+ };
+ }
+}
+
+
+
+/* LPC to LSP coefficients conversion */
+
+/* evaluate function C(x) (whose roots are LSP coeffs)*/
+
+double evalc(double cw,double *fonc)
+{
+ double b[7];
+ double x,res;
+ int k;
+
+ x=cw;
+ b[5]=1;
+ b[6]=0;
+ for(k=4;k>0;k--)
+ {
+ b[k]=2*x*b[k+1]-b[k+2]+fonc[5-k];
+ };
+ res=x*b[1]-b[2]+fonc[5]/2;
+ return(res);
+}
+
+
+
+/* converts LPC vector into LSP frequency vector */
+/* all LSP frenquencies are in [0;PI] but are normalized to be in [0;1] */
+void lpc2lsp(double lpc_coef[],double *f1,double *f2,double lsp_coef[])
+{
+
+ int i,k=1;
+ double *fonc,*prev_f,*f_exch;
+ double prev_sign1,sign,prev_sign2;
+ double *s, *prev_s,*s_exch;
+ double lpc_exp[11];
+
+ /* first computes an additional bandwidth expansion on LPC coeffs*/
+ for(i=1;i<11;i++)
+ {
+ lpc_exp[i]=lpc_coef[i]*BandExpTable[i];
+ };
+ /* computes the F1 and F2 coeffs*/
+ f1[0]=f2[0]=1;
+ for(i=0;i<5;i++)
+ {
+ f1[i+1]=lpc_exp[i+1]+lpc_exp[10-i]-f1[i];
+ f2[i+1]=lpc_exp[i+1]-lpc_exp[10-i]+f2[i];
+ };
+
+ /*find the roots of C(x) alternatively for F1 and F2*/
+ fonc=f1;
+ prev_f=f2;
+ prev_sign1=evalc(1.0,f1);
+ prev_sign2=evalc(1.0,f2);
+ s=&prev_sign1;
+ prev_s=&prev_sign2;
+ for(i=1;i<256;i++)
+ {
+ sign=evalc(CosineTable[i],fonc);
+ if ((sign)*(*s)<0)
+ {
+ /* interpolate to find root*/
+ lsp_coef[k]=((double)i-(*s)/(sign-(*s)))/256.0;
+ k++;
+ /* chek if all roots are found */
+ if (k==11) i=257;
+ (*s)=sign;
+ /* pointers exchange */
+ s_exch=s;
+ s=prev_s;
+ prev_s=s_exch;
+ f_exch=fonc;
+ fonc=prev_f;
+ prev_f=f_exch;
+ }
+ else (*s)=sign;
+ }
+ /* if here all roots are not found , use lspDC vector */
+ if (k!=11)
+ {
+ for(i=1;i<11;i++)
+ {
+ lsp_coef[i]=LspDcTable[i];
+ };
+ };
+}
+
+
+/* converts lsp frequencies to lpc coeffs */
+
+void lsp2lpc(double *lsp_coef,double *lpc_coef)
+{
+ int i,j=0,index,ok=1;
+ double lspcos[11],delta,tmp,p_avg;
+ double F1[12],F2[12]; /* begin at indice two*/
+
+ F1[0]=0;F1[1]=1;
+ F2[0]=0;F2[1]=1;
+ /* stability check */
+ while(ok && (j<11))
+ {
+ ok=0;
+ for(i=1;i<10;i++)
+ {
+ if( (lsp_coef[i+1]-lsp_coef[i]) < Dmin)
+ {
+ ok=1;
+ p_avg=(lsp_coef[i]+lsp_coef[i+1])/2.0;
+ lsp_coef[i]=p_avg-Dmin/2.0;
+ lsp_coef[i+1]=p_avg+Dmin/2.0;
+ };
+ };
+ j++;
+ }
+
+ /* first converts lsp frequencies to lsp coefficients */
+ for (i=1;i<11;i++)
+ {
+ /* interpolation */
+ tmp=lsp_coef[i]*255.0;
+ index=(int)tmp;
+ delta=CosineTable[index+1]-CosineTable[index];
+ lspcos[i]=CosineTable[index]+delta*(tmp-index);
+ };
+
+ for(i=2;i<7;i++)
+ {
+ F1[i]=-2*lspcos[2*i-3]*F1[i-1]+2*F1[i-2];
+ F2[i]=-2*lspcos[2*i-2]*F2[i-1]+2*F2[i-2];
+ for(j=i-1;j>1;j--)
+ {
+ F1[j]=F1[j]-2*lspcos[2*i-3]*F1[j-1]+F1[j-2];
+ F2[j]=F2[j]-2*lspcos[2*i-2]*F2[j-1]+F2[j-2];
+ };
+ };
+ for(i=6;i>1;i--)
+ {
+ F1[i]=F1[i]+F1[i-1];
+ F2[i]=F2[i]-F2[i-1];
+ };
+ for(i=2;i<7;i++)
+ {
+ lpc_coef[i-1]=(F1[i]+F2[i])*0.5;
+ lpc_coef[i+4]=(F1[8-i]-F2[8-i])*0.5;
+ };
+ lpc_coef[0]=1;
+}
+
diff --git a/vocoder~/lpc.h b/vocoder~/lpc.h
new file mode 100644
index 0000000..c8d5d63
--- /dev/null
+++ b/vocoder~/lpc.h
@@ -0,0 +1,33 @@
+/*
+vox - a musical real-time vocoder. version 1.0
+Copyright (C) 2000 Simon MORLAT (simon.morlat@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.
+
+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.
+*/
+
+/* variables globales */
+extern int dsp_fd;
+extern int bsize;
+extern double voix[512+256];
+extern double synth[512+256];
+extern double sortie[512+12];
+extern double *out;
+
+void lev_durb(double *corr,double *lpc_coef);
+void comp_lpc(double *buf_x,double *corr,double *lpc_coef,int n);
+void lpc_filter(double *buf_ppf, double *lpc_coef, double *buf_sy,int n);
+void lsp2lpc(double *lsp_coef,double *lpc_coef);
+void lpc2lsp(double lpc_coef[],double *f1,double *f2,double lsp_coef[]);
+double evalc(double cw,double *fonc);
diff --git a/vocoder~/lpc.o b/vocoder~/lpc.o
new file mode 100644
index 0000000..c150a14
--- /dev/null
+++ b/vocoder~/lpc.o
Binary files differ
diff --git a/vocoder~/rs-vocoder~.pd b/vocoder~/rs-vocoder~.pd
new file mode 100644
index 0000000..65dfc0d
--- /dev/null
+++ b/vocoder~/rs-vocoder~.pd
@@ -0,0 +1,13 @@
+#N canvas 0 0 450 300 10;
+#X obj 39 146 block~ 512;
+#X obj 89 36 inlet~;
+#X obj 151 34 inlet~;
+#X obj 129 77 vocoder~;
+#X obj 207 33 inlet;
+#X obj 261 33 inlet;
+#X obj 129 108 outlet~;
+#X connect 1 0 3 0;
+#X connect 2 0 3 1;
+#X connect 3 0 6 0;
+#X connect 4 0 3 2;
+#X connect 5 0 3 3;
diff --git a/vocoder~/tables.c b/vocoder~/tables.c
new file mode 100644
index 0000000..049a523
--- /dev/null
+++ b/vocoder~/tables.c
@@ -0,0 +1,311 @@
+/*
+vox - a musical real-time vocoder. version 1.0
+Copyright (C) 2000 Simon MORLAT (simon.morlat@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.
+
+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.
+*/
+
+double LspDcTable[11] = {
+ 0,
+ 0.0955505 ,
+ 0.144073 ,
+ 0.23468 ,
+ 0.329773 ,
+ 0.42334 ,
+ 0.503387 ,
+ 0.602783 ,
+ 0.679321 ,
+ 0.77771 ,
+ 0.845886
+};
+
+double CosineTable[257] = {
+ 1 ,
+ 0.999939 ,
+ 0.999695 ,
+ 0.999329 ,
+ 0.998779 ,
+ 0.998108 ,
+ 0.997314 ,
+ 0.996338 ,
+ 0.995178 ,
+ 0.993896 ,
+ 0.992493 ,
+ 0.990906 ,
+ 0.989197 ,
+ 0.987305 ,
+ 0.985291 ,
+ 0.983093 ,
+ 0.980774 ,
+ 0.978333 ,
+ 0.975708 ,
+ 0.972961 ,
+ 0.970032 ,
+ 0.96698 ,
+ 0.963806 ,
+ 0.960449 ,
+ 0.95697 ,
+ 0.953308 ,
+ 0.949524 ,
+ 0.945618 ,
+ 0.941528 ,
+ 0.937317 ,
+ 0.932983 ,
+ 0.928528 ,
+ 0.923889 ,
+ 0.919128 ,
+ 0.914185 ,
+ 0.90918 ,
+ 0.903992 ,
+ 0.898682 ,
+ 0.89325 ,
+ 0.887634 ,
+ 0.881897 ,
+ 0.876099 ,
+ 0.870117 ,
+ 0.863953 ,
+ 0.857727 ,
+ 0.851379 ,
+ 0.844849 ,
+ 0.838196 ,
+ 0.831482 ,
+ 0.824585 ,
+ 0.817566 ,
+ 0.810486 ,
+ 0.803223 ,
+ 0.795837 ,
+ 0.78833 ,
+ 0.780762 ,
+ 0.77301 ,
+ 0.765198 ,
+ 0.757202 ,
+ 0.749146 ,
+ 0.740967 ,
+ 0.732666 ,
+ 0.724243 ,
+ 0.715759 ,
+ 0.707092 ,
+ 0.698364 ,
+ 0.689514 ,
+ 0.680603 ,
+ 0.67157 ,
+ 0.662415 ,
+ 0.653198 ,
+ 0.64386 ,
+ 0.634399 ,
+ 0.624878 ,
+ 0.615234 ,
+ 0.60553 ,
+ 0.595703 ,
+ 0.585815 ,
+ 0.575806 ,
+ 0.565735 ,
+ 0.555542 ,
+ 0.545349 ,
+ 0.534973 ,
+ 0.524597 ,
+ 0.514099 ,
+ 0.50354 ,
+ 0.49292 ,
+ 0.482178 ,
+ 0.471375 ,
+ 0.46051 ,
+ 0.449585 ,
+ 0.438599 ,
+ 0.427551 ,
+ 0.416443 ,
+ 0.405212 ,
+ 0.393982 ,
+ 0.38269 ,
+ 0.371338 ,
+ 0.359924 ,
+ 0.348389 ,
+ 0.336914 ,
+ 0.325317 ,
+ 0.31366 ,
+ 0.302002 ,
+ 0.290283 ,
+ 0.278503 ,
+ 0.266724 ,
+ 0.254883 ,
+ 0.242981 ,
+ 0.231079 ,
+ 0.219116 ,
+ 0.207092 ,
+ 0.195068 ,
+ 0.183044 ,
+ 0.170959 ,
+ 0.158875 ,
+ 0.146729 ,
+ 0.134583 ,
+ 0.122437 ,
+ 0.110229 ,
+ 0.0980225 ,
+ 0.0858154 ,
+ 0.0735474 ,
+ 0.0613403 ,
+ 0.0490723 ,
+ 0.0368042 ,
+ 0.0245361 ,
+ 0.0122681 ,
+ 0 ,
+ -0.0122681 ,
+ -0.0245361 ,
+ -0.0368042 ,
+ -0.0490723 ,
+ -0.0613403 ,
+ -0.0735474 ,
+ -0.0858154 ,
+ -0.0980225 ,
+ -0.110229 ,
+ -0.122437 ,
+ -0.134583 ,
+ -0.146729 ,
+ -0.158875 ,
+ -0.170959 ,
+ -0.183044 ,
+ -0.195068 ,
+ -0.207092 ,
+ -0.219116 ,
+ -0.231079 ,
+ -0.242981 ,
+ -0.254883 ,
+ -0.266724 ,
+ -0.278503 ,
+ -0.290283 ,
+ -0.302002 ,
+ -0.31366 ,
+ -0.325317 ,
+ -0.336914 ,
+ -0.348389 ,
+ -0.359924 ,
+ -0.371338 ,
+ -0.38269 ,
+ -0.393982 ,
+ -0.405212 ,
+ -0.416443 ,
+ -0.427551 ,
+ -0.438599 ,
+ -0.449585 ,
+ -0.46051 ,
+ -0.471375 ,
+ -0.482178 ,
+ -0.49292 ,
+ -0.50354 ,
+ -0.514099 ,
+ -0.524597 ,
+ -0.534973 ,
+ -0.545349 ,
+ -0.555542 ,
+ -0.565735 ,
+ -0.575806 ,
+ -0.585815 ,
+ -0.595703 ,
+ -0.60553 ,
+ -0.615234 ,
+ -0.624878 ,
+ -0.634399 ,
+ -0.64386 ,
+ -0.653198 ,
+ -0.662415 ,
+ -0.67157 ,
+ -0.680603 ,
+ -0.689514 ,
+ -0.698364 ,
+ -0.707092 ,
+ -0.715759 ,
+ -0.724243 ,
+ -0.732666 ,
+ -0.740967 ,
+ -0.749146 ,
+ -0.757202 ,
+ -0.765198 ,
+ -0.77301 ,
+ -0.780762 ,
+ -0.78833 ,
+ -0.795837 ,
+ -0.803223 ,
+ -0.810486 ,
+ -0.817566 ,
+ -0.824585 ,
+ -0.831482 ,
+ -0.838196 ,
+ -0.844849 ,
+ -0.851379 ,
+ -0.857727 ,
+ -0.863953 ,
+ -0.870117 ,
+ -0.876099 ,
+ -0.881897 ,
+ -0.887634 ,
+ -0.89325 ,
+ -0.898682 ,
+ -0.903992 ,
+ -0.90918 ,
+ -0.914185 ,
+ -0.919128 ,
+ -0.923889 ,
+ -0.928528 ,
+ -0.932983 ,
+ -0.937317 ,
+ -0.941528 ,
+ -0.945618 ,
+ -0.949524 ,
+ -0.953308 ,
+ -0.95697 ,
+ -0.960449 ,
+ -0.963806 ,
+ -0.96698 ,
+ -0.970032 ,
+ -0.972961 ,
+ -0.975708 ,
+ -0.978333 ,
+ -0.980774 ,
+ -0.983093 ,
+ -0.985291 ,
+ -0.987305 ,
+ -0.989197 ,
+ -0.990906 ,
+ -0.992493 ,
+ -0.993896 ,
+ -0.995178 ,
+ -0.996338 ,
+ -0.997314 ,
+ -0.998108 ,
+ -0.998779 ,
+ -0.999329 ,
+ -0.999695 ,
+ -0.999939 ,
+ -1
+};
+
+double BandExpTable[11] = {
+ 1,
+ 0.993988 ,
+ 0.988037 ,
+ 0.982117 ,
+ 0.976227 ,
+ 0.970367 ,
+ 0.964539 ,
+ 0.95874 ,
+ 0.953003 ,
+ 0.947266 ,
+ 0.941589
+};
+
+
+double HammingWindowTable[128*3]={
+5.38469e-16, 6.69307e-05, 0.000267706, 0.000602271, 0.00107054, 0.00167238, 0.00240763, 0.00327611, 0.00427757, 0.00541174, 0.00667833, 0.00807699, 0.00960736, 0.011269, 0.0130615, 0.0149844, 0.0170371, 0.0192191, 0.0215298, 0.0239687, 0.0265349, 0.029228, 0.032047, 0.0349914, 0.0380602, 0.0412527, 0.0445681, 0.0480053, 0.0515636, 0.055242, 0.0590394, 0.0629548, 0.0669873, 0.0711357, 0.0753989, 0.0797758, 0.0842652, 0.0888659, 0.0935766, 0.0983962, 0.103323, 0.108357, 0.113495, 0.118736, 0.12408, 0.129524, 0.135068, 0.140709, 0.146447, 0.152279, 0.158204, 0.164221, 0.170327, 0.176522, 0.182803, 0.18917, 0.195619, 0.20215, 0.208761, 0.21545, 0.222215, 0.229054, 0.235966, 0.242949, 0.25, 0.257118, 0.264302, 0.271548, 0.278856, 0.286222, 0.293646, 0.301126, 0.308658, 0.316242, 0.323875, 0.331555, 0.33928, 0.347048, 0.354858, 0.362706, 0.37059, 0.37851, 0.386462, 0.394444, 0.402455, 0.410492, 0.418552, 0.426635, 0.434737, 0.442857, 0.450991, 0.459139, 0.467298, 0.475466, 0.48364, 0.491819, 0.5, 0.508181, 0.51636, 0.524534, 0.532702, 0.540861, 0.549009, 0.557143, 0.565263, 0.573365, 0.581448, 0.589508, 0.597545, 0.605556, 0.613538, 0.62149, 0.62941, 0.637294, 0.645142, 0.652952, 0.66072, 0.668445, 0.676125, 0.683758, 0.691342, 0.698874, 0.706354, 0.713778, 0.721144, 0.728452, 0.735698, 0.742882, 0.75, 0.757051, 0.764034, 0.770946, 0.777785, 0.78455, 0.791239, 0.79785, 0.804381, 0.81083, 0.817197, 0.823478, 0.829673, 0.835779, 0.841796, 0.847721, 0.853553, 0.859291, 0.864932, 0.870476, 0.87592, 0.881264, 0.886505, 0.891643, 0.896677, 0.901604, 0.906423, 0.911134, 0.915735, 0.920224, 0.924601, 0.928864, 0.933013, 0.937045, 0.940961, 0.944758, 0.948436, 0.951995, 0.955432, 0.958747, 0.96194, 0.965009, 0.967953, 0.970772, 0.973465, 0.976031, 0.97847, 0.980781, 0.982963, 0.985016, 0.986938, 0.988731, 0.990393, 0.991923, 0.993322, 0.994588, 0.995722, 0.996724, 0.997592, 0.998328, 0.998929, 0.999398, 0.999732, 0.999933, 1, 0.999933, 0.999732, 0.999398, 0.998929, 0.998328, 0.997592, 0.996724, 0.995722, 0.994588, 0.993322, 0.991923, 0.990393, 0.988731, 0.986938, 0.985016, 0.982963, 0.980781, 0.97847, 0.976031, 0.973465, 0.970772, 0.967953, 0.965009, 0.96194, 0.958747, 0.955432, 0.951995, 0.948436, 0.944758, 0.940961, 0.937045, 0.933013, 0.928864, 0.924601, 0.920224, 0.915735, 0.911134, 0.906423, 0.901604, 0.896677, 0.891643, 0.886505, 0.881264, 0.87592, 0.870476, 0.864932, 0.859291, 0.853553, 0.847721, 0.841796, 0.835779, 0.829673, 0.823478, 0.817197, 0.81083, 0.804381, 0.79785, 0.791239, 0.78455, 0.777785, 0.770946, 0.764034, 0.757051, 0.75, 0.742882, 0.735698, 0.728452, 0.721144, 0.713778, 0.706354, 0.698874, 0.691342, 0.683758, 0.676125, 0.668445, 0.66072, 0.652952, 0.645142, 0.637294, 0.62941, 0.62149, 0.613538, 0.605556, 0.597545, 0.589508, 0.581448, 0.573365, 0.565263, 0.557143, 0.549009, 0.540861, 0.532702, 0.524534, 0.51636, 0.508181, 0.5, 0.491819, 0.48364, 0.475466, 0.467298, 0.459139, 0.450991, 0.442857, 0.434737, 0.426635, 0.418552, 0.410492, 0.402455, 0.394444, 0.386462, 0.37851, 0.37059, 0.362706, 0.354858, 0.347048, 0.33928, 0.331555, 0.323875, 0.316242, 0.308658, 0.301126, 0.293646, 0.286222, 0.278856, 0.271548, 0.264302, 0.257118, 0.25, 0.242949, 0.235966, 0.229054, 0.222215, 0.21545, 0.208761, 0.20215, 0.195619, 0.18917, 0.182803, 0.176522, 0.170327, 0.164221, 0.158204, 0.152279, 0.146447, 0.140709, 0.135068, 0.129524, 0.12408, 0.118736, 0.113495, 0.108357, 0.103323, 0.0983962, 0.0935766, 0.0888659, 0.0842652, 0.0797758, 0.0753989, 0.0711357, 0.0669873, 0.0629548, 0.0590394, 0.055242, 0.0515636, 0.0480053, 0.0445681, 0.0412527, 0.0380602, 0.0349914, 0.032047, 0.029228, 0.0265349, 0.0239687, 0.0215298, 0.0192191, 0.0170371, 0.0149844, 0.0130615, 0.011269, 0.00960736, 0.00807699, 0.00667833, 0.00541174, 0.00427757, 0.00327611, 0.00240763, 0.00167238, 0.00107054, 0.000602271, 0.000267706, 6.69307e-05,
+ };
diff --git a/vocoder~/tables.h b/vocoder~/tables.h
new file mode 100644
index 0000000..6f500fc
--- /dev/null
+++ b/vocoder~/tables.h
@@ -0,0 +1,24 @@
+/*
+vox - a musical real-time vocoder. version 1.0
+Copyright (C) 2000 Simon MORLAT (simon.morlat@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.
+
+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.
+*/
+
+extern double BandExpTable[11];
+extern double BinomialWindowTable[11];
+extern double HammingWindowTable[128*3];
+extern double CosineTable[257];
+extern double LspDcTable[11];
diff --git a/vocoder~/tables.o b/vocoder~/tables.o
new file mode 100644
index 0000000..a31acab
--- /dev/null
+++ b/vocoder~/tables.o
Binary files differ
diff --git a/vocoder~/vocoder~.c b/vocoder~/vocoder~.c
new file mode 100644
index 0000000..08dbe3d
--- /dev/null
+++ b/vocoder~/vocoder~.c
@@ -0,0 +1,163 @@
+/* vocoder~ -- vocoder effect inspired by xvox
+ * written by Simon Morlat ( http://simon.morlat.free.fr )
+ *
+ * Copyleft 2001 Yves Degoyon.
+ * Permission is granted to use this software for any purpose provided you
+ * keep this copyright notice intact.
+ *
+ * THE AUTHOR AND HIS EXPLOITERS MAKE NO WARRANTY, EXPRESS OR IMPLIED,
+ * IN CONNECTION WITH THIS SOFTWARE.
+ *
+ */
+
+#include "m_pd.h"
+#include "filters.h"
+#include "lpc.h"
+
+#define OUTPUT_DELAY 50
+
+typedef struct _vocoder
+{
+ t_object x_obj;
+ t_float x_f;
+ t_float x_cutoff;
+ t_int x_vfeedback;
+ double *x_in1buf;
+ double *x_in2buf;
+ double *x_outbuf;
+ t_int x_blocksize;
+ t_int x_process;
+} t_vocoder;
+
+static t_class *vocoder_class;
+
+static char *vocoder_version = "vocoder~: version 0.1, written by ydegoyon@free.fr, inspired by xvox (Simon Morlat)";
+
+static void vocoder_cutoff(t_vocoder *x, t_floatarg fcutoff )
+{
+ if ( fcutoff > 128.0 )
+ {
+ fcutoff = 128.0;
+ }
+ if ( fcutoff < 0.0 )
+ {
+ fcutoff = 0.0;
+ }
+ x->x_cutoff = fcutoff;
+}
+
+static void vocoder_vfeedback(t_vocoder *x, t_floatarg fvfeedback )
+{
+ if ( fvfeedback > 100.0 )
+ {
+ fvfeedback = 100.0;
+ }
+ if ( fvfeedback < 0.0 )
+ {
+ fvfeedback = 0.0;
+ }
+ x->x_vfeedback = fvfeedback;
+}
+
+static t_int *vocoder_perform(t_int *w)
+{
+ t_vocoder *x = (t_vocoder *)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *fin1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out1 = (t_float *)(w[4]);
+ double correls[12], lpc_coef[11], f1[12], f2[12], lsp_coef[11];
+ int offset=0;
+ int n = (int)(w[5]), i;
+
+ if ( !x->x_process ) return (w+6);
+ if ( x->x_blocksize != n )
+ {
+ if ( x->x_in1buf ) freebytes( x->x_in1buf, 3*x->x_blocksize/2*sizeof( double ) );
+ if ( x->x_in2buf ) freebytes( x->x_in2buf, 3*x->x_blocksize/2*sizeof( double ) );
+ if ( x->x_outbuf ) freebytes( x->x_outbuf, (x->x_blocksize+OUTPUT_DELAY)*sizeof( double ) );
+ x->x_blocksize = n;
+ x->x_in1buf = (double*) getbytes( 3*x->x_blocksize/2*sizeof( double ) );
+ x->x_in2buf = (double*) getbytes( 3*x->x_blocksize/2*sizeof( double ) );
+ x->x_outbuf = (double*) getbytes( (x->x_blocksize+OUTPUT_DELAY)*sizeof( double ) );
+ if ( !x->x_in1buf || !x->x_in2buf || !x->x_outbuf )
+ {
+ post( "vocoder~ : allocations failed : stop processing" );
+ x->x_process = 0;
+ }
+ }
+
+ for(i=0;i<x->x_blocksize/2;i++)
+ {
+ x->x_in1buf[i]=x->x_in1buf[i+x->x_blocksize];
+ };
+ for(i=0;i<OUTPUT_DELAY;i++) x->x_outbuf[i]=x->x_outbuf[i+x->x_blocksize];
+ for(i=0;i<x->x_blocksize;i++)
+ {
+ x->x_in1buf[x->x_blocksize/2+i]=(double)(*(in1++));
+ x->x_in2buf[x->x_blocksize/2+i]=(double)(*(in2++));
+ }
+
+ hp_filter(x->x_in2buf,x->x_cutoff/128.,n);
+ for(i=0;i<4;i++)
+ {
+ comp_lpc(x->x_in1buf+offset,correls,lpc_coef,x->x_blocksize/4);
+ if (lpc_coef[0]!=0)
+ {
+ lpc2lsp(lpc_coef,f1,f2,lsp_coef);
+ lsp2lpc(lsp_coef,lpc_coef);
+ };
+ lpc_filter(x->x_in2buf+offset,lpc_coef,x->x_outbuf+OUTPUT_DELAY+offset,x->x_blocksize/4);
+ offset+=x->x_blocksize/4;
+ };
+ for(i=0;i<x->x_blocksize;i++)
+ {
+ if ( x->x_outbuf[OUTPUT_DELAY+i] > 1.0 ) x->x_outbuf[OUTPUT_DELAY+i]=1.0;
+ if ( x->x_outbuf[OUTPUT_DELAY+i] < -1.0 ) x->x_outbuf[OUTPUT_DELAY+i]=-1.0;
+ *(out1++)=(t_float)(((100-x->x_vfeedback)*x->x_outbuf[OUTPUT_DELAY+i]
+ + x->x_vfeedback*(*fin1++))/100.0);
+ };
+
+ return (w+6);
+}
+
+static void vocoder_dsp(t_vocoder *x, t_signal **sp)
+{
+ dsp_add(vocoder_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void *vocoder_new(void)
+{
+ t_vocoder *x = (t_vocoder *)pd_new(vocoder_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("cutoff"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("vfeedback"));
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_cutoff = 60.;
+ x->x_vfeedback = 50;
+ x->x_blocksize=-1;
+ x->x_in1buf = NULL;
+ x->x_in2buf = NULL;
+ x->x_outbuf = NULL;
+ x->x_process = 1;
+ return (x);
+}
+
+ /* clean up */
+static void vocoder_free(t_vocoder *x)
+{
+ if ( x->x_in1buf ) freebytes( x->x_in1buf, 3*x->x_blocksize/2*sizeof( double ) );
+ if ( x->x_in2buf ) freebytes( x->x_in2buf, 3*x->x_blocksize/2*sizeof( double ) );
+ if ( x->x_outbuf ) freebytes( x->x_outbuf, (x->x_blocksize+OUTPUT_DELAY)*sizeof( double ) );
+}
+
+void vocoder_tilde_setup(void)
+{
+ post(vocoder_version);
+ vocoder_class = class_new(gensym("vocoder~"), (t_newmethod)vocoder_new, (t_method)vocoder_free,
+ sizeof(t_vocoder), 0, 0);
+ CLASS_MAINSIGNALIN( vocoder_class, t_vocoder, x_f );
+ class_addmethod(vocoder_class, (t_method)vocoder_dsp, gensym("dsp"), 0);
+ class_addmethod(vocoder_class, (t_method)vocoder_cutoff, gensym("cutoff"), A_FLOAT, 0);
+ class_addmethod(vocoder_class, (t_method)vocoder_vfeedback, gensym("vfeedback"), A_FLOAT, 0);
+}
diff --git a/wahwah~/CHANGES.LOG b/wahwah~/CHANGES.LOG
new file mode 100644
index 0000000..dca0aa9
--- /dev/null
+++ b/wahwah~/CHANGES.LOG
@@ -0,0 +1,2 @@
+0.1
+ initial wahwah~ implementation
diff --git a/wahwah~/COPYING b/wahwah~/COPYING
new file mode 100644
index 0000000..2128a66
--- /dev/null
+++ b/wahwah~/COPYING
@@ -0,0 +1,280 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/wahwah~/INSTALL b/wahwah~/INSTALL
new file mode 100644
index 0000000..62ca7df
--- /dev/null
+++ b/wahwah~/INSTALL
@@ -0,0 +1,15 @@
+untar in /my/pd/dir/externs
+
+cd /my/pd/dir/externs/wahwah~
+
+make clean
+
+make
+
+make install
+
+open help-wahwah~.pd
+
+Thanx for getting here.
+Yves/
+comments and bugs @ ydegoyon@free.fr
diff --git a/wahwah~/Makefile b/wahwah~/Makefile
new file mode 100644
index 0000000..0a2837d
--- /dev/null
+++ b/wahwah~/Makefile
@@ -0,0 +1,82 @@
+NAME=wahwah~
+CSYM=wahwah~
+
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).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
+
+.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
+
+.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
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -DUNIX -DICECAST -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wno-shadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch #-Werror
+
+LINUXINCLUDE = -I../../src
+
+.c.pd_linux:
+ cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ ld -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o ../$*.pd_linux
+ ln -s $*/$*.pd_linux ..
+
+# ----------------------------------------------------------
+
+install:
+ cp help-*.pd rs-*.pd ../../doc/5.reference
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/wahwah~/README b/wahwah~/README
new file mode 100644
index 0000000..6565787
--- /dev/null
+++ b/wahwah~/README
@@ -0,0 +1,24 @@
+Version 0.01
+copyleft 2002 by Yves Degoyon.
+
+tarballs and updates available @ http://ydegoyon.free.fr
+
+wahwah~ : a kind of effect used in psychedelic music, use it elsewhere
+
+the algorithm was taken from Digital Effects,
+a guitar effects software for DOS which rocks, written by Alexey Smoli
+( http://st.karelia.ru/~smlalx/ )
+
+To install wahwah~, follow the steps from INSTALL
+
+This software is published under GPL terms, see COPYING
+for rights restrictions.
+
+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.
+
+*****************************************************************************
+
diff --git a/wahwah~/help-wahwah~.pd b/wahwah~/help-wahwah~.pd
new file mode 100644
index 0000000..8afeb3c
--- /dev/null
+++ b/wahwah~/help-wahwah~.pd
@@ -0,0 +1,48 @@
+#N canvas 45 57 817 573 10;
+#X text 319 534 comments & bugs @ ydegoyon.free.fr;
+#X text 431 111 Wahwah~ : used in psychedelic music;
+#X obj 144 411 dac~;
+#X obj 148 377 rs-wahwah~;
+#X msg 94 62 bang;
+#X obj 93 84 openpanel;
+#X obj 93 104 t s b;
+#X obj 150 106 float \$0;
+#X text 101 39 Step 1 : Load a sound file;
+#X obj 93 127 route float;
+#X obj 94 219 soundfiler;
+#X text 151 55 ( maybe \, a guitar sound ? );
+#X obj 93 150 makefilename %d-sample;
+#X obj 582 374 table \$0-sample;
+#X msg 94 197 read -resize \$1 \$2;
+#X obj 95 176 pack s s;
+#X msg 146 307 bang;
+#X text 191 307 Step 2 : Start playing;
+#X obj 59 288 adc~;
+#X text 229 379 Step 3 : Modify parameters;
+#X text 487 483 ( http://st.karelia.ru/~smlalx );
+#X text 320 470 a DOS guitar effects software that rocks;
+#X text 321 484 written by Alexei Smoli;
+#X obj 606 263 loadbang;
+#X msg 608 293 \; pd dsp 1;
+#X text 319 456 the algorithm is borrowed from Digital Effects \,;
+#X obj 146 354 tabplay~ \$0-sample;
+#X text 35 266 Plug a guitar ??;
+#X msg 228 330 stop;
+#X obj 146 330 metro 250;
+#X connect 3 0 2 0;
+#X connect 3 0 2 1;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 6 0 15 0;
+#X connect 6 1 7 0;
+#X connect 7 0 9 0;
+#X connect 9 0 12 0;
+#X connect 12 0 15 1;
+#X connect 14 0 10 0;
+#X connect 15 0 14 0;
+#X connect 16 0 29 0;
+#X connect 18 0 3 0;
+#X connect 23 0 24 0;
+#X connect 26 0 3 0;
+#X connect 28 0 29 0;
+#X connect 29 0 26 0;
diff --git a/wahwah~/rs-wahwah~.pd b/wahwah~/rs-wahwah~.pd
new file mode 100644
index 0000000..af5c256
--- /dev/null
+++ b/wahwah~/rs-wahwah~.pd
@@ -0,0 +1,348 @@
+#N canvas 97 16 837 658 10;
+#X obj 87 469 outlet~;
+#X msg 149 24 preset 1;
+#X msg 149 46 preset 2;
+#X msg 149 71 preset 3;
+#X msg 149 95 preset 4;
+#X msg 149 118 preset 5;
+#X text 216 25 fast change medium wah-wah;
+#X text 217 46 slow change medium wah-wah;
+#X text 219 71 fast wah-wah;
+#X text 219 94 ranged wah-wah;
+#X obj 53 307 inlet~;
+#X text 220 117 wah-wah 400/2000 Hz;
+#X obj 177 468 tabwrite~ owahwah;
+#N canvas 0 0 450 300 graph1 0;
+#X array owahwah 2000 float 1;
+#A 0 -0.039093 -0.0409546 -0.0498657 -0.0647583 -0.0871887 -0.115601
+-0.149658 -0.186188 -0.222839 -0.259918 -0.295898 -0.328308 -0.356567
+-0.380859 -0.399689 -0.412933 -0.419983 -0.419434 -0.410675 -0.392517
+-0.365753 -0.331726 -0.29129 -0.245361 -0.196503 -0.148499 -0.103546
+-0.0623779 -0.0287476 -0.00424194 0.00881958 0.0116577 0.00469971 -0.0116577
+-0.0361023 -0.0664978 -0.100555 -0.136414 -0.172302 -0.205841 -0.235596
+-0.261932 -0.283508 -0.299713 -0.311584 -0.318848 -0.321991 -0.322968
+-0.322998 -0.322662 -0.321503 -0.321228 -0.321503 -0.321747 -0.322876
+-0.323883 -0.324463 -0.324066 -0.320892 -0.31308 -0.299133 -0.277191
+-0.244019 -0.198334 -0.139526 -0.0670471 0.0205078 0.121002 0.230194
+0.344482 0.460846 0.573944 0.677521 0.765656 0.833282 0.876801 0.893036
+0.882629 0.846802 0.78891 0.714539 0.629425 0.539551 0.452789 0.374146
+0.307892 0.257263 0.222931 0.204132 0.19812 0.20163 0.210175 0.21933
+0.225739 0.22525 0.214874 0.194916 0.164948 0.12674 0.0838013 0.0399475
+-0.00134277 -0.0376587 -0.0657654 -0.0814819 -0.0820007 -0.0656738
+-0.0337219 0.0140381 0.0779724 0.156006 0.245911 0.346008 0.452057
+0.559235 0.663025 0.757202 0.837769 0.896179 0.925873 0.922516 0.882751
+0.806122 0.694183 0.55191 0.387329 0.210052 0.0307922 -0.138519 -0.286224
+-0.401611 -0.480316 -0.519104 -0.516846 -0.47644 -0.40213 -0.299652
+-0.175842 -0.0374451 0.108887 0.257507 0.401276 0.536102 0.658722 0.767181
+0.857239 0.927002 0.974548 0.99762 0.995697 0.969116 0.919312 0.852112
+0.772278 0.684723 0.5961 0.511749 0.437042 0.374969 0.326416 0.289948
+0.260529 0.233032 0.201965 0.157501 0.0927124 0.00149536 -0.120087
+-0.272583 -0.452911 -0.653748 -0.863739 -1 -1 -1 -1 -1 -1 -1 -1 -1
+-0.973389 -0.805054 -0.654327 -0.533722 -0.449554 -0.403442 -0.390808
+-0.404175 -0.431488 -0.458344 -0.471954 -0.461639 -0.419342 -0.340942
+-0.226868 -0.0821228 0.0829468 0.257294 0.426544 0.577087 0.695618
+0.771759 0.798157 0.771332 0.692352 0.566376 0.402252 0.209686 -0.00247192
+-0.22171 -0.43985 -0.650452 -0.847473 -1 -1 -1 -1 -1 -1 -1 -1 -1 -0.739136
+-0.431183 -0.0951538 0.245636 0.56543 0.838531 0.999969 0.999969 0.999969
+0.999969 0.999969 0.802216 0.559937 0.29715 0.0325623 -0.217773 -0.442688
+-0.636414 -0.795715 -0.92099 -1 -1 -1 -1 -1 -1 -1 -0.950989 -0.852966
+-0.744476 -0.634064 -0.530029 -0.443756 -0.384125 -0.356415 -0.362183
+-0.400238 -0.46228 -0.535309 -0.604767 -0.653046 -0.661835 -0.615387
+-0.499878 -0.308197 -0.0406799 0.294312 0.67923 0.999969 0.999969 0.999969
+0.999969 0.999969 0.999969 0.999969 0.999969 0.999969 0.999969 0.966919
+0.579712 0.242889 -0.0168762 -0.183319 -0.249573 -0.221954 -0.117706
+0.0397949 0.221771 0.399139 0.544708 0.6362 0.657806 0.601624 0.468964
+0.27002 0.0221863 -0.252197 -0.526459 -0.774719 -0.97522 -1 -1 -1 -1
+-0.943573 -0.758942 -0.54248 -0.306366 -0.0611267 0.189514 0.443115
+0.697449 0.950439 0.999969 0.999969 0.999969 0.999969 0.964325 0.130615
+-0.55246 -1 -1 -1 -1 -0.892181 -0.560394 -0.220734 0.0826416 0.317352
+0.468048 0.532959 0.52005 0.447357 0.337616 0.211273 0.0874939 -0.0170288
+-0.0913391 -0.131683 -0.139923 -0.121124 -0.0817871 -0.0301208 0.024353
+0.0731506 0.110504 0.135773 0.148865 0.149841 0.140442 0.124298 0.106171
+0.0886841 0.0727234 0.059021 0.0523376 0.0513 0.0559692 0.0643921 0.0751648
+0.0877991 0.100708 0.112091 0.121948 0.129303 0.135132 0.138153 0.14032
+0.140869 0.138428 0.133514 0.126801 0.11853 0.109406 0.0989685 0.0881042
+0.0773621 0.0661926 0.0561829 0.0480652 0.0427246 0.0401917 0.0408325
+0.0447388 0.0513611 0.0603638 0.0705261 0.0811157 0.0899658 0.0986023
+0.109009 0.120209 0.129822 0.13736 0.143433 0.147369 0.147949 0.144257
+0.136719 0.125061 0.11264 0.098175 0.0823669 0.0648804 0.0462036 0.0277405
+0.0106812 -0.00558472 -0.0222473 -0.0386353 -0.0551147 -0.0707397 -0.0862732
+-0.100494 -0.114716 -0.129669 -0.144409 -0.158783 -0.17392 -0.188385
+-0.202057 -0.214661 -0.228119 -0.240845 -0.252014 -0.262207 -0.269958
+-0.2742 -0.275787 -0.275604 -0.273346 -0.268707 -0.26062 -0.249481
+-0.234894 -0.216797 -0.196503 -0.174866 -0.1521 -0.129639 -0.108246
+-0.0873108 -0.0687561 -0.0557556 -0.0469055 -0.0423889 -0.0438843 -0.052002
+-0.0664673 -0.0872803 -0.114227 -0.145477 -0.179688 -0.217499 -0.255646
+-0.293396 -0.329254 -0.361755 -0.387848 -0.407257 -0.419189 -0.423859
+-0.421204 -0.410278 -0.390991 -0.363373 -0.32843 -0.288849 -0.245178
+-0.199188 -0.151886 -0.106201 -0.0655518 -0.0318909 -0.00665283 0.00817871
+0.0127258 0.00680542 -0.00918579 -0.0333862 -0.0639954 -0.0982666 -0.134338
+-0.170715 -0.205658 -0.237183 -0.263855 -0.28479 -0.300812 -0.31189
+-0.319458 -0.324249 -0.325256 -0.324219 -0.322723 -0.320953 -0.319489
+-0.319427 -0.319794 -0.32132 -0.323334 -0.325684 -0.325531 -0.321503
+-0.31308 -0.298218 -0.275696 -0.2435 -0.198578 -0.140106 -0.0680542
+0.0185242 0.117798 0.226654 0.342102 0.459686 0.574188 0.679474 0.769562
+0.838745 0.882385 0.899384 0.889221 0.853149 0.795837 0.721283 0.636169
+0.547119 0.459595 0.379211 0.31076 0.25708 0.219452 0.197266 0.188873
+0.192383 0.202209 0.213013 0.220642 0.221832 0.213165 0.19397 0.16626
+0.13089 0.088623 0.0440369 0.000915527 -0.0377197 -0.0675049 -0.0849304
+-0.0869141 -0.0715332 -0.0384521 0.0113525 0.0761108 0.153351 0.243347
+0.34433 0.450195 0.559174 0.665131 0.762085 0.843048 0.900848 0.930298
+0.927399 0.887878 0.810791 0.698273 0.555084 0.390106 0.211395 0.0317383
+-0.137634 -0.286163 -0.404236 -0.485474 -0.526031 -0.525208 -0.485352
+-0.40918 -0.304932 -0.179535 -0.0396118 0.107544 0.255615 0.399872
+0.536102 0.660431 0.770782 0.86261 0.9328 0.980865 0.999969 0.999969
+0.974121 0.92453 0.856995 0.77594 0.6875 0.598267 0.51413 0.439209
+0.374847 0.322754 0.283844 0.25415 0.227539 0.196381 0.153137 0.0905762
+0.00128174 -0.119019 -0.271637 -0.452423 -0.653564 -0.863922 -1 -1
+-1 -1 -1 -1 -1 -1 -1 -0.983398 -0.81308 -0.660461 -0.537537 -0.450836
+-0.401978 -0.387848 -0.399719 -0.425385 -0.452332 -0.466919 -0.458435
+-0.417389 -0.341614 -0.229828 -0.0864868 0.0791321 0.254517 0.425201
+0.577057 0.696777 0.775177 0.805115 0.779572 0.700653 0.57431 0.409943
+0.216797 0.00445557 -0.216492 -0.4375 -0.651215 -0.849945 -1 -1 -1
+-1 -1 -1 -1 -1 -1 -0.74588 -0.435699 -0.0969238 0.246063 0.567993 0.84314
+0.999969 0.999969 0.999969 0.999969 0.999969 0.809875 0.567505 0.303864
+0.0378418 -0.21463 -0.440674 -0.63559 -0.796692 -0.923798 -1 -1 -1
+-1 -1 -1 -1 -0.955811 -0.856628 -0.747009 -0.635651 -0.53183 -0.44516
+-0.384369 -0.356354 -0.361908 -0.400787 -0.461456 -0.533783 -0.603088
+-0.651306 -0.660767 -0.614563 -0.500214 -0.311096 -0.0456238 0.2883
+0.672974 0.999969 0.999969 0.999969 0.999969 0.999969 0.999969 0.999969
+0.999969 0.999969 0.999969 0.980499 0.590179 0.248199 -0.017334 -0.188782
+-0.259674 -0.235291 -0.132233 0.0249329 0.207764 0.386719 0.536774
+0.632294 0.657349 0.604553 0.475098 0.278259 0.0308228 -0.243103 -0.517395
+-0.768127 -0.973206 -1 -1 -1 -1 -0.959106 -0.774323 -0.556854 -0.318909
+-0.0692749 0.185944 0.443298 0.699951 0.954834 0.999969 0.999969 0.999969
+0.999969 0.974457 0.143829 -0.53949 -1 -1 -1 -1 -0.903381 -0.576324
+-0.239136 0.0640564 0.302643 0.458801 0.528595 0.521362 0.454559 0.34787
+0.223083 0.100708 -0.00384521 -0.0808716 -0.125244 -0.137299 -0.120941
+-0.0837097 -0.034668 0.0179138 0.0670166 0.107178 0.134186 0.148346
+0.149567 0.141113 0.127106 0.109955 0.0914917 0.0743103 0.0613708 0.0543518
+0.0514832 0.055542 0.0632629 0.0738831 0.086853 0.099884 0.112457 0.124176
+0.133881 0.140839 0.144562 0.143829 0.141327 0.13858 0.13269 0.124756
+0.116364 0.106812 0.0970764 0.0872192 0.0769348 0.0671387 0.0580139
+0.0501099 0.0437927 0.0418701 0.042572 0.0460205 0.052002 0.0600281
+0.0696106 0.0800171 0.0906982 0.101837 0.113098 0.123444 0.132507 0.139282
+0.144073 0.146057 0.145508 0.142029 0.135498 0.126556 0.115082 0.100403
+0.0848389 0.0665894 0.0477295 0.028595 0.00961304 -0.00848389 -0.0257874
+-0.0423584 -0.0579224 -0.0725403 -0.0869141 -0.101044 -0.115021 -0.129028
+-0.143372 -0.157471 -0.171783 -0.185913 -0.200317 -0.21463 -0.227814
+-0.240723 -0.25351 -0.263885 -0.272064 -0.27774 -0.278992 -0.277557
+-0.274323 -0.269073 -0.261414 -0.250854 -0.237091 -0.220551 -0.20047
+-0.177368 -0.153992 -0.131348 -0.108795 -0.0869141 -0.0672302 -0.0518494
+-0.0414734 -0.0362549 -0.0380554 -0.0472107 -0.0631714 -0.0870361 -0.115936
+-0.148407 -0.183716 -0.220856 -0.258362 -0.294525 -0.328491 -0.360291
+-0.386597 -0.405731 -0.418732 -0.424011 -0.420502 -0.409485 -0.390564
+-0.363495 -0.329498 -0.289948 -0.245575 -0.19812 -0.151825 -0.106964
+-0.0662842 -0.0315247 -0.00631714 0.00808716 0.0121765 0.00619507 -0.00915527
+-0.0331421 -0.0646973 -0.0995178 -0.135773 -0.170959 -0.204376 -0.234741
+-0.261475 -0.283386 -0.300293 -0.312531 -0.320435 -0.325775 -0.328857
+-0.328583 -0.327423 -0.324768 -0.321655 -0.320312 -0.320129 -0.321136
+-0.323212 -0.325043 -0.325714 -0.324677 -0.317566 -0.303802 -0.280762
+-0.246704 -0.200073 -0.140594 -0.0681763 0.0187073 0.119446 0.22998
+0.346741 0.465454 0.579559 0.684998 0.774353 0.843231 0.887451 0.903961
+0.892273 0.854736 0.795959 0.72168 0.636566 0.546875 0.457825 0.378052
+0.311493 0.258972 0.22226 0.201965 0.194702 0.195862 0.202515 0.211456
+0.21814 0.218964 0.211273 0.19342 0.165619 0.129242 0.0864563 0.0415344
+-0.000946045 -0.0385132 -0.0675964;
+#A 1000 -0.0828857 -0.0823669 -0.0689392 -0.0388794 0.00836182 0.0713806
+0.14975 0.241821 0.343811 0.451385 0.560455 0.666168 0.763092 0.844269
+0.90271 0.933441 0.93103 0.891785 0.815155 0.70285 0.559235 0.392944
+0.213409 0.0327759 -0.138458 -0.288544 -0.407806 -0.489197 -0.529602
+-0.528931 -0.489471 -0.415192 -0.311523 -0.184967 -0.0444336 0.103973
+0.253021 0.398804 0.536804 0.662079 0.772064 0.864349 0.936188 0.985199
+0.999969 0.999969 0.978607 0.930573 0.862488 0.779633 0.689514 0.59845
+0.512878 0.437439 0.373901 0.32309 0.284149 0.25415 0.226807 0.195282
+0.150726 0.0862732 -0.00366211 -0.123627 -0.274872 -0.454132 -0.654205
+-0.864258 -1 -1 -1 -1 -1 -1 -1 -1 -1 -0.991821 -0.820068 -0.665405
+-0.541504 -0.453644 -0.403442 -0.386169 -0.39621 -0.42099 -0.446625
+-0.461151 -0.453278 -0.413788 -0.338745 -0.227814 -0.0853882 0.0786133
+0.252533 0.423523 0.576965 0.698975 0.777679 0.805695 0.781158 0.704956
+0.580536 0.416809 0.222107 0.00863647 -0.21347 -0.435455 -0.649841
+-0.850922 -1 -1 -1 -1 -1 -1 -1 -1 -1 -0.750519 -0.43869 -0.0991211
+0.245605 0.57016 0.846985 0.999969 0.999969 0.999969 0.999969 0.999969
+0.822144 0.578339 0.312134 0.0435181 -0.211853 -0.442688 -0.641357
+-0.804596 -0.932831 -1 -1 -1 -1 -1 -1 -1 -0.957397 -0.857697 -0.746979
+-0.63446 -0.530609 -0.444061 -0.383301 -0.354889 -0.360779 -0.397675
+-0.457886 -0.530243 -0.599121 -0.648041 -0.658875 -0.614075 -0.501556
+-0.313599 -0.0487061 0.285431 0.670898 0.999969 0.999969 0.999969 0.999969
+0.999969 0.999969 0.999969 0.999969 0.999969 0.999969 0.994263 0.600861
+0.254944 -0.0148621 -0.190338 -0.26413 -0.241058 -0.140289 0.015686
+0.198242 0.379211 0.530151 0.627045 0.654694 0.604462 0.477448 0.282654
+0.0371704 -0.236206 -0.513153 -0.76593 -0.973389 -1 -1 -1 -1 -0.967407
+-0.781769 -0.56424 -0.324951 -0.0736084 0.183289 0.443054 0.702942
+0.960358 0.999969 0.999969 0.999969 0.999969 0.986908 0.159088 -0.523895
+-1 -1 -1 -1 -0.918671 -0.595154 -0.258484 0.046814 0.289673 0.451355
+0.529297 0.52771 0.463898 0.358154 0.232758 0.108521 0.00115967 -0.078125
+-0.124237 -0.138458 -0.124237 -0.089386 -0.0411987 0.0108032 0.0605774
+0.101654 0.130585 0.147491 0.152008 0.145264 0.131958 0.113983 0.0951233
+0.0777283 0.0628357 0.0530701 0.0495605 0.0513916 0.0587158 0.0714722
+0.0856323 0.0986938 0.110992 0.123718 0.133789 0.141266 0.145508 0.147034
+0.145386 0.140686 0.134216 0.125916 0.115723 0.105774 0.096283 0.0852051
+0.0751038 0.0665894 0.05896 0.0525513 0.0475464 0.0441895 0.0434875
+0.0458984 0.0515747 0.0593872 0.0674438 0.0768127 0.0877991 0.0993042
+0.110229 0.121124 0.131989 0.141052 0.147308 0.14975 0.148834 0.144836
+0.138489 0.129425 0.116486 0.100189 0.0821228 0.0637207 0.0458069 0.0279846
+0.0101318 -0.0088501 -0.0272217 -0.0437927 -0.0577393 -0.071228 -0.0854492
+-0.0998535 -0.11377 -0.127319 -0.141632 -0.157898 -0.17337 -0.187744
+-0.202179 -0.21701 -0.231873 -0.245453 -0.2565 -0.265259 -0.272217
+-0.2771 -0.278839 -0.277008 -0.272583 -0.267853 -0.261444 -0.251007
+-0.236786 -0.21933 -0.19931 -0.177551 -0.154633 -0.131104 -0.107788
+-0.0860291 -0.0675659 -0.0513306 -0.0410767 -0.037262 -0.0393066 -0.0481873
+-0.0643311 -0.0869446 -0.115143 -0.148315 -0.183868 -0.221497 -0.259308
+-0.29538 -0.328888 -0.359314 -0.384674 -0.403748 -0.416901 -0.423584
+-0.421875 -0.412445 -0.394135 -0.368683 -0.335114 -0.294617 -0.248718
+-0.200012 -0.150696 -0.103271 -0.0614319 -0.0278015 -0.00195312 0.0123291
+0.0169067 0.00997925 -0.0055542 -0.0300903 -0.0625 -0.0991211 -0.136505
+-0.172913 -0.207245 -0.238586 -0.265167 -0.287231 -0.30426 -0.316223
+-0.323425 -0.326294 -0.326965 -0.326263 -0.324585 -0.323242 -0.321442
+-0.32077 -0.320282 -0.322388 -0.323883 -0.32547 -0.326569 -0.324921
+-0.31781 -0.303741 -0.281006 -0.246765 -0.201111 -0.141479 -0.0682983
+0.0192566 0.11969 0.230042 0.346985 0.466461 0.582428 0.687988 0.777466
+0.847107 0.891693 0.908142 0.895447 0.859131 0.801605 0.726562 0.639618
+0.548218 0.459473 0.378784 0.310516 0.256836 0.219971 0.200043 0.192505
+0.195129 0.203156 0.211853 0.217621 0.218018 0.210602 0.192932 0.165924
+0.130157 0.0880737 0.0436707 0.000183105 -0.0377197 -0.0673523 -0.0857544
+-0.0892944 -0.0753784 -0.0438232 0.00436401 0.0688477 0.148773 0.241241
+0.343048 0.451538 0.561401 0.667877 0.76535 0.84613 0.903748 0.934753
+0.933105 0.895264 0.82016 0.707977 0.564514 0.39798 0.217407 0.0344543
+-0.138824 -0.291412 -0.41217 -0.494598 -0.535889 -0.534729 -0.494141
+-0.418274 -0.314331 -0.188263 -0.0472717 0.101135 0.25116 0.398132
+0.53775 0.665833 0.776978 0.870361 0.94281 0.990692 0.999969 0.999969
+0.980591 0.930176 0.862274 0.780884 0.691925 0.601074 0.516296 0.440979
+0.37616 0.324341 0.284668 0.253754 0.225769 0.192902 0.148743 0.0855713
+-0.00421143 -0.124268 -0.275452 -0.454956 -0.65567 -0.866638 -1 -1
+-1 -1 -1 -1 -1 -1 -1 -1 -0.828003 -0.672089 -0.544495 -0.453064 -0.400085
+-0.382477 -0.391357 -0.4151 -0.441681 -0.458649 -0.452606 -0.414001
+-0.339233 -0.228607 -0.0864258 0.078186 0.253143 0.424225 0.577881
+0.701019 0.781769 0.811951 0.789276 0.713867 0.589264 0.423553 0.227509
+0.0120239 -0.211914 -0.435303 -0.651703 -0.853729 -1 -1 -1 -1 -1 -1
+-1 -1 -1 -0.756287 -0.444092 -0.102905 0.243561 0.569672 0.849365 0.999969
+0.999969 0.999969 0.999969 0.999969 0.833405 0.590118 0.322998 0.0515442
+-0.206573 -0.438843 -0.638672 -0.804199 -0.935913 -1 -1 -1 -1 -1 -1
+-1 -0.96283 -0.861115 -0.749207 -0.636108 -0.531036 -0.444672 0.554535
+0.999969 0.999969 0.999969 0.999969 0.999969 0.999969 0.57547 0.100037
+-0.290497 -0.564453 -0.710022 -0.732971 -0.656952 -0.510254 -0.323334
+-0.128326 0.0491943 0.191101 0.28653 0.333221 0.336029 0.302673 0.245667
+0.17749 0.108307 0.0475159 0.00280762 -0.0238342 -0.0334473 -0.0276794
+-0.00997925 0.0147095 0.0418701 0.0684509 0.0918579 0.109528 0.120117
+0.124176 0.123077 0.118225 0.111725 0.105469 0.100128 0.0970154 0.0969849
+0.0992432 0.105286 0.112579 0.120056 0.12735 0.133453 0.136932 0.136902
+0.133301 0.126068 0.116638 0.105255 0.0941467 0.0830078 0.0715942 0.0602722
+0.0501099 0.0424805 0.0380859 0.0365295 0.0378418 0.0431519 0.0505371
+0.0605164 0.0729065 0.0870056 0.100586 0.114044 0.126099 0.136108 0.144623
+0.150208 0.151245 0.149628 0.145538 0.13916 0.1297 0.11673 0.101257
+0.0846252 0.0667725 0.0483398 0.0305786 0.0133057 -0.00411987 -0.0206909
+-0.0389404 -0.0566406 -0.0726929 -0.0880432 -0.102997 -0.11734 -0.131409
+-0.145782 -0.159973 -0.174347 -0.189453 -0.204712 -0.218262 -0.231842
+-0.243958 -0.254822 -0.264679 -0.272614 -0.278137 -0.280457 -0.277985
+-0.274139 -0.26651 -0.255615 -0.242767 -0.227753 -0.210876 -0.192017
+-0.171631 -0.150085 -0.12796 -0.106537 -0.0864563 -0.0697632 -0.0567932
+-0.0470886 -0.0434875 -0.0454712 -0.0533142 -0.0669861 -0.0858154 -0.109589
+-0.138916 -0.174042 -0.212128 -0.25116 -0.289917 -0.327362 -0.36142
+-0.389282 -0.410004 -0.423279 -0.428436 -0.42514 -0.413666 -0.39328
+-0.365875 -0.330109 -0.287811 -0.241241 -0.193298 -0.146057 -0.101135
+-0.0602417 -0.0259705 -0.00109863 0.0117798 0.0144653 0.00726318 -0.00985718
+-0.033844 -0.062439 -0.0951843 -0.13028 -0.165527 -0.199432 -0.230042
+-0.256622 -0.279663 -0.296783 -0.30954 -0.317444 -0.32251 -0.324615
+-0.324493 -0.323944 -0.323425 -0.322845 -0.324738 -0.325836 -0.326599
+-0.327118 -0.327057 -0.325226 -0.320679 -0.311951 -0.296753 -0.273376
+-0.240204 -0.194733 -0.136108 -0.0620117 0.0262451 0.125214 0.233795
+0.349182 0.466644 0.580963 0.68634 0.776581 0.846069 0.890045 0.907074
+0.899292 0.865997 0.809326 0.734558 0.647552 0.554962 0.463654 0.380096
+0.30957 0.255005 0.218353 0.196045 0.187775 0.189697 0.198151 0.208984
+0.216583 0.217407 0.209686 0.192047 0.165222 0.12973 0.0860291 0.0411072
+-0.00177002 -0.0402222 -0.0692444 -0.0855408 -0.087616 -0.0743713 -0.04422
+0.00427246 0.0694275 0.149475 0.241608 0.343414 0.451263 0.561371 0.667389
+0.764069 0.845642 0.905365 0.937836 0.937012 0.899841 0.82428 0.711792
+0.567657 0.39978 0.217377 0.0335083 -0.139648 -0.292023 -0.41394 -0.498688
+-0.541809 -0.54184 -0.500946 -0.424866 -0.320526 -0.195007 -0.0548401
+0.0941772 0.246277 0.395569 0.536713 0.665955 0.779266 0.873901 0.947601
+0.99646 0.999969 0.999969 0.985901 0.934845 0.865417 0.782837 0.693024
+0.601807 0.516235 0.439514 0.374481 0.323212 0.284424 0.253693 0.225494
+0.193054 0.148132 0.0826416 -0.00842285 -0.127563 -0.278015 -0.457214
+-0.657013 -0.867767 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -0.832947 -0.674957
+-0.546509 -0.455109 -0.401459 -0.381561 -0.38913 -0.413025 -0.43924
+-0.454773 -0.44754 -0.410187 -0.338013 -0.229919 -0.0897827 0.0737915
+0.248657 0.420746 0.575073 0.701202 0.783661 0.81601 0.795135 0.720795
+0.597382 0.432526 0.236237 0.0197754 -0.20636 -0.433411 -0.651581 -0.85675
+-1 -1 -1 -1 -1 -1 -1 -1 -1 -0.761597 -0.449127 -0.10733 0.240723 0.567749
+0.849518 0.999969 0.999969 0.999969 0.999969 0.999969 0.846893 0.602264
+0.333496 0.0600586 -0.202484 -0.440704 -0.646301 -0.815704 -0.948914
+-1 -1 -1 -1 -1 -1 -1 -0.964539 -0.862732 -0.751526 -0.638733 -0.534088
+-0.447662 -0.387573 -0.358978 -0.362793 -0.397034 -0.4552 -0.525391
+-0.592346 -0.640137 -0.651886 -0.610596 -0.502045 -0.315704 -0.0520325
+0.280945 0.666718 0.999969;
+#X coords 0 2 1999 -2 200 140 1;
+#X restore 596 461 graph;
+#X msg 177 446 bang;
+#X obj 602 315 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 1270 0;
+#X text 607 295 The pedal (step);
+#X obj 601 216 f;
+#X obj 632 216 + 1;
+#X msg 599 158 bang;
+#X obj 645 242 > 100;
+#X obj 688 241 route 1;
+#X msg 685 215 -1;
+#X msg 559 216 0;
+#X obj 693 185 route 1;
+#X obj 664 186 < 0;
+#X msg 690 159 1;
+#X msg 555 160 stop;
+#X obj 161 187 hsl 128 15 0 3000 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 5600 0;
+#X text 162 166 Minimum freq [ 0 - 3000 ];
+#X obj 212 221 hsl 128 15 0 3000 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 3300 0;
+#X text 207 205 Maximum freq [ 0 - 3000 ];
+#X obj 237 259 hsl 128 15 0 1000 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 4200 0;
+#X text 234 241 Sensibility [ 0 - 1000 ];
+#X obj 285 292 hsl 128 15 0 100 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 1100 0;
+#X text 280 275 Maxstep [ 0 - 100 ];
+#X obj 340 327 hsl 128 15 -15 15 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 12400 0;
+#X text 335 310 Gain [ -15 - 15 ];
+#X obj 408 369 hsl 128 15 0 10 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 5000 0;
+#X text 403 351 Bandwidth [ 0 - 10 ];
+#X text 597 126 Auto;
+#X text 164 148 Note : setting a parameter overrides presets;
+#X obj 87 414 wahwah~ --------------------------------------------------
+;
+#X text 133 543 Note : interesting to set bandwith close to 10;
+#X obj 600 185 metro 10;
+#X obj 648 127 loadbang;
+#X connect 1 0 42 0;
+#X connect 2 0 42 0;
+#X connect 3 0 42 0;
+#X connect 4 0 42 0;
+#X connect 5 0 42 0;
+#X connect 10 0 42 0;
+#X connect 14 0 12 0;
+#X connect 15 0 42 7;
+#X connect 17 0 18 0;
+#X connect 17 0 20 0;
+#X connect 17 0 25 0;
+#X connect 17 0 15 0;
+#X connect 18 0 17 1;
+#X connect 19 0 44 0;
+#X connect 20 0 21 0;
+#X connect 21 0 22 0;
+#X connect 22 0 18 1;
+#X connect 23 0 17 0;
+#X connect 24 0 26 0;
+#X connect 25 0 24 0;
+#X connect 26 0 18 1;
+#X connect 27 0 44 0;
+#X connect 28 0 42 1;
+#X connect 30 0 42 2;
+#X connect 32 0 42 3;
+#X connect 34 0 42 4;
+#X connect 36 0 42 5;
+#X connect 38 0 42 6;
+#X connect 42 0 0 0;
+#X connect 42 0 12 0;
+#X connect 44 0 17 0;
+#X connect 45 0 19 0;
diff --git a/wahwah~/wahwah~.c b/wahwah~/wahwah~.c
new file mode 100644
index 0000000..72c77d4
--- /dev/null
+++ b/wahwah~/wahwah~.c
@@ -0,0 +1,409 @@
+/* Copyright (c) 2002 Yves Degoyon. */
+/* For information on usage and redistribution, and for a DISCLAIMER OF ALL */
+/* WARRANTIES, see the file, "COPYING" in this distribution. */
+/* */
+/* wahwah~ -- a kind of effect used in psychedelic music */
+/* the algorithm was taken from Digital Effects, */
+/* a guitar effects software for DOS which rocks, written by Alexey Smoli */
+/* ( http://st.karelia.ru/~smlalx/ ) */
+/* */
+/* 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. */
+/* */
+/* Made while listening to : */
+/* */
+/* Crass -- "Shaved Women ( Collaborators )" */
+/* Zounds -- "Can't Cheat Karma" */
+/* */
+/* Special message for the french : */
+/* "Delay all your work...and go vote against national front" */
+/* ---------------------------------------------------------------------------- */
+
+#include "m_pd.h"
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef NT
+#define M_PI 3.14159265358979323846
+#endif
+
+#define BFSZ 4096 /* main delay buffer */
+#define BLOCK_DELAY 10 /* number of blocks to delay */
+#define NA 0.0 /* param not applicable */
+#define COEFFSIZE 3000 /* coefficients size */
+#define NBCOEFFS 5 /* number of coefficients */
+
+static char *wahwah_version = "wahwah~: an audio wahwah, version 0.1 (ydegoyon@free.fr)";
+
+typedef struct _wahwah
+{
+ t_object x_obj;
+ double *x_buf;
+ t_int x_samplerate;
+ t_float *x_coeffs;
+ double x_minfc; /* min frequency Hz */ /* 0< <3000 */
+ double x_maxfc; /* max frequency Hz */ /* 0< <3000 */
+ double x_sense; /* increase/decrease frequency change by one mouse movement Hz */ /* 0< <=1000 */
+ double x_maxstep; /* maximum frequency change step KHz */ /* 0< <=100 */
+ double x_dbgain; /* peaking filter gain dB */ /* -15<= <=15 */
+ double x_bandwidth; /* bandwidth in octaves (between midpoint (dBgain/2)
+ gain frequencies) or */ /* 0< <10 */
+ double x_Q; /* the EE kinda definition */ /* 0< <=1 */
+
+ /* variables for audio computation */
+ double min_coef,max_coef,cur_coef,step,maxstep;
+ t_int down;
+ /* amplitudes */
+ short x0,x1,x2;
+ t_int y0,y1,y2;
+
+ t_float x_f;
+} t_wahwah;
+
+static t_class *wahwah_class;
+
+static void wahwah_set_coeffs (t_wahwah *x)
+{
+ t_int i;
+ double omega;
+ double sn,cs;
+ double alpha = 0.0;
+ /* filter coefficients */
+ double a0,a1,a2,b0,b1,b2;
+ double A;
+
+ A = exp(x->x_dbgain/40.0)*log(10.0);
+ for (i = 0; i < COEFFSIZE; i++)
+ {
+ omega = 2.0*M_PI*(double)i/(double)x->x_samplerate;
+ sn = sin(omega);
+ cs = cos(omega);
+ if (x->x_bandwidth)
+ alpha = sn*sin(log(2.0)/2.0*x->x_bandwidth*omega/sn);
+ else
+ /* if Q is specified instead of bandwidth */
+ if (x->x_Q)
+ alpha = sn/(2.0*x->x_Q);
+
+ /* then compute the coefs for whichever filter type you want */
+ b0 = 1.0 + alpha*A;
+ b1 = -2.0*cs ;
+ b2 = 1.0 - alpha*A;
+ a0 = 1.0 + alpha/A;
+ a1 = -2.0*cs ;
+ a2 = 1.0 - alpha/A;
+
+ *(x->x_coeffs+i*NBCOEFFS) = (b0/a0);
+ *(x->x_coeffs+i*NBCOEFFS+1) = (b1/a0);
+ *(x->x_coeffs+i*NBCOEFFS+2) = (b2/a0);
+ *(x->x_coeffs+i*NBCOEFFS+3) = (a1/a0);
+ *(x->x_coeffs+i*NBCOEFFS+4) = (a2/a0);
+ // post( "wahwah~ : coeff : %f", *(x->x_coeffs+i*NBCOEFFS+4) );
+ }
+ x->min_coef = x->x_minfc;
+ x->max_coef = x->x_maxfc;
+ x->cur_coef = x->min_coef;
+ x->down = 1;
+ x->step = 0;
+ x->maxstep = x->x_maxstep/(double)x->x_samplerate*1000.0;
+}
+
+static void wahwah_bandwidth(t_wahwah *x, t_floatarg fbandwidth )
+{
+ if ( fbandwidth > 10.0 )
+ {
+ fbandwidth = 10.0;
+ }
+ if ( fbandwidth < 0.0 )
+ {
+ fbandwidth = 0.0;
+ }
+ x->x_bandwidth = fbandwidth;
+ // post( "wahwah~ : bandwidth: %f", x->x_bandwidth );
+ wahwah_set_coeffs( x );
+}
+
+static void wahwah_dbgain(t_wahwah *x, t_floatarg fdbgain )
+{
+ if ( fdbgain > 15.0 )
+ {
+ fdbgain = 15.0;
+ }
+ if ( fdbgain < -15.0 )
+ {
+ fdbgain = -15.0;
+ }
+ x->x_dbgain = fdbgain;
+ // post( "wahwah~ : dbgain: %f", x->x_dbgain );
+ wahwah_set_coeffs( x );
+}
+
+static void wahwah_maxstep(t_wahwah *x, t_floatarg fmaxstep )
+{
+ if ( fmaxstep > 100.0 )
+ {
+ fmaxstep = 100.0;
+ }
+ if ( fmaxstep < 0.0 )
+ {
+ fmaxstep = 0.0;
+ }
+ x->x_maxstep = fmaxstep;
+ // post( "wahwah~ : maxstep: %f", x->x_maxstep );
+ wahwah_set_coeffs( x );
+}
+
+static void wahwah_sensibility(t_wahwah *x, t_floatarg fsensibility )
+{
+ if ( fsensibility > 1000.0 )
+ {
+ fsensibility = 1000.0;
+ }
+ if ( fsensibility < 0.0 )
+ {
+ fsensibility = 0.0;
+ }
+ x->x_sense = fsensibility;
+ // post( "wahwah~ : sensibility: %f", x->x_sense );
+ wahwah_set_coeffs( x );
+}
+
+static void wahwah_maxfreq(t_wahwah *x, t_floatarg fmaxfreq )
+{
+ if ( fmaxfreq > 3000.0 )
+ {
+ fmaxfreq = 3000.0;
+ }
+ if ( fmaxfreq < 0.0 )
+ {
+ fmaxfreq = 0.0;
+ }
+ x->x_maxfc = fmaxfreq;
+ // post( "wahwah~ : maxfreq: %f", x->x_maxfc );
+ wahwah_set_coeffs( x );
+}
+
+static void wahwah_minfreq(t_wahwah *x, t_floatarg fminfreq )
+{
+ if ( fminfreq > 3000.0 )
+ {
+ fminfreq = 3000.0;
+ }
+ if ( fminfreq < 0.0 )
+ {
+ fminfreq = 0.0;
+ }
+ x->x_minfc = fminfreq;
+ // post( "wahwah~ : minfreq: %f", x->x_minfc );
+ wahwah_set_coeffs( x );
+}
+
+static void wahwah_step(t_wahwah *x, t_floatarg fstep )
+{
+ if ( fstep > x->x_maxstep )
+ {
+ fstep = x->x_maxstep;
+ }
+ if ( fstep < 0 )
+ {
+ fstep = 0;
+ }
+ x->step = fstep*x->x_sense/x->x_samplerate;
+}
+
+static t_int *wahwah_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ t_int n = (int)(w[3]);
+ t_wahwah *x = (t_wahwah*)(w[4]);
+ t_int i;
+
+ for (i=0; i<n; i++)
+ {
+ /* read input */
+ x->x0 = (int)((*(in+i))*32768);
+
+ x->y0 = (*(x->x_coeffs+(int)x->cur_coef*NBCOEFFS))*x->x0
+ + (*(x->x_coeffs+(int)x->cur_coef*NBCOEFFS+1))*x->x1
+ + (*(x->x_coeffs+(int)x->cur_coef*NBCOEFFS+2))*x->x2
+ - (*(x->x_coeffs+(int)x->cur_coef*NBCOEFFS+3))*x->y1
+ - (*(x->x_coeffs+(int)x->cur_coef*NBCOEFFS+4))*x->y2;
+
+ x->y2 = x->y1;
+ x->y1 = x->y0;
+ x->x2 = x->x1;
+ x->x1 = x->x0;
+
+ if(x->y0 > 32767.0)
+ x->y0 = 32767.0;
+ else if(x->y0 < -32768.0)
+ x->y0 = -32768.0;
+
+ *(out+i) = (t_float)(x->y0) / 32768.0;
+
+ x->cur_coef = x->cur_coef+x->down*x->step*(abs(x->x0)/(0.5*32768.0));
+ // post ( "wahwah~ : cur coeff : %f", x->cur_coef );
+ if(x->cur_coef > x->max_coef)
+ {
+ x->cur_coef = x->max_coef;
+ x->down = -1;
+ }
+ else if(x->cur_coef < x->min_coef)
+ {
+ x->cur_coef = x->min_coef;
+ x->down = 1;
+ }
+
+ }
+
+ return (w+5);
+}
+
+static void wahwah_preset(t_wahwah *x, t_float pnumber)
+{
+ switch ( (int)pnumber )
+ {
+ /* fast change medium wah wah */
+ case 1:
+ x->x_minfc = 100.0;
+ x->x_maxfc = 1600.0;
+ x->x_sense = 100.0;
+ x->x_maxstep = 60.0;
+ x->x_dbgain = 15.0;
+ x->x_Q = 1.0;
+ break;
+
+ /* slow change medium wah wah */
+ case 2:
+ x->x_minfc = 100.0;
+ x->x_maxfc = 1600.0;
+ x->x_sense = 50.0;
+ x->x_maxstep = 36.0;
+ x->x_dbgain = 15.0;
+ x->x_Q = 1.0;
+ break;
+
+ /* fast wah wah */
+ case 3:
+ x->x_minfc = 100.0;
+ x->x_maxfc = 600.0;
+ x->x_sense = 100.0;
+ x->x_maxstep = 66.0;
+ x->x_dbgain = 15.0;
+ x->x_Q = 1.0;
+ break;
+
+ /* ranged wah wah */
+ case 4:
+ x->x_minfc = 10.0;
+ x->x_maxfc = 2900.0;
+ x->x_sense = 100.0;
+ x->x_maxstep = 66.0;
+ x->x_dbgain = 15.0;
+ x->x_Q = 1.0;
+ break;
+
+ /* wah wah 400 - 2000 */
+ case 5:
+ x->x_minfc = 400.0;
+ x->x_maxfc = 2000.0;
+ x->x_sense = 100.0;
+ x->x_maxstep = 66.0;
+ x->x_dbgain = 15.0;
+ x->x_Q = 1.0;
+ break;
+
+ default:
+ post( "wahwah~ : unknown preset requested : %d", pnumber );
+ return;
+ break;
+ }
+ wahwah_set_coeffs( x );
+}
+
+static void wahwah_dsp(t_wahwah *x, t_signal **sp)
+{
+ dsp_add(wahwah_perform, 4, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n, x );
+}
+
+ /* clean up */
+static void wahwah_free(t_wahwah *x)
+{
+ if ( x->x_buf != NULL ) {
+ freebytes(x->x_buf, BFSZ*sizeof( double ) );
+ post( "Freed %d bytes", BFSZ*sizeof( double ) );
+ x->x_buf = NULL;
+ }
+ if ( x->x_coeffs != NULL ) {
+ freebytes(x->x_coeffs, COEFFSIZE*NBCOEFFS*sizeof( t_float ) );
+ post( "Freed %d bytes", COEFFSIZE*NBCOEFFS*sizeof( t_float ));
+ x->x_coeffs = NULL;
+ }
+}
+
+static void *wahwah_new(void)
+{
+ t_wahwah *x = (t_wahwah *)pd_new(wahwah_class);
+ outlet_new(&x->x_obj, &s_signal);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("minfreq"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("maxfreq"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("sensibility"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("maxstep"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("dbgain"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("bandwidth"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("step"));
+
+ x->x_samplerate = (int)sys_getsr();
+
+ if ( !( x->x_buf = ( double* ) getbytes( BFSZ*sizeof( double ) ) ) )
+ {
+ post ("wahwah~ : could not allocate buffer" );
+ return NULL;
+ }
+ if ( !( x->x_coeffs = ( t_float* ) getbytes( COEFFSIZE*NBCOEFFS*sizeof( t_float ) ) ) )
+ {
+ post ("wahwah~ : could not allocate coeffs" );
+ return NULL;
+ }
+
+ // set default parameters
+ wahwah_preset( x, 1 );
+ wahwah_set_coeffs( x );
+
+ return (x);
+}
+
+void wahwah_tilde_setup(void)
+{
+ post( wahwah_version );
+ wahwah_class = class_new(gensym("wahwah~"), (t_newmethod)wahwah_new, (t_method)wahwah_free,
+ sizeof(t_wahwah), 0, 0);
+
+ CLASS_MAINSIGNALIN( wahwah_class, t_wahwah, x_f );
+ class_sethelpsymbol( wahwah_class, gensym("help-wahwah~.pd") );
+ class_addmethod(wahwah_class, (t_method)wahwah_step, gensym("step"), A_FLOAT, 0);
+ class_addmethod(wahwah_class, (t_method)wahwah_minfreq, gensym("minfreq"), A_FLOAT, 0);
+ class_addmethod(wahwah_class, (t_method)wahwah_maxfreq, gensym("maxfreq"), A_FLOAT, 0);
+ class_addmethod(wahwah_class, (t_method)wahwah_sensibility, gensym("sensibility"), A_FLOAT, 0);
+ class_addmethod(wahwah_class, (t_method)wahwah_maxstep, gensym("maxstep"), A_FLOAT, 0);
+ class_addmethod(wahwah_class, (t_method)wahwah_dbgain, gensym("dbgain"), A_FLOAT, 0);
+ class_addmethod(wahwah_class, (t_method)wahwah_bandwidth, gensym("bandwidth"), A_FLOAT, 0);
+ class_addmethod(wahwah_class, (t_method)wahwah_dsp, gensym("dsp"), 0);
+ class_addmethod(wahwah_class, (t_method)wahwah_preset, gensym("preset"), A_FLOAT, 0);
+}