diff options
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&\;lid=-1-fra&\;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&\;lid=-1-fra&\;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 Binary files differnew file mode 100644 index 0000000..c0a0e89 --- /dev/null +++ b/vocoder~/filters.o 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 Binary files differnew file mode 100644 index 0000000..c150a14 --- /dev/null +++ b/vocoder~/lpc.o 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 Binary files differnew file mode 100644 index 0000000..a31acab --- /dev/null +++ b/vocoder~/tables.o 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); +} |