(no commit message)
authorcvs <>
Mon, 29 Mar 1999 11:14:02 +0000 (11:14 +0000)
committercvs <>
Mon, 29 Mar 1999 11:14:02 +0000 (11:14 +0000)
18 files changed:
CHANGES [new file with mode: 0644]
COPYING [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
endian.cc [new file with mode: 0644]
endian.h [new file with mode: 0644]
licmak.c [new file with mode: 0644]
main.cc [new file with mode: 0644]
tX.cc [new file with mode: 0644]
tX.h [new file with mode: 0644]
tX_types.h [new file with mode: 0644]
turntable.cc [new file with mode: 0644]
turntable.h [new file with mode: 0644]
version.h [new file with mode: 0644]
wav_file.h [new file with mode: 0644]
wav_read.cc [new file with mode: 0644]
wav_write.cc [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
new file mode 100644 (file)
index 0000000..a01b9d7
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,61 @@
+terminatorX - History
+All changes were done by me (Alexander Koenig) if not stated otherwise.
+
+[v2.3]
+- X-Window background fixed
+- wavfile overreading fixed by Andrew C. Bul+hac?k (acb@zikzak.net)
+- Using portable type definitions now where required. If you don't
+  have a <sys/types.h> on your system and your machines type sizes
+  equal those of an X86-machine you can specify -DUSE_X86_TYPES in
+  Makefile to compile without <sys/types.h>
+- Slight change in audiodevice-handling that fixes improper buffsize
+  settings on some soundcards (e.g. GUS)
+- Implemented "keep device open"-feature. Needs to be enabled via the
+  -DKEEP_DEV_OPEN switch in Makefile
+- Added some comments to the Makefile for easier editing
+- Added Big Endian support. Use -DBIG_ENDIAN_MACHINE for big endian hosts
+  like ultrapenguin suns or linux ppc. There's also -DBIG_ENDIAN_AUDIO
+  for big endian audio hardware (rare?) available, although proabably
+  nobody will need this.
+- Changed mix behaviour: Mix is now automatically turned on on startup if
+  the user has specified a proper loop file. (with the --loop or -l switch)
+- New mixing routine. You can now set the loop to scratch volume ratio with
+  the cursor keys (left/right). If you modify the volumes while recording
+  these action's will not be recorded. Saving happens with the currently
+  set level.
+- Fixed README-Bug said <m> instead of <x>
+  
+[v2.2]
+- first released version
+- added colors. more standard use of X11.
+- added loop support.
+- added statusbar with mode/status display
+- added commandline options and help (on usage and keys)
+- added raw/mixed save scratch feature
+- added licmak to include license into binary
+- new handling of XAutoRepeat, only turned off now when SPACE pressed.
+- modified wave display (faster + nicer + incorrect (who cares anyway))
+- Makefile fixed by Adrian Reber (adreit00@fht-esslingen.de)
+- bug fixes
+
+[prerelease]
+
+[v2.1]
+- added recording, playback of recording functionality
+
+[v2.0]
+- moved from multithreaded to singlethreaded
+- position feedback
+- bug fixes
+
+[v1.0]
+- mouse support
+- no more position display due to pthread/X probs
+- bug fixes
+
+[v0.5]
+- first version
+- no mouse handling
+- accelerating vtt via sinus
+- multithreaded
+- sound aliasing
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..dc63aac
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, 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.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..40109d2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,73 @@
+#terminatorX Makefile
+OBJECTS=turntable.o wav_read.o wav_write.o main.o tX.o endian.o
+
+#Correct the X11-Path if required
+INCLUDES=-I/usr/X11R6/include/
+LIBS=-L/usr/X11R6/lib -lX11 -lm
+
+#The tested big endian machines had problems
+#with opimized code if you own one of these
+#better leave this value the way it is -
+#On X86-machines it seems save to use:
+#OPT=-O2
+OPT=
+
+#Set the compiletime flags. Options:
+#-DUSE_CONSOLE        Output information to the console (should be defined)
+#-DUSE_STOPSENSE      If this is not defined terminatorX wil not
+#                     sense when mouse movement has stopped.
+#-DKEEP_DEV_OPEN      Audiodevice will be kept open until
+#                     terminatorX exits
+#-DBIG_ENDIAN_MACHINE Use this on big endian machines (LinuxPPC, SUN, etc...)
+#-DBIG_ENDIAN_AUDIO   Use this with big endian AUDIO HARDWARE (rare ?)
+#                     This IS NOT RELATED to BIG_ENDIAN_MACHINE 
+#-DUSE_X86_TYPES      Use this only IF you don't have <sys/types.h> AND a X86 machine
+#-DHANDLE_STOP        If enabled generated audio data is "correct"
+#                     but introduces clicks
+#-DUSE_OLD_MIX        re-enables old, bad, but proabably faster mixing routine
+CFLAGS=-DUSE_CONSOLE -DUSE_STOPSENSE -DHANDLE_STOP -Wall
+
+#Set the directory you want to install terminatorX in
+INSTALLDIR=/usr/local/bin
+
+#Set your compiler
+CC=egcs
+
+all:   terminatorX
+
+install:       terminatorX
+               cp terminatorX $(INSTALLDIR)
+
+clean: Makefile
+       rm -f $(OBJECTS) terminatorX core licmak licmak.o license.cc
+
+licmak.o:      licmak.c
+               $(CC) -o licmak.o -c licmak.c
+
+licmak:                licmak.o
+               $(CC) licmak.o -o licmak
+
+license.cc:    COPYING licmak
+               ./licmak
+
+tX.o:          tX.cc
+               $(CC) $(OPT) $(CFLAGS) $(INCLUDES) -o tX.o -c tX.cc     
+       
+main.o:                main.cc license.cc
+               $(CC) $(OPT) $(CFLAGS) $(INCLUDES) -o main.o -c main.cc 
+       
+wav_read.o:    wav_read.cc
+               $(CC) $(OPT) $(CFLAGS) $(INCLUDES) -o wav_read.o -c wav_read.cc
+
+wav_write.o:   wav_write.cc
+               $(CC) $(OPT) $(CFLAGS) $(INCLUDES) -o wav_write.o -c wav_write.cc
+       
+turntable.o:   turntable.h turntable.cc
+               $(CC) $(OPT) $(CFLAGS) $(INCLUDES) -o turntable.o -c turntable.cc
+
+endian.o:      endian.h endian.cc
+               $(CC) $(OPT) $(CFLAGS) $(INCLUDES) -o endian.o -c endian.cc
+                       
+terminatorX:   $(OBJECTS)
+               $(CC) $(LIBS) $(OBJECTS) -o terminatorX
+               
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..b69ca4b
--- /dev/null
+++ b/README
@@ -0,0 +1,263 @@
+terminatorX V2.3 README
+-----------------------
+
+Copyright (C) 1999 Alexander König
+eMail: alkoit00@fht-esslingen.de
+Homepage: http://www.termX.cjb.net
+
+This is open source software see the COPYING file that came with this
+distribution for details.
+
+Contens:
+--------
+
+       1.......What it is
+       2.......Quickstart
+       3.......Features
+       4.......Requirements
+       5.......Installation
+       6.......Operation
+       7.......Further notes
+       8.......Contact/Homepage
+
+1. What it is
+-------------
+
+TerminatorX is a realtime audio synthesizer. It enables you to scratch
+on wavfiles like you might have heard HipHop-DJs scratch on vinyl records.
+This is BETA Software please help me fix bugs. See section Contact/Homepage.
+Please read this README and take a look at the homepage
+http://www.termX.cjb.net BEFORE you complain.
+
+2. Quickstart:
+--------------
+
+       o tar xzf terminatorX-VXX.tar.gz
+       o cd terminatorX-VXX
+       o edit Makefile to your needs if required
+         (If you want to run terminatorX on a big endian machine (LinuxPPC,
+         Ultrapenguin SUN etc, enable -DBIG_ENDIAN_MACHINE (CFLAGS) and
+         disable optimizations (OPT=), on i386 machines you can safely use
+         OPT=-O2, set Compiler (default=egcs) and X-includes and libs)
+       o make
+       o become root
+       o make install
+       o become yourself
+       o start terminatorX with any 16Bit, 44.1 kHz, mono Wavfile:
+         e.g.: terminatorX anyfile.wav
+       o move your mouse pointer into terminatorX-Window
+       o press <RETURN> in the terminatorX-Window
+       o press and hold <SPACE>
+       o use your mouse to scratch
+       o release <SPACE> and if you enjoyed it press again.....
+       o press <RETURN> again to stop playback
+       o use <q> to quit
+       
+3. Features:
+------------
+
+       o CD-Quality operation
+       o Audio aliasing
+       o Optional playback of an additional loop wavfile to
+         enable rhythm based scratching
+       o Recording of your scratching in a memory buffer, customizable by user
+       o Save that buffer (as a wavfile) with or without the loop mixed to it,
+         no matter whether you recorded it with our without a loop playback
+       o Visual feedback to "see" current position in scratch-wavfile
+       o Kernel-level audio latency configurable via parameters
+       o Run terminatorX on the hardware platform of your choice,
+         this software is known to run on the following platforms        
+               - X86 (i386) (Linux)
+               - PowerPC (Linux)
+               - SUN Sparcs (Linux)
+         It should run on other Linux hardware as well, if you manage to
+         run it on any other platform (or you have prolems) please contact
+         me.
+       
+4. Requirements:
+----------------
+
+       o A Linux system with gcc/egcs and X-Windows installed. Since 
+         terminatorX is no longer multithreaded it shouldn't matter whether
+         you run it on glibc2 or libc5 system. I guess if your system
+         has more than let's say 100 BogoMIPS it should be capable
+         of running terminatorX (see --buffsize option for slow machines)
+       o A soundcard supported by OSS (Open Sound System, Linux Audio driver)
+         or any compatible audio driver.
+       o A good clean mouse and pad, a good X-Pointer setup. see the mouse
+         section on the homepage.
+
+Notes:         On performance the only thing I can say is this: it runs fine on my
+       P(I)233MMX with 98MB of RAM. On slower machines you might have to
+       enlarge the kernel-level audio buffer (default is 512 Bytes) with
+       the -b (--buffsize) switch on invoking the program. Nobody ever
+       told me it didn't run (due to cpu-power) so if you think your machine's
+       to slow please tell me so I can specify machines to slow...
+       
+5. Installation:
+----------------
+
+Installing terminatorX is pretty easy:
+- Extract the source-archive:
+  > tar xzf terminatorX-VXX.tar.gz
+
+- Change to the newly created directory
+  > cd terminatorX-VXX 
+
+- Edit the Makefile:
+  The Makefile uses egcs as the default-compiler, if you don´t have egcs
+  installed you might want to set CC to gcc. On i386 (X86) machines you may
+  want to set some optimizations OPT=-O2 seems to work on any i386-System.
+  If you want to run terminatorX on a big endian machines (LinuxPPC, SUN, etc.)
+  set -DBIG_ENDIAN_MACHINE in the CFLAGS. Some of you might also have to
+  correct the path to X-includes and X-libs, and the INSTALLDIR. 
+
+- Build the binary:  
+  The normal
+  > make
+  should do it.
+
+- Install the binary:
+  Become root. This depends on your machine and user status. You don't
+  actually have to install the binary. You can run it from any directory.
+  If you have superuser access type:
+  > make install
+  and terminatorX will be installed into the INSTALLDIR you specified or
+  the default (/usr/local/bin).
+  
+
+6. Operation:
+-------------
+
+For now terminatorX does not have a man-page but the most important information
+is contained within the binary:
+- run 
+  > terminatorX --help
+  to see all commandline options
+- run
+  > terminatorX --keys
+  to see all key-commandos avialable in the terminatorX window.
+
+Using terminatorX is not as straightforward as you might expect it from an
+X-Window program. This is due to the fact that we abuse the mouse for scratching
+instead of using it to operate the software. 
+
+Whenever you want to run terminatorX you have to give it one wavfile as 
+an parameter (the file you want to scratch on):
+> terminatorX example.wav
+
+Most important command-line options:
+------------------------------------
+All options except for -h, -k, -g and -v require a parameter (X in the
+following descriptions). The following are just the most important options
+try -h to see ALL options.
+
+--help (or -h), no Parameter
+       Displays all options
+       
+--keys (or -k), no Parameter
+       Displays all available keys in terminatorX's window.
+
+--mouse X (or -m) Parameter: float, Default: 0.5
+       Sets mouse sensitivity. Use negative values to invert scratch motion.
+       
+--speed X (or -s) Parameter: float, Default: 1.0
+       Sets the motor speed of the virtual turntable.
+       
+--loop X (or -l) Parameter: string, Default: none
+       Specifies a wavfile that can be played while you scratch on the main
+       wavfile. E.g. a beat if you want to scratch to a rythm. Mixing is
+       now automatically enabled if a loopfile was specified at startup,
+       use the <m>-key to toggle mix on/off.
+       
+--prefix X (or -p) Prameter: string, Default: tX_scratch
+       Specifies the name of your saved scratches with the default these
+       files are called tX_scratch01.wav, tX_scratch02.wav ....
+       
+--buffsize X (or -b) Parameter: integer, Default: 9
+       This configures the kernel-level audiobuffer's size. With
+       the default you get 2^9=512 Bytes. On slower systems you might
+       have to increase this value (10 -> 1024 Bytes, 11 -> 2048 Bytes ...)
+       The smaller this value the lower the latency of terminatorX.
+       
+--recbuff X (or -r) Parameter: integer, Default: 500
+       With this option you can set the size of the recording buffer in KBytes.
+       Recording a scratch stops when this buffer is full. A 500 KB Buffer
+       equals 5.6 seconds of audio just like a same sized Wavfile of 16 Bit 
+       44.1 kHz mono.
+
+The keys in terminatorX (or how to use it)
+------------------------------------------
+
+After you started terminatorX it displays its own window with a figure of
+the scratch-wavfile and a "statusbar". If you press <RETURN> now the virtual
+turntable starts spinning and you see a red position display underneath the
+wave-data. If you press <SPACE> now and keep it pressed you put your
+"virtual" hand on the turntable, which means if you don't move your mouse
+playback seems to stop. If you DO move your mouse now (with <SPACE> still
+pressed) this movement will be transferred to the vritual turntable -> you
+scratch. When you release <SPACE> the motor of the virtual turntable starts
+spinning again and the playback continues at the usual rate (or the rate you
+set with the --speed parameter). Press <RETURN> again to stop playback.
+
+The following keys are only available when playback has stopped:
+       
+<n>    Enter SCRATCH mode: of the three mode-displays in the lower right
+       edge of the window the empty circle becomes activated.
+       This mode enables you to scratch when playback is activated as long
+       as you want. Nothing will be recorded.
+       Start/Stop scratching with <RETURN>
+       
+<r>    Enter RECORD mode: full circled becomes activated.
+       This mode enables the recording of your scratching when playback has 
+       started. Playback will stop automatically when the recording buffer
+       is full.
+       Start/Stop recording with <RETURN>
+
+<p>    Enter PLAYBACK mode: arrow becomes activated.
+       In this mode you can NOT scratch. This mode enables you to playback
+       your last recorded scratch.
+       Start/Stop playback with <RETURN>
+       
+<m>    Toggle mixing on/off (This works only if you loaded an additional
+       loop wavfile via the --loop option)
+       This option is fully functional with all three modes described above.
+       So you can record a scratch with the mix enabled and play it back 
+       without.        
+
+<LEFT> Decreases the scratch-volume and increases the loop-volume.
+
+<RIGHT>        Decreases the loop-volume and increases the scratch-volume.
+
+<s>    Saves the last scratch recorded RAW (not mixed with loop wavfile).
+       Filenames are generated automatically and can be influenced via
+       the --prefix option (see above).
+       
+<x>    Saves the last scratch recorded MIXED (mixed with loop wavfile).
+       Filenames are the same as with the <s> key. Mixing happens at
+       the currently set volume-levels.
+       
+ATTENTION:     Files are saved to the current directory. If there are files
+               of the same name already, these files will be overwritten!
+               So be sure to move your scratches to an other directory or
+               set a different prefix each time you save scratches.    
+
+<q>    Quits the program.
+
+Now have fun and scratch! If you have further question see homepage or send
+me an eMail.
+
+7. Further notes:
+-----------------
+
+You can find more on terminatorX operation and especially the mouse
+configuration on the terminatorX homepage: http://www.termX.cjb.net
+
+8. Contact/Homepage:
+--------------------
+
+terminatorX's homepage:        http://www.termX.cjb.net
+
+If you wan't to send me comments, bug-reports, patches or scratches (see
+the users' scratches section on the terminatorX homepage) send a me
+an eMail to alkoit00@fht-esslingen.de 
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..0bd3251
--- /dev/null
+++ b/TODO
@@ -0,0 +1,36 @@
+TODO:
+
+These are the things I´d like to implement IF I have the time.
+The position of an idea in this list represents it´s priority:
+
+- correct getopt error handling.
+
+- Enhance audio quality with -DHANDLE_STOP -> no clicks.
+
+- Accept wavfiles that contain additional information (e.g. loops)
+
+- Support Y-mouse-movement for scratching
+
+- add a marker feature: this will allow you to set 12 markers visually
+  in the wavfile-display. These will be available via the F1-F12 keys in
+  NORMAL and RECORD mode. If you press (and hold) one of these keys it will
+  have the same effect as pressing space but if you release it it will
+  jump to the position you marked in the wavfile. Easier scratching for people
+  like me who don´t have any scratching skills.
+
+- implement licmak with either perl, awk or sed.
+
+- code cleanup: A lot of this code is ugly, e.g. writing to public member of
+  classes instead of calling a method. Or the position_update in render_block
+  I did this for easiness and speed. But it should be cleaned up I believe.
+
+DONE:
+
+The following stuff has been on the list above and is now ipmlemented:
+
+[V2.3] (use -DKEEP_DEV_OPEN in Makefile)
+
+- add a "keep device open" option and implement it
+  (this would help if you have problems opening device very often
+  due to memory fragmentation). And it would help me ;) as my card (or better
+  driver) clicks awfully when device is opened!
diff --git a/endian.cc b/endian.cc
new file mode 100644 (file)
index 0000000..a839528
--- /dev/null
+++ b/endian.cc
@@ -0,0 +1,128 @@
+/*
+    terminatorX - realtime audio scratching software
+    Copyright (C) 1999  Alexander König
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    File: endian.cc
+    Description: swap byte order for big endian systems/audiohardware.
+*/    
+
+
+#if defined (BIG_ENDIAN_MACHINE) || defined(BIG_ENDIAN_AUDIO) || defined (TEST_ENDIAN)
+
+#include "tX_types.h"
+
+void swap16(int16_t * val)
+{
+       int8_t temp;
+       int8_t *p;
+       
+       p=(int8_t *) val;
+       temp=*p;
+       *p=*++p;
+       *p=temp;
+}
+
+void swap32(int32_t * val)
+{
+       /*
+               This one is very inefficient but it wont be
+               called from performace critical areas so
+               who cares...
+       */
+       int8_t temp;
+       int8_t *p;
+       
+       p=(int8_t *) val;
+       temp=p[0];
+       p[0]=p[3];
+       p[3]=temp;
+       
+       temp=p[1];
+       p[1]=p[2];
+       p[2]=temp;
+}
+
+void swapbuffer(int16_t *buffer, int samples)
+{
+       int i;
+       int8_t temp;
+       int8_t *p;
+       int16_t *val;
+       
+       val=buffer;
+
+       for (i=0; i<samples; i++)
+       {
+               p=(int8_t *) val;               
+               temp=*p;
+               *p=*++p;
+               *p=temp;                
+               val++;
+       }
+}
+
+
+/* The following main() is just for testing */
+
+#ifdef TEST_ENDIAN
+
+#include <netinet/in.h>
+
+int main(int argc, char **argv)
+{
+       int16_t t16=0x1234;
+       int32_t t32=0x12345678;
+       
+       int16_t buffer[8]={0x1234, 0x5678, 0x9ABC, 0xDEF0, 10, 20, 30, 0};
+
+       int i;
+       
+       printf("16: %4x\n", (int) t16);
+       swap16(&t16);
+       printf("16: %4x\n", (int) t16);
+       swap16(&t16);
+       printf("16: %4x\n", (int) t16);
+       t16=htons(t16);
+       printf("16: %4x\n", (int) t16);
+       t16=htons(t16);
+       printf("16: %4x\n", (int) t16);
+
+       printf("32: %8x\n", (int) t32);
+       swap32(&t32);
+       printf("32: %8x\n", (int) t32);
+       swap32(&t32);
+       printf("32: %8x\n", (int) t32);
+       t32=htonl(t32);
+       printf("32: %8x\n", (int) t32);
+       t32=htonl(t32);
+       printf("32: %8x\n", (int) t32);
+       
+       printf("buf: ");
+       for (i=0; i<8; i++) printf("%4hx ", buffer[i]); 
+       swapbuffer(buffer, 8);
+       printf("\nbuf: ");      
+       for (i=0; i<8; i++) printf("%4hx ",  buffer[i]);
+       swapbuffer(buffer, 8);
+       printf("\nbuf: ");      
+       for (i=0; i<8; i++) printf("%4hx ", buffer[i]);
+       
+       puts("\nDone.\n");
+}
+#endif
+
+#endif
diff --git a/endian.h b/endian.h
new file mode 100644 (file)
index 0000000..b87dbfa
--- /dev/null
+++ b/endian.h
@@ -0,0 +1,32 @@
+/*
+    terminatorX - realtime audio scratching software
+    Copyright (C) 1999  Alexander König
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    File: endian.h
+    Description: header to endian.cc
+*/    
+
+#if defined (BIG_ENDIAN_MACHINE) || defined(BIG_ENDIAN_AUDIO)
+
+#include "tX_types.h"
+
+extern void swap16(int16_t * val);
+extern void swap32(int32_t * val);
+extern void swapbuffer(int16_t *buffer, int samples);
+
+#endif
diff --git a/licmak.c b/licmak.c
new file mode 100644 (file)
index 0000000..3dbcbcd
--- /dev/null
+++ b/licmak.c
@@ -0,0 +1,82 @@
+/*
+    licmak - include a program's license into c/c++-code
+    Copyright (C) 1999  Alexander König
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    File: licmak.c
+
+    Description: Turns COPYING into a C-String. This EXTREMELY ugly and
+    should be done with either perl, awk or sed. But I´m too lazy to learn
+    either one of these...
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+int main()
+{
+       FILE *in, *out;
+       char buffer[1024];
+       char outbuffer[2048];
+       char c;
+       int i,o;
+       
+       in = fopen ("COPYING", "r");
+       if (!in) 
+       {
+               puts("COPYING not found.");
+               return(1);
+       }
+       
+       out = fopen ("license.cc", "w");
+       if (!out)
+       {
+               puts("failed to open license.cc");
+               return(1);
+       }
+       
+       fprintf(out, "char license[]=\"\\\n");
+       
+       while (!feof(in))
+       {
+               fgets(buffer, 1024, in);
+               if (!feof(in))
+               {
+               for (i=0, o=0; i<strlen(buffer); i++, o++)
+               {
+                       c=buffer[i];
+
+                       if (c=='"')
+                       {
+                               outbuffer[o]='\\';
+                               o++;
+                       }
+                       
+                       outbuffer[o]=buffer[i];
+               }
+               outbuffer[o-1]=0;
+               strcat(outbuffer, "\\n\\\n");
+               /*
+               outbuffer[o-1]='\\';
+               outbuffer[o]='\n';
+               outbuffer[o+1]=0;
+               */
+               fprintf(out, "%s", outbuffer);
+               }
+       }
+       fprintf(out, "\";\n");
+       return(0);
+}
diff --git a/main.cc b/main.cc
new file mode 100644 (file)
index 0000000..4456cad
--- /dev/null
+++ b/main.cc
@@ -0,0 +1,483 @@
+/*
+    terminatorX - realtime audio scratching software
+    Copyright (C) 1999  Alexander König
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    
+    File: main.cc
+    
+    Description: This contains the main() function. All the initializing
+    happens here:
+    - Commandline parsing
+    - Loading of loop and scratch wavfiles
+    - Creating of one instance of tX_Window and one of Virtual_Turntable
+    - Running of the event loop in tX_Window   
+    
+    Changes:
+    
+    19 Mar 1999: Applied a patch by Andrew C. Bul+hac?k (eMail: acb@zikzak.net)
+                 that fixes wavfile reading routine for the overreading bug.
+                
+    20 Mar 1999: Big endian support.
+    
+    23 Mar 1999: display of new keys (<-, ->)
+*/
+#include <stdio.h>
+#include "wav_file.h"
+#include "turntable.h"
+#include "tX.h"
+#include <malloc.h>
+#include <math.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include "endian.h"
+#include "tX_types.h"
+#include "version.h"
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+Virtual_TurnTable *myvtt;
+tX_Window *mywin;
+
+#include "license.cc"
+
+/* glob_parm: struct for global parameters */
+
+typedef struct glob_parm
+{
+       float mouse_speed;              // -m, --mouse
+       char s_wav[256];                // no_opt
+       char m_wav[256];                // -l, --loop
+       char prefix[128];               // -p, --prefix
+       char dev_name[128];             // -d, --device
+       int buff_no;                    // -n, --buffno
+       int buff_size;                  // -b, --buffsize
+       int rec_size;                   // -t, --rectime
+       int stop_sense_cycles;          // -c, --sensecycles
+       int verbose;
+       int warp_border;                // -w, --warp
+       int width;                      // -x, --width
+       int height;                     // -y, --height
+       float vtt_default_speed;        // -s, --speed
+} glob_parm;
+
+glob_parm parms;
+
+/* set_defaults(): sets defaults in parms struct */
+
+void set_defaults()
+{
+       parms.mouse_speed=0.5;
+       strcpy(parms.s_wav, "");
+       strcpy(parms.m_wav, "");
+       strcpy(parms.prefix, "tX_scratch");
+       strcpy(parms.dev_name, "/dev/dsp");
+       
+       parms.buff_no=2;
+       parms.buff_size=9;
+       
+       parms.rec_size=512000;
+       parms.stop_sense_cycles=3;
+       parms.vtt_default_speed=1.0;
+       parms.verbose=0;
+       parms.warp_border=200;
+       parms.height=600;
+       parms.width=1000;
+}
+
+/* usage(): displays parameters */
+
+void usage()
+{
+       puts("usage:   terminatorX [options] wavfile\n");
+       puts("options:");
+       puts("[short] [long]          [type]      [default]    [description]");
+       puts("-m      --mouse         float       0.5          mouse sensitivity");
+       puts("-l      --loop          string      -            loop wavfile");
+       puts("-p      --prefix        string      tX_scratch   recfile prefix");
+       puts("-d      --device        string      /dev/dsp     audio output device");
+       puts("-n      --buffno        integer     2            number of audio buffers");
+       puts("-b      --buffsize      integer     9            size of audio buffers (2^size)");
+       puts("-r      --recbuff       integer     500          size of record buffer in KB");
+       puts("-c      --sensecycles   integer     3            cycles to mouse stop sense");
+       puts("-s      --speed         float       1.0          speed of turntable motor");
+       puts("-w      --warp          integer     200          border for mouse warp");
+       puts("-x      --width         integer     1000         window width");
+       puts("-y      --height        integer     600          window height");
+       puts("-v      --verbose                                verbose output");
+       puts("-k      --keys                                   display window keys");
+       puts("-h      --help                                   this page");
+       puts("-g      --license                                display license (GPL V2)");
+}
+
+/* keys(): display available keys in Window */
+
+void keys()
+{
+       puts("Available keys in terminatorX:\n");
+       puts("[key]     [description]");
+       puts("<RETURN>  start/stop playback");
+       puts("<SPACE>   activate mouse when playback active (to scratch)");
+       puts("            pressed:  hand on turntable");
+       puts("            released: hand off turntable");
+       puts("            symbol: lower right red rectangle");
+       puts("<n>       switch to \"normal\" scratch mode (no recording)");
+       puts("            symbol: empty circle. mouse active.");
+       puts("<r>       switch to record mode. playback stops when record buffer is full.");
+       puts("            symbol: full circle. mouse active.");
+       puts("<p>       switch to playback mode. plays the recorded scratch.");
+       puts("            symbol: arrow. mouse inactive");
+       puts("<m>       toggle mixing of loop on/off");
+#ifndef USE_OLD_MIX
+       puts("<LEFT>    increase loop volume, decrease scratch volume");
+       puts("<RIGHT>   increase scratch volume, decrease loop volume");
+#endif 
+       puts("<s>       save RAW scratch to wavfile");
+       puts("<x>       save MIXED scratch to wavfile");
+       puts("<q>       exit terminatorX\n");
+       puts("Saving, mode changes and mix toggles are only available when playback has stopped.");
+}
+
+/* parse_cd: parses the commandline using getopt
+
+   this could use some more error checking.
+*/
+
+void parse_cmd(int argc, char **argv)
+{  
+       int c;
+       
+       /* make -Wall shut up */        
+       // int digit_optind = 0;
+
+       set_defaults();
+
+       while (1)
+       {
+               /* make -Wall shut up */
+               // int this_option_optind = optind ? optind : 1;
+               int option_index = 0;
+               static struct option long_options[] =
+               {
+                       {"mouse", 1, 0, 'm'},
+                       {"loop", 1, 0, 'l'},
+                       {"prefix", 1, 0, 'p'},
+                       {"device", 1, 0, 'd'},
+                       {"buffno", 1, 0, 'n'},
+                       {"buffsize", 1, 0, 'b'},
+                       {"recbuff", 1, 0, 'r'},
+                       {"sensecycles", 1, 0, 'c'},
+                       {"speed", 1, 0, 's'},                   
+                       {"verbose", 1, 0, 'v'},                 
+                       {"help", 0, 0, 'h'},
+                       {"warp", 1, 0, 'w'},
+                       {"height", 1, 0, 'y'},
+                       {"width", 1, 0, 'x'},
+                       {"keys", 0, 0, 'k'},
+                       {"license", 0, 0, 'g'},
+                       {0, 0, 0, 0}
+               };
+
+               c = getopt_long (argc, argv, "m:l:p:d:n:b:r:c:s:vkhgw:x:y:", long_options, &option_index);
+               
+               if (c == -1)
+               break;
+
+               switch (c)
+               {
+                       case 'm':       
+                               sscanf(optarg, "%f", &parms.mouse_speed);
+                       break;
+       
+                       case 'l':
+                               strcpy(parms.m_wav, optarg);
+                       break;
+               
+                       case 'p':
+                               strcpy(parms.prefix, optarg);
+                       break;
+       
+                       case 'd':
+                               strcpy(parms.dev_name, optarg);
+                       break;
+       
+                       case 'n':
+                               sscanf(optarg, "%i", &parms.buff_no);
+                       break;
+       
+                       case 'b':
+                               sscanf(optarg, "%i", &parms.buff_size);
+                       break;
+       
+                       case 'r':
+                               sscanf(optarg, "%i", &parms.rec_size);
+                               parms.rec_size*=1024;
+                       break;
+       
+                       case 'c':
+                               sscanf(optarg, "%i", &parms.stop_sense_cycles);
+                       break;
+               
+                       case 's':
+                               sscanf(optarg, "%f", &parms.vtt_default_speed);
+                       break;
+       
+                       case 'v':
+                               parms.verbose=1;
+                       break;
+       
+                       case 'h':
+                               usage();
+                               exit(0);
+                       break;
+                       
+                       case 'k':
+                               keys();
+                               exit(0);
+                       break;
+       
+                       case 'w':
+                               sscanf(optarg, "%i", &parms.warp_border);
+                       break;
+       
+                       case 'x':               
+                               sscanf(optarg, "%i", &parms.width);
+                       break;
+                       
+                       case 'y':
+                               sscanf(optarg, "%i", &parms.height);
+                       break;
+                       
+                       case 'g':
+                               puts(license);
+                               exit(0);
+                       break;
+       
+                       case '?':
+                         break;
+       
+                       default:
+                         printf ("?? getopt returned character code 0%o ??\n", c);
+               }
+       }
+
+       if (optind != argc-1)
+       {
+               puts("Error: You must specify one WAV-file you want to scratch on.\n");
+               usage();
+               exit(1);
+       }
+       else
+       {
+               strcpy(parms.s_wav, argv[optind]);
+       }
+       
+
+       if (parms.verbose)
+       {       
+               printf("Mouse speed     : %f\n", parms.mouse_speed);
+               printf("Wavefile        : %s\n", parms.s_wav);
+               
+               if (strlen(parms.m_wav)) 
+               printf("Loop wavefile   : %s\n", parms.m_wav);
+               else puts("No loop file.");
+               
+               printf("Rec-prefix      : %s\n", parms.prefix);
+               printf("Device          : %s\n", parms.dev_name);
+               printf("Audio-Buffers   : %i\n", parms.buff_no);        
+               printf("Size            : %i (%i Bytes)\n", parms.buff_size, 1 << parms.buff_size);
+               printf("Recbuffsize     : %i (%f Seconds)\n", parms.rec_size, ((float) parms.rec_size) / 88200.0);
+               printf("Stopsensecycles : %i\n", parms.stop_sense_cycles);
+               printf("VTT speed       : %f\n", parms.vtt_default_speed);
+               printf("Warp border     : %i\n", parms.warp_border);
+               printf("Window height   : %i\n", parms.height);
+               printf("Window width    : %i\n", parms.width);
+       }
+}
+
+/* load_wav(): load a wavfile with filename name.
+               writes size of file to *size, and
+              returns a pointer to the loaded wave-data.
+*/
+
+int16_t *load_wav(char *name, unsigned int *size)
+{
+       wav_sig wav_in;
+       int16_t *data;
+       int16_t *p;
+       ssize_t allbytes=0;
+       ssize_t bytes=0;
+       int i;
+       
+       if (!init_wav_read(name, &wav_in))
+       {
+#ifdef USE_CONSOLE
+               printf("[load_wav] Error. Couldn't open \"%s\".\n", name);
+#endif 
+       }
+
+#ifdef USE_CONSOLE
+       printf("Loading: %s\n", name);
+       if (parms.verbose) printf("File: %i Bytes Data, %i Bit Depth, %i Hz Samplerate.\n", wav_in.len, wav_in.depth, wav_in.srate);    
+#endif 
+       
+       if (wav_in.depth != 16)
+       {
+#ifdef USE_CONSOLE
+               puts("[load_wav] Error: Wave-File is not 16 Bit. Fatal. Giving up.");           
+#endif         
+               exit(1);
+       }
+
+       if (wav_in.chans != 1)
+       {
+#ifdef USE_CONSOLE     
+               puts("[load_wav] Error: Wave-File is not Mono. Fatal. Giving up.");
+#endif
+               exit(2);                
+       }
+
+#ifdef USE_CONSOLE     
+       if (wav_in.srate != 44100) 
+       {
+               puts("[load_wav] Warning: Wave-File was not recorded at 44.100 Hz!");
+       }
+       if (wav_in.blkalign != 2)
+       {
+               printf("[load_wav] Warning: Unexpected block alignment: %i.\n", wav_in.blkalign);
+       }
+#endif
+
+       *size=wav_in.len;
+       data = (int16_t *) malloc (*size);
+       
+       if (!data)
+       {
+#ifdef USE_CONSOLE
+               puts("[load_wav] Error: Failed to allocate sample memory. Fatal. Giving up.");
+               exit(3);
+#endif 
+       }
+
+       p=data;
+
+
+       while (wav_in.len>allbytes)
+       {
+               bytes = read(wav_in.handle, p, min(1024, wav_in.len-allbytes));
+#ifdef BIG_ENDIAN_MACHINE
+               swapbuffer(p, bytes/sizeof(int16_t));
+#endif         
+               
+               if (bytes<=0)
+               {
+#ifdef USE_CONSOLE
+                      puts("[load_wav] Error: Failed to read Wave-Data (Corrupt?). Fatal. Giving up.");
+                       if(bytes<0) perror("terminatorX");
+#endif         
+                       exit(4);
+               }
+                               
+               allbytes+=bytes;
+               
+               for (i=0; i<bytes; i+=2) p++;
+       }
+       
+       close(wav_in.handle);
+       
+#ifdef USE_CONSOLE
+       if (parms.verbose) printf("Read: %i Bytes of Wave-Data.\n", allbytes);
+#endif 
+       return(data);
+}
+
+/* main(): */
+
+int main(int argc, char **argv)
+{
+       
+       int16_t *data_in;
+       unsigned int size_in;
+       
+       int16_t *beat_data;
+       unsigned int beat_size;
+       
+       int16_t *recordbuffer;
+               
+       TT_init init_data;
+       
+       printf("%s, Copyright (C) 1999 Alexander König, alkoit00@fht-esslingen.de\n", VERSIONSTRING);
+       puts("terminatorX comes with ABSOLUTELY NO WARRANTY; for details use option --license");
+       puts("This is free software, and you are welcome to redistribute it");
+       puts("under certain conditions; see option --license\n"); 
+       
+       parse_cmd(argc, argv);
+       
+       data_in = load_wav(parms.s_wav, &size_in);
+       
+       if (strlen(parms.m_wav))
+       {
+               beat_data = load_wav(parms.m_wav, &beat_size);
+       }
+       else
+       {
+               beat_data = NULL; beat_size=0;
+       }
+       
+#ifdef USE_CONSOLE
+       if (parms.verbose) printf("Allocating Recorder buffer of %i Bytes.\n", parms.rec_size);
+#endif
+       recordbuffer=(int16_t *) malloc(parms.rec_size);
+       
+       if (!recordbuffer)
+       {
+#ifdef USE_CONSOLE
+                       puts("[main] Error: Allocate Recorder buffer. Fatal. Giving up.");
+#endif                                         
+                       exit(1);
+       }
+       
+       init_data.speed=(f_prec) parms.vtt_default_speed;
+       init_data.default_speed=(f_prec) parms.vtt_default_speed;
+       init_data.buff_cfg=(parms.buff_no<<16) | parms.buff_size;
+       init_data.bsize=1<<parms.buff_size;
+       init_data.verbose=parms.verbose;
+       init_data.playback_data=data_in;
+       init_data.playback_size=size_in;
+       init_data.record_data=recordbuffer;
+       init_data.record_size=parms.rec_size;
+       init_data.mix_data=beat_data;
+       init_data.mix_size=beat_size;   
+       
+       strcpy(init_data.file_name, parms.prefix);
+       strcpy(init_data.devicename, parms.dev_name);
+       
+       myvtt=new Virtual_TurnTable(&init_data);
+
+       mywin=new tX_Window(myvtt, parms.width, parms.height, parms.warp_border, parms.stop_sense_cycles, parms.mouse_speed, parms.verbose, parms.s_wav, parms.m_wav);
+       myvtt->set_window(mywin);
+       
+       mywin->prepare_data_display(data_in, size_in);
+
+       mywin->loop();
+       
+       free(recordbuffer);
+       free(data_in);
+       
+       puts("Have a nice life.");
+}
diff --git a/tX.cc b/tX.cc
new file mode 100644 (file)
index 0000000..1abc62b
--- /dev/null
+++ b/tX.cc
@@ -0,0 +1,703 @@
+/*
+    terminatorX - realtime audio scratching software
+    Copyright (C) 1999  Alexander König
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    
+    File: tX.cc
+    
+    Description: Does all the X-Handling.
+
+    Comment: I know NOTHING about X11. All of the code I wrote here is
+    derived from the X-includes and man pages. So assume this is full of
+    bad X-Handling. Like all of my code this is: HACKED TO WORK NOT TO BE NICE
+    If you can make it better please do so. 
+
+    Changes:
+    
+    20 Mar 1999 - Fixed a bug that made terminatorX appear with a partly
+                  white background on a sun remote x-display.
+                 
+    20 Mar 1999 - moved short to int16_t
+    
+    23 Mar 1999 - support for new mixing in Virtual_Turntable
+*/
+
+#include "tX.h"
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "version.h"
+char title[]=VERSIONSTRING;
+
+#include "tX_types.h"
+
+#define BORDER_ALIGN 5
+#define TOOLBAR_SIZE 20
+
+#define DC DefaultColormap(disp, DefaultScreen(disp))
+
+/* tX_Window::tx_Window() : intializes tX_Window, connects to X-Server, and creates Window */
+
+tX_Window :: tX_Window(Virtual_TurnTable *vttptr, int sizex, int sizey, int warp, int cycles, f_prec mspeed, int verb, char *sname, char *lname)
+{
+       XColor dummy;
+
+       verbose=verb;
+       mouse_speed=mspeed;
+       
+       vtt=vttptr;
+       
+       playback_active=0;
+       
+       width = sizex;
+       height = sizey;
+       
+       mouse_border=warp;
+
+       strcpy(s_name, sname);
+       if (strlen(s_name)>20)
+       {
+               s_name[18]='.';
+               s_name[19]='.';
+               s_name[20]='.';
+               s_name[21]=0;           
+       }
+       strcpy(l_name, lname);
+       if (strlen(l_name)>20)
+       {
+               l_name[18]='.';
+               l_name[19]='.';
+               l_name[20]='.';
+               l_name[21]=0;           
+       }
+       
+       if (width < 3*mouse_border) 
+       {
+#ifdef USE_CONSOLE
+               puts("[tX] Error. Window with should be at least 3 times the warp border.");            
+#endif         
+               exit(5);
+       }
+
+       sense_cycles=cycles;
+       
+       medx=width/2;
+       medy=height/2;
+       
+       quit=0;
+       motor_on=1;
+       
+       warpx_min=mouse_border;
+       warpx_max=width-mouse_border;
+       ptrwarped=0;
+
+#ifdef USE_CONSOLE
+       if (verbose) puts("[tX] Initializing.");
+#endif 
+       disp=XOpenDisplay(NULL);
+       
+       if (!disp)
+       {
+#ifdef USE_CONSOLE
+               puts("[tX] Error: Failed to connect to default display. Fatal. Giving up.");
+#endif 
+               exit(1);
+       }
+               
+       win=XCreateSimpleWindow(disp, DefaultRootWindow(disp), 0,0, width, height,0,0,0);
+       gc=XCreateGC(disp, win, GCBackground | GCForeground, &xgcv);
+       XMapWindow(disp, win);
+       XStoreName(disp,win,title);     
+
+       event_mask = KeyReleaseMask | KeyPressMask | PointerMotionMask | ExposureMask;
+
+       XSelectInput(disp,win,event_mask);
+               
+       XSync(disp,False);      
+       
+       xkeyev=(XKeyEvent *) &xev;
+       xmotev=(XMotionEvent *) &xev;
+       
+       XAllocNamedColor(disp, DC, "green", &col_data, &dummy);
+       XAllocNamedColor(disp, DC, "grey", &col_frame, &dummy);
+       XAllocNamedColor(disp, DC, "red", &col_pos, &dummy);
+       XAllocNamedColor(disp, DC, "yellow", &col_marker, &dummy);
+       XAllocNamedColor(disp, DC, "orange", &col_activebtn, &dummy);
+       XAllocNamedColor(disp, DC, "grey", &col_inactivebtn, &dummy);
+       
+       black=BlackPixel(disp, DefaultScreen(disp));
+       white=WhitePixel(disp, DefaultScreen(disp));
+       
+       font = XLoadFont(disp, "fixed");
+       if (font)
+       {
+#ifdef USE_CONSOLE     
+               if (verbose) puts("[tX] Font loaded.");
+#endif         
+               XSetFont(disp, gc, font);
+       }
+       
+}
+
+/* tX_Window::prepare_data_display(): calculates values necessary for data diplay. */
+
+void tX_Window :: prepare_data_display(int16_t *data, unsigned int size)
+{
+       data_disp_x=BORDER_ALIGN;
+       data_disp_y=BORDER_ALIGN;
+       
+       data_disp_width=width-2*BORDER_ALIGN;
+       data_disp_height=height-3*BORDER_ALIGN-TOOLBAR_SIZE;
+       
+       data_samples=size/2;
+       data_ptr=data;
+       
+       samples_per_pixel=data_samples/width;
+       y0=data_disp_y+data_disp_height/2;
+       
+       pos_y=data_disp_y+data_disp_height+BORDER_ALIGN;
+       pos_max_x=data_disp_x+data_disp_width;  
+       
+       modex=width-3*(TOOLBAR_SIZE)-BORDER_ALIGN;
+       modey=height-TOOLBAR_SIZE;
+       bt_w=TOOLBAR_SIZE-BORDER_ALIGN;
+       bt_h=bt_w;
+       bt_a=BORDER_ALIGN;
+       modex-=2*(bt_w+bt_a);
+}
+
+/* tX_Window::display-data(): actually displays the wave-data */
+
+void tX_Window :: display_data()
+{
+       int sample;
+       int16_t value;
+       int x,y1;
+       f_prec temp;
+       f_prec half_data_height;
+       
+       half_data_height = (f_prec) data_disp_height/2;
+       
+       XSetForeground(disp, gc, col_frame.pixel);
+       XDrawRectangle(disp, win, gc, data_disp_x, data_disp_y, data_disp_width, data_disp_height);     
+
+       XSetForeground(disp, gc, col_data.pixel);
+
+       for (x=0; x<data_disp_width; x++)
+       {
+               value=data_ptr[x*samples_per_pixel];
+               for (sample=x*samples_per_pixel; sample<(x+1)*samples_per_pixel; sample++)
+               {
+                       value=(value+data_ptr[sample])/2;
+               }
+               temp=((f_prec) value)/32767.0;
+               y1=(int) (temp * half_data_height);
+               XDrawLine(disp, win, gc, data_disp_x+x, y0-y1, data_disp_x+x, y1+y0);
+       }
+       XSync(disp, False);
+}
+
+/* tX_Window::set_pos() : updates the (sample-)position display to position pos
+
+   If SLIM_POS is defined set_pos() draws lines instead of rectangles.
+   Might be slightly faster (and uglier).
+*/
+
+void tX_Window :: set_pos(int pos)
+{
+#ifdef SLIM_POS        
+       pos+=BORDER_ALIGN;
+
+       XSetForeground(disp, gc, col_pos.pixel);
+       XDrawLine(disp, win, gc, data_disp_x, pos_y, pos, pos_y);
+       
+       XSetForeground(disp, gc, black);
+       XDrawLine(disp, win, gc, pos, pos_y, pos_max_x, pos_y); 
+#else
+       XSetForeground(disp, gc, col_pos.pixel);
+       XFillRectangle(disp, win, gc, data_disp_x, pos_y-1, pos-2*BORDER_ALIGN, 3);
+       
+       XSetForeground(disp, gc, black);
+       XFillRectangle(disp, win, gc, pos+BORDER_ALIGN, pos_y-1, pos_max_x-pos, 3);     
+#endif 
+}
+
+/* tX_Window::get_samples_per_pixel() : returns value calculated in prepare_data_display()*/
+
+int tX_Window :: get_samples_per_pixel()
+{
+       return(samples_per_pixel);
+}
+
+#include <X11/keysym.h>
+
+/* tx_Window::handle_KeyPress() : Evaluates xkeyev as KeyPress Event */
+
+void tX_Window :: handle_KeyPress()
+{
+       KeySym key;
+
+       key=XKeycodeToKeysym (disp, xkeyev->keycode, 0);
+       
+       switch (key)
+       {
+               case XK_Return:
+               {
+                       if (playback_active)
+                       {
+                               playback_active=0;                      
+                               vtt->needle_up();
+                               if (vtt->mode == MODE_RECORD_SCRATCH)
+                               {
+                                       vtt->store_rec_pos();
+                               }
+                               set_pos(0);
+                               display_action();
+                       }
+                       else
+                       {
+                               playback_active=1;
+                               vtt->speed=vtt->default_speed;
+                               vtt->needle_down();
+                               if (vtt->mode == MODE_RECORD_SCRATCH)
+                               {
+                                       vtt->reset_rec_pos();
+                               }
+                               display_action();
+                       }
+               }
+               break;
+               
+               case XK_space:
+               {
+                       XAutoRepeatOff(disp);           
+                       vtt->speed=0;
+                       XGrabPointer(disp, win, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
+                       XWarpPointer(disp, win, win, 0, 0, 0, 0, medx, medy);
+                       mx=medx;
+                       first_mot_event=1;
+                       mtime=CurrentTime;
+                       motor_on=0;
+               }
+               break;
+               
+               case XK_q:
+               {
+                       if (playback_active)
+                       {
+                               vtt->needle_up();
+                               playback_active=0;
+                               XUngrabPointer(disp, CurrentTime);                      
+                       }
+                       XAutoRepeatOn(disp);
+                       XSync(disp, False);                     
+                       quit=1;
+               }               
+               break;
+               
+               case XK_n:
+               {
+                       if (!playback_active)
+                       {
+                               vtt->set_mode(MODE_SCRATCH);
+                               display_mode();
+                       }
+               }
+               break;
+               
+               case XK_r:
+               {
+                       if (!playback_active)
+                       {
+                               vtt->set_mode(MODE_RECORD_SCRATCH);
+                               display_mode();
+                       }
+               }
+               break;
+               
+               case XK_p:
+               {
+                       if (!playback_active)
+                       {
+                               vtt->set_mode(MODE_PLAYBACK_RECORDED);
+                               display_mode();
+                       }
+               }
+               break;
+               
+               case XK_m:
+                       if (!playback_active)
+                       {
+                               vtt->toggle_mix();                              
+                               display_text();
+                       }
+               break;
+               
+               case XK_s:
+                       if (!playback_active)
+                       {
+                               vtt->save(0);
+                               display_text();                         
+                       }
+               break;
+               
+               case XK_x:
+                       if (!playback_active)
+                       {
+                               vtt->save(1);
+                               display_text();                         
+                       }
+               break;
+               
+#ifndef USE_OLD_MIX
+               case XK_Left:
+                       if (vtt->vol_loop < 1.0)
+                       {
+                               vtt->vol_loop+=0.01;
+                               vtt->vol_scratch=1.0-vtt->vol_loop;
+                               display_text();
+                       }
+               break;
+
+               case XK_Right:
+                       if (vtt->vol_loop > 0.0)
+                       {
+                               vtt->vol_loop-=0.01;
+                               vtt->vol_scratch=1.0-vtt->vol_loop;
+                               display_text();
+                       }
+               break;
+#endif         
+       }
+}
+
+/* tx_Window::handle_KeyRelease() : Evaluates xkeyev as KeyRelease Event */
+
+void tX_Window :: handle_KeyRelease()
+{
+       KeySym key;
+       
+       key=XKeycodeToKeysym (disp, xkeyev->keycode, 0);
+       
+       switch (key)
+       {
+               case XK_space:
+               {
+                       vtt->speed=vtt->default_speed;
+                       XUngrabPointer(disp, CurrentTime);                      
+                       motor_on=1;
+                       XAutoRepeatOn(disp);                    
+               }
+               break;
+       }       
+}
+
+/* tx_Window::repaint() : Redraws all components of the window.*/
+
+void tX_Window :: repaint()
+{
+/*
+       No longer just clearing the window, as that produces
+       different results on different X-Servers, instead we paint
+       it black.
+*/
+       XSetForeground(disp, gc, black);
+       XFillRectangle(disp, win, gc, 0, 0, width, height);     
+       display_data(); 
+       display_mode();
+       display_action();
+       display_text();
+}
+
+/* tx_Window::handle_Motion() : Evaluates xmotev as Motion Event */
+
+void tX_Window :: handle_Motion()
+{
+       int dist;
+       int nx;
+       f_prec tspeed;
+       Time ntime, dtime;
+       
+       if (!playback_active) return;
+
+       nx=xmotev->x;
+       ntime=xmotev->time;
+
+       if (first_mot_event)
+       {
+               mx=nx;
+               mtime=ntime;
+               first_mot_event=0;
+               return;
+       }
+
+#ifdef USE_STOPSENSE   
+       mouse_busy=sense_cycles;
+#endif 
+                       
+       if ((ptrwarped) && (nx=medx)) 
+       {
+               mx=medx;
+               ptrwarped=0;
+               return;
+       }
+
+       if ((nx >= warpx_max) || (nx <= warpx_min))
+       {
+               XWarpPointer(disp, win, win, 0, 0, 0, 0, medx, medy);
+               ptrwarped=1;
+       }
+
+       if (motor_on) return;
+                       
+       dtime=ntime-mtime;
+       if (dtime==0) dtime=1;
+       dist=mx-nx;
+       tspeed= (f_prec) dist/dtime;
+       vtt->speed=tspeed*mouse_speed;
+       
+       mx=nx;
+       mtime=ntime;
+}
+
+/* tx_Window::handle_event() : Evaluates the type of the event and calls
+   corresponding method.
+*/
+
+void tX_Window :: handle_event()
+{
+       switch (xev.type)
+       {
+               case KeyPress: 
+                       handle_KeyPress();
+               break;
+               
+               case KeyRelease:
+                       handle_KeyRelease();
+               break;
+               
+               case MotionNotify:
+                       handle_Motion();
+               break;
+               
+               case Expose:
+                       repaint();
+               break;
+               
+               default:
+                       printf("[tX:check_event] Unhandled Event of type: 0x%x\n", xev.type);
+       }
+}
+
+/* tx_Window::event_wait() : Waits for an event. Is called when playback
+   is not active.
+*/
+
+int tX_Window :: event_wait()
+{
+       XWindowEvent(disp, win, event_mask, &xev);
+       handle_event();
+       return(quit);
+}
+
+
+/* tX_Window::event_check() : Checks for an event. If there is one handle_event is called. 
+   For use when playback is active.
+*/
+
+int tX_Window :: event_check()
+{
+#ifdef USE_STOPSENSE
+       mouse_busy--;
+       if ((mouse_busy==0) && (!motor_on)) vtt->speed=0.0;
+#endif 
+       if (XCheckWindowEvent(disp, win, event_mask, &xev) == True)
+       {
+               handle_event();
+       }
+       return (quit);
+}
+
+/* tX_Window::loop() : Calls event_check and event_wait until
+   quit is set.
+*/
+
+void tX_Window :: loop()
+{
+       int newpb;
+       
+       while (!quit)
+       {
+               if (playback_active)
+               {
+                       event_check();
+                       if (playback_active)
+                       {
+                               newpb=!vtt->block_action();
+                               if (!newpb)
+                               {
+                                       vtt->needle_up();
+                                       if (vtt->mode == MODE_RECORD_SCRATCH)
+                                       {
+                                               vtt->store_rec_pos();
+                                       }
+                                       playback_active=newpb;
+                                       
+                                       set_pos(0);
+                                       display_action();
+                               }
+                               XUngrabPointer(disp, CurrentTime);
+                               playback_active=newpb;
+                       }
+               }
+               else
+               {
+                       event_wait();
+               }
+       }
+}
+
+/* tX_Window::display_mode() : displays the current vtt mode in the lower
+   right edge of the window (empty and full circle & arrow)
+*/
+
+void tX_Window :: display_mode()
+{
+       int x,y,w,h;
+
+       x=modex;
+       y=modey;
+       w=bt_w;
+       h=bt_h;
+
+       if (vtt->mode == MODE_SCRATCH) XSetForeground(disp, gc, col_activebtn.pixel);
+       else XSetForeground(disp, gc, col_inactivebtn.pixel);
+               
+       XDrawArc(disp, win, gc, x, y, w, h, 0, 23040);
+       
+       x+=bt_a+bt_w;
+       
+       if (vtt->mode == MODE_RECORD_SCRATCH) XSetForeground(disp, gc, col_activebtn.pixel);
+       else XSetForeground(disp, gc, col_inactivebtn.pixel);
+
+       XFillArc(disp, win, gc, x, y, w, h, 0, 23040);
+       XDrawArc(disp, win, gc, x, y, w, h, 0, 23040);
+       
+       x+=bt_a+bt_w;
+       
+       if (vtt->mode == MODE_PLAYBACK_RECORDED) XSetForeground(disp, gc, col_activebtn.pixel);
+       else XSetForeground(disp, gc, col_inactivebtn.pixel);
+
+       XDrawLine(disp, win, gc, x, y, x, y+bt_h);
+       XDrawLine(disp, win, gc, x, y, x+bt_w, y+(bt_h/2));
+       XDrawLine(disp, win, gc, x, y+bt_h, x+bt_w, y+(bt_h/2));
+       
+       XSync(disp, False);
+}
+
+/* tX_Window :: display_action() : Displays the current playback status. */
+
+void tX_Window :: display_action()
+{
+       int x,y,w,h;
+
+       x=modex+3*(bt_w+bt_a);
+       y=modey;
+       w=2*bt_w+bt_a;
+       h=bt_h;
+
+
+       if (playback_active)
+       {
+               XSetForeground(disp, gc, col_pos.pixel);                
+               XDrawRectangle(disp, win, gc, x, y, w, h);
+               XFillRectangle(disp, win, gc, x, y, w, h);              
+       }       
+       else
+       {
+               XSetForeground(disp, gc, black);
+               XFillRectangle(disp, win, gc, x, y, w, h);                              
+               XSetForeground(disp, gc, col_pos.pixel);        
+               XDrawRectangle(disp, win, gc, x, y, w, h);              
+       }       
+}
+
+/* tX_Window::display_text() : The method name says it all...*/
+
+void tX_Window :: display_text()
+{
+       int x,y,w,h;
+       char buffer[256];
+       char out[1024];
+       
+       x=0; y=height-TOOLBAR_SIZE; w=modex-1; h=TOOLBAR_SIZE;
+       
+       XSetForeground(disp, gc, black);
+       XFillRectangle(disp, win, gc, x, y, w, h);
+       
+       x=BORDER_ALIGN;
+       y=height-TOOLBAR_SIZE+2*BORDER_ALIGN;
+       
+       strcpy(out, "Scratch: [");
+       strcat(out, s_name);
+       strcat(out, "] - ");
+       
+       if (strlen(l_name))
+       {
+               strcat(out, "Loop: [");
+               strcat(out, l_name);
+               strcat(out, "] - ");
+       }
+
+       if (vtt->do_mix) 
+       {
+#ifdef USE_OLD_MIX     
+               strcat(out, "Mix: [ON]");
+#else
+               sprintf(buffer, "Mix: [S:%3i/L:%3i]", (int) (vtt->vol_scratch * 100), (int) (vtt->vol_loop * 100));
+               strcat(out, buffer);
+#endif         
+       }
+       else strcat(out, "Mix: [OFF]");
+
+       if (strlen(vtt->last_fn))
+       {
+               sprintf (buffer, " - Saved: [%s] ", vtt->last_fn);              
+               strcat(out, buffer);            
+       }
+       
+       XSetForeground(disp, gc, col_frame.pixel);
+       XDrawString(disp, win, gc, x, y, out, strlen(out));
+       
+       XSync(disp, False);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tX.h b/tX.h
new file mode 100644 (file)
index 0000000..5a3561c
--- /dev/null
+++ b/tX.h
@@ -0,0 +1,147 @@
+/*
+    terminatorX - realtime audio scratching software
+    Copyright (C) 1999  Alexander König
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    File: tX.h
+
+    Description: Header to tX.cc
+
+    For a closer description of the methods see implementation (tX.cc).
+*/
+
+#ifndef _H_TX
+#define _H_TX
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/shape.h>
+
+class tX_Window;
+class Virtual_TurnTable;
+
+#include "turntable.h"
+#include "tX_types.h"
+
+class tX_Window
+{
+       XColor col_data;
+       XColor col_frame;
+       XColor col_pos;
+       XColor col_activebtn;
+       XColor col_inactivebtn;
+       XColor col_marker;
+
+       Font font;
+       
+       unsigned long black;
+       unsigned long white;
+       
+       int verbose;
+       
+       Display *disp;  
+       Window win;
+       XSetWindowAttributes set_attr;
+       GC gc;
+       XGCValues xgcv;
+       long event_mask;        
+       XEvent xev;     
+       XKeyEvent *xkeyev;
+       XMotionEvent *xmotev;
+       
+       int modex, modey, bt_w, bt_h, bt_a;
+       
+       int samples_per_pixel;
+       int mouse_border;
+       f_prec mouse_speed;
+       int sense_cycles;
+       char s_name[256];
+       char l_name[256];
+       
+       int width;
+       int height;
+       int medx;
+       int medy;
+       int warpx_max;
+       int warpx_min;
+       
+       int data_disp_x;
+       int data_disp_y;
+       
+       int data_disp_width;
+       int data_disp_height;   
+       
+       unsigned int data_samples;
+       int16_t *data_ptr;
+
+       int pos_y;
+       int pos_max_x;
+       
+       int motor_on;
+       int first_mot_event;
+
+#ifdef USE_STOPSENSE
+       int mouse_busy;
+#endif
+       
+       int y0;
+       
+       int ptrwarped;
+       
+       int quit;       
+       
+       Virtual_TurnTable *vtt;
+
+       int mx,my;
+       Time mtime;
+       
+       public:
+       int playback_active;
+       
+       tX_Window(Virtual_TurnTable *, int, int, int, int, f_prec, int, char *, char *);
+       ~tX_Window();
+       
+       void prepare_data_display(int16_t *, unsigned int);
+       void display_data();
+       void display_mode();
+       void display_action();
+       void display_text();
+       void set_pos(int pos);
+       int get_samples_per_pixel();
+
+       int event_wait();       
+       int event_check();
+       void handle_event();
+       void handle_KeyPress();
+       void handle_KeyRelease();
+       void handle_Motion();
+       void repaint();
+       void loop();
+};
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tX_types.h b/tX_types.h
new file mode 100644 (file)
index 0000000..95062a0
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+    terminatorX - realtime audio scratching software
+    Copyright (C) 1999  Alexander König
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    File: tX_types.h
+    Description: Use correct type sizes. If <sys/types.h> is not
+                 available define USE_X86_TYPES on i386 machines
+*/    
+
+#ifndef _H_TX_TYPES
+#define _H_TX_TYPES
+
+#ifndef USE_X86_TYPES
+
+#include <sys/types.h>
+
+#else
+
+#define int8_t char
+#define int16_t short
+#define int32_t long
+
+#endif
+
+#endif
diff --git a/turntable.cc b/turntable.cc
new file mode 100644 (file)
index 0000000..f4157fe
--- /dev/null
@@ -0,0 +1,680 @@
+/*
+    terminatorX - realtime audio scratching software
+    Copyright (C) 1999  Alexander König
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    File: turntable.cc
+
+    Description: This implements the virtual turntable. Contains
+    all audio related stuff.
+
+    I no longer have -DUSE_ALIASING as I don´t have time to maintain the same
+    code twice. Aliasing is now default. 
+    
+    Changes:
+    
+    20 Mar 1999: Setting the buffer size in open_device() no
+                 happens before the DSP_RESET. This might
+                help fighting latency with some audio drivers.
+                
+    20 Mar 1999: If KEEP_DEV_OPEN is defined the audio device
+                 will be opened only once and is only closed
+                by termination of the terminatorX-process via
+                the OS. This helps if you have problems with
+                memory fragmentation and the sounddriver fails
+                to malloc the audiobuffers. If your sounddriver
+                causes awfull clicks on opening the device this
+                is nice too. Of course other processes can not access
+                the audio device while terminatorX is running.
+                see open_dev() and close_dev().
+                
+    20 Mar 1999: Big endian support
+    
+    20 Mar 1999: Removed audio clicks. Use -DHANDLE_STOP to re-enable.
+                 This is not the solution I want as it produces
+                what I consider corrupt audio.
+    
+    21 Mar 1999: do_mix is enabled automatically now if mix_data is
+                 available.
+                
+    23 Mar 1999: new mixing routine allows to set the loop to scratch
+                 ratio. Old mixing (is faster) can be re-enabled
+                via -DUSE_OLD_MIX. I consider this code as obsolete
+                if nobody tells me he/she uses that switch I'll drop the
+                old code.
+*/
+
+#include "turntable.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/soundcard.h>
+#include <stdio.h>
+#include <malloc.h>
+#include "wav_file.h"
+#include <math.h>
+
+#include "endian.h"
+#include "tX_types.h"
+
+/* Virtual_TurnTable::Virtual_TurnTable() : Does what a constructor does...
+   intialization.
+*/
+
+Virtual_TurnTable :: Virtual_TurnTable(TT_init *init_data)
+{
+#ifdef USE_CONSOLE
+       if (init_data->verbose) puts("[VTT] Initializing.");
+#endif 
+
+#ifndef USE_OLD_MIX
+       vol_loop=0.5;
+       vol_scratch=0.5;
+#endif
+       speed=init_data->speed;
+       strcpy(devicename, init_data->devicename);
+
+       default_speed=init_data->default_speed;
+       buff_cfg=init_data->buff_cfg;
+       
+       playback_data=init_data->playback_data;
+       playback_size=init_data->playback_size;
+       
+       record_data=init_data->record_data;
+       record_size=init_data->record_size;
+
+       mix_data=init_data->mix_data;
+       mix_size=init_data->mix_size;
+       
+       mix_pos=mix_data;
+       mix_max=mix_data+(size_t) (mix_size/sizeof(int16_t));
+       
+       last_block_recorded=0;
+       
+       verbose=init_data->verbose;
+
+       if (!mix_data) do_mix=0; else do_mix=1;
+       
+       dev_open=0;
+       devicefd=0;
+       win=init_data->win;
+       last_sample=0;
+       
+       strcpy(file_name, init_data->file_name);
+       file_ctr=0;
+       
+       mode=MODE_SCRATCH;
+       
+       store_pos=record_data;
+       strcpy(last_fn,"");
+}
+
+/* Virtual_TurnTable::open_dev() : Opens and configures the audio device */
+
+int Virtual_TurnTable :: open_dev()
+{
+#ifdef USE_CONSOLE
+       if (verbose) puts("[VTT:open_dev] Trying to open device.");
+#endif
+       int i=0;
+       int p;
+       
+#ifdef KEEP_DEV_OPEN
+       if (dev_open) return(0);
+#else  
+       if (dev_open) 
+       {
+#ifdef USE_CONSOLE
+       puts("[VTT:open_dev] Error: Device already open.");
+#endif
+               return (1);
+       }
+#endif
+
+        devicefd = open(devicename, O_WRONLY, 0);
+       
+       /* setting buffer size */
+       
+       p=buff_cfg;
+               
+       i = ioctl(devicefd, SNDCTL_DSP_SETFRAGMENT, &p);
+
+        ioctl(devicefd, SNDCTL_DSP_RESET, 0);          
+
+       /* 16 Bits */
+       
+        p =  16;
+        i +=  ioctl(devicefd, SOUND_PCM_WRITE_BITS, &p);
+
+       /* MONO */
+       
+        p =  1;
+        i += ioctl(devicefd, SOUND_PCM_WRITE_CHANNELS, &p);
+       
+       /* 44.1 khz */
+
+        p =  44100;
+        i += ioctl(devicefd, SOUND_PCM_WRITE_RATE, &p);
+       
+        i += ioctl(devicefd, SNDCTL_DSP_GETBLKSIZE, &deviceblocksize);
+       
+        ioctl(devicefd, SNDCTL_DSP_SYNC, 0);
+
+       dev_open=!i;
+
+        return(i);
+}
+
+/* Virtual_TurnTable::close_dev() : Closes audio device */
+
+int Virtual_TurnTable :: close_dev()
+{
+#ifdef KEEP_DEV_OPEN
+       return(ioctl(devicefd, SNDCTL_DSP_POST, 0));
+#else
+#ifdef USE_CONSOLE
+       if (verbose) puts("[VTT:close_dev] Trying to close device.");
+#endif
+       if (!dev_open)
+       {       
+#ifdef USE_CONSOLE
+       puts("[VTT:close_dev] Error: Device not open.");
+#endif 
+               return(1);              
+       }
+
+       close(devicefd);
+       devicefd=0;
+       dev_open=0;
+       
+       return(0);
+#endif
+}
+
+/* Virtual_TurnTable::set_window() : UGLY. Sets the win pointer of
+   Virutal_TurnTable. Required for position updates.
+*/
+
+void Virtual_TurnTable :: set_window(tX_Window *window)
+{
+       win=window;
+}
+
+/* Virtual_TurnTable::play_block() : plays the given audio buffer size must
+   be deviceblocksize.
+*/
+
+void Virtual_TurnTable :: play_block(int16_t *buffer)
+{
+#ifdef BIG_ENDIAN_MACHINE
+#ifndef BIG_ENDIAN_AUDIO
+       swapbuffer(buffer, samples_per_block);
+#endif 
+#else
+#ifdef BIG_ENDIAN_AUDIO
+       swapbuffer(buffer, samples_per_block);
+#endif
+#endif
+       write(devicefd, buffer, deviceblocksize);
+}
+
+/* Virtual_TurnTable::render_block() : "renders" one block of audio (scratch)
+   data into given buffer (size == deviceblocksize)
+*/
+
+void Virtual_TurnTable :: render_block(int16_t *buffer)
+{      
+       int16_t *ptr;
+       
+       int sample;
+       
+       int x_upd;      
+       
+       f_prec true_pos_a;
+       
+       f_prec diff;
+       f_prec amount_a;
+       f_prec amount_b;
+       
+       unsigned int real_pos_a;
+
+       f_prec sample_a;
+       f_prec sample_b;
+       
+       f_prec sample_res;
+       
+       if (win) 
+       {
+               x_upd=(int) (pos/spp);
+               if (x_upd!=x_last)
+               {
+                       win->set_pos(x_upd);                    
+                       x_last=x_upd;
+               }
+       }
+               
+       if (speed != target_speed)
+       {
+               target_speed=speed;
+               speed_step=target_speed-real_speed;
+               speed_step/=10.0;
+       }
+               
+       if (target_speed != real_speed)
+       {
+               real_speed+=speed_step;
+               if ((speed_step<0) && (real_speed<target_speed)) real_speed=target_speed;
+               else
+               if ((speed_step>0) && (real_speed>target_speed)) real_speed=target_speed;                       
+       }
+               
+       for (sample=0; sample < samples_per_block; sample++)
+       {
+#ifdef HANDLE_STOP     
+               if (real_speed!=0)
+               {
+#endif         
+                       pos+=real_speed;
+                       if (pos>maxpos) pos-=maxpos;
+                       else if (pos<0) pos+=maxpos;
+                               
+                       true_pos_a=floor(pos);
+                                                               
+                       diff=pos-true_pos_a;
+                               
+                       amount_b=diff;
+                       amount_a=1.0-diff;
+                               
+                       real_pos_a=(unsigned int) true_pos_a;
+                               
+                       ptr=&playback_data[real_pos_a];
+                       sample_a=(f_prec) *ptr;
+                       
+                       if (real_pos_a == playback_size) 
+                       {
+                               sample_b=*playback_data;
+                       }
+                       else
+                       {
+                               ptr++;
+                               sample_b=(f_prec) *ptr;
+                       }
+                               
+                       sample_res=(sample_a*amount_a)+(sample_b*amount_b);
+#ifdef HANDLE_STOP                     
+                       last_sample=(int16_t) sample_res;                       
+                       buffer[sample]=last_sample;
+#else
+                       buffer[sample]=(int16_t) sample_res;
+#endif
+#ifdef HANDLE_STOP
+               }
+               else
+               {
+                       if (last_sample==1) last_sample=0;
+                       if (last_sample!=0)
+                       {
+                               last_sample=(int16_t) (((f_prec) last_sample) * 0.9);
+                               buffer[sample]=last_sample;
+                       }
+                       else
+                       {                       
+                               buffer[sample]=0;
+                       }
+               }
+#endif         
+       }
+}
+
+/* Virtual_TurnTable::needle_down() : Starts playback */
+
+void Virtual_TurnTable :: needle_down()
+{
+       int result;
+       
+       spp=(f_prec) win->get_samples_per_pixel();
+       pos=0;
+       x_last=-1;
+       maxpos=(f_prec) playback_size / 2.0;
+
+       real_speed=speed;
+       target_speed=speed;
+       speed_step=0;
+/*     
+#ifdef USE_CONSOLE
+       puts("[VTT:needle_down] Trying to open device.");
+#endif */
+       result = open_dev();
+       
+       if (result) 
+       {
+#ifdef USE_CONSOLE
+               puts("[VTT:needle_down] Error: Failed opening device. Fatal. Giving up.");
+#endif         
+               exit(1);
+       }
+
+#ifdef USE_CONSOLE
+       if (verbose) printf("[VTT:needle_down] Using Blocksize of %i Bytes.\n", deviceblocksize);
+#endif
+       samples_per_block=deviceblocksize/sizeof(int16_t);
+       
+       samplebuffer=(int16_t *) malloc(deviceblocksize);
+
+       if (!samplebuffer)
+       {
+#ifdef USE_CONSOLE
+               puts("[VTT:needle_down] Error. Failed to allocate sample_buffer. Fatal. Giving up.");
+#endif
+               exit(1);        
+       }
+       
+       store_pos=record_data;
+       mix_pos=mix_data;
+       block_ctr=0;
+       block_max=record_size/deviceblocksize;
+}
+
+/* Virtual_TurnTable::needle_up() : Stops playback. */
+
+void Virtual_TurnTable :: needle_up()
+{
+       int result;
+       
+       free(samplebuffer);     
+       
+/*#ifdef USE_CONSOLE
+       puts("[VTT:needle_up] Trying to close device.");
+#endif */
+       result = close_dev();
+#ifdef USE_CONSOLE
+       if (result)
+       puts("[VTT:needle_up] Error: Failed closing device.");
+#endif 
+       
+}
+
+/* Virtual_TurnTable::set_speed() : Sets the rotation speed of the
+   Virtual TurnTable. Rarely used as writing to speed directly is 
+   faster (and uglier). 
+*/
+
+void Virtual_TurnTable :: set_speed(f_prec targetspeed)
+{
+#ifdef FUSE_CONSOLE
+       if (verbose) printf("[VTT:set_speed] Speed setup: %f.\n", targetspeed);
+#endif
+       speed=targetspeed;
+}
+
+/* Virtual_TurnTable::set_mode() : Just what it says ..*/
+
+void Virtual_TurnTable :: set_mode(int newmode)
+{
+       mode=newmode;
+}
+
+/* Virtual_TurnTable::get_next_storage_block() : Returns a pointer to the next
+   block in recordbuffer.
+*/
+
+int16_t * Virtual_TurnTable :: get_next_storage_block()
+{
+       if (block_ctr)
+       {
+               block_ctr++;
+               if (block_ctr > block_max) return(NULL);
+               store_pos+=(size_t) samples_per_block;  
+               return(store_pos);
+       }
+       else
+       {
+               block_ctr++;
+               return(store_pos);
+       }
+
+}
+
+/* Virtual_TurnTable::() : This triggers all required actions depending
+   on current mode.
+*/
+
+int Virtual_TurnTable :: block_action()
+{
+       int16_t *ptr;
+
+       switch(mode)
+       {
+               case MODE_SCRATCH:
+                       render_block(samplebuffer);
+                       if (do_mix) add_mix(samplebuffer);
+                       play_block(samplebuffer);
+                       return(0);
+
+               case MODE_RECORD_SCRATCH:
+                       ptr=get_next_storage_block();
+                       if (ptr)
+                       {
+                               render_block(ptr);
+                               if (do_mix) 
+                               {
+                                       memcpy(samplebuffer, ptr, deviceblocksize);
+                                       add_mix(samplebuffer);
+                                       play_block(samplebuffer);
+                               }
+                               else
+                               {
+                                       play_block(ptr);
+                               }
+                               return(0);
+                       }
+                       else
+                       {
+                               return(1);
+                       }
+               
+               case MODE_PLAYBACK_RECORDED:
+                       if (block_ctr>last_block_recorded) return (1);
+                       ptr=get_next_storage_block();
+                       if (ptr)
+                       {
+                               if (do_mix)
+                               {
+                                       memcpy(samplebuffer, ptr, deviceblocksize);
+                                       add_mix(samplebuffer);
+                                       play_block(samplebuffer);
+                               }
+                               else
+                               {
+                                       play_block(ptr);
+                               }
+                               return(0);
+                       }
+                       else
+                       {
+                               return(1);
+                       }
+       }
+       return(1);
+}
+
+/* Virtual_TurnTable::add_mix() : This mixes the loop file date to the
+   given buffer (size = deviceblocksize)
+*/
+
+void Virtual_TurnTable :: add_mix(int16_t * buffer)
+{
+       int sample;
+       int16_t *scratch_pos;
+       
+#ifdef USE_OLD_MIX
+       int16_t value;
+#else
+       f_prec f_val_s, f_val_l;        
+#endif
+       
+       for (sample=0, scratch_pos=buffer; sample < samples_per_block; sample ++, scratch_pos++)
+       {
+#ifdef USE_OLD_MIX     
+               value=(*mix_pos)>>1;
+               value+=(*scratch_pos)>>1;
+               *scratch_pos=value;
+#else
+               f_val_l=(f_prec) *mix_pos;
+               f_val_l*=vol_loop;
+               f_val_s=(f_prec) *scratch_pos;
+               f_val_s*=vol_scratch;
+               *scratch_pos=(int16_t) (f_val_s + f_val_l);
+#endif                         
+               mix_pos++;
+               if (mix_pos>=mix_max) mix_pos=mix_data;         
+       }
+}
+
+/* Virtual_TurnTable::toggle_mix() : Dis- or enable mixing of loop data.*/
+
+void Virtual_TurnTable :: toggle_mix()
+{
+       if (mix_data) do_mix=!do_mix;
+       else
+       {
+#ifdef USE_CONSOLE
+               puts("[VTT:toggle_mix] Error: Can't enable mixing: no loop loaded.");
+#endif         
+               do_mix=0;
+       }
+}
+
+/* Virtual_TurnTable::store_rec_pos() : Stores current recording position
+   for later playback or saving.
+*/
+
+void Virtual_TurnTable :: store_rec_pos()
+{
+       if (block_ctr > block_max) last_block_recorded=block_max;
+       else last_block_recorded=block_ctr;     
+}
+
+/* Virtual_TurnTable::() : See above and guess ;) */
+
+void Virtual_TurnTable :: reset_rec_pos()
+{
+       last_block_recorded=0;
+}
+
+/* Virtual_TurnTable::save() : Saves a recorded scratch. If the mix == 1
+   then with loop data mixed else unmixed raw scratch.
+*/
+
+void Virtual_TurnTable :: save(int mix)
+{
+       wav_sig out_wav;
+       int16_t *ptr;
+
+       if ((mix) && (!mix_data))
+       {
+#ifdef USE_CONSOLE
+               puts("[VTT:save] Error: Can't save a mixed file: no loop loaded.");
+#endif 
+               return;
+       }
+       
+       file_ctr++;
+       
+       out_wav.srate=44100;
+       out_wav.chans=1;
+       out_wav.depth=16;
+       out_wav.bps=88200;
+       out_wav.blkalign=2;
+       out_wav.len=last_block_recorded*deviceblocksize;
+       out_wav.sofar=out_wav.len;
+       
+       sprintf(out_wav.name, "%s%02i.wav", file_name, file_ctr);       
+       strcpy(last_fn, out_wav.name);
+
+#ifdef USE_CONSOLE
+       if (!mix)
+       {
+               printf("[VTT:save] Saving RAW recorded scratch to %s.\n", out_wav.name);
+       }
+       else
+       {
+               printf("[VTT:save] Saving MIXED recorded scratch to %s.\n", out_wav.name);
+       }
+#endif
+       
+       if (!open_wav_rec(&out_wav))
+       {
+#ifdef USE_CONSOLE
+               puts("[VTT:save] Failed to open output file.");
+#endif 
+               return;
+       }
+       
+       block_ctr=0;
+       store_pos=record_data;
+       mix_pos=mix_data;
+       
+#ifndef BIG_ENDIAN_MACHINE
+       if (mix)
+#endif 
+       samplebuffer=(int16_t *) malloc(deviceblocksize);
+       
+       while (block_ctr<last_block_recorded)
+       {
+               ptr=get_next_storage_block();
+               if (mix)
+               {
+                       memcpy(samplebuffer, ptr, deviceblocksize);
+                       add_mix(samplebuffer);
+#ifdef BIG_ENDIAN_MACHINE
+                       swapbuffer(samplebuffer, samples_per_block);
+#endif                 
+                       write(out_wav.handle, samplebuffer, deviceblocksize); 
+               }
+               else
+               {
+#ifdef BIG_ENDIAN_MACHINE
+                       memcpy(samplebuffer, ptr, deviceblocksize);
+                       swapbuffer(samplebuffer, samples_per_block);
+                       write(out_wav.handle, samplebuffer, deviceblocksize);                   
+#else
+                       write(out_wav.handle, ptr, deviceblocksize);
+
+#endif
+               }
+       }
+
+#ifndef BIG_ENDIAN_MACHINE     
+       if (mix)
+#endif 
+               free(samplebuffer);
+       
+       close(out_wav.handle);
+       
+#ifdef USE_CONSOLE
+       if (verbose) puts("[VTT:save] Saving done.");
+#endif 
+}
+
+
+
+
+
+
+
diff --git a/turntable.h b/turntable.h
new file mode 100644 (file)
index 0000000..94a49dd
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+    terminatorX - realtime audio scratching software
+    Copyright (C) 1999  Alexander König
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    File: turntable.h
+
+    Description: Header to turntable.cc
+
+    For a closer desciption of the methods see implementation (tunrtable.cc).
+    
+    Changes:
+    
+    20 Mar 1999: Using int16_t instead of short
+*/
+
+
+#ifndef _H_TURNTABLE
+#define _H_TURNTABLE
+
+#define MODE_SCRATCH                   1
+#define MODE_RECORD_SCRATCH            2
+#define MODE_PLAYBACK_RECORDED         3
+
+#define f_prec double
+
+#include "tX.h"
+#include "tX_types.h"
+
+typedef struct {
+       f_prec speed;
+       f_prec default_speed;
+       int buff_cfg;   
+       int bsize;      
+       int16_t *playback_data;
+       unsigned int playback_size;
+       int16_t *record_data;
+       unsigned int record_size;       
+       int16_t *mix_data;
+       unsigned int mix_size;
+       char devicename[256];
+       char file_name[128];
+       int verbose;
+       tX_Window *win;
+} TT_init;
+
+class Virtual_TurnTable
+{
+
+       f_prec real_speed;
+       f_prec target_speed;
+       f_prec speed_step;
+               
+       f_prec pos;
+       f_prec maxpos;
+
+       int buff_cfg;   
+
+       int x_last;
+       f_prec spp;
+
+       int samples_per_block;
+
+       int16_t last_sample;
+       int block_ctr;
+       int block_max;
+       int last_block_recorded;
+       int verbose;
+
+
+       public:
+
+#ifndef USE_OLD_MIX
+       f_prec vol_loop;
+       f_prec vol_scratch;
+#endif
+       
+       /* Rotation-Speed of Turntable */
+       f_prec speed;
+       f_prec default_speed;   
+       
+       char devicename[256];
+       int devicefd;
+       int deviceblocksize;
+       
+       tX_Window *win;
+       
+       int file_ctr;
+       char file_name[128];
+       char last_fn[128];
+       
+       int16_t *playback_data;
+       unsigned int playback_size;
+       
+       int16_t *record_data;
+       int16_t *store_pos;
+       unsigned int record_size;
+               
+       int16_t *mix_data;
+       unsigned int mix_size;
+       int16_t *mix_pos;
+       int16_t *mix_max;       
+       int do_mix;
+
+       /* Dynamic Data */
+       
+       int dev_open;
+       int mode;       
+               
+       public:
+       
+       int16_t *samplebuffer;
+
+       Virtual_TurnTable(TT_init *);
+       ~Virtual_TurnTable();
+               
+       void set_window(tX_Window *);           
+
+       void needle_up();
+       void needle_down();
+       
+       void play_block(int16_t *);
+       int16_t * get_next_storage_block();
+       
+       void render_block(int16_t *);
+
+       void toggle_mix();      
+       void set_mode(int );
+       void add_mix(int16_t *);
+       
+       void store_rec_pos();
+       void reset_rec_pos();
+       
+       void save(int);
+       
+       int block_action();
+       
+       void set_speed(f_prec);
+               
+       int open_dev();
+       int close_dev();
+};
+
+#endif
diff --git a/version.h b/version.h
new file mode 100644 (file)
index 0000000..997de08
--- /dev/null
+++ b/version.h
@@ -0,0 +1,6 @@
+#ifndef _H_VERSION
+#define _H_VERSION
+
+#define VERSIONSTRING "terminatorX V2.3"
+
+#endif
diff --git a/wav_file.h b/wav_file.h
new file mode 100644 (file)
index 0000000..473368b
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+    wav_file.h - taken from wav-tools 1.1
+    Copyright (C) by Colin Ligertwood
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    
+    Changes:
+    
+    11 Mar 1999: -added license hint
+                 -slight changes for use with terminatorX
+
+    20 Mar 1999: now includes sys/types.h and uses types
+                 defined there for interplatform compability. 
+*/
+
+#ifndef _H_WAVFILE
+#define _H_WAVFILE
+
+#include "tX_types.h"
+
+typedef struct{
+       int32_t srate;
+       int8_t  chans;
+       int8_t  depth;
+       int32_t bps;
+       int8_t  blkalign;
+       int32_t len;
+       int32_t sofar;
+       
+       int     handle;
+       char    name[31];
+       char    head[43];
+} wav_sig;
+
+extern int init_wav_read(char file_name[], wav_sig *info);
+extern int open_wav_rec(wav_sig *info);
+extern int rewrite_head(wav_sig *info);
+
+#endif
diff --git a/wav_read.cc b/wav_read.cc
new file mode 100644 (file)
index 0000000..fabe122
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+    wav_read.cc - taken from wav-tools 1.1
+    Copyright (C) by Colin Ligertwood
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    
+    Changes:
+    
+    11 Mar 1999: added license hint
+    
+    20 Mar 1999: using types in sys/types for interplatform
+                 compability.
+                
+    20 Mar 1999: support for big endian machines
+*/
+
+/* operations for verifying and reading wav files. */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include "wav_file.h"
+#include <unistd.h>
+
+#include "endian.h"
+
+/* Read little endian 16bit values little endian
+*/
+#define le_read16(x); \
+       int16_t tmp; \
+       int8_t *p; \
+       \
+       p = (int8_t *) &tmp; \
+       p[0] = info->head[x]; \
+       p[1] = info->head[x+1]; 
+       
+
+/* Handle Endianess
+*/
+#ifdef BIG_ENDIAN_MACHINE
+#define read16(x); le_read16(x); swap16(&tmp); return(tmp);
+#else
+#define read16(x); le_read16(x); return(tmp);
+#endif
+
+/* Read little endian 32bit values little endian
+*/
+#define le_read32(x); \
+       int32_t tmp; \
+       int8_t *p; \
+       \
+       p = (int8_t *) &tmp; \
+       p[0] = info->head[x]; \
+       p[1] = info->head[x+1]; \
+       p[2] = info->head[x+2]; \
+       p[3] = info->head[x+3]; 
+       
+
+/* Handle Endianess
+*/
+#ifdef BIG_ENDIAN_MACHINE
+#define read32(x); le_read32(x); swap32(&tmp); return(tmp);
+#else
+#define read32(x); le_read32(x); return(tmp);
+#endif
+
+       /* wav header is 44 bytes long */
+int open_wav(char *header, char file_name[]){
+       int handle;
+       handle = open(file_name, O_RDONLY, S_IREAD);
+       read(handle,(char *) header, 44);
+
+       return(handle);
+}
+
+int16_t get_wav_format(wav_sig *info){
+       read16(20);
+}
+
+       /* mono or stereo */
+int8_t get_wav_channels(wav_sig *info){
+       return(info->head[22]);
+//     read16(22);
+}
+
+       /* sample rate */
+int32_t get_wav_srate(wav_sig *info){
+       read32(24);
+}
+
+int32_t get_wav_bps(wav_sig *info){
+       read32(28);
+}
+
+int8_t get_wav_blkalign(wav_sig *info){
+       return(info->head[32]);
+//     read16(32);
+}
+
+       /* sample depth (8bit or 16bit) */
+int8_t get_wav_depth(wav_sig *info){
+       return(info->head[34]);
+//     read16(34);
+}
+
+       /* data section only  ==  totalfile - 44 */
+int32_t get_wav_len(wav_sig *info){
+       read32(40);
+}
+
+
+int init_wav_read(char file_name[], wav_sig *info){
+       info->handle = open_wav(info->head, file_name);
+       strcpy(info->name,file_name);
+       info->chans = get_wav_channels(info);
+       info->srate = get_wav_srate(info);
+       info->bps   = get_wav_bps(info);
+       info->blkalign = get_wav_blkalign(info);
+       info->depth = get_wav_depth(info);
+       info->len   = get_wav_len(info);
+       return(info->handle);   
+}
diff --git a/wav_write.cc b/wav_write.cc
new file mode 100644 (file)
index 0000000..b948a1a
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+    wav_write.cc - taken from wav-tools 1.1
+    Copyright (C) by Colin Ligertwood
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    
+    Changes:
+    
+    11 Mar 1999: -added license hint
+                 -added return statement in rewrite_head
+                
+    20 Mar 1999: -using sys/types.h for type sizes for interplatform
+                compatibility
+
+    22 Mar 1999: removed some wav-tools bugs (handling 8-Bit
+                 values as 16Bit integers) 
+*/
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/soundcard.h>
+#include "wav_file.h"
+#include <unistd.h>
+
+#include "endian.h"
+
+void init_head(wav_sig *info){
+       int16_t tmp16;
+       int32_t tmp32;
+       
+       strcpy(info->head, "RIFF    WAVEfmt                     data    ");
+       
+       tmp32=(info->sofar + 32);       
+#ifdef BIG_ENDIAN_MACHINE      
+       swap32(&tmp32);
+#endif
+       *(int32_t  *)&info->head[4]  = tmp32;
+       
+       
+       tmp32=16;
+#ifdef BIG_ENDIAN_MACHINE      
+       swap32(&tmp32);
+#endif
+       *(int32_t *)&info->head[16] = tmp32;
+       
+       tmp16=1;
+#ifdef BIG_ENDIAN_MACHINE      
+       swap16(&tmp16);
+#endif
+       *(int16_t *)&info->head[20] = tmp16;
+       
+       info->head[22] = info->chans;
+       info->head[23] = 0;     
+       
+       tmp32=info->srate;
+#ifdef BIG_ENDIAN_MACHINE      
+       swap32(&tmp32);
+#endif
+       *(int32_t  *)&info->head[24] = tmp32;
+       
+       tmp32=info->bps;
+#ifdef BIG_ENDIAN_MACHINE      
+       swap32(&tmp32);
+#endif
+       *(int32_t  *)&info->head[28] = tmp32;
+       
+        info->head[32] = info->blkalign;
+       info->head[33] = 0;
+               
+       info->head[34] = info->depth;
+       info->head[35] = 0;
+       
+       tmp32=info->sofar;
+#ifdef BIG_ENDIAN_MACHINE      
+       swap32(&tmp32);
+#endif
+       *(int32_t  *)&info->head[40] = tmp32;
+}
+
+int open_wav_rec(wav_sig *info){
+       info->handle = open(info->name, O_CREAT | O_RDWR, 0644);
+       init_head(info);
+       write(info->handle, info->head, 44);
+       return(info->handle);
+}
+
+int rewrite_head(wav_sig *info){
+       lseek(info->handle, 0, SEEK_SET);
+       init_head(info);
+       write(info->handle, info->head, 44);
+       /* make -Wall shut_up */
+       return(0);
+}