[LibRemix] libremix library added. Debianization is done. multi channel support added...
authorprince <prince.dubey@samsung.com>
Mon, 19 Sep 2011 12:00:10 +0000 (21:00 +0900)
committerprince <prince.dubey@samsung.com>
Tue, 20 Sep 2011 12:24:11 +0000 (21:24 +0900)
.svn folder removed.

Change-Id: I8ae32b3fa09d6a6a8d023e8b8518d0346a0e0aea

89 files changed:
ACKNOWLEDGEMENTS [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
config.h.in [new file with mode: 0644]
configure.ac [new file with mode: 0644]
ctxdata.pc.in [new file with mode: 0644]
debian/changelog [new file with mode: 0755]
debian/compat [new file with mode: 0755]
debian/control [new file with mode: 0755]
debian/copyright [new file with mode: 0755]
debian/libremix-dev.install [new file with mode: 0644]
debian/libremix.install [new file with mode: 0755]
debian/rules [new file with mode: 0755]
doc/Doxyfile.in [new file with mode: 0644]
doc/Makefile.am [new file with mode: 0644]
include/Makefile.am [new file with mode: 0644]
include/remix/Makefile.am [new file with mode: 0644]
include/remix/remix.h [new file with mode: 0644]
include/remix/remix_deck.h [new file with mode: 0644]
include/remix/remix_envelope.h [new file with mode: 0644]
include/remix/remix_meta.h [new file with mode: 0644]
include/remix/remix_plugin.h [new file with mode: 0644]
include/remix/remix_stream.h [new file with mode: 0644]
include/remix/remix_time.h [new file with mode: 0644]
include/remix/remix_types.h [new file with mode: 0644]
ltconfig [new file with mode: 0755]
m4/ac_attribute.m4 [new file with mode: 0644]
remix.pc.in [new file with mode: 0644]
remix.spec [new file with mode: 0644]
remix.spec.in [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/ctxdata/Makefile.am [new file with mode: 0644]
src/ctxdata/cd_list.c [new file with mode: 0644]
src/ctxdata/cd_scalar.c [new file with mode: 0644]
src/ctxdata/cd_set.c [new file with mode: 0644]
src/ctxdata/ctxdata.h [new file with mode: 0644]
src/examples/1052.wav [new file with mode: 0644]
src/examples/909_cl.wav [new file with mode: 0644]
src/examples/M1F1-int16-AFsp.wav [new file with mode: 0644]
src/examples/Makefile.am [new file with mode: 0644]
src/examples/cd_list_test.c [new file with mode: 0644]
src/examples/noisedemo.c [new file with mode: 0644]
src/examples/simple_sndfiledemo.c [new file with mode: 0755]
src/examples/simple_squaredemo.c [new file with mode: 0755]
src/examples/sndfiledemo.c [new file with mode: 0644]
src/examples/squaredemo.c [new file with mode: 0644]
src/libremix/Makefile.am [new file with mode: 0644]
src/libremix/remix_base.c [new file with mode: 0644]
src/libremix/remix_channel.c [new file with mode: 0644]
src/libremix/remix_channelset.c [new file with mode: 0644]
src/libremix/remix_chunk.c [new file with mode: 0644]
src/libremix/remix_compat.h [new file with mode: 0644]
src/libremix/remix_context.c [new file with mode: 0644]
src/libremix/remix_debug.c [new file with mode: 0644]
src/libremix/remix_deck.c [new file with mode: 0644]
src/libremix/remix_envelope.c [new file with mode: 0644]
src/libremix/remix_error.c [new file with mode: 0644]
src/libremix/remix_gain.c [new file with mode: 0644]
src/libremix/remix_layer.c [new file with mode: 0644]
src/libremix/remix_meta.c [new file with mode: 0644]
src/libremix/remix_monitor.c [new file with mode: 0644]
src/libremix/remix_null.c [new file with mode: 0644]
src/libremix/remix_pcm.c [new file with mode: 0644]
src/libremix/remix_plugin.c [new file with mode: 0644]
src/libremix/remix_private.h [new file with mode: 0644]
src/libremix/remix_sndfile.c [new file with mode: 0644]
src/libremix/remix_sound.c [new file with mode: 0644]
src/libremix/remix_squaretone.c [new file with mode: 0644]
src/libremix/remix_stream.c [new file with mode: 0644]
src/libremix/remix_time.c [new file with mode: 0644]
src/libremix/remix_track.c [new file with mode: 0644]
src/plugins/Makefile.am [new file with mode: 0644]
src/plugins/ladspa/Makefile.am [new file with mode: 0644]
src/plugins/ladspa/ladspa.h [new file with mode: 0644]
src/plugins/ladspa/remix_ladspa.c [new file with mode: 0644]
src/plugins/noise/Makefile.am [new file with mode: 0644]
src/plugins/noise/remix_noise.c [new file with mode: 0644]
src/tests/Makefile.am [new file with mode: 0644]
src/tests/noop.c [new file with mode: 0644]
src/tests/sndfiletest.c [new file with mode: 0644]
src/tests/tests.h [new file with mode: 0644]
stamp-h.in [new file with mode: 0644]

diff --git a/ACKNOWLEDGEMENTS b/ACKNOWLEDGEMENTS
new file mode 100644 (file)
index 0000000..a591721
--- /dev/null
@@ -0,0 +1,28 @@
+Thanks to the following people, without whose advice and encouragement
+Remix would never have seen the light of day. -K.
+
+
+Carsten Haitzler (The Rasterman) <raster@rasterman.com>
+
+  Rasterman wrote Evas, a graphical canvas library. The simplicity of
+Remix's programming interface was inspired by that of Evas, and Rasterman
+has effusively explained the motivation for much of Evas' design to me.
+Having programmed with Evas, and having witnessed Rasterman code up complex
+graphical applications in no time flat using Evas, I knew that it would be
+well worth the effort to write a similarly powerful abstraction library for
+audio.
+
+
+Erik de Castro Lopo <erikd@zip.com.au>
+
+  Erik is the author of libsndfile, and has given excellent advice on
+optimisations for Remix.
+
+
+Silvia Pfeiffer <Silvia.Pfeiffer@CSIRO.AU>
+
+  Silvia supervised the construction of Remix, and has a knack for
+pinpointing obscure design problems and limitations. She prompted the
+creation of Remix after noticing the lack of genericity within early
+versions of Sweep, and she has guided the scope of Remix with an eye to
+ensuring its utility in a wide range of projects.
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..b9e0b9b
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Conrad Parker <conrad@metadecks.org>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..223ede7
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,504 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, 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 library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+  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.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+  If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be 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.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+  9. 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 Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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 with
+this License.
+\f
+  11. 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 Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  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 library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..11c9e4d
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,27 @@
+Thu May  1 08:58:55 EST 2003 Conrad Parker <conrad@metadecks.org>
+
+       * changed name to libremix, type names to Remix*, funcs remix_*
+
+Sun Apr 27 20:23:15 EST 2003 Conrad Parker <conrad@metadecks.org>
+
+       * added ctxdata.pc
+
+Tue Apr  8 22:57:37 EST 2003 Conrad Parker <conrad@metadecks.org>
+
+       * merged in ALSA monitor support from Erik de Castro Lopo
+       * merged in tests subdir from Erik de Castro Lopo
+       * random bugfixes
+
+Wed Apr  2 22:34:07 EST 2003 Conrad Parker <conrad@metadecks.org>
+
+       * changed name to libmash
+       * made pointer types explicit
+       * changed all type and function names to Mash*/mash_*
+
+Mon Nov 25 2002 Conrad Parker <conrad@metadecks.org>
+
+       * updated to use libsndfile1
+
+Fri Aug 17 11:41:50 EST 2001 Conrad Parker <Conrad.Parker@CSIRO.AU>
+
+       * First build (5000 lines, 3 weeks, much coffee)
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..b42a17a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+   These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+   The file `configure.in' is used to create `configure' by a program
+called `autoconf'.  You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  You can give `configure'
+initial values for variables by setting them in the environment.  Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+     CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+     env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory.  After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on.  Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+     CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+   If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+     Use and save the results of the tests in FILE instead of
+     `./config.cache'.  Set FILE to `/dev/null' to disable caching, for
+     debugging `configure'.
+
+`--help'
+     Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--version'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..3ed3bb8
--- /dev/null
@@ -0,0 +1,11 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = doc include src
+DIST_SUBDIRS = $(SUBDIRS)
+
+EXTRA_DIST = ACKNOWLEDGEMENTS \
+       ctxdata.pc.in remix.pc.in \
+       remix.spec.in remix.spec
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = ctxdata.pc remix.pc
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..212f3f2
--- /dev/null
+++ b/README
@@ -0,0 +1,58 @@
+About libremix
+==============
+
+libremix is a library for audio sequencing and mixing.
+
+More information is available online at the libremix homepage:
+
+http://www.metadecks.org/software/remix/
+
+To receive announcements about new libremix releases, please join the
+remix-announce mailing list listed on the homepage.
+
+Developers
+----------
+
+Please join the remix-devel mailing list, linked from the homepage.
+
+libremix is maintained in Subversion with anonymous read access. You can
+check out the most current version of libremix from:
+
+svn co http://svn.metadecks.org/libremix/trunk libremix
+
+A list of outstanding tasks is maintained in the TODO file of this source
+distribution. When implementing anything listed in this file, please update
+it by deleting that entry, and include that as part of the patch or commit
+that implements the fix.
+
+Copyrights
+----------
+
+Copyright (C) 2000-2010 Conrad Parker <conrad@metadecks.org>
+Copyright (C) 2001, 2002 Commonwealth Scientific and Industrial Research
+Organisation (CSIRO), Australia.
+
+Licence
+-------
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact
+-------
+
+For technical and other queries, please contact the author:
+
+Conrad Parker <conrad@metadecks.org>
+(kfish on #lad or #sweep on Freenode).
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..ca89a2a
--- /dev/null
+++ b/TODO
@@ -0,0 +1,16 @@
+
+This is a loosely-categorized list of outstanding tasks and ideas for improving
+libremix. When implementing any of these, please include an update to this TODO
+file removing that task, in the same commit.
+
+* update with TODOs from paper file
+
+Memory leaks
+------------
+
+libremix:
+       * implement remix_destroy_list() in remix_context.c, and call it on
+         world->plugins and world->bases
+
+ladspa:
+       * free schemes created for each ladspa port
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..2e69190
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+package="remix"
+rm -rf autom4te.cache
+rm -f aclocal.m4 ltmain.sh
+
+touch README
+
+echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1
+echo "Running aclocal..." ; aclocal $ACLOCAL_FLAGS -I m4 || exit 1
+echo "Running autoheader..." ; autoheader || exit 1
+echo "Running autoconf..." ; autoconf || exit 1
+echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1
+
+if [ -z "$NOCONFIGURE" ]; then
+        ./configure "$@"
+fi
+
diff --git a/config.h.in b/config.h.in
new file mode 100644 (file)
index 0000000..3c3f2ad
--- /dev/null
@@ -0,0 +1,98 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to build experimental code */
+#undef ANX_CONFIG_EXPERIMENTAL
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define if libsndfile version 1 found */
+#undef HAVE_LIBSNDFILE1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/soundcard.h> header file. */
+#undef HAVE_SYS_SOUNDCARD_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Set the plugin directory for remix */
+#undef PACKAGE_PLUGIN_DIR
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..797957f
--- /dev/null
@@ -0,0 +1,203 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(src/libremix/remix_base.c)
+
+AM_INIT_AUTOMAKE(remix, 0.2.3)
+AM_CONFIG_HEADER(config.h)
+
+dnl Checks for programs.
+AM_PROG_LIBTOOL
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AM_PROG_CC_C_O
+
+# Check for doxygen
+AC_CHECK_PROG(HAVE_DOXYGEN, doxygen, true, false)
+AM_CONDITIONAL(HAVE_DOXYGEN,$HAVE_DOXYGEN)
+if test $HAVE_DOXYGEN = "false"; then
+             AC_MSG_WARN([*** doxygen not found, docs will not be built])
+fi
+
+# Check for valgrind
+VALGRIND_ENVIRONMENT=""
+ac_enable_valgrind=no
+AC_ARG_ENABLE(valgrind-testing,
+     [  --enable-valgrind-testing     enable running of tests inside Valgrind ],     [ ac_enable_valgrind=yes ], [ ac_enable_valgrind=no] )
+
+if test "x${ac_enable_valgrind}" = xyes ; then
+  if test "x${enable_shared}" = xyes ; then
+    VALGRIND_ENVIRONMENT="libtool --mode=execute "
+  fi
+
+  AC_CHECK_PROG(HAVE_VALGRIND, valgrind, yes, no)
+  if test "x$HAVE_VALGRIND" = xyes ; then
+    VALGRIND_ENVIRONMENT="$VALGRIND_ENVIRONMENT valgrind -q --leak-check=yes --show-reachable=yes --num-callers=50"
+    AC_SUBST(VALGRIND_ENVIRONMENT)
+    TESTS_INFO="'make check' test suite will be run under:
+  ${VALGRIND_ENVIRONMENT}"
+  else
+    TESTS_INFO="'make check' to run test suite (Valgrind not found)"
+  fi
+else
+  TESTS_INFO="'make check' to run test suite (Valgrind testing not enabled)"
+fi
+
+dnl
+dnl  Configuration option for building of experimental code.
+dnl
+
+ac_enable_experimental=no
+AC_ARG_ENABLE(experimental,
+     [  --enable-experimental   enable building of experimental code ],
+     [ ac_enable_experimental=yes ])
+
+if test "x${ac_enable_experimental}" = xyes ; then
+    AC_DEFINE(ANX_CONFIG_EXPERIMENTAL, [], [Define to build experimental code])
+fi
+
+dnl Checks for libraries.
+
+dnl
+dnl  Detect libsndfile 1.0
+dnl
+
+PKG_CHECK_MODULES(SNDFILE, sndfile >= 1.0.0,
+                  HAVE_LIBSNDFILE1="yes", HAVE_LIBSNDFILE1="no")
+
+AC_SUBST(SNDFILE_LIBS)
+AC_SUBST(SNDFILE_CFLAGS)
+
+if test "$HAVE_LIBSNDFILE1" = "yes" ; then
+  AC_DEFINE([HAVE_LIBSNDFILE1], [], [Define if libsndfile version 1 found])
+  AC_SUBST(SNDFILE_LIBS)
+  AC_SUBST(SNDFILE_CFLAGS)
+else
+  AC_CHECK_LIB(sndfile, sf_open, HAVE_LIBSNDFILE1="maybe")
+  if test "$HAVE_LIBSNDFILE1" = "maybe" ; then
+    AC_MSG_ERROR([
+***
+*** libsndfile-1.0.0 or greater seems to exist on your system, however
+*** the pkg-config tool cannot find its build information.
+***
+*** Please set your PKG_CONFIG_PATH environment variable to include the
+*** directory in which sndfile.pc was installed. For example, sndfile.pc
+*** is installed in /usr/local/lib/pkgconfig by default; if that is the
+*** case do:
+***
+***     export PKG_CONFIG_PATH="\$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig"
+***
+*** then run this ./configure again. If you configured libsndfile with a
+*** different --prefix option, replace /usr/local above with that prefix.
+***
+])
+  fi
+fi
+
+AM_CONDITIONAL(HAVE_LIBSNDFILE1, test "x${HAVE_LIBSNDFILE1}" = xyes)
+
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(limits.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_SIZE_T
+AC_TYPE_UID_T
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(strdup strerror)
+
+dnl Test for sys/soundcard.h -- if user doesn't have it, don't build remix_monitor
+HAVE_SYS_SOUNDCARD_H=0
+AC_CHECK_HEADERS(sys/soundcard.h)
+  if test "x${ac_cv_header_sys_soundcard_h}" = xyes ; then
+    HAVE_SYS_SOUNDCARD_H=1
+    BUILD_MONITOR=1
+  fi
+AC_SUBST(BUILD_MONITOR)
+AM_CONDITIONAL(BUILD_MONITOR, test -n "$BUILD_MONITOR")
+
+dnl
+dnl Set PACKAGE_PLUGIN_DIR in Makefiles and config.h.
+dnl
+
+PACKAGE_PLUGIN_DIR="${libdir}/remix"
+AC_SUBST(PACKAGE_PLUGIN_DIR)
+if test "x${prefix}" = "xNONE"; then
+  PACKAGE_PLUGIN_DIR="${ac_default_prefix}/lib/remix"
+else
+  PACKAGE_PLUGIN_DIR="${prefix}/lib/remix"
+fi
+AC_DEFINE_UNQUOTED(PACKAGE_PLUGIN_DIR, "$PACKAGE_PLUGIN_DIR",
+    [Set the plugin directory for remix])
+
+AC_ARG_ENABLE(gcc-werror,
+       AC_HELP_STRING([--enable-gcc-werror], [enable -Werror in all Makefiles]))
+
+dnl Use -Wall if we have gcc.
+
+if test "x$ac_cv_prog_gcc" = xyes ; then
+  CFLAGS="$CFLAGS -Wall"
+
+  if test x$enable_gcc_werror = "xyes" ; then
+    CFLAGS="$CFLAGS -Werror"
+       fi
+
+fi
+
+AC_OUTPUT([
+Makefile
+doc/Makefile
+doc/Doxyfile
+include/Makefile
+include/remix/Makefile
+src/Makefile
+src/ctxdata/Makefile
+src/libremix/Makefile
+src/plugins/Makefile
+src/plugins/ladspa/Makefile
+src/plugins/noise/Makefile
+src/examples/Makefile
+src/tests/Makefile
+ctxdata.pc
+remix.pc
+remix.spec
+])
+
+AC_MSG_RESULT([
+------------------------------------------------------------------------
+  $PACKAGE $VERSION:  Automatic configuration OK.
+
+  General configuration:
+
+    Experimental code: ........... ${ac_enable_experimental}
+
+  Plugins:
+
+    ladspa noise
+
+  Example programs (./src/examples):
+
+    ${example_programs}
+
+  Installation paths:
+
+    libremix: .................... ${prefix}/lib
+    Plugins: ..................... ${PACKAGE_PLUGIN_DIR}
+    C header files: .............. ${prefix}/include/remix
+    Documentation: ............... ${prefix}/share/doc/$PACKAGE
+
+  Building:
+
+    Type 'make' to compile $PACKAGE.
+
+    Type 'make install' to install $PACKAGE.
+
+    Type 'make check' to test $PACKAGE using the unit tests
+    contained in the src/tests directory.
+    ${TESTS_INFO}
+
+  Example programs will be built but not installed.
+------------------------------------------------------------------------
+])
+
diff --git a/ctxdata.pc.in b/ctxdata.pc.in
new file mode 100644 (file)
index 0000000..9782569
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: ctxdata
+Description: data types with functional mappings and context callbacks 
+Requires:
+Version: @VERSION@
+Libs: -L${libdir} -lctxdata
+Cflags: -I${includedir}
diff --git a/debian/changelog b/debian/changelog
new file mode 100755 (executable)
index 0000000..43ec6ac
--- /dev/null
@@ -0,0 +1,5 @@
+libremix (0.2.3) unstable; urgency=low
+
+  * Initial Version.
+
+ -- Prince Kumar Dubey <prince.dubey@samsung.com> Govindaraju S M <govi.sm@samsung.com>  Tue, 20 Sep 2011 15:00:00 +0900
\ No newline at end of file
diff --git a/debian/compat b/debian/compat
new file mode 100755 (executable)
index 0000000..7ed6ff8
--- /dev/null
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100755 (executable)
index 0000000..f6374d1
--- /dev/null
@@ -0,0 +1,29 @@
+Source: libremix
+Section: libs
+Priority: optional
+Uploaders: Prince Kumar Dubey<prince.dubey@samsung.com> Govindaraju S M<govi.sm@samsung.com>
+Maintainer: Conrad Parker <conrad@metadecks.org>
+Build-Depends: cdbs, libsndfile1-dev, pkg-config, libtool
+Standards-Version: 0.2.3
+Homepage: http://www.metadecks.org/software/remix/
+
+Package: libremix
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, libsndfile1-dev
+Suggests: libremix (= ${binary:Version})
+Description: Various binaries for use with libremix.
+   Remix is an audio sequencing and mixing library that provides a multichannel,
+   sparse audio data container (streams), a structured mixing abstraction (decks),
+   and widely useful means of generating control data (via envelopes) and of
+   caching audio data.
+
+
+Package: libremix-dev
+Architecture: any
+Section: libdevel
+Depends: ${misc:Depends}, libremix (= ${binary:Version}), libsndfile1-dev
+Description: libremix headers and static libraries
+   Remix is an audio sequencing and mixing library that provides a multichannel,
+   sparse audio data container (streams), a structured mixing abstraction (decks),
+   and widely useful means of generating control data (via envelopes) and of
+   caching audio data.
\ No newline at end of file
diff --git a/debian/copyright b/debian/copyright
new file mode 100755 (executable)
index 0000000..0413cd5
--- /dev/null
@@ -0,0 +1,23 @@
+This is libremix library, written and maintained by Conrad Parker <conrad@metadecks.org>
+on , Fri Aug 17 11:41:50 EST 2001
+
+The original source can always be found at:
+   http://www.metadecks.org/software/remix/
+
+Copyright (C) 2000-2010 Conrad Parker <conrad@metadecks.org>
+Copyright (C) 2001, 2002 Commonwealth Scientific and Industrial Research Organisation (CSIRO), Australia.
+
+License:
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
diff --git a/debian/libremix-dev.install b/debian/libremix-dev.install
new file mode 100644 (file)
index 0000000..b5a812f
--- /dev/null
@@ -0,0 +1,6 @@
+debian/tmp/usr/include/*
+debian/tmp/usr/lib/lib*.la
+debian/tmp/usr/lib/lib*.a
+debian/tmp/usr/lib/libremix.so
+debian/tmp/usr/lib/libctxdata.so
+debian/tmp/usr/lib/pkgconfig/*
diff --git a/debian/libremix.install b/debian/libremix.install
new file mode 100755 (executable)
index 0000000..7f08496
--- /dev/null
@@ -0,0 +1,2 @@
+debian/tmp/usr/lib/libremix.so.*
+debian/tmp/usr/lib/libctxdata.so.*
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..8856c24
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/class/autotools.mk
+include /usr/share/cdbs/1/rules/debhelper.mk
+
+DEB_CONFIGURE_SCRIPT := ./autogen.sh
+DEB_MAKE_CLEAN_TARGET := distclean
+DEB_CONFIGURE_EXTRA_FLAGS := --enable-dependency-tracking
+
+CFLAGS += -fvisibility=default -fPIC -W -Wall -Wextra
+LDFLAGS += -fvisibility=default -Wl,--hash-style=both -Wl,--as-needed
+
+clean::
+       [ ! -f Makefile ] || make distclean
+       rm -f libremix*.tar.bz2 libremix-*.tar.bz2.cdbs-config_list
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644 (file)
index 0000000..f13e94e
--- /dev/null
@@ -0,0 +1,1078 @@
+# Doxyfile 1.3.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = @PACKAGE@
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = @VERSION@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = libremix
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, 
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en 
+# (Japanese with English messages), Korean, Norwegian, Polish, Portuguese, 
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# This tag can be used to specify the encoding used in the generated output. 
+# The encoding is not always determined by the language that is chosen, 
+# but also whether or not the output is meant for Windows or non-Windows users. 
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES 
+# forces the Windows encoding (this is the default for the Windows binary), 
+# whereas setting the tag to NO uses a Unix-style encoding (the default for 
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING   = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited 
+# members of a class in the documentation of that class as if those members were 
+# ordinary class members. Constructors, destructors and assignment operators of 
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH        = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like the Qt-style comments (thus requiring an 
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# reimplements.
+
+INHERIT_DOCS           = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 
+# only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources 
+# only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = @top_srcdir@/include/remix
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp 
+# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc
+
+FILE_PATTERNS          = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories 
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories.
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = ../COPYING ../INSTALL ../src/examples
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = .
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.
+
+INPUT_FILTER           = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output dir.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimised for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assigments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse the 
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or 
+# super classes. Setting the tag to NO turns the diagrams off. Note that this 
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is 
+# recommended to install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similiar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes that 
+# lay further from the root node will be omitted. Note that setting this option to 
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also 
+# note that a graph may be further truncated if the graph's image dimensions are 
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). 
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..fc9e479
--- /dev/null
@@ -0,0 +1,54 @@
+docdir=$(prefix)/share/doc/@PACKAGE@
+
+EXTRA_DIST = Doxyfile.in
+
+doc_DATA = doxygen-build.stamp
+
+if HAVE_DOXYGEN
+doxygen-build.stamp: Doxyfile $(top_srcdir)/include/remix/*.h
+       doxygen
+       touch doxygen-build.stamp
+else
+doxygen-build.stamp:
+       echo "*** Warning: Doxygen not found; documentation will not be built."
+       touch doxygen-build.stamp
+endif
+
+dist_docdir = $(distdir)/libremix
+
+dist-hook:
+       if test -d libremix; then \
+         mkdir $(dist_docdir); \
+         for dir in libremix/*; do \
+            if test -d $$dir; then \
+              b=`basename $$dir`; \
+              mkdir $(dist_docdir)/$$b; \
+             for f in $$dir/*; do \
+                cp -p $$f $(dist_docdir)/$$b; \
+              done \
+            fi \
+          done \
+       fi
+
+
+install-data-local: doxygen-build.stamp
+       $(mkinstalldirs) $(docdir)
+       if test -d libremix; then \
+         for dir in libremix/*; do \
+           if test -d $$dir; then \
+             b=`basename $$dir`; \
+             $(mkinstalldirs) $(docdir)/$$b; \
+             for f in $$dir/*; do \
+               $(INSTALL_DATA) $$f $(docdir)/$$b; \
+              done \
+           fi \
+         done \
+       fi
+
+uninstall-local:
+       rm -rf $(docdir)
+
+clean-local:
+       if test -d libremix; then rm -rf libremix; fi
+       if test -f doxygen-build.stamp; then rm -f doxygen-build.stamp; fi
+
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644 (file)
index 0000000..b58b753
--- /dev/null
@@ -0,0 +1,2 @@
+
+SUBDIRS = remix
diff --git a/include/remix/Makefile.am b/include/remix/Makefile.am
new file mode 100644 (file)
index 0000000..1e86fc1
--- /dev/null
@@ -0,0 +1,10 @@
+## Process this file with automake to produce Makefile.in
+
+# Include files to install
+includedir = $(prefix)/include/remix
+
+include_HEADERS = \
+       remix.h remix_types.h remix_time.h remix_meta.h \
+       remix_deck.h remix_stream.h \
+       remix_envelope.h \
+       remix_plugin.h
diff --git a/include/remix/remix.h b/include/remix/remix.h
new file mode 100644 (file)
index 0000000..8a4583e
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ * Copyright (C) 2003 Conrad Parker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/** \file
+ * Base types and public interfaces to libremix
+ *
+ */
+
+/*
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#ifndef __REMIX_H__
+#define __REMIX_H__
+
+/** \mainpage
+ *
+ * \section Introduction
+ *
+ * Remix is an audio sequencing and mixing library that provides a
+ * multichannel, sparse audio data container (streams), a structured mixing
+ * abstraction (decks), and widely useful means of generating control data
+ * (via envelopes) and of caching audio data.
+ *
+ * \subsection contents Contents
+ *
+ * - \link remix_deck.h Decks \endlink:
+ * The Remix hierarchical mixing abstraction
+ *
+ * - \link remix_stream.h Streams \endlink:
+ * The multichannel PCM stream abstraction
+ *
+ * - \link remix.h remix.h \endlink:
+ * Documentation of the Remix C API
+ *
+ * - \link examples Examples \endlink:
+ * Annotated example programs
+ *
+ * - \link configuration Configuration \endlink:
+ * Customizing libremix.
+ *
+ * - \link building Building \endlink:
+ * Information related to building software that uses libremix.
+ *
+ * \section licensing Licensing
+ *
+ * libremix is provided under the
+ * \link lgpl GNU Lesser General Public License \endlink.
+ *
+ */
+
+/** \defgroup lgpl Licensing
+ * \section lgpl GNU Lesser General Public License
+ *
+ * \include COPYING
+ */
+
+/** \defgroup configuration Configuration
+ * \section ./configure ./configure
+ *
+ * It is possible to customize the functionality of libremix
+ * by using various ./configure flags when
+ * building it from source.
+ *
+ * For general information about using ./configure, see the file
+ * \link install INSTALL \endlink
+ */
+
+/** \defgroup install Installation
+ * \section install INSTALL
+ *
+ * \include INSTALL
+ */
+
+/** \defgroup building Building against libremix
+ *
+ *
+ * \section autoconf Using GNU autoconf
+ *
+ * If you are using GNU autoconf, you do not need to call pkg-config
+ * directly. Use the following macro to determine if libremix is
+ * available:
+ *
+ <pre>
+ PKG_CHECK_MODULES(REMIX, remix >= 0.2.0,
+                   HAVE_REMIX="yes", HAVE_REMIX="no")
+ if test "x$HAVE_REMIX" = "xyes" ; then
+   AC_SUBST(REMIX_CFLAGS)
+   AC_SUBST(REMIX_LIBS)
+ fi
+ </pre>
+ *
+ * If libremix is found, HAVE_REMIX will be set to "yes", and
+ * the autoconf variables REMIX_CFLAGS and REMIX_LIBS will
+ * be set appropriately.
+ *
+ * \section pkg-config Determining compiler options with pkg-config
+ *
+ * If you are not using GNU autoconf in your project, you can use the
+ * pkg-config tool directly to determine the correct compiler options.
+ *
+ <pre>
+ REMIX_CFLAGS=`pkg-config --cflags remix`
+
+ REMIX_LIBS=`pkg-config --libs remix`
+ </pre>
+ *
+ */
+
+/** \defgroup examples Example programs
+ *
+ * Example programs are fun for all the family.
+ *
+ * Here's some examples.
+ * - \link noisedemo Noise demo \endlink
+ * - \link squaredemo Square demo \endlink
+ * - \link sndfiledemo Sndfile demo \endlink
+ */
+
+/** \defgroup noisedemo Noise demo
+ *
+ * Plays a sequence of short bursts of whitenoise.
+ *
+ * \include noisedemo.c noisedemo.c
+ */
+
+/** \defgroup squaredemo Square demo
+ *
+ * Plays a polyphonic sequence of musical notes generated by a builtin
+ * square wave synthesizer.
+ *
+ * \include squaredemo.c squaredemo.c
+ */
+
+/** \defgroup sndfiledemo Sndfile demo
+ *
+ * Plays a sequence of notes using sound files from disk.
+ *
+ * \include sndfiledemo.c sndfiledemo.c
+ */
+
+#include <remix/remix_types.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern CDSet * REMIX_MONO;
+extern CDSet * REMIX_STEREO;
+
+
+/* RemixEnv */
+RemixEnv * remix_init (void);
+RemixEnv * remix_init_clone (RemixEnv * env);
+void remix_purge (RemixEnv * env);
+RemixError remix_last_error (RemixEnv * env);
+char * remix_error_string (RemixEnv * env, RemixError error);
+RemixSamplerate remix_set_samplerate (RemixEnv * env, RemixSamplerate samplerate);
+RemixSamplerate remix_get_samplerate (RemixEnv * env);
+RemixTempo remix_set_tempo (RemixEnv * env, RemixTempo tempo);
+RemixTempo remix_get_tempo (RemixEnv * env);
+CDSet * remix_set_channels (RemixEnv * env, CDSet * channelset);
+CDSet * remix_get_channels (RemixEnv * env);
+
+/* Base objects */
+
+RemixPlugin * remix_find_plugin (RemixEnv * env, char * identifier);
+
+RemixBase * remix_new (RemixEnv * env, RemixPlugin * plugin, CDSet * parameters);
+CDSet * remix_suggest (RemixEnv * env, RemixPlugin * plugin, CDSet * parameters);
+
+int remix_get_init_parameter_key (RemixEnv * env, RemixPlugin * plugin, char * name);
+int remix_get_parameter_key (RemixEnv * env, RemixBase * base, char * name);
+
+RemixParameter remix_set_parameter (RemixEnv * env, RemixBase * base, int key,
+                                 RemixParameter parameter);
+RemixParameter remix_get_parameter (RemixEnv * env, RemixBase * base, int key);
+RemixParameterType remix_get_parameter_type (RemixEnv * env, RemixBase * base, int key);
+
+
+RemixBase * remix_clone_subclass (RemixEnv * env, RemixBase * base);
+int remix_destroy (RemixEnv * env, RemixBase * base);
+int remix_destroy_list (RemixEnv * env, CDList * list);
+RemixBase * remix_prepare (RemixEnv * env, RemixBase * base);
+RemixCount remix_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                   RemixStream * input, RemixStream * output);
+RemixCount remix_length (RemixEnv * env, RemixBase * base);
+RemixCount remix_seek (RemixEnv * env, RemixBase * base, RemixCount offset, int whence);
+RemixCount remix_tell (RemixEnv * env, RemixBase * base);
+int remix_flush (RemixEnv * env, RemixBase * base);
+
+RemixCount remix_set_mixlength (RemixEnv * env, RemixCount mixlength);
+RemixCount remix_get_mixlength (RemixEnv * env);
+
+
+int remix_is_writeable (RemixEnv * env, RemixBase * base);
+int remix_is_seekable (RemixEnv * env, RemixBase * base);
+int remix_is_cacheable (RemixEnv * env, RemixBase * base);
+int remix_is_causal (RemixEnv * env, RemixBase * base);
+
+char * remix_set_name (RemixEnv * env, RemixBase * base, char * name);
+char * remix_get_name (RemixEnv * env, RemixBase * base);
+
+#include <remix/remix_deck.h>
+#include <remix/remix_envelope.h>
+#include <remix/remix_stream.h>
+
+/* SquareTone */
+RemixBase * remix_squaretone_new (RemixEnv * env, float frequency);
+float remix_squaretone_set_frequency (RemixEnv * env,
+                                     RemixBase * squaretone,
+                                     float frequency);
+float remix_squaretone_get_frequency (RemixEnv * env,
+                                     RemixBase * squaretone);
+
+/* Monitor */
+RemixMonitor * remix_monitor_new (RemixEnv * env);
+
+/* Scrubby */
+RemixBase * remix_scrubby_new (RemixEnv * env);
+RemixBase * remix_scrubby_set_source (RemixEnv * env, RemixBase * scrubby,
+                                     RemixBase * source);
+RemixBase * remix_scrubby_get_source (RemixEnv * env, RemixBase * scrubby);
+int remix_scrubby_set_direction (RemixEnv * env, RemixBase * scrubby, int direction);
+int remix_scrubby_get_direction (RemixEnv * env, RemixBase * scrubby);
+
+#include <remix/remix_time.h>
+
+#include <remix/remix_meta.h>
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __REMIX_H__ */
diff --git a/include/remix/remix_deck.h b/include/remix/remix_deck.h
new file mode 100644 (file)
index 0000000..e27053a
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ * Copyright (C) 2003 Conrad Parker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#ifndef __REMIX_DECK_H__
+#define __REMIX_DECK_H__
+
+/** \file
+ *
+ * The top level structured mixing abstraction in libremix is known as a deck.
+ * A deck contains a number of tracks which are mixed in parallel. Each
+ * track may contain a number of layers which are mixed from bottom
+ * to top in series. Finally, these layers each contain a sequence of
+ * sounds with transparency.
+ *
+ * \image html decks.png
+ * \image latex decks.eps "Inside a Remix deck" width=10cm
+ *
+ * The sequence of sounds in a layer can be indexed by samples, seconds or
+ * tempo.
+ * Sounds provide audio data from any instrument or effect source, and these
+ * sources can each be reused multiple times. A sound can even source its
+ * audio data from another entire deck, thus decks can be used to sequence
+ * other decks. In this manner effects can be applied to sequences of decks,
+ * and sequences of decks can be stored as higher level units such as
+ * verses and choruses in a music application.
+ */
+
+
+#include <remix/remix_types.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Decks */
+RemixDeck * remix_deck_new (RemixEnv * env);
+
+RemixCount remix_deck_set_mixlength (RemixEnv * env, RemixDeck * deck, RemixCount mixlength);
+RemixCount remix_deck_get_mixlength (RemixEnv * env, RemixDeck * deck);
+
+CDList * remix_deck_get_tracks (RemixEnv * env, RemixDeck * deck);
+
+/* Tracks */
+RemixTrack * remix_track_new (RemixEnv * env, RemixDeck * deck);
+RemixPCM remix_track_set_gain (RemixEnv * env, RemixTrack * track, RemixPCM gain);
+RemixPCM remix_track_get_gain (RemixEnv * env, RemixTrack * track);
+RemixCount remix_track_set_mixlength (RemixEnv * env, RemixTrack * track,
+                               RemixCount mixlength);
+RemixCount remix_track_get_mixlength (RemixEnv * env, RemixTrack * track);
+void remix_remove_track (RemixEnv * env, RemixTrack * track);
+
+RemixDeck * remix_track_get_deck (RemixEnv * env, RemixTrack * track);
+
+
+/* Layers */
+RemixLayer * remix_layer_new_ontop (RemixEnv * env, RemixTrack * track,
+                                   RemixTimeType timetype);
+RemixLayer * remix_layer_new_above (RemixEnv * env, RemixLayer * above,
+                                   RemixTimeType timetype);
+RemixLayer * remix_layer_move_ontop (RemixEnv * env, RemixLayer * layer, RemixTrack * track);
+RemixLayer * remix_layer_move_above (RemixEnv * env, RemixLayer * layer, RemixLayer * above);
+RemixLayer * remix_layer_raise (RemixEnv * env, RemixLayer * layer);
+RemixLayer * remix_layer_lower (RemixEnv * env, RemixLayer * layer);
+RemixTrack * remix_layer_get_track (RemixEnv * env, RemixLayer * layer);
+RemixDeck * remix_layer_get_deck (RemixEnv * env, RemixLayer * layer);
+RemixTimeType remix_layer_set_timetype (RemixEnv * env, RemixLayer * layer,
+                                 RemixTimeType new_type);
+RemixTimeType remix_layer_get_timetype (RemixEnv * env, RemixLayer * layer);
+RemixSound * remix_layer_get_sound_before (RemixEnv * env, RemixLayer * layer,
+                                    RemixTime time);
+RemixSound * remix_layer_get_sound_at (RemixEnv * env, RemixLayer * layer, RemixTime time);
+RemixSound * remix_layer_get_sound_after (RemixEnv * env, RemixLayer * layer, RemixTime time);
+RemixLayer * remix_layer_below (RemixEnv * env, RemixLayer * layer);
+RemixLayer * remix_layer_above (RemixEnv * env, RemixLayer * layer);
+
+/* Sounds */
+RemixSound * remix_sound_new (RemixEnv * env, RemixBase * source,
+                             RemixLayer * layer,
+                             RemixTime start_time, RemixTime duration);
+
+RemixBase * remix_sound_set_source (RemixEnv * env, RemixSound * sound,
+                                   RemixBase * source);
+RemixBase * remix_sound_get_source (RemixEnv * env, RemixSound * sound);
+RemixLayer * remix_sound_get_layer (RemixEnv * env, RemixSound * sound);
+RemixTrack * remix_sound_get_track (RemixEnv * env, RemixSound * sound);
+RemixDeck * remix_sound_get_deck (RemixEnv * env, RemixSound * sound);
+
+RemixTime remix_sound_move (RemixEnv * env, RemixSound * sound,
+                           RemixTime time);
+RemixSound * remix_sound_get_prev (RemixEnv * env, RemixSound * sound);
+RemixSound * remix_sound_get_next (RemixEnv * env, RemixSound * sound);
+
+RemixTime remix_sound_set_start_time (RemixEnv * env, RemixSound * sound,
+                                     RemixTime time);
+RemixTime remix_sound_get_start_time (RemixEnv * env, RemixSound * sound);
+RemixTime remix_sound_set_duration (RemixEnv * env, RemixSound * sound,
+                                   RemixTime time);
+RemixTime remix_sound_get_duration (RemixEnv * env, RemixSound * sound);
+
+RemixBase * remix_sound_set_rate_envelope (RemixEnv * env, RemixSound * sound,
+                                          RemixBase * rate_envelope);
+RemixBase * remix_sound_get_rate_envelope (RemixEnv * env, RemixSound * sound);
+RemixBase * remix_sound_set_gain_envelope (RemixEnv * env, RemixSound * sound,
+                                          RemixBase * gain_envelope);
+RemixBase * remix_sound_get_gain_envelope (RemixEnv * env, RemixSound * sound);
+RemixBase * remix_sound_set_blend_envelope (RemixEnv * env, RemixSound * sound,
+                                           RemixBase * blend_envelope);
+RemixBase * remix_sound_get_blend_envelope (RemixEnv * env, RemixSound * sound);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __REMIX_DECK_H__ */
diff --git a/include/remix/remix_envelope.h b/include/remix/remix_envelope.h
new file mode 100644 (file)
index 0000000..659e4f7
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ * Copyright (C) 2003 Conrad Parker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/** \file
+ * Base types and public interfaces to libremix
+ *
+ */
+
+/*
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#ifndef __REMIX_ENVELOPE_H__
+#define __REMIX_ENVELOPE_H__
+
+/** \file
+ *
+ * The information describing how a parameter changes over time appears
+ * as a generic data source. In order to create this mix automation information
+ * Remix provides linear and spline envelopes.
+ * However, parameters could alternatively be controlled by other means such
+ * as from a recording of physical slider values, from a sine wave
+ * generator, or from a deck constructed solely to generate interesting
+ * parameter values.
+ */
+
+#include <remix/remix_types.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Envelopes */
+RemixEnvelope * remix_envelope_new (RemixEnv * env, RemixEnvelopeType type);
+RemixEnvelopeType remix_envelope_set_type (RemixEnv * env,
+                                          RemixEnvelope * envelope,
+                                          RemixEnvelopeType type);
+RemixEnvelopeType remix_envelope_get_type (RemixEnv * env, RemixEnvelope * envelope);
+RemixTimeType remix_envelope_set_timetype (RemixEnv * env,
+                                          RemixEnvelope * envelope,
+                                          RemixTimeType timetype);
+RemixTimeType remix_envelope_get_timetype (RemixEnv * env,
+                                          RemixEnvelope * envelope);
+RemixPCM remix_envelope_get_value (RemixEnv * env, RemixEnvelope * envelope,
+                                  RemixTime time);
+RemixTime remix_envelope_get_duration (RemixEnv * env,
+                                      RemixEnvelope * envelope);
+RemixPCM remix_envelope_get_integral (RemixEnv * env, RemixEnvelope * envelope,
+                                     RemixTime t1, RemixTime t2);
+RemixPoint * remix_envelope_add_point (RemixEnv * env,
+                                      RemixEnvelope * envelope,
+                                      RemixTime time, RemixPCM value);
+RemixEnvelope * remix_envelope_remove_point (RemixEnv * env,
+                                            RemixEnvelope * envelope,
+                                            RemixPoint * point);
+RemixEnvelope * remix_envelope_scale (RemixEnv * env, RemixEnvelope * envelope,
+                                     RemixPCM gain);
+RemixEnvelope * remix_envelope_shift (RemixEnv * env, RemixEnvelope * envelope,
+                                     RemixTime delta);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __REMIX_H__ */
diff --git a/include/remix/remix_meta.h b/include/remix/remix_meta.h
new file mode 100644 (file)
index 0000000..f075d7a
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ * Copyright (C) 2003 Conrad Parker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/** \file
+ * Metadata for RemixBase objects
+ */
+
+/*
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#ifndef __REMIX_META_H__
+#define __REMIX_META_H__
+
+char * remix_meta_text_get_identifier (RemixEnv * env, RemixMetaText * mt);
+char * remix_meta_text_set_identifier (RemixEnv * env, RemixMetaText * mt,
+                                      char * identifier);
+char * remix_meta_text_get_category (RemixEnv * env, RemixMetaText * mt);
+char * remix_meta_text_set_category (RemixEnv * env, RemixMetaText * mt,
+                                    char * category);
+char * remix_meta_text_get_description (RemixEnv * env, RemixMetaText * mt);
+char * remix_meta_text_set_description (RemixEnv * env, RemixMetaText * mt,
+                                       char * description);
+char * remix_meta_text_get_copyright (RemixEnv * env, RemixMetaText * mt);
+char * remix_meta_text_set_copyright (RemixEnv * env, RemixMetaText * mt,
+                                     char * copyright);
+char * remix_meta_text_get_url (RemixEnv * env, RemixMetaText * mt);
+char * remix_meta_text_set_url (RemixEnv * env, RemixMetaText * mt,
+                               char * url);
+CDList * remix_meta_text_get_authors (RemixEnv * env, RemixMetaText * mt);
+void remix_meta_text_add_author (RemixEnv * env, RemixMetaText * mt,
+                                char * name, char * email);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __REMIX_META_H__ */
diff --git a/include/remix/remix_plugin.h b/include/remix/remix_plugin.h
new file mode 100644 (file)
index 0000000..51c7e33
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * remix_plugin.h -- libremix internal data types and functions.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#ifndef __REMIX_PLUGIN_H__
+#define __REMIX_PLUGIN_H__
+
+/*#define DEBUG*/
+
+#if defined(__REMIX_PLUGIN__) || defined(__REMIX__)
+
+#include <stdio.h>
+
+#include "ctxdata.h"
+
+#define REMIX_PLUGIN_API_MAJOR 1
+#define REMIX_PLUGIN_API_MINOR 0
+#define REMIX_PLUGIN_API_REVISION 0
+
+typedef struct _RemixMetaAuthor RemixMetaAuthor;
+typedef struct _RemixMetaText RemixMetaText;
+
+typedef struct _RemixParameterScheme RemixParameterScheme;
+typedef struct _RemixParameterRange RemixParameterRange;
+
+typedef struct _RemixNamedParameter RemixNamedParameter;
+
+typedef union _RemixConstraint RemixConstraint;
+
+typedef struct _RemixMethods RemixMethods;;
+
+#define REMIX_PLUGIN_WRITEABLE 1<<0
+#define REMIX_PLUGIN_SEEKABLE  1<<1
+#define REMIX_PLUGIN_CACHEABLE 1<<2
+#define REMIX_PLUGIN_CAUSAL    1<<3
+
+/* A base of a plugin */
+typedef struct _RemixPlugin RemixPlugin;
+/*typedef struct _RemixBase * RemixBase;*/
+
+typedef struct _RemixChunk RemixChunk;
+
+typedef struct _Remix_Sound_Data Remix_Sound_Data;
+
+#if defined (__REMIX__)
+#include "remix_private.h"
+#else
+typedef RemixOpaque RemixEnv;
+typedef RemixOpaque RemixPoint;
+typedef RemixOpaque RemixEnvelope;
+typedef RemixOpaque RemixStream;
+typedef RemixOpaque RemixChannel;
+typedef RemixOpaque RemixDeck;
+typedef RemixOpaque RemixTrack;
+typedef RemixOpaque RemixLayer;
+typedef RemixOpaque RemixSound;
+typedef RemixOpaque RemixSquareTone;
+typedef RemixOpaque RemixMonitor;
+#endif
+
+
+typedef CDList * (*RemixPluginInitFunc) (RemixEnv * env);
+typedef int (*RemixPluginDestroyFunc) (RemixEnv * env, RemixPlugin * plugin);
+
+typedef RemixBase * (*RemixInitFunc) (RemixEnv * env, RemixBase * base,
+                                     CDSet * parameters);
+
+typedef CDSet * (*RemixSuggestFunc) (RemixEnv * env, RemixPlugin * plugin,
+                                    CDSet * parameters,
+                                    void * plugin_data);
+
+typedef RemixBase * (*RemixCloneFunc) (RemixEnv * env, RemixBase * base);
+typedef int (*RemixDestroyFunc) (RemixEnv * env, RemixBase * base);
+typedef int (*RemixReadyFunc) (RemixEnv * env, RemixBase * base);
+typedef RemixBase * (*RemixPrepareFunc) (RemixEnv * env, RemixBase * base);
+typedef RemixCount (*RemixSeekFunc) (RemixEnv * env, RemixBase * base,
+                                    RemixCount count);
+typedef RemixCount (*RemixLengthFunc) (RemixEnv * env, RemixBase * base);
+typedef RemixCount (*RemixProcessFunc) (RemixEnv * env, RemixBase * base,
+                                       RemixCount count,
+                                       RemixStream * input,
+                                       RemixStream * output);
+typedef int (*RemixFlushFunc) (RemixEnv * env, RemixBase * base);
+
+#define REMIX_FLAGS_NONE (0)
+
+#define REMIX_AUTHOR(n,e) ((struct _RemixMetaAuthor){(n),(e)})
+#define REMIX_ONE_AUTHOR(n,e) CD_SINGLETON_LIST(CD_POINTER(&(REMIX_AUTHOR((n),(e)))))
+
+/* ChunkChunkFuncs and all the rest */
+
+/* RemixChunkFunc: a function to apply to one chunk */
+typedef RemixCount (*RemixChunkFunc) (RemixEnv * env, RemixChunk * chunk,
+                                     RemixCount offset,
+                                     RemixCount count, int channelname,
+                                     void * data);
+
+/* RemixChunkChunkFunc: a function to apply between two chunks :) */
+typedef RemixCount (*RemixChunkChunkFunc) (RemixEnv * env,
+                                          RemixChunk * src,
+                                          RemixCount src_offset,
+                                          RemixChunk * dest,
+                                          RemixCount dest_offset,
+                                          RemixCount count, int channelname,
+                                          void * data);
+
+/* RemixChunkChunkChunkFunc: a function to apply between THREE chunks !! */
+typedef RemixCount (*RemixChunkChunkChunkFunc) (RemixEnv * env,
+                                               RemixChunk * src1,
+                                               RemixCount src1_offset,
+                                               RemixChunk * src2,
+                                               RemixCount src2_offset,
+                                               RemixChunk * dest,
+                                               RemixCount dest_offset,
+                                               RemixCount count,
+                                               int channelname,
+                                               void * data);
+
+struct _RemixMetaAuthor {
+  char * name;
+  char * email;
+};
+
+struct _RemixMetaText {
+  char * identifier;
+  char * category;
+  char * description;
+  char * copyright;
+  char * url;
+  CDList * authors;
+};
+
+struct _RemixParameterRange {
+  RemixFlags valid_mask;
+  RemixParameter lower;
+  RemixParameter upper;
+  RemixParameter step;
+};
+
+struct _RemixNamedParameter {
+  char * name;
+  RemixParameter parameter;
+};
+
+#define REMIX_NAMED_PARAMETER(n,p) (&((struct _RemixNamedParameter){(n),(p)}))
+
+union _RemixConstraint {
+  CDList * list; /* list of RemixNamedParameter */
+  RemixParameterRange * range;
+};
+
+struct _RemixParameterScheme {
+  char * name;
+  char * description;
+  RemixParameterType type;
+  RemixConstraintType constraint_type;
+  RemixConstraint constraint;
+  RemixFlags hints;
+};
+
+struct _RemixPlugin {
+  RemixMetaText * metatext;
+  RemixFlags flags;
+  CDSet * init_scheme;
+  RemixInitFunc init;
+  CDSet * process_scheme;
+  RemixSuggestFunc suggest;
+  void * plugin_data;
+  RemixPluginDestroyFunc destroy;
+};
+
+struct _RemixMethods {
+  RemixCloneFunc clone;
+  RemixDestroyFunc destroy;
+  RemixReadyFunc ready;
+  RemixPrepareFunc prepare;
+  RemixProcessFunc process;
+  RemixLengthFunc length;
+  RemixSeekFunc seek;
+  RemixFlushFunc flush;
+};
+
+
+struct _RemixChunk {
+  RemixCount start_index;
+  RemixCount length;
+  RemixPCM * data;
+};
+
+
+/* debug */
+void remix_dprintf (const char * fmt, ...);
+
+/* SOUNDRENDER, remix_context */
+
+RemixError remix_set_error (RemixEnv * env, RemixError error);
+
+
+/* remix_base */
+RemixBase * remix_base_new (RemixEnv * env);
+
+RemixPlugin * remix_base_set_plugin (RemixEnv * env, RemixBase * base,
+                                    RemixPlugin * plugin);
+RemixPlugin * remix_base_get_plugin (RemixEnv * env, RemixBase * base);
+RemixMethods * remix_base_set_methods (RemixEnv * env, RemixBase * base,
+                                      RemixMethods * methods);
+void * remix_base_set_instance_data (RemixEnv * env, RemixBase * base,
+                                    void * data);
+void * remix_base_get_instance_data (RemixEnv * env, RemixBase * base);
+
+RemixCount remix_base_get_mixlength (RemixEnv * env, RemixBase * base);
+RemixSamplerate remix_base_get_samplerate (RemixEnv * env, RemixBase * base);
+RemixTempo remix_base_get_tempo (RemixEnv * env, RemixBase * base);
+CDSet * remix_base_get_channels (RemixEnv * env, RemixBase * base);
+
+int remix_base_has_samplerate (RemixEnv * env, RemixBase * base);
+int remix_base_has_tempo (RemixEnv * env, RemixBase * base);
+int remix_base_encompasses_mixlength (RemixEnv * env, RemixBase * base);
+int remix_base_encompasses_channels (RemixEnv * env, RemixBase * base);
+
+
+/* remix_meta */
+RemixMetaText * remix_meta_text_new (RemixEnv * env);
+void remix_meta_text_free (RemixEnv * env, RemixMetaText * mt);
+RemixMetaText * remix_get_meta_text (RemixEnv * env, RemixBase * base);
+RemixMetaText * remix_set_meta_text (RemixEnv * env, RemixBase * base,
+                                    RemixMetaText * mt);
+
+
+/* remix_null */
+RemixCount remix_null_length (RemixEnv * env, RemixBase * base);
+RemixCount remix_null_process (RemixEnv * env, RemixBase * base,
+                              RemixCount count,
+                              RemixStream * input, RemixStream * output);
+RemixCount remix_null_seek (RemixEnv * env, RemixBase * base,
+                           RemixCount offset);
+
+
+/* remix_stream */
+RemixCount remix_stream_chunkfuncify (RemixEnv * env, RemixStream * stream,
+                                     RemixCount count,
+                                     RemixChunkFunc func, void * data);
+RemixCount remix_stream_chunkchunkfuncify (RemixEnv * env,
+                                          RemixStream * src,
+                                          RemixStream * dest,
+                                          RemixCount count,
+                                          RemixChunkChunkFunc func,
+                                          void * data);
+RemixCount remix_stream_chunkchunkchunkfuncify (RemixEnv * env,
+                                               RemixStream * src1,
+                                               RemixStream * src2,
+                                               RemixStream * dest,
+                                               RemixCount count,
+                                               RemixChunkChunkChunkFunc func,
+                                               void * data);
+
+/* RemixChannel */
+RemixChunk * remix_channel_get_chunk_at (RemixEnv * env,
+                                        RemixChannel * channel,
+                                        RemixCount offset);
+
+RemixCount remix_channel_chunkfuncify (RemixEnv * env, RemixChannel * channel,
+                                      RemixCount count, RemixChunkFunc func,
+                                      int channelname, void * data);
+RemixCount remix_channel_chunkchunkfuncify (RemixEnv * env,
+                                           RemixChannel * src,
+                                           RemixChannel * dest,
+                                           RemixCount count,
+                                           RemixChunkChunkFunc func,
+                                           int channelname, void * data);
+RemixCount remix_channel_chunkchunkchunkfuncify (RemixEnv * env,
+                                                RemixChannel * src1,
+                                                RemixChannel * src2,
+                                                RemixChannel * dest,
+                                                RemixCount count,
+                                                RemixChunkChunkChunkFunc func,
+                                                int channelname, void * data);
+/* RemixPCM */
+
+RemixCount _remix_pcm_clear_region (RemixPCM * data, RemixCount count,
+                                   void * unused);
+RemixCount _remix_pcm_set (RemixPCM * data, RemixPCM value, RemixCount count);
+RemixCount _remix_pcm_gain (RemixPCM * data, RemixCount count,
+                           /* (RemixPCM *) */ void * gain);
+RemixCount _remix_pcm_copy (RemixPCM * src, RemixPCM * dest, RemixCount count,
+                           void * unused);
+RemixCount _remix_pcm_add (RemixPCM * src, RemixPCM * dest, RemixCount count,
+                          void * unused);
+RemixCount _remix_pcm_mult (RemixPCM * src, RemixPCM * dest, RemixCount count,
+                           void * unused);
+RemixCount _remix_pcm_fade (RemixPCM * src, RemixPCM * dest, RemixCount count,
+                           void * unused);
+RemixCount _remix_pcm_interleave_2 (RemixPCM * src1, RemixPCM * src2,
+                                   RemixCount count, void * data);
+RemixCount _remix_pcm_deinterleave_2 (RemixPCM * dest1, RemixPCM * dest2,
+                                     RemixCount count, void * data);
+RemixCount _remix_pcm_blend (RemixPCM * src, RemixPCM * blend, RemixPCM * dest,
+                            RemixCount count, void * unused);
+RemixCount _remix_pcm_write_linear (RemixPCM * data, RemixCount x1,
+                                   RemixPCM y1, RemixCount x2, RemixPCM y2,
+                                   RemixCount offset, RemixCount count);
+
+#endif /* defined(__REMIX__) */
+
+#endif /* __REMIX_PLUGIN_H__ */
diff --git a/include/remix/remix_stream.h b/include/remix/remix_stream.h
new file mode 100644 (file)
index 0000000..893736a
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ * Copyright (C) 2003 Conrad Parker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#ifndef __REMIX_STREAM_H__
+#define __REMIX_STREAM_H__
+
+/** \file
+ *
+ * The abstraction of multichannel audio data in libremix is known as a
+ * stream.
+ * A stream may consist of multiple channels, each of which can consist
+ * of an arbitrary number of sparsely placed chunks of raw audio data.
+ * The channels are named with spatial names such as LEFT, RIGHT and CENTRE
+ * as required for common home, studio and theatre environments.
+ *
+ * \image html streams.png
+ * \image latex streams.eps "Inside a Remix stream" width=10cm
+ *
+ * Generic routines are provided for mixing, multiplying and blending
+ * streams of data.
+ *
+ */
+
+#include <remix/remix_types.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Streams */
+RemixStream * remix_stream_new (RemixEnv * env);
+RemixStream * remix_stream_new_contiguous (RemixEnv * env, RemixCount length);
+RemixStream * remix_stream_new_from_buffers (RemixEnv * env, RemixCount length,
+                                            RemixPCM ** buffers);
+RemixCount remix_stream_nr_channels (RemixEnv * env, RemixStream * stream);
+RemixChannel * remix_stream_find_channel (RemixEnv * env,
+                                         RemixStream * stream, int name);
+RemixChannel * remix_stream_add_channel (RemixEnv * env,
+                                        RemixStream * stream, int name);
+RemixStream * remix_stream_remove_channel (RemixEnv * env,
+                                          RemixStream * stream, int name);
+RemixStream * remix_stream_add_chunks (RemixEnv * env, RemixStream * stream,
+                                      RemixCount offset, RemixCount length);
+
+RemixCount remix_stream_write0 (RemixEnv * env, RemixStream * stream,
+                               RemixCount count);
+RemixCount remix_stream_write (RemixEnv * env, RemixStream * stream,
+                              RemixCount count, RemixStream * data);
+RemixCount remix_stream_copy (RemixEnv * env, RemixStream * src,
+                             RemixStream * dest, RemixCount count);
+RemixCount remix_stream_gain (RemixEnv * env, RemixStream * stream,
+                             RemixCount count, RemixPCM gain);
+RemixCount remix_stream_mix (RemixEnv * env, RemixStream * src,
+                            RemixStream * dest, RemixCount count);
+RemixCount remix_stream_mult (RemixEnv * env, RemixStream * src,
+                             RemixStream * dest, RemixCount count);
+RemixCount remix_streams_mix (RemixEnv * env, CDList * streams,
+                             RemixStream * dest, RemixCount count);
+RemixCount remix_stream_fade (RemixEnv * env, RemixStream * src,
+                             RemixStream * dest, RemixCount count);
+RemixCount remix_stream_blend (RemixEnv * env, RemixStream * src,
+                              RemixStream * dest,
+                              RemixStream * blend, RemixCount count);
+
+RemixCount remix_stream_interleave_2 (RemixEnv * env, RemixStream * stream,
+                                     int name1, int name2,
+                                     RemixPCM * dest, RemixCount count);
+RemixCount remix_stream_deinterleave_2 (RemixEnv * env, RemixStream * stream,
+                                       int name1, int name2,
+                                       RemixPCM * src, RemixCount count);
+
+/* Chunks */
+int remix_chunk_later (RemixEnv * env, RemixChunk * u1, RemixChunk * u2);
+RemixCount remix_chunk_clear (RemixEnv * env, RemixChunk * chunk);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __REMIX_STREAM_H__ */
diff --git a/include/remix/remix_time.h b/include/remix/remix_time.h
new file mode 100644 (file)
index 0000000..2ec5ba4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ * Copyright (C) 2003 Conrad Parker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/** \file
+ * Base types and public interfaces to libremix
+ *
+ */
+
+/*
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#ifndef __REMIX_TIME_H__
+#define __REMIX_TIME_H__
+
+#include <remix/remix_types.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Time */
+RemixTime remix_time_convert (RemixEnv * env, RemixTime time,
+                             RemixTimeType old_type, RemixTimeType new_type);
+RemixTime remix_time_zero (RemixTimeType type);
+RemixTime remix_time_invalid (RemixTimeType type);
+int remix_time_is_invalid (RemixTimeType type, RemixTime time);
+RemixTime remix_time_add (RemixTimeType type, RemixTime t1, RemixTime t2);
+RemixTime remix_time_sub (RemixTimeType type, RemixTime t1, RemixTime t2);
+RemixTime remix_time_min (RemixTimeType type, RemixTime t1, RemixTime t2);
+RemixTime remix_time_max (RemixTimeType type, RemixTime t1, RemixTime t2);
+int remix_time_eq (RemixTimeType type, RemixTime t1, RemixTime t2);
+int remix_time_gt (RemixTimeType type, RemixTime t1, RemixTime t2);
+int remix_time_lt (RemixTimeType type, RemixTime t1, RemixTime t2);
+int remix_time_ge (RemixTimeType type, RemixTime t1, RemixTime t2);
+int remix_time_le (RemixTimeType type, RemixTime t1, RemixTime t2);
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __REMIX_TIME_H__ */
diff --git a/include/remix/remix_types.h b/include/remix/remix_types.h
new file mode 100644 (file)
index 0000000..52e733a
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ * Copyright (C) 2003 Conrad Parker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/** \file
+ * Base types and public interfaces to libremix
+ *
+ */
+
+/*
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#ifndef __REMIX_TYPES_H__
+#define __REMIX_TYPES_H__
+
+#include <limits.h>
+
+#include "ctxdata.h"
+
+#define RemixNone NULL
+
+typedef int RemixError;
+
+typedef float RemixPCM;
+
+typedef long RemixCount;
+#define REMIX_COUNT_MAX (LONG_MAX - 1L)
+#define REMIX_COUNT_MIN LONG_MIN
+#define REMIX_COUNT_INFINITE REMIX_COUNT_MAX
+
+//TODO xxx : Change this
+typedef struct _RemixOpaque RemixOpaque;
+
+#if defined (__REMIX__)
+typedef struct _RemixBase RemixBase;
+#else
+typedef RemixOpaque RemixBase;
+#endif
+
+//TODO xxx : Change this
+struct _RemixOpaque {
+  void * instance_data;
+};
+
+typedef CDScalar RemixParameter;
+
+typedef int RemixFlags;
+typedef double RemixSamplerate;
+typedef double RemixTempo;
+typedef union _RemixTime RemixTime;
+
+
+/* Errors */
+#define REMIX_ERROR_OK              0
+#define REMIX_ERROR_INVALID         1
+#define REMIX_ERROR_NOENTITY        2
+#define REMIX_ERROR_EXISTS          3
+#define REMIX_ERROR_SILENCE         4
+#define REMIX_ERROR_NOOP            5
+#define REMIX_ERROR_SYSTEM          6
+
+typedef enum {
+  REMIX_CHANNEL_LEFT,
+  REMIX_CHANNEL_RIGHT,
+  REMIX_CHANNEL_CENTRE,
+  REMIX_CHANNEL_REAR,
+  REMIX_CHANNEL_REAR_LEFT,
+  REMIX_CHANNEL_REAR_RIGHT,
+  REMIX_CHANNEL_REAR_CENTRE,
+  REMIX_CHANNEL_LFE /* Low Frequency Effects */
+} RemixChannelName;
+
+typedef enum {
+  REMIX_TIME_INVALID,
+  REMIX_TIME_SAMPLES,
+  REMIX_TIME_SECONDS,
+  REMIX_TIME_BEAT24S
+} RemixTimeType;
+
+/* Envelope types */
+typedef enum {
+  REMIX_ENVELOPE_LINEAR,
+  REMIX_ENVELOPE_SPLINE
+} RemixEnvelopeType;
+
+union _RemixTime {
+  long TIME;
+  RemixCount samples;
+  float seconds;
+  int beat24s;
+};
+
+typedef enum {
+  REMIX_TYPE_BOOL = 0,
+  REMIX_TYPE_INT,
+  REMIX_TYPE_FLOAT,
+  REMIX_TYPE_STRING,
+  REMIX_TYPE_BASE
+} RemixParameterType;
+
+typedef enum {
+  REMIX_CONSTRAINT_TYPE_NONE = 0,
+  REMIX_CONSTRAINT_TYPE_LIST,
+  REMIX_CONSTRAINT_TYPE_RANGE
+} RemixConstraintType;
+
+
+#define REMIX_RANGE_LOWER_BOUND_VALID (1<<0)
+#define REMIX_RANGE_UPPER_BOUND_VALID (1<<1)
+#define REMIX_RANGE_STEP_VALID        (1<<2)
+#define REMIX_RANGE_ALL_VALID (REMIX_RANGE_LOWER_BOUND_VALID | \
+                              REMIX_RANGE_UPPER_BOUND_VALID | \
+                              REMIX_RANGE_STEP_VALID)
+
+#define REMIX_HINT_DEFAULT  (0)
+#define REMIX_HINT_LOG      (1<<0)
+#define REMIX_HINT_TIME     (1<<1)
+#define REMIX_HINT_FILENAME (1<<2)
+#define REMIX_HINT_CHANNEL (1<<3)
+
+#define REMIX_CONSTRAINT_EMPTY ((RemixConstraint){NULL})
+
+#define REMIX_SAMPLES(x) ((RemixTime){(RemixCount)(x)})
+#define REMIX_SECONDS(x) ((RemixTime){(float)(x)})
+#define REMIX_BEAT24S(x) ((RemixTime){(int)(x)})
+
+
+#if (defined(__REMIX__) || defined(__REMIX_PLUGIN__))
+#include <remix/remix_plugin.h>
+#else
+typedef RemixOpaque RemixEnv;
+typedef RemixOpaque RemixPoint;
+typedef RemixOpaque RemixEnvelope;
+typedef RemixOpaque RemixChunk;
+typedef RemixOpaque RemixChannel;
+typedef RemixOpaque RemixStream;
+typedef RemixOpaque RemixDeck;
+typedef RemixOpaque RemixTrack;
+typedef RemixOpaque RemixLayer;
+typedef RemixOpaque RemixSound;
+typedef RemixOpaque RemixMetaAuthor;
+typedef RemixOpaque RemixMetaText;
+typedef RemixOpaque RemixPlugin;
+typedef RemixOpaque RemixSquareTone;
+typedef RemixOpaque RemixMonitor;
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __REMIX_TYPES_H__ */
diff --git a/ltconfig b/ltconfig
new file mode 100755 (executable)
index 0000000..65ec6f6
--- /dev/null
+++ b/ltconfig
@@ -0,0 +1,3017 @@
+#! /bin/sh
+
+# ltconfig - Create a system-specific libtool.
+# Copyright (C) 1996-1999 Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# A lot of this script is taken from autoconf-2.10.
+
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+echo=echo
+if test "X$1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X$1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+  # Yippee, $echo works!
+  :
+else
+  # Restart under the correct shell.
+  exec "$SHELL" "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<EOF
+$*
+EOF
+  exit 0
+fi
+
+# Find the correct PATH separator.  Usually this is `:', but
+# DJGPP uses `;' like DOS.
+if test "X${PATH_SEPARATOR+set}" != "Xset"; then
+  UNAME=${UNAME-`uname 2>/dev/null`}
+  case X$UNAME in
+    *-DOS) PATH_SEPARATOR=';' ;;
+    *)     PATH_SEPARATOR=':' ;;
+  esac
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi
+
+if test "X${echo_test_string+set}" != "Xset"; then
+  # find a string as large as possible, as long as the shell can cope with it
+  for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
+    # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+    if (echo_test_string="`eval $cmd`") 2>/dev/null &&
+       echo_test_string="`eval $cmd`" &&
+       (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null; then
+      break
+    fi
+  done
+fi
+
+if test "X`($echo '\t') 2>/dev/null`" != 'X\t' ||
+   test "X`($echo "$echo_test_string") 2>/dev/null`" != X"$echo_test_string"; then
+  # The Solaris, AIX, and Digital Unix default echo programs unquote
+  # backslashes.  This makes it impossible to quote backslashes using
+  #   echo "$something" | sed 's/\\/\\\\/g'
+  #
+  # So, first we look for a working echo in the user's PATH.
+
+  IFS="${IFS=  }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
+  for dir in $PATH /usr/ucb; do
+    if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+       test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+       test "X`($dir/echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
+      echo="$dir/echo"
+      break
+    fi
+  done
+  IFS="$save_ifs"
+
+  if test "X$echo" = Xecho; then
+    # We didn't find a better echo, so look for alternatives.
+    if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+       test "X`(print -r "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
+      # This shell has a builtin print -r that does the trick.
+      echo='print -r'
+    elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+        test "X$CONFIG_SHELL" != X/bin/ksh; then
+      # If we have ksh, try running ltconfig again with it.
+      ORIGINAL_CONFIG_SHELL="${CONFIG_SHELL-/bin/sh}"
+      export ORIGINAL_CONFIG_SHELL
+      CONFIG_SHELL=/bin/ksh
+      export CONFIG_SHELL
+      exec "$CONFIG_SHELL" "$0" --no-reexec ${1+"$@"}
+    else
+      # Try using printf.
+      echo='printf "%s\n"'
+      if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+        test "X`($echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
+       # Cool, printf works
+       :
+      elif test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' &&
+          test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
+       CONFIG_SHELL="$ORIGINAL_CONFIG_SHELL"
+       export CONFIG_SHELL
+       SHELL="$CONFIG_SHELL"
+       export SHELL
+       echo="$CONFIG_SHELL $0 --fallback-echo"
+      elif test "X`("$CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' &&
+          test "X`("$CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
+       echo="$CONFIG_SHELL $0 --fallback-echo"
+      else
+       # maybe with a smaller string...
+       prev=:
+
+       for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
+         if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null; then
+           break
+         fi
+         prev="$cmd"
+       done
+
+       if test "$prev" != 'sed 50q "$0"'; then
+         echo_test_string=`eval $prev`
+         export echo_test_string
+         exec "${ORIGINAL_CONFIG_SHELL}" "$0" ${1+"$@"}
+       else
+         # Oops.  We lost completely, so just stick with echo.
+         echo=echo
+       fi
+      fi
+    fi
+  fi
+fi
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e s/^X//'
+sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# The name of this program.
+progname=`$echo "X$0" | $Xsed -e 's%^.*/%%'`
+
+# Constants:
+PROGRAM=ltconfig
+PACKAGE=libtool
+VERSION=1.3.3
+TIMESTAMP=" (1.385.2.181 1999/07/02 15:49:11)"
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.c 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.c $LIBS 1>&5'
+rm="rm -f"
+
+help="Try \`$progname --help' for more information."
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+enable_shared=yes
+# All known linkers require a `.a' archive for static linking (except M$VC,
+# which needs '.lib').
+enable_static=yes
+enable_fast_install=yes
+enable_dlopen=unknown
+enable_win32_dll=no
+ltmain=
+silent=
+srcdir=
+ac_config_guess=
+ac_config_sub=
+host=
+nonopt=
+ofile="$default_ofile"
+verify_host=yes
+with_gcc=no
+with_gnu_ld=no
+need_locks=yes
+ac_ext=c
+objext=o
+libext=a
+exeext=
+cache_file=
+
+old_AR="$AR"
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+old_CPPFLAGS="$CPPFLAGS"
+old_LDFLAGS="$LDFLAGS"
+old_LD="$LD"
+old_LN_S="$LN_S"
+old_LIBS="$LIBS"
+old_NM="$NM"
+old_RANLIB="$RANLIB"
+old_DLLTOOL="$DLLTOOL"
+old_OBJDUMP="$OBJDUMP"
+old_AS="$AS"
+
+# Parse the command line options.
+args=
+prev=
+for option
+do
+  case "$option" in
+  -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) optarg= ;;
+  esac
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$prev"; then
+    eval "$prev=\$option"
+    prev=
+    continue
+  fi
+
+  case "$option" in
+  --help) cat <<EOM
+Usage: $progname [OPTION]... [HOST [LTMAIN]]
+
+Generate a system-specific libtool script.
+
+    --debug                enable verbose shell tracing
+    --disable-shared       do not build shared libraries
+    --disable-static       do not build static libraries
+    --disable-fast-install do not optimize for fast installation
+    --enable-dlopen        enable dlopen support
+    --enable-win32-dll     enable building dlls on win32 hosts
+    --help                 display this help and exit
+    --no-verify            do not verify that HOST is a valid host type
+-o, --output=FILE          specify the output file [default=$default_ofile]
+    --quiet                same as \`--silent'
+    --silent               do not print informational messages
+    --srcdir=DIR           find \`config.guess' in DIR
+    --version              output version information and exit
+    --with-gcc             assume that the GNU C compiler will be used
+    --with-gnu-ld          assume that the C compiler uses the GNU linker
+    --disable-lock         disable file locking
+    --cache-file=FILE      configure cache file
+
+LTMAIN is the \`ltmain.sh' shell script fragment or \`ltmain.c' program
+that provides basic libtool functionality.
+
+HOST is the canonical host system name [default=guessed].
+EOM
+  exit 0
+  ;;
+
+  --debug)
+    echo "$progname: enabling shell trace mode"
+    set -x
+    ;;
+
+  --disable-shared) enable_shared=no ;;
+
+  --disable-static) enable_static=no ;;
+
+  --disable-fast-install) enable_fast_install=no ;;
+
+  --enable-dlopen) enable_dlopen=yes ;;
+
+  --enable-win32-dll) enable_win32_dll=yes ;;
+
+  --quiet | --silent) silent=yes ;;
+
+  --srcdir) prev=srcdir ;;
+  --srcdir=*) srcdir="$optarg" ;;
+
+  --no-verify) verify_host=no ;;
+
+  --output | -o) prev=ofile ;;
+  --output=*) ofile="$optarg" ;;
+
+  --version) echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"; exit 0 ;;
+
+  --with-gcc) with_gcc=yes ;;
+  --with-gnu-ld) with_gnu_ld=yes ;;
+
+  --disable-lock) need_locks=no ;;
+
+  --cache-file=*) cache_file="$optarg" ;;
+
+  -*)
+    echo "$progname: unrecognized option \`$option'" 1>&2
+    echo "$help" 1>&2
+    exit 1
+    ;;
+
+  *)
+    if test -z "$ltmain"; then
+      ltmain="$option"
+    elif test -z "$host"; then
+# This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1
+#      if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then
+#        echo "$progname: warning \`$option' is not a valid host type" 1>&2
+#      fi
+      host="$option"
+    else
+      echo "$progname: too many arguments" 1>&2
+      echo "$help" 1>&2
+      exit 1
+    fi ;;
+  esac
+done
+
+if test -z "$ltmain"; then
+  echo "$progname: you must specify a LTMAIN file" 1>&2
+  echo "$help" 1>&2
+  exit 1
+fi
+
+if test ! -f "$ltmain"; then
+  echo "$progname: \`$ltmain' does not exist" 1>&2
+  echo "$help" 1>&2
+  exit 1
+fi
+
+# Quote any args containing shell metacharacters.
+ltconfig_args=
+for arg
+do
+  case "$arg" in
+  *" "*|*"     "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ltconfig_args="$ltconfig_args '$arg'" ;;
+  *) ltconfig_args="$ltconfig_args $arg" ;;
+  esac
+done
+
+# A relevant subset of AC_INIT.
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 5 compiler messages saved in config.log
+# 6 checking for... messages and results
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>>./config.log
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+
+if test -n "$cache_file" && test -r "$cache_file"; then
+  echo "loading cache $cache_file within ltconfig"
+  . $cache_file
+fi
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='       '
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+if test -z "$srcdir"; then
+  # Assume the source directory is the same one as the path to LTMAIN.
+  srcdir=`$echo "X$ltmain" | $Xsed -e 's%/[^/]*$%%'`
+  test "$srcdir" = "$ltmain" && srcdir=.
+fi
+
+trap "$rm conftest*; exit 1" 1 2 15
+if test "$verify_host" = yes; then
+  # Check for config.guess and config.sub.
+  ac_aux_dir=
+  for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+    if test -f $ac_dir/config.guess; then
+      ac_aux_dir=$ac_dir
+      break
+    fi
+  done
+  if test -z "$ac_aux_dir"; then
+    echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2
+    echo "$help" 1>&2
+    exit 1
+  fi
+  ac_config_guess=$ac_aux_dir/config.guess
+  ac_config_sub=$ac_aux_dir/config.sub
+
+  # Make sure we can run config.sub.
+  if $SHELL $ac_config_sub sun4 >/dev/null 2>&1; then :
+  else
+    echo "$progname: cannot run $ac_config_sub" 1>&2
+    echo "$help" 1>&2
+    exit 1
+  fi
+
+  echo $ac_n "checking host system type""... $ac_c" 1>&6
+
+  host_alias=$host
+  case "$host_alias" in
+  "")
+    if host_alias=`$SHELL $ac_config_guess`; then :
+    else
+      echo "$progname: cannot guess host type; you must specify one" 1>&2
+      echo "$help" 1>&2
+      exit 1
+    fi ;;
+  esac
+  host=`$SHELL $ac_config_sub $host_alias`
+  echo "$ac_t$host" 1>&6
+
+  # Make sure the host verified.
+  test -z "$host" && exit 1
+
+elif test -z "$host"; then
+  echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2
+  echo "$help" 1>&2
+  exit 1
+else
+  host_alias=$host
+fi
+
+# Transform linux* to *-*-linux-gnu*, to support old configure scripts.
+case "$host_os" in
+linux-gnu*) ;;
+linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'`
+esac
+
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+case "$host_os" in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "${COLLECT_NAMES+set}" != set; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR cru $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+# Set a sane default for `AR'.
+test -z "$AR" && AR=ar
+
+# Set a sane default for `OBJDUMP'.
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+# If RANLIB is not set, then run the test.
+if test "${RANLIB+set}" != "set"; then
+  result=no
+
+  echo $ac_n "checking for ranlib... $ac_c" 1>&6
+  IFS="${IFS=  }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
+  for dir in $PATH; do
+    test -z "$dir" && dir=.
+    if test -f $dir/ranlib || test -f $dir/ranlib$ac_exeext; then
+      RANLIB="ranlib"
+      result="ranlib"
+      break
+    fi
+  done
+  IFS="$save_ifs"
+
+  echo "$ac_t$result" 1>&6
+fi
+
+if test -n "$RANLIB"; then
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+  old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
+fi
+
+# Set sane defaults for `DLLTOOL', `OBJDUMP', and `AS', used on cygwin.
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$AS" && AS=as
+
+# Check to see if we are using GCC.
+if test "$with_gcc" != yes || test -z "$CC"; then
+  # If CC is not set, then try to find GCC or a usable CC.
+  if test -z "$CC"; then
+    echo $ac_n "checking for gcc... $ac_c" 1>&6
+    IFS="${IFS=        }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
+    for dir in $PATH; do
+      test -z "$dir" && dir=.
+      if test -f $dir/gcc || test -f $dir/gcc$ac_exeext; then
+       CC="gcc"
+       break
+      fi
+    done
+    IFS="$save_ifs"
+
+    if test -n "$CC"; then
+      echo "$ac_t$CC" 1>&6
+    else
+      echo "$ac_t"no 1>&6
+    fi
+  fi
+
+  # Not "gcc", so try "cc", rejecting "/usr/ucb/cc".
+  if test -z "$CC"; then
+    echo $ac_n "checking for cc... $ac_c" 1>&6
+    IFS="${IFS=        }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
+    cc_rejected=no
+    for dir in $PATH; do
+      test -z "$dir" && dir=.
+      if test -f $dir/cc || test -f $dir/cc$ac_exeext; then
+       if test "$dir/cc" = "/usr/ucb/cc"; then
+         cc_rejected=yes
+         continue
+       fi
+       CC="cc"
+       break
+      fi
+    done
+    IFS="$save_ifs"
+    if test $cc_rejected = yes; then
+      # We found a bogon in the path, so make sure we never use it.
+      set dummy $CC
+      shift
+      if test $# -gt 0; then
+       # We chose a different compiler from the bogus one.
+       # However, it has the same name, so the bogon will be chosen
+       # first if we set CC to just the name; use the full file name.
+       shift
+       set dummy "$dir/cc" "$@"
+       shift
+       CC="$@"
+      fi
+    fi
+
+    if test -n "$CC"; then
+      echo "$ac_t$CC" 1>&6
+    else
+      echo "$ac_t"no 1>&6
+    fi
+
+    if test -z "$CC"; then
+      echo "$progname: error: no acceptable cc found in \$PATH" 1>&2
+      exit 1
+    fi
+  fi
+
+  # Now see if the compiler is really GCC.
+  with_gcc=no
+  echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6
+  echo "$progname:581: checking whether we are using GNU C" >&5
+
+  $rm conftest.c
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+  if { ac_try='${CC-cc} -E conftest.c'; { (eval echo $progname:589: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+    with_gcc=yes
+  fi
+  $rm conftest.c
+  echo "$ac_t$with_gcc" 1>&6
+fi
+
+# Allow CC to be a program name with arguments.
+set dummy $CC
+compiler="$2"
+
+echo $ac_n "checking for object suffix... $ac_c" 1>&6
+$rm conftest*
+echo 'int i = 1;' > conftest.c
+echo "$progname:603: checking for object suffix" >& 5
+if { (eval echo $progname:604: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; }; then
+  # Append any warnings to the config.log.
+  cat conftest.err 1>&5
+
+  for ac_file in conftest.*; do
+    case $ac_file in
+    *.c) ;;
+    *) objext=`echo $ac_file | sed -e s/conftest.//` ;;
+    esac
+  done
+else
+  cat conftest.err 1>&5
+  echo "$progname: failed program was:" >&5
+  cat conftest.c >&5
+fi
+$rm conftest*
+echo "$ac_t$objext" 1>&6
+
+echo $ac_n "checking for executable suffix... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_exeext="no"
+  $rm conftest*
+  echo 'main () { return 0; }' > conftest.c
+  echo "$progname:629: checking for executable suffix" >& 5
+  if { (eval echo $progname:630: \"$ac_link\") 1>&5; (eval $ac_link) 2>conftest.err; }; then
+    # Append any warnings to the config.log.
+    cat conftest.err 1>&5
+
+    for ac_file in conftest.*; do
+      case $ac_file in
+      *.c | *.err | *.$objext ) ;;
+      *) ac_cv_exeext=.`echo $ac_file | sed -e s/conftest.//` ;;
+      esac
+    done
+  else
+    cat conftest.err 1>&5
+    echo "$progname: failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  $rm conftest*
+fi
+if test "X$ac_cv_exeext" = Xno; then
+  exeext=""
+else
+  exeext="$ac_cv_exeext"
+fi
+echo "$ac_t$ac_cv_exeext" 1>&6
+
+echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6
+pic_flag=
+special_shlib_compile_flags=
+wl=
+link_static_flag=
+no_builtin_flag=
+
+if test "$with_gcc" = yes; then
+  wl='-Wl,'
+  link_static_flag='-static'
+
+  case "$host_os" in
+  beos* | irix5* | irix6* | osf3* | osf4*)
+    # PIC is the default for these OSes.
+    ;;
+  aix*)
+    # Below there is a dirty hack to force normal static linking with -ldl
+    # The problem is because libdl dynamically linked with both libc and
+    # libC (AIX C++ library), which obviously doesn't included in libraries
+    # list by gcc. This cause undefined symbols with -static flags.
+    # This hack allows C programs to be linked with "-static -ldl", but
+    # we not sure about C++ programs.
+    link_static_flag="$link_static_flag ${wl}-lC"
+    ;;
+  cygwin* | mingw* | os2*)
+    # We can build DLLs from non-PIC.
+    ;;
+  amigaos*)
+    # FIXME: we need at least 68020 code to build shared libraries, but
+    # adding the `-m68020' flag to GCC prevents building anything better,
+    # like `-m68040'.
+    pic_flag='-m68020 -resident32 -malways-restore-a4'
+    ;;
+  sysv4*MP*)
+    if test -d /usr/nec; then
+       pic_flag=-Kconform_pic
+    fi
+    ;;
+  *)
+    pic_flag='-fPIC'
+    ;;
+  esac
+else
+  # PORTME Check for PIC flags for the system compiler.
+  case "$host_os" in
+  aix3* | aix4*)
+    # All AIX code is PIC.
+    link_static_flag='-bnso -bI:/lib/syscalls.exp'
+    ;;
+
+  hpux9* | hpux10* | hpux11*)
+    # Is there a better link_static_flag that works with the bundled CC?
+    wl='-Wl,'
+    link_static_flag="${wl}-a ${wl}archive"
+    pic_flag='+Z'
+    ;;
+
+  irix5* | irix6*)
+    wl='-Wl,'
+    link_static_flag='-non_shared'
+    # PIC (with -KPIC) is the default.
+    ;;
+
+  cygwin* | mingw* | os2*)
+    # We can build DLLs from non-PIC.
+    ;;
+
+  osf3* | osf4*)
+    # All OSF/1 code is PIC.
+    wl='-Wl,'
+    link_static_flag='-non_shared'
+    ;;
+
+  sco3.2v5*)
+    pic_flag='-Kpic'
+    link_static_flag='-dn'
+    special_shlib_compile_flags='-belf'
+    ;;
+
+  solaris*)
+    pic_flag='-KPIC'
+    link_static_flag='-Bstatic'
+    wl='-Wl,'
+    ;;
+
+  sunos4*)
+    pic_flag='-PIC'
+    link_static_flag='-Bstatic'
+    wl='-Qoption ld '
+    ;;
+
+  sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+    pic_flag='-KPIC'
+    link_static_flag='-Bstatic'
+    wl='-Wl,'
+    ;;
+
+  uts4*)
+    pic_flag='-pic'
+    link_static_flag='-Bstatic'
+    ;;
+  sysv4*MP*)
+    if test -d /usr/nec ;then
+      pic_flag='-Kconform_pic'
+      link_static_flag='-Bstatic'
+    fi
+    ;;
+  *)
+    can_build_shared=no
+    ;;
+  esac
+fi
+
+if test -n "$pic_flag"; then
+  echo "$ac_t$pic_flag" 1>&6
+
+  # Check to make sure the pic_flag actually works.
+  echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6
+  $rm conftest*
+  echo "int some_variable = 0;" > conftest.c
+  save_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS $pic_flag -DPIC"
+  echo "$progname:776: checking if $compiler PIC flag $pic_flag works" >&5
+  if { (eval echo $progname:777: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.$objext; then
+    # Append any warnings to the config.log.
+    cat conftest.err 1>&5
+    
+    case "$host_os" in
+    hpux9* | hpux10* | hpux11*)
+      # On HP-UX, both CC and GCC only warn that PIC is supported... then they
+      # create non-PIC objects.  So, if there were any warnings, we assume that
+      # PIC is not supported.
+      if test -s conftest.err; then
+       echo "$ac_t"no 1>&6
+       can_build_shared=no
+       pic_flag=
+      else
+       echo "$ac_t"yes 1>&6
+       pic_flag=" $pic_flag"
+      fi
+      ;;
+    *)
+      echo "$ac_t"yes 1>&6
+      pic_flag=" $pic_flag"
+      ;;
+    esac
+  else
+    # Append any errors to the config.log.
+    cat conftest.err 1>&5
+    can_build_shared=no
+    pic_flag=
+    echo "$ac_t"no 1>&6
+  fi
+  CFLAGS="$save_CFLAGS"
+  $rm conftest*
+else
+  echo "$ac_t"none 1>&6
+fi
+
+# Check to see if options -o and -c are simultaneously supported by compiler
+echo $ac_n "checking if $compiler supports -c -o file.o... $ac_c" 1>&6
+$rm -r conftest 2>/dev/null
+mkdir conftest
+cd conftest
+$rm conftest*
+echo "int some_variable = 0;" > conftest.c
+mkdir out
+# According to Tom Tromey, Ian Lance Taylor reported there are C compilers
+# that will create temporary files in the current directory regardless of
+# the output directory.  Thus, making CWD read-only will cause this test
+# to fail, enabling locking or at least warning the user not to do parallel
+# builds.
+chmod -w .
+save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -o out/conftest2.o"
+echo "$progname:829: checking if $compiler supports -c -o file.o" >&5
+if { (eval echo $progname:830: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.o; then
+
+  # The compiler can only warn and ignore the option if not recognized
+  # So say no if there are warnings
+    if test -s out/conftest.err; then
+      echo "$ac_t"no 1>&6
+      compiler_c_o=no
+    else
+      echo "$ac_t"yes 1>&6
+      compiler_c_o=yes
+    fi
+else
+  # Append any errors to the config.log.
+  cat out/conftest.err 1>&5
+  compiler_c_o=no
+  echo "$ac_t"no 1>&6
+fi
+CFLAGS="$save_CFLAGS"
+chmod u+w .
+$rm conftest* out/*
+rmdir out
+cd ..
+rmdir conftest
+$rm -r conftest 2>/dev/null
+
+if test x"$compiler_c_o" = x"yes"; then
+  # Check to see if we can write to a .lo
+  echo $ac_n "checking if $compiler supports -c -o file.lo... $ac_c" 1>&6
+  $rm conftest*
+  echo "int some_variable = 0;" > conftest.c
+  save_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -c -o conftest.lo"
+  echo "$progname:862: checking if $compiler supports -c -o file.lo" >&5
+if { (eval echo $progname:863: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.lo; then
+
+    # The compiler can only warn and ignore the option if not recognized
+    # So say no if there are warnings
+      if test -s conftest.err; then
+       echo "$ac_t"no 1>&6
+       compiler_o_lo=no
+      else
+       echo "$ac_t"yes 1>&6
+       compiler_o_lo=yes
+      fi
+  else
+    # Append any errors to the config.log.
+    cat conftest.err 1>&5
+    compiler_o_lo=no
+    echo "$ac_t"no 1>&6
+  fi
+  CFLAGS="$save_CFLAGS"
+  $rm conftest*
+else
+  compiler_o_lo=no
+fi
+
+# Check to see if we can do hard links to lock some files if needed
+hard_links="nottested"
+if test "$compiler_c_o" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  echo $ac_n "checking if we can lock with hard links... $ac_c" 1>&6
+  hard_links=yes
+  $rm conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  echo "$ac_t$hard_links" 1>&6
+  $rm conftest*
+  if test "$hard_links" = no; then
+    echo "*** WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+if test "$with_gcc" = yes; then
+  # Check to see if options -fno-rtti -fno-exceptions are supported by compiler
+  echo $ac_n "checking if $compiler supports -fno-rtti -fno-exceptions ... $ac_c" 1>&6
+  $rm conftest*
+  echo "int some_variable = 0;" > conftest.c
+  save_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.c"
+  echo "$progname:914: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+  if { (eval echo $progname:915: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then
+
+    # The compiler can only warn and ignore the option if not recognized
+    # So say no if there are warnings
+      if test -s conftest.err; then
+       echo "$ac_t"no 1>&6
+       compiler_rtti_exceptions=no
+      else
+       echo "$ac_t"yes 1>&6
+       compiler_rtti_exceptions=yes
+      fi
+  else
+    # Append any errors to the config.log.
+    cat conftest.err 1>&5
+    compiler_rtti_exceptions=no
+    echo "$ac_t"no 1>&6
+  fi
+  CFLAGS="$save_CFLAGS"
+  $rm conftest*
+
+  if test "$compiler_rtti_exceptions" = "yes"; then
+    no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions'
+  else
+    no_builtin_flag=' -fno-builtin'
+  fi
+  
+fi
+
+# Check for any special shared library compilation flags.
+if test -n "$special_shlib_compile_flags"; then
+  echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2
+  if echo "$old_CC $old_CFLAGS " | egrep -e "[         ]$special_shlib_compile_flags[  ]" >/dev/null; then :
+  else
+    echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2
+    can_build_shared=no
+  fi
+fi
+
+echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6
+$rm conftest*
+echo 'main(){return(0);}' > conftest.c
+save_LDFLAGS="$LDFLAGS"
+LDFLAGS="$LDFLAGS $link_static_flag"
+echo "$progname:958: checking if $compiler static flag $link_static_flag works" >&5
+if { (eval echo $progname:959: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  echo "$ac_t$link_static_flag" 1>&6
+else
+  echo "$ac_t"none 1>&6
+  link_static_flag=
+fi
+LDFLAGS="$save_LDFLAGS"
+$rm conftest*
+
+if test -z "$LN_S"; then
+  # Check to see if we can use ln -s, or we need hard links.
+  echo $ac_n "checking whether ln -s works... $ac_c" 1>&6
+  $rm conftest.dat
+  if ln -s X conftest.dat 2>/dev/null; then
+    $rm conftest.dat
+    LN_S="ln -s"
+  else
+    LN_S=ln
+  fi
+  if test "$LN_S" = "ln -s"; then
+    echo "$ac_t"yes 1>&6
+  else
+    echo "$ac_t"no 1>&6
+  fi
+fi
+
+# Make sure LD is an absolute path.
+if test -z "$LD"; then
+  ac_prog=ld
+  if test "$with_gcc" = yes; then
+    # Check if gcc -print-prog-name=ld gives a path.
+    echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6
+    echo "$progname:991: checking for ld used by GCC" >&5
+    ac_prog=`($CC -print-prog-name=ld) 2>&5`
+    case "$ac_prog" in
+    # Accept absolute paths.
+    [\\/]* | [A-Za-z]:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the path of ld
+      ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+       ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+    "")
+      # If it fails, then pretend we are not using GCC.
+      ac_prog=ld
+      ;;
+    *)
+      # If it is relative, then search for the first ld in PATH.
+      with_gnu_ld=unknown
+      ;;
+    esac
+  elif test "$with_gnu_ld" = yes; then
+    echo $ac_n "checking for GNU ld... $ac_c" 1>&6
+    echo "$progname:1015: checking for GNU ld" >&5
+  else
+    echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6
+    echo "$progname:1018: checking for non-GNU ld" >&5
+  fi
+
+  if test -z "$LD"; then
+    IFS="${IFS=        }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
+    for ac_dir in $PATH; do
+      test -z "$ac_dir" && ac_dir=.
+      if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+       LD="$ac_dir/$ac_prog"
+       # Check to see if the program is GNU ld.  I'd rather use --version,
+       # but apparently some GNU ld's only accept -v.
+       # Break only if it was the GNU/non-GNU ld that we prefer.
+       if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
+         test "$with_gnu_ld" != no && break
+       else
+         test "$with_gnu_ld" != yes && break
+       fi
+      fi
+    done
+    IFS="$ac_save_ifs"
+  fi
+
+  if test -n "$LD"; then
+    echo "$ac_t$LD" 1>&6
+  else
+    echo "$ac_t"no 1>&6
+  fi
+
+  if test -z "$LD"; then
+    echo "$progname: error: no acceptable ld found in \$PATH" 1>&2
+    exit 1
+  fi
+fi
+
+# Check to see if it really is or is not GNU ld.
+echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6
+# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
+  with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+echo "$ac_t$with_gnu_ld" 1>&6
+
+# See if the linker supports building shared libraries.
+echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6
+
+allow_undefined_flag=
+no_undefined_flag=
+need_lib_prefix=unknown
+need_version=unknown
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+archive_cmds=
+archive_expsym_cmds=
+old_archive_from_new_cmds=
+export_dynamic_flag_spec=
+whole_archive_flag_spec=
+thread_safe_flag_spec=
+hardcode_libdir_flag_spec=
+hardcode_libdir_separator=
+hardcode_direct=no
+hardcode_minus_L=no
+hardcode_shlibpath_var=unsupported
+runpath_var=
+always_export_symbols=no
+export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols'
+# include_expsyms should be a list of space-separated symbols to be *always*
+# included in the symbol list
+include_expsyms=
+# exclude_expsyms can be an egrep regular expression of symbols to exclude
+# it will be wrapped by ` (' and `)$', so one must not match beginning or
+# end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+# as well as any symbol that contains `d'.
+exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
+# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+# platforms (ab)use it in PIC code, but their linkers get confused if
+# the symbol is explicitly referenced.  Since portable code cannot
+# rely on this symbol name, it's probably fine to never include it in
+# preloaded symbol tables.
+
+case "$host_os" in
+cygwin* | mingw*)
+  # FIXME: the MSVC++ port hasn't been tested in a loooong time
+  # When not using gcc, we currently assume that we are using
+  # Microsoft Visual C++.
+  if test "$with_gcc" != yes; then
+    with_gnu_ld=no
+  fi
+  ;;
+
+esac
+
+ld_shlibs=yes
+if test "$with_gnu_ld" = yes; then
+  # If archive_cmds runs LD, not CC, wlarc should be empty
+  wlarc='${wl}'
+
+  # See if GNU ld supports shared libraries.
+  case "$host_os" in
+  aix3* | aix4*)
+    # On AIX, the GNU linker is very broken
+    ld_shlibs=no
+    cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+    ;;
+
+  amigaos*)
+    archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)'
+    hardcode_libdir_flag_spec='-L$libdir'
+    hardcode_minus_L=yes
+
+    # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+    # that the semantics of dynamic libraries on AmigaOS, at least up
+    # to version 4, is to share data among multiple programs linked
+    # with the same dynamic library.  Since this doesn't match the
+    # behavior of shared libraries on other platforms, we can use
+    # them.
+    ld_shlibs=no
+    ;;
+
+  beos*)
+    if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+      allow_undefined_flag=unsupported
+      # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+      # support --undefined.  This deserves some investigation.  FIXME
+      archive_cmds='$CC -nostart $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib'
+    else
+      ld_shlibs=no
+    fi
+    ;;
+
+  cygwin* | mingw*)
+    # hardcode_libdir_flag_spec is actually meaningless, as there is
+    # no search path for DLLs.
+    hardcode_libdir_flag_spec='-L$libdir'
+    allow_undefined_flag=unsupported
+    always_export_symbols=yes
+
+    # Extract the symbol export list from an `--export-all' def file,
+    # then regenerate the def file from the symbol export list, so that
+    # the compiled dll only exports the symbol export list.
+    export_symbols_cmds='test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~
+      test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~
+      $DLLTOOL --export-all --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --output-def $objdir/$soname-def  $objdir/$soname-ltdll.$objext $libobjs $convenience~
+      sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]* ; *//" < $objdir/$soname-def > $export_symbols'
+
+    archive_expsym_cmds='echo EXPORTS > $objdir/$soname-def~
+      _lt_hint=1;
+      for symbol in `cat $export_symbols`; do
+       echo "  \$symbol @ \$_lt_hint ; " >> $objdir/$soname-def;
+       _lt_hint=`expr 1 + \$_lt_hint`;
+      done~
+      test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~
+      test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~
+      $CC -Wl,--base-file,$objdir/$soname-base -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~
+      $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~
+      $CC -Wl,--base-file,$objdir/$soname-base $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~
+      $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~
+      $CC $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts'
+
+      old_archive_from_new_cmds='$DLLTOOL --as=$AS --dllname $soname --def $objdir/$soname-def --output-lib $objdir/$libname.a' 
+    ;;
+
+  netbsd*)
+    if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+      archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib'
+      archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+    else
+      archive_cmds='$LD -Bshareable $libobjs $deplibs $linkopts -o $lib'
+      # can we support soname and/or expsyms with a.out? -oliva
+    fi
+    ;;
+
+  solaris*)
+    if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then
+      ld_shlibs=no
+      cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+    elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+      archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib'
+      archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+    else
+      ld_shlibs=no
+    fi
+    ;;      
+
+  sunos4*)
+    archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linkopts'
+    wlarc=
+    hardcode_direct=yes
+    hardcode_shlibpath_var=no
+    ;;
+
+  *)
+    if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+      archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib'
+      archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+    else
+      ld_shlibs=no
+    fi
+    ;;
+  esac
+
+  if test "$ld_shlibs" = yes; then
+    runpath_var=LD_RUN_PATH
+    hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
+    export_dynamic_flag_spec='${wl}--export-dynamic'
+    case $host_os in
+    cygwin* | mingw*)
+      # dlltool doesn't understand --whole-archive et. al.
+      whole_archive_flag_spec=
+      ;;
+    *)
+      whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+      ;;
+    esac
+  fi
+else
+  # PORTME fill in a description of your system's linker (not GNU ld)
+  case "$host_os" in
+  aix3*)
+    allow_undefined_flag=unsupported
+    always_export_symbols=yes
+    archive_expsym_cmds='$LD -o $objdir/$soname $libobjs $deplibs $linkopts -bE:$export_symbols -T512 -H512 -bM:SRE~$AR cru $lib $objdir/$soname'
+    # Note: this linker hardcodes the directories in LIBPATH if there
+    # are no directories specified by -L.
+    hardcode_minus_L=yes
+    if test "$with_gcc" = yes && test -z "$link_static_flag"; then
+      # Neither direct hardcoding nor static linking is supported with a
+      # broken collect2.
+      hardcode_direct=unsupported
+    fi
+    ;;
+
+  aix4*)
+    hardcode_libdir_flag_spec='${wl}-b ${wl}nolibpath ${wl}-b ${wl}libpath:$libdir:/usr/lib:/lib'
+    hardcode_libdir_separator=':'
+    if test "$with_gcc" = yes; then
+      collect2name=`${CC} -print-prog-name=collect2`
+      if test -f "$collect2name" && \
+        strings "$collect2name" | grep resolve_lib_name >/dev/null
+      then
+       # We have reworked collect2
+       hardcode_direct=yes
+      else
+       # We have old collect2
+       hardcode_direct=unsupported
+       # It fails to find uninstalled libraries when the uninstalled
+       # path is not listed in the libpath.  Setting hardcode_minus_L
+       # to unsupported forces relinking
+       hardcode_minus_L=yes
+       hardcode_libdir_flag_spec='-L$libdir'
+       hardcode_libdir_separator=
+      fi
+      shared_flag='-shared'
+    else
+      shared_flag='${wl}-bM:SRE'
+      hardcode_direct=yes
+    fi
+    allow_undefined_flag=' ${wl}-berok'
+    archive_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bexpall ${wl}-bnoentry${allow_undefined_flag}'
+    archive_expsym_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}'
+    case "$host_os" in aix4.[01]|aix4.[01].*)
+      # According to Greg Wooledge, -bexpall is only supported from AIX 4.2 on
+      always_export_symbols=yes ;;
+    esac
+   ;;
+
+  amigaos*)
+    archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)'
+    hardcode_libdir_flag_spec='-L$libdir'
+    hardcode_minus_L=yes
+    # see comment about different semantics on the GNU ld section
+    ld_shlibs=no
+    ;;
+
+  cygwin* | mingw*)
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    # hardcode_libdir_flag_spec is actually meaningless, as there is
+    # no search path for DLLs.
+    hardcode_libdir_flag_spec=' '
+    allow_undefined_flag=unsupported
+    # Tell ltmain to make .lib files, not .a files.
+    libext=lib
+    # FIXME: Setting linknames here is a bad hack.
+    archive_cmds='$CC -o $lib $libobjs $linkopts `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames='
+    # The linker will automatically build a .lib file if we build a DLL.
+    old_archive_from_new_cmds='true'
+    # FIXME: Should let the user specify the lib program.
+    old_archive_cmds='lib /OUT:$oldlib$oldobjs'
+    fix_srcfile_path='`cygpath -w $srcfile`'
+    ;;
+
+  freebsd1*)
+    ld_shlibs=no
+    ;;
+
+  # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+  # support.  Future versions do this automatically, but an explicit c++rt0.o
+  # does not break anything, and helps significantly (at the cost of a little
+  # extra space).
+  freebsd2.2*)
+    archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts /usr/lib/c++rt0.o'
+    hardcode_libdir_flag_spec='-R$libdir'
+    hardcode_direct=yes
+    hardcode_shlibpath_var=no
+    ;;
+
+  # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+  freebsd2*)
+    archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts'
+    hardcode_direct=yes
+    hardcode_minus_L=yes
+    hardcode_shlibpath_var=no
+    ;;
+
+  # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+  freebsd*)
+    archive_cmds='$CC -shared -o $lib $libobjs $deplibs $linkopts'
+    hardcode_libdir_flag_spec='-R$libdir'
+    hardcode_direct=yes
+    hardcode_shlibpath_var=no
+    ;;
+
+  hpux9* | hpux10* | hpux11*)
+    case "$host_os" in
+    hpux9*) archive_cmds='$rm $objdir/$soname~$LD -b +b $install_libdir -o $objdir/$soname $libobjs $deplibs $linkopts~test $objdir/$soname = $lib || mv $objdir/$soname $lib' ;;
+    *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linkopts' ;;
+    esac
+    hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+    hardcode_libdir_separator=:
+    hardcode_direct=yes
+    hardcode_minus_L=yes # Not in the search PATH, but as the default
+                        # location of the library.
+    export_dynamic_flag_spec='${wl}-E'
+    ;;
+
+  irix5* | irix6*)
+    if test "$with_gcc" = yes; then
+      archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+    else
+      archive_cmds='$LD -shared $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+    fi
+    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+    hardcode_libdir_separator=:
+    ;;
+
+  netbsd*)
+    if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts'  # a.out
+    else
+      archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linkopts'      # ELF
+    fi
+    hardcode_libdir_flag_spec='${wl}-R$libdir'
+    hardcode_direct=yes
+    hardcode_shlibpath_var=no
+    ;;
+
+  openbsd*)
+    archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts'
+    hardcode_libdir_flag_spec='-R$libdir'
+    hardcode_direct=yes
+    hardcode_shlibpath_var=no
+    ;;
+
+  os2*)
+    hardcode_libdir_flag_spec='-L$libdir'
+    hardcode_minus_L=yes
+    allow_undefined_flag=unsupported
+    archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def~$echo DATA >> $objdir/$libname.def~$echo " SINGLE NONSHARED" >> $objdir/$libname.def~$echo EXPORTS >> $objdir/$libname.def~emxexp $libobjs >> $objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $linkopts $objdir/$libname.def'
+    old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def'
+    ;;
+
+  osf3* | osf4*)
+    if test "$with_gcc" = yes; then
+      allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+      archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+    else
+      allow_undefined_flag=' -expect_unresolved \*'
+      archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+    fi
+    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+    hardcode_libdir_separator=:
+    ;;
+
+  sco3.2v5*)
+    archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
+    hardcode_shlibpath_var=no
+    runpath_var=LD_RUN_PATH
+    hardcode_runpath_var=yes
+    ;;
+
+  solaris*)
+    no_undefined_flag=' -z text'
+    # $CC -shared without GNU ld will not create a library from C++
+    # object files and a static libstdc++, better avoid it by now
+    archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts'
+    archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+               $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp'
+    hardcode_libdir_flag_spec='-R$libdir'
+    hardcode_shlibpath_var=no
+    case "$host_os" in
+    solaris2.[0-5] | solaris2.[0-5].*) ;;
+    *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+      whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;;
+    esac
+    ;;
+
+  sunos4*)
+    archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linkopts'
+    hardcode_libdir_flag_spec='-L$libdir'
+    hardcode_direct=yes
+    hardcode_minus_L=yes
+    hardcode_shlibpath_var=no
+    ;;
+
+  sysv4)
+    archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
+    runpath_var='LD_RUN_PATH'
+    hardcode_shlibpath_var=no
+    hardcode_direct=no #Motorola manual says yes, but my tests say they lie 
+    ;;  
+
+  sysv4.3*)
+    archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
+    hardcode_shlibpath_var=no
+    export_dynamic_flag_spec='-Bexport'
+    ;;
+
+  uts4*)
+    archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
+    hardcode_libdir_flag_spec='-L$libdir'
+    hardcode_shlibpath_var=no
+    ;;
+
+  dgux*)
+    archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
+    hardcode_libdir_flag_spec='-L$libdir'
+    hardcode_shlibpath_var=no
+    ;;
+
+  sysv4*MP*)
+    if test -d /usr/nec ;then
+    # archive_cmds='$LD -G -z text -h $soname -o $lib$libobjs$deplibs'
+    archive_cmds='$LD -G -h $soname -o $lib$libobjs$deplibs'
+    hardcode_shlibpath_var=no
+    runpath_var=LD_RUN_PATH
+    hardcode_runpath_var=yes
+    ld_shlibs=yes
+    fi
+    ;;
+
+  *)
+    ld_shlibs=no
+    ;;
+  esac
+fi
+echo "$ac_t$ld_shlibs" 1>&6
+test "$ld_shlibs" = no && can_build_shared=no
+
+if test -z "$NM"; then
+  echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6
+  case "$NM" in
+  [\\/]* | [A-Za-z]:[\\/]*) ;; # Let the user override the test with a path.
+  *)
+    IFS="${IFS=        }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
+    for ac_dir in $PATH /usr/ucb /usr/ccs/bin /bin; do
+      test -z "$ac_dir" && ac_dir=.
+      if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext; then
+       # Check to see if the nm accepts a BSD-compat flag.
+       # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+       #   nm: unknown option "B" ignored
+       if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+         NM="$ac_dir/nm -B"
+         break
+       elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+         NM="$ac_dir/nm -p"
+         break
+       else
+         NM=${NM="$ac_dir/nm"} # keep the first match, but
+         continue # so that we can try to find one that supports BSD flags
+       fi
+      fi
+    done
+    IFS="$ac_save_ifs"
+    test -z "$NM" && NM=nm
+    ;;
+  esac
+  echo "$ac_t$NM" 1>&6
+fi
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Transform the above into a raw symbol and a C symbol.
+symxfrm='\1 \2\3 \3'
+
+# Transform an extracted symbol line into a proper C declaration
+global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'"
+
+# Define system-specific variables.
+case "$host_os" in
+aix*)
+  symcode='[BCDT]'
+  ;;
+cygwin* | mingw*)
+  symcode='[ABCDGISTW]'
+  ;;
+hpux*) # Its linker distinguishes data from code symbols
+  global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^. .* \(.*\)$/extern char \1;/p'"
+  ;;
+irix*)
+  symcode='[BCDEGRST]'
+  ;;
+solaris*)
+  symcode='[BDT]'
+  ;;
+sysv4)
+  symcode='[DFNSTU]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then
+  symcode='[ABCDGISTW]'
+fi
+
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Write the raw and C identifiers.
+  global_symbol_pipe="sed -n -e 's/^.*[        ]\($symcode\)[  ][      ]*\($ac_symprfx\)$sympat$/$symxfrm/p'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+  $rm conftest*
+  cat > conftest.c <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+  echo "$progname:1592: checking if global_symbol_pipe works" >&5
+  if { (eval echo $progname:1593: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.$objext; then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if { echo "$progname:1596: eval \"$NM conftest.$objext | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.$objext | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then
+
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+       mv -f "$nlist"T "$nlist"
+      else
+       rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if egrep ' nm_test_var$' "$nlist" >/dev/null; then
+       if egrep ' nm_test_func$' "$nlist" >/dev/null; then
+         cat <<EOF > conftest.c
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+         # Now generate the symbol file.
+         eval "$global_symbol_to_cdecl"' < "$nlist" >> conftest.c'
+
+         cat <<EOF >> conftest.c
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+  const char *name;
+  lt_ptr_t address;
+}
+lt_preloaded_symbols[] =
+{
+EOF
+         sed 's/^. \(.*\) \(.*\)$/  {"\2", (lt_ptr_t) \&\2},/' < "$nlist" >> conftest.c
+         cat <<\EOF >> conftest.c
+  {0, (lt_ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+         # Now try linking the two files.
+         mv conftest.$objext conftstm.$objext
+         save_LIBS="$LIBS"
+         save_CFLAGS="$CFLAGS"
+         LIBS="conftstm.$objext"
+         CFLAGS="$CFLAGS$no_builtin_flag"
+         if { (eval echo $progname:1648: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+           pipe_works=yes
+         else
+           echo "$progname: failed program was:" >&5
+           cat conftest.c >&5
+         fi
+         LIBS="$save_LIBS"
+       else
+         echo "cannot find nm_test_func in $nlist" >&5
+       fi
+      else
+       echo "cannot find nm_test_var in $nlist" >&5
+      fi
+    else
+      echo "cannot run $global_symbol_pipe" >&5
+    fi
+  else
+    echo "$progname: failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  $rm conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    global_symbol_pipe=
+  fi
+done
+if test "$pipe_works" = yes; then
+  echo "${ac_t}ok" 1>&6
+else
+  echo "${ac_t}failed" 1>&6
+fi
+
+if test -z "$global_symbol_pipe"; then
+  global_symbol_to_cdecl=
+fi
+
+# Check hardcoding attributes.
+echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" || \
+   test -n "$runpath_var"; then
+
+  # We can hardcode non-existant directories.
+  if test "$hardcode_direct" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$hardcode_shlibpath_var" != no &&
+     test "$hardcode_minus_L" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action=unsupported
+fi
+echo "$ac_t$hardcode_action" 1>&6
+
+
+reload_flag=
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6
+# PORTME Some linkers may need a different reload flag.
+reload_flag='-r'
+echo "$ac_t$reload_flag" 1>&6
+test -n "$reload_flag" && reload_flag=" $reload_flag"
+
+# PORTME Fill in your ld.so characteristics
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+file_magic_cmd=
+file_magic_test_file=
+deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [regex]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given egrep regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6
+case "$host_os" in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}.so$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}.so$major'
+  ;;
+
+aix4*)
+  version_type=linux
+  # AIX has no versioning support, so currently we can not hardcode correct
+  # soname into executable. Probably we can add versioning support to
+  # collect2, so additional links can be useful in future.
+  # We preserve .a as extension for shared libraries though AIX4.2
+  # and later linker supports .so
+  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.a'
+  shlibpath_var=LIBPATH
+  deplibs_check_method=pass_all
+  ;;
+
+amigaos*)
+  library_names_spec='$libname.ixlibrary $libname.a'
+  # Create ${libname}_ixlibrary.a entries in /sys/libs.
+  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done'
+  ;;
+
+beos*)
+  library_names_spec='${libname}.so'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  deplibs_check_method=pass_all
+  lt_cv_dlopen="load_add_on"
+  lt_cv_dlopen_libs=
+  lt_cv_dlopen_self=yes
+  ;;
+
+bsdi4*)
+  version_type=linux
+  library_names_spec='${libname}.so$major ${libname}.so'
+  soname_spec='${libname}.so'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+  file_magic_cmd=/usr/bin/file
+  file_magic_test_file=/shlib/libc.so
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw*)
+  version_type=windows
+  need_version=no
+  need_lib_prefix=no
+  if test "$with_gcc" = yes; then
+    library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.a'
+  else
+    library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib'
+  fi
+  dynamic_linker='Win32 ld.exe'
+  deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+  file_magic_cmd='${OBJDUMP} -f'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  lt_cv_dlopen="LoadLibrary"
+  lt_cv_dlopen_libs=
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+  
+freebsd*)
+  objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+  version_type=freebsd-$objformat
+  case "$version_type" in
+    freebsd-elf*)
+      deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object'
+      file_magic_cmd=/usr/bin/file
+      file_magic_test_file=`echo /usr/lib/libc.so*`
+      library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      deplibs_check_method=unknown
+      library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix'
+      need_version=yes
+      ;;
+  esac
+  finish_cmds='PATH="\$PATH:/sbin" OBJFORMAT="'"$objformat"'" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  case "$host_os" in
+  freebsd2* | freebsd3.[01]*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  *) # from 3.2 on
+    shlibpath_overrides_runpath=no
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so'
+  soname_spec='${libname}${release}.so$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  dynamic_linker="$host_os dld.sl"
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  shlibpath_var=SHLIB_PATH
+  shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+  library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl'
+  soname_spec='${libname}${release}.sl$major'
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
+
+irix5* | irix6*)
+  version_type=irix
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}.so.$major'
+  library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major ${libname}${release}.so $libname.so'
+  case "$host_os" in
+  irix5*)
+    libsuff= shlibsuff=
+    # this will be overridden with pass_all, but let us keep it just in case
+    deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1"
+    ;;
+  *)
+    case "$LD" in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    # this will be overridden with pass_all, but let us keep it just in case
+    deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1"
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  file_magic_cmd=/usr/bin/file
+  file_magic_test_file=`echo /lib${libsuff}/libc.so*`
+  deplibs_check_method='pass_all'
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux-gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+  soname_spec='${libname}${release}.so$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+  file_magic_cmd=/usr/bin/file
+  file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so`
+
+  if test -f /lib/ld.so.1; then
+    dynamic_linker='GNU ld.so'
+  else
+    # Only the GNU ld.so supports shared libraries on MkLinux.
+    case "$host_cpu" in
+    powerpc*) dynamic_linker=no ;;
+    *) dynamic_linker='Linux ld.so' ;;
+    esac
+  fi
+  ;;
+
+netbsd*)
+  version_type=sunos
+  if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so'
+    soname_spec='${libname}${release}.so$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+openbsd*)
+  version_type=sunos
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+    need_version=no
+  fi
+  library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+os2*)
+  libname_spec='$name'
+  need_lib_prefix=no
+  library_names_spec='$libname.dll $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4*)
+  version_type=osf
+  need_version=no
+  soname_spec='${libname}${release}.so'
+  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
+  shlibpath_var=LD_LIBRARY_PATH
+  # this will be overridden with pass_all, but let us keep it just in case
+  deplibs_check_method='file_magic COFF format alpha shared library'
+  file_magic_cmd=/usr/bin/file
+  file_magic_test_file=/shlib/libc.so
+  deplibs_check_method='pass_all'
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+sco3.2v5*)
+  version_type=osf
+  soname_spec='${libname}${release}.so$major'
+  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+  soname_spec='${libname}${release}.so$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  deplibs_check_method="file_magic ELF [0-9][0-9]-bit [LM]SB dynamic lib"
+  file_magic_cmd=/usr/bin/file
+  file_magic_test_file=/lib/libc.so
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+  version_type=linux
+  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+  soname_spec='${libname}${release}.so$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case "$host_vendor" in
+    ncr)
+      deplibs_check_method='pass_all'
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+      file_magic_cmd=/usr/bin/file
+      file_magic_test_file=`echo /usr/lib/libc.so*`
+      ;;
+  esac
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+  soname_spec='${libname}${release}.so$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+  soname_spec='${libname}${release}.so$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so'
+    soname_spec='$libname.so.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+echo "$ac_t$dynamic_linker" 1>&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+# Report the final consequences.
+echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6
+
+# Only try to build win32 dlls if AC_LIBTOOL_WIN32_DLL was used in
+# configure.in, otherwise build static only libraries.
+case "$host_os" in
+cygwin* | mingw* | os2*)
+  if test x$can_build_shared = xyes; then
+    test x$enable_win32_dll = xno && can_build_shared=no
+    echo "checking if package supports dlls... $can_build_shared" 1>&6
+  fi
+;;
+esac
+
+if test -n "$file_magic_test_file" && test -n "$file_magic_cmd"; then
+  case "$deplibs_check_method" in
+  "file_magic "*)
+    file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+    if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+       egrep "$file_magic_regex" > /dev/null; then
+      :
+    else
+      cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+EOF
+    fi ;;
+  esac
+fi
+
+echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+  test "$enable_shared" = yes && enable_static=no
+  if test -n "$RANLIB"; then
+    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+    postinstall_cmds='$RANLIB $lib'
+  fi
+  ;;
+
+aix4*)
+  test "$enable_shared" = yes && enable_static=no
+  ;;
+esac
+
+echo "$ac_t$enable_shared" 1>&6
+
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+
+echo "checking whether to build static libraries... $enable_static" 1>&6
+
+if test "$hardcode_action" = relink; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+echo $ac_n "checking for objdir... $ac_c" 1>&6
+rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+echo "$ac_t$objdir" 1>&6
+
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+if eval "test \"`echo '$''{'lt_cv_dlopen'+set}'`\" != set"; then
+  lt_cv_dlopen=no lt_cv_dlopen_libs=
+echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
+echo "$progname:2170: checking for dlopen in -ldl" >&5
+ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2178 "ltconfig"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char dlopen();
+
+int main() {
+dlopen()
+; return 0; }
+EOF
+if { (eval echo $progname:2188: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "$progname: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for dlopen""... $ac_c" 1>&6
+echo "$progname:2207: checking for dlopen" >&5
+if eval "test \"`echo '$''{'ac_cv_func_dlopen'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2212 "ltconfig"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char dlopen(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char dlopen();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_dlopen) || defined (__stub___dlopen)
+choke me
+#else
+dlopen();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo $progname:2234: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_dlopen=yes"
+else
+  echo "$progname: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_dlopen=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  lt_cv_dlopen="dlopen"
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for dld_link in -ldld""... $ac_c" 1>&6
+echo "$progname:2251: checking for dld_link in -ldld" >&5
+ac_lib_var=`echo dld'_'dld_link | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldld  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2259 "ltconfig"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char dld_link();
+
+int main() {
+dld_link()
+; return 0; }
+EOF
+if { (eval echo $progname:2269: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "$progname: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for shl_load""... $ac_c" 1>&6
+echo "$progname:2288: checking for shl_load" >&5
+if eval "test \"`echo '$''{'ac_cv_func_shl_load'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2293 "ltconfig"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char shl_load(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char shl_load();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_shl_load) || defined (__stub___shl_load)
+choke me
+#else
+shl_load();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo $progname:2315: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_shl_load=yes"
+else
+  echo "$progname: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_shl_load=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'shl_load`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  lt_cv_dlopen="shl_load"
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6
+echo "$progname:2333: checking for shl_load in -ldld" >&5
+ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldld  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2341 "ltconfig"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char shl_load();
+
+int main() {
+shl_load()
+; return 0; }
+EOF
+if { (eval echo $progname:2352: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "$progname: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+fi
+
+    
+fi
+
+  
+fi
+
+
+fi
+
+fi
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  fi
+
+  case "$lt_cv_dlopen" in
+  dlopen)
+for ac_hdr in dlfcn.h; do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "$progname:2395: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2400 "ltconfig"
+#include <$ac_hdr>
+int fnord = 0;
+EOF
+ac_try="$ac_compile conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo $progname:2405: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "$progname: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+    if test "x$ac_cv_header_dlfcn_h" = xyes; then
+      CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+    fi
+    eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+  echo $ac_n "checking whether a program can dlopen itself""... $ac_c" 1>&6
+echo "$progname:2433: checking whether a program can dlopen itself" >&5
+if test "${lt_cv_dlopen_self+set}" = set; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    lt_cv_dlopen_self=cross
+  else
+    cat > conftest.c <<EOF
+#line 2441 "ltconfig"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LTDL_GLOBAL   RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+#  define LTDL_GLOBAL  DL_GLOBAL
+# else
+#  define LTDL_GLOBAL  0
+# endif
+#endif
+
+/* We may have to define LTDL_LAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LTDL_LAZY_OR_NOW
+# ifdef RTLD_LAZY
+#  define LTDL_LAZY_OR_NOW     RTLD_LAZY
+# else
+#  ifdef DL_LAZY
+#   define LTDL_LAZY_OR_NOW    DL_LAZY
+#  else
+#   ifdef RTLD_NOW
+#    define LTDL_LAZY_OR_NOW   RTLD_NOW
+#   else
+#    ifdef DL_NOW
+#     define LTDL_LAZY_OR_NOW  DL_NOW
+#    else
+#     define LTDL_LAZY_OR_NOW  0
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+fnord() { int i=42;}
+main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW);
+    if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord");
+              if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); } 
+
+EOF
+if { (eval echo $progname:2487: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  lt_cv_dlopen_self=yes
+else
+  echo "$progname: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  lt_cv_dlopen_self=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$lt_cv_dlopen_self" 1>&6
+
+  if test "$lt_cv_dlopen_self" = yes; then
+    LDFLAGS="$LDFLAGS $link_static_flag"
+  echo $ac_n "checking whether a statically linked program can dlopen itself""... $ac_c" 1>&6
+echo "$progname:2506: checking whether a statically linked program can dlopen itself" >&5
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    lt_cv_dlopen_self_static=cross
+  else
+    cat > conftest.c <<EOF
+#line 2514 "ltconfig"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LTDL_GLOBAL   RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+#  define LTDL_GLOBAL  DL_GLOBAL
+# else
+#  define LTDL_GLOBAL  0
+# endif
+#endif
+
+/* We may have to define LTDL_LAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LTDL_LAZY_OR_NOW
+# ifdef RTLD_LAZY
+#  define LTDL_LAZY_OR_NOW     RTLD_LAZY
+# else
+#  ifdef DL_LAZY
+#   define LTDL_LAZY_OR_NOW    DL_LAZY
+#  else
+#   ifdef RTLD_NOW
+#    define LTDL_LAZY_OR_NOW   RTLD_NOW
+#   else
+#    ifdef DL_NOW
+#     define LTDL_LAZY_OR_NOW  DL_NOW
+#    else
+#     define LTDL_LAZY_OR_NOW  0
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+fnord() { int i=42;}
+main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW);
+    if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord");
+    if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); } 
+
+EOF
+if { (eval echo $progname:2560: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  lt_cv_dlopen_self_static=yes
+else
+  echo "$progname: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  lt_cv_dlopen_self_static=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$lt_cv_dlopen_self_static" 1>&6
+fi
+    ;;
+  esac
+
+  case "$lt_cv_dlopen_self" in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case "$lt_cv_dlopen_self_static" in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+
+# Copy echo and quote the copy, instead of the original, because it is
+# used later.
+ltecho="$echo"
+if test "X$ltecho" = "X$CONFIG_SHELL $0 --fallback-echo"; then
+   ltecho="$CONFIG_SHELL \$0 --fallback-echo"
+fi
+LTSHELL="$SHELL"
+
+LTCONFIG_VERSION="$VERSION"
+
+# Only quote variables if we're using ltmain.sh.
+case "$ltmain" in
+*.sh)
+  # Now quote all the things that may contain metacharacters.
+  for var in ltecho old_CC old_CFLAGS old_CPPFLAGS \
+    old_LD old_LDFLAGS old_LIBS \
+    old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS \
+    AR CC LD LN_S NM LTSHELL LTCONFIG_VERSION \
+    reload_flag reload_cmds wl \
+    pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \
+    thread_safe_flag_spec whole_archive_flag_spec libname_spec \
+    library_names_spec soname_spec \
+    RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \
+    old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds postuninstall_cmds \
+    file_magic_cmd export_symbols_cmds deplibs_check_method allow_undefined_flag no_undefined_flag \
+    finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \
+    hardcode_libdir_flag_spec hardcode_libdir_separator  \
+    sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+    compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do
+
+    case "$var" in
+    reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \
+    old_postinstall_cmds | old_postuninstall_cmds | \
+    export_symbols_cmds | archive_cmds | archive_expsym_cmds | \
+    postinstall_cmds | postuninstall_cmds | \
+    finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+      # Double-quote double-evaled strings.
+      eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+      ;;
+    *)
+      eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+      ;;
+    esac
+  done
+
+  case "$ltecho" in
+  *'\$0 --fallback-echo"')
+    ltecho=`$echo "X$ltecho" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+    ;;
+  esac
+
+  trap "$rm \"$ofile\"; exit 1" 1 2 15
+  echo "creating $ofile"
+  $rm "$ofile"
+  cat <<EOF > "$ofile"
+#! $SHELL
+
+# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+# NOTE: Changes made to this file will be lost: look at ltconfig or ltmain.sh.
+#
+# Copyright (C) 1996-1999 Free Software Foundation, Inc.
+# Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="sed -e s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "\${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi
+
+### BEGIN LIBTOOL CONFIG
+EOF
+  cfgfile="$ofile"
+  ;;
+
+*)
+  # Double-quote the variables that need it (for aesthetics).
+  for var in old_CC old_CFLAGS old_CPPFLAGS \
+    old_LD old_LDFLAGS old_LIBS \
+    old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS; do
+    eval "$var=\\\"\$var\\\""
+  done
+
+  # Just create a config file.
+  cfgfile="$ofile.cfg"
+  trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+  echo "creating $cfgfile"
+  $rm "$cfgfile"
+  cat <<EOF > "$cfgfile"
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Libtool configuration file.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+EOF
+  ;;
+esac
+
+cat <<EOF >> "$cfgfile"
+# Libtool was configured as follows, on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# CC=$old_CC CFLAGS=$old_CFLAGS CPPFLAGS=$old_CPPFLAGS \\
+# LD=$old_LD LDFLAGS=$old_LDFLAGS LIBS=$old_LIBS \\
+# NM=$old_NM RANLIB=$old_RANLIB LN_S=$old_LN_S \\
+# DLLTOOL=$old_DLLTOOL OBJDUMP=$old_OBJDUMP AS=$old_AS \\
+#   $0$ltconfig_args
+#
+# Compiler and other test output produced by $progname, useful for
+# debugging $progname, is in ./config.log if it exists.
+
+# The version of $progname that generated this script.
+LTCONFIG_VERSION=$LTCONFIG_VERSION
+
+# Shell to use when invoking shell scripts.
+SHELL=$LTSHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$ltecho
+
+# The archiver.
+AR=$AR
+
+# The default C compiler.
+CC=$CC
+
+# The linker used to build libraries.
+LD=$LD
+
+# Whether we need hard or soft links.
+LN_S=$LN_S
+
+# A BSD-compatible nm program.
+NM=$NM
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$reload_flag
+reload_cmds=$reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$wl
+
+# Object file suffix (normally "o").
+objext="$objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$pic_flag
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$compiler_c_o
+
+# Can we write directly to a .lo ?
+compiler_o_lo=$compiler_o_lo
+
+# Must we lock files when doing compilation ?
+need_locks=$need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$link_static_flag
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$no_builtin_flag
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$whole_archive_flag_spec
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$thread_safe_flag_spec
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$RANLIB
+old_archive_cmds=$old_archive_cmds
+old_postinstall_cmds=$old_postinstall_cmds
+old_postuninstall_cmds=$old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$old_archive_from_new_cmds
+
+# Commands used to build and install a shared archive.
+archive_cmds=$archive_cmds
+archive_expsym_cmds=$archive_expsym_cmds
+postinstall_cmds=$postinstall_cmds
+postuninstall_cmds=$postuninstall_cmds
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$allow_undefined_flag
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$no_undefined_flag
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$global_symbol_to_cdecl
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$hardcode_libdir_flag_spec
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$hardcode_libdir_separator
+
+# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$include_expsyms
+
+EOF
+
+case "$ltmain" in
+*.sh)
+  echo '### END LIBTOOL CONFIG' >> "$ofile"
+  echo >> "$ofile"
+  case "$host_os" in
+  aix3*)
+    cat <<\EOF >> "$ofile"
+
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "${COLLECT_NAMES+set}" != set; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+EOF
+    ;;
+  esac
+
+  # Append the ltmain.sh script.
+  sed '$q' "$ltmain" >> "$ofile" || (rm -f "$ofile"; exit 1)
+
+  chmod +x "$ofile"
+  ;;
+
+*)
+  # Compile the libtool program.
+  echo "FIXME: would compile $ltmain"
+  ;;
+esac
+
+test -n "$cache_file" || exit 0
+
+# AC_CACHE_SAVE
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+exit 0
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/m4/ac_attribute.m4 b/m4/ac_attribute.m4
new file mode 100644 (file)
index 0000000..23479a9
--- /dev/null
@@ -0,0 +1,47 @@
+dnl Copyright (C) 2004-2008 Kim Woelders
+dnl Copyright (C) 2008 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+dnl Originally snatched from somewhere...
+
+dnl Macro for checking if the compiler supports __attribute__
+
+dnl Usage: AC_C___ATTRIBUTE__
+dnl call AC_DEFINE for HAVE___ATTRIBUTE__ and __UNUSED__
+dnl if the compiler supports __attribute__, HAVE___ATTRIBUTE__ is
+dnl defined to 1 and __UNUSED__ is defined to __attribute__((unused))
+dnl otherwise, HAVE___ATTRIBUTE__ is not defined and __UNUSED__ is
+dnl defined to nothing.
+
+AC_DEFUN([AC_C___ATTRIBUTE__],
+[
+
+AC_MSG_CHECKING([for __attribute__])
+
+AC_CACHE_VAL([ac_cv___attribute__],
+   [AC_TRY_COMPILE(
+       [
+#include <stdlib.h>
+
+int func(int x);
+int foo(int x __attribute__ ((unused)))
+{
+   exit(1);
+}
+       ],
+       [],
+       [ac_cv___attribute__="yes"],
+       [ac_cv___attribute__="no"]
+    )])
+
+AC_MSG_RESULT($ac_cv___attribute__)
+
+if test "x${ac_cv___attribute__}" = "xyes" ; then
+   AC_DEFINE([HAVE___ATTRIBUTE__], [1], [Define to 1 if your compiler has __attribute__])
+   AC_DEFINE([__UNUSED__], [__attribute__((unused))], [Macro declaring a function argument to be unused])
+  else
+    AC_DEFINE([__UNUSED__], [], [Macro declaring a function argument to be unused])
+fi
+
+])
+
+dnl End of ac_attribute.m4
diff --git a/remix.pc.in b/remix.pc.in
new file mode 100644 (file)
index 0000000..e70bda1
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: remix
+Description: An audio rendering library
+Requires: ctxdata sndfile
+Version: @VERSION@
+Libs: -L${libdir} -lremix -ldl
+Cflags: -I${includedir}
diff --git a/remix.spec b/remix.spec
new file mode 100644 (file)
index 0000000..539e8c7
--- /dev/null
@@ -0,0 +1,58 @@
+
+%define name    remix
+%define version 0.2.3
+%define release 1
+%define prefix  /usr
+
+Summary: An audio rendering library
+Name: %{name}
+Version: %{version}
+Release: %{release}
+Prefix: %{prefix}
+Copyright: LGPL
+Group: Libraries/Sound
+Source: http://www.metadecks.org/software/remix/download/libremix-%{version}.tar.gz
+URL: http://www.metadecks.org/software/remix/
+BuildRoot: /var/tmp/%{name}-%{version}
+
+%description
+Remix is a library for rendering audio data.
+
+%package devel
+Summary: Libraries, includes, etc to develop remix applications
+Group: Libraries
+
+%description devel
+Libraries, include files, etc you can use to develop remix applications.
+
+%prep
+%setup
+
+%build
+./configure --prefix=%{prefix}
+make
+
+%install
+if [ -d $RPM_BUILD_ROOT ]; then rm -rf $RPM_BUILD_ROOT; fi
+mkdir -p $RPM_BUILD_ROOT
+make prefix=$RPM_BUILD_ROOT%{prefix} install
+
+%clean
+if [ -d $RPM_BUILD_ROOT ]; then rm -rf $RPM_BUILD_ROOT; fi
+
+%files
+%defattr(-,root,root)
+%doc AUTHORS COPYING ChangeLog INSTALL NEWS README TODO doc
+%prefix/lib/libremix.so.*
+
+%files devel
+%defattr(-,root,root)
+%{prefix}/lib/libremix.a
+%{prefix}/lib/libremix.la
+%{prefix}/lib/libremix.so
+%{prefix}/include/remix.h
+%{prefix}/include/remix_plugin.h
+
+%changelog
+* Tue Sep 18 2001 Conrad Parker <Conrad.Parker@CSIRO.AU>
+- Created axel.spec.in (hacked from libsndfile.spec.in)
diff --git a/remix.spec.in b/remix.spec.in
new file mode 100644 (file)
index 0000000..57d1972
--- /dev/null
@@ -0,0 +1,58 @@
+
+%define name    @PACKAGE@
+%define version @VERSION@
+%define release 1
+%define prefix  /usr
+
+Summary: An audio rendering library
+Name: %{name}
+Version: %{version}
+Release: %{release}
+Prefix: %{prefix}
+Copyright: LGPL
+Group: Libraries/Sound
+Source: http://www.metadecks.org/software/remix/download/libremix-%{version}.tar.gz
+URL: http://www.metadecks.org/software/remix/
+BuildRoot: /var/tmp/%{name}-%{version}
+
+%description
+Remix is a library for rendering audio data.
+
+%package devel
+Summary: Libraries, includes, etc to develop remix applications
+Group: Libraries
+
+%description devel
+Libraries, include files, etc you can use to develop remix applications.
+
+%prep
+%setup
+
+%build
+./configure --prefix=%{prefix}
+make
+
+%install
+if [ -d $RPM_BUILD_ROOT ]; then rm -rf $RPM_BUILD_ROOT; fi
+mkdir -p $RPM_BUILD_ROOT
+make prefix=$RPM_BUILD_ROOT%{prefix} install
+
+%clean
+if [ -d $RPM_BUILD_ROOT ]; then rm -rf $RPM_BUILD_ROOT; fi
+
+%files
+%defattr(-,root,root)
+%doc AUTHORS COPYING ChangeLog INSTALL NEWS README TODO doc
+%prefix/lib/libremix.so.*
+
+%files devel
+%defattr(-,root,root)
+%{prefix}/lib/libremix.a
+%{prefix}/lib/libremix.la
+%{prefix}/lib/libremix.so
+%{prefix}/include/remix.h
+%{prefix}/include/remix_plugin.h
+
+%changelog
+* Tue Sep 18 2001 Conrad Parker <Conrad.Parker@CSIRO.AU>
+- Created axel.spec.in (hacked from libsndfile.spec.in)
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..d0afad3
--- /dev/null
@@ -0,0 +1,2 @@
+
+SUBDIRS = ctxdata libremix plugins examples tests
diff --git a/src/ctxdata/Makefile.am b/src/ctxdata/Makefile.am
new file mode 100644 (file)
index 0000000..e5ef4d1
--- /dev/null
@@ -0,0 +1,12 @@
+
+INCLUDES = 
+
+lib_LTLIBRARIES = libctxdata.la
+
+libctxdata_la_SOURCES = \
+       ctxdata.h \
+       cd_list.c \
+       cd_scalar.c \
+       cd_set.c
+
+include_HEADERS = ctxdata.h
diff --git a/src/ctxdata/cd_list.c b/src/ctxdata/cd_list.c
new file mode 100644 (file)
index 0000000..1de9c5c
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * CtxData -- Context oriented data types
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * CDList: A generic doubly-linked list implementation.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+
+#include "ctxdata.h"
+
+static CDList *
+cd_list_item_new (void * ctx, CDScalar data)
+{
+  CDList * l;
+
+  l = cd_malloc (sizeof (struct _CDList));
+  l->prev = l->next = NULL;
+  l->data = data;
+
+  return l;
+}
+
+CDList *
+cd_list_new (void * ctx)
+{
+  return NULL;
+}
+
+CDList *
+cd_list_copy (void * ctx, CDList * list)
+{
+  CDList * new_list = cd_list_new (ctx);
+  CDList * l;
+
+  for (l = list; l; l = l->next) {
+    new_list = cd_list_append (ctx, new_list, l->data);
+  }
+
+  return new_list;
+}
+
+CDList *
+cd_list_clone (void * ctx, CDList * list, CDCloneFunc clone)
+{
+  CDList * new_list = cd_list_new (ctx);
+  CDList * l;
+  CDScalar new_data;
+
+  for (l = list; l; l = l->next) {
+    new_data = CD_POINTER (clone (ctx, l->data.s_pointer));
+    new_list = cd_list_append (ctx, new_list, new_data);
+  }
+
+  return new_list;
+}
+
+CDList *
+cd_list_clone_with (void * ctx, CDList * list, CDCloneWithFunc clone,
+                   void * with)
+{
+  CDList * new_list = cd_list_new (ctx);
+  CDList * l;
+  CDScalar new_data;
+
+  for (l = list; l; l = l->next) {
+    new_data = CD_POINTER (clone (ctx, l->data.s_pointer, with));
+    new_list = cd_list_append (ctx, new_list, new_data);
+  }
+
+  return new_list;
+}
+
+CDList *
+cd_list_last_item (void * ctx, CDList * list)
+{
+  CDList * l;
+  for (l = list; l; l = l->next)
+    if (l->next == NULL) return l;
+  return NULL;
+}
+
+CDScalar
+cd_list_last (void * ctx, CDList * list, CDScalarType type)
+{
+  CDList * l = cd_list_last_item (ctx, list);
+  return ((l == NULL) ? cd_scalar_invalid (ctx, type) : l->data);
+}
+
+CDList *
+cd_list_prepend (void * ctx, CDList * list, CDScalar data)
+{
+  CDList * l = cd_list_item_new (ctx, data);
+
+  if (list == NULL) return l;
+
+  l->next = list;
+  list->prev = l;
+
+  return l;
+}
+
+CDList *
+cd_list_append (void * ctx, CDList * list, CDScalar data)
+{
+  CDList * l = cd_list_item_new (ctx, data);
+  CDList * last;
+
+  if (list == NULL) return l;
+
+  last = cd_list_last_item (ctx, list);
+  if (last) last->next = l;
+  l->prev = last;
+  return list;
+}
+
+CDList *
+cd_list_add_before_item (void * ctx, CDList * list, CDScalar data,
+                        CDList * item)
+{
+  CDList * l, * p;
+
+  if (list == NULL) return cd_list_item_new (ctx, data);
+  if (item == NULL) return cd_list_append (ctx, list, data);
+  if (item == list) return cd_list_prepend (ctx, list, data);
+
+  l = cd_list_item_new (ctx, data);
+  p = item->prev;
+
+  l->prev = p;
+  l->next = item;
+  if (p) p->next = l;
+  item->prev = l;
+
+  return list;
+}
+
+CDList *
+cd_list_add_after_item (void * ctx, CDList * list, CDScalar data,
+                       CDList * item)
+{
+  CDList * l, * n;
+
+  if (item == NULL) return cd_list_prepend (ctx, list, data);
+
+  l = cd_list_item_new (ctx, data);
+  n = item->next;
+
+  l->prev = item;
+  l->next = n;
+  if (n) n->prev = l;
+  item->next = l;
+
+  return list;
+}
+
+CDList *
+cd_list_add_before (void * ctx, CDList * list, CDScalarType type,
+                   CDScalar data, CDScalar before)
+{
+  CDList * b = cd_list_find (ctx, list, type, before);
+  return cd_list_add_before_item (ctx, list, data, b);
+}
+
+CDList *
+cd_list_add_after (void * ctx, CDList * list, CDScalarType type,
+                  CDScalar data, CDScalar after)
+{
+  CDList * a = cd_list_find (ctx, list, type, after);
+  return cd_list_add_after_item (ctx, list, data, a);
+}
+
+
+CDList *
+cd_list_find (void * ctx, CDList * list, CDScalarType type, CDScalar data)
+{
+  CDList * l;
+
+  for (l = list; l; l = l->next)
+    if (cd_scalar_eq (ctx, type, l->data, data)) return l;
+
+  return NULL;
+}
+
+/*
+ * cd_list_find_first (ctx, list, f, data)
+ *
+ * Finds the first item l of 'list' for which f (ctx, l->data, data) is true.
+ * Returns NULL if the condition is not true for any item of 'list'.
+ */
+CDList *
+cd_list_find_first (void * ctx, CDList * list, CDScalarType type,
+                   CDCmpFunc f, CDScalar data)
+{
+  CDList * l;
+
+  switch (type) {
+  case CD_TYPE_CHAR:
+    for (l = list; l; l = l->next)
+      if (((CDCmpCharFunc)f)(ctx, l->data.s_char, data.s_char)) return l;
+    break;
+  case CD_TYPE_UCHAR:
+    for (l = list; l; l = l->next)
+      if (((CDCmpUCharFunc)f)(ctx, l->data.s_uchar, data.s_uchar)) return l;
+    break;
+  case CD_TYPE_INT:
+    for (l = list; l; l = l->next)
+      if (((CDCmpIntFunc)f)(ctx, l->data.s_int, data.s_int)) return l;
+    break;
+  case CD_TYPE_UINT:
+    for (l = list; l; l = l->next)
+      if (((CDCmpUIntFunc)f)(ctx, l->data.s_uint, data.s_uint)) return l;
+    break;
+  case CD_TYPE_LONG:
+    for (l = list; l; l = l->next)
+      if (((CDCmpLongFunc)f)(ctx, l->data.s_long, data.s_long)) return l;
+    break;
+  case CD_TYPE_ULONG:
+    for (l = list; l; l = l->next)
+      if (((CDCmpULongFunc)f)(ctx, l->data.s_ulong, data.s_ulong)) return l;
+    break;
+  case CD_TYPE_FLOAT:
+    for (l = list; l; l = l->next)
+      if (((CDCmpFloatFunc)f)(ctx, l->data.s_float, data.s_float)) return l;
+    break;
+  case CD_TYPE_DOUBLE:
+    for (l = list; l; l = l->next)
+      if (((CDCmpDoubleFunc)f)(ctx, l->data.s_double, data.s_double)) return l;
+    break;
+  case CD_TYPE_STRING:
+    for (l = list; l; l = l->next)
+      if (((CDCmpStringFunc)f)(ctx, l->data.s_string, data.s_string)) return l;
+    break;
+  case CD_TYPE_POINTER:
+    for (l = list; l; l = l->next)
+      if (((CDCmpFunc)f)(ctx, l->data.s_pointer, data.s_pointer)) return l;
+    break;
+  default: break;
+  }
+
+  return NULL;
+}
+
+/*
+ * cd_list_find_last (ctx, list, f, data)
+ *
+ * Finds the last item l of 'list' for which f (ctx, l->data, data) is true.
+ * Returns NULL if no items are found for which the condition is true
+ * before an item is found for which it is false.
+ */
+CDList *
+cd_list_find_last (void * ctx, CDList * list, CDScalarType type,
+                  CDCmpFunc f, CDScalar data)
+{
+  CDList * l, * lp = NULL;
+
+  switch (type) {
+  case CD_TYPE_CHAR:
+    for (l = list; l; l = l->next) {
+      if (!((CDCmpCharFunc)f)(ctx, l->data.s_char, data.s_char))
+       return lp;
+      lp = l;
+    }
+    break;
+  case CD_TYPE_UCHAR:
+    for (l = list; l; l = l->next) {
+      if (!((CDCmpUCharFunc)f)(ctx, l->data.s_uchar, data.s_uchar))
+       return lp;
+      lp = l;
+    }
+    break;
+  case CD_TYPE_INT:
+    for (l = list; l; l = l->next) {
+      if (!((CDCmpIntFunc)f)(ctx, l->data.s_int, data.s_int))
+       return lp;
+      lp = l;
+    }
+    break;
+  case CD_TYPE_UINT:
+    for (l = list; l; l = l->next) {
+      if (!((CDCmpUIntFunc)f)(ctx, l->data.s_uint, data.s_uint))
+       return lp;
+      lp = l;
+    }
+    break;
+  case CD_TYPE_LONG:
+    for (l = list; l; l = l->next) {
+      if (!((CDCmpLongFunc)f)(ctx, l->data.s_long, data.s_long))
+       return lp;
+      lp = l;
+    }
+    break;
+  case CD_TYPE_ULONG:
+    for (l = list; l; l = l->next) {
+      if (!((CDCmpULongFunc)f)(ctx, l->data.s_ulong, data.s_ulong))
+       return lp;
+      lp = l;
+    }
+    break;
+  case CD_TYPE_FLOAT:
+    for (l = list; l; l = l->next) {
+      if (!((CDCmpFloatFunc)f)(ctx, l->data.s_float, data.s_float))
+       return lp;
+      lp = l;
+    }
+    break;
+  case CD_TYPE_DOUBLE:
+    for (l = list; l; l = l->next) {
+      if (!((CDCmpDoubleFunc)f)(ctx, l->data.s_double, data.s_double))
+       return lp;
+      lp = l;
+    }
+    break;
+  case CD_TYPE_STRING:
+    for (l = list; l; l = l->next) {
+      if (!((CDCmpStringFunc)f)(ctx, l->data.s_string, data.s_string))
+       return lp;
+      lp = l;
+    }
+    break;
+  case CD_TYPE_POINTER:
+    for (l = list; l; l = l->next) {
+      if (!((CDCmpFunc)f)(ctx, l->data.s_pointer, data.s_pointer))
+       return lp;
+      lp = l;
+    }
+    break;
+  default: break;
+  }
+
+  return lp;
+}
+
+/*
+ * cd_list_insert (ctx, list, data, f)
+ *
+ * Inserts data into sorted list 'list' using the comparison function 'f'.
+ * 'data' is inserted before the first item l found for which f(ctx, l, data)
+ * is true.
+ */
+CDList *
+cd_list_insert (void * ctx, CDList * list, CDScalarType type, CDScalar data,
+               CDCmpFunc f)
+{
+  CDList * l;
+  if (list == NULL) return cd_list_prepend (ctx, list, data);
+  if ((l = cd_list_find_first (ctx, list, type, f, data)) == NULL)
+    return cd_list_append (ctx, list, data);
+  return cd_list_add_before_item (ctx, list, data, l);
+}
+
+CDList *
+cd_list_remove (void * ctx, CDList * list, CDScalarType type, CDScalar data)
+{
+  CDList * l = cd_list_find (ctx, list, type, data);
+
+  if (l == NULL) return list;
+
+  if (l->prev) l->prev->next = l->next;
+  if (l->next) l->next->prev = l->prev;
+
+  if (l == list) return list->next;
+  else return list;
+}
+
+CDList *
+cd_list_join (void * ctx, CDList * l1, CDList * l2)
+{
+  CDList * l1_last = cd_list_last_item (ctx, l1);
+
+  if (l1_last == NULL) return l2;
+
+  l1_last->next = l2;
+  if (l2 != NULL) l2->prev = l1_last;
+
+  return l1;
+}
+
+int
+cd_list_length (void * ctx, CDList * list)
+{
+  CDList * l;
+  int c = 0;
+
+  for (l = list; l; l = l->next)
+    c++;
+
+  return c;
+}
+
+int
+cd_list_is_empty (void * ctx, CDList * list)
+{
+  return (list == NULL);
+}
+
+int
+cd_list_is_singleton (void * ctx, CDList * list)
+{
+  if (list == NULL) return 0;
+  if (list->next == NULL) return 1;
+  else return 0;
+}
+
+/*
+ * cd_list_destroy_with (ctx, list, destroy)
+ *
+ * Step through list 'list', destroying each item using AxDestroyFunc destroy,
+ * and also free the list structure itself.
+ */
+CDList *
+cd_list_destroy_with (void * ctx, CDList * list, CDDestroyFunc destroy)
+{
+  CDList * l, * ln;
+
+  for (l = list; l; l = ln) {
+    ln = l->next;
+//    destroy (ctx, l->data.s_pointer);
+    cd_free (l);
+  }
+
+  return NULL;
+}
+
+/*
+ * cd_list_free_all (ctx, list)
+ *
+ * Step through list 'list', freeing each item using cd_free(), and
+ * also free the list structure itself.
+ */
+CDList *
+cd_list_free_all (void * ctx, CDList * list)
+{
+  return cd_list_destroy_with (ctx, list, (CDDestroyFunc)cd_free);
+}
+
+/*
+ * cd_list_free (list)
+ *
+ * Free the list structure 'list', but not its items.
+ */
+CDList *
+cd_list_free (void * ctx, CDList * list)
+{
+  CDList * l, * ln;
+
+  for (l = list; l; l = ln) {
+    ln = l->next;
+    cd_free (l);
+  }
+
+  return NULL;
+}
+
+void
+cd_list_apply (void * ctx, CDList * list, CDFunc func)
+{
+  CDList * l;
+
+  for (l = list; l; l = l->next) {
+    func (ctx, l->data.s_pointer);
+  }
+}
diff --git a/src/ctxdata/cd_scalar.c b/src/ctxdata/cd_scalar.c
new file mode 100644 (file)
index 0000000..ea8b473
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * CtxData -- Context oriented data types
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * CDScalar: Polymorphic scalar values
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+
+#include "ctxdata.h"
+
+CDScalar
+cd_scalar_invalid (void * ctx, CDScalarType type)
+{
+  return CD_POINTER(NULL);
+}
+
+int
+cd_scalar_eq (void * ctx, CDScalarType type, CDScalar d1, CDScalar d2)
+{
+  switch (type) {
+  case CD_TYPE_CHAR: return (d1.s_char == d2.s_char); break;
+  case CD_TYPE_UCHAR: return (d1.s_uchar == d2.s_uchar); break;
+  case CD_TYPE_INT: return (d1.s_int == d2.s_int); break;
+  case CD_TYPE_UINT: return (d1.s_uint == d2.s_uint); break;
+  case CD_TYPE_LONG: return (d1.s_long == d2.s_long); break;
+  case CD_TYPE_ULONG: return (d1.s_ulong == d2.s_ulong); break;
+  case CD_TYPE_FLOAT: return (d1.s_float == d2.s_float); break;
+  case CD_TYPE_DOUBLE: return (d1.s_double == d2.s_double); break;
+  case CD_TYPE_STRING: return (d1.s_string == d2.s_string); break;
+  case CD_TYPE_POINTER: return (d1.s_pointer == d2.s_pointer); break;
+  default: return 0;
+  }
+}
diff --git a/src/ctxdata/cd_set.c b/src/ctxdata/cd_set.c
new file mode 100644 (file)
index 0000000..ca56c0c
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * CtxData -- Context oriented data types
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * CDSet: A keyed set implementation.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+
+#include "ctxdata.h"
+
+static CDSet *
+cd_set_item_new (void * ctx, int key, CDScalar data)
+{
+  CDSet * s;
+
+  s = cd_malloc (sizeof (struct _CDSet));
+  s->prev = s->next = NULL;
+  s->key = key;
+  s->data = data;
+
+  return s;
+}
+
+CDSet *
+cd_set_new (void * ctx)
+{
+  return NULL;
+}
+
+CDSet *
+cd_set_clone (void * ctx, CDSet * set, CDCloneFunc clone)
+{
+  CDSet * new_set = cd_set_new (ctx);
+  CDSet * s;
+  void * new_data;
+
+  for (s = set; s; s = s->next) {
+    new_data = clone (ctx, s->data.s_pointer);
+    new_set = cd_set_insert (ctx, new_set, s->key, CD_POINTER(new_data));
+  }
+
+  return new_set;
+}
+
+CDSet *
+cd_set_clone_keys (void * ctx, CDSet * set)
+{
+  CDSet * new_set = cd_set_new (ctx);
+  CDSet * s;
+
+  for (s = set; s; s = s->next) {
+    new_set = cd_set_insert (ctx, new_set, s->key, CD_INT(0));
+  }
+
+  return new_set;
+}
+
+CDSet *
+cd_set_clone_with (void * ctx, CDSet * set, CDCloneWithFunc clone,
+                  void * with)
+{
+  CDSet * new_set = cd_set_new (ctx);
+  CDSet * s;
+  void * new_data;
+
+  for (s = set; s; s = s->next) {
+    new_data = clone (ctx, s->data.s_pointer, with);
+    new_set = cd_set_insert (ctx, new_set, s->key, CD_POINTER(new_data));
+  }
+
+  return new_set;
+}
+
+static CDSet *
+cd_set_find_item (void * ctx, CDSet * set, int key)
+{
+  CDSet * s;
+
+  for (s = set; s; s = s->next)
+    if (s->key == key) return s;
+
+  return NULL;
+}
+
+int
+cd_set_contains (void * ctx, CDSet * set, int key)
+{
+  CDSet * s = cd_set_find_item (ctx, set, key);
+  return (s != NULL);
+}
+
+CDScalar
+cd_set_find (void * ctx, CDSet * set, int key)
+{
+  CDSet * s = cd_set_find_item (ctx, set, key);
+  if (s == NULL) return CD_POINTER(NULL);
+  return s->data;
+}
+  
+
+/*
+ * cd_set_insert (ctx, set, key, data)
+ *
+ * Inserts data into set 'set'.
+ */
+CDSet *
+cd_set_insert (void * ctx, CDSet * set, int key, CDScalar data)
+{
+  CDSet * check, * s;
+
+  check = cd_set_find_item (ctx, set, key);
+  if (check != NULL) return NULL; /* already contained */
+
+  s = cd_set_item_new (ctx, key, data);
+
+  if (set == NULL) return s;
+
+  s->next = set;
+  set->prev = s;
+
+  return s;
+}
+
+CDSet *
+cd_set_remove (void * ctx, CDSet * set, int key)
+{
+  CDSet * s = cd_set_find_item (ctx, set, key);
+
+  if (s == NULL) return set;
+
+  if (s->prev) s->prev->next = s->next;
+  if (s->next) s->next->prev = s->prev;
+
+  if (s == set) return set->next;
+  else return set;
+}
+
+CDSet *
+cd_set_replace (void * ctx, CDSet * set, int key, CDScalar data)
+{
+  CDSet * s = cd_set_find_item (ctx, set, key);
+
+  if (s == NULL) { /* Not previously contained */
+    return cd_set_insert (ctx, set, key, data);
+  }
+
+  s->data = data;
+
+  return set;
+}
+
+int
+cd_set_size (void * ctx, CDSet * set)
+{
+  CDSet * s;
+  int n = 0;
+
+  for (s = set; s; s = s->next)
+    n++;
+
+  return n;
+}
+
+int
+cd_set_is_empty (void * ctx, CDSet * set)
+{
+  return (set == NULL);
+}
+
+int
+cd_set_is_singleton (void * ctx, CDSet * set)
+{
+  if (set == NULL) return 0;
+  if (set->next == NULL) return 1;
+  else return 0;
+}
+
+/*
+ * cd_set_destroy_with (ctx, set, destroy)
+ *
+ * Step through set 'set', destroying each item using CDDestroyFunc destroy,
+ * and also free the set structure itself.
+ */
+CDSet *
+cd_set_destroy_with (void * ctx, CDSet * set, CDDestroyFunc destroy)
+{
+  CDSet * s, * sn;
+
+  for (s = set; s; s = sn) {
+    sn = s->next;
+    destroy (ctx, s->data.s_pointer);
+    cd_free (s);
+  }
+
+  return NULL;
+}
+
+/*
+ * cd_set_free_all (ctx, set)
+ *
+ * Step through set 'set', freeing each item using cd_free(), and
+ * also free the set structure itself.
+ */
+CDSet *
+cd_set_free_all (void * ctx, CDSet * set)
+{
+  return cd_set_destroy_with (ctx, set, (CDDestroyFunc)cd_free);
+}
+
+/*
+ * cd_set_free (set)
+ *
+ * Free the set structure 'set', but not its items.
+ */
+CDSet *
+cd_set_free (void * ctx, CDSet * set)
+{
+  CDSet * s, * sn;
+
+  for (s = set; s; s = sn) {
+    sn = s->next;
+    cd_free (s);
+  }
+
+  return NULL;
+}
diff --git a/src/ctxdata/ctxdata.h b/src/ctxdata/ctxdata.h
new file mode 100644 (file)
index 0000000..a930098
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * CtxData -- Context dependent data types
+ *
+ * Copyright (C) 2001 Conrad Parker <conrad@vergenet.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __CTXDATA_H__
+#define __CTXDATA_H__
+
+#include <stdlib.h>
+
+#define cd_malloc malloc
+#define cd_free free
+
+#ifdef FALSE
+#undef FALSE
+#endif
+#define FALSE (0)
+
+#ifdef TRUE
+#undef TRUE
+#endif
+#define TRUE (!FALSE)
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+typedef int CDScalarType;
+typedef union _CDScalar CDScalar;
+typedef struct _CDSet CDSet;
+typedef struct _CDList CDList;
+
+#define CD_ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+typedef void * (*CDOpaqueFunc) (void);
+
+typedef void * (*CDFunc) (void * ctx, void * data);
+typedef void * (*CDCloneFunc) (void * ctx, void * data);
+typedef void * (*CDCloneWithFunc) (void * ctx, void * data, void * with);
+typedef void (*CDFreeFunc) (void * ctx, void * data);
+typedef int (*CDDestroyFunc) (void * ctx, void * data);
+
+typedef int (*CDCmpBoolFunc) (void * ctx, int data1, int data2);
+typedef int (*CDCmpCharFunc) (void * ctx, char data1, char data2);
+typedef int (*CDCmpUCharFunc) (void * ctx, unsigned char data1,
+                              unsigned char data2);
+typedef int (*CDCmpIntFunc) (void * ctx, int data1, int data2);
+typedef int (*CDCmpUIntFunc) (void * ctx, unsigned int data1,
+                             unsigned int data2);
+typedef int (*CDCmpLongFunc) (void * ctx, long data1, long data2);
+typedef int (*CDCmpULongFunc) (void * ctx, unsigned long data1,
+                              unsigned long data2);
+typedef int (*CDCmpFloatFunc) (void * ctx, float data1, float data2);
+typedef int (*CDCmpDoubleFunc) (void * ctx, double data1, double data2);
+typedef int (*CDCmpStringFunc) (void * ctx, char * data1, char * data2);
+
+typedef int (*CDCmpFunc) (void * ctx, void * data1, void * data2);
+
+enum _CDScalarType {
+  CD_TYPE_CHAR,
+  CD_TYPE_UCHAR,
+  CD_TYPE_INT,
+  CD_TYPE_UINT,
+  CD_TYPE_LONG,
+  CD_TYPE_ULONG,
+  CD_TYPE_FLOAT,
+  CD_TYPE_DOUBLE,
+  CD_TYPE_STRING,
+  CD_TYPE_POINTER
+};
+
+union _CDScalar {
+  int s_bool;
+  char s_char;
+  unsigned char s_uchar;
+  int s_int;
+  unsigned int s_uint;
+  long s_long;
+  unsigned long s_ulong;
+  float s_float;
+  double s_double;
+  char * s_string;
+  void * s_pointer;
+};
+
+#define CD_BOOL(x) ((CDScalar)((unsigned char)(x)))
+#define CD_CHAR(x) ((CDScalar)((char)(x)))
+#define CD_UCHAR(x) ((CDScalar)((unsigned char)(x)))
+#define CD_INT(x) ((CDScalar)((int)(x)))
+#define CD_UINT(x) ((CDScalar)((unsigned int)(x)))
+#define CD_LONG(x) ((CDScalar)((long)(x)))
+#define CD_ULONG(x) ((CDScalar)((unsigned long)(x)))
+#define CD_FLOAT(x) ((CDScalar)((float)(x)))
+#define CD_DOUBLE(x) ((CDScalar)((double)(x)))
+#define CD_STRING(x) ((CDScalar)((char *)(x)))
+#define CD_POINTER(x) ((CDScalar)((void *)(x)))
+
+struct _CDSet {
+  CDSet * prev;
+  CDSet * next;
+  int key;
+  CDScalar data;
+};
+
+struct _CDList {
+  CDList * prev;
+  CDList * next;
+  CDScalar data;
+};
+
+/* cd_type */
+
+CDScalar cd_scalar_invalid (void * ctx, CDScalarType type);
+int cd_scalar_eq (void * ctx, CDScalarType type, CDScalar d1, CDScalar d2);
+
+/* cd_set */
+
+#define CD_EMPTY_SET NULL
+#define CD_SINGLETON_SET(k,x) (&(((struct _CDSet){NULL, NULL, (k), (x)})))
+
+CDSet * cd_set_new (void * ctx);
+CDSet * cd_set_clone (void * ctx, CDSet * set, CDCloneFunc clone);
+CDSet * cd_set_clone_keys (void * ctx, CDSet * set);
+CDSet * cd_set_clone_with (void * ctx, CDSet * set, CDCloneWithFunc clone,
+                          void * with);
+int cd_set_contains (void * ctx, CDSet * set, int key);
+CDScalar cd_set_find (void * ctx, CDSet * set, int key);
+CDSet * cd_set_insert (void * ctx, CDSet * set, int key, CDScalar data);
+CDSet * cd_set_remove (void * ctx, CDSet * set, int key);
+CDSet * cd_set_replace (void * ctx, CDSet * set, int key, CDScalar data);
+int cd_set_is_empty (void * ctx, CDSet * set);
+int cd_set_is_singleton (void * ctx, CDSet * set);
+int cd_set_size (void * ctx, CDSet * set);
+CDSet * cd_set_destroy_with (void * ctx, CDSet * set, CDDestroyFunc destroy);
+CDSet * cd_set_free_all (void * ctx, CDSet * set);
+CDSet * cd_set_free (void * ctx, CDSet * set);
+
+
+/* cd_list */
+
+#define CD_EMPTY_LIST NULL
+#define CD_SINGLETON_LIST(x) (&(((struct _CDList){NULL, NULL, (x)})))
+
+CDList * cd_list_new (void * ctx);
+CDList * cd_list_copy (void * ctx, CDList * list);
+CDList * cd_list_clone (void * ctx, CDList * list, CDCloneFunc clone);
+CDList * cd_list_clone_with (void * ctx, CDList * list, CDCloneWithFunc clone,
+                            void * with);
+CDList * cd_list_last_item (void * ctx, CDList * list);
+CDScalar cd_list_last (void * ctx, CDList * list, CDScalarType type);
+CDList * cd_list_prepend (void * ctx, CDList * list, CDScalar data);
+CDList * cd_list_add_before_item (void * ctx, CDList * list, CDScalar data,
+                                 CDList * item);
+CDList * cd_list_add_after_item (void * ctx, CDList * list, CDScalar data,
+                                CDList * item);
+CDList * cd_list_add_before (void * ctx, CDList * list, CDScalarType type,
+                            CDScalar data, CDScalar before);
+CDList * cd_list_add_after (void * ctx, CDList * list, CDScalarType type,
+                           CDScalar data, CDScalar after);
+CDList * cd_list_append (void * ctx, CDList * list, CDScalar data);
+CDList * cd_list_find (void * ctx, CDList * list, CDScalarType type,
+                      CDScalar data);
+CDList * cd_list_find_first (void * ctx, CDList * list, CDScalarType type,
+                            CDCmpFunc f, CDScalar data);
+CDList * cd_list_find_last (void * ctx, CDList * list, CDScalarType type,
+                           CDCmpFunc f, CDScalar data);
+CDList * cd_list_insert (void * ctx, CDList * list, CDScalarType type,
+                        CDScalar data, CDCmpFunc f);
+CDList * cd_list_remove (void * ctx, CDList * list, CDScalarType type,
+                        CDScalar data);
+CDList * cd_list_join (void * ctx, CDList * l1, CDList * l2);
+int cd_list_length (void * ctx, CDList * list);
+int cd_list_is_empty (void * ctx, CDList * list);
+int cd_list_is_singleton (void * ctx, CDList * list);
+CDList * cd_list_destroy_with (void * ctx, CDList * list,
+                              CDDestroyFunc destroy);
+CDList * cd_list_free_all (void * ctx, CDList * list);
+CDList * cd_list_free (void * ctx, CDList * list);
+
+void cd_list_apply (void * ctx, CDList * list, CDFunc func);
+
+#endif /* __CTXDATA_H__ */
diff --git a/src/examples/1052.wav b/src/examples/1052.wav
new file mode 100644 (file)
index 0000000..e1132ee
Binary files /dev/null and b/src/examples/1052.wav differ
diff --git a/src/examples/909_cl.wav b/src/examples/909_cl.wav
new file mode 100644 (file)
index 0000000..3032a00
Binary files /dev/null and b/src/examples/909_cl.wav differ
diff --git a/src/examples/M1F1-int16-AFsp.wav b/src/examples/M1F1-int16-AFsp.wav
new file mode 100644 (file)
index 0000000..26a744b
Binary files /dev/null and b/src/examples/M1F1-int16-AFsp.wav differ
diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am
new file mode 100644 (file)
index 0000000..d9f29fd
--- /dev/null
@@ -0,0 +1,36 @@
+
+INCLUDES = -I$(top_srcdir)/src/ctxdata -I$(top_srcdir)/include -I../ctxdata
+
+if BUILD_MONITOR
+monitor_programs = noisedemo squaredemo mysquaredemo
+if HAVE_LIBSNDFILE1
+sndfile_programs = sndfiledemo simple_sndfiledemo
+endif
+
+endif
+
+noinst_PROGRAMS = cd_list_test $(monitor_programs) $(sndfile_programs)
+
+EXTRA_DIST = 909_cl.wav 1052.wav
+
+REMIX_LIBS = ../ctxdata/libctxdata.la ../libremix/libremix.la ../ctxdata/libctxdata.la -ldl
+
+cd_list_test_SOURCES = cd_list_test.c
+cd_list_test_LDADD = ../ctxdata/libctxdata.la
+
+noisedemo_SOURCES = noisedemo.c
+noisedemo_LDADD = $(REMIX_LIBS)
+
+squaredemo_SOURCES = squaredemo.c
+squaredemo_LDADD = $(REMIX_LIBS)
+
+mysquaredemo_SOURCES = simple_squaredemo.c
+mysquaredemo_LDADD = $(REMIX_LIBS)
+
+sndfiledemo_CFLAGS = -DSAMPLEDIR=\"$(srcdir)\"
+sndfiledemo_SOURCES = sndfiledemo.c
+sndfiledemo_LDADD = $(REMIX_LIBS) @SNDFILE_LIBS@
+
+simple_sndfiledemo_CFLAGS = -DSAMPLEDIR=\"$(srcdir)\"
+simple_sndfiledemo_SOURCES = simple_sndfiledemo.c
+simple_sndfiledemo_LDADD = $(REMIX_LIBS) @SNDFILE_LIBS@
diff --git a/src/examples/cd_list_test.c b/src/examples/cd_list_test.c
new file mode 100644 (file)
index 0000000..5ab6fd8
--- /dev/null
@@ -0,0 +1,107 @@
+#include <stdio.h>
+
+#include <ctxdata.h>
+
+void
+ildump (void * ctx, CDList * list)
+{
+  CDList * l;
+  int *i;
+
+  if (list == NULL) {
+    printf ("NULL");
+  } else {
+    for (l=list; l; l = l->next) {
+      i = (int *)l->data.s_pointer;
+      printf ("%d ", *i);
+    }
+  }
+
+  printf ("\n\t[length %d, %s, %s]\n", cd_list_length (ctx, list),
+    cd_list_is_empty (ctx, list) ? "empty" : "non-empty",
+    cd_list_is_singleton (ctx, list) ? "singleton" : "non-singleton");
+}
+
+int
+int_gt (void * ctx, void * d1, void * d2)
+{
+  int i1 = *(int *)d1;
+  int i2 = *(int *)d2;
+  return (i1 > i2);
+}
+
+void *
+int_clone (void * ctx, void * data)
+{
+  int * n = cd_malloc (sizeof (int));
+  *n = *(int *)data;
+  return (void *)n;
+}
+
+int
+main (int argc, char ** argv)
+{
+  CDList * list, * list2;
+  void * ctx;
+  int a=1, b=2, d=4, f=6, g=7, k=11;
+  int v=22, w=23;
+  int z=26;
+
+  ctx = NULL;
+
+  printf ("creating new list\n");
+  list = cd_list_new (ctx);
+  ildump (ctx, list);
+
+  printf ("appending %d\n", f);
+  list = cd_list_append (ctx, list, (CDScalar)(void *)(&f));
+  ildump (ctx, list);
+
+  printf ("appending %d\n", k);
+  list = cd_list_append (ctx, list, CD_POINTER(&k));
+  ildump (ctx, list);
+
+  printf ("inserting %d\n", g);
+  list = cd_list_insert (ctx, list, CD_TYPE_POINTER, CD_POINTER(&g), int_gt);
+  ildump (ctx, list);
+
+  printf ("inserting %d\n", w);
+  list = cd_list_insert (ctx, list, CD_TYPE_POINTER, CD_POINTER(&w), int_gt);
+  ildump (ctx, list);
+
+  printf ("inserting %d\n", z);
+  list = cd_list_insert (ctx, list, CD_TYPE_POINTER, CD_POINTER(&z), int_gt);
+  ildump (ctx, list);
+
+  printf ("inserting %d\n", b);
+  list = cd_list_insert (ctx, list, CD_TYPE_POINTER, CD_POINTER(&b), int_gt);
+  ildump (ctx, list);
+
+  printf ("prepending %d\n", a);
+  list = cd_list_prepend (ctx, list, CD_POINTER(&a));
+  ildump (ctx, list);
+
+  printf ("removing %d\n", g);
+  list = cd_list_remove (ctx, list, CD_TYPE_POINTER, CD_POINTER(&g));
+  ildump (ctx, list);
+
+  printf ("adding %d after %d\n", d, b);
+  list = cd_list_add_after (ctx, list, CD_TYPE_POINTER, CD_POINTER(&d),
+                            CD_POINTER(&b));
+  ildump (ctx, list);
+
+  printf ("adding %d before %d\n", v, w);
+  list = cd_list_add_before (ctx, list, CD_TYPE_POINTER, CD_POINTER(&v),
+                             CD_POINTER(&w));
+  ildump (ctx, list);
+
+  printf ("cloning list\n");
+  list2 = cd_list_clone (ctx, list, int_clone);
+  ildump (ctx, list2);
+
+  printf ("freeing cloned list\n");
+  list2 = cd_list_free_all (ctx, list2);
+  ildump (ctx, list2);
+
+  exit (0);
+}
diff --git a/src/examples/noisedemo.c b/src/examples/noisedemo.c
new file mode 100644 (file)
index 0000000..9c50577
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * noisedemo.c
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or
+ * implied warranty.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <remix/remix.h>
+
+int
+main (int argc, char ** argv)
+{
+  RemixEnv * env;
+  RemixDeck * deck;
+  RemixTrack * track;
+  RemixLayer * l1, * l2;
+  RemixPlugin * noise_plugin;
+  RemixBase * noise1, * noise2;
+  RemixCount length;
+  RemixMonitor * monitor;
+  int i;
+
+  env = remix_init ();
+  remix_set_channels (env, REMIX_MONO);
+
+  deck = remix_deck_new (env);
+  track = remix_track_new (env, deck);
+
+  noise_plugin = remix_find_plugin (env, "envstd::noise");
+
+  if (noise_plugin == NULL) {
+    fprintf (stderr, "Noise plugin not found. You must do 'make install' to install it.\n");
+    exit (1);
+  }
+
+  noise1 = remix_new (env, noise_plugin, NULL);
+  noise2 = remix_new (env, noise_plugin, NULL);
+
+  l1 = remix_layer_new_ontop (env, track, REMIX_TIME_SAMPLES);
+  for (i=0; i < 10; i++) {
+    remix_sound_new (env, noise1, l1, REMIX_SAMPLES(i*2500),
+                    REMIX_SAMPLES(1250));
+  }
+
+  length = remix_length (env, deck);
+
+  monitor = remix_monitor_new (env);
+
+  l2 = remix_layer_new_ontop (env, track, REMIX_TIME_SAMPLES);
+  remix_sound_new (env, monitor, l2, REMIX_SAMPLES(0), REMIX_SAMPLES(length));
+
+  remix_process (env, deck, length, RemixNone, RemixNone);
+
+  remix_purge (env);
+
+  exit (0);
+}
diff --git a/src/examples/simple_sndfiledemo.c b/src/examples/simple_sndfiledemo.c
new file mode 100755 (executable)
index 0000000..55bfec5
--- /dev/null
@@ -0,0 +1,61 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <remix/remix.h>
+
+int
+main (int argc, char ** argv)
+{
+  RemixEnv * env;
+  RemixDeck * deck;
+  RemixTrack * track;
+  RemixLayer * l1, * l2, * sample_layer;
+  RemixBase * sf1;
+  RemixBase * player;
+  RemixCount length;
+  RemixPlugin * sf_plugin;
+  RemixPlugin * player_plugin;
+
+  CDSet * sf_parms;
+  int i;
+  int sf_path_key;
+  RemixSound * sound;
+
+  env = remix_init ();
+  remix_set_samplerate(env, 8000);
+  printf( "remix sample rate: %f\n", remix_get_samplerate(env));
+  remix_set_channels (env, REMIX_STEREO);
+
+
+  //############################   Setting files for MIXING ########################
+  sf_plugin = remix_find_plugin (env, "builtin::sndfile_reader");   // keep the plugin list, no need to lookup everytime
+   if (sf_plugin == NULL) {
+     fprintf (stderr, "sf_plugin == NULL\n");
+     exit (1);
+   }
+  sf_parms = cd_set_new (env);
+  sf_path_key = remix_get_init_parameter_key (env, sf_plugin, "path");
+  sf_parms = cd_set_insert (env, sf_parms, sf_path_key, CD_STRING(SAMPLEDIR "/M1F1-int16-AFsp.wav"));
+  sf1 = remix_new (env, sf_plugin, sf_parms);
+
+  deck = remix_deck_new (env);
+  track = remix_track_new (env, deck);
+  l1 = remix_layer_new_ontop (env, track, REMIX_TIME_SAMPLES);
+  remix_sound_new (env, (RemixBase *)sf1, l1, REMIX_SAMPLES(7000), REMIX_SAMPLES(35000) );
+  //################################################################################
+
+   /////////////////////////////////  ADDING PLAYER ////////////////
+   sample_layer = remix_layer_new_ontop (env, track, REMIX_TIME_SAMPLES);
+   player_plugin = remix_find_plugin (env, "stream_player");   // keep the plugin list, no need to lookup everytime
+     if (player_plugin == NULL) {
+       fprintf (stderr, "player_plugin == NULL\n");
+       exit (1);
+     }
+    player =  remix_new (env, player_plugin, NULL);
+   remix_sound_new (env, (RemixBase *)player, sample_layer, REMIX_SAMPLES(0), REMIX_SAMPLES(35000));
+   //////////////////////////////////////////////////////////////////
+
+   remix_process (env, deck, 35000, RemixNone, RemixNone);
+   exit (0);
+}
diff --git a/src/examples/simple_squaredemo.c b/src/examples/simple_squaredemo.c
new file mode 100755 (executable)
index 0000000..00d4497
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * squaredemo.c
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or
+ * implied warranty.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <remix/remix.h>
+
+#define remix_add_sound_B(a,s,l,t1,t2) \
+  remix_sound_new ((a), (s), (l), REMIX_BEAT24S(t1), REMIX_BEAT24S(t2))
+
+#define BEAT 24
+#define HALF_BEAT 12
+#define QUARTER_BEAT 6
+#define EIGHTH_BEAT 3
+
+int
+main (int argc, char ** argv)
+{
+  RemixEnv * env;
+  RemixDeck * deck, * deck2;
+  RemixTrack * track, * track2, * track3, * track4;
+  RemixLayer * l1, * l2, * l3, * l4, * l5;
+  RemixSound * s;
+  RemixSquareTone * square1, * square2, * square3, * square4, * square5;
+  RemixPlugin * noise_plugin;
+  RemixBase * noise;
+  RemixEnvelope * env1, * env2, * env3;
+  RemixEnvelope * ge;
+  RemixCount length;
+  RemixMonitor * monitor;
+  int b = 0, b2 = 0, mb;
+
+  env = remix_init ();
+
+  remix_set_tempo (env, 500);
+  remix_set_channels (env, REMIX_STEREO);
+
+  square1 = remix_squaretone_new (env, 100.0);
+  remix_squaretone_add_channel (env, square1, 0 );
+
+  square2 = remix_squaretone_new (env, 200.0);
+  remix_squaretone_add_channel (env, square2, 0 );
+  remix_squaretone_add_channel (env, square2, 1 );
+
+  square3 = remix_squaretone_new (env, 385.0);
+  remix_squaretone_add_channel (env, square3, 0 );
+
+ // square4 = remix_squaretone_new (env, 231.0);
+ // square5 = remix_squaretone_new (env, 165.0);
+
+  monitor = remix_monitor_new (env);
+
+  deck = remix_deck_new (env);
+  track = remix_track_new (env, deck);
+  l1 = remix_layer_new_ontop (env, track, REMIX_TIME_BEAT24S);
+  s =  remix_sound_new (env, square1, l1, REMIX_BEAT24S(0), REMIX_BEAT24S(6));
+  s =  remix_sound_new (env, square2, l1, REMIX_BEAT24S(8), REMIX_BEAT24S(12));
+  s =  remix_sound_new (env, square3, l1, REMIX_BEAT24S(21), REMIX_BEAT24S(12));
+
+/*
+  remix_track_set_gain (env, track2, 0.6);
+
+ ge = remix_envelope_new (env, REMIX_ENVELOPE_LINEAR);
+ remix_envelope_set_timetype (env, ge, REMIX_TIME_SAMPLES);
+ remix_envelope_add_point (env, ge, REMIX_BEAT24S(2), 0.6);
+*/
+
+
+  length = remix_length (env, deck);
+
+  l2 = remix_layer_new_ontop (env, track, REMIX_TIME_SAMPLES);
+  s = remix_sound_new (env, monitor, l2, REMIX_SAMPLES(0), REMIX_SAMPLES(length));
+  //remix_sound_set_gain_envelope (env, s, ge);
+
+  remix_process (env, deck, length, RemixNone, RemixNone);
+
+  remix_purge (env);
+
+  exit (0);
+}
+
diff --git a/src/examples/sndfiledemo.c b/src/examples/sndfiledemo.c
new file mode 100644 (file)
index 0000000..54e3336
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * sndfiledemo.c
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or
+ * implied warranty.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <remix/remix.h>
+
+int
+main (int argc, char ** argv)
+{
+  RemixEnv * env;
+  RemixDeck * deck, * deck2;
+  RemixTrack * track, * track2, * track3;
+  RemixLayer * l1, * l2, * l3, * l4, * l5;
+  RemixBase * sf1, * sf2;
+  RemixSquareTone * square;
+  RemixCount length;
+  RemixMonitor * monitor;
+  RemixSound * sm;
+  RemixEnvelope * envelope;
+  RemixPlugin * gain_plugin;
+  RemixPlugin * sf_plugin;
+  RemixBase * gain;
+  CDSet * sf_parms;
+  int i;
+  int gain_key;
+  int sf_path_key;
+
+  env = remix_init ();
+  remix_set_tempo (env, 140);
+  remix_set_channels (env, REMIX_STEREO);
+
+#if 0
+  sf1 = remix_sndfile_new (env, "./1052.wav", 0);
+  sf2 = remix_sndfile_new (env, "./909_cl.wav", 0);
+#else
+  sf_plugin = remix_find_plugin (env, "builtin::sndfile_reader");
+  sf_parms = cd_set_new (env);
+  sf_path_key = remix_get_init_parameter_key (env, sf_plugin, "path");
+  sf_parms = cd_set_insert (env, sf_parms, sf_path_key, CD_STRING(SAMPLEDIR "/1052.wav"));
+  if (sf_plugin == NULL) {
+    fprintf (stderr, "sf_plugin == NULL\n");
+    exit (1);
+  }
+  sf1 = remix_new (env, sf_plugin, sf_parms);
+  sf_parms = cd_set_replace (env, sf_parms, 1, CD_STRING(SAMPLEDIR "/909_cl.wav"));
+  sf2 = remix_new (env, sf_plugin, sf_parms);
+#endif
+  square = remix_squaretone_new (env, 220);
+  monitor = remix_monitor_new (env);
+
+#if 0
+  gain = remix_gain_new (env);
+#else
+  gain_plugin = remix_find_plugin (env, "builtin::gain");
+  gain = remix_new (env, gain_plugin, NULL);
+#endif
+
+  envelope = remix_envelope_new (env, REMIX_ENVELOPE_LINEAR);
+  remix_envelope_set_timetype (env, envelope, REMIX_TIME_BEAT24S);
+  remix_envelope_add_point (env, envelope, REMIX_BEAT24S(0), 0.1);
+  remix_envelope_add_point (env, envelope, REMIX_BEAT24S(48), 1.3);
+  remix_envelope_add_point (env, envelope, REMIX_BEAT24S(96), 0.1);
+
+#if 0
+  remix_gain_set_envelope (env, gain, env);
+#else
+  gain_key = remix_get_parameter_key (env, gain, "Gain envelope");
+  printf ("got gain key: %d\n", gain_key);
+  remix_set_parameter (env, gain, gain_key, (CDScalar)((void *)envelope));
+#endif
+
+  deck = remix_deck_new (env);
+  track = remix_track_new (env, deck);
+
+  l1 = remix_layer_new_ontop (env, track, REMIX_TIME_BEAT24S);
+  for (i=0; i < 4; i++) {
+    remix_sound_new (env, (RemixBase *)sf1, l1, REMIX_BEAT24S(i*24), REMIX_BEAT24S(18));
+  }
+
+  track2 = remix_track_new (env, deck);
+  l2 = remix_layer_new_ontop (env, track2, REMIX_TIME_BEAT24S);
+  for (i=0; i < 16; i++) {
+    remix_sound_new (env, (RemixBase *)sf2, l2, REMIX_BEAT24S(i*6), REMIX_BEAT24S(4));
+  }
+
+  deck2 = remix_deck_new (env);
+  track3 = remix_track_new (env, deck2);
+
+  l3 = remix_layer_new_ontop (env, track3, REMIX_TIME_BEAT24S);
+  remix_sound_new (env, (RemixBase *)deck, l3, REMIX_BEAT24S(0), REMIX_BEAT24S(96));
+
+#if 1
+  l4 = remix_layer_new_ontop (env, track3, REMIX_TIME_BEAT24S);
+  remix_sound_new (env, (RemixBase *)gain, l4, REMIX_BEAT24S(0), REMIX_BEAT24S(96));
+#endif
+
+  l5 = remix_layer_new_ontop (env, track3, REMIX_TIME_SAMPLES);
+
+  length = remix_length (env, (RemixBase *)deck);
+  sm = remix_sound_new (env, monitor, l5, REMIX_SAMPLES(0), REMIX_SAMPLES(length));
+
+  printf ("deck: %p\ttrack: %p\tl1: %p\nl3: %p\tmonitor: %p\n",
+          deck, track, l1, l3, monitor);
+
+  remix_process (env, deck2, length, RemixNone, RemixNone);
+
+  remix_set_tempo (env, 105);
+  length = remix_length (env, (RemixBase *)deck);
+  remix_sound_set_duration (env, sm, REMIX_SAMPLES(length));
+  remix_seek (env, deck2, 0, SEEK_SET);
+  remix_process (env, deck2, length, RemixNone, RemixNone);
+
+  remix_set_tempo (env, 168);
+  length = remix_length (env, (RemixBase *)deck);
+  remix_sound_set_duration (env, sm, REMIX_SAMPLES(length));
+  remix_seek (env, deck2, 0, SEEK_SET);
+  remix_process (env, deck2, length, RemixNone, RemixNone);
+
+  remix_purge (env);
+
+  exit (0);
+}
diff --git a/src/examples/squaredemo.c b/src/examples/squaredemo.c
new file mode 100644 (file)
index 0000000..5fce454
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * squaredemo.c
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or
+ * implied warranty.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <remix/remix.h>
+
+#define remix_add_sound_B(a,s,l,t1,t2) \
+  remix_sound_new ((a), (s), (l), REMIX_BEAT24S(t1), REMIX_BEAT24S(t2))
+
+#define BEAT 24
+#define HALF_BEAT 12
+#define QUARTER_BEAT 6
+#define EIGHTH_BEAT 3
+
+int
+main (int argc, char ** argv)
+{
+  RemixEnv * env;
+  RemixDeck * deck, * deck2;
+  RemixTrack * track, * track2, * track3, * track4;
+  RemixLayer * l1, * l2, * l3, * l4, * l5;
+  RemixSound * s;
+  RemixSquareTone * square1, * square2, * square3, * square4, * square5;
+  RemixPlugin * noise_plugin;
+  RemixBase * noise;
+  RemixEnvelope * env1, * env2, * env3;
+  RemixEnvelope * be1, * be2, * be3;
+  RemixCount length;
+  RemixMonitor * monitor;
+  int b = 0, b2 = 0, mb;
+
+  env = remix_init ();
+
+  remix_set_tempo (env, 160);
+  remix_set_channels (env, REMIX_STEREO);
+
+  square1 = remix_squaretone_new (env, 220.0);
+  square2 = remix_squaretone_new (env, 440.0);
+  square3 = remix_squaretone_new (env, 385.0);
+  square4 = remix_squaretone_new (env, 231.0);
+  square5 = remix_squaretone_new (env, 165.0);
+
+  noise_plugin = remix_find_plugin (env, "builtin::noise");
+  noise = remix_new (env, noise_plugin, NULL);
+
+  monitor = remix_monitor_new (env);
+
+  deck = remix_deck_new (env);
+
+#if 1
+  track = remix_track_new (env, deck);
+
+  l1 = remix_layer_new_ontop (env, track, REMIX_TIME_BEAT24S);
+  remix_add_sound_B (env, square1, l1, b, BEAT); b += BEAT;
+#if 1
+  remix_add_sound_B (env, square2, l1, b, QUARTER_BEAT); b += HALF_BEAT;
+  remix_add_sound_B (env, square2, l1, b, HALF_BEAT); b += HALF_BEAT;
+  remix_add_sound_B (env, square1, l1, b, HALF_BEAT); b += HALF_BEAT;
+  remix_add_sound_B (env, square2, l1, b, QUARTER_BEAT); b += HALF_BEAT;
+  remix_add_sound_B (env, square3, l1, b, HALF_BEAT); b += HALF_BEAT;
+  remix_add_sound_B (env, square2, l1, b, HALF_BEAT); b += HALF_BEAT;
+#endif
+#endif
+
+#if 1
+#if 1
+  track2 = remix_track_new (env, deck);
+  remix_track_set_gain (env, track2, 0.6);
+#else
+  track2 = track;
+#endif
+  l2 = remix_layer_new_ontop (env, track2, REMIX_TIME_BEAT24S);
+  s = remix_add_sound_B (env, square4, l2, b2, HALF_BEAT); b2 += BEAT;
+
+  be1 = remix_envelope_new (env, REMIX_ENVELOPE_LINEAR);
+  remix_envelope_set_timetype (env, be1, REMIX_TIME_BEAT24S);
+  remix_envelope_add_point (env, be1, REMIX_BEAT24S(0), 0.9);
+  remix_sound_set_blend_envelope (env, s, be1);
+
+#if 1
+  s = remix_add_sound_B (env, square5, l2, b2, HALF_BEAT); b2 += BEAT;
+  be2 = remix_envelope_new (env, REMIX_ENVELOPE_LINEAR);
+  remix_envelope_set_timetype (env, be2, REMIX_TIME_BEAT24S);
+  remix_envelope_add_point (env, be2, REMIX_BEAT24S(0), 0.6);
+  remix_sound_set_blend_envelope (env, s, be2);
+
+  s = remix_add_sound_B (env, square4, l2, b2, BEAT); b2 += 48;
+  be3 = remix_envelope_new (env, REMIX_ENVELOPE_LINEAR);
+  remix_envelope_set_timetype (env, be3, REMIX_TIME_BEAT24S);
+  remix_envelope_add_point (env, be3, REMIX_BEAT24S(0), 0.8);
+  remix_sound_set_blend_envelope (env, s, be3);
+#endif
+#endif
+
+#if 1
+  track4 = remix_track_new (env, deck);
+  remix_track_set_gain (env, track4, 0.1);
+  l5 = remix_layer_new_ontop (env, track4, REMIX_TIME_BEAT24S);
+  remix_add_sound_B (env, noise, l5, 0, b);
+#endif
+
+  mb = MAX (b, b2);
+
+  length = remix_length (env, deck);
+  printf ("deck has length %ld\n", length);
+
+  deck2 = remix_deck_new (env);
+  track3 = remix_track_new (env, deck2);
+  l3 = remix_layer_new_ontop (env, track3, REMIX_TIME_BEAT24S);
+
+  s = remix_add_sound_B (env, deck, l3, 0, mb);
+
+#if 1
+  env1 = remix_envelope_new (env, REMIX_ENVELOPE_LINEAR);
+  remix_envelope_set_timetype (env, env1, REMIX_TIME_BEAT24S);
+  remix_envelope_add_point (env, env1, REMIX_BEAT24S(0), 0.0);
+  remix_envelope_add_point (env, env1, REMIX_BEAT24S(mb), 0.9);
+  remix_sound_set_gain_envelope (env, s, env1);
+#endif
+
+  s = remix_add_sound_B (env, deck, l3, mb, mb);
+
+#if 1
+  env2 = remix_envelope_new (env, REMIX_ENVELOPE_LINEAR);
+  remix_envelope_set_timetype (env, env2, REMIX_TIME_BEAT24S);
+  remix_envelope_add_point (env, env2, REMIX_BEAT24S(0), 0.9);
+  remix_sound_set_gain_envelope (env, s, env2);
+#endif
+
+  s = remix_add_sound_B (env, deck, l3, 2*mb, mb);
+
+#if 1
+  env3 = remix_envelope_new (env, REMIX_ENVELOPE_LINEAR);
+  remix_envelope_set_timetype (env, env3, REMIX_TIME_BEAT24S);
+  remix_envelope_add_point (env, env3, REMIX_BEAT24S(0), 0.9);
+  remix_envelope_add_point (env, env3, REMIX_BEAT24S(mb), 0.0);
+  remix_sound_set_gain_envelope (env, s, env3);
+#endif
+
+  length = remix_length (env, deck2);
+
+  l4 = remix_layer_new_ontop (env, track3, REMIX_TIME_SAMPLES);
+  remix_sound_new (env, monitor, l4, REMIX_SAMPLES(0), REMIX_SAMPLES(length));
+
+  printf ("deck: %p\ttrack: %p\tl1: %p\ttrack2: %p\tl2: %p\n",
+          deck, track, l1, track2, l2);
+  printf ("deck2: %p\ttrack3: %p\tl3: %p\tl4: %p\n", deck2, track3, l3, l4);
+  printf ("square1: %p\tsquare2: %p\tsquare3: %p\nsquare4: %p\tsquare5: %p\n",
+          square1, square2, square3, square4, square5);
+  printf ("monitor: %p\n", monitor);
+
+  remix_process (env, deck2, length, RemixNone, RemixNone);
+
+  remix_purge (env);
+
+  exit (0);
+}
diff --git a/src/libremix/Makefile.am b/src/libremix/Makefile.am
new file mode 100644 (file)
index 0000000..892bfb7
--- /dev/null
@@ -0,0 +1,40 @@
+INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/include/remix $(SNDFILE_CFLAGS) -I$(top_srcdir)/src/ctxdata
+
+lib_LTLIBRARIES = libremix.la
+
+if BUILD_MONITOR
+monitor_sources = remix_monitor.c
+endif
+
+if HAVE_LIBSNDFILE1
+sndfile_sources = remix_sndfile.c
+endif
+
+libremix_la_SOURCES = \
+       $(monitor_sources) \
+       $(sndfile_sources) \
+       remix_base.c \
+       remix_channel.c \
+       remix_channelset.c \
+       remix_chunk.c \
+       remix_context.c \
+       remix_debug.c \
+       remix_deck.c \
+       remix_envelope.c \
+       remix_error.c \
+       remix_gain.c \
+       remix_layer.c \
+       remix_meta.c \
+       remix_null.c \
+       remix_pcm.c \
+       remix_plugin.c \
+       remix_sound.c \
+       remix_squaretone.c \
+       remix_stream.c \
+       remix_time.c \
+       remix_track.c \
+       remix_private.h \
+       remix_compat.h
+
+libremix_la_LIBADD = @SNDFILE_LIBS@
+
diff --git a/src/libremix/remix_base.c b/src/libremix/remix_base.c
new file mode 100644 (file)
index 0000000..1b27484
--- /dev/null
@@ -0,0 +1,662 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixBase: A generic interface for sound generation and processing.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#include <string.h>
+
+#define __REMIX__
+#include "remix.h"
+
+
+RemixBase *
+remix_new (RemixEnv * env, RemixPlugin * plugin, CDSet * parameters)
+{
+  RemixBase * base;
+
+  if (plugin == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  base = remix_base_new (env);
+
+  if (base == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  base->plugin = plugin;
+
+  if (plugin->init != NULL) {
+    if (plugin->init (env, base, parameters) == RemixNone) {
+      remix_destroy (env, base);
+      return RemixNone;
+    }
+  }
+
+  return base;
+}
+
+CDSet *
+remix_suggest (RemixEnv * env, RemixPlugin * plugin, CDSet * parameters)
+{
+  if (plugin == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  if (!plugin->suggest) {
+    /* XXX: should remix_set_error: is NOOP appropriate ?? */
+    return RemixNone;
+  }
+
+  return plugin->suggest (env, plugin, parameters, plugin->plugin_data);
+}
+
+static int
+remix_parameter_scheme_get_key (RemixEnv * env, CDSet * scheme_set, char * name)
+{
+  CDSet * s;
+  RemixParameterScheme * scheme;
+
+  for (s = scheme_set; s; s = s->next) {
+    scheme = (RemixParameterScheme *)s->data.s_pointer;
+    if (!strcmp (scheme->name, name)) return s->key;
+  }
+
+  remix_set_error (env, REMIX_ERROR_NOENTITY);
+
+  return -1;
+}
+
+int
+remix_get_init_parameter_key (RemixEnv * env, RemixPlugin * plugin, char * name)
+{
+  if (plugin == RemixNone) {
+    remix_dprintf ("[remix_get_init_parameter_key] plugin == RemixNone\n");
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  return remix_parameter_scheme_get_key (env, plugin->init_scheme, name);
+}
+
+int
+remix_get_parameter_key (RemixEnv * env, RemixBase * base, char * name)
+{
+  if (base == RemixNone) {
+    remix_dprintf ("[remix_get_parameter_key] base == RemixNone\n");
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  if (base->plugin == RemixNone) {
+    remix_dprintf ("[remix_get_parameter_key] base->plugin == RemixNone\n");
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  return remix_parameter_scheme_get_key (env, base->plugin->process_scheme, name);
+}
+
+RemixParameter
+remix_set_parameter (RemixEnv * env, RemixBase * base, int key,
+                   RemixParameter parameter)
+{
+  if (base == RemixNone) {
+    remix_dprintf ("[remix_set_parameter] base == RemixNone\n");
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return (RemixParameter)-1;
+  }
+
+  remix_dprintf ("[remix_set_parameter] base %p, [%d] ==> %p\n", base, key,
+                 parameter.s_pointer);
+  base->parameters = cd_set_replace (env, base->parameters, key, parameter);
+  return parameter;
+}
+
+RemixParameter
+remix_get_parameter (RemixEnv * env, RemixBase * base, int key)
+{
+  RemixParameter p;
+
+  if (base == RemixNone) {
+    remix_dprintf ("[remix_get_parameter] base == RemixNone\n");
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return (RemixParameter)-1;
+  }
+
+  p = cd_set_find (env, base->parameters, key);
+  remix_dprintf ("[remix_get_parameter] base %p, [%d] == %p\n", base, key,
+                 p.s_pointer);
+  return p;
+}
+
+RemixParameterType
+remix_get_parameter_type (RemixEnv * env, RemixBase * base, int key)
+{
+  RemixPlugin * plugin;
+  CDScalar k;
+  RemixParameterScheme * scheme;
+
+  if (base == RemixNone) {
+    remix_dprintf ("[remix_get_parameter_type] base == RemixNone\n");
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  plugin = base->plugin;
+
+  if (plugin == RemixNone) {
+    remix_dprintf ("[remix_get_parameter_type] base->plugin == RemixNone\n");
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  k = cd_set_find (env, plugin->process_scheme, key);
+  scheme = (RemixParameterScheme *)k.s_pointer;
+
+  if (scheme == RemixNone) {
+    remix_dprintf ("[remix_get_parameter_type] scheme == RemixNone\n");
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  return scheme->type;
+}
+
+RemixBase *
+remix_base_new_subclass (RemixEnv * env, size_t size)
+{
+  RemixBase * base = remix_malloc (size);
+  _remix_context_copy (env, &base->context_limit);
+  _remix_register_base (env, base);
+  return base;
+}
+
+RemixBase *
+remix_base_new (RemixEnv * env)
+{
+  return remix_base_new_subclass (env, sizeof (struct _RemixBase));
+}
+
+RemixCount
+remix_base_get_mixlength (RemixEnv * env, RemixBase * base)
+{
+  if (base == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  return _remix_base_get_mixlength (env, base);
+}
+
+RemixSamplerate
+remix_base_get_samplerate (RemixEnv * env, RemixBase * base)
+{
+  if (base == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  return _remix_base_get_samplerate (env, base);
+}
+
+RemixTempo
+remix_base_get_tempo (RemixEnv * env, RemixBase * base)
+{
+  if (base == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  return _remix_base_get_tempo (env, base);
+}
+
+CDSet *
+remix_base_get_channels (RemixEnv * env, RemixBase * base)
+{
+  if (base == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  return _remix_base_get_channels (env, base);
+}
+
+void *
+remix_base_set_instance_data (RemixEnv * env, RemixBase * base, void * data)
+{
+  if (base == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  return _remix_set_instance_data (env, base, data);
+}
+
+void *
+remix_base_get_instance_data (RemixEnv * env, RemixBase * base)
+{
+  if (base == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  return _remix_get_instance_data (env, base);
+}
+
+int
+remix_base_has_samplerate (RemixEnv * env, RemixBase * base)
+{
+  RemixSamplerate asr, bsr;
+
+  asr = remix_get_samplerate (env);
+  bsr = _remix_base_get_samplerate (env, base);
+
+  return (asr == bsr);
+}
+
+int
+remix_base_has_tempo (RemixEnv * env, RemixBase * base)
+{
+  RemixTempo at, bt;
+
+  at = remix_get_tempo (env);
+  bt = _remix_base_get_tempo (env, base);
+
+  return (at == bt);
+}
+
+int
+remix_base_encompasses_mixlength (RemixEnv * env, RemixBase * base)
+{
+  RemixCount aml, bml;
+
+  aml = remix_get_mixlength (env);
+  bml = _remix_base_get_mixlength (env, base);
+
+  return (aml < bml);
+}
+
+int
+remix_base_encompasses_channels (RemixEnv * env, RemixBase * base)
+{
+  CDSet * s, * as, * bs;
+  CDScalar k;
+
+  as = remix_get_channels (env);
+  bs = _remix_base_get_channels (env, base);
+
+  for (s = as; s; s = s->next) {
+    k = cd_set_find (env, bs, s->key);
+    if (k.s_pointer == NULL) return 0;
+  }
+
+  return 1;
+}
+
+RemixMethods *
+remix_base_set_methods (RemixEnv * env, RemixBase * base, RemixMethods * methods)
+{
+  RemixMethods * old = base->methods;
+  _remix_set_methods (env, base, methods);
+  return old;
+}
+
+RemixMethods *
+remix_base_get_methods (RemixEnv * env, RemixBase * base)
+{
+  return _remix_get_methods (env, base);
+}
+
+RemixPlugin *
+remix_base_set_plugin (RemixEnv * env, RemixBase * base, RemixPlugin * plugin)
+{
+  RemixPlugin * old = base->plugin;
+  _remix_set_plugin (env, base, plugin);
+  return old;
+}
+
+RemixPlugin *
+remix_base_get_plugin (RemixEnv * env, RemixBase * base)
+{
+  return _remix_get_plugin (env, base);
+}
+
+RemixBase *
+remix_clone_subclass (RemixEnv * env, RemixBase * base)
+{
+  if (!base) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return NULL;
+  }
+  if (!base->methods || !base->methods->clone) {
+    remix_set_error (env, REMIX_ERROR_INVALID);
+    return NULL;
+  }
+  return _remix_clone (env, base);
+}
+
+int
+remix_destroy (RemixEnv * env, RemixBase * base)
+{
+  if (!base) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  _remix_unregister_base (env, base);
+
+  if (!base->methods || !base->methods->destroy) {
+    remix_set_error (env, REMIX_ERROR_INVALID);
+    return -1;
+  }
+  return _remix_destroy (env, base);
+}
+
+int
+remix_destroy_list (RemixEnv * env, CDList * list)
+{
+  cd_list_destroy_with (env, list, (CDDestroyFunc)remix_destroy);
+  return 0;
+}
+
+/*
+ * Prepare the methods for process, seek and length calls.
+ *
+ * "Prepare" means to make sure the base has enough internal buffers
+ * to deal with the current context (sample rate, mixlength).
+ *
+ * If the methods has a ready() function, that is checked first. If it
+ * does not have a ready() function, it is assumed to always be ready.
+ */
+RemixBase *
+remix_prepare (RemixEnv * env, RemixBase * base)
+{
+  int is_ready = 0;
+
+  if (!base) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return NULL;
+  }
+  if (base->methods && base->methods->prepare) {
+    if (base->methods->ready) {
+      is_ready = base->methods->ready (env, base);
+    }
+
+    _remix_context_merge (env, &base->context_limit);
+
+    if (!is_ready) base =_remix_prepare (env, base);
+  }
+
+  return base;
+}
+
+RemixCount
+remix_process_fast (RemixEnv * env, RemixBase * base, RemixCount count,
+                  RemixStream * input, RemixStream * output)
+{
+  RemixCount n;
+
+  if (!base) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+  if (!base->methods || !base->methods->process) {
+    remix_set_error (env, REMIX_ERROR_INVALID);
+    return -1;
+  }
+
+  remix_get_meta_text (env, base);
+
+  n = _remix_process (env, base, count, input, output);
+  if (n > 0) base->offset += n;
+  return n;
+}
+
+RemixCount
+remix_process (RemixEnv * env, RemixBase * base, RemixCount count,
+             RemixStream * input, RemixStream * output)
+{
+  RemixCount processed;
+  RemixCount n;
+  RemixError error;
+  char * str;
+
+  remix_debug_down ();
+
+  processed = remix_process_fast (env, base, count, input, output);
+
+  if (processed == -1) {
+    error = remix_last_error (env);
+    str = remix_error_string (env, error);
+    remix_dprintf ("*** ERROR in remix_process: %s\n", str);
+    switch (error) {
+    case REMIX_ERROR_NOOP:
+      n = remix_stream_write (env, output, count, input);
+      if (n > 0) {
+       base->offset += n;
+       processed = n;
+      }
+      break;
+    case REMIX_ERROR_SILENCE:
+      n = remix_stream_write0 (env, output, count);
+      if (n > 0) {
+       base->offset += n;
+       processed = n;
+      }
+      break;
+    default: break;
+    }
+  }
+
+  remix_debug_up ();
+
+  return processed;
+}
+
+RemixCount
+remix_length (RemixEnv * env, RemixBase * base)
+{
+  if (!base) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+  if (!base->methods || !base->methods->length) {
+    remix_set_error (env, REMIX_ERROR_INVALID);
+    return -1;
+  }
+  return _remix_length (env, base);
+}
+
+RemixCount
+remix_seek (RemixEnv * env, RemixBase * base, RemixCount offset, int whence)
+{
+  RemixCount new_offset, len;
+
+  if (!base) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  new_offset = base->offset;
+
+  switch (whence) {
+  case SEEK_SET: new_offset = offset; break;
+  case SEEK_CUR: new_offset += offset; break;
+  case SEEK_END:
+    len = remix_length (env, base);
+    if (len == -1) return -1;
+    new_offset = len + offset;
+    break;
+  default:
+    remix_set_error (env, REMIX_ERROR_INVALID);
+    return -1;
+    break;
+  }
+
+  if (new_offset == base->offset) return new_offset;
+
+  remix_dprintf ("SEEK %p @ %ld\n", base, new_offset);
+
+  if (base->methods && base->methods->seek)
+    base->offset = base->methods->seek (env, base, new_offset);
+  else
+    base->offset = new_offset;
+
+  return base->offset;
+}
+
+RemixCount
+remix_tell (RemixEnv * env, RemixBase * base)
+{
+  if (!base) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+  return base->offset;
+}
+
+int
+remix_flush (RemixEnv * env, RemixBase * base)
+{
+  if (!base) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+  if (!base->methods || !base->methods->flush) {
+    remix_set_error (env, REMIX_ERROR_INVALID);
+    return -1;
+  }
+  return _remix_flush (env, base);
+}
+
+RemixMetaText *
+remix_get_meta_text (RemixEnv * env, RemixBase * base)
+{
+  RemixPlugin * plugin = base->plugin;
+  return (plugin ? plugin->metatext : NULL);
+}
+
+RemixMetaText *
+remix_set_meta_text (RemixEnv * env, RemixBase * base, RemixMetaText * mt)
+{
+  RemixPlugin * plugin;
+  RemixMetaText * old;
+
+  if (base == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  plugin = base->plugin;
+  if (plugin == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  old = plugin->metatext;
+  plugin->metatext = mt;
+  return old;
+}
+
+int
+remix_is_writeable (RemixEnv * env, RemixBase * base)
+{
+  RemixPlugin * plugin;
+
+  if (base == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  plugin = base->plugin;
+  if (plugin == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  return (plugin->flags & REMIX_PLUGIN_WRITEABLE);
+}
+
+int
+remix_is_seekable (RemixEnv * env, RemixBase * base)
+{
+  RemixPlugin * plugin;
+
+  if (base == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  plugin = base->plugin;
+  if (plugin == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  return (plugin->flags & REMIX_PLUGIN_SEEKABLE);
+}
+
+int
+remix_is_cacheable (RemixEnv * env, RemixBase * base)
+{
+  RemixPlugin * plugin;
+
+  if (base == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  plugin = base->plugin;
+  if (plugin == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  return (plugin->flags & REMIX_PLUGIN_CACHEABLE);
+}
+
+int
+remix_is_causal (RemixEnv * env, RemixBase * base)
+{
+  RemixPlugin * plugin;
+
+  if (base == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  plugin = base->plugin;
+  if (plugin == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  return (plugin->flags & REMIX_PLUGIN_CAUSAL);
+}
diff --git a/src/libremix/remix_channel.c b/src/libremix/remix_channel.c
new file mode 100644 (file)
index 0000000..81da965
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixChannel: An indexed, sparse, monophonic PCM data container.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ *
+ * Description
+ * -----------
+ *
+ * A channel contains a sequence of chunks which contain raw PCM data.
+ *
+ * Channels are named, such that when streams are mixed together their
+ * correspondingly named channels are mixed together.
+ *
+ * A channel is indexed by sample count. When reading a channel, all
+ * index points for which no chunk is defined are defined as zero. Writing
+ * to a channel stops early if no chunk is available at a required point.
+ *
+ * If two or more chunks overlap, the chunk with the latest start index
+ * is always used for both reading and writing data values for the region
+ * of overlap.
+ *
+ * Invariants
+ * ----------
+ *
+ * A channel must be contained within a stream.
+ */
+
+#define __REMIX__
+#include "remix.h"
+
+/* RemixChannel */
+
+RemixChannel *
+remix_channel_new (RemixEnv * env)
+{
+  RemixChannel * c;
+
+  c = (RemixChannel *) remix_malloc (sizeof (struct _RemixChannel));
+
+  c->chunks = cd_list_new (env);
+  c->_current_offset = 0;
+  c->_current_chunk = RemixNone;
+
+  return c;
+}
+
+RemixChannel *
+remix_channel_clone (RemixEnv * env, RemixChannel * channel)
+{
+  RemixChannel * new_channel = remix_channel_new (env);
+  new_channel->chunks = cd_list_clone (env, channel->chunks,
+                                      (CDCloneFunc)remix_chunk_clone);
+  return new_channel;
+}
+
+int
+remix_channel_destroy (RemixEnv * env, RemixBase * base)
+{
+  RemixChannel * channel = (RemixChannel *)base;
+  CDList * l;
+
+  for (l = channel->chunks; l; l = l->next) {
+    remix_chunk_free (env, (RemixChunk *)l->data.s_pointer);
+  }
+
+  cd_list_free (env, channel->chunks);
+  remix_free (channel);
+  return 0;
+}
+
+RemixChunk *
+remix_channel_add_chunk (RemixEnv * env, RemixChannel * channel,
+                        RemixChunk * chunk)
+{
+  channel->chunks = cd_list_insert (env, channel->chunks, CD_TYPE_POINTER,
+                                    CD_POINTER(chunk),
+                                   (CDCmpFunc)remix_chunk_later);
+  return chunk;
+}
+
+RemixChunk *
+remix_channel_add_new_chunk (RemixEnv * env, RemixChannel * channel,
+                            RemixCount offset, RemixCount length)
+{
+  RemixChunk * chunk = remix_chunk_new (env, offset, length);
+  return remix_channel_add_chunk (env, channel, chunk);
+}
+
+void
+remix_channel_remove_chunk (RemixEnv * env, RemixChannel * channel,
+                           RemixChunk * chunk)
+{
+  channel->chunks = cd_list_remove (env, channel->chunks, CD_TYPE_POINTER,
+                                   CD_POINTER(chunk));
+}
+
+RemixChunk *
+remix_channel_find_chunk_before (RemixEnv * env, RemixChannel * channel,
+                                RemixCount index)
+{
+  CDList * l;
+  RemixChunk * u, * up = RemixNone;
+
+  for (l = channel->chunks; l; l = l->next) {
+    u = (RemixChunk *)l->data.s_pointer;
+    if (u->start_index > index) return up;
+    up = u;
+  }
+
+  return up;
+}
+
+/*
+ * remix_chunk_item_valid_length (l)
+ *
+ * Returns the length for which the chunk item 'l' is valid. The valid
+ * length of a chunk item in a channel is defined as the minimum of
+ * (the chunk's actual length) and (the difference between the offset
+ * of the chunk and the offset of the following chunk). ie. if the
+ * chunk is followed by another chunk that cuts it off early, the valid
+ * length is the difference between the two chunk offsets. Crikey, email
+ * me if you're confused.
+ */
+static RemixCount
+remix_chunk_item_valid_length (CDList * l)
+{
+  CDList * ln = l->next;
+  RemixChunk * u = (RemixChunk *)l->data.s_pointer, * un;
+
+  if (ln == RemixNone) {
+    return u->length;
+  } else {
+    un = (RemixChunk *)ln->data.s_pointer;
+    return MIN (u->length, un->start_index - u->start_index);
+  }
+}
+
+RemixChunk *
+remix_channel_get_chunk_at (RemixEnv * env, RemixChannel * channel,
+                           RemixCount offset)
+{
+  CDList * l;
+  RemixChunk * u;
+  RemixCount vl; /* valid length */
+
+  for (l = channel->chunks; l; l = l->next) {
+    u = (RemixChunk *)l->data.s_pointer;
+    vl = remix_chunk_item_valid_length (l);
+    if (u->start_index <= offset && u->start_index + vl > offset) {
+      /* chunk validly spans offset: return it */
+      return u;
+    }
+  }
+
+  /* No chunks found spanning offset */
+  return RemixNone;
+}
+
+CDList *
+remix_channel_get_chunk_item_at (RemixChannel * channel, RemixCount offset)
+{
+  CDList * l;
+  RemixChunk * u;
+  RemixCount vl; /* valid length */
+
+  for (l = channel->chunks; l; l = l->next) {
+    u = (RemixChunk *)l->data.s_pointer;
+    vl = remix_chunk_item_valid_length (l);
+    if (u->start_index <= offset && u->start_index + vl > offset) {
+      /* chunk validly spans offset: return its item */
+      return l;
+    }
+  }
+
+  /* No chunks found spanning offset */
+  return RemixNone;
+}
+
+CDList *
+remix_channel_get_chunk_item_after (RemixChannel * channel, RemixCount offset)
+{
+  CDList * l;
+  RemixChunk * u;
+
+  for (l = channel->chunks; l; l = l->next) {
+    u = (RemixChunk *)l->data.s_pointer;
+    if (u->start_index >= offset) return l;
+  }
+
+  return RemixNone;
+}
+
+RemixCount
+remix_channel_write0 (RemixEnv * env, RemixChannel * channel, RemixCount length)
+{
+  CDList * l = channel->_current_chunk;
+  RemixChunk * u;
+  RemixCount remaining = length, n, vl;
+  RemixCount offset = channel->_current_offset;
+
+  while (remaining > 0) {
+    if (l == RemixNone) break; /* No more chunks */
+
+    u = (RemixChunk *)l->data.s_pointer;
+
+    if (u->start_index > offset) { /* skip ahead to start of next chunk */
+      n = MIN (remaining, u->start_index - offset);
+      offset += n;
+      remaining -= n;
+    }
+
+    if (remaining > 0) {
+      vl = remix_chunk_item_valid_length (l);
+      n = _remix_chunk_clear_region (env, u, offset, MIN(remaining, vl),
+                                 0, NULL);
+      offset += n;
+      remaining -= n;
+    }
+
+    l = l->next;
+  }
+
+  channel->_current_chunk = l;
+  channel->_current_offset += length;
+
+  return length;
+}
+
+/*
+ * remix_channel_chunkfuncify (env, channel, count, func, data)
+ *
+ * Apply the RemixChunkFunc func to 'count' samples from consecutive chunks
+ * of 'channel'.
+ * Stops early if the channel runs out of chunks.
+ * Returns the number of samples func'ed.
+ */
+RemixCount
+remix_channel_chunkfuncify (RemixEnv * env, RemixChannel * channel,
+                           RemixCount count, RemixChunkFunc func,
+                           int channelname, void * data)
+{
+  RemixChunk * u;
+  RemixCount remaining = count, funced = 0, n, vl;
+  RemixError error;
+
+  remix_dprintf ("[remix_channel_chunkfuncify] (%p, +%ld) @ %ld\n",
+                channel, count, channel->_current_offset);
+
+  while (remaining > 0) {
+    channel->_current_chunk =
+      remix_channel_get_chunk_item_at (channel, channel->_current_offset);
+    if (channel->_current_chunk == RemixNone) {
+      remix_dprintf ("[remix_channel_chunkfuncify] channel incomplete, funced %ld\n",
+                    funced);
+      return funced; /* Channel incomplete */
+    }
+
+    u = (RemixChunk *)channel->_current_chunk->data.s_pointer;
+    vl = remix_chunk_item_valid_length (channel->_current_chunk);
+
+    n = func (env, u, channel->_current_offset, MIN(remaining, vl),
+             channelname, data);
+
+    if (n == -1) {
+      error = remix_last_error (env);
+      switch (error) {
+      case REMIX_ERROR_SILENCE:
+       n = _remix_chunk_clear_region (env, u, channel->_current_offset,
+                                      MIN(remaining, vl), 0, NULL);
+       break;
+      default:
+       n = 0;
+      }
+    }
+
+    funced += n;
+    remaining -= n;
+    channel->_current_offset += n;
+  }
+
+  return funced;
+}
+
+/*
+ * remix_channel_chunkchunkfuncify (env, src, dest, count, func, data)
+ *
+ * Apply the RemixChunkChunkFunc func to corresponding chunks of 'src' and
+ * 'dest' to 'count' samples.
+ * Stops early if 'dest' cannot contain part of the region for which
+ * 'src' is defined. Copies zeroes to 'dest' wherever 'src' is empty.
+ * Returns the number of samples func'ed.
+ */
+RemixCount
+remix_channel_chunkchunkfuncify (RemixEnv * env, RemixChannel * src, RemixChannel * dest,
+                             RemixCount count, RemixChunkChunkFunc func,
+                             int channelname, void * data)
+{
+  RemixChunk * su, * du;
+  RemixCount remaining = count, funced = 0, n, vl;
+  RemixError error;
+
+  remix_dprintf ("[remix_channel_ccf...] (%p -> %p, +%ld), src @ %ld, dest @ %ld\n",
+         src, dest, count, src->_current_offset, dest->_current_offset);
+
+  while (remaining > 0) {
+    n = 0; /* watch for early changes to n */
+
+    dest->_current_chunk =
+       remix_channel_get_chunk_item_at (dest, dest->_current_offset);
+    if (dest->_current_chunk == RemixNone) {
+      remix_dprintf ("[remix_channel_ccf...] channel incomplete after %ld\n", funced);
+      return funced; /* Destination channel incomplete */
+    }
+
+    src->_current_chunk =
+       remix_channel_get_chunk_item_at (src, src->_current_offset);
+    if (src->_current_chunk == RemixNone) { /* No source data at offset */
+      src->_current_chunk =
+       remix_channel_get_chunk_item_after (src, src->_current_offset);
+
+      if (src->_current_chunk == RemixNone) {
+        /* No following source data at all */
+       remix_dprintf ("[remix_channel_ccf...] no source data after %ld\n",
+                   src->_current_offset);
+       n = remix_channel_write0 (env, dest, remaining);
+       funced += n;
+       remaining -= n;
+       return funced;
+      } else {
+       remix_dprintf ("[remix_channel_ccf...] no source data at %ld\n",
+                   src->_current_offset);
+      }
+    }
+
+    /* *** Now, sl is the current or following source chunk item *** */
+
+    su = (RemixChunk *)src->_current_chunk->data.s_pointer;
+
+    if (su->start_index > src->_current_offset) { /* No source data at offset */
+      remix_dprintf ("[remix_channel_ccf...] no source data at %ld (warn 2)\n",
+                 src->_current_offset);
+      n = remix_channel_write0 (env, dest, su->start_index - src->_current_offset);
+      funced += n;
+      remaining -= n;
+      src->_current_offset += n;
+    }
+
+    if (remaining > 0) {
+      if (n > 0) {
+       dest->_current_chunk =
+         remix_channel_get_chunk_item_at (dest, dest->_current_offset);
+       if (dest->_current_chunk == RemixNone) {
+         remix_dprintf ("[remix_channel_ccf...] dest incomplete after %ld\n",
+                     dest->_current_chunk);
+         return funced; /* Destination channel incomplete */
+       }
+      }
+
+      du = (RemixChunk *)dest->_current_chunk->data.s_pointer;
+
+      vl = remix_chunk_item_valid_length (dest->_current_chunk);
+      n = func (env, su, src->_current_offset, du, dest->_current_offset,
+                MIN(remaining, vl), channelname, data);
+
+      if (n == -1) {
+       error = remix_last_error (env);
+       switch (error) {
+       case REMIX_ERROR_SILENCE:
+         n = _remix_chunk_clear_region (env, du, dest->_current_offset,
+                                     MIN(remaining, vl), 0, NULL);
+         break;
+       default:
+         n = 0;
+       }
+      }
+
+      funced += n;
+      remaining -= n;
+      src->_current_offset += n;
+      dest->_current_offset += n;
+    }
+  }
+
+  remix_dprintf ("[remix_channel_ccf...] funced %ld\n", funced);
+
+  return funced;
+}
+
+/*
+ * remix_channel_chunkchunkchunkfuncify (env, src1, src2, dest, count, func,
+ *                                    data)
+ *
+ * Apply the RemixChunkChunkChunkFunc func to corresponding chunks of 'src1',
+ * 'src2' and 'dest' to 'count' samples.
+ * Stops early if 'dest' cannot contain part of the region for which
+ * both 'src1' and 'src2' is defined. Copies zeroes to 'dest' wherever
+ * either 'src1' or 'src2' are empty.
+ * Returns the number of samples func'ed.
+ */
+RemixCount
+remix_channel_chunkchunkchunkfuncify (RemixEnv * env,
+                                  RemixChannel * src1, RemixChannel * src2,
+                                  RemixChannel * dest, RemixCount count,
+                                  RemixChunkChunkChunkFunc func,
+                                  int channelname, void * data)
+{
+  RemixChunk * s1u, * s2u, * du;
+  RemixCount remaining = count, funced = 0, n, vl, undef_length;
+  RemixError error;
+
+  while (remaining > 0) {
+    n = 0; /* watch for early changes to n */
+
+    dest->_current_chunk =
+      remix_channel_get_chunk_item_at (dest, dest->_current_offset);
+    if (dest->_current_chunk == RemixNone)
+      return funced; /* Destination channel incomplete */
+
+    src1->_current_chunk =
+      remix_channel_get_chunk_item_at (src1, src1->_current_offset);
+    if (src1->_current_chunk == RemixNone) {
+      src1->_current_chunk =
+       remix_channel_get_chunk_item_after (src1, src1->_current_offset);
+    }
+
+    src2->_current_chunk =
+      remix_channel_get_chunk_item_at (src2, src2->_current_offset);
+    if (src2->_current_chunk == RemixNone) {
+      src2->_current_chunk =
+       remix_channel_get_chunk_item_after (src2, src2->_current_offset);
+    }
+
+    if (src1->_current_chunk == RemixNone || src2->_current_chunk == RemixNone) {
+      n = remix_channel_write0 (env, dest, remaining);
+      funced += n;
+      remaining -= n;
+      return funced;
+    }
+
+    s1u = (RemixChunk *)src1->_current_chunk->data.s_pointer;
+    s2u = (RemixChunk *)src2->_current_chunk->data.s_pointer;
+
+    if (s1u->start_index > src1->_current_offset ||
+       s2u->start_index > src2->_current_offset) {
+      undef_length = MAX (s1u->start_index - src1->_current_offset,
+                         s2u->start_index - src2->_current_offset);
+      n = remix_channel_write0 (env, dest, undef_length);
+      funced += n;
+      remaining -= n;
+      src1->_current_offset += n;
+      src2->_current_offset += n;
+    }
+
+    if (remaining > 0) {
+      if (n > 0) {
+       dest->_current_chunk =
+          remix_channel_get_chunk_item_at (dest, dest->_current_offset);
+       if (dest->_current_chunk == RemixNone)
+          return funced; /* Destination channel incomplete */
+      }
+
+      du = (RemixChunk *)dest->_current_chunk->data.s_pointer;
+
+      vl = remix_chunk_item_valid_length (dest->_current_chunk);
+      n = func (env, s1u, src1->_current_offset, s2u, src2->_current_offset,
+               du, dest->_current_offset, MIN(remaining, vl), channelname,
+               data);
+
+      if (n == -1) {
+       error = remix_last_error (env);
+       switch (error) {
+       case REMIX_ERROR_SILENCE:
+         n = _remix_chunk_clear_region (env, du, dest->_current_offset,
+                                     MIN(remaining, vl), 0, NULL);
+         break;
+       default:
+         n = 0;
+       }
+      }
+
+      funced += n;
+      remaining -= n;
+      src1->_current_offset += n;
+      src2->_current_offset += n;
+      dest->_current_offset += n;
+    }
+  }
+
+  return funced;
+}
+
+/*
+ * remix_channel_copy (src, dest, count)
+ *
+ * Copies 'count' samples from 'src' to 'dest'.
+ * Stops early if 'dest' cannot contain part of 'src'. Copies zeroes to
+ * 'dest' wherever 'src' is correspondingly empty.
+ * Returns the count of samples actually copied.
+ */
+RemixCount
+remix_channel_copy (RemixEnv * env, RemixChannel * src, RemixChannel * dest, RemixCount count)
+{
+  return
+    remix_channel_chunkchunkfuncify (env, src, dest, count,
+                                    (RemixChunkChunkFunc)_remix_chunk_copy,
+                                    0, NULL);
+}
+
+RemixCount
+remix_channel_mix (RemixEnv * env, RemixChannel * src, RemixChannel * dest, RemixCount count)
+{
+  return remix_channel_chunkchunkfuncify (env, src, dest, count,
+                                       (RemixChunkChunkFunc)_remix_chunk_add_inplace,
+                                      0, NULL);
+}
+
+RemixCount
+remix_channel_interleave_2 (RemixEnv * env, RemixChannel * src1, RemixChannel * src2,
+                        RemixPCM * dest, RemixCount count)
+{
+  return
+    remix_channel_chunkchunkfuncify (env, src1, src2, count,
+                                 (RemixChunkChunkFunc)_remix_chunk_interleave_2,
+                                 0, dest);
+}
+
+RemixCount
+remix_channel_deinterleave_2 (RemixEnv * env, RemixChannel * dest1, RemixChannel * dest2,
+                          RemixPCM * src, RemixCount count)
+{
+  return
+    remix_channel_chunkchunkfuncify (env, dest1, dest2, count,
+                                 (RemixChunkChunkFunc)_remix_chunk_deinterleave_2,
+                                 0, src);
+}
+
+RemixCount
+_remix_channel_write (RemixEnv * env, RemixChannel * channel, RemixCount count,
+                  RemixChannel * data)
+{
+  RemixCount n = remix_channel_copy (env, data, channel, count);
+  data->_current_offset += n;
+  data->_current_chunk =
+    remix_channel_get_chunk_item_after (data, data->_current_offset);
+  channel->_current_offset += n;
+  channel->_current_chunk =
+    remix_channel_get_chunk_item_after (channel, channel->_current_offset);
+  return n;
+}
+
+RemixCount
+_remix_channel_length (RemixEnv * env, RemixChannel * channel)
+{
+  RemixChunk * last = (RemixChunk *)
+    (cd_list_last (env, channel->chunks, CD_TYPE_POINTER)).s_pointer;
+  if (last == RemixNone) return 0;
+  return (last->start_index + last->length);
+}
+
+RemixCount
+_remix_channel_seek (RemixEnv * env, RemixChannel * channel, RemixCount offset)
+{
+  if (offset == channel->_current_offset) return offset;
+  channel->_current_offset = offset;
+  /* Cache the current chunk */
+  channel->_current_chunk =
+    remix_channel_get_chunk_item_after (channel, offset);
+  return offset;
+}
diff --git a/src/libremix/remix_channelset.c b/src/libremix/remix_channelset.c
new file mode 100644 (file)
index 0000000..f166dfe
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * remix_channelset: default channel sets.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#define __REMIX__
+#include "remix.h"
+
+CDSet * REMIX_MONO = RemixNone;
+CDSet * REMIX_STEREO = RemixNone;
+
+void
+remix_channelset_defaults_initialise (RemixEnv * env)
+{
+  if (REMIX_MONO == NULL) {
+    REMIX_MONO = cd_set_new (env);
+    REMIX_MONO = cd_set_insert (env, REMIX_MONO, REMIX_CHANNEL_LEFT,
+                              CD_POINTER(NULL));
+  }
+
+  if (REMIX_STEREO == NULL) {
+    REMIX_STEREO = cd_set_new (env);
+    REMIX_STEREO = cd_set_insert (env, REMIX_STEREO, REMIX_CHANNEL_LEFT,
+                                CD_POINTER(NULL));
+    REMIX_STEREO = cd_set_insert (env, REMIX_STEREO, REMIX_CHANNEL_RIGHT,
+                                CD_POINTER(NULL));
+  }
+
+  return;
+}
+
+void
+remix_channelset_defaults_destroy (RemixEnv * env)
+{
+  if (REMIX_MONO != NULL) {
+    cd_set_free (env, REMIX_MONO);
+    REMIX_MONO = NULL;
+  }
+
+  if (REMIX_STEREO != NULL) {
+    cd_set_free (env, REMIX_STEREO);
+    REMIX_STEREO = NULL;
+  }
+}
diff --git a/src/libremix/remix_chunk.c b/src/libremix/remix_chunk.c
new file mode 100644 (file)
index 0000000..a0ce15b
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixChunk: A contiguous chunk of monophonic PCM data.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ *
+ * Description
+ * -----------
+ *
+ * A chunk contains raw PCM data.
+ *
+ * Invariants
+ * ----------
+ *
+ * A chunk must always be contained within a channel. The data within
+ * a chunk is only valid where it is not overlapped by a later chunk
+ * in the same channel; elsewhere, the chunk's data is not used.
+ *
+ */
+
+#include <string.h>
+
+#define __REMIX__
+#include "remix.h"
+
+typedef RemixCount
+  (*RemixPFunc) (RemixPCM * src, RemixCount count, void * data);
+
+typedef RemixCount
+  (*RemixPPFunc) (RemixPCM * src, RemixPCM * dest, RemixCount count,
+                            void * data);
+typedef RemixCount
+  (*RemixPPPFunc) (RemixPCM * src1, RemixPCM * src2, RemixPCM * dest,
+                   RemixCount count, void * data);
+
+
+RemixChunk *
+remix_chunk_new (RemixEnv * env, RemixCount start_index, RemixCount length)
+{
+  RemixChunk * u;
+
+  u = (RemixChunk *) remix_malloc (sizeof (struct _RemixChunk));
+  u->start_index = start_index;
+  u->length = length;
+
+  u->data = (RemixPCM *) remix_malloc (length * sizeof (RemixPCM));
+
+  return u;
+}
+
+RemixChunk *
+remix_chunk_new_from_buffer (RemixEnv * env, RemixCount start_index,
+                             RemixCount length, RemixPCM * buffer)
+{
+  RemixChunk * u;
+
+  u = (RemixChunk *) remix_malloc (sizeof (struct _RemixChunk));
+  u->start_index = start_index;
+  u->length = length;
+
+  u->data = buffer;
+
+  return u;
+}
+
+RemixChunk *
+remix_chunk_clone (RemixEnv * env, RemixChunk * chunk)
+{
+  RemixChunk * u = remix_chunk_new (env, chunk->start_index, chunk->length);
+  memcpy (u->data, chunk->data, (chunk->length * sizeof (RemixPCM)));
+  return u;
+}
+
+void
+remix_chunk_free (RemixEnv * env, RemixChunk * chunk)
+{
+  remix_free (chunk->data);
+  remix_free (chunk);
+}
+
+int
+remix_chunk_later (RemixEnv * env, RemixChunk * u1, RemixChunk * u2)
+{
+  return (u1->start_index > u2->start_index);
+}
+
+RemixCount
+remix_chunk_clear (RemixEnv * env, RemixChunk * chunk)
+{
+  RemixCount len = chunk->length;
+  memset (chunk->data, (RemixPCM)0, len * sizeof (RemixPCM));
+  return len;
+}
+
+
+/*
+ * FUNCTION APPLIERS
+ */
+
+static RemixCount
+_remix_pfunc_apply (RemixEnv * env, RemixPFunc func, RemixChunk * chunk,
+                    RemixCount start, RemixCount count, void * data)
+{
+  RemixCount chunk_start = start - chunk->start_index;
+
+  /* chunk_start: 'start' relative to chunk */
+  if (chunk_start < 0) {
+    count += chunk_start;
+    chunk_start = 0;
+  }
+
+  if (chunk_start + count > chunk->length) {
+    count = chunk->length - chunk_start;
+  }
+
+  func (&chunk->data[chunk_start], count, data);
+
+  return (count);
+}
+
+/*
+ * _remix_ppfunc_apply (env, func, src, src_offset, dest, dest_offset, count,
+ *                      data)
+ *
+ * Apply RemixPCMPCMFunc 'func' to 'count' samples of chunks 'src' and 'dest'.
+ */
+static RemixCount
+_remix_ppfunc_apply (RemixEnv * env, RemixPPFunc func,
+                     RemixChunk * src, RemixCount src_offset,
+                     RemixChunk * dest, RemixCount dest_offset,
+                     RemixCount count, void * data)
+{
+  RemixCount dest_start = dest_offset - dest->start_index;
+  RemixCount src_start;
+  RemixPCM *s, *d;
+
+  if (dest_start < 0) {
+    count += dest_start;
+    dest_offset -= dest_start;
+    src_offset -= dest_start;
+    dest_start = 0;
+  }
+
+  src_start = src_offset - src->start_index;
+
+  /* Shorten count if either chunk is shorter than required */
+  if (src_start + count > src->length)
+    count = src->length - src_start;
+
+  if (dest_start + count > dest->length)
+    count = dest->length - dest_start;
+
+  s = &src->data[src_start];
+  d = &dest->data[dest_start];
+
+  func (s, d, count, data);
+
+  return count;
+}
+
+/*
+ * _remix_pppfunc_apply (env, func, src, src_offset, dest, dest_offset, count,
+ *                       data)
+ *
+ * Apply RemixPPPFunc 'func' to 'count' samples of chunks 'src1', 'src2'
+ * and 'dest'.
+ */
+static RemixCount
+_remix_pppfunc_apply (RemixEnv * env, RemixPPPFunc func,
+                      RemixChunk * src1, RemixCount src1_offset,
+                      RemixChunk * src2, RemixCount src2_offset,
+                      RemixChunk * dest, RemixCount dest_offset,
+                      RemixCount count, void * data)
+{
+  RemixCount dest_start = dest_offset - dest->start_index;
+  RemixCount src1_start, src2_start;
+  RemixPCM *s1, *s2, *d;
+
+  if (dest_start < 0) {
+    count += dest_start;
+    dest_offset -= dest_start;
+    src1_offset -= dest_start;
+    src2_offset -= dest_start;
+    dest_start = 0;
+  }
+
+  src1_start = src1_offset - src1->start_index;
+  src2_start = src2_offset - src2->start_index;
+
+  /* Shorten count if any chunk is shorter than required */
+  if (src1_start + count > src1->length)
+    count = src1->length - src1_start;
+
+  if (src2_start + count > src2->length)
+    count = src2->length - src2_start;
+
+  if (dest_start + count > dest->length)
+    count = dest->length - dest_start;
+
+  s1 = &src1->data[src1_start];
+  s2 = &src2->data[src2_start];
+  d = &dest->data[dest_start];
+
+  func (s1, s2, d, count, data);
+
+  return count;
+}
+
+/* PFunc appliers */
+
+/*
+ * _remix_chunk_clear_region (chunk, start, length, unused)
+ *
+ * Clear 'chunk' from stream index 'start' for 'length' samples.
+ * Returns the count of samples actually cleared.
+ */
+RemixCount
+_remix_chunk_clear_region (RemixEnv * env, RemixChunk * chunk,
+                           RemixCount start, RemixCount length,
+                           int channelname, void * unused)
+{
+  return _remix_pfunc_apply (env,_remix_pcm_clear_region,
+                             chunk, start, length, NULL);
+}
+
+/*
+ * _remix_chunk_gain (chunk, start, length, gain)
+ *
+ * Multiply by gain all samples in 'chunk' from stream index 'start' for
+ * 'length' samples.
+ * Returns the count of samples modified.
+ */
+RemixCount
+_remix_chunk_gain (RemixEnv * env, RemixChunk * chunk,
+                   RemixCount start, RemixCount count,
+                   int channelname, /* (RemixPCM *) */ void * gain)
+{
+  return _remix_pfunc_apply (env, _remix_pcm_gain, chunk, start, count, gain);
+}
+
+
+/* PPFunc appliers */
+
+/*
+ * _remix_chunk_copy (env, src+offset, dest+offset, count, channelname)
+ *
+ * Copy data from 'src' to 'dest' from stream index 'offset' for
+ * 'count'. Returns the count of samples actually copied.
+ */
+RemixCount
+_remix_chunk_copy (RemixEnv * env, RemixChunk * src, RemixCount src_offset,
+                   RemixChunk * dest, RemixCount dest_offset, RemixCount count,
+                   int channelname, void * unused)
+{
+  return _remix_ppfunc_apply (env, _remix_pcm_copy, src, src_offset,
+                              dest, dest_offset, count, NULL);
+}
+
+/*
+ * _remix_chunk_add_inplace (env, src+offset, dest+offset, count, channelname)
+ *
+ * Add data from 'src' to data in 'dest' from stream index 'start' for
+ * 'count' samples. Returns the count of samples actually added.
+ */
+RemixCount
+_remix_chunk_add_inplace (RemixEnv * env,
+                          RemixChunk * src, RemixCount src_offset,
+                          RemixChunk * dest, RemixCount dest_offset,
+                          RemixCount count, int channelname, void * unused)
+{
+  return _remix_ppfunc_apply (env, _remix_pcm_add, src, src_offset,
+                          dest, dest_offset, count, NULL);
+}
+
+/*
+ * _remix_chunk_mult_inplace (src, dest, start, count, unused)
+ *
+ * Multiply data of 'dest' by that of 'src' from stream index 'start' for
+ * 'count' samples. Returns the count of samples actually multiplied.
+ */
+RemixCount
+_remix_chunk_mult_inplace (RemixEnv * env,
+                           RemixChunk * src, RemixCount src_offset,
+                           RemixChunk * dest, RemixCount dest_offset,
+                           RemixCount count, int channelname, void * unused)
+{
+  return _remix_ppfunc_apply (env, _remix_pcm_mult, src, src_offset,
+                          dest, dest_offset, count, NULL);
+}
+
+/*
+ * _remix_chunk_fade_inplace (src, src_offset, dest, dest_offset, count, unused)
+ *
+ * Fade data of 'dest' by that of 'src' from stream index 'start' for
+ * 'count' samples. Returns the count of samples actually faded.
+ */
+RemixCount
+_remix_chunk_fade_inplace (RemixEnv * env,
+                           RemixChunk * src, RemixCount src_offset,
+                           RemixChunk * dest, RemixCount dest_offset,
+                           RemixCount count, int channelname, void * unused)
+{
+  return _remix_ppfunc_apply (env, _remix_pcm_fade, src, src_offset,
+                          dest, dest_offset, count, NULL);
+}
+
+/*
+ * _remix_chunk_interleave_2 (env, src1+offset, src2+offset, count, dest)
+ *
+ * Interleave data of 'src1' from stream index 'src1_offset' with that
+ * of 'src2' from stream index 'src2_offset' for 'count' samples, storing
+ * the resulting interleaved PCM data in 'dest'.
+ *
+ * Returns the count of sample frames interleaved.
+ */
+RemixCount
+_remix_chunk_interleave_2 (RemixEnv * env,
+                           RemixChunk * src1, RemixCount src1_offset,
+                           RemixChunk * src2, RemixCount src2_offset,
+                           RemixCount count, int unused, void * dest)
+{
+  return _remix_ppfunc_apply (env, _remix_pcm_interleave_2, src1, src1_offset,
+                              src2, src2_offset, count, dest);
+}
+
+/*
+ * _remix_chunk_deinterleave_2 (env, dest1+offset, dest2+offset, count, src)
+ *
+ * Deinterleave data of 'src' and store the result in streams 'dest1' (from
+ * stream index 'dest1_offset') and 'dest2' (from stream index
+ * 'dest2_offset').
+ *
+ * Returns the number of sample frames deinterleaved.
+ */
+RemixCount
+_remix_chunk_deinterleave_2 (RemixEnv * env,
+                             RemixChunk * dest1, RemixCount dest1_offset,
+                             RemixChunk * dest2, RemixCount dest2_offset,
+                             RemixCount count, int unused, void * src)
+{
+  return _remix_ppfunc_apply (env, _remix_pcm_deinterleave_2,
+                              dest1, dest1_offset, dest2, dest2_offset,
+                              count, src);
+}
+
+/* PPPFunc appliers */
+
+/*
+ * _remix_chunk_blend_inplace (env, src+offset, blend+offset,
+ *                             dest+offset, count, unused)
+ *
+ * Blend data of 'src' into that of 'dest' by blend values given in
+ * 'blend'.
+ */
+RemixCount
+_remix_chunk_blend_inplace (RemixEnv * env,
+                            RemixChunk * src, RemixCount src_offset,
+                            RemixChunk * blend, RemixCount blend_offset,
+                            RemixChunk * dest, RemixCount dest_offset,
+                            RemixCount count, int channelname, void * unused)
+{
+  return _remix_pppfunc_apply (env, _remix_pcm_blend, src, src_offset,
+                               blend, blend_offset, dest, dest_offset,
+                               count, NULL);
+}
diff --git a/src/libremix/remix_compat.h b/src/libremix/remix_compat.h
new file mode 100644 (file)
index 0000000..886b4bf
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "config.h"
+
+#ifndef WIN32
+#  define remix_stat_regular(mode) (S_ISREG((mode)) || S_ISLNK((mode)))
+#else
+#  define remix_stat_regular(mode) ((mode) & S_IFREG)
+#endif
diff --git a/src/libremix/remix_context.c b/src/libremix/remix_context.c
new file mode 100644 (file)
index 0000000..a5398c1
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixContext: REMIX core context.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#include <string.h>
+
+#define __REMIX__
+#include "remix.h"
+
+static void
+remix_plugin_destroy (RemixEnv * env, RemixPlugin * plugin)
+{
+  if (plugin->destroy) {
+    plugin->destroy (env, plugin);
+  }
+}
+
+static void
+remix_context_destroy (RemixEnv * env)
+{
+  RemixContext * ctx = env->context;
+  RemixWorld * world = env->world;
+
+  world->purging = 1;
+
+  world->plugins = cd_list_destroy_with (env, world->plugins, remix_plugin_destroy);
+  remix_plugin_defaults_unload (env);
+//need to analyse why its commented in svn version ???
+  //world->bases = cd_list_destroy_with (env, world->bases, remix_destroy);
+
+  remix_channelset_defaults_destroy (env);
+  remix_free (ctx);
+  remix_free (world);
+}
+
+static RemixEnv *
+remix_add_thread_context (RemixContext * ctx, RemixWorld * world)
+{
+  RemixEnv * env = remix_malloc (sizeof (struct _RemixThreadContext));
+  env->context = ctx;
+  env->world = world;
+  world->refcount++;
+  return env;
+}
+
+RemixContext *
+_remix_context_copy (RemixEnv * env, RemixContext * dest)
+{
+  RemixContext * ctx = env->context;
+
+  if (dest == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  dest->samplerate = ctx->samplerate;
+  dest->tempo = ctx->tempo;
+  dest->mixlength = ctx->mixlength;
+  dest->channels = cd_set_clone_keys (env, ctx->channels);
+
+  return dest;
+}
+
+/*
+ * _remix_context_merge (env, dest)
+ *
+ * Merges the context of env into context 'dest'. Copies over the samplerate
+ * and tempo, and expands the mixlength and channels if they are greater in
+ * 'env's context than in 'dest'.
+ */
+RemixContext *
+_remix_context_merge (RemixEnv * env, RemixContext * dest)
+{
+  RemixContext * ctx = env->context;
+  CDSet * s;
+  CDScalar k;
+
+  if (dest == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  dest->samplerate = ctx->samplerate;
+  dest->tempo = ctx->tempo;
+
+  if (ctx->mixlength > dest->mixlength)
+    dest->mixlength = ctx->mixlength;
+
+  for (s = ctx->channels; s; s = s->next) {
+    k = cd_set_find (env, dest->channels, s->key);
+    if (k.s_pointer == NULL)
+      dest->channels = cd_set_insert (env, dest->channels, s->key,
+                                     CD_POINTER(NULL));
+  }
+
+  return dest;
+}
+
+/*
+ * remix_init ()
+ */
+RemixEnv *
+remix_init (void)
+{
+  RemixEnv * env;
+  RemixWorld * world =
+    (RemixWorld *) remix_malloc (sizeof (struct _RemixWorld));
+  RemixContext * ctx =
+    (RemixContext *) remix_malloc (sizeof (struct _RemixContext));
+
+  world->refcount = 0;
+  world->plugins = cd_list_new (ctx);
+  world->bases = cd_list_new (ctx);
+  world->purging = FALSE;
+
+  ctx->mixlength = REMIX_DEFAULT_MIXLENGTH;
+  ctx->samplerate = REMIX_DEFAULT_SAMPLERATE;
+  ctx->tempo = REMIX_DEFAULT_TEMPO;
+
+  env = remix_add_thread_context (ctx, world);
+  remix_channelset_defaults_initialise (env);
+  ctx->channels = REMIX_MONO;
+
+  remix_plugin_defaults_initialise (env);
+
+  return env;
+}
+
+/*
+ * remix_init_clone ()
+ */
+RemixEnv *
+remix_init_clone (RemixEnv * env)
+{
+  RemixEnv * new_env = remix_add_thread_context (env->context, env->world);
+  return new_env;
+}
+
+void
+remix_purge (RemixEnv * env)
+{
+  RemixWorld * world = env->world;
+  world->refcount--;
+  if (world->refcount <= 0) {
+    remix_context_destroy (env);
+  }
+  remix_free (env);
+}
+
+RemixError
+remix_set_error (RemixEnv * env, RemixError error)
+{
+  RemixError old = env->last_error;
+  env->last_error = error;
+  return old;
+}
+
+RemixError
+remix_last_error (RemixEnv * env)
+{
+  return env->last_error;
+}
+
+RemixCount
+remix_set_mixlength (RemixEnv * env, RemixCount mixlength)
+{
+  RemixContext * ctx = env->context;
+  RemixCount old = ctx->mixlength;
+  ctx->mixlength = mixlength;
+  return old;
+}
+
+RemixCount
+remix_get_mixlength (RemixEnv * env)
+{
+  RemixContext * ctx = env->context;
+  return ctx->mixlength;
+}
+
+RemixSamplerate
+remix_set_samplerate (RemixEnv * env, RemixSamplerate samplerate)
+{
+  RemixContext * ctx = env->context;
+  RemixSamplerate old = ctx->samplerate;
+  ctx->samplerate = samplerate;
+  return old;
+}
+
+RemixSamplerate
+remix_get_samplerate (RemixEnv * env)
+{
+  RemixContext * ctx = env->context;
+  return ctx->samplerate;
+}
+
+RemixTempo
+remix_set_tempo (RemixEnv * env, RemixTempo tempo)
+{
+  RemixContext * ctx = env->context;
+  RemixTempo old = ctx->tempo;
+  ctx->tempo = tempo;
+  return old;
+}
+
+RemixTempo
+remix_get_tempo (RemixEnv * env)
+{
+  RemixContext * ctx = env->context;
+  return ctx->tempo;
+}
+
+CDSet *
+remix_set_channels (RemixEnv * env,  CDSet * channels)
+{
+  RemixContext * ctx = env->context;
+  CDSet * old = ctx->channels;
+  ctx->channels = cd_set_clone_keys (env, channels);
+  return old;
+}
+
+CDSet *
+remix_get_channels (RemixEnv * env)
+{
+  RemixContext * ctx = env->context;
+  return ctx->channels;
+}
+
+RemixEnv *
+_remix_register_plugin (RemixEnv * env, RemixPlugin * plugin)
+{
+  RemixWorld * world = env->world;
+  remix_dprintf ("[_remix_register_plugin] REGISTERING %s\n",
+                plugin->metatext ? plugin->metatext->identifier : "(\?\?\?)");
+  world->plugins = cd_list_append (env, world->plugins, CD_POINTER(plugin));
+  return env;
+}
+
+RemixEnv *
+_remix_unregister_plugin (RemixEnv * env, RemixPlugin * plugin)
+{
+  RemixWorld * world = env->world;
+  if (world->purging) return env;
+
+  world->plugins = cd_list_remove (env, world->plugins, CD_TYPE_POINTER,
+                                  CD_POINTER(plugin));
+  return env;
+}
+
+RemixEnv *
+_remix_register_base (RemixEnv * env, RemixBase * base)
+{
+  RemixWorld * world = env->world;
+  world->bases = cd_list_append (env, world->bases, CD_POINTER(base));
+  return env;
+}
+
+RemixEnv *
+_remix_unregister_base (RemixEnv * env, RemixBase * base)
+{
+  RemixWorld * world = env->world;
+  if (world->purging) return env;
+
+  world->bases = cd_list_remove (env, world->bases, CD_TYPE_POINTER,
+                                CD_POINTER(base));
+  return env;
+}
+
+static int
+plugin_id_eq (RemixEnv * env, RemixPlugin * plugin, char * identifier)
+{
+  if (plugin == RemixNone) return FALSE;
+  if (plugin->metatext == RemixNone) return FALSE;
+  return !(strcmp(plugin->metatext->identifier, identifier));
+}
+
+RemixPlugin *
+remix_find_plugin (RemixEnv * env, char * identifier)
+{
+  RemixWorld * world = env->world;
+  CDList * l = cd_list_find_first (env, world->plugins, CD_TYPE_POINTER,
+                                  (CDCmpFunc)plugin_id_eq,
+                                  CD_POINTER(identifier));
+
+  if (l == RemixNone) return RemixNone;
+  return (RemixPlugin *)l->data.s_pointer;
+}
diff --git a/src/libremix/remix_debug.c b/src/libremix/remix_debug.c
new file mode 100644 (file)
index 0000000..c782b7d
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * remix_debug.c -- Debuggin routines for Remix
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ *
+ * Description
+ * -----------
+ *
+ * This file contains printing routines for formatted debugging.
+ *
+ */
+
+#include <string.h>
+#include <stdarg.h>
+
+#define __REMIX__
+#include "remix.h"
+
+static int indent = 0;
+
+/*
+ * remix_debug_down (void)
+ */
+void
+remix_debug_down (void)
+{
+  indent ++;
+}
+
+/*
+ * remix_debug_up (void)
+ */
+void
+remix_debug_up (void)
+{
+  indent --;
+}
+
+/*
+ * remix_dprintf (fmt)
+ *
+ * Print a formatted debugging message to stdout at the current indent
+ */
+void
+remix_dprintf (const char * fmt, ...)
+{
+#if 0
+  va_list ap;
+  char buf[4096];
+  int i, n;
+
+  va_start (ap, fmt);
+
+  n = MIN (4096, indent);
+
+  for (i = 0; i < n; i++) {
+    buf[i] = ' ';
+  }
+
+  vsnprintf (buf+n, 4096-n, fmt, ap);
+
+  fputs (buf, stdout);
+  fflush (NULL);
+
+  va_end (ap);
+#endif
+}
diff --git a/src/libremix/remix_deck.c b/src/libremix/remix_deck.c
new file mode 100644 (file)
index 0000000..c0206f7
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixDeck: A high level audio mixing abstraction.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ *
+ * Description
+ * -----------
+ *
+ * A deck contains a number of tracks which are mixed in parallel.
+ *
+ * Invariants
+ * ----------
+ *
+ * Decks are independent entities. The creation of a new deck does not
+ * depend on the existence of any other bases. Any tracks (and, by
+ * extension, layers and sounds) added to a deck become part of that
+ * deck and are destroyed when the deck is destroyed.
+ *
+ */
+
+#define __REMIX__
+#include "remix.h"
+
+/* Optimisation dependencies: optimise on change of nr. tracks */
+static RemixDeck * remix_deck_optimise (RemixEnv * env, RemixDeck * deck);
+
+static RemixDeck *
+remix_deck_replace_mixstream (RemixEnv * env, RemixDeck * deck)
+{
+  RemixCount mixlength = _remix_base_get_mixlength (env, deck);
+
+  if (deck->_mixstream != RemixNone)
+    remix_destroy (env, (RemixBase *)deck->_mixstream);
+
+  deck->_mixstream = remix_stream_new_contiguous (env, mixlength);
+
+  return deck;
+}
+
+RemixBase *
+remix_deck_init (RemixEnv * env, RemixBase * base)
+{
+  RemixDeck * deck = (RemixDeck *)base;
+  deck->tracks = cd_list_new (env);
+  deck->_mixstream = RemixNone;
+  remix_deck_replace_mixstream (env, deck);
+  remix_deck_optimise (env, deck);
+  return (RemixBase *)deck;
+}
+
+RemixDeck *
+remix_deck_new (RemixEnv * env)
+{
+  RemixDeck * deck =
+    (RemixDeck *) remix_base_new_subclass (env, sizeof (struct _RemixDeck));
+  return (RemixDeck *)remix_deck_init (env, (RemixBase *)deck);
+}
+
+RemixBase *
+remix_deck_clone (RemixEnv * env, RemixBase * base)
+{
+  RemixDeck * deck = (RemixDeck *)base;
+  RemixDeck * new_deck = remix_deck_new (env);
+  new_deck->tracks = cd_list_clone (env, deck->tracks,
+                                   (CDCloneFunc)remix_track_clone);
+  return (RemixBase *)new_deck;
+}
+
+static int
+remix_deck_destroy (RemixEnv * env, RemixBase * base)
+{
+  RemixDeck * deck = (RemixDeck *)base;
+  remix_destroy_list (env, deck->tracks);
+  remix_destroy (env, (RemixBase *)deck->_mixstream);
+  remix_free (deck);
+  return 0;
+}
+
+static int
+remix_deck_ready (RemixEnv * env, RemixBase * base)
+{
+  return (remix_base_encompasses_mixlength (env, base) &&
+         remix_base_encompasses_channels (env, base));
+}
+
+static RemixBase *
+remix_deck_prepare (RemixEnv * env, RemixBase * base)
+{
+  RemixDeck * deck = (RemixDeck *)base;
+  remix_deck_replace_mixstream (env, deck);
+  return base;
+}
+
+RemixTrack *
+_remix_deck_add_track (RemixEnv * env, RemixDeck * deck, RemixTrack * track)
+{
+  deck->tracks = cd_list_prepend (env, deck->tracks, CD_POINTER(track));
+  remix_deck_optimise (env, deck);
+  return track;
+}
+
+RemixTrack *
+_remix_deck_remove_track (RemixEnv * env, RemixDeck * deck, RemixTrack * track)
+{
+  deck->tracks = cd_list_remove (env, deck->tracks, CD_TYPE_POINTER,
+                                CD_POINTER(track));
+  remix_deck_optimise (env, deck);
+  return track;
+}
+
+int
+remix_deck_nr_tracks (RemixEnv * env, RemixDeck * deck)
+{
+  return cd_list_length (env, deck->tracks);
+}
+
+static RemixCount
+remix_deck_length (RemixEnv * env, RemixBase * base)
+{
+  RemixDeck * deck = (RemixDeck *)base;
+  RemixCount length, maxlength = 0;
+  CDList * l;
+  RemixBase * track;
+
+  for (l = deck->tracks; l; l = l->next) {
+    track = (RemixBase *)l->data.s_pointer;
+    length = remix_length (env, track);
+    remix_dprintf ("[remix_deck_length] found track %p length %ld\n",
+                   track, length);
+    maxlength = MAX (maxlength, length);
+  }
+
+  return maxlength;
+}
+
+CDList *
+remix_deck_get_tracks (RemixEnv * env, RemixDeck * deck)
+{
+  return cd_list_copy (env, deck->tracks);
+}
+
+#if 0
+static RemixCount
+remix_deck_process (RemixEnv * env, RemixBase base, RemixCount count, RemixStream input,
+                RemixStream output)
+{
+  RemixDeck deck = (RemixDeck)base;
+  CDList tl, ml;
+  RemixTrack track;
+  RemixStream mixstream;
+  RemixCount processed = 0, remaining = count, n, minn;
+  RemixCount input_offset;
+
+  remix_dprintf ("PROCESS DECK (%p, +%ld, %p -> %p) @ %ld\n",
+             deck, count, input, output, remix_tell (env, base));
+
+  while (remaining > 0) {
+    /* Get mixlength from each track */
+    minn = deck->mixlength;
+    input_offset = remix_tell (env, (RemixBase)input);
+    for (tl = deck->tracks, ml = deck->mixstreams; tl && ml;
+         tl = tl->next, ml = ml->next) {
+      track = (RemixTrack)tl->data;
+      mixstream = (RemixStream)ml->data;
+      remix_seek (env, (RemixBase)input, input_offset);
+      n = remix_process (env, (RemixBase)track, MIN (remaining, deck->mixlength),
+                     input, mixstream);
+      minn = MIN (minn, n);
+    }
+
+
+    if (output != RemixNone) {
+      /* mix tracks together to the output */
+      n = remix_streams_mix (env, deck->mixstreams, output, minn);
+    } else {
+      /* don't need to create output */
+      n = minn;
+    }
+
+    processed += n;
+    remaining -= n;
+  }
+
+  remix_dprintf ("[remix_deck_process] processed %ld\n", processed);
+
+  return processed;
+}
+#endif
+
+static RemixCount
+remix_deck_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                    RemixStream * input, RemixStream * output)
+{
+  RemixDeck * deck = (RemixDeck *)base;
+  CDList * l;
+  RemixTrack * track;
+  RemixCount remaining = count, processed = 0, n;
+  RemixCount current_offset = remix_tell (env, base);
+  RemixCount input_offset = remix_tell (env, (RemixBase *)input);
+  RemixCount output_offset = remix_tell (env, (RemixBase *)output);
+  RemixCount mixlength = _remix_base_get_mixlength (env, deck);
+  RemixStream * mixstream = deck->_mixstream;
+
+  remix_dprintf ("PROCESS DECK (%p, +%ld, %p -> %p) @ %ld\n",
+                 deck, count, input, output, current_offset);
+
+  while (remaining > 0) {
+
+    l = deck->tracks;
+    track = (RemixTrack *)l->data.s_pointer;
+
+    n = MIN (remaining, mixlength);
+
+    n = remix_process (env, (RemixBase *)track, n, input, output);
+    remix_seek (env, (RemixBase *)output, output_offset, SEEK_SET);
+    n = remix_stream_gain (env, output, n, track->gain);
+
+    for (l = l->next; l; l = l->next) {
+      track = (RemixTrack *)l->data.s_pointer;
+
+      remix_seek (env, (RemixBase *)input, input_offset, SEEK_SET);
+      remix_seek (env, (RemixBase *)mixstream, 0, SEEK_SET);
+      n = remix_process (env, (RemixBase *)track, n, input, mixstream);
+
+      remix_seek (env, (RemixBase *)mixstream, 0, SEEK_SET);
+      n = remix_stream_gain (env, mixstream, n, track->gain);
+
+      remix_seek (env, (RemixBase *)mixstream, 0, SEEK_SET);
+      remix_seek (env, (RemixBase *)output, output_offset, SEEK_SET);
+      n = remix_stream_mix (env, mixstream, output, n);
+    }
+
+    processed += n;
+    remaining -= n;
+  }
+
+  remix_dprintf ("[remix_deck_process] processed %ld\n", processed);
+
+  return processed;
+}
+
+static RemixCount
+remix_deck_twotrack_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                             RemixStream * input, RemixStream * output)
+{
+  RemixDeck * deck = (RemixDeck *)base;
+  CDList * l;
+  RemixTrack * track1, * track2;
+  RemixCount n;
+  RemixCount current_offset = remix_tell (env, base);
+  RemixCount input_offset = remix_tell (env, (RemixBase *)input);
+  RemixCount output_offset = remix_tell (env, (RemixBase *)output);
+  RemixStream * mixstream = deck->_mixstream;
+
+  remix_dprintf ("PROCESS DECK [twotrack] (%p, +%ld, %p -> %p) @ %ld\n",
+                 deck, count, input, output, current_offset);
+
+  l = deck->tracks;
+  track1 = (RemixTrack *)l->data.s_pointer;
+
+  l = l->next;
+  track2 = (RemixTrack *)l->data.s_pointer;
+
+  n = remix_process (env, (RemixBase *)track1, count, input, output);
+
+  remix_seek (env, (RemixBase *)output, output_offset, SEEK_SET);
+  n = remix_stream_gain (env, output, n, track1->gain);
+
+  remix_seek (env, (RemixBase *)input, input_offset, SEEK_SET);
+  remix_seek (env, (RemixBase *)mixstream, 0, SEEK_SET);
+  n = remix_process (env, (RemixBase *)track2, n, input, mixstream);
+
+  remix_seek (env, (RemixBase *)mixstream, 0, SEEK_SET);
+  n = remix_stream_gain (env, mixstream, n, track2->gain);
+
+  remix_seek (env, (RemixBase *)mixstream, 0, SEEK_SET);
+  remix_seek (env, (RemixBase *)output, output_offset, SEEK_SET);
+  n = remix_stream_mix (env, mixstream, output, n);
+
+  remix_dprintf ("[remix_deck_twotrack_process] processed %ld\n", n);
+
+  return n;
+}
+
+static RemixCount
+remix_deck_onetrack_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                             RemixStream * input, RemixStream * output)
+{
+  RemixDeck * deck = (RemixDeck *)base;
+  RemixTrack * track = (RemixTrack *)deck->tracks->data.s_pointer;
+  RemixCount n;
+
+  remix_dprintf ("PROCESS DECK [onetrack] (%p, +%ld, %p -> %p) @ %ld\n",
+                 deck, count, input, output, remix_tell (env, base));
+
+  n = remix_process (env, (RemixBase *)track, count, input, output);
+
+  remix_dprintf ("*** deck @ %ld\ttrack @ %ld\n", remix_tell (env, base),
+                 remix_tell (env, (RemixBase *)track));
+
+  remix_dprintf ("[remix_deck_onetrack_process] processed %ld\n", n);
+
+  return n;
+}
+
+static RemixCount
+remix_deck_seek (RemixEnv * env, RemixBase * base, RemixCount offset)
+{
+  RemixDeck * deck = (RemixDeck *)base;
+  CDList * l;
+  RemixTrack * track;
+
+  for (l = deck->tracks; l; l = l->next) {
+    track = (RemixTrack *)l->data.s_pointer;
+    remix_seek (env, (RemixBase *)track, offset, SEEK_SET);
+  }
+
+  return offset;
+}
+
+static int
+remix_deck_flush (RemixEnv * env, RemixBase * base)
+{
+  RemixDeck * deck = (RemixDeck *)base;
+  CDList * l;
+  RemixTrack * track;
+
+  for (l = deck->tracks; l; l = l->next) {
+    track = (RemixTrack *)l->data.s_pointer;
+    remix_flush (env, (RemixBase *)track);
+  }
+
+  return 0;
+}
+
+static struct _RemixMethods _remix_deck_empty_methods = {
+  remix_deck_clone,   /* clone */
+  remix_deck_destroy, /* destroy */
+  remix_deck_ready,   /* ready */
+  remix_deck_prepare, /* preapre */
+  remix_null_process, /* process */
+  remix_null_length,  /* length */
+  NULL,            /* seek */
+  NULL,            /* flush */
+};
+
+static struct _RemixMethods _remix_deck_methods = {
+  remix_deck_clone,   /* clone */
+  remix_deck_destroy, /* destroy */
+  remix_deck_ready,   /* ready */
+  remix_deck_prepare, /* preapre */
+  remix_deck_process, /* process */
+  remix_deck_length,  /* length */
+  remix_deck_seek,    /* seek */
+  remix_deck_flush,   /* flush */
+};
+
+static struct _RemixMethods _remix_deck_onetrack_methods = {
+  remix_deck_clone,            /* clone */
+  remix_deck_destroy,          /* destroy */
+  remix_deck_ready,            /* ready */
+  remix_deck_prepare,          /* preapre */
+  remix_deck_onetrack_process, /* process */
+  remix_deck_length,           /* length */
+  remix_deck_seek,             /* seek */
+  remix_deck_flush,   /* flush */
+};
+
+static struct _RemixMethods _remix_deck_twotrack_methods = {
+  remix_deck_clone,            /* clone */
+  remix_deck_destroy,          /* destroy */
+  remix_deck_ready,            /* ready */
+  remix_deck_prepare,          /* preapre */
+  remix_deck_twotrack_process, /* process */
+  remix_deck_length,           /* length */
+  remix_deck_seek,             /* seek */
+  remix_deck_flush,   /* flush */
+};
+
+static RemixDeck *
+remix_deck_optimise (RemixEnv * env, RemixDeck * deck)
+{
+  int nr_tracks = cd_list_length (env, deck->tracks);
+
+  switch (nr_tracks) {
+  case 0: _remix_set_methods (env, deck, &_remix_deck_empty_methods); break;
+  case 1: _remix_set_methods (env, deck, &_remix_deck_onetrack_methods); break;
+  case 2: _remix_set_methods (env, deck, &_remix_deck_twotrack_methods); break;
+  default: _remix_set_methods (env, deck, &_remix_deck_methods); break;
+  }
+
+  return deck;
+}
diff --git a/src/libremix/remix_envelope.c b/src/libremix/remix_envelope.c
new file mode 100644 (file)
index 0000000..f039bc0
--- /dev/null
@@ -0,0 +1,542 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixEnvelope: Generic mathy envelopes for env.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#define __REMIX__
+#include "remix.h"
+
+/* Optimisation dependencies: optimise when adding and removing points
+ * or changing envelope type */
+static RemixEnvelope *
+remix_envelope_optimise (RemixEnv * env, RemixEnvelope * envelope);
+
+static void
+remix_envelope_debug (RemixEnv * env, RemixEnvelope * envelope)
+{
+#ifdef DEBUG
+  CDList * l;
+  RemixPoint * point;
+
+  printf ("envelope %p\n", envelope);
+  printf ("envelope->points: %p\n", envelope->points);
+
+  /*  printf (" has %d points\n", cd_list_length (env, envelope->points));*/
+  for (l = envelope->points; l; l = l->next) {
+    point = (RemixPoint *)l->data.s_pointer;
+    switch (envelope->timetype) {
+    case REMIX_TIME_SAMPLES:
+      printf ("%ld samples, %f\n", point->time.samples, point->value);
+      break;
+    case REMIX_TIME_SECONDS:
+      printf ("%f seconds, %f\n", point->time.seconds, point->value);
+      break;
+    case REMIX_TIME_BEAT24S:
+      printf ("%d beat24s, %f\n", point->time.beat24s, point->value);
+      break;
+    default:
+      printf ("*** unknown envelope->timetype ***\n");
+      break;
+    }
+  }
+#endif
+}
+
+static RemixPoint *
+remix_point_new (RemixTime time, RemixPCM value)
+{
+  RemixPoint * point = remix_malloc (sizeof (struct _RemixPoint));
+  point->time = time;
+  point->value = value;
+  return point;
+}
+
+static RemixPoint *
+remix_point_clone (RemixEnv * env, RemixPoint * point)
+{
+  return remix_point_new (point->time, point->value);
+}
+
+static int
+remix_point_later_X (RemixEnv * env, RemixPoint * p1, RemixPoint * p2)
+{
+  return _remix_time_gt(REMIX_TIME_SAMPLES, p1->time, p2->time);
+}
+
+static int
+remix_point_later_S (RemixEnv * env, RemixPoint * p1, RemixPoint * p2)
+{
+  return _remix_time_gt(REMIX_TIME_SECONDS, p1->time, p2->time);
+}
+
+static int
+remix_point_later_B (RemixEnv * env, RemixPoint * p1, RemixPoint * p2)
+{
+  return _remix_time_gt(REMIX_TIME_BEAT24S, p1->time, p2->time);
+}
+
+RemixBase *
+remix_envelope_init (RemixEnv * env, RemixBase * base)
+{
+  RemixEnvelope * envelope = (RemixEnvelope *)base;
+  envelope->type = REMIX_ENVELOPE_LINEAR;
+  envelope->points = cd_list_new (env);
+  remix_envelope_optimise (env, envelope);
+  return (RemixBase *)envelope;
+}
+
+RemixEnvelope *
+remix_envelope_new (RemixEnv * env, RemixEnvelopeType type)
+{
+  RemixEnvelope * envelope = (RemixEnvelope *)
+    remix_base_new_subclass (env, sizeof (struct _RemixEnvelope));
+  remix_envelope_init (env, (RemixBase *)envelope);
+  envelope->type = type;
+  remix_envelope_debug (env, envelope);
+
+  return envelope;
+}
+
+RemixBase *
+remix_envelope_clone (RemixEnv * env, RemixBase * base)
+{
+  RemixEnvelope * envelope = (RemixEnvelope *)base;
+  RemixEnvelope * new_envelope = remix_envelope_new (env, envelope->type);
+  new_envelope->points = cd_list_clone (env, envelope->points,
+                                       (CDCloneFunc)remix_point_clone);
+  remix_envelope_optimise (env, new_envelope);
+  return (RemixBase *)new_envelope;
+}
+
+static int
+remix_envelope_destroy (RemixEnv * env, RemixBase * base)
+{
+  RemixEnvelope * envelope = (RemixEnvelope *)base;
+  cd_list_free_all (env, envelope->points);
+  remix_free (envelope);
+  return 0;
+}
+
+RemixEnvelopeType
+remix_envelope_set_type (RemixEnv * env, RemixEnvelope * envelope, RemixEnvelopeType type)
+{
+  RemixEnvelopeType old = envelope->type;
+  envelope->type = type;
+  remix_envelope_optimise (env, envelope);
+  return old;
+}
+
+RemixEnvelopeType
+remix_envelope_get_type (RemixEnv * env, RemixEnvelope * envelope)
+{
+  return envelope->type;
+}
+
+RemixTimeType
+remix_envelope_set_timetype (RemixEnv * env, RemixEnvelope * envelope,
+                         RemixTimeType timetype)
+{
+  RemixTimeType old = envelope->timetype;
+  envelope->timetype = timetype;
+  return old;
+}
+
+RemixTimeType
+remix_envelope_get_timetype (RemixEnv * env, RemixEnvelope * envelope)
+{
+  return envelope->timetype;
+}
+
+RemixTime
+remix_envelope_get_duration (RemixEnv * env, RemixEnvelope * envelope)
+{
+  CDList * l = cd_list_last_item (env, envelope->points);
+  RemixPoint * p;
+
+  if (l == RemixNone) return _remix_time_zero (envelope->timetype);
+
+  p = (RemixPoint *)l->data.s_pointer;
+  if (p == RemixNone) return _remix_time_zero (envelope->timetype);
+
+  return p->time;
+}
+
+RemixPoint *
+remix_envelope_add_point (RemixEnv * env, RemixEnvelope * envelope,
+                          RemixTime time, RemixPCM value)
+{
+  RemixPoint * point = remix_point_new (time, value);
+  switch (envelope->timetype) {
+  case REMIX_TIME_SAMPLES:
+    envelope->points = cd_list_insert (env, envelope->points,
+                                      CD_TYPE_POINTER, CD_POINTER(point),
+                                      (CDCmpFunc)remix_point_later_X);
+    break;
+  case REMIX_TIME_SECONDS:
+    envelope->points = cd_list_insert (env, envelope->points,
+                                      CD_TYPE_POINTER, CD_POINTER(point),
+                                      (CDCmpFunc)remix_point_later_S);
+    break;
+  case REMIX_TIME_BEAT24S:
+    envelope->points = cd_list_insert (env, envelope->points,
+                                      CD_TYPE_POINTER, CD_POINTER(point),
+                                      (CDCmpFunc)remix_point_later_B);
+    break;
+  default: /* uncommon, we should hope */
+    remix_free (point); point = RemixNone;
+    break;
+  }
+  remix_envelope_debug (env, envelope);
+  remix_envelope_optimise (env, envelope);
+  return point;
+}
+
+RemixEnvelope *
+remix_envelope_remove_point (RemixEnv * env, RemixEnvelope * envelope,
+                             RemixPoint * point)
+{
+  envelope->points = cd_list_remove (env, envelope->points,
+                                    CD_TYPE_POINTER, CD_POINTER(point));
+  remix_free (point);
+  remix_envelope_debug (env, envelope);
+  remix_envelope_optimise (env, envelope);
+  return envelope;
+}
+
+RemixEnvelope *
+remix_envelope_scale (RemixEnv * env, RemixEnvelope * envelope, RemixPCM gain)
+{
+  CDList * l;
+  RemixPoint * p;
+
+  for (l = envelope->points; l; l = l->next) {
+    p = (RemixPoint *)l->data.s_pointer;
+    p->value *= gain;
+  }
+
+  return envelope;
+}
+
+RemixEnvelope *
+remix_envelope_shift (RemixEnv * env, RemixEnvelope * envelope, RemixTime delta)
+{
+  CDList * l;
+  RemixPoint * p;
+
+  for (l = envelope->points; l; l = l->next) {
+    p = (RemixPoint *)l->data.s_pointer;
+    p->time = _remix_time_add (envelope->timetype, p->time, delta);
+  }
+
+  return envelope;
+}
+
+static CDList *
+remix_envelope_point_item_before (RemixEnv * env, RemixEnvelope * envelope,
+                                  RemixCount offset)
+{
+  CDList * l, * lp = RemixNone;
+  RemixPoint * point;
+  RemixTime ptime;
+
+  for (l = envelope->points; l; l = l->next) {
+    point = (RemixPoint *)l->data.s_pointer;
+    ptime = remix_time_convert (env, point->time, envelope->timetype,
+                                REMIX_TIME_SAMPLES);
+    if (ptime.samples > offset) break;
+    lp = l;
+  }
+  return lp;
+}
+
+static RemixCount
+remix_envelope_constant_write_chunk (RemixEnv * env, RemixChunk * chunk,
+                                     RemixCount offset, RemixCount count,
+                                     int channelname, void * data)
+{
+  RemixEnvelope * envelope = (RemixEnvelope *)data;
+  RemixPoint * point;
+  RemixPCM value;
+  RemixPCM * d;
+  RemixCount n;
+
+  point = (RemixPoint *)envelope->points->data.s_pointer;
+  value = point->value;
+  d = &chunk->data[offset];
+
+  n = _remix_pcm_set (d, value, count);
+  envelope->_current_offset += n;
+  return n;
+}
+
+#if 0
+static RemixCount
+remix_envelope_spline_write_chunk (RemixEnv * env, RemixChunk * chunk,
+                                   RemixCount offset, RemixCount count,
+                                   int channelname, void * data)
+{
+  RemixEnvelope * envelope = (RemixEnvelope *)data;
+  /* XXX: Implement ;) */
+  return -1;
+}
+#endif
+
+/* A RemixChunkFunc for creating envelope data */
+static RemixCount
+remix_envelope_linear_write_chunk (RemixEnv * env, RemixChunk * chunk,
+                                   RemixCount offset, RemixCount count,
+                                   int channelname, void * data)
+{
+  RemixEnvelope * envelope = (RemixEnvelope *)data;
+  RemixCount remaining = count, written = 0;
+  RemixCount pos = envelope->_current_offset;
+  CDList * l, * nl;
+  RemixPoint * point, * next_point;
+  RemixCount px, npx, n;
+  RemixTime t;
+  RemixPCM py, npy, gradient;
+  RemixPCM * d;
+
+  remix_dprintf ("[remix_envelope_linear_write_chunk] (%ld, +%ld) @ %ld\n",
+         offset, count, pos);
+
+
+  l = envelope->_current_point_item;
+
+  if (l == RemixNone) {/* No points before start */
+    l = envelope->points;
+    if (l == RemixNone) {/* No points at all */
+      n = _remix_chunk_clear_region (env, chunk, offset, count, 0, NULL);
+      envelope->_current_offset += n;
+      return n;
+    }
+  }
+
+  nl = l->next;
+  if (nl == RemixNone) {
+    /* if the last point was before offset, and there were
+     * more points, set l to the second last and nl to the last */
+    nl = l; l = l->prev;
+    if (l == RemixNone) {/* Constant envelope (one point) */
+      return remix_envelope_constant_write_chunk (env, chunk, offset, count,
+                                              channelname, envelope);
+    }
+  }
+
+  point = (RemixPoint *)l->data.s_pointer;
+  t = remix_time_convert (env, point->time, envelope->timetype,
+                          REMIX_TIME_SAMPLES);
+  px = t.samples;
+  py = point->value;
+
+  next_point = (RemixPoint *)nl->data.s_pointer;
+  t = remix_time_convert (env, next_point->time, envelope->timetype,
+                          REMIX_TIME_SAMPLES);
+  npx = t.samples;
+  npy = next_point->value;
+
+  while (remaining > 0) {
+    if (nl->next == RemixNone) {
+      /* These are the last two points, so fill out with this gradient */
+      n = remaining;
+    } else {
+      n = MIN (remaining, npx - pos);
+    }
+    gradient = (npy - py) / (RemixPCM)(npx - px);
+
+    d = &chunk->data[offset];
+    /*  _remix_pcm_write_linear (d, px - chunk->start_index, py, gradient, n);*/
+    n = _remix_pcm_write_linear (d, px, py, npx, npy, pos, n);
+
+    remaining -= n;
+    written += n;
+    pos += n;
+    offset += n;
+
+    if (remaining > 0) {
+      l = nl; point = next_point; px = npx; py = npy;
+
+      nl = nl->next;
+      next_point = (RemixPoint *)nl->data.s_pointer;
+      t = remix_time_convert (env, next_point->time, envelope->timetype,
+                              REMIX_TIME_SAMPLES);
+      npx = t.samples;
+      npy = next_point->value;
+    }
+  }
+
+  envelope->_current_point_item = l;
+  envelope->_current_offset = pos;
+
+  return written;
+}
+
+static RemixCount
+remix_envelope_constant_process (RemixEnv * env, RemixBase * base,
+                                 RemixCount count, RemixStream * input,
+                                 RemixStream * output)
+{
+  RemixEnvelope * envelope = (RemixEnvelope *)base;
+  return remix_stream_chunkfuncify (env, output, count,
+                                    remix_envelope_constant_write_chunk,
+                                    envelope);
+}
+
+static RemixCount
+remix_envelope_spline_process (RemixEnv * env, RemixBase * base,
+                               RemixCount count, RemixStream * input,
+                               RemixStream * output)
+{
+  /* XXX: Implement */
+  return -1;
+}
+
+static RemixCount
+remix_envelope_linear_process (RemixEnv * env, RemixBase * base,
+                               RemixCount count, RemixStream * input,
+                               RemixStream * output)
+{
+  RemixEnvelope * envelope = (RemixEnvelope *)base;
+  return remix_stream_chunkfuncify (env, output, count,
+                                    remix_envelope_linear_write_chunk,
+                                    envelope);
+}
+
+static RemixCount
+remix_envelope_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                        RemixStream * input, RemixStream * output)
+{
+  RemixEnvelope * envelope = (RemixEnvelope *)base;
+
+  switch (envelope->type) {
+  case REMIX_ENVELOPE_LINEAR:
+    return remix_envelope_linear_process (env, base, count, input, output);
+    break;
+  case REMIX_ENVELOPE_SPLINE:
+    return remix_envelope_spline_process (env, base, count, input, output);
+    break;
+  default:
+    break;
+  }
+  remix_set_error (env, REMIX_ERROR_NOOP);
+  return 0;
+}
+
+static RemixCount
+remix_envelope_length (RemixEnv * env, RemixBase * base)
+{
+  RemixEnvelope * envelope = (RemixEnvelope *)base;
+  RemixTime duration = remix_envelope_get_duration (env, envelope);
+  RemixTime t = remix_time_convert (env, duration, envelope->timetype,
+                                    REMIX_TIME_SAMPLES);
+  return t.samples;
+}
+
+static RemixCount
+remix_envelope_seek (RemixEnv * env, RemixBase * base, RemixCount offset)
+{
+  RemixEnvelope * envelope = (RemixEnvelope *)base;
+  envelope->_current_point_item =
+    remix_envelope_point_item_before (env, envelope, offset);
+  envelope->_current_offset = offset;
+  return offset;
+}
+
+static struct _RemixMethods _remix_envelope_empty_methods = {
+  remix_envelope_clone,
+  remix_envelope_destroy,
+  NULL, /* ready */
+  NULL, /* prepare */
+  remix_null_process,
+  remix_null_length,
+  remix_envelope_seek,
+  NULL, /* flush */
+};
+
+static struct _RemixMethods _remix_envelope_constant_methods = {
+  remix_envelope_clone,
+  remix_envelope_destroy,
+  NULL, /* ready */
+  NULL, /* prepare */
+  remix_envelope_constant_process,
+  remix_envelope_length,
+  remix_envelope_seek,
+  NULL, /* flush */
+};
+
+static struct _RemixMethods _remix_envelope_linear_methods = {
+  remix_envelope_clone,
+  remix_envelope_destroy,
+  NULL, /* ready */
+  NULL, /* prepare */
+  remix_envelope_linear_process,
+  remix_envelope_length,
+  remix_envelope_seek,
+  NULL, /* flush */
+};
+
+static struct _RemixMethods _remix_envelope_spline_methods = {
+  remix_envelope_clone,
+  remix_envelope_destroy,
+  NULL, /* ready */
+  NULL, /* prepare */
+  remix_envelope_spline_process,
+  remix_envelope_length,
+  remix_envelope_seek,
+  NULL, /* flush */
+};
+
+static struct _RemixMethods _remix_envelope_methods = {
+  remix_envelope_clone,
+  remix_envelope_destroy,
+  NULL, /* ready */
+  NULL, /* prepare */
+  remix_envelope_process,
+  remix_envelope_length,
+  remix_envelope_seek,
+  NULL, /* flush */
+};
+
+static RemixEnvelope *
+remix_envelope_optimise (RemixEnv * env, RemixEnvelope * envelope)
+{
+  if (cd_list_is_empty (env, envelope->points)) {
+    _remix_set_methods (env, envelope, &_remix_envelope_empty_methods);
+  } else if (cd_list_is_singleton (env, envelope->points)) {
+    _remix_set_methods (env, envelope, &_remix_envelope_constant_methods);
+  } else {
+    switch (envelope->type) {
+    case REMIX_ENVELOPE_LINEAR:
+      _remix_set_methods (env, envelope, &_remix_envelope_linear_methods); break;
+    case REMIX_ENVELOPE_SPLINE:
+      _remix_set_methods (env, envelope, &_remix_envelope_spline_methods); break;
+    default:
+      _remix_set_methods (env, envelope, &_remix_envelope_methods); break;
+    }
+  }
+
+  return envelope;
+}
diff --git a/src/libremix/remix_error.c b/src/libremix/remix_error.c
new file mode 100644 (file)
index 0000000..41791bb
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixError -- SOUNDRENDER error handling.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#define __REMIX__
+#include "remix.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+
+char *
+remix_error_string (RemixEnv * env, RemixError error)
+{
+  switch (error) {
+  case REMIX_ERROR_OK: return "OK"; break;
+  case REMIX_ERROR_INVALID: return "Invalid base"; break;
+  case REMIX_ERROR_NOENTITY: return "No such base"; break;
+  case REMIX_ERROR_SILENCE: return "Operation would yield silence"; break;
+  case REMIX_ERROR_NOOP: return "Operation would not modify data"; break;
+  case REMIX_ERROR_SYSTEM: return "System error"; break;
+  default: return "Unknown error"; break;
+  }
+}
+
+/*
+ * remix_exit_err (fmt)
+ *
+ * Print a formatted error message and errno information to stderr,
+ * then exit with return code 1.
+ */
+void
+remix_exit_err (const char * fmt, ...)
+{
+  va_list ap;
+  int errno_save;
+  char buf[REMIX_MAXLINE];
+  int n;
+
+  errno_save = errno;
+
+  va_start (ap, fmt);
+
+  snprintf (buf, REMIX_MAXLINE, "Remix: ");
+  n = strlen (buf);
+
+  vsnprintf (buf+n, REMIX_MAXLINE-n, fmt, ap);
+  n = strlen (buf);
+
+  snprintf (buf+n, REMIX_MAXLINE-n, ": %s\n", strerror (errno_save));
+
+  fflush (stdout); /* in case stdout and stderr are the same */
+  fputs (buf, stderr);
+  fflush (NULL);
+
+  va_end (ap);
+  exit (1);
+}
+
+/*
+ * remix_print_err (fmt)
+ *
+ * Print a formatted error message to stderr.
+ */
+void
+remix_print_err (const char * fmt, ...)
+{
+  va_list ap;
+  int errno_save;
+  char buf[REMIX_MAXLINE];
+  int n;
+
+  errno_save = errno;
+
+  va_start (ap, fmt);
+
+  snprintf (buf, REMIX_MAXLINE, "SOUNDRENDER: ");
+  n = strlen (buf);
+
+  vsnprintf (buf+n, REMIX_MAXLINE-n, fmt, ap);
+  n = strlen (buf);
+
+  fflush (stdout); /* in case stdout and stderr are the same */
+  fputs (buf, stderr);
+  fputc ('\n', stderr);
+  fflush (NULL);
+
+  va_end (ap);
+}
+
+/*
+ * print_debug (level, fmt)
+ *
+ * Print a formatted debugging message of level 'level' to stderr
+ */
+
diff --git a/src/libremix/remix_gain.c b/src/libremix/remix_gain.c
new file mode 100644 (file)
index 0000000..86e2c9b
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixGain: a gain filter
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#include <stdlib.h>
+
+#define __REMIX_PLUGIN__
+#include "remix.h"
+
+#define GAIN_ENVELOPE_KEY 1
+
+typedef struct _RemixGain RemixGain;
+
+struct _RemixGain {
+  RemixStream * _gain_envstream;
+};
+
+/* Optimisation dependencies: none */
+static RemixBase * remix_gain_optimise (RemixEnv * env, RemixBase * gain);
+
+static void
+remix_gain_replace_mixstream (RemixEnv * env, RemixBase * gain)
+{
+  RemixCount mixlength = remix_base_get_mixlength (env, gain);
+  RemixGain * gi = (RemixGain *)remix_base_get_instance_data (env, gain);
+
+  if (gi->_gain_envstream != RemixNone)
+    remix_destroy (env, (RemixBase *)gi->_gain_envstream);
+
+  gi->_gain_envstream =
+    remix_stream_new_contiguous (env, mixlength);
+}
+
+static RemixBase *
+remix_gain_init (RemixEnv * env, RemixBase * base, CDSet * parameters)
+{
+  remix_base_set_instance_data (env, base,
+                              calloc (1, sizeof (struct _RemixGain)));
+  remix_gain_replace_mixstream (env, base);
+  remix_gain_optimise (env, base);
+  return base;
+}
+
+static RemixBase *
+remix_gain_clone (RemixEnv * env, RemixBase * base)
+{
+  RemixBase * new_gain = remix_base_new (env);
+  remix_gain_init (env, new_gain, CD_EMPTY_SET);
+  remix_gain_optimise (env, new_gain);
+  return (RemixBase *)new_gain;
+}
+
+static int
+remix_gain_destroy (RemixEnv * env, RemixBase * base)
+{
+  free (remix_base_get_instance_data (env, base));
+  free (base);
+  return 0;
+}
+
+static int
+remix_gain_ready (RemixEnv * env, RemixBase * base)
+{
+  return (remix_base_encompasses_mixlength (env, base) &&
+         remix_base_encompasses_channels (env, base));
+}
+
+static RemixBase *
+remix_gain_prepare (RemixEnv * env, RemixBase * base)
+{
+  remix_gain_replace_mixstream (env, base);
+  return base;
+}
+
+static RemixCount
+remix_gain_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                RemixStream * input, RemixStream * output)
+{
+  RemixCount remaining = count, processed = 0, n;
+  RemixCount output_offset;
+  RemixCount mixlength = remix_base_get_mixlength (env, base);
+  RemixBase * gain_envelope;
+  RemixGain * gi = remix_base_get_instance_data (env, base);
+
+  remix_dprintf ("PROCESS GAIN (%p, +%ld) @ %ld\n", base, count,
+             remix_tell (env, base));
+
+  gain_envelope =
+    (RemixBase *) (remix_get_parameter (env, base, GAIN_ENVELOPE_KEY)).s_pointer;
+
+  if (gain_envelope == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOOP);
+    return -1;
+  }
+
+  while (remaining > 0) {
+    n = MIN (remaining, mixlength);
+
+    output_offset = remix_tell (env, (RemixBase *)output);
+    n = remix_stream_copy (env, input, output, n);
+
+    remix_seek (env, (RemixBase *)gi->_gain_envstream, 0, SEEK_SET);
+    n = remix_process (env, gain_envelope, n, RemixNone,
+                   gi->_gain_envstream);
+
+    remix_seek (env, (RemixBase *)gi->_gain_envstream, 0, SEEK_SET);
+    remix_seek (env, (RemixBase *)output, output_offset, SEEK_SET);
+    n = remix_stream_mult (env, gi->_gain_envstream, output, n);
+
+    remaining -= n;
+    processed += n;
+  }
+
+  remix_dprintf ("[remix_gain_process] processed %ld\n", processed);
+
+  return processed;
+}
+
+static RemixCount
+remix_gain_length (RemixEnv * env, RemixBase * base)
+{
+  RemixBase * gain_envelope =
+    (RemixBase *) (remix_get_parameter (env, base, GAIN_ENVELOPE_KEY)).s_pointer;
+
+  if (gain_envelope == RemixNone) {
+    return REMIX_COUNT_INFINITE;
+  }
+
+  return remix_length (env, gain_envelope);
+}
+
+static RemixCount
+remix_gain_seek (RemixEnv * env, RemixBase * base, RemixCount offset)
+{
+  RemixBase * gain_envelope =
+    (RemixBase *) (remix_get_parameter (env, base, GAIN_ENVELOPE_KEY)).s_pointer;
+
+  return remix_seek (env, (RemixBase *)gain_envelope, offset, SEEK_SET);
+}
+
+static struct _RemixMethods _remix_gain_methods = {
+  remix_gain_clone,
+  remix_gain_destroy,
+  remix_gain_ready,
+  remix_gain_prepare,
+  remix_gain_process,
+  remix_gain_length,
+  remix_gain_seek,
+};
+
+static RemixBase *
+remix_gain_optimise (RemixEnv * env, RemixBase * gain)
+{
+  remix_base_set_methods (env, gain, &_remix_gain_methods);
+  return gain;
+}
+
+static int
+remix_gain_plugin_destroy (RemixEnv * env, RemixPlugin * plugin)
+{
+  cd_set_free (env, plugin->process_scheme);
+  return 0;
+}
+
+static struct _RemixParameterScheme gain_envelope_scheme = {
+  "Gain envelope",
+  "An envelope to control the amplitude",
+  REMIX_TYPE_BASE,
+  REMIX_CONSTRAINT_TYPE_NONE,
+  REMIX_CONSTRAINT_EMPTY,
+  REMIX_HINT_DEFAULT,
+};
+
+static struct _RemixMetaText gain_metatext = {
+  "builtin::gain",
+  "Processors::Gain Adjustment",
+  "Adjusts the gain of its input",
+  "Copyright (C) 2001 CSIRO Australia",
+  "http://www.metadecks.org/env/plugins/gain.html",
+  REMIX_ONE_AUTHOR ("Conrad Parker", "conrad@metadecks.org"),
+};
+
+static struct _RemixPlugin gain_plugin = {
+  &gain_metatext,
+  REMIX_FLAGS_NONE,
+  CD_EMPTY_SET, /* new scheme */
+  remix_gain_init,
+  CD_EMPTY_SET, /* process_scheme */
+  NULL, /* suggests */
+  NULL, /* plugin_data */
+  remix_gain_plugin_destroy /* destroy */
+};
+
+/* module init function */
+CDList *
+__gain_init (RemixEnv * env)
+{
+  CDList * plugins = cd_list_new (env);
+
+  gain_plugin.process_scheme =
+    cd_set_insert (env, gain_plugin.process_scheme, GAIN_ENVELOPE_KEY,
+                  CD_POINTER(&gain_envelope_scheme));
+
+  plugins = cd_list_prepend (env, plugins, CD_POINTER(&gain_plugin));
+
+  return plugins;
+}
diff --git a/src/libremix/remix_layer.c b/src/libremix/remix_layer.c
new file mode 100644 (file)
index 0000000..158fe09
--- /dev/null
@@ -0,0 +1,653 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixLayer: A sound sequence abstraction.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ *
+ * Description
+ * -----------
+ *
+ * A layer is contained within a track. It consists of a sequence of
+ * sounds. A layer has a time type (RemixTimeType) with which its sounds
+ * are indexed.
+ * XXX: Overlapping sounds in a layer should be mixed together.
+ *
+ * Invariants
+ * ----------
+ *
+ * A layer must be contained in a track.
+ *
+ */
+
+#define __REMIX__
+#include "remix.h"
+
+/* Optimisation dependencies: none */
+static RemixLayer * remix_layer_optimise (RemixEnv * env, RemixLayer * layer);
+
+/* Coherency dependencies: ensure coherency on addition+removal of sounds */
+static RemixLayer * remix_layer_ensure_coherency (RemixEnv * env, RemixLayer * layer);
+
+void
+remix_layer_debug (RemixEnv * env, RemixLayer * layer)
+{
+#ifdef DEBUG
+  CDList * l;
+  RemixSound * s;
+
+  remix_dprintf ("Layer (0x%p): ", layer);
+  if (layer == RemixNone) return;
+
+  for (l = layer->sounds; l; l = l->next) {
+    s = (RemixSound *)l->data.s_pointer;
+    /* XXX: assumes samples */
+    remix_dprintf ("[0x%p: %ld, +%ld] ", s, s->start_time.samples,
+               s->duration.samples);
+  }
+  remix_dprintf ("\n");
+#endif
+}
+
+static RemixBase *
+remix_layer_init (RemixEnv * env, RemixBase * base)
+{
+  RemixLayer * layer = (RemixLayer *)base;
+  layer->timetype = REMIX_TIME_SAMPLES;
+  layer->sounds = cd_list_new (env);
+  /*  layer->_current_time = _remix_time_zero (layer->timetype);*/
+  layer->_current_sound_item = RemixNone;
+  layer->_current_tempo = remix_get_tempo (env);
+  layer->_current_offset = 0;
+  remix_layer_optimise (env, layer);
+  return (RemixBase *)layer;
+}
+
+static RemixBase *
+_remix_layer_new (RemixEnv * env)
+{
+  return (RemixBase *)
+    remix_base_new_subclass (env, sizeof (struct _RemixLayer));
+}
+
+RemixBase *
+remix_layer_clone (RemixEnv * env, RemixBase * base)
+{
+  RemixLayer * layer = (RemixLayer *)base;
+  RemixLayer * new_layer = (RemixLayer *)_remix_layer_new (env);
+  RemixCount offset = remix_tell (env, base);
+
+  new_layer->timetype = layer->timetype;
+  new_layer->sounds =
+    cd_list_clone_with (env, layer->sounds,
+                       (CDCloneWithFunc)remix_sound_clone_with_layer,
+                       new_layer);
+  remix_seek (env, (RemixBase *)new_layer, offset, SEEK_SET);
+
+  new_layer->track = layer->track;
+  _remix_track_add_layer_above (env, layer->track, new_layer, layer);
+
+  return (RemixBase *)new_layer;
+}
+
+static int
+remix_layer_destroy (RemixEnv * env, RemixBase * base)
+{
+  RemixLayer * layer = (RemixLayer *)base;
+  if (layer->track)
+    _remix_track_remove_layer (env, layer->track, layer);
+  remix_destroy_list (env, layer->sounds);
+  remix_free (layer);
+  return 0;
+}
+
+RemixLayer *
+remix_layer_new_ontop (RemixEnv * env, RemixTrack * track,
+                      RemixTimeType timetype)
+{
+  RemixLayer * layer = (RemixLayer *)_remix_layer_new (env);
+
+  layer->track = track;
+  _remix_track_add_layer_above (env, track, layer, RemixNone);
+  remix_layer_init (env, (RemixBase *)layer);
+  layer->timetype = timetype;
+
+  return layer;
+}
+
+RemixLayer *
+remix_layer_new_above (RemixEnv * env, RemixLayer * above,
+                      RemixTimeType timetype)
+{
+  RemixLayer * layer;
+  if (above == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  layer = (RemixLayer *)_remix_layer_new (env);
+  layer->track = above->track;
+  _remix_track_add_layer_above (env, above->track, layer, above);
+  remix_layer_init (env, (RemixBase *)layer);
+  layer->timetype = timetype;
+
+  return layer;
+}
+
+RemixLayer *
+remix_layer_move_ontop (RemixEnv * env, RemixLayer * layer, RemixTrack * track)
+{
+  if (layer->track)
+    _remix_track_remove_layer (env, layer->track, layer);
+
+  if (track)
+    _remix_track_add_layer_above (env, track, layer, RemixNone);
+
+  return layer;
+}
+
+RemixLayer *
+remix_layer_move_above (RemixEnv * env, RemixLayer * layer, RemixLayer * above)
+{
+  if (layer->track)
+    _remix_track_remove_layer (env, layer->track, layer);
+
+  if (above->track)
+    _remix_track_add_layer_above (env, above->track, layer, above);
+
+  return layer;
+}
+
+RemixLayer *
+remix_layer_raise (RemixEnv * env, RemixLayer * layer)
+{
+  RemixLayer * above;
+
+  if (layer->track) {
+    above = _remix_track_get_layer_above (env, layer->track, layer);
+    remix_layer_move_above (env, layer, above);
+  }
+
+  return layer;
+}
+
+RemixLayer *
+remix_layer_lower (RemixEnv * env, RemixLayer * layer)
+{
+  RemixLayer * below;
+
+  if (layer->track) {
+    below = _remix_track_get_layer_below (env, layer->track, layer);
+    remix_layer_move_above (env, below, layer);
+  }
+
+  return layer;
+}
+
+RemixLayer *
+_remix_remove_layer (RemixEnv * env, RemixLayer * layer)
+{
+  if (layer->track)
+    _remix_track_remove_layer (env, layer->track, layer);
+
+  layer->track = RemixNone;
+  return layer;
+}
+
+RemixTrack *
+remix_layer_get_track (RemixEnv * env, RemixLayer * layer)
+{
+  return layer->track;
+}
+
+RemixDeck *
+remix_layer_get_deck (RemixEnv * env, RemixLayer * layer)
+{
+  RemixTrack * track = layer->track;
+  if (track == RemixNone) return RemixNone;
+  return remix_track_get_deck (env, track);
+}
+
+RemixTimeType
+remix_layer_set_timetype (RemixEnv * env, RemixLayer * layer, RemixTimeType new_type)
+{
+  RemixTimeType old_type = layer->timetype;
+  CDList * l;
+  RemixDeck * deck;
+  RemixSound * sound;
+
+  if (old_type == new_type) return old_type;
+
+  deck = remix_layer_get_deck (env, layer);
+
+  for (l = layer->sounds; l; l = l->next) {
+    sound = (RemixSound *)l->data.s_pointer;
+    sound->start_time = remix_time_convert (env, sound->start_time, old_type,
+                                          new_type);
+    sound->duration = remix_time_convert (env, sound->duration, old_type,
+                                        new_type);
+  }
+
+  layer->timetype = new_type;
+
+  return old_type;
+}
+
+RemixTimeType
+remix_layer_get_timetype (RemixEnv * env, RemixLayer * layer)
+{
+  return layer->timetype;
+}
+
+RemixSound *
+_remix_layer_add_sound (RemixEnv * env, RemixLayer * layer, RemixSound * sound,
+                    RemixTime start_time)
+{
+  sound->start_time = start_time;
+  layer->sounds = cd_list_insert (env, layer->sounds, CD_TYPE_POINTER,
+                                 CD_POINTER(sound),
+                                 (CDCmpFunc)remix_sound_later);
+  remix_layer_ensure_coherency (env, layer);
+  return sound;
+}
+
+RemixSound *
+_remix_layer_remove_sound (RemixEnv * env, RemixLayer * layer, RemixSound * sound)
+{
+  layer->sounds = cd_list_remove (env, layer->sounds, CD_TYPE_POINTER,
+                                 CD_POINTER(sound));
+  remix_layer_ensure_coherency (env, layer);
+  return sound;
+}
+
+/*
+ * remix_layer_get_sound_item_before (layer, time)
+ *
+ * Finds the last sound with a start_time before 'time'.
+ */
+static CDList *
+remix_layer_get_sound_item_before (RemixEnv * env, RemixLayer * layer, RemixTime time)
+{
+  RemixSound * s;
+  CDList * l, * lp = RemixNone;
+
+  for (l = layer->sounds; l; l = l->next) {
+    s = (RemixSound *)l->data.s_pointer;
+    if (_remix_time_gt (layer->timetype, s->start_time, time)) return lp;
+    lp = l;
+  }
+
+  return lp;
+}
+
+/*
+ * remix_layer_get_sound_item_at (layer, time)
+ *
+ * Finds the sound occurring at 'time'. If no sound is playing at 'time',
+ * returns RemixNone.
+ */
+CDList *
+remix_layer_get_sound_item_at (RemixEnv * env, RemixLayer * layer, RemixTime time)
+{
+  RemixTime t;
+  CDList * l = remix_layer_get_sound_item_before (env, layer, time);
+  RemixSound * s;
+
+  if (l == RemixNone) return RemixNone;
+
+  s = (RemixSound *)l->data.s_pointer;
+
+  t = _remix_time_add (layer->timetype, s->start_time, s->duration);
+  if (_remix_time_le (layer->timetype, t, time)) l = RemixNone;
+
+  return l;
+}
+
+/*
+ * remix_layer_get_sound_item_after (layer, time)
+ *
+ * Finds the first sound at or after 'time' and returns its list item.
+ */
+static CDList *
+remix_layer_get_sound_item_after (RemixEnv * env, RemixLayer * layer, RemixTime time)
+{
+  RemixSound * s;
+  CDList * l;
+
+  for (l = layer->sounds; l; l = l->next) {
+    s = (RemixSound *)l->data.s_pointer;
+    if (_remix_time_ge (layer->timetype, s->start_time, time)) return l;
+  }
+
+  return RemixNone;
+}
+
+/*
+ * remix_layer_get_sound_after (layer, time)
+ *
+ * Finds the first sound with a start_time at or after 'time'.
+ */
+RemixSound *
+remix_layer_get_sound_after (RemixEnv * env, RemixLayer * layer, RemixTime time)
+{
+  CDList * l = remix_layer_get_sound_item_after (env, layer, time);
+
+  if (l == RemixNone) return RemixNone;
+  else return (RemixSound *)l->data.s_pointer;
+}
+
+RemixSound *
+_remix_layer_get_sound_prev (RemixEnv * env, RemixLayer * layer, RemixSound * sound)
+{
+  CDList * sound_item;
+  RemixSound * sn;
+
+  if (layer->sounds == NULL) return RemixNone;
+
+  if (sound == RemixNone) {
+    sn = (RemixSound *) layer->sounds->data.s_pointer;
+  } else {
+    sound_item = cd_list_find (env, layer->sounds, CD_TYPE_POINTER,
+                              CD_POINTER(sound));
+    if (sound_item == NULL) return RemixNone;
+    sound_item = sound_item->prev;
+    if (sound_item == NULL) return RemixNone;
+    sn = (RemixSound *) sound_item->data.s_pointer;
+  }
+
+  return sn;
+}
+
+RemixSound *
+_remix_layer_get_sound_next (RemixEnv * env, RemixLayer * layer, RemixSound * sound)
+{
+  CDList * sound_item;
+  RemixSound * sn;
+
+  if (layer->sounds == NULL) return RemixNone;
+
+  if (sound == NULL) {
+    sn = (RemixSound *)
+      (cd_list_last (env, layer->sounds, CD_TYPE_POINTER)).s_pointer;
+  } else {
+    sound_item = cd_list_find (env, layer->sounds, CD_TYPE_POINTER,
+                              CD_POINTER(sound));
+    if (sound_item == NULL) return RemixNone;
+    sound_item = sound_item->next;
+    if (sound_item == NULL) return RemixNone;
+    sn = (RemixSound *) sound_item->data.s_pointer;
+  }
+
+  return sn;
+}
+
+RemixLayer *
+remix_layer_below (RemixEnv * env, RemixLayer * layer)
+{
+  if (layer->track)
+    return _remix_track_get_layer_below (env, layer->track, layer);
+  else
+    return RemixNone;
+}
+
+RemixLayer *
+remix_layer_above (RemixEnv * env, RemixLayer * layer)
+{
+  if (layer->track)
+    return _remix_track_get_layer_above (env, layer->track, layer);
+  else
+    return RemixNone;
+}
+
+static RemixCount
+remix_layer_length (RemixEnv * env, RemixBase * base)
+{
+  RemixLayer * layer = (RemixLayer *)base;
+  RemixSound * sound = (RemixSound *)
+    (cd_list_last (env, layer->sounds, CD_TYPE_POINTER)).s_pointer;
+  RemixTime end, t;
+
+  if (sound == RemixNone) {
+    remix_dprintf ("[remix_layer_length] layer %p has no sounds\n", layer);
+    return 0;
+  }
+
+  /* Convert sound's end time to offset and return that */
+  end = _remix_time_add (layer->timetype, sound->start_time, sound->duration);
+  t = remix_time_convert (env, end, layer->timetype, REMIX_TIME_SAMPLES);
+
+  remix_dprintf ("[remix_layer_length] (%p) last sound ends at %d ticks == %ld samples\n",
+                 layer, end.beat24s, t.samples);
+
+  return t.samples;
+}
+
+static RemixCount
+remix_layer_seek (RemixEnv * env, RemixBase * base, RemixCount offset)
+{
+  RemixLayer * layer = (RemixLayer *)base;
+  RemixTime current_time;
+
+  /* Evaluate this offset as a time value using the current samplerate and
+   * tempo */
+  current_time = remix_time_convert (env, (RemixTime)offset, REMIX_TIME_SAMPLES,
+                                   layer->timetype);
+
+  /* Cache the current sound item */
+  layer->_current_sound_item =
+    remix_layer_get_sound_item_at (env, layer, current_time);
+
+  if (layer->_current_sound_item == RemixNone)
+    layer->_current_sound_item =
+      remix_layer_get_sound_item_after (env, layer, current_time);
+
+  layer->_current_offset = offset;
+
+  return offset;
+}
+
+static RemixCount
+remix_layer_process_sound (RemixEnv * env, RemixLayer * layer,
+                         RemixCount current_offset, RemixSound * sound,
+                         RemixCount sound_offset, RemixCount sound_length,
+                         RemixCount count,
+                         RemixStream * input, RemixStream * output)
+{
+  RemixCount remaining = count, processed = 0, n;
+
+  /* If the next sound starts after the current offset, fill up to it */
+  if (sound_offset > current_offset) {
+    n = MIN (remaining, sound_offset - current_offset);
+
+    remix_dprintf ("[remix_layer_process_sound] %p is after offset, filling %ld\n",
+               sound, n);
+
+    if (output != RemixNone)
+      n = remix_stream_write (env, output, n, input);
+    current_offset += n;
+    processed += n;
+    remaining -= n;
+  }
+
+  /* If that didn't fill the output, process part of the next sound */
+  if (processed < count) {
+    n = MIN (remaining, sound_offset + sound_length - current_offset);
+    /* XXX: fix following line to use SEEK_CUR ??? */
+    remix_seek (env, (RemixBase *)sound, current_offset - sound_offset,
+              SEEK_SET);
+    n = remix_process (env, (RemixBase *)sound, n, input, output);
+    processed += n;
+    remaining -= n;
+  }
+
+  return processed;
+}
+
+static RemixCount
+remix_layer_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                   RemixStream * input, RemixStream * output)
+{
+  RemixLayer * layer = (RemixLayer *)base;
+  RemixTempo tempo = remix_get_tempo (env);
+  RemixCount processed = 0, remaining = count, n;
+  RemixCount sound_offset, sound_length, next_offset;
+  RemixCount current_offset = remix_tell (env, (RemixBase *)layer);
+  RemixSound * sound, * sn;
+  RemixTime t;
+
+  remix_dprintf ("PROCESS LAYER (%p, +%ld, %p -> %p) @ %ld\n",
+             layer, count, input, output, current_offset);
+
+
+  if (layer->timetype == REMIX_TIME_BEAT24S && layer->_current_tempo != tempo) {
+#if 0
+    RemixCount new_offset;
+
+#if 0
+    if (layer->_current_sound_item == RemixNone) {
+      RemixSamplerate samplerate = remix_get_samplerate (env);
+      int beat24s;
+
+      beat24s = ((int)((float)remix_tell (env, (RemixBase *)layer) *
+                      layer->_current_tempo * 24.0 / (samplerate * 60.0)));
+      new_offset = (RemixCount)(beat24s * samplerate * 60.0 / (tempo * 24.0));
+    } else {
+      sound = (RemixSound *)layer->_current_sound_item->data.s_pointer;
+      t = remix_time_convert (env, sound->start_time, layer->timetype,
+                            REMIX_TIME_SAMPLES);
+
+      new_offset = t.samples + remix_tell (env, (RemixBase *)sound);
+    }
+#else
+    new_offset = layer->_current_offset * tempo / layer->_current_tempo;
+#endif
+
+    remix_layer_seek (env, (RemixBase *)layer, new_offset);
+    layer->_current_tempo = tempo;
+#else
+    if (layer->_current_sound_item != RemixNone)
+      remix_layer_ensure_coherency (env, layer);
+#endif
+  }
+
+  while (remaining > 0) {
+
+    if (layer->_current_sound_item == RemixNone) {
+      /* No more sounds */
+      remix_dprintf ("[remix_layer_process] ## no more sounds!\n");
+
+      n = (output == RemixNone) ? remaining :
+       remix_stream_write (env, output, remaining, input);
+      current_offset += n;
+      processed += n;
+      remaining -= n;
+      break;
+    }
+
+    sound = (RemixSound *)layer->_current_sound_item->data.s_pointer;
+    t = remix_time_convert (env, sound->start_time, layer->timetype,
+                          REMIX_TIME_SAMPLES);
+    sound_offset = t.samples;
+
+    t = remix_time_convert (env, sound->duration, layer->timetype,
+                          REMIX_TIME_SAMPLES);
+    sound_length = t.samples;
+
+    if (layer->_current_sound_item->next) {
+      sn = (RemixSound *)(layer->_current_sound_item->next->data.s_pointer);
+      t = remix_time_convert (env, sn->start_time, layer->timetype,
+                            REMIX_TIME_SAMPLES);
+      next_offset = t.samples;
+      if (next_offset < sound_offset + sound_length)
+        sound_length = next_offset - sound_offset;
+    }
+
+    /* *** We now have the next sound and its valid length *** */
+    remix_dprintf ("[remix_layer_process] to process sound %p, [%ld, +%ld]\n",
+                 sound, sound_offset, sound_length);
+
+    n = remix_layer_process_sound (env, layer, current_offset,
+                                 sound, sound_offset, sound_length,
+                                 remaining, input, output);
+    current_offset += n;
+    processed += n;
+    remaining -= n;
+
+    if (current_offset >= sound_offset + sound_length)
+      layer->_current_sound_item = layer->_current_sound_item->next;
+  }
+
+  remix_dprintf ("[remix_layer_process] processed %ld\n", processed);
+
+  if (processed == 0) {
+    remix_set_error (env, REMIX_ERROR_NOOP);
+    return -1;
+  }
+
+  layer->_current_offset = current_offset;
+
+  return processed;
+}
+
+static int
+remix_layer_flush (RemixEnv * env, RemixBase * base)
+{
+  RemixLayer * layer = (RemixLayer *)base;
+  RemixBase * sound;
+
+  if (layer->_current_sound_item == RemixNone) return 0;
+
+  sound = (RemixBase *)layer->_current_sound_item->data.s_pointer;
+
+  return remix_flush (env, sound);
+}
+
+static RemixLayer *
+remix_layer_ensure_coherency (RemixEnv * env, RemixLayer * layer)
+{
+  RemixCount offset = remix_tell (env, (RemixBase *)layer);
+
+  remix_layer_seek (env, (RemixBase *)layer, offset);
+  layer->_current_tempo = remix_get_tempo (env);
+
+  return layer;
+}
+
+static struct _RemixMethods _remix_layer_methods = {
+  remix_layer_clone,   /* clone */
+  remix_layer_destroy, /* destroy */
+  NULL,             /* ready */
+  NULL,             /* prepare */
+  remix_layer_process, /* process */
+  remix_layer_length,  /* length */
+  remix_layer_seek,    /* seek */
+  remix_layer_flush,   /* flush */
+};
+
+static RemixLayer *
+remix_layer_optimise (RemixEnv * env, RemixLayer * layer)
+{
+  _remix_set_methods (env, layer, &_remix_layer_methods);
+  return layer;
+}
+
diff --git a/src/libremix/remix_meta.c b/src/libremix/remix_meta.c
new file mode 100644 (file)
index 0000000..e6454f4
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixMetaText: Metadata for RemixBases.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+
+#define __REMIX__
+#include "remix.h"
+
+#include <string.h>
+
+RemixMetaText *
+remix_meta_text_new (RemixEnv * env)
+{
+  RemixMetaText * mt;
+
+  mt = (RemixMetaText *) remix_malloc (sizeof (struct _RemixMetaText));
+  mt->authors = cd_list_new (env);
+
+  return mt;
+}
+
+char *
+remix_meta_text_get_identifier (RemixEnv * env, RemixMetaText * mt)
+{
+  return mt->identifier;
+}
+
+char *
+remix_meta_text_set_identifier (RemixEnv * env, RemixMetaText * mt, char * identifier)
+{
+  char * old = mt->identifier;
+  mt->identifier = (identifier == NULL) ? NULL : strdup(identifier);
+  return old;
+}
+
+char *
+remix_meta_text_get_category (RemixEnv * env, RemixMetaText * mt)
+{
+  return mt->category;
+}
+
+char *
+remix_meta_text_set_category (RemixEnv * env, RemixMetaText * mt, char * category)
+{
+  char * old = mt->category;
+  mt->category = (category == NULL) ? NULL : strdup(category);
+  return old;
+}
+
+char *
+remix_meta_text_get_description (RemixEnv * env, RemixMetaText * mt)
+{
+  return mt->description;
+}
+
+char *
+remix_meta_text_set_description (RemixEnv * env, RemixMetaText * mt, char * description)
+{
+  char * old = mt->description;
+  mt->description = (description == NULL) ? NULL : strdup(description);
+  return old;
+}
+
+char *
+remix_meta_text_get_copyright (RemixEnv * env, RemixMetaText * mt)
+{
+  return mt->copyright;
+}
+
+char *
+remix_meta_text_set_copyright (RemixEnv * env, RemixMetaText * mt, char * copyright)
+{
+  char * old = mt->copyright;
+  mt->copyright = (copyright == NULL) ? NULL : strdup(copyright);
+  return old;
+}
+
+char *
+remix_meta_text_get_url (RemixEnv * env, RemixMetaText * mt)
+{
+  return mt->url;
+}
+
+char *
+remix_meta_text_set_url (RemixEnv * env, RemixMetaText * mt, char * url)
+{
+  char * old = mt->url;
+  mt->url = (url == NULL) ? NULL : strdup(url);
+  return old;
+}
+
+static RemixMetaAuthor *
+remix_meta_author_new (RemixEnv * env, char * name, char * email)
+{
+  RemixMetaAuthor * ma = remix_malloc (sizeof (struct _RemixMetaAuthor));
+  ma->name = (name == NULL) ? NULL : strdup(name);
+  ma->email = (email == NULL) ? NULL: strdup(email);
+  return ma;
+}
+
+CDList *
+remix_meta_text_get_authors (RemixEnv * env, RemixMetaText * mt)
+{
+  return mt->authors;
+}
+void
+remix_meta_text_add_author (RemixEnv * env, RemixMetaText * mt,
+                        char * name, char * email)
+{
+  RemixMetaAuthor * ma = remix_meta_author_new (env, name, email);
+  mt->authors = cd_list_append (env, mt->authors, CD_POINTER(ma));
+}
+
+void
+remix_meta_text_free (RemixEnv * env, RemixMetaText * mt)
+{
+  cd_list_free_all (env, mt->authors);
+  remix_free (mt);
+}
diff --git a/src/libremix/remix_monitor.c b/src/libremix/remix_monitor.c
new file mode 100644 (file)
index 0000000..fa9990f
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixMonitor: device output
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/soundcard.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <config.h>
+
+#define __REMIX__
+#include "remix.h"
+
+#define DEFAULT_FORMAT AFMT_S16_LE
+#define DEFAULT_STEREO 1
+#define DEFAULT_FREQUENCY 44100
+#define DEFAULT_NUMFRAGS 4
+#define DEFAULT_FRAGSIZE 10
+
+/* Must be either 1 or 0. */
+#define DEBUG_FILE     0
+
+#if (DEBUG_FILE == 1)
+/* make sure this file exists; we're not using O_CREAT! */
+#define FILENAME "/tmp/env.out"
+#else
+#define FILENAME "/dev/dsp"
+#endif
+
+/* Optimisation dependencies: none */
+static RemixMonitor * remix_monitor_optimise (RemixEnv * env, RemixMonitor * monitor);
+
+static RemixBase *
+remix_monitor_reset_device (RemixEnv * env, RemixBase * base)
+{
+  RemixMonitor * monitor = (RemixMonitor *)base;
+  CDSet * channels = remix_get_channels (env);
+  RemixCount nr_channels;
+  int fragmentsize;
+
+  nr_channels = cd_set_size (env, channels);
+
+  if (nr_channels == 1)
+    monitor->stereo = 0;
+  else if (nr_channels > 1)
+    monitor->stereo = 1;
+
+  monitor->mask = 0;
+  monitor->format = DEFAULT_FORMAT;
+
+  monitor->frequency = remix_get_samplerate (env);
+  monitor->numfrags = DEFAULT_NUMFRAGS;
+  monitor->fragsize = DEFAULT_FRAGSIZE;
+
+  if (DEBUG_FILE == 1) {
+    monitor->format = AFMT_S16_LE;
+    return base;
+  }
+
+  if (ioctl (monitor->dev_dsp_fd, SNDCTL_DSP_GETFMTS, &monitor->mask) == -1) {
+    remix_set_error (env, REMIX_ERROR_SYSTEM);
+    return RemixNone;
+  }
+
+  if (monitor->mask & AFMT_U8) {
+    monitor->format = AFMT_U8;
+  }
+  if (monitor->mask & AFMT_U16_LE) {
+    monitor->format = AFMT_U16_LE;
+  }
+  if (monitor->mask & AFMT_S16_LE) {
+    monitor->format = AFMT_S16_LE;
+  }
+  if (monitor->mask & AFMT_U16_BE) {
+    monitor->format = AFMT_U16_BE;
+  }
+  if (monitor->mask & AFMT_S16_BE) {
+    monitor->format = AFMT_S16_BE;
+  }
+  if (monitor->mask & AFMT_S8) {
+    monitor->format = AFMT_S8;
+  }
+  if (monitor->mask & AFMT_S16_LE) {
+    monitor->format = AFMT_S16_LE;
+  }
+
+  if (ioctl(monitor->dev_dsp_fd, SNDCTL_DSP_SETFMT, &monitor->format) == -1) {
+    remix_set_error (env, REMIX_ERROR_SYSTEM);
+    return RemixNone;
+  }
+
+  if (ioctl(monitor->dev_dsp_fd, SNDCTL_DSP_STEREO, &(monitor->stereo)) == -1) {
+    remix_set_error (env, REMIX_ERROR_SYSTEM);
+    return RemixNone;
+  }
+
+  if (ioctl(monitor->dev_dsp_fd, SNDCTL_DSP_SPEED, &(monitor->frequency)) == -1) {
+    remix_set_error (env, REMIX_ERROR_SYSTEM);
+    return RemixNone;
+  }
+
+  fragmentsize = (monitor->numfrags << 16) | monitor->fragsize;
+  if (ioctl(monitor->dev_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragmentsize) == -1) {
+    remix_set_error (env, REMIX_ERROR_SYSTEM);
+    return RemixNone;
+  }
+
+  return base;
+}
+
+static RemixBase *
+remix_monitor_init (RemixEnv * env, RemixBase * base)
+{
+  RemixMonitor * monitor = (RemixMonitor *)base;
+
+  monitor->dev_dsp_fd = -1;
+
+  monitor->dev_dsp_fd = open (FILENAME, O_WRONLY, 0);
+  if (monitor->dev_dsp_fd == -1) {
+    printf ("Couldn't open any output device.\n");
+    remix_set_error (env, REMIX_ERROR_SYSTEM);
+    return RemixNone;
+  }
+
+  remix_monitor_reset_device (env, base);
+
+  remix_monitor_optimise (env, monitor);
+
+  return (RemixBase *)monitor;
+}
+
+RemixMonitor *
+remix_monitor_new (RemixEnv * env)
+{
+  RemixBase * monitor = remix_base_new_subclass (env, sizeof (struct _RemixMonitor));
+
+  remix_monitor_init (env, monitor);
+  return (RemixMonitor *)monitor;
+}
+
+static RemixBase *
+remix_monitor_clone (RemixEnv * env, RemixBase * base)
+{
+  RemixMonitor * new_monitor = remix_monitor_new (env);
+
+  remix_monitor_optimise (env, new_monitor);
+  return (RemixBase *)new_monitor;
+}
+
+static int
+remix_monitor_destroy (RemixEnv * env, RemixBase * base)
+{
+  RemixMonitor * monitor = (RemixMonitor *)base;
+
+  if (monitor->dev_dsp_fd != -1) {
+    close (monitor->dev_dsp_fd);
+  }
+  remix_free (monitor);
+  return 0;
+}
+
+static int
+remix_monitor_ready (RemixEnv * env, RemixBase * base)
+{
+  RemixMonitor * monitor = (RemixMonitor *) base;
+  CDSet * channels = remix_get_channels (env);
+  int samplerate = (int) remix_get_samplerate (env);
+  RemixCount nr_channels;
+
+  nr_channels = cd_set_size (env, channels);
+
+  return (samplerate == monitor->frequency &&
+         ((nr_channels == 1 && monitor->stereo == 0) ||
+          (nr_channels > 1 && monitor->stereo == 1)));
+}
+
+static RemixBase *
+remix_monitor_prepare (RemixEnv * env, RemixBase * base)
+{
+  remix_monitor_reset_device (env, base);
+  return base;
+}
+
+static RemixCount
+remix_monitor_write_short (RemixEnv * env, RemixMonitor * monitor, RemixCount count)
+{
+  static struct timeval tv_instant = {0, 0};
+
+  RemixCount n = 0;
+  fd_set fds;
+
+  if (!(monitor->format & AFMT_S16_LE)) {
+    printf ("###### device cannot play AFMT_S16_LE nicely\n");
+    return count;
+  }
+
+  FD_ZERO (&fds);
+  FD_SET (monitor->dev_dsp_fd, &fds);
+
+  if ((select (monitor->dev_dsp_fd + 1, NULL, &fds, NULL, &tv_instant) == 0));
+#if 0
+  {
+    printf ("select error\n");
+    remix_set_error (env, REMIX_ERROR_SYSTEM);
+    return -1;
+  }
+#endif
+
+  n = write (monitor->dev_dsp_fd, monitor->playbuffer, count * sizeof(short));
+  if (n == -1) {
+    printf ("####### system error writing to fd %d #######\n",
+           monitor->dev_dsp_fd);
+
+    remix_set_error (env, REMIX_ERROR_SYSTEM);
+    return -1;
+  }
+
+  return n;
+}
+
+static RemixCount
+remix_monitor_playbuffer (RemixEnv * env, RemixMonitor * monitor, RemixPCM * data,
+                        RemixCount count)
+{
+  RemixCount i;
+  RemixPCM value;
+  const RemixPCM max_value = (RemixPCM)SHRT_MAX / 2;
+
+  for (i = 0; i < count; i++) {
+    value = *data++ * max_value;
+    monitor->playbuffer[i] = (short)value;
+  }
+
+  count = remix_monitor_write_short (env, monitor, count);
+
+  return count;
+}
+
+/* An RemixChunkFunc for making noise */
+static RemixCount
+remix_monitor_chunk (RemixEnv * env, RemixChunk * chunk, RemixCount offset,
+                   RemixCount count, int channelname, void * data)
+{
+  RemixMonitor * monitor = (RemixMonitor *)data;
+  RemixCount remaining = count, written = 0, n, playcount;
+  RemixPCM * d;
+
+  if (monitor->dev_dsp_fd == -1) {
+    remix_dprintf ("[remix_monitor_chunk] no file\n");
+    remix_set_error (env, REMIX_ERROR_NOENTITY); /* XXX: different error ? */
+    return -1;
+  }
+
+  remix_dprintf ("[remix_monitor_chunk] (%p [chunk %p], +%ld), @ %ld\n",
+               monitor, chunk, count, offset);
+
+  while (remaining > 0) {
+    playcount = MIN (remaining, REMIX_MONITOR_BUFFERLEN);
+    d = &chunk->data[offset];
+    n = remix_monitor_playbuffer (env, monitor, d, playcount);
+
+    if (n == -1) {
+      return -1;
+    } else {
+      n /= sizeof (short);
+    }
+
+    offset += n;
+    written += n;
+    remaining -= n;
+  }
+
+  return written;
+}
+
+static RemixCount
+remix_monitor_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                     RemixStream * input, RemixStream * output)
+{
+  RemixMonitor * monitor = (RemixMonitor *)base;
+  RemixCount nr_channels = remix_stream_nr_channels (env, input);
+  RemixCount remaining = count, processed = 0, n, nn;
+
+  if (nr_channels == 1 && monitor->stereo == 0) { /* MONO */
+    return remix_stream_chunkfuncify (env, input, count,
+                                    remix_monitor_chunk, monitor);
+  } else if (nr_channels == 2 && monitor->stereo == 1) { /* STEREO */
+
+    while (remaining > 0) {
+      n = MIN (remaining, REMIX_MONITOR_BUFFERLEN/2);
+      n = remix_stream_interleave_2 (env, input,
+                                   REMIX_CHANNEL_LEFT, REMIX_CHANNEL_RIGHT,
+                                   monitor->databuffer, n);
+      nn = 2 * n;
+      nn = remix_monitor_playbuffer (env, monitor, monitor->databuffer, nn);
+
+      processed += n;
+      remaining -= n;
+    }
+    return processed;
+  } else {
+    printf ("[remix_monitor_process] unsupported stream/output channel\n");
+    printf ("combination %ld / %d\n", nr_channels, monitor->stereo ? 2 : 1);
+    return -1;
+  }
+}
+
+static RemixCount
+remix_monitor_length (RemixEnv * env, RemixBase * base)
+{
+  return REMIX_COUNT_INFINITE;
+}
+
+static RemixCount
+remix_monitor_seek (RemixEnv * env, RemixBase * base, RemixCount count)
+{
+  return count;
+}
+
+static int
+remix_monitor_flush (RemixEnv * env, RemixBase * base)
+{
+  RemixMonitor * monitor = (RemixMonitor *)base;
+
+  if (DEBUG_FILE == 1)
+       return 0;
+
+  if (ioctl(monitor->dev_dsp_fd, SNDCTL_DSP_POST, NULL) == -1) {
+    remix_set_error (env, REMIX_ERROR_SYSTEM);
+    return -1;
+  }
+
+  return 0;
+}
+
+static struct _RemixMethods _remix_monitor_methods = {
+  remix_monitor_clone,
+  remix_monitor_destroy,
+  remix_monitor_ready,
+  remix_monitor_prepare,
+  remix_monitor_process,
+  remix_monitor_length,
+  remix_monitor_seek,
+  remix_monitor_flush,
+};
+
+static RemixMonitor *
+remix_monitor_optimise (RemixEnv * env, RemixMonitor * monitor)
+{
+  _remix_set_methods (env, (RemixBase *)monitor, &_remix_monitor_methods);
+  return monitor;
+}
diff --git a/src/libremix/remix_null.c b/src/libremix/remix_null.c
new file mode 100644 (file)
index 0000000..428e83f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixNull: A RemixBase with no processing
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ *
+ * Description
+ * -----------
+ *
+ * This is a small set of base functions (process, length and seek)
+ * which are useful as optimised versions of an empty container base;
+ * see eg. RemixDeck.
+ * The process function always returns with error REMIX_ERROR_NOOP.
+ * The length function always returns 0
+ * The seek function always returns its argument. Note the seek function
+ * is not needed; you may define an base's seek function as NULL for
+ * the same effect.
+ *
+ * Invariants
+ * ----------
+ *
+ * There is nothing to be invariant about here :)
+ *
+ */
+
+#define __REMIX__
+#include "remix.h"
+
+RemixCount
+remix_null_length (RemixEnv * env, RemixBase * base)
+{
+  return 0;
+}
+
+RemixCount
+remix_null_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                    RemixStream * input, RemixStream * output)
+{
+  remix_set_error (env, REMIX_ERROR_NOOP);
+  return 0;
+}
+
+RemixCount
+remix_null_seek (RemixEnv * env, RemixBase * base, RemixCount offset)
+{
+  return offset;
+}
diff --git a/src/libremix/remix_pcm.c b/src/libremix/remix_pcm.c
new file mode 100644 (file)
index 0000000..6a5ec2b
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixPCM: generic functions for anonymous blocks of PCM data.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ *
+ * Description
+ * -----------
+ *
+ * This file contains only generic functions to manipulate blocks of
+ * RemixPCM data. The RemixPCM type is defined in <remix_types.h>,  usually as
+ * a floating point value (float).
+ *
+ * The functions in this file are an excellent target for short vector
+ * machine optimisations.
+ *
+ * Invariants
+ * ----------
+ *
+ * N/A
+ *
+ */
+
+#include <string.h>
+
+#define __REMIX__
+#include "remix.h"
+
+
+/* PFunc */
+
+/*
+ * _remix_pcm_clear_region (data, count)
+ */
+RemixCount
+_remix_pcm_clear_region (RemixPCM * data, RemixCount count, void * unused)
+{
+  memset (data, (RemixPCM)0, count * sizeof (RemixPCM));
+  return count;
+}
+
+
+/* PVFunc */
+
+RemixCount
+_remix_pcm_set (RemixPCM * data, RemixPCM value, RemixCount count)
+{
+  RemixCount i;
+
+  for (i = 0; i < count; i++) {
+    *data++ = value;
+  }
+
+  return count;
+}
+
+RemixCount
+_remix_pcm_gain (RemixPCM * data, RemixCount count, void * gain)
+{
+  RemixPCM _gain = *(RemixPCM *)gain;
+  RemixCount i;
+
+  for (i = 0; i < count; i++) {
+    *data++ *= _gain;
+  }
+
+  return count;
+}
+
+
+/* PPFunc */
+
+/*
+ * _remix_pcm_copy (src, dest, count)
+ *
+ * Copy PCM data from src to dest.
+ */
+RemixCount
+_remix_pcm_copy (RemixPCM * src, RemixPCM * dest, RemixCount count,
+                 void * unused)
+{
+  memcpy (dest, src, count * sizeof (RemixPCM));
+  return count;
+}
+
+/*
+ * _remix_pcm_add (src, dest, count)
+ *
+ * Add PCM data from src to dest.
+ */
+RemixCount
+_remix_pcm_add (RemixPCM * src, RemixPCM * dest, RemixCount count,
+                void * unused)
+{
+  RemixCount i;
+
+  for (i = 0; i < count; i++) {
+    *dest++ += *src++;
+  }
+
+  return count;
+}
+
+/*
+ * _remix_pcm_mult (src, dest, count)
+ *
+ * Multiply PCM data of dest by that in src.
+ */
+RemixCount
+_remix_pcm_mult (RemixPCM * src, RemixPCM * dest, RemixCount count,
+                 void * unused)
+{
+  RemixCount i;
+
+  for (i = 0; i < count; i++) {
+    *dest++ *= *src++;
+  }
+
+  return count;
+}
+
+/*
+ * _remix_pcm_fade (src, dest, count)
+ *
+ * Fade PCM data of dest by that in src.
+ */
+RemixCount
+_remix_pcm_fade (RemixPCM * src, RemixPCM * dest, RemixCount count,
+                 void * unused)
+{
+  RemixCount i;
+
+  for (i = 0; i < count; i++) {
+    *dest++ *= (1.0 - *src++);
+  }
+
+  return count;
+}
+
+/*
+ * _remix_pcm_interleave_2 (src1, src2, count, dest)
+ *
+ * Interleave data of src1 and src2, storing result in dest
+ */
+RemixCount
+_remix_pcm_interleave_2 (RemixPCM * src1, RemixPCM * src2, RemixCount count,
+                         void * data)
+{
+  RemixPCM * dest = (RemixPCM *)data;
+  RemixCount i;
+
+  for (i = 0; i < count; i++) {
+    *dest++ = *src1++;
+    *dest++ = *src2++;
+  }
+
+  return count;
+}
+
+/*
+ * _remix_pcm_deinterleave_2 (dest1, dest2, count, src)
+ *
+ * Deinterleave data of src, storing result in dest1 and dest2
+ */
+RemixCount
+_remix_pcm_deinterleave_2 (RemixPCM * dest1, RemixPCM * dest2,
+                           RemixCount count, void * data)
+{
+  RemixPCM * src = (RemixPCM *)data;
+  RemixCount i;
+
+  for (i = 0; i < count; i++) {
+    *dest1++ = *src++;
+    *dest2++ = *src++;
+  }
+
+  return count;
+}
+
+/* PPPFunc */
+
+/*
+ * _remix_pcm_blend (src, blend, dest, count)
+ *
+ * Blend PCM data of 'src' into 'dest' by blend values in 'blend'.
+ */
+RemixCount
+_remix_pcm_blend (RemixPCM * src, RemixPCM * blend, RemixPCM * dest,
+                  RemixCount count, void * unused)
+{
+  RemixCount i;
+  RemixPCM b, d;
+
+  for (i = 0; i < count; i++) {
+    b = *blend++;
+    d = (*dest * b) + (*src++ * (1.0 - b));
+    *dest++ = d;
+  }
+
+  return count;
+}
+
+
+/* Miscellaneous */
+
+/*
+ * remix_pcm_write_linear (data, x1, y1, x2, y2, offset, count)
+ *
+ * Write 'count' samples at 'data' following line passing through (x1, y1)
+ * and (x2, y2), with writing starting at x = 'offset'.
+ */
+RemixCount
+_remix_pcm_write_linear (RemixPCM * data, RemixCount x1, RemixPCM y1,
+                         RemixCount x2, RemixPCM y2,
+                         RemixCount offset, RemixCount count)
+{
+  RemixCount i;
+
+  remix_dprintf ("[remix_pcm_write_linear] ((%ld, %f) -> (%ld, %f), %ld +%ld)\n",
+                 x1, y1, x2, y2, offset, count);
+
+  for (i = 0; i < count; i++) {
+    *data++ = y1 + (RemixPCM)(i + offset - x1) * (y2 - y1) / (x2 - x1);
+  }
+
+  return count;
+}
diff --git a/src/libremix/remix_plugin.c b/src/libremix/remix_plugin.c
new file mode 100644 (file)
index 0000000..8d234f1
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixPlugin: A container for RemixBase types.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <sys/stat.h>
+
+#define __REMIX__
+#include "remix.h"
+
+static CDList * modules_list = CD_EMPTY_LIST;
+
+static CDList *
+remix_plugin_initialise_static (RemixEnv * env)
+{
+  CDList * plugins = cd_list_new (env);
+
+  plugins = cd_list_join (env, plugins, __gain_init (env));
+
+#ifdef HAVE_LIBSNDFILE1
+  plugins = cd_list_join (env, plugins, __sndfile_init (env));
+#endif
+
+  return plugins;
+}
+
+static CDList *
+remix_plugin_init (RemixEnv * env, const char * path)
+{
+  void * module;
+  CDList * l;
+  RemixPluginInitFunc init;
+
+  module = dlopen (path, RTLD_NOW);
+
+  if (!module) {
+    remix_dprintf ("[remix_plugin_init] Unable to open %s: %s\n", path,
+                  dlerror ());
+    remix_set_error (env, REMIX_ERROR_SYSTEM);
+    return CD_EMPTY_LIST;
+  }
+
+  /* Check that this module has not already been loaded (eg. if it is
+   * a symlink etc.) */
+  for (l = modules_list; l; l = l->next) {
+    if (l->data.s_pointer == module) {
+      dlclose (module);
+      return CD_EMPTY_LIST;
+    }
+  }
+
+  modules_list = cd_list_append (env, modules_list, CD_POINTER(module));
+
+  if ((init = dlsym (module, "remix_load")) != NULL) {
+    return init (env);
+  }
+
+  return CD_EMPTY_LIST;
+}
+
+#define BUFLEN 256
+
+static CDList *
+init_dynamic_plugins_dir (RemixEnv * env, char * dirname)
+{
+  CDList * plugins = cd_list_new (env);
+  DIR * dir;
+  struct dirent * dirent;
+  char * name;
+  static char buf[BUFLEN];
+  struct stat statbuf;
+
+  dir = opendir (dirname);
+  if (!dir) {
+    /* fail silently */
+    return CD_EMPTY_LIST;
+  }
+
+  while ((dirent = readdir (dir)) != NULL) {
+    name = dirent->d_name;
+
+    remix_dprintf ("[init_dynamic_plugins_dir] trying %s ... ", name);
+    snprintf (buf, BUFLEN, "%s/%s", dirname, name);
+
+    if (stat (buf, &statbuf) == -1) {
+      remix_set_error (env, REMIX_ERROR_SYSTEM);
+    } else if (remix_stat_regular (statbuf.st_mode)) {
+      plugins = cd_list_join (env, plugins, remix_plugin_init (env, buf));
+    }
+  }
+
+  closedir (dir);
+
+  return plugins;
+}
+
+static CDList *
+remix_plugin_initialise_dynamic (RemixEnv * env)
+{
+  return init_dynamic_plugins_dir (env, PACKAGE_PLUGIN_DIR);
+}
+
+void
+remix_plugin_defaults_initialise (RemixEnv * env)
+{
+  CDList * plugins = cd_list_new (env);
+
+  plugins = cd_list_join (env, plugins, remix_plugin_initialise_static (env));
+  plugins = cd_list_join (env, plugins, remix_plugin_initialise_dynamic (env));
+
+  cd_list_apply (env, plugins, (CDFunc)_remix_register_plugin);
+
+  cd_list_free (env, plugins);
+}
+
+static int
+remix_plugin_unload (RemixEnv * env, void * module)
+{
+  RemixPluginInitFunc unload; /* TODO: make new unload type */
+
+  if ((unload = dlsym (module, "remix_unload")) != NULL) {
+    unload (env);
+  }
+
+  dlclose (module);
+
+  return 0;
+}
+
+void
+remix_plugin_defaults_unload (RemixEnv * env)
+{
+  CDList * l;
+
+  modules_list = cd_list_destroy_with (env, modules_list, (CDDestroyFunc)remix_plugin_unload);
+}
+
+#if 0
+
+RemixPlugin
+remix_plugin_new (void)
+{
+  RemixPlugin plugin = remix_malloc (sizeof (struct _RemixPlugin));
+#if 0
+  plugin->text = remix_meta_text_new ();
+#endif
+  return plugin;
+}
+
+RemixMetaText *
+remix_plugin_get_meta_text (RemixPlugin * plugin)
+{
+  return plugin->text;
+}
+
+RemixMetaText *
+remix_plugin_set_meta_text (RemixPlugin * plugin, RemixMetaText * mt)
+{
+  RemixMetaText * old = plugin->text;
+  plugin->text = mt;
+  return old;
+}
+
+int
+remix_plugin_writeable (RemixPlugin * plugin)
+{
+  return (plugin->flags & REMIX_PLUGIN_WRITEABLE);
+}
+
+int
+remix_plugin_seekable (RemixPlugin * plugin)
+{
+  return (plugin->flags & REMIX_PLUGIN_SEEKABLE);
+}
+
+int
+remix_plugin_cacheable (RemixPlugin * plugin)
+{
+  return (plugin->flags & REMIX_PLUGIN_CACHEABLE);
+}
+
+int
+remix_plugin_causal (RemixPlugin * plugin)
+{
+  return (plugin->flags & REMIX_PLUGIN_CAUSAL);
+}
+
+#endif
diff --git a/src/libremix/remix_private.h b/src/libremix/remix_private.h
new file mode 100644 (file)
index 0000000..b72cc4d
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * remix_private.h -- libremix internal data types and functions.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#ifndef __REMIX_PRIVATE_H__
+#define __REMIX_PRIVATE_H__
+
+/*#define DEBUG*/
+
+#if defined(__REMIX__)
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "ctxdata.h"
+
+#include "remix_compat.h"
+#include "remix_plugin.h"
+
+/* Max line length for error messages etc. */
+#define REMIX_MAXLINE 4096
+
+#define REMIX_DEFAULT_MIXLENGTH 1024
+#define REMIX_DEFAULT_SAMPLERATE 44100
+#define REMIX_DEFAULT_TEMPO 120
+
+typedef struct _RemixThreadContext RemixThreadContext;
+typedef struct _RemixWorld RemixWorld;
+typedef struct _RemixContext RemixContext;
+
+typedef RemixThreadContext RemixEnv;
+
+typedef struct _RemixPoint RemixPoint;
+typedef struct _RemixEnvelope RemixEnvelope;
+/*typedef struct _RemixChunk RemixChunk;*/
+typedef struct _RemixChannel RemixChannel;
+typedef struct _RemixStream RemixStream;
+typedef struct _RemixDeck RemixDeck;
+typedef struct _RemixTrack RemixTrack;
+typedef struct _RemixLayer RemixLayer;
+typedef struct _RemixSound RemixSound;
+
+
+struct _RemixThreadContext {
+  RemixError last_error;
+  RemixContext * context;
+  RemixWorld * world;
+};
+
+struct _RemixWorld {
+  RemixCount refcount;
+  CDList * plugins;
+  CDList * bases;
+  int purging;
+};
+
+struct _RemixContext {
+  RemixSamplerate samplerate;
+  RemixTempo tempo;
+  CDSet * channels;
+  RemixCount mixlength;
+};
+
+struct _RemixBase {
+  RemixPlugin * plugin;
+  RemixMethods * methods;
+  CDSet * parameters;
+  RemixCount offset; /* current position */
+  RemixContext context_limit;
+  void * instance_data;
+};
+
+struct _RemixPoint {
+  RemixTime time;
+  RemixPCM value;
+};
+
+struct _RemixEnvelope {
+  RemixBase base;
+  RemixEnvelopeType type;
+  RemixTimeType timetype;
+  CDList * points;
+  CDList * _current_point_item;
+  RemixCount _current_offset;
+};
+
+/* XXX: multichannel envelopes ? */
+
+
+struct _RemixStream {
+  RemixBase base;
+  CDSet * channels;
+};
+
+struct _RemixChannel {
+  CDList * chunks;
+  RemixCount _current_offset;
+  CDList * _current_chunk;
+};
+
+struct _RemixDeck {
+  RemixBase base;
+  CDList * tracks;
+  RemixStream * _mixstream;
+};
+
+struct _RemixTrack {
+  RemixBase base;
+  RemixDeck * deck;
+  RemixPCM gain;
+  CDList * layers;
+  RemixStream * _mixstream_a;
+  RemixStream * _mixstream_b;
+};
+
+struct _RemixLayer {
+  RemixBase base;
+  RemixTrack * track;
+  RemixTimeType timetype;
+  CDList * sounds;
+  /*RemixTime _current_time;*/
+  CDList * _current_sound_item;
+  RemixTempo _current_tempo;
+  RemixCount _current_offset;
+};
+
+struct _RemixSound {
+  RemixBase base;
+  RemixBase * source;
+  RemixBase * rate_envelope;
+  RemixBase * gain_envelope;
+  RemixBase * blend_envelope;
+  RemixLayer * layer;
+  RemixTime start_time; /* position in layer */
+  RemixTime duration; /* maximum time length */
+  RemixCount cutin;  /* start offset into sound source */
+  RemixCount cutlength;
+  RemixCount _current_source_offset;
+  RemixStream * _rate_envstream;
+  RemixStream * _gain_envstream;
+  RemixStream * _blend_envstream;
+};
+
+typedef struct _RemixMonitor RemixMonitor;
+
+#define REMIX_MONITOR_BUFFERLEN 2048
+
+struct _RemixMonitor {
+  RemixBase base;
+  RemixPCM databuffer[REMIX_MONITOR_BUFFERLEN];
+  short playbuffer[REMIX_MONITOR_BUFFERLEN];
+  int dev_dsp_fd;
+  int mode;
+  int mask;
+  int format;
+  int stereo;
+  int frequency;
+  int numfrags;
+  int fragsize;
+};
+
+#define _remix_time_zero(t) (RemixTime)\
+  (((t)==REMIX_TIME_SAMPLES) ? ((RemixCount)0) : \
+  (((t)==REMIX_TIME_SECONDS) ? ((float)0.0) : \
+                            ((int)0)))
+
+#define _remix_time_invalid(t) (RemixTime)\
+  (((t)==REMIX_TIME_SAMPLES) ? ((RemixCount)-1) : \
+  (((t)==REMIX_TIME_SECONDS) ? ((float)-1.0) : \
+                            ((int)-1)))
+
+#define _remix_time_is_invalid(t,ti) \
+  (((t)==REMIX_TIME_SAMPLES) ? ((ti).samples < (RemixCount)0) : \
+  (((t)==REMIX_TIME_SECONDS) ? ((ti).seconds < (float)0.0) : \
+                            ((ti).beat24s < (int)0)))
+
+#define _remix_time_add(t,t1,t2) \
+  (((t)==REMIX_TIME_SAMPLES) ? REMIX_SAMPLES((t1).samples + (t2).samples) : \
+  (((t)==REMIX_TIME_SECONDS) ? REMIX_SECONDS((t1).seconds + (t2).seconds) : \
+                            REMIX_BEAT24S((t1).beat24s + (t2).beat24s)))
+
+#define _remix_time_sub(t,t1,t2) \
+  (((t)==REMIX_TIME_SAMPLES) ? REMIX_SAMPLES((t1).samples - (t2).samples) : \
+  (((t)==REMIX_TIME_SECONDS) ? REMIX_SECONDS((t1).seconds - (t2).seconds) : \
+                            REMIX_BEAT24S((t1).beat24s - (t2).beat24s)))
+
+#define _remix_time_eq(t,t1,t2) \
+  (((t)==REMIX_TIME_SAMPLES) ? ((t1).samples == (t2).samples) : \
+  (((t)==REMIX_TIME_SECONDS) ? ((t1).seconds == (t2).seconds) : \
+                            ((t1).beat24s == (t2).beat24s)))
+
+#define _remix_time_gt(t,t1,t2) \
+  (((t)==REMIX_TIME_SAMPLES) ? ((t1).samples > (t2).samples) : \
+  (((t)==REMIX_TIME_SECONDS) ? ((t1).seconds > (t2).seconds) : \
+                            ((t1).beat24s > (t2).beat24s)))
+
+#define _remix_time_lt(t,t1,t2) \
+  (((t)==REMIX_TIME_SAMPLES) ? ((t1).samples < (t2).samples) : \
+  (((t)==REMIX_TIME_SECONDS) ? ((t1).seconds < (t2).seconds) : \
+                            ((t1).beat24s < (t2).beat24s)))
+
+#define _remix_time_ge(t,t1,t2) \
+  (((t)==REMIX_TIME_SAMPLES) ? ((t1).samples >= (t2).samples) : \
+  (((t)==REMIX_TIME_SECONDS) ? ((t1).seconds >= (t2).seconds) : \
+                            ((t1).beat24s >= (t2).beat24s)))
+
+#define _remix_time_le(t,t1,t2) \
+  (((t)==REMIX_TIME_SAMPLES) ? ((t1).samples <= (t2).samples) : \
+  (((t)==REMIX_TIME_SECONDS) ? ((t1).seconds <= (t2).seconds) : \
+                            ((t1).beat24s <= (t2).beat24s)))
+
+#define _remix_time_min(t,t1,t2) \
+  (((t)==REMIX_TIME_SAMPLES) ? ((t1).samples < (t2).samples ? (t1) : (t2)) : \
+  (((t)==REMIX_TIME_SECONDS) ? ((t1).seconds < (t2).seconds ? (t1) : (t2)) : \
+                            ((t1).beat24s < (t2).beat24s ? (t1) : (t2))))
+
+#define _remix_time_max(t,t1,t2) \
+  (((t)==REMIX_TIME_SAMPLES) ? ((t1).samples > (t2).samples ? (t1) : (t2)) : \
+  (((t)==REMIX_TIME_SECONDS) ? ((t1).seconds > (t2).seconds ? (t1) : (t2)) : \
+                            ((t1).beat24s > (t2).beat24s ? (t1) : (t2))))
+
+#define _remix_base_get_samplerate(a,b) (((RemixBase*)b)->context_limit.samplerate)
+#define _remix_base_get_tempo(a,b) (((RemixBase*)b)->context_limit.tempo)
+#define _remix_base_get_mixlength(a,b) (((RemixBase*)b)->context_limit.mixlength)
+#define _remix_base_get_channels(a,b) (((RemixBase*)b)->context_limit.channels)
+
+#define _remix_set_plugin(a,b,p) (((RemixBase*)b)->plugin = (p))
+#define _remix_get_plugin(a,b) (((RemixBase*)b)->plugin)
+#define _remix_set_methods(a,b,m) (((RemixBase*)b)->methods = (m))
+#define _remix_get_methods(a,b) (((RemixBase*)b)->methods)
+#define _remix_set_instance_data(a,b,d) (((RemixBase*)b)->instance_data = (d))
+#define _remix_get_instance_data(a,b) (((RemixBase*)b)->instance_data)
+#define _remix_set_name(a,b,n) (((RemixBase*)b)->name = (n))
+#define _remix_get_name(a,b) (((RemixBase*)b)->name)
+#define _remix_clone(a,b) (((RemixBase*)b)->methods->clone ((a), ((RemixBase*)b)))
+#define _remix_destroy(a,b) (((RemixBase*)b)->methods->destroy ((a), ((RemixBase*)b)))
+#define _remix_prepare(a,b) (((RemixBase*)b)->methods->prepare ((a), ((RemixBase*)b)))
+#define _remix_process(a,b,c,i,o) \
+        (((RemixBase*)b)->methods->process ((a),((RemixBase*)b),(c),(i),(o)))
+#define _remix_length(a,b) (((RemixBase*)b)->methods->length ((a), ((RemixBase*)b)))
+#define _remix_flush(a,b) (((RemixBase*)b)->methods->flush ((a), ((RemixBase*)b)))
+
+
+/* util */
+#define remix_malloc(x) calloc(1, x)
+#define remix_free free
+
+/* debug */
+void remix_debug_down (void);
+void remix_debug_up (void);
+
+/* RemixEnv, remix_context */
+
+RemixBase * remix_base_new_subclass (RemixEnv * env, size_t size);
+
+RemixContext * _remix_context_copy (RemixEnv * env, RemixContext * dest);
+RemixContext * _remix_context_merge (RemixEnv * env, RemixContext * dest);
+RemixEnv * _remix_register_plugin (RemixEnv * env, RemixPlugin * plugin);
+RemixEnv * _remix_unregister_plugin (RemixEnv * env, RemixPlugin * plugin);
+RemixEnv * _remix_register_base (RemixEnv * env, RemixBase * base);
+RemixEnv * _remix_unregister_base (RemixEnv * env, RemixBase * base);
+
+/* remix_plugin */
+void remix_plugin_defaults_initialise (RemixEnv * env);
+void remix_plugin_defaults_unload (RemixEnv * env);
+
+/* remix_deck */
+RemixTrack * _remix_deck_add_track (RemixEnv * env, RemixDeck * deck,
+                                   RemixTrack * track);
+RemixTrack * _remix_deck_remove_track (RemixEnv * env, RemixDeck * deck,
+                                      RemixTrack * track);
+
+/* remix_track */
+RemixBase * remix_track_clone (RemixEnv * env, RemixBase * base);
+RemixLayer * _remix_track_add_layer_above (RemixEnv * env, RemixTrack * track,
+                                    RemixLayer * layer, RemixLayer * above);
+RemixLayer * _remix_track_remove_layer (RemixEnv * env, RemixTrack * track,
+                                 RemixLayer * layer);
+RemixLayer * _remix_track_get_layer_above (RemixEnv * env, RemixTrack * track,
+                                    RemixLayer * above);
+RemixLayer * _remix_track_get_layer_below (RemixEnv * env, RemixTrack * track,
+                                    RemixLayer * below);
+
+/* remix_layer */
+RemixLayer * _remix_remove_layer (RemixEnv * env, RemixLayer * layer);
+RemixBase * remix_layer_clone (RemixEnv * env, RemixBase * base);
+RemixSound * _remix_layer_add_sound (RemixEnv * env, RemixLayer * layer,
+                                    RemixSound * sound, RemixTime position);
+RemixSound * _remix_layer_remove_sound (RemixEnv * env, RemixLayer * layer,
+                                 RemixSound * sound);
+RemixSound * _remix_layer_get_sound_prev (RemixEnv * env, RemixLayer * layer,
+                                   RemixSound * sound);
+RemixSound * _remix_layer_get_sound_next (RemixEnv * env, RemixLayer * layer,
+                                   RemixSound * sound);
+
+/* remix_sound */
+RemixBase *  remix_sound_clone_with_layer (RemixEnv * env, RemixBase * base,
+                                          RemixLayer * new_layer);
+int remix_sound_later (RemixEnv * env, RemixSound * s1, RemixSound * s2);
+
+/* remix_envelope */
+RemixBase * remix_envelope_clone (RemixEnv * env, RemixBase * base);
+
+
+/* remix_channel */
+RemixChannel * remix_channel_new (RemixEnv * env);
+RemixChannel * remix_channel_clone (RemixEnv * env, RemixChannel * channel);
+int remix_channel_destroy (RemixEnv * env, RemixBase * base);
+
+RemixChunk * remix_channel_add_chunk (RemixEnv * env, RemixChannel * channel,
+                                     RemixChunk * chunk);
+RemixChunk * remix_channel_add_new_chunk (RemixEnv * env,
+                                         RemixChannel * channel,
+                                         RemixCount offset,
+                                         RemixCount length);
+
+RemixCount remix_channel_write0 (RemixEnv * env, RemixChannel * channel,
+                                RemixCount length);
+
+RemixCount _remix_channel_write (RemixEnv * env, RemixChannel * channel,
+                                RemixCount count, RemixChannel * data);
+RemixCount _remix_channel_length (RemixEnv * env, RemixChannel * channel);
+RemixCount _remix_channel_seek (RemixEnv * env, RemixChannel * channel,
+                               RemixCount offset);
+
+RemixCount remix_channel_interleave_2 (RemixEnv * env,
+                                      RemixChannel * src1,
+                                      RemixChannel * src2,
+                                      RemixPCM * dest, RemixCount count);
+RemixCount remix_channel_deinterleave_2 (RemixEnv * env,
+                                        RemixChannel * dest1,
+                                        RemixChannel * dest2,
+                                        RemixPCM * src, RemixCount count);
+RemixCount remix_channel_mix (RemixEnv * env, RemixChannel * src,
+                             RemixChannel * dest, RemixCount count);
+
+
+/* remix_channelset */
+void remix_channelset_defaults_initialise (RemixEnv * env);
+void remix_channelset_defaults_destroy (RemixEnv * env);
+
+/* remix_chunk */
+RemixChunk * remix_chunk_new (RemixEnv * env, RemixCount start_index,
+                             RemixCount length);
+RemixChunk * remix_chunk_new_from_buffer (RemixEnv * env,
+                                         RemixCount start_index,
+                                         RemixCount length,
+                                         RemixPCM * buffer);
+RemixChunk * remix_chunk_clone (RemixEnv * env, RemixChunk * chunk);
+void remix_chunk_free (RemixEnv * env, RemixChunk * chunk);
+RemixCount _remix_chunk_clear_region (RemixEnv * env, RemixChunk * chunk,
+                                     RemixCount start, RemixCount length,
+                                     int channelname, void * unused);
+RemixCount _remix_chunk_gain (RemixEnv * env, RemixChunk * chunk,
+                             RemixCount start, RemixCount count,
+                             int channelname, /* (RemixPCM *) */ void * gain);
+RemixCount _remix_chunk_copy (RemixEnv * env, RemixChunk * src,
+                             RemixCount src_offset,
+                             RemixChunk * dest, RemixCount dest_offset,
+                             RemixCount count, int channelname,
+                             void * unused);
+RemixCount _remix_chunk_add_inplace (RemixEnv * env, RemixChunk * src,
+                                    RemixCount src_offset,
+                                    RemixChunk * dest, RemixCount dest_offset,
+                                    RemixCount count, int channelname,
+                                    void * unused);
+RemixCount _remix_chunk_mult_inplace (RemixEnv * env, RemixChunk * src,
+                                     RemixCount src_offset,
+                                     RemixChunk * dest,
+                                     RemixCount dest_offset,
+                                     RemixCount count, int channelname,
+                                     void * unused);
+RemixCount _remix_chunk_fade_inplace (RemixEnv * env, RemixChunk * src,
+                                     RemixCount src_offset,
+                                     RemixChunk * dest,
+                                     RemixCount dest_offset,
+                                     RemixCount count, int channelname,
+                                     void * unused);
+RemixCount _remix_chunk_interleave_2 (RemixEnv * env,
+                                     RemixChunk * src1,
+                                     RemixCount src1_offset,
+                                     RemixChunk * src2,
+                                     RemixCount src2_offset,
+                                     RemixCount count,
+                                     int unused, void * dest);
+RemixCount _remix_chunk_deinterleave_2 (RemixEnv * env,
+                                       RemixChunk * dest1,
+                                       RemixCount dest1_offset,
+                                       RemixChunk * dest2,
+                                       RemixCount dest2_offset,
+                                       RemixCount count,
+                                       int unused, void * src);
+RemixCount _remix_chunk_blend_inplace (RemixEnv * env,
+                                      RemixChunk * src, RemixCount src_offset,
+                                      RemixChunk * blend,
+                                      RemixCount blend_offset,
+                                      RemixChunk * dest,
+                                      RemixCount dest_offset,
+                                      RemixCount count,
+                                      int channelname, void * unused);
+
+/* XXX: remove these when dynamic! */
+CDList * __gain_init (RemixEnv * env);
+CDList * __sndfile_init (RemixEnv * env);
+CDList * __ogg_init (RemixEnv * env);
+
+#endif /* defined(__REMIX__) */
+
+#endif /* __REMIX_PRIVATE_H__ */
diff --git a/src/libremix/remix_sndfile.c b/src/libremix/remix_sndfile.c
new file mode 100644 (file)
index 0000000..664ba83
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixSndfile: a libsndfile handler
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#include <stdio.h>
+#include <sndfile.h>
+#include <string.h>
+
+#define __REMIX__
+#include "remix.h"
+
+#define PATH_KEY 1
+#define BLOCK_FRAMES 4096
+
+typedef struct _RemixSndfileInstance RemixSndfileInstance;
+
+struct _RemixSndfileInstance {
+  char * path;
+  int writing;
+  SNDFILE * file;
+  SF_INFO info;
+  float * pcm;
+  sf_count_t pcm_n;
+  CDSet * channels;
+};
+
+
+/* Optimisation dependencies: none */
+static RemixBase * remix_sndfile_optimise (RemixEnv * env, RemixBase * sndfile);
+
+
+static RemixBase *
+remix_sndfile_create (RemixEnv * env, RemixBase * sndfile,
+                    const char * path, int writing)
+{
+  RemixSndfileInstance * si =
+    remix_malloc (sizeof (struct _RemixSndfileInstance));
+
+  si->path = strdup (path);
+  si->writing = writing;
+
+  if (writing) {
+    si->info.samplerate = remix_get_samplerate (env);
+    si->info.channels = 1; /* XXX: how many channels, or specify? */
+    si->info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; /* XXX: assumes WAV */
+
+    si->file = sf_open  (path, SFM_WRITE, &si->info);
+    si->pcm = NULL;
+    si->pcm_n = 0;
+  } else {
+    si->file = sf_open (path, SFM_READ, &si->info);
+    si->pcm = (float *) malloc (BLOCK_FRAMES * si->info.channels *
+                               sizeof(float));
+    si->pcm_n = 0;
+  }
+
+  if (si->file == NULL) {
+    remix_set_error (env, REMIX_ERROR_SYSTEM);
+    remix_destroy (env, (RemixBase *)sndfile);
+    return RemixNone;
+  }
+
+  sf_command (si->file, SFC_SET_NORM_FLOAT, NULL, SF_TRUE);
+
+  if (writing)
+    sf_command (si->file, SFC_SET_ADD_DITHER_ON_WRITE, NULL, SF_TRUE);
+
+  sndfile->instance_data = si;
+
+  return sndfile;
+}
+
+static RemixBase *
+remix_sndfile_reader_init (RemixEnv * env, RemixBase * base, CDSet * parameters)
+{
+  char * path;
+
+  path = (cd_set_find (env, parameters, PATH_KEY)).s_string;
+
+  if (remix_sndfile_create (env, base, path, 0) == RemixNone)
+       return RemixNone;
+
+  remix_sndfile_optimise (env, base);
+  return base;
+}
+
+static RemixBase *
+remix_sndfile_writer_init (RemixEnv * env, RemixBase * base, CDSet * parameters)
+{
+  char * path;
+
+  path = (cd_set_find (env, parameters, PATH_KEY)).s_string;
+
+  remix_sndfile_create (env, base, path, 1);
+  remix_sndfile_optimise (env, base);
+  return base;
+}
+
+static RemixBase *
+remix_sndfile_clone (RemixEnv * env, RemixBase * base)
+{
+  RemixBase * new_sndfile = remix_base_new (env);
+  RemixSndfileInstance * si = (RemixSndfileInstance *)base->instance_data;
+  remix_sndfile_create (env, new_sndfile, si->path, si->writing);
+  remix_sndfile_optimise (env, new_sndfile);
+  return new_sndfile;
+}
+
+static int
+remix_sndfile_destroy (RemixEnv * env, RemixBase * base)
+{
+  RemixSndfileInstance * si = (RemixSndfileInstance *)base->instance_data;
+  if (si->file != NULL) sf_close (si->file);
+  remix_free (si);
+  remix_free (base);
+  return 0;
+}
+
+/* An RemixChunkFunc for creating sndfile */
+
+static RemixCount
+remix_sndfile_read_update (RemixEnv * env, RemixBase * sndfile,
+                          RemixCount count)
+{
+  RemixSndfileInstance * si = (RemixSndfileInstance *)sndfile->instance_data;
+
+  si->pcm_n = sf_readf_float (si->file, si->pcm, count);
+
+  return si->pcm_n;
+}
+
+static RemixCount
+remix_sndfile_read_into_chunk (RemixEnv * env, RemixChunk * chunk,
+                              RemixCount offset, RemixCount count,
+                              int channelname, void * data)
+{
+  RemixBase * sndfile = (RemixBase *)data;
+  RemixPCM * d, * p;
+  RemixCount remaining = count, written = 0, n, i;
+  RemixSndfileInstance * si = (RemixSndfileInstance *)sndfile->instance_data;
+
+  remix_dprintf ("[remix_sndfile_read_into_chunk] (%p, +%ld) @ %ld\n",
+                sndfile, count, remix_tell (env, sndfile));
+
+  d = &chunk->data[offset];
+
+  n = MIN (remaining, BLOCK_FRAMES);
+  if (channelname == 0)
+    remix_sndfile_read_update (env, sndfile, n);
+
+  n = MIN (si->pcm_n, remaining);
+
+  p = si->pcm;
+  p += channelname;
+
+  for (i = 0; i < n; i++) {
+    *d++ = *p;
+    p += si->info.channels;
+  }
+
+  if (n == 0) { /* EOF */
+    n = _remix_pcm_set (d, 0.0, remaining);
+  }
+
+  remaining -= n;
+  written += n;
+
+#if 0 /* mono only */
+  d = &chunk->data[offset];
+
+  while (remaining > 0) {
+    n = MIN (remaining, BLOCK_FRAMES);
+    n = sf_readf_float (si->file, d, n);
+
+    if (n == 0) { /* EOF */
+      n = _remix_pcm_set (d, 0.0, remaining);
+    }
+
+    remaining -= n;
+    written += n;
+
+    d += n;
+  }
+#endif
+
+  return written;
+}
+
+static RemixCount
+remix_sndfile_write_from_chunk (RemixEnv * env, RemixChunk * chunk,
+                              RemixCount offset, RemixCount count,
+                              int channelname, void * data)
+{
+  RemixBase * sndfile = (RemixBase *)data;
+  RemixPCM * d;
+  RemixCount remaining = count, read = 0, n;
+  RemixSndfileInstance * si = (RemixSndfileInstance *) sndfile->instance_data;
+
+  remix_dprintf ("[remix_sndfile_write_from_chunk] (%p, +%ld) @ %ld\n",
+                sndfile, count, remix_tell (env, sndfile));
+
+  d = &chunk->data[offset];
+
+  while (remaining > 0) {
+    n = MIN (remaining, BLOCK_FRAMES);
+    n = sf_write_float (si->file, d, n);
+
+    if (n == 0) { /* EOF */
+      n = remaining;
+    }
+
+    remaining -= n;
+    read += n;
+
+    d += n;
+  }
+
+  return read;
+}
+
+static RemixCount
+remix_sndfile_reader_process (RemixEnv * env, RemixBase * base,
+                             RemixCount count,
+                             RemixStream * input, RemixStream * output)
+{
+  return remix_stream_chunkfuncify (env, output, count,
+                                   remix_sndfile_read_into_chunk, base);
+}
+
+static RemixCount
+remix_sndfile_writer_process (RemixEnv * env, RemixBase * base,
+                             RemixCount count,
+                             RemixStream * input, RemixStream * output)
+{
+  return remix_stream_chunkfuncify (env, output, count,
+                                  remix_sndfile_write_from_chunk, base);
+}
+
+static RemixCount
+remix_sndfile_length (RemixEnv * env, RemixBase * base)
+{
+  RemixSndfileInstance * si = (RemixSndfileInstance *)base->instance_data;
+  return si->info.frames;
+}
+
+static RemixCount
+remix_sndfile_seek (RemixEnv * env, RemixBase * base, RemixCount offset)
+{
+  RemixSndfileInstance * si = (RemixSndfileInstance *)base->instance_data;
+  return sf_seek (si->file, offset, SEEK_SET);
+}
+
+static struct _RemixMethods _remix_sndfile_reader_methods = {
+  remix_sndfile_clone,
+  remix_sndfile_destroy,
+  NULL, /* ready */
+  NULL, /* prepare */
+  remix_sndfile_reader_process,
+  remix_sndfile_length,
+  remix_sndfile_seek,
+  NULL, /* flush */
+};
+
+static struct _RemixMethods _remix_sndfile_writer_methods = {
+  remix_sndfile_clone,
+  remix_sndfile_destroy,
+  NULL, /* ready */
+  NULL, /* prepare */
+  remix_sndfile_writer_process,
+  remix_sndfile_length,
+  remix_sndfile_seek,
+  NULL, /* flush */
+};
+
+static RemixBase *
+remix_sndfile_optimise (RemixEnv * env, RemixBase * sndfile)
+{
+  RemixSndfileInstance * si = (RemixSndfileInstance *)sndfile->instance_data;
+
+  if (si->writing)
+    remix_base_set_methods (env, sndfile, &_remix_sndfile_writer_methods);
+  else
+    remix_base_set_methods (env, sndfile, &_remix_sndfile_reader_methods);
+
+  return sndfile;
+}
+
+
+static struct _RemixParameterScheme path_scheme = {
+  "path",
+  "Path to sound file",
+  REMIX_TYPE_STRING,
+  REMIX_CONSTRAINT_TYPE_NONE,
+  REMIX_CONSTRAINT_EMPTY,
+  REMIX_HINT_FILENAME,
+};
+
+
+static struct _RemixParameterScheme channels_scheme = {
+  "channels",
+  "Channel List to play file",
+  REMIX_TYPE_BOOL,
+  REMIX_CONSTRAINT_TYPE_NONE,
+  REMIX_CONSTRAINT_EMPTY,
+  REMIX_HINT_CHANNEL,
+};
+
+
+#if 0
+static RemixNamedParameter types[] = {
+  REMIX_NAMED_PARAMETER ("WAV", CD_INT(SF_FORMAT_WAV)),
+  REMIX_NAMED_PARAMETER ("AIFF", CD_INT(SF_FORMAT_AIFF)),
+  REMIX_NAMED_PARAMETER ("Sun/NeXT AU format (big endian)", CD_INT(SF_FORMAT_AU)),
+  REMIX_NAMED_PARAMETER ("DEC AU format (little endian)", CD_INT(SF_FORMAT_AULE)),
+  REMIX_NAMED_PARAMETER ("RAW PCM data", CD_INT(SF_FORMAT_RAW)),
+  REMIX_NAMED_PARAMETER ("Ensoniq PARIS", CD_INT(SF_FORMAT_PAF)),
+  REMIX_NAMED_PARAMETER ("Amiga IFF / SVX8 / SV16", CD_INT(SF_FORMAT_SVX)),
+  REMIX_NAMED_PARAMETER ("Sphere NIST", CD_INT(SF_FORMAT_NIST)),
+  REMIX_NAMED_PARAMETER ("Windows Media Audio", CD_INT(SF_FORMAT_WMA)),
+  REMIX_NAMED_PARAMETER ("Sekd Samplitude", CD_INT(SF_FORMAT_SMPLTD)),
+  REMIX_NAMED_PARAMETER ("VOC", CD_INT(SF_FORMAT_VOC)),
+  REMIX_NAMED_PARAMETER ("Sound Designer 2", CD_INT(SF_FORMAT_SD2)),
+  REMIX_NAMED_PARAMETER ("Rex2", CD_INT(SF_FORMAT_REX2)),
+  REMIX_NAMED_PARAMETER ("PCM", CD_INT(SF_FORMAT_PCM)),
+  REMIX_NAMED_PARAMETER ("32 bit floats", CD_INT(SF_FORMAT_FLOAT)),
+  REMIX_NAMED_PARAMETER ("U-Law encoded", CD_INT(SF_FORMAT_ULAW)),
+  REMIX_NAMED_PARAMETER ("A-Law encoded", CD_INT(SF_FORMAT_ALAW)),
+  REMIX_NAMED_PARAMETER ("IMA ADPCM", CD_INT(SF_FORMAT_IMA_ADPCM)),
+  REMIX_NAMED_PARAMETER ("Microsoft ADPCM", CD_INT(SF_FORMAT_MS_ADPCM)),
+  REMIX_NAMED_PARAMETER ("Big endian PCM", CD_INT(SF_FORMAT_PCM_BE)),
+  REMIX_NAMED_PARAMETER ("Little endian PCM", CD_INT(SF_FORMAT_PCM_LE)),
+  REMIX_NAMED_PARAMETER ("Signed 8 bit PCM", CD_INT(SF_FORMAT_PCM_S8)),
+  REMIX_NAMED_PARAMETER ("Unsigned 8 bit PCM", CD_INT(SF_FORMAT_PCM_U8)),
+  REMIX_NAMED_PARAMETER ("SVX Fibonacci Delta", CD_INT(SF_FORMAT_SVX_FIB)),
+  REMIX_NAMED_PARAMETER ("SVX Exponential Delta", CD_INT(SF_FORMAT_SVX_EXP)),
+  REMIX_NAMED_PARAMETER ("GSM 6.10 Encoding", CD_INT(SF_FORMAT_GSM610)),
+  REMIX_NAMED_PARAMETER ("32kbs G721 ADPCM", CD_INT(SF_FORMAT_G721_32)),
+  REMIX_NAMED_PARAMETER ("24kbs G723 ADPCM", CD_INT(SF_FORMAT_G723_24)),
+};
+#endif
+
+static struct _RemixParameterScheme format_scheme = {
+  "format",
+  "Format of sound file",
+  REMIX_TYPE_INT,
+  REMIX_CONSTRAINT_TYPE_LIST,
+  REMIX_CONSTRAINT_EMPTY,
+  REMIX_HINT_DEFAULT,
+};
+
+static struct _RemixMetaText sndfile_reader_metatext = {
+  "builtin::sndfile_reader",
+  "File::Sndfile Reader",
+  "Reads PCM audio files using libsndfile",
+  "Copyright (C) 2001, 2002 CSIRO Australia",
+  "http://www.metadecks.org/software/env/plugins/sndfile.html",
+  REMIX_ONE_AUTHOR ("Conrad Parker", "conrad@metadecks.org"),
+};
+
+static struct _RemixMetaText sndfile_writer_metatext = {
+  "builtin::sndfile_writer",
+  "File::Sndfile Writer",
+  "Writes PCM audio files using libsndfile",
+  "Copyright (C) 2001, 2002 CSIRO Australia",
+  "http://www.metadecks.org/software/env/plugins/sndfile.html",
+  REMIX_ONE_AUTHOR ("Conrad Parker", "conrad@metadecks.org"),
+};
+
+static struct _RemixPlugin sndfile_reader_plugin = {
+  &sndfile_reader_metatext,
+  REMIX_FLAGS_NONE,
+  CD_EMPTY_SET, /* init scheme */
+  remix_sndfile_reader_init,
+  CD_EMPTY_SET, /* process scheme */
+  NULL, /* suggests */
+  NULL, /* plugin data */
+  NULL  /* destroy */
+};
+
+static struct _RemixPlugin sndfile_writer_plugin = {
+  &sndfile_writer_metatext,
+  REMIX_FLAGS_NONE,
+  CD_EMPTY_SET, /* init scheme */
+  remix_sndfile_writer_init,
+  CD_EMPTY_SET, /* process scheme */
+  NULL, /* suggests */
+  NULL, /* plugin data */
+  NULL  /* destroy */
+};
+
+/* module init function */
+CDList *
+__sndfile_init (RemixEnv * env)
+{
+  CDList * plugins = cd_list_new (env);
+  int i, count;
+  SF_FORMAT_INFO info;
+  RemixNamedParameter * param;
+
+  sndfile_reader_plugin.init_scheme =
+    cd_set_insert (env, sndfile_reader_plugin.init_scheme, PATH_KEY,
+                  CD_POINTER(&path_scheme));
+
+  plugins = cd_list_prepend (env, plugins,
+                            CD_POINTER(&sndfile_reader_plugin));
+
+  format_scheme.constraint.list = cd_list_new (env);
+
+  sf_command (NULL, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof (int)) ;
+
+  for (i = 0; i < count ; i++) {
+    info.format = i ;
+    sf_command (NULL, SFC_GET_FORMAT_MAJOR, &info, sizeof (info)) ;
+
+    param = remix_malloc (sizeof(RemixNamedParameter));
+    param->name = strdup (info.name);
+    param->parameter = CD_INT(info.format);
+
+    format_scheme.constraint.list =
+      cd_list_append (env, format_scheme.constraint.list, CD_POINTER(param));
+  }
+
+  sndfile_writer_plugin.init_scheme =
+    cd_set_insert (env, sndfile_writer_plugin.init_scheme, PATH_KEY,
+                  CD_POINTER(&path_scheme));
+
+  plugins = cd_list_prepend (env, plugins,
+                            CD_POINTER(&sndfile_writer_plugin));
+
+  return plugins;
+}
+
diff --git a/src/libremix/remix_sound.c b/src/libremix/remix_sound.c
new file mode 100644 (file)
index 0000000..a36cb8f
--- /dev/null
@@ -0,0 +1,577 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixSound: An instance of an base within an RemixLayer sequence.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ *
+ * Description
+ * -----------
+ *
+ * A sound is contained within a layer. Each sound is a unique entity, but
+ * many sounds may have the same source base.
+ *
+ * Invariants
+ * ----------
+ *
+ * A sound must be contained in a layer.
+ */
+
+#include <string.h>
+
+#define __REMIX__
+#include "remix.h"
+
+/* Optimisation dependencies: none */
+static RemixSound * remix_sound_optimise (RemixEnv * env, RemixSound * sound);
+
+/*
+ * remix_sound_replace_mixstreams (env, sound)
+ *
+ * Replaces mix- (and envelope-) streams of 'sound' with new ones of
+ * the env's mixlength.
+ */
+static void
+remix_sound_replace_mixstreams (RemixEnv * env, RemixSound * sound)
+{
+  RemixCount mixlength = _remix_base_get_mixlength (env, sound);
+
+  if (sound->_rate_envstream != RemixNone)
+    remix_destroy (env, (RemixBase *)sound->_rate_envstream);
+  if (sound->_gain_envstream != RemixNone)
+    remix_destroy (env, (RemixBase *)sound->_gain_envstream);
+  if (sound->_blend_envstream != RemixNone)
+    remix_destroy (env, (RemixBase *)sound->_blend_envstream);
+
+  sound->_rate_envstream =
+    remix_stream_new_contiguous (env, mixlength);
+  sound->_gain_envstream =
+    remix_stream_new_contiguous (env, mixlength);
+  sound->_blend_envstream =
+    remix_stream_new_contiguous (env, mixlength);
+}
+
+static RemixBase *
+remix_sound_init (RemixEnv * env, RemixBase * base)
+{
+  RemixSound * sound = (RemixSound *)base;
+  sound->rate_envelope = sound->gain_envelope = sound->blend_envelope =
+    RemixNone;
+  sound->cutin = sound->cutlength = 0;
+  sound->_rate_envstream = sound->_gain_envstream = sound->_blend_envstream =
+    RemixNone;
+  remix_sound_replace_mixstreams (env, sound);
+  remix_sound_optimise (env, sound);
+  return (RemixBase *)sound;
+}
+
+static RemixSound *
+_remix_sound_new (RemixEnv * env)
+{
+  return (RemixSound *)
+    remix_base_new_subclass (env, sizeof (struct _RemixSound));
+}
+
+RemixBase *
+remix_sound_clone_invalid (RemixEnv * env, RemixBase * base)
+{
+  RemixSound * sound = (RemixSound *)base;
+  RemixSound * new_sound = _remix_sound_new (env);
+
+  memcpy (new_sound, sound, sizeof (struct _RemixSound));
+  new_sound->layer = RemixNone;
+
+  return (RemixBase *)new_sound;
+}
+
+RemixBase *
+remix_sound_clone_with_layer (RemixEnv * env, RemixBase * base,
+                              RemixLayer * new_layer)
+{
+  RemixSound * sound = (RemixSound *)base;
+  RemixSound * new_sound = _remix_sound_new (env);
+
+  memcpy (new_sound, sound, sizeof (struct _RemixSound));
+  new_sound->layer = new_layer;
+  _remix_layer_add_sound (env, new_layer, new_sound, new_sound->start_time);
+
+  return (RemixBase *)new_sound;
+}
+
+/* XXX: This breaks sound invariant */
+RemixSound *
+_remix_sound_remove (RemixEnv * env, RemixSound * sound)
+{
+  if (sound->layer == RemixNone) return RemixNone;
+  return _remix_layer_remove_sound (env, sound->layer, sound);
+}
+
+
+static int
+remix_sound_destroy (RemixEnv * env, RemixBase * base)
+{
+  RemixSound * sound = (RemixSound *)base;
+
+  _remix_sound_remove (env, sound);
+
+  if (sound->rate_envelope)
+    remix_destroy (env, sound->rate_envelope);
+  if (sound->gain_envelope)
+    remix_destroy (env, sound->gain_envelope);
+  if (sound->blend_envelope)
+    remix_destroy (env, sound->blend_envelope);
+  if (sound->_rate_envstream)
+    remix_destroy (env, (RemixBase *)sound->_rate_envstream);
+  if (sound->_gain_envstream)
+    remix_destroy (env, (RemixBase *)sound->_gain_envstream);
+  if (sound->_blend_envstream)
+    remix_destroy (env, (RemixBase *)sound->_blend_envstream);
+  remix_free (sound);
+
+  return 0;
+}
+
+static int
+remix_sound_ready (RemixEnv * env, RemixBase * base)
+{
+  return 0;
+}
+
+static RemixBase *
+remix_sound_prepare (RemixEnv * env, RemixBase * base)
+{
+  RemixSound * sound = (RemixSound *)base;
+  remix_sound_replace_mixstreams (env, sound);
+  return base;
+}
+
+RemixBase *
+remix_sound_set_source (RemixEnv * env, RemixSound * sound, RemixBase * source)
+{
+  RemixBase * old = sound->source;
+  sound->source = source;
+  return old;
+}
+
+RemixBase *
+remix_sound_get_source (RemixEnv * env, RemixSound * sound)
+{
+  return sound->source;
+}
+
+RemixSound *
+remix_sound_new (RemixEnv * env, RemixBase * source, RemixLayer * layer,
+                RemixTime start_time, RemixTime duration)
+{
+  RemixSound * sound = _remix_sound_new (env);
+
+  sound->layer = layer;
+  sound->start_time = start_time;
+  sound->duration = duration;
+  _remix_layer_add_sound (env, layer, sound, start_time);
+  sound->source = source;
+  remix_sound_init (env, (RemixBase *)sound);
+  return sound;
+}
+
+RemixLayer *
+remix_sound_get_layer (RemixEnv * env, RemixSound * sound)
+{
+  return sound->layer;
+}
+
+RemixTrack *
+remix_sound_get_track (RemixEnv * env, RemixSound * sound)
+{
+  if (sound->layer == RemixNone) return RemixNone;
+  return remix_layer_get_track (env, sound->layer);
+}
+
+RemixDeck *
+remix_sound_get_deck (RemixEnv * env, RemixSound * sound)
+{
+  if (sound->layer == RemixNone) return RemixNone;
+  return remix_layer_get_deck (env, sound->layer);
+}
+
+RemixTime
+remix_sound_move (RemixEnv * env, RemixSound * sound, RemixTime start_time)
+{
+  RemixTime old = sound->start_time;
+  RemixLayer * layer = sound->layer;
+  if (_remix_sound_remove (env, sound) != RemixNone) {
+    _remix_layer_add_sound (env, layer, sound, start_time);
+    return old;
+  } else {
+    return _remix_time_invalid (sound->layer->timetype);
+  }
+}
+
+RemixSound *
+remix_sound_get_prev (RemixEnv * env, RemixSound * sound)
+{
+  if (sound->layer)
+    return _remix_layer_get_sound_prev (env, sound->layer, sound);
+  else
+    return RemixNone;
+}
+
+RemixSound *
+remix_sound_get_next (RemixEnv * env, RemixSound * sound)
+{
+  if (sound->layer)
+    return _remix_layer_get_sound_next (env, sound->layer, sound);
+  else
+    return RemixNone;
+}
+
+int
+remix_sound_later (RemixEnv * env, RemixSound * s1, RemixSound * s2)
+{
+  RemixLayer * layer = remix_sound_get_layer (env, s1);
+  return _remix_time_gt (layer->timetype, s1->start_time, s2->start_time);
+}
+
+RemixTime
+remix_sound_set_start_time (RemixEnv * env, RemixSound * sound,
+                            RemixTime start_time)
+{
+  RemixTime old = sound->start_time;
+  RemixLayer * layer = sound->layer;
+  _remix_layer_remove_sound (env, layer, sound);
+  _remix_layer_add_sound (env, layer, sound, start_time);
+  return old;
+}
+
+RemixTime
+remix_sound_get_start_time (RemixEnv * env, RemixSound * sound)
+{
+  return sound->start_time;
+}
+
+RemixTime
+remix_sound_set_duration (RemixEnv * env, RemixSound * sound,
+                          RemixTime duration)
+{
+  RemixTime old = sound->duration;
+  sound->duration = duration;
+  return old;
+}
+
+RemixTime
+remix_sound_get_duration (RemixEnv * env, RemixSound * sound)
+{
+  return sound->duration;
+}
+
+RemixBase *
+remix_sound_set_rate_envelope (RemixEnv * env, RemixSound * sound,
+                           RemixBase * rate_envelope)
+{
+  RemixBase * old = sound->rate_envelope;
+  sound->rate_envelope = rate_envelope;
+  return old;
+}
+
+RemixBase *
+remix_sound_get_rate_envelope (RemixEnv * env, RemixSound * sound)
+{
+  if (sound == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_INVALID);
+    return RemixNone;
+  }
+  return sound->rate_envelope;
+}
+
+RemixBase *
+remix_sound_set_gain_envelope (RemixEnv * env, RemixSound * sound,
+                           RemixBase * gain_envelope)
+{
+  RemixBase * old;
+
+  if (sound == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_INVALID);
+    return RemixNone;
+  }
+  old = sound->gain_envelope;
+  sound->gain_envelope = gain_envelope;
+
+  return old;
+}
+
+RemixBase *
+remix_sound_get_gain_envelope (RemixEnv * env, RemixSound * sound)
+{
+  if (sound == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_INVALID);
+    return RemixNone;
+  }
+  return sound->gain_envelope;
+}
+
+RemixBase *
+remix_sound_set_blend_envelope (RemixEnv * env, RemixSound * sound,
+                            RemixBase * blend_envelope)
+{
+  RemixBase * old = sound->blend_envelope;
+  sound->blend_envelope = blend_envelope;
+  return old;
+}
+
+RemixBase *
+remix_sound_get_blend_envelope (RemixEnv * env, RemixSound * sound)
+{
+  if (sound == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_INVALID);
+    return RemixNone;
+  }
+  return sound->blend_envelope;
+}
+
+static RemixCount
+_remix_sound_fade (RemixEnv * env, RemixSound * sound, RemixCount count,
+                 RemixStream * input, RemixStream * output)
+{
+  RemixCount output_offset, n;
+
+  output_offset = remix_tell (env, (RemixBase *)output);
+
+  /* XXX: this wanted to use 'block' not 'count': have we bounds
+   * checked the sound ?? */
+
+  remix_seek (env, (RemixBase *)sound->_blend_envstream, 0, SEEK_SET);
+  n = remix_process (env, sound->blend_envelope, count, RemixNone,
+                 sound->_blend_envstream);
+  remix_stream_write (env, output, count, input);
+  remix_seek (env, (RemixBase *)sound->_blend_envstream, 0, SEEK_SET);
+  remix_seek (env, (RemixBase *)output, output_offset, SEEK_SET);
+  n = remix_stream_fade (env, sound->_blend_envstream, output, count);
+
+  return n;
+}
+
+/* Do rate conversion, handle offset etc.: get raw sound data */
+static RemixCount
+_remix_sound_get_raw (RemixEnv * env, RemixSound * sound, RemixCount offset,
+                      RemixCount count, RemixStream * input,
+                      RemixStream * output)
+{
+  RemixCount block, n;
+
+  remix_dprintf ("[_remix_sound_get_raw] (%p, +%ld, %p -> %p) @ %ld\n",
+             sound, count, input, output, offset);
+
+  /* XXX: deal with rate conversion!! */
+
+  if (sound->cutlength > 0) {
+    if (offset > sound->cutlength) {
+      remix_set_error (env, REMIX_ERROR_SILENCE);
+      return -1;
+    }
+    block = MIN (count, sound->cutlength - offset);
+  } else {
+    block = count;
+  }
+
+  remix_dprintf ("[_remix_sound_get_raw] block +%ld (cutin: %ld, cutlength: %ld)\n",
+             block, sound->cutin, sound->cutlength);
+
+  remix_seek (env, sound->source, sound->cutin + offset, SEEK_SET);
+  n = remix_process (env, sound->source, block, input, output);
+
+  if (n == -1) {
+    remix_dprintf ("error getting source data: %s\n",
+               remix_error_string(env, remix_last_error(env)));
+  } else {
+
+    if (block < count)
+      n += remix_stream_write0 (env, output, count - block);
+  }
+
+  remix_dprintf ("[_remix_sound_get_raw] got %ld raw samples\n", n);
+
+  return n;
+}
+
+static RemixCount
+_remix_sound_apply_gain (RemixEnv * env, RemixSound * sound,
+                     RemixCount offset, RemixCount count,
+                     RemixStream * data, RemixCount data_offset)
+{
+  RemixCount n;
+
+  remix_dprintf ("in _remix_sound_apply_gain (%p, +%ld)\n", sound, count);
+
+  remix_seek (env, sound->gain_envelope, offset, SEEK_SET);
+  remix_seek (env, (RemixBase *)sound->_gain_envstream, 0, SEEK_SET);
+  n = remix_process (env, sound->gain_envelope, count,
+                 RemixNone, sound->_gain_envstream);
+  remix_dprintf ("Got %ld values from gain_envelope %p onto stream %p\n",
+         n, sound->gain_envelope, sound->_gain_envstream);
+
+  remix_seek (env, (RemixBase *)data, data_offset, SEEK_SET);
+  remix_seek (env, (RemixBase *)sound->_gain_envstream, 0, SEEK_SET);
+  n = remix_stream_mult (env, sound->_gain_envstream, data, n);
+  remix_dprintf ("Multiplied %ld values of gain\n", n);
+
+  return n;
+}
+
+static RemixCount
+_remix_sound_blend (RemixEnv * env, RemixSound * sound, RemixCount count,
+                  RemixStream * input, RemixStream * output)
+{
+  RemixCount n;
+
+  /* XXX: this wanted to use 'block' not 'count': have we bounds
+   * checked the sound ?? */
+
+  remix_seek (env, (RemixBase * )sound->_blend_envstream, 0, SEEK_SET);
+  n = remix_process (env, sound->blend_envelope, count, RemixNone,
+                   sound->_blend_envstream);
+  remix_seek (env, (RemixBase *)sound->_blend_envstream, 0, SEEK_SET);
+  n = remix_stream_blend (env, input, sound->_blend_envstream, output,
+                        count);
+
+  return n;
+}
+
+static RemixCount
+remix_sound_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                     RemixStream * input, RemixStream * output)
+{
+  RemixSound * sound = (RemixSound *)base;
+  RemixCount remaining = count, processed = 0, block, m, n;
+  RemixCount offset, input_offset, output_offset;
+  RemixCount mixlength = _remix_base_get_mixlength (env, sound);
+
+  offset = remix_tell (env, (RemixBase *)sound);
+
+  remix_dprintf ("PROCESS SOUND (%p [%p], +%ld, %p -> %p) @ %ld\n",
+         sound, sound ? sound->source : NULL, count, input, output, offset);
+
+  /* if we're beyond the source's actual length, then
+   * just fade the input to the output using the sound's blend
+   * envelope */
+  if (offset > remix_length (env, sound->source)) {
+    remix_dprintf ("## offset %ld > length %ld\n", offset,
+           remix_length (env, sound->source));
+
+    /* Fade input and copy to output */
+    if (sound->blend_envelope == RemixNone) {
+      remix_set_error (env, REMIX_ERROR_NOOP);
+      return -1;
+    } else {
+      return _remix_sound_fade (env, sound, count, input, output);
+    }
+  }
+
+  while (remaining > 0) {
+    block = MIN (remaining, mixlength);
+
+    input_offset = remix_tell (env, (RemixBase *)input);
+    output_offset = remix_tell (env, (RemixBase *)output);
+
+    /* Get raw sound data; handle rate conversion etc. */
+    m = _remix_sound_get_raw (env, sound, offset, block, input, output);
+    if (m == -1) {
+      remix_dprintf ("error getting raw sound data\n");
+      break;
+    } else {
+      n = m;
+    }
+
+    /* Apply gain envelope */
+    if (sound->gain_envelope != RemixNone) {
+      m = _remix_sound_apply_gain (env, sound, offset, n, output, output_offset);
+      if (m == -1) {
+       remix_dprintf ("error applying gain!\n");
+      } else {
+       n = m;
+      }
+    }
+
+    /* Blend input back in */
+    if (sound->blend_envelope != RemixNone) {
+      remix_seek (env, (RemixBase *)input, input_offset, SEEK_SET);
+      remix_seek (env, (RemixBase *)output, output_offset, SEEK_SET);
+      n = _remix_sound_blend (env, sound, n, input, output);
+    }
+
+    offset += n;
+    processed += n;
+    remaining -= n;
+  }
+
+  remix_dprintf ("[remix_sound_process] processed %ld from sound %p\n",
+             processed, sound);
+
+  return processed;
+}
+
+static RemixCount
+remix_sound_length (RemixEnv * env, RemixBase * base)
+{
+  RemixSound * sound = (RemixSound *)base;
+  RemixTime duration = remix_sound_get_duration (env, sound);
+  RemixTime t = remix_time_convert (env, duration, sound->layer->timetype,
+                             REMIX_TIME_SAMPLES);
+  return t.samples;
+}
+
+static RemixCount
+remix_sound_seek (RemixEnv * env, RemixBase * base, RemixCount offset)
+{
+  RemixSound * sound = (RemixSound *)base;
+  if (sound->cutlength > 0 && offset > sound->cutlength) {
+    offset = sound->cutlength;
+  }
+  remix_seek (env, sound->source, sound->cutin + offset, SEEK_SET);
+  return offset;
+}
+
+static int
+remix_sound_flush (RemixEnv * env, RemixBase * base)
+{
+  RemixSound * sound = (RemixSound *)base;
+  return remix_flush (env, sound->source);
+}
+
+static struct _RemixMethods _remix_sound_methods = {
+  remix_sound_clone_invalid, /* clone */
+  remix_sound_destroy,       /* destroy */
+  remix_sound_ready,         /* ready */
+  remix_sound_prepare,       /* prepare */
+  remix_sound_process,       /* process */
+  remix_sound_length,        /* length */
+  remix_sound_seek,          /* seek */
+  remix_sound_flush,         /* flush */
+};
+
+static RemixSound *
+remix_sound_optimise (RemixEnv * env, RemixSound * sound)
+{
+  _remix_set_methods (env, sound, &_remix_sound_methods);
+  return sound;
+}
+
diff --git a/src/libremix/remix_squaretone.c b/src/libremix/remix_squaretone.c
new file mode 100644 (file)
index 0000000..9d25a77
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixSquareTone: a square wave tone generator
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#define __REMIX__
+#include "remix.h"
+
+typedef struct _RemixSquareToneChannelData RemixSquareToneChannelData;
+typedef struct _RemixSquareTone RemixSquareTone;
+
+struct _RemixSquareToneChannelData {
+  RemixCount _cycle_offset;
+};
+
+struct _RemixSquareTone {
+  RemixBase base;
+  float frequency;
+  CDSet * channel_data;
+  CDSet * channels;
+};
+
+/* Optimisation dependencies: none */
+static RemixSquareTone * remix_squaretone_optimise (RemixEnv * env,
+                                             RemixSquareTone * squaretone);
+
+static RemixSquareTone *
+remix_squaretone_replace_channels (RemixEnv * env, RemixSquareTone * squaretone)
+{
+  RemixSquareToneChannelData * sqch;
+  CDSet * s, * channels = remix_get_channels (env);
+  RemixCount offset = remix_tell (env, (RemixBase *)squaretone);
+
+  cd_set_free_all (env, squaretone->channel_data);
+
+  for (s = channels; s; s = s->next) {
+    remix_dprintf ("[remix_squaretone_replace_channels] %p replacing channel %d\n",
+               squaretone, s->key);
+    sqch = (RemixSquareToneChannelData *)
+      remix_malloc (sizeof (struct _RemixSquareToneChannelData));
+    sqch->_cycle_offset = 0;
+    squaretone->channel_data =
+      cd_set_insert (env, squaretone->channel_data, s->key, CD_POINTER(sqch));
+  }
+
+  if (offset > 0) remix_seek (env, (RemixBase *)squaretone, offset, SEEK_SET);
+
+  return squaretone;
+}
+
+static RemixBase *
+remix_squaretone_init (RemixEnv * env, RemixBase * base)
+{
+  RemixSquareTone * squaretone = (RemixSquareTone *)base;
+  squaretone->channel_data = NULL;
+  remix_squaretone_replace_channels (env, squaretone);
+  remix_squaretone_optimise (env, squaretone);
+  return base;
+}
+
+RemixBase *
+remix_squaretone_new (RemixEnv * env, float frequency)
+{
+  RemixSquareTone * squaretone = (RemixSquareTone *)
+    remix_base_new_subclass (env, sizeof (struct _RemixSquareTone));
+  remix_squaretone_init (env, (RemixBase *)squaretone);
+  squaretone->frequency = frequency;
+
+  return (RemixBase *)squaretone;
+}
+
+static RemixBase *
+remix_squaretone_clone (RemixEnv * env, RemixBase * base)
+{
+  RemixSquareTone * squaretone = (RemixSquareTone *)base;
+  RemixBase * new_squaretone =
+    remix_squaretone_new (env, squaretone->frequency);
+  remix_squaretone_optimise (env, (RemixSquareTone *)new_squaretone);
+  return new_squaretone;
+}
+
+static int
+remix_squaretone_destroy (RemixEnv * env, RemixBase * base)
+{
+  RemixSquareTone * squaretone = (RemixSquareTone *)base;
+  remix_free (squaretone);
+  return 0;
+}
+
+static int
+remix_squaretone_ready (RemixEnv * env, RemixBase * base)
+{
+  return (remix_base_has_samplerate (env, base) &&
+         remix_base_encompasses_channels (env, base));
+}
+
+static RemixBase *
+remix_squaretone_prepare (RemixEnv * env, RemixBase * base)
+{
+  RemixSquareTone * squaretone = (RemixSquareTone *)base;
+  remix_squaretone_replace_channels (env, squaretone);
+  return base;
+}
+
+float
+remix_squaretone_set_frequency (RemixEnv * env, RemixBase * base,
+                            float frequency)
+{
+  RemixSquareTone * squaretone = (RemixSquareTone *)base;
+  float old = squaretone->frequency;
+  squaretone->frequency = frequency;
+  return old;
+}
+
+float
+remix_squaretone_get_frequency (RemixEnv * env, RemixBase * base)
+{
+  RemixSquareTone * squaretone = (RemixSquareTone *)base;
+  return squaretone->frequency;
+}
+
+void
+remix_squaretone_add_channel (RemixEnv * env, RemixBase * base, RemixChannelName channel )
+{
+  RemixSquareTone * squaretone = (RemixSquareTone *)base;
+  squaretone->channels = cd_set_replace (env, squaretone->channels, channel, CD_POINTER(NULL));;
+}
+
+void
+remix_squaretone_remove_channel (RemixEnv * env, RemixBase * base, RemixChannelName channel )
+{
+  RemixSquareTone * squaretone = (RemixSquareTone *)base;
+  squaretone->channels = cd_set_remove(env, squaretone->channels, channel );
+}
+
+CDSet *
+remix_squaretone_get_channels (RemixEnv * env, RemixBase * base )
+{
+  RemixSquareTone * squaretone = (RemixSquareTone *)base;
+  return squaretone->channels;
+}
+
+
+/* An RemixChunkFunc for creating squaretone data */
+static RemixCount
+remix_squaretone_write_chunk (RemixEnv * env, RemixChunk * chunk,
+                              RemixCount offset, RemixCount count,
+                              int channelname, void * data)
+{
+  RemixSquareTone * squaretone = (RemixSquareTone *)data;
+  RemixSquareToneChannelData * sqch;
+  RemixCount remaining = count, written = 0, n;
+  RemixCount wavelength;
+  RemixPCM * d, value;
+  CDScalar k;
+  int channel_enabled = 0;
+
+  remix_dprintf ("[remix_squaretone_write_chunk] (+%ld) @ %ld\n",
+                 count, offset);
+
+  k = cd_set_find (env, squaretone->channel_data, channelname);
+  sqch = k.s_pointer;
+
+  channel_enabled = cd_set_contains (env, squaretone->channels, channelname);
+
+  if (sqch == RemixNone) {
+    remix_dprintf ("[remix_squaretone_write_chunk] channel %d not found\n",
+                   channelname);
+    remix_set_error (env, REMIX_ERROR_SILENCE);
+    return -1;
+  }
+
+  wavelength = (RemixCount)(remix_get_samplerate (env) / squaretone->frequency);
+
+  remix_dprintf ("[remix_squaretone_write_chunk] wavelength %ld, cycle_offset %ld\n",
+                 wavelength, sqch->_cycle_offset);
+
+  if (sqch->_cycle_offset < wavelength/2) {
+    n = MIN (remaining, wavelength/2 - sqch->_cycle_offset);
+    value = 1.0;
+  } else {
+    n = MIN (remaining, wavelength - sqch->_cycle_offset);
+    value = -1.0;
+  }
+
+  if(!channel_enabled ) value = 0;
+
+  d = &chunk->data[offset];
+  _remix_pcm_set (d, value, n);
+  remaining -= n; written += n; offset += n;
+
+  while (remaining > 0) {
+    n = MIN (remaining, wavelength/2);
+    value = -(value);
+    d = &chunk->data[offset];
+    _remix_pcm_set (d, value, n);
+    remaining -= n; written += n; offset += n;
+  }
+
+  sqch->_cycle_offset += written;
+  sqch->_cycle_offset %= wavelength;
+
+  remix_dprintf ("[remix_squaretone_write_chunk] written %ld\n", written);
+
+  return written;
+}
+
+static RemixCount
+remix_squaretone_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                          RemixStream * input, RemixStream * output)
+{
+  RemixSquareTone * squaretone = (RemixSquareTone *)base;
+  return remix_stream_chunkfuncify (env, output, count,
+                                    remix_squaretone_write_chunk, squaretone);
+}
+
+static RemixCount
+remix_squaretone_length (RemixEnv * env, RemixBase * base)
+{
+  return REMIX_COUNT_INFINITE;
+}
+
+static RemixCount
+remix_squaretone_seek (RemixEnv * env, RemixBase * base, RemixCount offset)
+{
+  RemixSquareTone * squaretone = (RemixSquareTone *)base;
+  RemixCount wavelength;
+  CDSet * s;
+  RemixCount cycle_offset;
+  RemixSquareToneChannelData * sqch;
+
+  wavelength = (RemixCount)(remix_get_samplerate (env) / squaretone->frequency);
+  cycle_offset = offset % wavelength;
+
+  for (s = squaretone->channel_data; s; s = s->next) {
+    sqch = (RemixSquareToneChannelData *)s->data.s_pointer;
+    sqch->_cycle_offset = cycle_offset;
+  }
+
+  return offset;
+}
+
+static struct _RemixMethods _remix_squaretone_methods = {
+  remix_squaretone_clone,
+  remix_squaretone_destroy,
+  remix_squaretone_ready,
+  remix_squaretone_prepare,
+  remix_squaretone_process,
+  remix_squaretone_length,
+  remix_squaretone_seek,
+  NULL, /* flush */
+};
+
+static RemixSquareTone *
+remix_squaretone_optimise (RemixEnv * env, RemixSquareTone * squaretone)
+{
+  _remix_set_methods (env, squaretone, &_remix_squaretone_methods);
+  return squaretone;
+}
diff --git a/src/libremix/remix_stream.c b/src/libremix/remix_stream.c
new file mode 100644 (file)
index 0000000..eab7b82
--- /dev/null
@@ -0,0 +1,647 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixStream: An indexed, sparse, polyphonic PCM data container.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ *
+ * Description
+ * -----------
+ *
+ * A stream consists of multiple channels of PCM data.
+ *
+ * Invariants
+ * ----------
+ *
+ * A stream is an independent entity.
+ */
+
+#define __REMIX__
+#include "remix.h"
+
+/* RemixStream */
+
+/* Optimisation dependencies: none */
+static RemixStream * remix_stream_optimise (RemixEnv * env,
+                                           RemixStream * stream);
+
+RemixBase *
+remix_stream_init (RemixEnv * env, RemixBase * base)
+{
+  RemixStream * stream = (RemixStream *)base;
+  CDSet * s, * channels = remix_get_channels (env);
+
+  stream->channels = cd_set_new (env);
+
+  for (s = channels; s; s = s->next) {
+    remix_stream_add_channel (env, stream, s->key);
+  }
+
+  remix_stream_optimise (env, stream);
+  return (RemixBase *)stream;
+}
+
+static RemixStream *
+remix_stream_add_channel_unchecked (RemixEnv * env, RemixStream * stream,
+                                   int name, RemixChannel * channel)
+{
+  stream->channels = cd_set_insert (env, stream->channels, name,
+                                   CD_POINTER(channel));
+  return stream;
+}
+
+RemixChannel *
+remix_stream_add_channel (RemixEnv * env, RemixStream * stream, int name)
+{
+  RemixChannel * channel = remix_stream_find_channel (env, stream, name);
+
+  if (channel == RemixNone) {
+    channel = remix_channel_new (env);
+    remix_stream_add_channel_unchecked (env, stream, name, channel);
+  }
+
+  return channel;
+}
+
+RemixStream *
+remix_stream_new (RemixEnv * env)
+{
+  RemixStream * stream =
+    (RemixStream *)remix_base_new_subclass (env, sizeof (struct _RemixStream));
+
+  remix_stream_init (env, (RemixBase *)stream);
+
+  return stream;
+}
+
+RemixStream *
+remix_stream_new_contiguous (RemixEnv * env, RemixCount length)
+{
+  RemixStream * stream = remix_stream_new (env);
+  remix_stream_add_chunks (env, stream, 0, length);
+  return stream;
+}
+
+RemixStream *
+remix_stream_new_from_buffers (RemixEnv * env, RemixCount length,
+                              RemixPCM ** buffers)
+{
+  CDSet * s;
+  RemixStream * stream = remix_stream_new (env);
+  RemixChannel * channel;
+  RemixChunk * chunk;
+  int i = 0;
+
+  for (s = stream->channels; s; s = s->next) {
+    channel = (RemixChannel *)s->data.s_pointer;
+    chunk = remix_chunk_new_from_buffer (env, 0, length, buffers[i++]);
+    remix_channel_add_chunk (env, channel, chunk);
+  }
+
+  return stream;
+}
+
+static RemixBase *
+remix_stream_clone (RemixEnv * env, RemixBase * base)
+{
+  RemixStream * stream = (RemixStream *)base;
+  RemixStream * new_stream;
+  CDSet * s;
+  RemixChannel * channel, * new_channel;
+
+  if (stream == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  new_stream = (RemixStream *)remix_stream_new (env);
+
+  /* clone channels */
+  for (s = stream->channels; s; s = s->next) {
+    channel = (RemixChannel *)s->data.s_pointer;
+    new_channel = remix_channel_clone (env, channel);
+    remix_stream_add_channel_unchecked (env, new_stream, s->key, new_channel);
+  }
+  return (RemixBase *)new_stream;
+}
+
+static int
+remix_stream_destroy (RemixEnv * env, RemixBase * base)
+{
+  RemixStream * stream = (RemixStream *)base;
+
+  if (stream == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  cd_set_destroy_with (env, stream->channels, (CDDestroyFunc)remix_destroy);
+
+  remix_free (stream);
+  return 0;
+}
+
+RemixCount
+remix_stream_nr_channels (RemixEnv * env, RemixStream * stream)
+{
+  if (stream == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  return (RemixCount)cd_set_size (env, stream->channels);
+}
+
+RemixChannel *
+remix_stream_find_channel (RemixEnv * env, RemixStream * stream, int name)
+{
+  CDScalar k;
+
+  if (stream == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  k = cd_set_find (env, stream->channels, name);
+  return (RemixChannel *)k.s_pointer;
+}
+
+
+RemixStream *
+remix_stream_remove_channel (RemixEnv * env, RemixStream * stream, int name)
+{
+  if (stream == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  stream->channels = cd_set_remove (env, stream->channels, name);
+
+  return stream;
+}
+
+RemixStream *
+remix_stream_add_chunks (RemixEnv * env, RemixStream * stream,
+                         RemixCount offset, RemixCount length)
+{
+  CDSet * s;
+  RemixChannel * channel;
+
+  if (stream == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  for (s = stream->channels; s; s = s->next) {
+    channel = (RemixChannel *)s->data.s_pointer;
+    remix_channel_add_new_chunk (env, channel, offset, length);
+  }
+
+  return stream;
+}
+
+RemixCount
+remix_stream_write0 (RemixEnv * env, RemixStream * stream, RemixCount count)
+{
+  CDSet * s;
+  RemixChannel * channel;
+  RemixCount offset;
+
+  if (stream == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  offset = remix_tell (env, (RemixBase *)stream);
+
+  for (s = stream->channels; s; s = s->next) {
+    channel = (RemixChannel *)s->data.s_pointer;
+    remix_channel_write0 (env, channel, count);
+  }
+
+  remix_seek (env, (RemixBase *)stream, offset + count, SEEK_SET);
+
+  remix_dprintf ("[remix_stream_write0] (%p) written %ld\n", stream, count);
+
+  return count;
+}
+
+/*
+ * remix_stream_process (env, stream, count, input, output)
+ *
+ * RemixProcessFunc for RemixStream.
+ * Ignores input. Copies data from 'stream' to 'output'.
+ */
+static RemixCount
+remix_stream_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                      RemixStream * input, RemixStream * output)
+{
+  RemixStream * stream = (RemixStream *)base;
+  return remix_stream_write (env, output, count, stream);
+}
+
+static RemixCount
+remix_stream_length (RemixEnv * env, RemixBase * base)
+{
+  RemixStream * stream = (RemixStream *)base;
+  RemixCount length, maxlength = 0;
+  CDSet * s;
+  RemixChannel * channel;
+
+  if (stream == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  for (s = stream->channels; s; s = s->next) {
+    channel = (RemixChannel *)s->data.s_pointer;
+    length = _remix_channel_length (env, channel);
+    maxlength = MAX (maxlength, length);
+  }
+
+  return maxlength;
+}
+
+static RemixCount
+remix_stream_seek (RemixEnv * env, RemixBase * base, RemixCount offset)
+{
+  RemixStream * stream = (RemixStream *)base;
+  CDSet * s;
+  RemixChannel * channel;
+
+  for (s = stream->channels; s; s = s->next) {
+    channel = (RemixChannel *)s->data.s_pointer;
+    _remix_channel_seek (env, channel, offset);
+  }
+
+  return offset;
+}
+
+static struct _RemixMethods _remix_stream_methods = {
+  remix_stream_clone,
+  remix_stream_destroy,
+  NULL, /* ready */
+  NULL, /* prepare */
+  remix_stream_process,
+  remix_stream_length,
+  remix_stream_seek,
+};
+
+static RemixStream *
+remix_stream_optimise (RemixEnv * env, RemixStream * stream)
+{
+  _remix_set_methods (env, stream, &_remix_stream_methods);
+  return stream;
+}
+
+
+/*
+ * remix_stream_chunkfuncify (stream, count, func, data)
+ *
+ */
+RemixCount
+remix_stream_chunkfuncify (RemixEnv * env, RemixStream * stream,
+                          RemixCount count,
+                          RemixChunkFunc func, void * data)
+{
+  RemixCount n, minn = count, offset = remix_tell (env, (RemixBase *)stream);
+  CDSet * s, * channels = remix_get_channels (env);
+  RemixChannel * channel;
+
+  for (s = channels; s; s = s->next) {
+    remix_dprintf ("[remix_stream_chunkfuncify] thinking of channel %d\n",
+                  s->key);
+  }
+
+  if (stream == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  remix_dprintf ("[remix_stream_chunkfuncify] (%p, +%ld) @ %ld\n",
+                stream, count, offset);
+
+  for (s = stream->channels; s; s = s->next) {
+    if (cd_set_contains (env, channels, s->key)) {
+      channel = (RemixChannel *)s->data.s_pointer;
+      n = remix_channel_chunkfuncify (env, channel, minn, func, s->key, data);
+      minn = MIN (n, minn);
+    } else {
+      remix_dprintf ("[remix_stream_chunkfuncify] channel %d not funced\n", s->key);
+    }
+  }
+
+  remix_seek (env, (RemixBase *)stream, offset + minn, SEEK_SET);
+
+  return minn;
+}
+
+RemixCount
+remix_stream_chunkchunkfuncify (RemixEnv * env, RemixStream * src,
+                               RemixStream * dest, RemixCount count,
+                               RemixChunkChunkFunc func, void * data)
+{
+  RemixCount n, minn = count;
+  RemixCount src_offset = remix_tell (env, (RemixBase *)src);
+  RemixCount dest_offset = remix_tell (env, (RemixBase *)dest);
+  CDSet * s, * channels = remix_get_channels (env);
+  RemixChannel * sch, * dch;
+
+  if (dest == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  remix_dprintf ("[remix_stream_ccf...] (%p -> %p, +%ld), src @ %ld, dest @ %ld\n",
+             src, dest, count, src_offset, dest_offset);
+
+  for (s = dest->channels; s; s = s->next) {
+    if (cd_set_contains (env, channels, s->key)) {
+      dch = (RemixChannel *)s->data.s_pointer;
+      sch = remix_stream_find_channel (env, src, s->key);
+      if (sch != RemixNone) {
+       n = remix_channel_chunkchunkfuncify (env, sch, dch, count, func, s->key,
+                                         data);
+       if (n == -1) {
+         return -1;
+       }
+
+       minn = MIN (n, minn);
+      }
+    }
+  }
+
+  remix_seek (env, (RemixBase *)src, src_offset + minn, SEEK_SET);
+  remix_seek (env, (RemixBase *)dest, dest_offset + minn, SEEK_SET);
+
+  return minn;
+}
+
+RemixCount
+remix_stream_chunkchunkchunkfuncify (RemixEnv * env,
+                                     RemixStream * src1, RemixStream * src2,
+                                     RemixStream * dest, RemixCount count,
+                                     RemixChunkChunkChunkFunc func, void * data)
+{
+  RemixCount n, minn = count;
+  RemixCount src1_offset = remix_tell (env, (RemixBase *)src1);
+  RemixCount src2_offset = remix_tell (env, (RemixBase *)src2);
+  RemixCount dest_offset = remix_tell (env, (RemixBase *)dest);
+  CDSet * s, * channels = remix_get_channels (env);
+  RemixChannel * s1ch, * s2ch, * dch;
+
+  if (dest == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  for (s = dest->channels; s; s = s->next) {
+    if (cd_set_contains (env, channels, s->key)) {
+      dch = (RemixChannel *)s->data.s_pointer;
+      s1ch = remix_stream_find_channel (env, src1, s->key);
+      s2ch = remix_stream_find_channel (env, src2, s->key);
+      if (s1ch != RemixNone && s2ch != RemixNone) {
+       n = remix_channel_chunkchunkchunkfuncify (env, s1ch, s2ch, dch,
+                                              count, func, s->key, data);
+       minn = MIN (n, minn);
+      }
+    }
+  }
+
+  remix_seek (env, (RemixBase *)src1, src1_offset + minn, SEEK_SET);
+  remix_seek (env, (RemixBase *)src2, src2_offset + minn, SEEK_SET);
+  remix_seek (env, (RemixBase *)dest, dest_offset + minn, SEEK_SET);
+
+  return minn;
+}
+
+/*
+ * remix_stream_gain (env, src, dest, count, gain)
+ */
+RemixCount
+remix_stream_gain (RemixEnv * env, RemixStream * stream, RemixCount count,
+                   RemixPCM gain)
+{
+  return remix_stream_chunkfuncify (env, stream, count,
+                                   _remix_chunk_gain, &gain);
+}
+
+/*
+ * remix_stream_copy (env, src, dest, count)
+ *
+ * Copy 'count' samples from 'src' to 'dest'
+ */
+RemixCount
+remix_stream_copy (RemixEnv * env, RemixStream * src, RemixStream * dest,
+                   RemixCount count)
+{
+  remix_dprintf ("[remix_stream_copy] (%p -> %p, +%ld)\n", src, dest, count);
+
+  return remix_stream_chunkchunkfuncify (env, src, dest, count,
+                                         _remix_chunk_copy, NULL);
+}
+
+/*
+ * remix_stream_write (env, stream, count, data)
+ *
+ * Write 'count' samples of 'data' to the stream 'stream'.
+ */
+/* XXX: this is a wrapper to obsolete remix_stream_write above */
+RemixCount
+remix_stream_write (RemixEnv * env, RemixStream * stream, RemixCount count,
+                    RemixStream * data)
+{
+  remix_dprintf ("[remix_stream_write] (%p -> %p, +%ld)\n", data, stream, count);
+
+  if (data == RemixNone)
+    return remix_stream_write0 (env, stream, count);
+
+  return remix_stream_copy (env, data, stream, count);
+}
+
+/*
+ * remix_stream_mix (src, dest, count)
+ *
+ * Mix 'count' samples from 'src' into 'dest'.
+ */
+RemixCount
+remix_stream_mix (RemixEnv * env, RemixStream * src, RemixStream * dest,
+                  RemixCount count)
+{
+  remix_dprintf ("[remix_stream_mix] (%p -> %p, +%ld)\n", src, dest, count);
+
+  return remix_stream_chunkchunkfuncify (env, src, dest, count,
+                                         _remix_chunk_add_inplace, NULL);
+}
+
+/*
+ * remix_stream_mult (src, dest, count)
+ *
+ * Multiply 'count' samples of 'src' into 'dest'.
+ */
+RemixCount
+remix_stream_mult (RemixEnv * env, RemixStream * src, RemixStream * dest,
+                   RemixCount count)
+{
+  remix_dprintf ("[remix_stream_mult] (%p -> %p, +%ld)\n", src, dest, count);
+
+  return remix_stream_chunkchunkfuncify (env, src, dest, count,
+                                     _remix_chunk_mult_inplace, NULL);
+}
+
+/*
+ * remix_stream_fade (src, dest, count)
+ *
+ * Fade 'count' samples of 'dest' by values in 'src'.
+ */
+RemixCount
+remix_stream_fade (RemixEnv * env, RemixStream * src, RemixStream * dest,
+                   RemixCount count)
+{
+  remix_dprintf ("[remix_stream_fade] (%p -> %p, +%ld)\n", src, dest, count);
+
+  return remix_stream_chunkchunkfuncify (env, src, dest, count,
+                                         _remix_chunk_fade_inplace, NULL);
+}
+
+/*
+ * remix_stream_blend (env, src, blend, dest, count)
+ *
+ * Blend 'count' samples of 'src' into 'dest' by amounts in 'blend'.
+ */
+RemixCount
+remix_stream_blend (RemixEnv * env, RemixStream * src, RemixStream * blend,
+                    RemixStream * dest, RemixCount count)
+{
+  remix_dprintf ("[remix_stream_blend] (%p -> (%p) -> %p, +%ld)\n", src, blend,
+             dest, count);
+
+  return remix_stream_chunkchunkchunkfuncify (env, src, blend, dest, count,
+                                              _remix_chunk_blend_inplace, NULL);
+}
+
+
+/*
+ * remix_streams_mix (streams, dest, count)
+ *
+ * Mix 'count' samples from all streams in list 'streams' together into
+ * 'dest'.
+ */
+RemixCount
+remix_streams_mix (RemixEnv * env, CDList * streams, RemixStream * dest,
+                   RemixCount count)
+{
+  CDList * sl;
+  CDSet * s;
+  RemixChannel * sch, * dch;
+  RemixStream * stream;
+  RemixCount dest_start = remix_tell (env, (RemixBase *)dest);
+  RemixCount stream_start;
+
+  if (dest == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  for (s = dest->channels; s; s = s->next) {
+    dch = (RemixChannel *)s->data.s_pointer;
+    for (sl = streams; sl; sl = sl->next) {
+      stream = (RemixStream *)sl->data.s_pointer;
+      stream_start = remix_tell (env, (RemixBase *)stream);
+      sch = remix_stream_find_channel (env, stream, s->key);
+      if (sch != RemixNone) {
+        _remix_channel_seek (env, dch, dest_start);
+        remix_channel_mix (env, sch, dch, count);
+        remix_seek (env, (RemixBase *)stream, stream_start, SEEK_SET);
+      }
+    }
+  }
+
+  for (sl = streams; sl; sl = sl->next) {
+    stream = (RemixStream *)sl->data.s_pointer;
+    stream_start = remix_tell (env, (RemixBase *)stream);
+    remix_seek (env, (RemixBase *)stream, stream_start + count, SEEK_SET);
+  }
+
+  remix_seek (env, (RemixBase *)dest, dest_start+count, SEEK_SET);
+
+  return count;
+}
+
+/*
+ * remix_stream_interleave_2 (env, stream, name1, name2, dest, count)
+ *
+ * Interleave 'count' frames of the channels named 'name1' and 'name2' in
+ * 'stream', placing the resulting PCM data in the memory region pointed
+ * to by 'dest'.
+ */
+RemixCount
+remix_stream_interleave_2 (RemixEnv * env, RemixStream * stream,
+                           int name1, int name2,
+                           RemixPCM * dest, RemixCount count)
+{
+  RemixChannel * channel1, * channel2;
+  RemixCount n = 0;
+
+  channel1 = remix_stream_find_channel (env, stream, name1);
+  channel2 = remix_stream_find_channel (env, stream, name2);
+
+  if (channel1 != RemixNone && channel2 != RemixNone) {
+    n = remix_channel_chunkchunkfuncify (env, channel1, channel2,
+                                       count, _remix_chunk_interleave_2,
+                                       0, dest);
+  }
+
+  if (n > 0) remix_seek (env, (RemixBase *)stream, n, SEEK_CUR);
+
+  return n;
+}
+
+/*
+ * remix_stream_deinterleave_stereo (env, stream, name1, name2, src, count)
+ *
+ * Deinterleave 'count' frames from the memory region pointed to by 'src',
+ * placing the resulting channels into those named 'name1' and 'name2' in
+ * 'stream'.
+ */
+RemixCount
+remix_stream_deinterleave_2 (RemixEnv * env, RemixStream * stream,
+                             int name1, int name2,
+                             RemixPCM * src, RemixCount count)
+{
+  RemixChannel * channel1, * channel2;
+  RemixCount n = 0;
+
+  channel1 = remix_stream_find_channel (env, stream, name1);
+  channel2 = remix_stream_find_channel (env, stream, name2);
+
+  if (channel1 != RemixNone && channel2 != RemixNone) {
+    n = remix_channel_chunkchunkfuncify (env, channel1, channel2,
+                                       count, _remix_chunk_deinterleave_2,
+                                       0, src);
+  }
+
+  if (n > 0) remix_seek (env, (RemixBase *)stream, n, SEEK_CUR);
+
+  return n;
+}
diff --git a/src/libremix/remix_time.c b/src/libremix/remix_time.c
new file mode 100644 (file)
index 0000000..f1232a6
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixTime: A generic time abstraction for sequencing information.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#define __REMIX__
+#include "remix.h"
+
+RemixTime
+remix_time_zero (RemixTimeType type)
+{
+  return _remix_time_zero (type);
+}
+
+RemixTime
+remix_time_invalid (RemixTimeType type)
+{
+  return _remix_time_invalid (type);
+}
+
+int
+remix_time_is_invalid (RemixTimeType type, RemixTime time)
+{
+  return _remix_time_is_invalid (type, time);
+}
+
+RemixTime
+remix_time_add (RemixTimeType type, RemixTime t1, RemixTime t2)
+{
+  return _remix_time_add (type, t1, t2);
+}
+
+RemixTime
+remix_time_sub (RemixTimeType type, RemixTime t1, RemixTime t2)
+{
+  return _remix_time_sub (type, t1, t2);
+}
+
+RemixTime
+remix_time_min (RemixTimeType type, RemixTime t1, RemixTime t2)
+{
+  return _remix_time_min (type, t1, t2);
+}
+
+RemixTime
+remix_time_max (RemixTimeType type, RemixTime t1, RemixTime t2)
+{
+  return _remix_time_max (type, t1, t2);
+}
+
+int
+remix_time_eq (RemixTimeType type, RemixTime t1, RemixTime t2)
+{
+  return _remix_time_eq (type, t1, t2);
+}
+
+int
+remix_time_gt (RemixTimeType type, RemixTime t1, RemixTime t2)
+{
+  return _remix_time_gt (type, t1, t2);
+}
+
+int
+remix_time_lt (RemixTimeType type, RemixTime t1, RemixTime t2)
+{
+  return _remix_time_lt (type, t1, t2);
+}
+
+int
+remix_time_ge (RemixTimeType type, RemixTime t1, RemixTime t2)
+{
+  return _remix_time_ge (type, t1, t2);
+}
+
+int
+remix_time_le (RemixTimeType type, RemixTime t1, RemixTime t2)
+{
+  return _remix_time_le (type, t1, t2);
+}
+
+
+static float
+remix_samples_to_seconds (RemixCount samples, RemixSamplerate samplerate)
+{
+  return ((float)samples / samplerate);
+}
+
+static int
+remix_samples_to_beat24s (RemixCount samples, RemixSamplerate samplerate,
+                      RemixTempo tempo)
+{
+  return ((int)((float)samples * tempo * 24.0 / (samplerate * 60.0)));
+}
+
+static RemixCount
+remix_seconds_to_samples (float seconds, RemixSamplerate samplerate)
+{
+  return (RemixCount)(seconds * samplerate);
+}
+
+static int
+remix_seconds_to_beat24s (float seconds, RemixTempo tempo)
+{
+  return (int)(seconds * tempo * 24.0 / 60.0);
+}
+
+static RemixCount
+remix_beat24s_to_samples (int beat24s, RemixSamplerate samplerate,
+                          RemixTempo tempo)
+{
+  return (RemixCount)(beat24s * samplerate * 60.0 / (tempo * 24.0));
+}
+
+static float
+remix_beat24s_to_seconds (int beat24s, RemixTempo tempo)
+{
+  return ((float)beat24s * 60.0 / (tempo * 24.0));
+}
+
+
+RemixTime
+remix_time_convert (RemixEnv * env, RemixTime time, RemixTimeType old_type,
+                    RemixTimeType new_type)
+{
+  RemixSamplerate samplerate;
+  RemixTempo tempo;
+
+  if (old_type == new_type) return time;
+
+  samplerate = remix_get_samplerate (env);
+  tempo = remix_get_tempo (env);
+
+  switch (old_type) {
+  case REMIX_TIME_SAMPLES:
+    switch (new_type) {
+    case REMIX_TIME_SECONDS:
+      return (RemixTime) remix_samples_to_seconds (time.samples, samplerate);
+      break;
+    case REMIX_TIME_BEAT24S:
+      return (RemixTime)
+        remix_samples_to_beat24s (time.samples, samplerate, tempo);
+      break;
+    default: break;
+    }
+    break;
+  case REMIX_TIME_SECONDS:
+    switch (new_type) {
+    case REMIX_TIME_SAMPLES:
+      return (RemixTime) remix_seconds_to_samples (time.seconds, samplerate);
+      break;
+    case REMIX_TIME_BEAT24S:
+      return (RemixTime) remix_seconds_to_beat24s (time.seconds, tempo);
+      break;
+    default: break;
+    }
+    break;
+  case REMIX_TIME_BEAT24S:
+    switch (new_type) {
+    case REMIX_TIME_SAMPLES:
+      return (RemixTime)
+        remix_beat24s_to_samples (time.beat24s, samplerate, tempo);
+      break;
+    case REMIX_TIME_SECONDS:
+      return (RemixTime) remix_beat24s_to_seconds (time.beat24s, tempo);
+      break;
+    default: break;
+    }
+    break;
+  default:
+    /* Cannot convert invalid time type to anything */
+    break;
+  }
+
+  return remix_time_invalid (new_type);
+}
diff --git a/src/libremix/remix_track.c b/src/libremix/remix_track.c
new file mode 100644 (file)
index 0000000..0cf2eb2
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixTrack: An RemixLayer mixing abstraction.
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ *
+ * Description
+ * -----------
+ *
+ * A track is contained within a deck. A track contains a number of
+ * layers which are mixed in series.
+ *
+ * Invariants
+ * ----------
+ *
+ * A track must be contained within a deck.
+ */
+
+#define __REMIX__
+#include "remix.h"
+
+/* Optimisation dependencies: optimise on change of nr. layers */
+static RemixTrack * remix_track_optimise (RemixEnv * env, RemixTrack * track);
+
+static void
+remix_track_replace_mixstreams (RemixEnv * env, RemixTrack * track)
+{
+  RemixCount mixlength = _remix_base_get_mixlength (env, track);
+
+  if (track->_mixstream_a != RemixNone)
+    remix_destroy (env, (RemixBase *)track->_mixstream_a);
+  if (track->_mixstream_b != RemixNone)
+    remix_destroy (env, (RemixBase *)track->_mixstream_b);
+
+  track->_mixstream_a = remix_stream_new_contiguous (env, mixlength);
+  track->_mixstream_b = remix_stream_new_contiguous (env, mixlength);
+}
+
+static RemixBase *
+remix_track_init (RemixEnv * env, RemixBase * base)
+{
+  RemixTrack * track = (RemixTrack *)base;
+  track->gain = 1.0;
+  track->layers = cd_list_new (env);
+  track->_mixstream_a = track->_mixstream_b = RemixNone;
+  remix_track_replace_mixstreams (env, track);
+  remix_track_optimise (env, track);
+  return (RemixBase *)track;
+}
+
+static RemixTrack *
+_remix_track_new (RemixEnv * env)
+{
+  return (RemixTrack *)
+    remix_base_new_subclass (env, sizeof (struct _RemixTrack));
+}
+
+RemixBase *
+remix_track_clone (RemixEnv * env, RemixBase * base)
+{
+  RemixTrack * track = (RemixTrack *)base;
+  RemixTrack * new_track = _remix_track_new (env);
+
+  new_track->gain = track->gain;
+  new_track->layers = cd_list_clone (env, track->layers,
+                                    (CDCloneFunc)remix_layer_clone);
+  remix_track_optimise (env, track);
+
+  return (RemixBase *)new_track;
+}
+
+static int
+remix_track_destroy (RemixEnv * env, RemixBase * base)
+{
+  RemixTrack * track = (RemixTrack *)base;
+  remix_destroy_list (env, track->layers);
+  remix_free (track);
+  return 0;
+}
+
+static int
+remix_track_ready (RemixEnv * env, RemixBase * base)
+{
+  return (remix_base_encompasses_mixlength (env, base) &&
+         remix_base_encompasses_channels (env, base));
+}
+
+static RemixBase *
+remix_track_prepare (RemixEnv * env, RemixBase * base)
+{
+  RemixTrack * track = (RemixTrack *)base;
+  remix_track_replace_mixstreams (env, track);
+  return base;
+}
+
+RemixTrack *
+remix_track_new (RemixEnv * env, RemixDeck * deck)
+{
+  RemixTrack * track;
+
+  track = _remix_track_new (env);
+  track->deck = deck;
+  remix_track_init (env, (RemixBase *)track);
+  _remix_deck_add_track (env, deck, track);
+
+  return track;
+}
+
+static RemixCount
+remix_track_length (RemixEnv * env, RemixBase * base)
+{
+  RemixTrack * track = (RemixTrack *)base;
+  RemixCount length, maxlength = 0;
+  CDList * l;
+  RemixLayer * layer;
+
+  for (l = track->layers; l; l = l->next) {
+    layer = (RemixLayer *)l->data.s_pointer;
+    length = remix_length (env, (RemixBase *)layer);
+    remix_dprintf ("[remix_track_length] found layer %p length %ld\n",
+               layer, length);
+    maxlength = MAX (maxlength, length);
+  }
+
+  return maxlength;
+}
+
+RemixPCM
+remix_track_set_gain (RemixEnv * env, RemixTrack * track, RemixPCM gain)
+{
+  RemixPCM old = track->gain;
+  track->gain = gain;
+  return old;
+}
+
+RemixPCM
+remix_track_get_gain (RemixEnv * env, RemixTrack * track)
+{
+  return track->gain;
+}
+
+void
+remix_remove_track (RemixEnv * env, RemixTrack * track)
+{
+  RemixDeck * deck = track->deck;
+
+  if (deck)
+    _remix_deck_remove_track (env, deck, track);
+}
+
+RemixDeck *
+remix_track_get_deck (RemixEnv * env, RemixTrack * track)
+{
+  return track->deck;
+}
+
+/*
+ * _remix_track_add_layer_above (env, track, layer, above)
+ *
+ * Adds 'layer' above 'above'. If above is RemixNone, adds 'layer' on top
+ * of 'track'.
+ */
+RemixLayer *
+_remix_track_add_layer_above (RemixEnv * env, RemixTrack * track,
+                              RemixLayer * layer, RemixLayer * above)
+{
+  layer->track = track;
+  if (above == RemixNone)
+    above = (RemixLayer *)
+      (cd_list_last (env, track->layers, CD_TYPE_POINTER)).s_pointer;
+  track->layers = cd_list_add_after (env, track->layers, CD_TYPE_POINTER,
+                                    CD_POINTER(layer), CD_POINTER(above));
+  remix_track_optimise (env, track);
+  return layer;
+}
+
+RemixLayer *
+_remix_track_remove_layer (RemixEnv * env, RemixTrack * track,
+                           RemixLayer * layer)
+{
+  track->layers = cd_list_remove (env, track->layers, CD_TYPE_POINTER,
+                                 CD_POINTER(layer));
+  remix_track_optimise (env, track);
+  return layer;
+}
+
+/*
+ * gets layer above 'above'. If above is RemixNone, returns topmost layer
+ */
+RemixLayer *
+_remix_track_get_layer_above (RemixEnv * env, RemixTrack * track,
+                              RemixLayer * above)
+{
+  CDList * above_item;
+  RemixLayer * layer;
+
+  if (track->layers == NULL) return RemixNone;
+
+  if (above == RemixNone) {
+    layer = (RemixLayer *)
+      (cd_list_last (env, track->layers, CD_TYPE_POINTER)).s_pointer;
+  } else {
+    above_item = cd_list_find (env, track->layers, CD_TYPE_POINTER,
+                              CD_POINTER(above));
+    if (above_item == NULL) return RemixNone;
+    above_item = above_item->next;
+    if (above_item == NULL) return RemixNone;
+    layer = (RemixLayer *) above_item->data.s_pointer;
+  }
+
+  return layer;
+}
+
+/*
+ * gets layer below 'below'. If below is RemixNone, returns lowest layer
+ */
+RemixLayer *
+_remix_track_get_layer_below (RemixEnv * env, RemixTrack * track,
+                              RemixLayer * below)
+{
+  CDList * below_item;
+  RemixLayer * layer;
+
+  if (track->layers == NULL) return RemixNone;
+
+  if (below == RemixNone) {
+    layer = (RemixLayer *) track->layers->data.s_pointer;
+  } else {
+    below_item = cd_list_find (env, track->layers, CD_TYPE_POINTER,
+                              CD_POINTER(below));
+    if (below_item == NULL) return RemixNone;
+    below_item = below_item->prev;
+    if (below_item == NULL) return RemixNone;
+    layer = (RemixLayer *) below_item->data.s_pointer;
+  }
+
+  return layer;
+}
+
+
+static RemixCount
+remix_track_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                     RemixStream * input, RemixStream * output)
+{
+  RemixTrack * track = (RemixTrack *)base;
+  CDList * l;
+  RemixBase * layer;
+  RemixStream * si, * so, * swap_stream;
+  RemixCount remaining = count, processed = 0, n = 0;
+  RemixCount mixlength = _remix_base_get_mixlength (env, track);
+
+  remix_dprintf ("PROCESS TRACK (%p, +%ld, %p -> %p) @ %ld\n",
+               track, count, input, output, remix_tell (env, base));
+
+  if (track->layers == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOOP);
+    return 0;
+  }
+
+  while (remaining > 0) {
+    l = track->layers;
+    si = input;
+    so = track->_mixstream_a;
+    n = MIN (remaining, mixlength);
+
+    while (l) {
+      layer = (RemixBase *)l->data.s_pointer;
+
+      if (si == input) {
+       swap_stream = track->_mixstream_b;
+      } else {
+       swap_stream = si;
+       remix_seek (env, (RemixBase *)si, 0, SEEK_SET);
+      }
+
+      if (l->next == RemixNone) {
+       so = output;
+      } else {
+       remix_seek (env, (RemixBase *)so, 0, SEEK_SET);
+      }
+
+      n = remix_process (env, layer, n, si, so);
+
+      l = l->next;
+
+      /* swap si, st using swap_stream as evaluated above */
+      si = so; so = swap_stream;
+    }
+    remaining -= n;
+    processed += n;
+  }
+
+  remix_dprintf ("[remix_track_process] processed %ld\n", processed);
+
+  return processed;
+}
+
+static RemixCount
+remix_track_twolayer_process (RemixEnv * env, RemixBase * base,
+                              RemixCount count, RemixStream * input,
+                              RemixStream * output)
+{
+  RemixTrack * track = (RemixTrack *)base;
+  CDList * l;
+  RemixBase * layer1, * layer2;
+  RemixCount remaining = count, processed = 0, n = 0;
+  RemixStream * mix = track->_mixstream_a;
+  RemixCount current_offset = remix_tell (env, base);
+  RemixCount mixlength = _remix_base_get_mixlength (env, track);
+
+  remix_dprintf ("PROCESS TRACK [twolayer] (%p, +%ld, %p -> %p) @ %ld\n",
+             track, count, input, output, current_offset);
+
+  l = track->layers;
+  layer1 = (RemixBase *)l->data.s_pointer;
+  remix_seek (env, (RemixBase *)layer1, current_offset, SEEK_SET);
+
+  l = l->next;
+  layer2 = (RemixBase *)l->data.s_pointer;
+  remix_seek (env, (RemixBase *)layer2, current_offset, SEEK_SET);
+
+  while (remaining > 0) {
+    n = MIN (remaining, mixlength);
+
+    remix_seek (env, (RemixBase *)mix, 0, SEEK_SET);
+    n = remix_process (env, layer1, n, input, mix);
+
+    remix_seek (env, (RemixBase *)mix, 0, SEEK_SET);
+    n = remix_process (env, layer2, n, mix, output);
+
+    remaining -= n;
+    processed += n;
+  }
+
+  remix_dprintf ("*** PRE-SEEK: track @ %ld\n", remix_tell (env, base));
+
+  /*remix_seek (env, base, current_offset + processed, SEEK_SET);*/
+
+  remix_dprintf ("*** POST-SEEK: track @ %ld\n", remix_tell (env, base));
+
+  remix_dprintf ("[remix_track_twolayer_process] processed %ld\n", processed);
+
+  return processed;
+}
+
+static RemixCount
+remix_track_onelayer_process (RemixEnv * env, RemixBase * base,
+                              RemixCount count, RemixStream * input,
+                              RemixStream * output)
+{
+  RemixTrack * track = (RemixTrack *)base;
+  CDList * l = track->layers;
+  RemixBase * layer = (RemixBase *)l->data.s_pointer;
+  RemixCount n;
+
+  remix_dprintf ("PROCESS TRACK [onelayer] (%p, +%ld, %p -> %p) @ %ld\n",
+             track, count, input, output, remix_tell (env, base));
+
+  n = remix_process (env, layer, count, input, output);
+
+  remix_dprintf ("[remix_track_onelayer_process] processed %ld\n", n);
+
+  return n;
+}
+
+static RemixCount
+remix_track_seek (RemixEnv * env, RemixBase * base, RemixCount offset)
+{
+  RemixTrack * track = (RemixTrack *)base;
+  CDList * l;
+  RemixLayer * layer;
+
+  for (l = track->layers; l; l = l->next) {
+    layer = (RemixLayer *)l->data.s_pointer;
+    remix_seek (env, (RemixBase *)layer, offset, SEEK_SET);
+  }
+
+  return offset;
+}
+
+static int
+remix_track_flush (RemixEnv * env, RemixBase * base)
+{
+  RemixTrack * track = (RemixTrack *)base;
+  CDList * l;
+  RemixLayer * layer;
+
+  for (l = track->layers; l; l = l->next) {
+    layer = (RemixLayer *)l->data.s_pointer;
+    remix_flush (env, (RemixBase *)layer);
+  }
+
+  return 0;
+}
+
+static struct _RemixMethods _remix_track_empty_methods = {
+  remix_track_clone,   /* clone */
+  remix_track_destroy, /* destroy */
+  remix_track_ready,   /* ready */
+  remix_track_prepare, /* prepare */
+  remix_null_process,  /* process */
+  remix_null_length,   /* length */
+  remix_null_seek,     /* seek */
+  NULL,             /* flush */
+};
+
+static struct _RemixMethods _remix_track_methods = {
+  remix_track_clone,   /* clone */
+  remix_track_destroy, /* destroy */
+  remix_track_ready,   /* ready */
+  remix_track_prepare, /* prepare */
+  remix_track_process, /* process */
+  remix_track_length,  /* length */
+  remix_track_seek,    /* seek */
+  remix_track_flush,            /* flush */
+};
+
+static struct _RemixMethods _remix_track_onelayer_methods = {
+  remix_track_clone,            /* clone */
+  remix_track_destroy,          /* destroy */
+  remix_track_ready,            /* ready */
+  remix_track_prepare,          /* prepare */
+  remix_track_onelayer_process, /* process */
+  remix_track_length,           /* length */
+  remix_track_seek,             /* seek */
+  remix_track_flush,            /* flush */
+};
+
+static struct _RemixMethods _remix_track_twolayer_methods = {
+  remix_track_clone,            /* clone */
+  remix_track_destroy,          /* destroy */
+  remix_track_ready,            /* ready */
+  remix_track_prepare,          /* prepare */
+  remix_track_twolayer_process, /* process */
+  remix_track_length,           /* length */
+  remix_track_seek,             /* seek */
+  remix_track_flush,            /* flush */
+};
+
+static RemixTrack *
+remix_track_optimise (RemixEnv * env, RemixTrack * track)
+{
+  RemixCount nr_layers = cd_list_length (env, track->layers);
+
+  switch (nr_layers) {
+  case 0:
+    _remix_set_methods (env, track, &_remix_track_empty_methods); break;
+  case 1:
+    _remix_set_methods (env, track, &_remix_track_onelayer_methods); break;
+  case 2:
+    _remix_set_methods (env, track, &_remix_track_twolayer_methods); break;
+  default:
+      _remix_set_methods (env, track, &_remix_track_methods); break;
+  }
+
+  return track;
+}
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
new file mode 100644 (file)
index 0000000..56e8c00
--- /dev/null
@@ -0,0 +1,3 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = ladspa noise
diff --git a/src/plugins/ladspa/Makefile.am b/src/plugins/ladspa/Makefile.am
new file mode 100644 (file)
index 0000000..9e79121
--- /dev/null
@@ -0,0 +1,18 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = -I$(top_srcdir)/include -I$(CTXDATADIR)
+
+libdir = $(PACKAGE_PLUGIN_DIR)
+
+CTXDATADIR = $(top_srcdir)/src/ctxdata
+CTXDATA_LIBS = $(top_builddir)/src/ctxdata/libctxdata.la
+
+REMIXDIR = ../../libremix
+REMIX_LIBS = $(REMIXDIR)/libremix.la
+
+lib_LTLIBRARIES = \
+       libremix_ladspa.la
+
+libremix_ladspa_la_SOURCES = remix_ladspa.c ladspa.h
+libremix_ladspa_la_LDFLAGS = -module -version-info 1:0:0
+libremix_ladspa_la_LIBADD = $(REMIX_LIBS) $(CTXDATA_LIBS)
diff --git a/src/plugins/ladspa/ladspa.h b/src/plugins/ladspa/ladspa.h
new file mode 100644 (file)
index 0000000..5ed8d08
--- /dev/null
@@ -0,0 +1,497 @@
+/* ladspa.h
+
+   Version 1. Copyright 2000 Richard W.E. Furse, Paul Barton-Davis,
+   Stefan Westerfeld. */
+
+#ifndef LADSPA_INCLUDED
+#define LADSPA_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+/* Overview: 
+
+   There is a large number of synthesis packages in use or development
+   on the Linux platform at this time. This API (`The Linux Audio
+   Developer's Simple Plugin API') attempts to give programmers the
+   ability to write simple `plugin' audio processors in C/C++ and link
+   them dynamically (`plug') into a range of these packages (`hosts').
+   It should be possible for any host and any plugin to communicate
+   completely through this interface. The LADSPA plugin API is free to
+   use.
+
+   This API is deliberately short and simple. To achieve compatibility
+   with a range of promising Linux sound synthesis packages it
+   attempts to find the `greatest common divisor' in their logical
+   behaviour. Having said this, certain limiting decisions are
+   implicit, notably the use of a fixed type (LADSPA_Data) for all
+   data transfer and absence of a parameterised `initialisation'
+   phase. See below for the LADSPA_Data typedef.
+
+   Plugins are expected to distinguish between control and audio
+   data. Plugins have `ports' that are inputs or outputs for audio or
+   control data and each plugin is `run' for a `block' corresponding
+   to a short time interval measured in samples. Audio data is
+   communicated using arrays of LADSPA_Data, allowing a block of audio
+   to be processed by the plugin in a single pass. Control data is
+   communicated using single LADSPA_Data values. Control data has a
+   single value at the start of a call to the `run()' or `run_adding()'
+   function, and may be considered to remain this value for its
+   duration. The plugin may assume that all its input and output ports
+   have been connected to the relevant data location (see the
+   `connect_port()' function below) before it is asked to run.
+
+   Plugins will reside in shared object files suitable for dynamic
+   linking by dlopen() and family. The file will provide a number of
+   `plugin types' that can be used to instantiate actual plugins
+   (sometimes known as `plugin instances') that can be connected
+   together to perform tasks.
+
+   This API contains very limited error-handling. */
+
+/*****************************************************************************/
+
+/* Fundamental data type passed in and out of plugin. This data type
+   is used to communicate audio samples and control values. It is
+   assumed that the plugin will work sensibly given any numeric input
+   value although it may have a preferred range (see hints below). */
+
+typedef float LADSPA_Data;
+
+/*****************************************************************************/
+
+/* Special Plugin Properties: 
+   Optional features of the plugin type are encapsulated in the
+   LADSPA_Properties type. This is assembled by ORing individual
+   properties together. */
+
+typedef int LADSPA_Properties;
+
+/* Property LADSPA_PROPERTY_REALTIME indicates that the plugin has a
+   real-time dependency (e.g. listens to a MIDI device) and so its
+   output must not be cached or subject to significant latency. */
+#define LADSPA_PROPERTY_REALTIME        0x1
+
+/* Property LADSPA_PROPERTY_INPLACE_BROKEN indicates that the plugin
+   may cease to work correctly if the host elects to use the same data
+   location for both input and output (see connect_port()). This
+   should be avoided as enabling this flag makes it impossible for
+   hosts to use the plugin to process audio `in-place.' */
+#define LADSPA_PROPERTY_INPLACE_BROKEN  0x2
+
+/* Property LADSPA_PROPERTY_HARD_RT_CAPABLE indicates that the plugin
+   is capable of running not only in a conventional host but also in a
+   `hard real-time' environment. To qualify for this the plugin must
+   satisfy all of the following:
+
+   (1) The plugin must not use malloc(), free() or other heap memory
+   management within its run() or run_adding() functions. All new
+   memory used in run() must be managed via the stack. These
+   restrictions only apply to the run() function.
+
+   (2) The plugin will not attempt to make use of any library
+   functions with the exceptions of functions in the ANSI standard C
+   and C maths libraries, which the host is expected to provide.
+
+   (3) The plugin will not access files, devices, pipes, sockets, IPC
+   or any other mechanism that might result in process or thread
+   blocking.
+      
+   (4) The plugin will take an amount of time to execute a run() or
+   run_adding() call approximately of form (A+B*SampleCount) where A
+   and B depend on the machine and host in use. This amount of time
+   may not depend on input signals or plugin state. The host is left
+   the responsibility to perform timings to estimate upper bounds for
+   A and B. */
+#define LADSPA_PROPERTY_HARD_RT_CAPABLE 0x4
+
+#define LADSPA_IS_REALTIME(x)        ((x) & LADSPA_PROPERTY_REALTIME)
+#define LADSPA_IS_INPLACE_BROKEN(x)  ((x) & LADSPA_PROPERTY_INPLACE_BROKEN)
+#define LADSPA_IS_HARD_RT_CAPABLE(x) ((x) & LADSPA_PROPERTY_HARD_RT_CAPABLE)
+
+/*****************************************************************************/
+
+/* Plugin Ports: 
+
+   Plugins have `ports' that are inputs or outputs for audio or
+   data. Ports can communicate arrays of LADSPA_Data (for audio
+   inputs/outputs) or single LADSPA_Data values (for control
+   input/outputs). This information is encapsulated in the
+   LADSPA_PortDescriptor type which is assembled by ORing individual
+   properties together.
+
+   Note that a port must be an input or an output port but not both
+   and that a port must be a control or audio port but not both. */
+
+typedef int LADSPA_PortDescriptor;
+
+/* Property LADSPA_PORT_INPUT indicates that the port is an input. */
+#define LADSPA_PORT_INPUT   0x1
+
+/* Property LADSPA_PORT_OUTPUT indicates that the port is an output. */
+#define LADSPA_PORT_OUTPUT  0x2
+
+/* Property LADSPA_PORT_CONTROL indicates that the port is a control
+   port. */
+#define LADSPA_PORT_CONTROL 0x4
+
+/* Property LADSPA_PORT_AUDIO indicates that the port is a audio
+   port. */
+#define LADSPA_PORT_AUDIO   0x8
+
+#define LADSPA_IS_PORT_INPUT(x)   ((x) & LADSPA_PORT_INPUT)
+#define LADSPA_IS_PORT_OUTPUT(x)  ((x) & LADSPA_PORT_OUTPUT)
+#define LADSPA_IS_PORT_CONTROL(x) ((x) & LADSPA_PORT_CONTROL)
+#define LADSPA_IS_PORT_AUDIO(x)   ((x) & LADSPA_PORT_AUDIO)
+
+/*****************************************************************************/
+
+/* Plugin Port Range Hints: 
+
+   The host may wish to provide a representation of data entering or
+   leaving a plugin (e.g. to generate a GUI automatically). To make
+   this more meaningful, the plugin should provide `hints' to the host
+   describing the usual values taken by the data.
+   
+   Note that these are only hints. The host may ignore them and the
+   plugin must not assume that data supplied to it is meaningful. If
+   the plugin receives invalid input data it is expected to continue
+   to run without failure and, where possible, produce a sensible
+   output (e.g. a high-pass filter given a negative cutoff frequency
+   might switch to an all-pass mode).
+    
+   Hints are meaningful for all input and output ports but hints for
+   input control ports are expected to be particularly useful.
+   
+   More hint information is encapsulated in the
+   LADSPA_PortRangeHintDescriptor type which is assembled by ORing
+   individual hint types together. Hints may require further
+   LowerBound and UpperBound information.
+
+   All the hint information for a particular port is aggregated in the
+   LADSPA_PortRangeHint structure. */
+
+typedef int LADSPA_PortRangeHintDescriptor;
+
+/* Hint LADSPA_HINT_BOUNDED_BELOW indicates that the LowerBound field
+   of the LADSPA_PortRangeHint should be considered meaningful. The
+   value in this field should be considered the (inclusive) lower
+   bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also
+   specified then the value of LowerBound should be multiplied by the
+   sample rate. */
+#define LADSPA_HINT_BOUNDED_BELOW 0x1
+
+/* Hint LADSPA_HINT_BOUNDED_ABOVE indicates that the UpperBound field
+   of the LADSPA_PortRangeHint should be considered meaningful. The
+   value in this field should be considered the (inclusive) upper
+   bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also
+   specified then the value of UpperBound should be multiplied by the
+   sample rate. */
+#define LADSPA_HINT_BOUNDED_ABOVE 0x2
+
+/* Hint LADSPA_HINT_TOGGLED indicates that the data item should be
+   considered a Boolean toggle. Data less than or equal to zero should
+   be considered `off' or `false,' and data above zero should be
+   considered `on' or `true.' LADSPA_HINT_TOGGLED may not be used in
+   conjunction with any other hint. */
+#define LADSPA_HINT_TOGGLED       0x4
+
+/* Hint LADSPA_HINT_SAMPLE_RATE indicates that any bounds specified
+   should be interpreted as multiples of the sample rate. For
+   instance, a frequency range from 0Hz to the Nyquist frequency (half
+   the sample rate) could be requested by this hint in conjunction
+   with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds
+   at all must support this hint to retain meaning. */
+#define LADSPA_HINT_SAMPLE_RATE   0x8
+
+/* Hint LADSPA_HINT_LOGARITHMIC indicates that it is likely that the
+   user will find it more intuitive to view values using a logarithmic
+   scale. This is particularly useful for frequencies and gains. */
+#define LADSPA_HINT_LOGARITHMIC   0x10
+
+/* Hint LADSPA_HINT_INTEGER indicates that a user interface would
+   probably wish to provide a stepped control taking only integer
+   values. Any bounds set should be slightly wider than the actual
+   integer range required to avoid floating point rounding errors. For
+   instance, the integer set {0,1,2,3} might be described as [-0.1,
+   3.1]. */
+#define LADSPA_HINT_INTEGER       0x20
+
+#define LADSPA_IS_HINT_BOUNDED_BELOW(x) ((x) & LADSPA_HINT_BOUNDED_BELOW)
+#define LADSPA_IS_HINT_BOUNDED_ABOVE(x) ((x) & LADSPA_HINT_BOUNDED_ABOVE)
+#define LADSPA_IS_HINT_TOGGLED(x)       ((x) & LADSPA_HINT_TOGGLED)
+#define LADSPA_IS_HINT_SAMPLE_RATE(x)   ((x) & LADSPA_HINT_SAMPLE_RATE)
+#define LADSPA_IS_HINT_LOGARITHMIC(x)   ((x) & LADSPA_HINT_LOGARITHMIC)
+#define LADSPA_IS_HINT_INTEGER(x)       ((x) & LADSPA_HINT_INTEGER)
+
+typedef struct _LADSPA_PortRangeHint {
+
+  /* Hints about the port. */
+  LADSPA_PortRangeHintDescriptor HintDescriptor;
+
+  /* Meaningful when hint LADSPA_HINT_BOUNDED_BELOW is active. When
+     LADSPA_HINT_SAMPLE_RATE is also active then this value should be
+     multiplied by the relevant sample rate. */
+  LADSPA_Data LowerBound;
+
+  /* Meaningful when hint LADSPA_HINT_BOUNDED_ABOVE is active. When
+     LADSPA_HINT_SAMPLE_RATE is also active then this value should be
+     multiplied by the relevant sample rate. */
+  LADSPA_Data UpperBound;
+
+} LADSPA_PortRangeHint;
+
+/*****************************************************************************/
+
+/* Plugin Handles: 
+
+   This plugin handle indicates a particular instance of the plugin
+   concerned. It is valid to compare this to NULL (0 for C++) but
+   otherwise the host should not attempt to interpret it. The plugin
+   may use it to reference internal instance data. */
+
+typedef void * LADSPA_Handle;
+
+/*****************************************************************************/
+
+/* Descriptor for a Type of Plugin: 
+
+   This structure is used to describe a plugin type. It provides a
+   number of functions to examine the type, instantiate it, link it to
+   buffers and workspaces and to run it. */
+
+typedef struct _LADSPA_Descriptor { 
+
+  /* This numeric identifier indicates the plugin type
+     uniquely. Plugin programmers may reserve ranges of IDs from a
+     central body to avoid clashes. Hosts may assume that IDs are
+     below 0x1000000. */
+  unsigned long UniqueID;
+
+  /* This identifier can be used as a unique, case-sensitive
+     identifier for the plugin type within the plugin file. Plugin
+     types should be identified by file and label rather than by index
+     or plugin name, which may be changed in new plugin
+     versions. Labels must not contain white-space characters. */
+  const char * Label;
+
+  /* This indicates a number of properties of the plugin. */
+  LADSPA_Properties Properties;
+
+  /* This member points to the null-terminated name of the plugin
+     (e.g. "Sine Oscillator"). */
+  const char * Name;
+
+  /* This member points to the null-terminated string indicating the
+     maker of the plugin. This can be an empty string but not NULL. */
+  const char * Maker;
+
+  /* This member points to the null-terminated string indicating any
+     copyright applying to the plugin. If no Copyright applies the
+     string "None" should be used. */
+  const char * Copyright;
+
+  /* This indicates the number of ports (input AND output) present on
+     the plugin. */
+  unsigned long PortCount;
+
+  /* This member indicates an array of port descriptors. Valid indices
+     vary from 0 to PortCount-1. */
+  const LADSPA_PortDescriptor * PortDescriptors;
+
+  /* This member indicates an array of null-terminated strings
+     describing ports (e.g. "Frequency (Hz)"). Valid indices vary from
+     0 to PortCount-1. */
+  const char * const * PortNames;
+
+  /* This member indicates an array of range hints for each port (see
+     above). Valid indices vary from 0 to PortCount-1. */
+  const LADSPA_PortRangeHint * PortRangeHints;
+
+  /* This may be used by the plugin developer to pass any custom
+     implementation data into an instantiate call. It must not be used
+     or interpreted by the host. It is expected that most plugin
+     writers will not use this facility as LADSPA_Handle should be
+     used to hold instance data. */
+  void * ImplementationData;
+
+  /* This member is a function pointer that instantiates a plugin. A
+     handle is returned indicating the new plugin instance. The
+     instantiation function accepts a sample rate as a parameter. The
+     plugin descriptor from which this instantiate function was found
+     must also be passed. This function must return NULL if
+     instantiation fails. 
+
+     Note that instance initialisation should generally occur in
+     activate() rather than here. */
+  LADSPA_Handle (*instantiate)(const struct _LADSPA_Descriptor * Descriptor,
+                               unsigned long                     SampleRate);
+
+  /* This member is a function pointer that connects a port on an
+     instantiated plugin to a memory location at which a block of data
+     for the port will be read/written. The data location is expected
+     to be an array of LADSPA_Data for audio ports or a single
+     LADSPA_Data value for control ports. Memory issues will be
+     managed by the host. The plugin must read/write the data at these
+     locations every time run() or run_adding() is called and the data
+     present at the time of this connection call should not be
+     considered meaningful.
+
+     connect_port() may be called more than once for a plugin instance
+     to allow the host to change the buffers that the plugin is
+     reading or writing. These calls may be made before or after
+     activate() or deactivate() calls.
+
+     connect_port() must be called at least once for each port before
+     run() or run_adding() is called. When working with blocks of
+     LADSPA_Data the plugin should pay careful attention to the block
+     size passed to the run function as the block allocated may only
+     just be large enough to contain the block of samples.
+
+     Plugin writers should be aware that the host may elect to use the
+     same buffer for more than one port and even use the same buffer
+     for both input and output (see LADSPA_PROPERTY_INPLACE_BROKEN).
+     However, overlapped buffers or use of a single buffer for both
+     audio and control data may result in unexpected behaviour. */
+   void (*connect_port)(LADSPA_Handle Instance,
+                        unsigned long Port,
+                        LADSPA_Data * DataLocation);
+
+  /* This member is a function pointer that initialises a plugin
+     instance and activates it for use. This is separated from
+     instantiate() to aid real-time support and so that hosts can
+     reinitialise a plugin instance by calling deactivate() and then
+     activate(). In this case the plugin instance must reset all state
+     information dependent on the history of the plugin instance
+     except for any data locations provided by connect_port() and any
+     gain set by set_run_adding_gain(). If there is nothing for
+     activate() to do then the plugin writer may provide a NULL rather
+     than an empty function.
+
+     When present, hosts must call this function once before run() (or
+     run_adding()) is called for the first time. This call should be
+     made as close to the run() call as possible and indicates to
+     real-time plugins that they are now live. Plugins should not rely
+     on a prompt call to run() after activate(). activate() may not be
+     called again unless deactivate() is called first. Note that
+     connect_port() may be called before or after a call to
+     activate(). */
+  void (*activate)(LADSPA_Handle Instance);
+
+  /* This method is a function pointer that runs an instance of a
+     plugin for a block. Two parameters are required: the first is a
+     handle to the particular instance to be run and the second
+     indicates the block size (in samples) for which the plugin
+     instance may run.
+
+     Note that if an activate() function exists then it must be called
+     before run() or run_adding(). If deactivate() is called for a
+     plugin instance then the plugin instance may not be reused until
+     activate() has been called again.
+
+     If the plugin has the property LADSPA_PROPERTY_HARD_RT_CAPABLE
+     then there are various things that the plugin should not do
+     within the run() or run_adding() functions (see above). */
+  void (*run)(LADSPA_Handle Instance,
+              unsigned long SampleCount);
+
+  /* This method is a function pointer that runs an instance of a
+     plugin for a block. This has identical behaviour to run() except
+     in the way data is output from the plugin. When run() is used,
+     values are written directly to the memory areas associated with
+     the output ports. However when run_adding() is called, values
+     must be added to the values already present in the memory
+     areas. Furthermore, output values written must be scaled by the
+     current gain set by set_run_adding_gain() (see below) before
+     addition.
+
+     run_adding() is optional. When it is not provided by a plugin,
+     this function pointer must be set to NULL. When it is provided,
+     the function set_run_adding_gain() must be provided also. */
+  void (*run_adding)(LADSPA_Handle Instance,
+                    unsigned long SampleCount);
+
+  /* This method is a function pointer that sets the output gain for
+     use when run_adding() is called (see above). If this function is
+     never called the gain is assumed to default to 1. Gain
+     information should be retained when activate() or deactivate()
+     are called.
+
+     This function should be provided by the plugin if and only if the
+     run_adding() function is provided. When it is absent this
+     function pointer must be set to NULL. */
+  void (*set_run_adding_gain)(LADSPA_Handle Instance,
+                             LADSPA_Data   Gain);
+
+  /* This is the counterpart to activate() (see above). If there is
+     nothing for deactivate() to do then the plugin writer may provide
+     a NULL rather than an empty function.
+
+     Hosts must deactivate all activated units after they have been
+     run() (or run_adding()) for the last time. This call should be
+     made as close to the last run() call as possible and indicates to
+     real-time plugins that they are no longer live. Plugins should
+     not rely on prompt deactivation. Note that connect_port() may be
+     called before or after a call to deactivate().
+
+     Deactivation is not similar to pausing as the plugin instance
+     will be reinitialised when activate() is called to reuse it. */
+  void (*deactivate)(LADSPA_Handle Instance);
+
+  /* Once an instance of a plugin has been finished with it can be
+     deleted using the following function. The instance handle passed
+     ceases to be valid after this call.
+  
+     If activate() was called for a plugin instance then a
+     corresponding call to deactivate() must be made before cleanup()
+     is called. */
+  void (*cleanup)(LADSPA_Handle Instance);
+
+} LADSPA_Descriptor;
+
+/**********************************************************************/
+
+/* Accessing a Plugin: */
+
+/* The exact mechanism by which plugins are loaded is host-dependent,
+   however all most hosts will need to know is the name of shared
+   object file containing the plugin types. To allow multiple hosts to
+   share plugin types, hosts may wish to check for environment
+   variable LADSPA_PATH. If present, this should contain a
+   colon-separated path indicating directories that should be searched
+   (in order) when loading plugin types.
+
+   A plugin programmer must include a function called
+   "ladspa_descriptor" with the following function prototype within
+   the shared object file. This function will have C-style linkage (if
+   you are using C++ this is taken care of by the `extern "C"' clause
+   at the top of the file).
+
+   A host will find the plugin shared object file by one means or
+   another, find the ladspa_descriptor() function, call it, and
+   proceed from there.
+
+   Plugin types are accessed by index (not ID) using values from 0
+   upwards. Out of range indexes must result in this function
+   returning NULL, so the plugin count can be determined by checking
+   for the least index that results in NULL being returned. */
+
+const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index);
+
+/* Datatype corresponding to the ladspa_descriptor() function. */
+typedef const LADSPA_Descriptor * 
+(*LADSPA_Descriptor_Function)(unsigned long Index);
+
+/**********************************************************************/
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* LADSPA_INCLUDED */
+
+/* EOF */
diff --git a/src/plugins/ladspa/remix_ladspa.c b/src/plugins/ladspa/remix_ladspa.c
new file mode 100644 (file)
index 0000000..cdb6984
--- /dev/null
@@ -0,0 +1,1045 @@
+/*
+ * LADSPA wrapper plugin for libremix
+ *
+ * Copyright (C) 2000 Conrad Parker
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * This file assumes that both LADSPA and libremix are built with
+ * an audio datatype of 'float'.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <math.h> /* for ceil() */
+
+#include <dlfcn.h>
+#include <sys/stat.h>
+
+#define __REMIX_PLUGIN__
+#include <remix/remix.h>
+
+#include "ladspa.h"
+
+#define PATH_LEN 1024
+
+/* Compile in support for inplace processing? */
+#define _PROCESS_INPLACE
+
+#ifdef _PROCESS_INPLACE
+#define LADSPA_WRAPPER_IS_INPLACE_BROKEN(x) LADSPA_IS_INPLACE_BROKEN(x)
+#else
+#define LADSPA_WRAPPER_IS_INPLACE_BROKEN(x) (1L)
+#endif
+
+#define LADSPA_IS_CONTROL_INPUT(x) (LADSPA_IS_PORT_INPUT(x) && LADSPA_IS_PORT_CONTROL(x))
+#define LADSPA_IS_AUDIO_INPUT(x) (LADSPA_IS_PORT_INPUT(x) && LADSPA_IS_PORT_AUDIO(x))
+#define LADSPA_IS_CONTROL_OUTPUT(x) (LADSPA_IS_PORT_OUTPUT(x) && LADSPA_IS_PORT_CONTROL(x))
+#define LADSPA_IS_AUDIO_OUTPUT(x) (LADSPA_IS_PORT_OUTPUT(x) && LADSPA_IS_PORT_AUDIO(x))
+
+#define LADSPA_frames_to_bytes(f) (f * sizeof(LADSPA_Data))
+
+static char * default_ladspa_path = "/usr/lib/ladspa:/usr/local/lib/ladspa:/opt/ladspa/lib";
+
+#ifndef WIN32
+#  define remix_stat_regular(mode) (S_ISREG((mode)) || S_ISLNK((mode)))
+#else
+#  define remix_stat_regular(mode) ((mode) & S_IFREG)
+#endif
+
+/* Dummy control output, used to connect all LADSPA control outputs to */
+static LADSPA_Data dummy_control_output;
+
+static CDList * modules_list = CD_EMPTY_LIST;
+static int ladspa_wrapper_initialised = FALSE;
+
+
+typedef struct _RemixLADSPA RemixLADSPA;
+
+struct _RemixLADSPA {
+  unsigned long samplerate; /* samplerate initialised at */
+  LADSPA_Descriptor * d;
+  LADSPA_Handle * handle;
+  LADSPA_Data * control_inputs;
+};
+
+static RemixBase * remix_ladspa_optimise (RemixEnv * env, RemixBase * base);
+
+/*
+ * is_usable (d)
+ *
+ * Determine if a LADSPA_Descriptor * d is usable by this remix ladspa
+ * wrapper plugin. Currently this means that there is not more than 1
+ * audio input or more than 1 audio output.
+ */
+static int
+is_usable(const LADSPA_Descriptor * d)
+{
+  LADSPA_PortDescriptor pd;
+  int i;
+  int
+    nr_ai=0, /* audio inputs */
+    nr_ao=0; /* audio outputs */
+
+  for (i=0; i < d->PortCount; i++) {
+    pd = d->PortDescriptors[i];
+    if (LADSPA_IS_AUDIO_INPUT(pd))
+      nr_ai++;
+    if (LADSPA_IS_AUDIO_OUTPUT(pd))
+      nr_ao++;
+  }
+
+  /* Sanity checks */
+  if (! d->run) return FALSE; /* plugin does nothing! */
+  if (! d->instantiate) return FALSE; /* plugin cannot be instantiated */
+  if (! d->connect_port) return FALSE; /* plugin cannot be wired up */
+
+  if (nr_ao == 1 && nr_ai == 1) return TRUE;
+  if (nr_ao == 0 && nr_ai == 1) return TRUE;
+  if (nr_ao == 1 && nr_ai == 0) return TRUE;
+
+  return FALSE;
+}
+
+static RemixParameterType
+convert_type (const LADSPA_PortRangeHintDescriptor prhd)
+{
+  if (LADSPA_IS_HINT_TOGGLED(prhd))
+    return REMIX_TYPE_BOOL;
+  else if (LADSPA_IS_HINT_INTEGER(prhd))
+    return REMIX_TYPE_INT;
+  else
+    return REMIX_TYPE_FLOAT;
+}
+
+static RemixFlags
+get_valid_mask (const LADSPA_PortRangeHintDescriptor prhd)
+{
+  RemixFlags ret = 0;
+
+  if (LADSPA_IS_HINT_BOUNDED_BELOW(prhd))
+    ret &= REMIX_RANGE_LOWER_BOUND_VALID;
+  if (LADSPA_IS_HINT_BOUNDED_ABOVE(prhd))
+    ret &= REMIX_RANGE_UPPER_BOUND_VALID;
+
+  return ret;
+}
+
+static RemixParameterRange *
+convert_constraint (const LADSPA_PortRangeHint * prh)
+{
+  RemixParameterRange * pr;
+  LADSPA_PortRangeHintDescriptor prhd = prh->HintDescriptor;
+
+  if (LADSPA_IS_HINT_TOGGLED(prhd))
+    return NULL;
+
+  pr = malloc (sizeof (*pr));
+
+  pr->valid_mask = get_valid_mask (prhd);
+
+  if (LADSPA_IS_HINT_INTEGER(prhd)) {
+    if (LADSPA_IS_HINT_BOUNDED_BELOW(prhd))
+      pr->lower.s_int = (int)prh->LowerBound;
+    if (LADSPA_IS_HINT_BOUNDED_ABOVE(prhd))
+      pr->upper.s_int = (int)prh->UpperBound;
+  } else {
+    if (LADSPA_IS_HINT_BOUNDED_BELOW(prhd))
+      pr->lower.s_float = (float)prh->LowerBound;
+    if (LADSPA_IS_HINT_BOUNDED_ABOVE(prhd))
+      pr->upper.s_float = (float)prh->UpperBound;
+  }
+
+  return pr;
+}
+
+static RemixBase *
+remix_ladspa_replace_handle (RemixEnv * env, RemixBase * base)
+{
+  RemixPlugin * plugin = remix_base_get_plugin (env, base);
+  RemixLADSPA * al = (RemixLADSPA *) remix_base_get_instance_data (env, base);
+  LADSPA_Descriptor * d;
+
+  if (al == NULL) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  if (al->d != NULL)
+    if (al->d->deactivate) al->d->deactivate (al->handle);
+
+  al->samplerate = (unsigned long) remix_get_samplerate (env);
+
+  al->d = d = (LADSPA_Descriptor *) plugin->plugin_data;
+
+  if (d != NULL) {
+    al->handle = d->instantiate (d, al->samplerate);
+    if (d->activate) d->activate (al->handle);
+  }
+
+  return base;
+}
+
+static RemixBase *
+remix_ladspa_init (RemixEnv * env, RemixBase * base, CDSet * parameters)
+{
+  RemixLADSPA * al = malloc (sizeof (*al));
+
+  remix_base_set_instance_data (env, base, al);
+  al->d = NULL; /* let this get set in replace_handle() */
+
+  remix_ladspa_replace_handle (env, base);
+  remix_ladspa_optimise (env, base);
+  return base;
+}
+
+static RemixBase *
+remix_ladspa_clone (RemixEnv * env, RemixBase * base)
+{
+  /* XXX: Most of this should really be handled in remix_base.c */
+  RemixPlugin * plugin = remix_base_get_plugin (env, base);
+  RemixBase * new_base = remix_base_new (env);
+  remix_base_set_plugin (env, new_base, plugin);
+  remix_ladspa_init (env, new_base, CD_EMPTY_SET);
+  return new_base;
+}
+
+static int
+remix_ladspa_destroy (RemixEnv * env, RemixBase * base)
+{
+  RemixLADSPA * al = (RemixLADSPA *) remix_base_get_instance_data (env, base);
+
+  if (al->d) {
+    if (al->d->deactivate) al->d->deactivate (al->handle);
+  }
+
+  free (al->control_inputs);
+  free (al);
+  free (base);
+
+  return 0;
+}
+
+static int
+remix_ladspa_ready (RemixEnv * env, RemixBase * base)
+{
+  unsigned long samplerate = (unsigned long)remix_get_samplerate (env);
+  RemixLADSPA * al = (RemixLADSPA *) remix_base_get_instance_data (env, base);
+  return (samplerate == al->samplerate);
+}
+
+static RemixBase *
+remix_ladspa_prepare (RemixEnv * env, RemixBase * base)
+{
+  remix_ladspa_replace_handle (env, base);
+  return base;
+
+}
+
+/*
+ * remix_ladspa_1_0:
+ * A RemixChunkChunkFunc for a mono LADSPA sound consumer.
+ */
+static RemixCount
+remix_ladspa_1_0 (RemixEnv * env, RemixChunk * chunk, RemixCount offset,
+              RemixCount count, int channelname, void * data)
+{
+  RemixLADSPA * al = (RemixLADSPA *) data;
+  LADSPA_Descriptor * d;
+  LADSPA_PortDescriptor pd;
+  unsigned long port_i;
+
+  d = al->d;
+
+  /* Connect audio input */
+  for (port_i = 0; port_i < d->PortCount; port_i++) {
+    pd = d->PortDescriptors[(int)port_i];
+    if (LADSPA_IS_AUDIO_INPUT(pd)) {
+      d->connect_port (al->handle, port_i, &chunk->data[offset]);
+    }
+  }
+
+  d->run (al->handle, count);
+
+  return count;
+}
+
+/*
+ * remix_ladspa_0_1:
+ * A RemixChunkChunkFunc for a mono LADSPA sound generator.
+ */
+static RemixCount
+remix_ladspa_0_1 (RemixEnv * env, RemixChunk * chunk, RemixCount offset,
+              RemixCount count, int channelname, void * data)
+{
+  RemixLADSPA * al = (RemixLADSPA *) data;
+  LADSPA_Descriptor * d;
+  LADSPA_PortDescriptor pd;
+  unsigned long port_i;
+
+  d = al->d;
+  
+  /* Connect audio output */
+  for (port_i = 0; port_i < d->PortCount; port_i++) {
+    pd = d->PortDescriptors[(int)port_i];
+    if (LADSPA_IS_AUDIO_OUTPUT(pd)) {
+      d->connect_port (al->handle, port_i, &chunk->data[offset]);
+    }
+  }
+
+  d->run (al->handle, count);
+
+  return count;
+}
+
+/*
+ * remix_ladspa_1_1:
+ * A RemixChunkChunkFunc for filtering with a mono LADSPA plugin.
+ */
+static RemixCount
+remix_ladspa_1_1 (RemixEnv * env, RemixChunk * src, RemixCount src_offset,
+                  RemixChunk * dest, RemixCount dest_offset,
+                  RemixCount count, int channelname, void * data)
+{
+  RemixLADSPA * al = (RemixLADSPA *) data;
+  LADSPA_Descriptor * d;
+  LADSPA_PortDescriptor pd;
+  unsigned long port_i;
+
+  d = al->d;
+
+  if (al == NULL) {
+    remix_set_error (env, REMIX_ERROR_INVALID);
+    return -1;
+  }
+
+  for (port_i = 0; port_i < d->PortCount; port_i++) {
+    pd = d->PortDescriptors[(int)port_i];
+    if (LADSPA_IS_AUDIO_INPUT(pd)) {
+      d->connect_port (al->handle, port_i, &src->data[src_offset]);
+    }
+    if (LADSPA_IS_AUDIO_OUTPUT(pd)) {
+      d->connect_port (al->handle, port_i, &dest->data[dest_offset]);
+    }
+  }
+
+  d->run (al->handle, count);
+
+  return count;
+}
+
+
+#if 0
+static void
+ladspa_wrapper_apply_region (RemixEnv * env, gpointer pcmdata, sw_format * format,
+                            gint nr_frames,
+                            sw_param_set pset, void * custom_data)
+{
+  lm_custom * lm = (lm_custom *)custom_data;
+  const LADSPA_Descriptor * d = lm->d;
+  sw_param_spec * param_specs = lm->param_specs;
+
+  LADSPA_Handle * handle;
+  LADSPA_Data ** input_buffers, ** output_buffers;
+  LADSPA_Data * mono_input_buffer=NULL;
+  LADSPA_Data * p;
+  LADSPA_Data * control_inputs;
+  LADSPA_Data dummy_control_output;
+  LADSPA_PortDescriptor pd;
+  long length_b;
+  unsigned long port_i; /* counter for iterating over ports */
+  int i, j, n;
+
+  /* The number of times the plugin will be run; ie. if the number of
+   * channels in the input pcmdata is greater than the number of
+   * audio ports on the ladspa plugin, the plugin will be run
+   * multiple times until enough output channels have been calculated.
+   */
+  gint iterations;
+
+  /* Enumerate the numbers of each type of port on the ladspa plugin */
+  gint
+    nr_ci=0, /* control inputs */
+    nr_ai=0, /* audio inputs */
+    nr_co=0, /* control outputs */
+    nr_ao=0; /* audio outputs */
+
+  /* The number of audio channels to be processed */
+  gint nr_channels = format->channels;
+
+  /* The number of input and output buffers to use */
+  gint nr_i=0, nr_o=0;
+
+  /* Counters for allocating input and output buffers */
+  gint ibi=0, obi=0;
+
+
+  /* instantiate the ladspa plugin */
+  handle = d->instantiate (d, (long)format->rate);
+
+  /* Cache how many of each type of port this ladspa plugin has */
+  for (port_i=0; port_i < d->PortCount; port_i++) {
+    pd = d->PortDescriptors[(int)port_i];
+    if (LADSPA_IS_CONTROL_INPUT(pd))
+      nr_ci++;
+    if (LADSPA_IS_AUDIO_INPUT(pd))
+      nr_ai++;
+    if (LADSPA_IS_CONTROL_OUTPUT(pd))
+      nr_co++;
+    if (LADSPA_IS_AUDIO_OUTPUT(pd))
+      nr_ao++;
+  }
+
+  /* Basic assumption of this wrapper plugin, which was
+   * checked above in is_usable(); nb. for future expansion
+   * much of this routine is written to accomodate this
+   * assumption being incorrect.
+   */
+  g_assert (nr_ai == nr_ao);
+
+  /* Basic assumption that this plugin has audio output.
+   * Also important as we are about to divide by nr_ao.
+   */
+  g_assert (nr_ao > 0);
+
+  iterations = (gint) ceil(((double)nr_channels) / ((double)nr_ao));
+
+  /* Numbers of input and output buffers: ensure
+   * nr_i >= nr_channels && nr_o >= nr_channels
+   */
+  nr_i = iterations * nr_ai;
+  nr_o = iterations * nr_ao;
+
+  if ((nr_channels == 1) && (nr_ai == 1) && (nr_ao >= 1)) {
+    /*
+     * Processing a mono sample with a mono filter.
+     * Attempt to do this in place.
+     */
+
+    /* Copy PCM data if this ladspa plugin cannot work inplace */
+    if (LADSPA_WRAPPER_IS_INPLACE_BROKEN(d->Properties)) {
+      length_b = frames_to_bytes (format, nr_frames);
+      mono_input_buffer = g_malloc (length_b);
+      input_buffers = &mono_input_buffer;
+    } else {
+      input_buffers = (LADSPA_Data **)&pcmdata;
+    }
+    
+    output_buffers = (LADSPA_Data **)&pcmdata;
+
+  } else {
+    length_b = LADSPA_frames_to_bytes (nr_frames);
+
+    /* Allocate zeroed input buffers; these will remain zeroed
+     * if there aren't enough channels in the input pcmdata
+     * to use them.
+     */
+    input_buffers = g_malloc (sizeof(LADSPA_Data *) * nr_i);
+    for (i=0; i < nr_i; i++) {
+      input_buffers[i] = g_malloc0 (length_b);
+    }
+
+    output_buffers = g_malloc(sizeof(LADSPA_Data *) * nr_o);
+
+    /* Create separate output buffers if this ladspa plugin cannot
+     * work inplace */
+    if (LADSPA_WRAPPER_IS_INPLACE_BROKEN(d->Properties)) {
+      for (i=0; i < nr_o; i++) {
+       output_buffers[i] = g_malloc (length_b);
+      }
+    } else {
+      /* Re-use the input buffers, directly mapping them to
+       * corresponding output buffers
+       */
+      for (i=0; i < MIN(nr_i, nr_o); i++) {
+       output_buffers[i] = input_buffers[i];
+      }
+      /* Create some extra output buffers if nr_o > nr_i */
+      for (; i < nr_o; i++) {
+       output_buffers[i] = g_malloc (length_b);
+      }
+    }
+  }
+
+  /* Copy data into input buffers */
+  if (nr_channels == 1) {
+    if (!LADSPA_WRAPPER_IS_INPLACE_BROKEN(d->Properties)) {
+      length_b = frames_to_bytes (format, nr_frames);
+      memcpy (input_buffers[0], pcmdata, length_b);
+    } /* else we're processing in-place, so we haven't needed to set
+       * up a separate input buffer; input_buffers[0] actually
+       * points to pcmdata hence we don't do any copying here.
+       */
+  } else {
+    /* de-interleave multichannel data */
+
+    p = (LADSPA_Data *)pcmdata;
+
+    for (n=0; n < nr_channels; n++) {
+      for (i=0; i < nr_frames; i++) {
+       input_buffers[n][i] = *p++;
+      }
+    }
+  }
+
+  /* connect control ports */
+  control_inputs = g_malloc (nr_ci * sizeof(LADSPA_Data));
+  j=0;
+  for (port_i=0; port_i < d->PortCount; port_i++) {
+    pd = d->PortDescriptors[(int)port_i];
+    if (LADSPA_IS_CONTROL_INPUT(pd)) {
+      /* do something with pset! */
+      switch (param_specs[j].type) {
+      case SWEEP_TYPE_BOOL:
+       /* from ladspa.h:
+        * Data less than or equal to zero should be considered
+        * `off' or `false,'
+        * and data above zero should be considered `on' or `true.'
+        */
+       control_inputs[j] = pset[j].b ? 1.0 : 0.0;
+       break;
+      case SWEEP_TYPE_INT:
+       control_inputs[j] = (LADSPA_Data)pset[j].i;
+       break;
+      case SWEEP_TYPE_FLOAT:
+       control_inputs[j] = pset[j].f;
+       break;
+      default:
+       /* This plugin should produce no other types */
+       g_assert_not_reached ();
+       break;
+      }
+      d->connect_port (handle, port_i, &control_inputs[j]);
+      j++;
+    }
+    if (LADSPA_IS_CONTROL_OUTPUT(pd)) {
+      d->connect_port (handle, port_i, &dummy_control_output);
+    }
+  }
+
+  /* run the plugin as many times as necessary */
+  while (iterations--) {
+
+    /* connect input and output audio buffers to the
+     * audio ports of the ladspa plugin */
+    for (port_i=0; port_i < d->PortCount; port_i++) {
+      pd = d->PortDescriptors[(int)port_i];
+      if (LADSPA_IS_AUDIO_INPUT(pd)) {
+       d->connect_port (handle, port_i, input_buffers[ibi++]);
+      }
+      if (LADSPA_IS_AUDIO_OUTPUT(pd)) {
+       d->connect_port (handle, port_i, output_buffers[obi++]);
+      }
+    }
+
+    /* activate the ladspa plugin */
+    if (d->activate)
+      d->activate (handle);
+
+    /* run the ladspa plugin */
+    d->run (handle, nr_frames);
+
+    /* deactivate the ladspa plugin */
+    if (d->deactivate)
+      d->deactivate (handle);
+  }
+
+  /* re-interleave data */
+  if (nr_channels > 1) {
+    p = (LADSPA_Data *)pcmdata;
+
+    for (n=0; n < nr_channels; n++) {
+      for (i=0; i < nr_frames; i++) {
+       *p++ = output_buffers[n][i];
+      }
+    }
+  }
+
+  /* let the ladspa plugin clean up after itself */
+  if (d->cleanup)
+    d->cleanup (handle);
+
+  /* free the input and output buffers */
+  if (control_inputs) g_free (control_inputs);
+
+  if ((nr_channels == 1) && (nr_ai == 1) && (nr_ao >= 1)) {
+    if (LADSPA_WRAPPER_IS_INPLACE_BROKEN(d->Properties)) {
+      g_free (mono_input_buffer);
+    }
+  } else {
+
+    /* free the output buffers */
+    for (i=0; i < nr_o; i++) {
+      g_free (output_buffers[i]);
+    }
+    g_free (output_buffers);
+
+    /* free the input buffers, if we created some */
+    if (LADSPA_WRAPPER_IS_INPLACE_BROKEN(d->Properties)) {
+      for (i=0; i < nr_i; i++) {
+       g_free (input_buffers[i]);
+      }
+    } else {
+      /* inplace worked, but if (nr_i > nr_o), then
+       * we still need to free the last input buffers
+       */
+      for (i=nr_o; i < nr_i; i++) {
+       g_free (input_buffers[i]);
+      }
+    }
+    g_free (input_buffers);  
+  }
+}
+#endif
+
+static RemixBase *
+remix_ladspa_connect_control_inputs (RemixEnv * env, RemixBase * base)
+{
+  RemixLADSPA * al = (RemixLADSPA *) remix_base_get_instance_data (env, base);
+  LADSPA_Descriptor * d;
+  LADSPA_PortDescriptor pd;
+  RemixParameter parameter;
+  RemixParameterType type;
+  int j;
+  unsigned long port_i;
+
+  d = al->d;
+
+  if (d == NULL) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  j=0;
+  for (port_i=0; port_i < d->PortCount; port_i++) {
+    pd = d->PortDescriptors[(int)port_i];
+    if (LADSPA_IS_CONTROL_INPUT(pd)) {
+      type = remix_get_parameter_type (env, base, j);
+      parameter = remix_get_parameter (env, base, j);
+      switch (type) {
+      case REMIX_TYPE_BOOL:
+       /* from ladspa.h:
+        * Data less than or equal to zero should be considered
+        * `off' or `false,'
+        * and data above zero should be considered `on' or `true.'
+        */
+       al->control_inputs[j] = parameter.s_bool ? 1.0 : 0.0;
+       break;
+      case REMIX_TYPE_INT:
+       al->control_inputs[j] = (LADSPA_Data)parameter.s_int;
+       break;
+      case REMIX_TYPE_FLOAT:
+       al->control_inputs[j] = parameter.s_float;
+       break;
+      default:
+       /* This plugin should produce no other types */
+       break;
+      }
+      d->connect_port (al->handle, port_i, &al->control_inputs[j]);
+      j++;
+    }
+    if (LADSPA_IS_CONTROL_OUTPUT(pd)) {
+      d->connect_port (al->handle, port_i, &dummy_control_output);
+    }
+  }
+
+  return base;
+}
+
+static RemixCount
+remix_ladspa_1_0_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                          RemixStream * input, RemixStream * output)
+{
+  RemixLADSPA * al = remix_base_get_instance_data (env, base);
+  remix_ladspa_connect_control_inputs (env, base);
+  return remix_stream_chunkfuncify (env, input, count, remix_ladspa_1_0, al);
+}
+
+static RemixCount
+remix_ladspa_0_1_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                          RemixStream * input, RemixStream * output)
+{
+  RemixLADSPA * al = remix_base_get_instance_data (env, base);
+  remix_ladspa_connect_control_inputs (env, base);
+  return remix_stream_chunkfuncify (env, output, count, remix_ladspa_0_1, al);
+}
+
+static RemixCount
+remix_ladspa_1_1_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                          RemixStream * input, RemixStream * output)
+{
+  RemixLADSPA * al = remix_base_get_instance_data (env, base);
+  remix_ladspa_connect_control_inputs (env, base);
+  return remix_stream_chunkchunkfuncify (env, input, output, count,
+                                         remix_ladspa_1_1, al);
+}
+
+static RemixCount
+remix_ladspa_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                      RemixStream * input, RemixStream * output)
+{
+  RemixPlugin * plugin = remix_base_get_plugin (env, base);
+  RemixLADSPA * al;
+  LADSPA_PortDescriptor pd;
+  unsigned long port_i; /* counter for iterating over ports */
+
+  /* Enumerate the numbers of each type of port on the ladspa plugin */
+  int
+    nr_ci=0, /* control inputs */
+    nr_ai=0, /* audio inputs */
+    nr_co=0, /* control outputs */
+    nr_ao=0; /* audio outputs */
+
+  if (plugin == RemixNone) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return -1;
+  }
+
+  remix_ladspa_connect_control_inputs (env, base);
+
+  al = remix_base_get_instance_data (env, base);
+
+  /* Cache how many of each type of port this ladspa plugin has */
+  for (port_i=0; port_i < al->d->PortCount; port_i++) {
+    pd = al->d->PortDescriptors[(int)port_i];
+    if (LADSPA_IS_CONTROL_INPUT(pd))
+      nr_ci++;
+    if (LADSPA_IS_AUDIO_INPUT(pd))
+      nr_ai++;
+    if (LADSPA_IS_CONTROL_OUTPUT(pd))
+      nr_co++;
+    if (LADSPA_IS_AUDIO_OUTPUT(pd))
+      nr_ao++;
+  }
+
+  if (nr_ai == 1 && nr_ao == 1) {
+    return remix_stream_chunkchunkfuncify (env, input, output, count,
+                                       remix_ladspa_1_1, al);
+  } else if (nr_ai == 1 && nr_ao == 0) {
+    return remix_stream_chunkfuncify (env, input, count, remix_ladspa_1_0, al);
+  } else if (nr_ai == 0 && nr_ao == 1) {
+    return remix_stream_chunkfuncify (env, output, count, remix_ladspa_0_1, al);
+  } else {
+    remix_set_error (env, REMIX_ERROR_INVALID);
+    return -1;
+  }
+}
+
+static RemixCount
+remix_ladspa_length (RemixEnv * env, RemixBase * base)
+{
+  return REMIX_COUNT_INFINITE;
+}
+
+static struct _RemixMethods _remix_ladspa_1_0_methods = {
+  remix_ladspa_clone,
+  remix_ladspa_destroy,
+  remix_ladspa_ready, /* ready */
+  remix_ladspa_prepare, /* prepare */
+  remix_ladspa_1_0_process,
+  remix_ladspa_length,
+  NULL, /* seek */
+  NULL, /* flush */
+};
+
+static struct _RemixMethods _remix_ladspa_0_1_methods = {
+  remix_ladspa_clone,
+  remix_ladspa_destroy,
+  remix_ladspa_ready, /* ready */
+  remix_ladspa_prepare, /* prepare */
+  remix_ladspa_0_1_process,
+  remix_ladspa_length,
+  NULL, /* seek */
+  NULL, /* flush */
+};
+
+static struct _RemixMethods _remix_ladspa_1_1_methods = {
+  remix_ladspa_clone,
+  remix_ladspa_destroy,
+  remix_ladspa_ready, /* ready */
+  remix_ladspa_prepare, /* prepare */
+  remix_ladspa_1_1_process,
+  remix_ladspa_length,
+  NULL, /* seek */
+  NULL, /* flush */
+};
+
+
+static struct _RemixMethods _remix_ladspa_methods = {
+  remix_ladspa_clone,
+  remix_ladspa_destroy,
+  remix_ladspa_ready, /* ready */
+  remix_ladspa_prepare, /* prepare */
+  remix_ladspa_process,
+  remix_ladspa_length,
+  NULL, /* seek */
+  NULL, /* flush */
+};
+
+static RemixBase *
+remix_ladspa_optimise (RemixEnv * env, RemixBase * base)
+{
+  RemixLADSPA * al = remix_base_get_instance_data (env, base);
+  LADSPA_Descriptor * d;
+  LADSPA_PortDescriptor pd;
+  unsigned long port_i; /* counter for iterating over ports */
+
+  /* Enumerate the numbers of each type of port on the ladspa plugin */
+  int
+    nr_ci=0, /* control inputs */
+    nr_ai=0, /* audio inputs */
+    nr_co=0, /* control outputs */
+    nr_ao=0; /* audio outputs */
+
+  if (al == NULL) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  d = al->d;
+
+  if (d == NULL) {
+    remix_set_error (env, REMIX_ERROR_NOENTITY);
+    return RemixNone;
+  }
+
+  /* Cache how many of each type of port this ladspa plugin has */
+  for (port_i=0; port_i < d->PortCount; port_i++) {
+    pd = d->PortDescriptors[(int)port_i];
+    if (LADSPA_IS_CONTROL_INPUT(pd))
+      nr_ci++;
+    if (LADSPA_IS_AUDIO_INPUT(pd))
+      nr_ai++;
+    if (LADSPA_IS_CONTROL_OUTPUT(pd))
+      nr_co++;
+    if (LADSPA_IS_AUDIO_OUTPUT(pd))
+      nr_ao++;
+  }
+
+  al->control_inputs = malloc (nr_ci * sizeof (LADSPA_Data));
+
+  if (nr_ai == 1 && nr_ao == 1) {
+    remix_base_set_methods (env, base, &_remix_ladspa_1_1_methods);
+  } else if (nr_ai == 1 && nr_ao == 0) {
+    remix_base_set_methods (env, base, &_remix_ladspa_1_0_methods);
+  } else if (nr_ai == 0 && nr_ao == 1) {
+    remix_base_set_methods (env, base, &_remix_ladspa_0_1_methods);
+  } else { 
+    remix_base_set_methods (env, base, &_remix_ladspa_methods);
+  }
+
+  return base;
+}
+
+
+/*
+ * ladspa_wrapper_load_plugins (dir, name, gl)
+ *
+ * form RemixPlugins to describe the ladspa plugin functions that
+ * are in the shared library file "dir/name"
+ */
+static CDList *
+ladspa_wrapper_load_plugins (RemixEnv * env, char * dir, char * name)
+{
+  char path[PATH_LEN];
+  void * module;
+  LADSPA_Descriptor_Function desc_func;
+  const LADSPA_Descriptor * d;
+  LADSPA_PortDescriptor pd;
+  int i, j, k;
+  int valid_mask;
+  RemixPlugin * plugin;
+  RemixMetaText * mt;
+  RemixParameterScheme * scheme;
+  CDList * l, * plugins = CD_EMPTY_LIST;
+#define BUF_LEN 256
+  static char buf[BUF_LEN];
+  struct stat statbuf;
+
+  snprintf (path, PATH_LEN, "%s/%s", dir, name);
+
+  if (stat (path, &statbuf) == -1) return CD_EMPTY_LIST;
+  if (!remix_stat_regular (statbuf.st_mode)) return CD_EMPTY_LIST;
+
+  module = dlopen (path, RTLD_NOW);
+  if (!module) return CD_EMPTY_LIST;
+
+  /* Check that this module has not already been loaded (eg. if it is
+   * a symlink etc.) */
+  for (l = modules_list; l; l = l->next) {
+    if (l->data.s_pointer == module) {
+      dlclose (module);
+      return CD_EMPTY_LIST;
+    }
+  }
+
+  modules_list = cd_list_append (env, modules_list, CD_POINTER(module));
+
+  if ((desc_func = dlsym (module, "ladspa_descriptor"))) {
+    for (i=0; (d = desc_func (i)) != NULL; i++) {
+
+      if (!is_usable(d))
+       continue;
+
+      remix_dprintf ("[ladspa_wrapper_load_plugins] adding %s [%lu] by %s\n",
+                 d->Name, d->UniqueID, d->Maker);
+
+      plugin = malloc (sizeof (*plugin));
+      
+      mt = remix_meta_text_new (env);
+
+      snprintf (buf, BUF_LEN, "ladspa::%lu", d->UniqueID);
+      remix_meta_text_set_identifier (env, mt, strdup (buf));
+
+      snprintf (buf, BUF_LEN, "Miscellaneous::%s", d->Name);
+      remix_meta_text_set_category (env, mt, strdup (buf));
+
+      remix_meta_text_set_copyright (env, mt, (char *)d->Copyright);
+      remix_meta_text_add_author (env, mt, (char *)d->Maker, NULL);
+
+      plugin->metatext = mt;
+
+      plugin->init_scheme = CD_EMPTY_SET;
+      plugin->process_scheme = CD_EMPTY_SET;
+
+      k=0;
+      for (j=0; j < d->PortCount; j++) {
+       pd = d->PortDescriptors[j];
+       if (LADSPA_IS_CONTROL_INPUT(pd)) {
+         scheme = malloc (sizeof (*scheme));
+
+         scheme->name = (char *)d->PortNames[j];
+         scheme->description = (char *)d->PortNames[j];
+         scheme->type = convert_type (d->PortRangeHints[j].HintDescriptor);
+         valid_mask = get_valid_mask (d->PortRangeHints[j].HintDescriptor);
+         if (valid_mask == 0) {
+           scheme->constraint_type = REMIX_CONSTRAINT_TYPE_NONE;
+         } else {
+           scheme->constraint_type = REMIX_CONSTRAINT_TYPE_RANGE;
+           scheme->constraint.range =
+             convert_constraint (&d->PortRangeHints[j]);
+         }
+         plugin->process_scheme = cd_set_insert (env, plugin->process_scheme,
+                                                 k, CD_POINTER(scheme));
+         k++;
+       }
+      }
+
+      plugin->init = remix_ladspa_init;
+
+      plugin->plugin_data = (void *)d;
+
+      plugin->destroy = NULL;
+
+      plugins = cd_list_append (env, plugins, CD_POINTER(plugin));
+    }
+  }
+
+  return plugins;
+
+#undef BUF_LEN
+}
+
+/*
+ * ladspa_wrapper_load_dir (dir, gl)
+ *
+ * scan a directory "dirname" for LADSPA plugins, and attempt to load
+ * each of them.
+ */
+static CDList *
+ladspa_wrapper_load_dir (RemixEnv * env, char * dirname)
+{
+  DIR * dir;
+  struct dirent * dirent;
+  CDList * plugins = CD_EMPTY_LIST, * l;
+
+  if (!dirname) return plugins;
+
+  dir = opendir (dirname);
+  if (!dir) {
+    return plugins;
+  }
+
+  while ((dirent = readdir (dir)) != NULL) {
+    l = ladspa_wrapper_load_plugins (env, dirname, dirent->d_name);
+    plugins = cd_list_join (env, plugins, l);
+  }
+
+  closedir (dir);
+
+  return plugins;
+}
+
+CDList *
+remix_load (RemixEnv * env)
+{
+  CDList * plugins = CD_EMPTY_LIST, * l;
+  char * ladspa_path=NULL;
+  char * next_sep=NULL;
+  char * saved_lp=NULL;
+
+  /* If this ladspa_wrapper module has already been initialised, don't
+   * initialise again until cleaned up.
+   */
+  if (ladspa_wrapper_initialised)
+    return CD_EMPTY_LIST;
+
+  ladspa_path = getenv ("LADSPA_PATH");
+  if (!ladspa_path)
+    ladspa_path = saved_lp = strdup(default_ladspa_path);
+
+  do {
+    next_sep = strchr (ladspa_path, ':');
+    if (next_sep != NULL) *next_sep = '\0';
+    
+    l = ladspa_wrapper_load_dir (env, ladspa_path);
+    plugins = cd_list_join (env, plugins, l);
+
+    if (next_sep != NULL) ladspa_path = ++next_sep;
+
+  } while ((next_sep != NULL) && (*next_sep != '\0'));
+
+  ladspa_wrapper_initialised = TRUE;
+
+  /* free string if dup'd for ladspa_path */
+  if (saved_lp != NULL) free(saved_lp);
+
+  return plugins;
+}
+
+void
+remix_unload (RemixEnv * env)
+{
+  CDList * l;
+
+  if (!ladspa_wrapper_initialised) return;
+
+  for (l = modules_list; l; l = l->next) {
+    dlclose(l->data.s_pointer);
+  }
+
+  modules_list = NULL;
+}
+
diff --git a/src/plugins/noise/Makefile.am b/src/plugins/noise/Makefile.am
new file mode 100644 (file)
index 0000000..7324e61
--- /dev/null
@@ -0,0 +1,17 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = -I$(top_srcdir)/include -I$(CTXDATADIR)
+
+libdir = $(PACKAGE_PLUGIN_DIR)
+
+CTXDATADIR = $(top_srcdir)/src/ctxdata
+CTXDATA_LIBS = $(top_builddir)/src/ctxdata/libctxdata.la
+
+REMIXDIR = ../../libremix
+REMIX_LIBS = $(REMIXDIR)/libremix.la
+
+lib_LTLIBRARIES = libremix_noise.la
+
+libremix_noise_la_SOURCES = remix_noise.c
+libremix_noise_la_LDFLAGS = -module -version-info 1:0:0
+libremix_noise_la_LIBADD = $(REMIX_LIBS) $(CTXDATA_LIBS)
diff --git a/src/plugins/noise/remix_noise.c b/src/plugins/noise/remix_noise.c
new file mode 100644 (file)
index 0000000..65337db
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * libremix -- An audio mixing and sequencing library.
+ *
+ * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * RemixNoise: a noise generator
+ *
+ * Conrad Parker <conrad@metadecks.org>, August 2001
+ */
+
+#include <stdlib.h>
+
+#define __REMIX_PLUGIN__
+#include <remix/remix.h>
+
+/* Optimisation dependencies: none */
+static RemixBase * remix_noise_optimise (RemixEnv * env, RemixBase * noise);
+
+static RemixBase *
+remix_noise_init (RemixEnv * env, RemixBase * base, CDSet * parameters)
+{
+  remix_noise_optimise (env, base);
+  return base;
+}
+
+static RemixBase *
+remix_noise_clone (RemixEnv * env, RemixBase * base)
+{
+  RemixBase * new_noise = remix_base_new (env);
+  remix_noise_optimise (env, new_noise);
+  return new_noise;
+}
+
+static int
+remix_noise_destroy (RemixEnv * env, RemixBase * base)
+{
+  free (base);
+  return 0;
+}
+
+/* An RemixChunkFunc for creating noise */
+static RemixCount
+remix_noise_write_chunk (RemixEnv * env, RemixChunk * chunk, RemixCount offset,
+                     RemixCount count, int channelname, void * data)
+{
+  RemixPCM * d;
+  RemixPCM r, rmax = (RemixPCM)RAND_MAX;
+  RemixCount i;
+
+  remix_dprintf ("[remix_noise_write_chunk] (%p, +%ld) @ %ld\n", data, count,
+             offset);
+
+  d = &chunk->data[offset];
+  for (i = 0; i < count; i++) {
+    r = (RemixPCM) random ();
+    r *= 2.0;
+    r /= rmax;
+    *d++ = r - 1.0;
+  }
+
+  return count;
+}
+
+static RemixCount
+remix_noise_process (RemixEnv * env, RemixBase * base, RemixCount count,
+                 RemixStream * input, RemixStream * output)
+{
+  return remix_stream_chunkfuncify (env, output, count,
+                                remix_noise_write_chunk, base);
+}
+
+static RemixCount
+remix_noise_length (RemixEnv * env, RemixBase * base)
+{
+  return REMIX_COUNT_INFINITE;
+}
+
+static struct _RemixMethods _remix_noise_methods = {
+  remix_noise_clone,
+  remix_noise_destroy,
+  NULL, /* ready */
+  NULL, /* prepare */
+  remix_noise_process,
+  remix_noise_length,
+  NULL, /* seek */
+  NULL, /* flush */
+};
+
+static RemixBase *
+remix_noise_optimise (RemixEnv * env, RemixBase * noise)
+{
+  remix_base_set_methods (env, noise, &_remix_noise_methods);
+  return noise;
+}
+
+static struct _RemixMetaText noise_metatext = {
+  "envstd::noise",
+  "Generators::Noise",
+  "White noise generator",
+  "Copyright (C) 2001 CSIRO Australia",
+  "http://www.metadecks.org/remix/plugins/noise.html",
+  REMIX_ONE_AUTHOR ("Conrad Parker", "conrad@metadecks.org"),
+};
+
+static struct _RemixPlugin noise_plugin = {
+  &noise_metatext,
+  REMIX_FLAGS_NONE,
+  CD_EMPTY_SET, /* new scheme */
+  remix_noise_init,
+  CD_EMPTY_SET, /* process scheme */
+  NULL, /* suggests */
+  NULL, /* plugin data */
+  NULL  /* destroy */
+};
+
+CDList *
+remix_load (RemixEnv * env)
+{
+  CDList * plugins = cd_list_new (env);
+
+  plugins = cd_list_prepend (env, plugins, CD_POINTER(&noise_plugin));
+
+  return plugins;
+}
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
new file mode 100644 (file)
index 0000000..bf49e0a
--- /dev/null
@@ -0,0 +1,24 @@
+## Process this file with automake to produce Makefile.in
+
+AM_CFLAGS = -Wall -pedantic
+
+INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/ctxdata
+
+REMIX_LIBS = ../ctxdata/libctxdata.la ../libremix/libremix.la ../ctxdata/libctxdata.la -ldl
+
+# Test programs
+
+TESTS_ENVIRONMENT = $(VALGRIND_ENVIRONMENT)
+
+test: check
+
+TESTS = noop sndfiletest
+
+noinst_PROGRAMS = $(TESTS)
+noinst_HEADERS = tests.h
+
+noop_SOURCES = noop.c
+noop_LDADD = $(REMIX_LIBS)
+
+sndfiletest_SOURCES = sndfiletest.c
+sndfiletest_LDADD = $(REMIX_LIBS) @SNDFILE_LIBS@
diff --git a/src/tests/noop.c b/src/tests/noop.c
new file mode 100644 (file)
index 0000000..21cfe4f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * noop.c
+ *
+ * Copyright (C) 2006 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or
+ * implied warranty.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <remix/remix.h>
+
+#include "tests.h"
+
+int
+main (int argc, char ** argv)
+{
+  RemixEnv * env;
+
+  INFO ("+ Creating new RemixEnv");
+  env = remix_init ();
+
+  INFO ("+ Purging RemixEnv");
+  remix_purge (env);
+
+  return 0;
+}
diff --git a/src/tests/sndfiletest.c b/src/tests/sndfiletest.c
new file mode 100644 (file)
index 0000000..76ffc03
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * sndfiletest.c
+ *
+ * Copyright (C) 2006 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO), Australia.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or
+ * implied warranty.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <remix/remix.h>
+
+#include "tests.h"
+
+static void non_existant_file (void);
+
+static void
+non_existant_file (void)
+{
+  RemixEnv * env;
+  RemixBase * sf1;
+  RemixPlugin * sf_plugin;
+  CDSet * sf_parms;
+  int sf_path_key;
+  CDScalar name;
+
+  INFO ("Attempting to read non existant file") ;
+  
+  env = remix_init ();
+  remix_set_tempo (env, 120);
+  remix_set_channels (env, REMIX_STEREO);
+
+  sf_plugin = remix_find_plugin (env, "builtin::sndfile_reader");
+  sf_parms = cd_set_new (env);
+  sf_path_key = remix_get_init_parameter_key (env, sf_plugin, "path");
+  name.s_string = "bad_file_name.wav" ;
+  sf_parms = cd_set_insert (env, sf_parms, sf_path_key, name);
+  if (sf_plugin == NULL) {
+    FAIL ("Newly created sndfile plugin NULL");
+  }
+
+  sf1 = remix_new (env, sf_plugin, sf_parms);
+}
+
+int
+main (int argc, char ** argv)
+{
+  non_existant_file () ;
+
+  return 0;
+}
diff --git a/src/tests/tests.h b/src/tests/tests.h
new file mode 100644 (file)
index 0000000..f99c99e
--- /dev/null
@@ -0,0 +1,31 @@
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_INTTYPES_H
+#  include <inttypes.h>
+#else
+#  define PRId64 "I64d"
+#endif
+
+/* FIXME: on Mac OS X, off_t is 64-bits.  Obviously we want a nicer
+ * way to do it than this, but a quick fix is a good fix */
+#ifdef __APPLE__
+#  define PRI_off_t "q"
+#else
+#  define PRI_off_t "l"
+#endif
+
+#define INFO(str) \
+  { printf ("----  %s ...\n", (str)); }
+
+#define WARN(str) \
+  { printf ("%s:%d: warning: %s\n", __FILE__, __LINE__, (str)); }
+
+#define FAIL(str) \
+  { printf ("%s:%d: %s\n", __FILE__, __LINE__, (str)); exit(1); }
+
+#undef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
diff --git a/stamp-h.in b/stamp-h.in
new file mode 100644 (file)
index 0000000..9788f70
--- /dev/null
@@ -0,0 +1 @@
+timestamp