]> git.parisson.com Git - telemeta.git/commitdiff
* Remove/add audiolab
authoryomguy <>
Wed, 20 Aug 2008 22:13:18 +0000 (22:13 +0000)
committeryomguy <>
Wed, 20 Aug 2008 22:13:18 +0000 (22:13 +0000)
* Install audiolab with setup.py
* Cleanup
* Audiolab waveform is default view

87 files changed:
setup.py
telemeta/util/audiolab/COPYING.txt [new file with mode: 0644]
telemeta/util/audiolab/Changelog [new file with mode: 0644]
telemeta/util/audiolab/FLAC_SUPPORT.txt [new file with mode: 0644]
telemeta/util/audiolab/INSTALL.txt [new file with mode: 0644]
telemeta/util/audiolab/MANIFEST.in [new file with mode: 0644]
telemeta/util/audiolab/Makefile [new file with mode: 0644]
telemeta/util/audiolab/README.txt [new file with mode: 0644]
telemeta/util/audiolab/TODO [new file with mode: 0644]
telemeta/util/audiolab/build/lib/scikits/__init__.py [new file with mode: 0644]
telemeta/util/audiolab/build/lib/scikits/audiolab/__init__.py [new file with mode: 0644]
telemeta/util/audiolab/build/lib/scikits/audiolab/info.py [new file with mode: 0644]
telemeta/util/audiolab/build/lib/scikits/audiolab/matapi.py [new file with mode: 0644]
telemeta/util/audiolab/build/lib/scikits/audiolab/pyaudioio.py [new file with mode: 0644]
telemeta/util/audiolab/build/lib/scikits/audiolab/pysndfile.py [new file with mode: 0644]
telemeta/util/audiolab/build/lib/scikits/audiolab/tests/__init__.py [new file with mode: 0644]
telemeta/util/audiolab/build/lib/scikits/audiolab/tests/test_matapi.py [new file with mode: 0644]
telemeta/util/audiolab/build/lib/scikits/audiolab/tests/test_pysndfile.py [new file with mode: 0644]
telemeta/util/audiolab/build/lib/scikits/audiolab/tests/testcommon.py [new file with mode: 0644]
telemeta/util/audiolab/generate.sh [new file with mode: 0644]
telemeta/util/audiolab/generate_const.py [new file with mode: 0644]
telemeta/util/audiolab/generate_const.pyc [new file with mode: 0644]
telemeta/util/audiolab/header_parser.py [new file with mode: 0644]
telemeta/util/audiolab/header_parser.pyc [new file with mode: 0644]
telemeta/util/audiolab/scikits.audiolab.egg-info/PKG-INFO [new file with mode: 0644]
telemeta/util/audiolab/scikits.audiolab.egg-info/SOURCES.txt [new file with mode: 0644]
telemeta/util/audiolab/scikits.audiolab.egg-info/dependency_links.txt [new file with mode: 0644]
telemeta/util/audiolab/scikits.audiolab.egg-info/namespace_packages.txt [new file with mode: 0644]
telemeta/util/audiolab/scikits.audiolab.egg-info/requires.txt [new file with mode: 0644]
telemeta/util/audiolab/scikits.audiolab.egg-info/top_level.txt [new file with mode: 0644]
telemeta/util/audiolab/scikits.audiolab.egg-info/zip-safe [new file with mode: 0644]
telemeta/util/audiolab/scikits/__init__.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/__init__.pyc [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/__init__.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/__init__.pyc [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/docs/Makefile [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/docs/audiolab1.png [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/docs/base.tex [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/docs/examples/format1.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/docs/examples/format2.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/docs/examples/matlab1.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/docs/examples/quick1.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/docs/examples/usage1.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/docs/examples/usage2.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/docs/examples/write1.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/docs/index.txt [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/docs/user.tex [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/info.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/info.pyc [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/matapi.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/matapi.pyc [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/misc/Makefile [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/misc/Sconstruct [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/misc/badflac.c [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/misc/badflac.flac [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/misc/winfdopen.c [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/pyaudioio.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/pysndfile.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/pysndfile.py.in [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/pysndfile.pyc [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/soundio/SConstruct [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/soundio/_alsa.pyx [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/soundio/alsa.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/soundio/alsa_ctypes.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/soundio/setup.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/soundio/simple.c [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/soundio/simple2.c [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/test_data/original.aif [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/test_data/test.aiff [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/test_data/test.au [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/test_data/test.flac [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/test_data/test.raw [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/test_data/test.sdif [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/test_data/test.wav [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/tests/__init__.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/tests/test_matapi.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/tests/test_pysndfile.py [new file with mode: 0644]
telemeta/util/audiolab/scikits/audiolab/tests/testcommon.py [new file with mode: 0644]
telemeta/util/audiolab/setup.cfg [new file with mode: 0644]
telemeta/util/audiolab/setup.py [new file with mode: 0644]
telemeta/util/audiolab/site.cfg.win32 [new file with mode: 0644]
telemeta/util/audiolab/site.cfg_noflac [new file with mode: 0644]
telemeta/util/audiolab/tester.py [new file with mode: 0644]
telemeta/visualization/octave_core.py
telemeta/visualization/spectrogram3.py
telemeta/visualization/waveform3.py
telemeta/web/base.py

index bc5b867a56689871ac6a8d0b057e31c070c2c010..5a7ab8600ebeaaa0b33804dd4bb646e10932cd49 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -48,7 +48,7 @@ setup(
   url = "/http://svn.parisson.org/telemeta",
   description = "web frontend to backup, transcode and tag any audio content with metadata",
   author = ["Guillaume Pellerin, Olivier Guilyardi"],
-  author_email = ["pellerin@parisson.com"],
+  author_email = ["pellerin@parisson.com","olivier@samalyse.com"],
   version = version,
   packages = packages,
   data_files = data_files,
@@ -82,3 +82,7 @@ See http://svn.parisson.org/telemeta/ for more informations.
 """
 )
 
+# Install audiolab
+os.chdir('telemeta/util/audiolab/')
+os.system('python setup.py install')
+
diff --git a/telemeta/util/audiolab/COPYING.txt b/telemeta/util/audiolab/COPYING.txt
new file mode 100644 (file)
index 0000000..5ab7695
--- /dev/null
@@ -0,0 +1,504 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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/telemeta/util/audiolab/Changelog b/telemeta/util/audiolab/Changelog
new file mode 100644 (file)
index 0000000..58d64a7
--- /dev/null
@@ -0,0 +1,139 @@
+audiolab (0.7) Sun, 09 Sep 2007 20:10:27 +0900
+
+       * More robust wrapping of libsndfile: sf_file are objects pointers,
+       the destructor checks that the handle already exists, and NULL
+       pointers are better detected.
+       * Add preliminary alsa version (not enabled yet).
+       * Opening non existing files now throws meaningful exception.
+
+audiolab (0.7dev) Tue, 17 Jul 2007 12:03:41 +0900
+
+       * Rename pyaudiolab to audiolab.
+
+pyaudiolab (0.7dev) Fri, 25 May 2007 16:00:24 +0900
+
+       * Add the possibility to open an audio file from file descriptor
+
+pyaudiolab (0.7dev) Thu, 24 May 2007 13:34:11 +0900
+
+       * Support for read and write seek
+       * Set correct location of pysndfile.py in setup.py, so that it is
+       correctly removed during setup.
+
+pyaudiolab (0.7dev) Tue, 22 May 2007 10:50:53 +0900
+
+       * Relicense under the LGPL
+       * Add data files with distutils instead of setuptools because of
+       setuptools bug with sdist targets
+
+pyaudiolab (0.7dev) Mon, 21 May 2007 11:09:32 +0900
+
+       * Convert the layout to scikits convention + setuptools
+
+pyaudiolab (0.6.7) Mon, 19 Mar 2007 15:19:10 +0900
+
+       * Add some meta-data for setup.py
+
+pyaudiolab (0.6.7) Mon, 12 Mar 2007 15:48:12 +0900
+
+       * Mainly Bug fixes for win32 and libsndfile without FLAC support.
+       * Add a site.cfg.win32 + instructions in the doc to show how to use with
+       win32.
+       * Replace all remove functions in tests for temp files (Does not work
+       under win32)
+       * If FLAC is not supported, set flacread and flacwrite functions to None
+       and catch exceptions related to unavailable FLAC support to avoid tests
+       failing.
+       * Replace non FLAC tests using FLAC files to WAV files.
+
+pyaudiolab (0.6.6dev) Mon, 05 Feb 2007 20:37:49 +0900
+
+       * Add reader/writer factory to matlab-like API. 
+       * Generate au/wav/aiff/sdif/flac read/write functions
+       with Matlab-like behaviour.
+       * disable seek support for FLAC files by default, because of problems
+       when using sf_seek(offset, SEEK_SET) with some FLAC versions.
+
+pyaudiolab (0.6.6dev) Mon, 05 Feb 2007 12:06:10 +0900
+
+       * Change system to detect sndfile shared library file (based on
+       sys.plaform instead of so_ext which does not seem to work on darwin at
+       least).
+
+pyaudiolab (0.6.5) Fri, 02 Feb 2007 14:53:01 +0900
+
+       * bump to 0.6.5
+       * Add mechanism to automatic release+upload
+       * release 0.6.5
+
+pyaudiolab (0.6.5dev) Fri, 02 Feb 2007 14:53:01 +0900
+
+       * Put a proper LICENSE in COPYING.txt, and note in the README.txt
+       that pyaudiolab depends on LGPL package
+
+pyaudiolab (0.6.5dev) Thu, 01 Feb 2007 15:06:51 +0900
+
+       * Add int and short support for reading/writing
+       * fix write and read such as float arguments for number of frames is
+       possible + test.
+       * Whenever a long long is expected by libsndfile, check that the number
+       given by user is valid.
+       * Give more meaningful error messages when bad parameters are given for
+       opening a file for writing.
+       * Give more meaningful error messages when trying to read a file opened
+       only for writing.
+       * Add examples scripts into doc/examples. Run them in test.sh
+
+pyaudiolab (0.6.1) Wed, 31 Jan 2007 16:03:02 +0900
+
+       * Bump to 0.6.1
+       * Change the name to pyaudiolab to avoid clashes with existing pyaudio 
+       toolboxes.
+
+pyaudio (0.6) Wed, 31 Jan 2007 14:32:41 +0900
+
+       * Bump to 0.6.
+       * Add support for seeking.
+       * Add sync to sndfile to force flushing OS IO buffers to file without need
+       to close.
+       * read takes dtype argument instead of read_*_float, read_*_double.
+       * wavread, wavwrite are working and similar to matlab's ones.
+
+pyaudio (0.5) Tue, 30 Jan 2007 14:40:36 +0900
+
+       * Bump to 0.5
+       * More explicit import error when used with bad ctypes
+       * Add matlab-like functions wavread, wavwrite, aiffread, aiffwrite
+       * Add API to have useful strings from format in sndfile class
+
+pyaudio (0.4) Mon, 06 Nov 2006 12:56:55 +0900
+
+       * Bump to 0.4
+       * replace c_longlong with c_int64; if ctypes does not support 64 bits
+       integer, it will result in an import error instead of having c_longlong
+       silently converted to 32 bits integer, which would result in difficult
+       to trace bugs
+       * add support for raw files (which requires a format, even for reading)
+
+pyaudio (0.3.1) Mon, 06 Nov 2006 12:56:55 +0900
+
+       * Bump to 0.3.1
+       * Check that samplerate and number of channels are int. If not,
+       warn the user about potential unsafe conversion.
+       * Move functions used to parse enum in header files into
+       a other module, for easier sharing with other packages.
+
+pyaudio (0.3) Tue, 31 Oct 2006 21:38:46 +0900
+
+       * Bump to 0.3
+       * Added a class format, which can be used to open
+       file for writing. The class hides all internal representation
+       used by libsndfile, for a much saner API.
+       * Various Bug fixes
+
+pyaudio (0.2) Mon, 30 Oct 2006 17:45:14 +0900
+
+       * Bump to 0.2
+       * Added a sndfile_info in setup.py for an automatic detection
+       of sndfile under the installed system
+       * mode is now a simple string in sndfile class ctor
diff --git a/telemeta/util/audiolab/FLAC_SUPPORT.txt b/telemeta/util/audiolab/FLAC_SUPPORT.txt
new file mode 100644 (file)
index 0000000..1f96d27
--- /dev/null
@@ -0,0 +1,28 @@
+ABOUT SEEK AND FLAC SUPPORT:
+
+    audiolab supports flac, because libsndfile does. Unfortunately, some FLAC
+libraries seem buggy (at least the one with ubuntu Dapper is) with respect to
+their seek implementation. That's why by default, seeking in flac support is
+NOT enabled. If you want to test whether you FLAC library has the problem,
+compile the file badflac.c in the misc directory, eg on Linux:
+
+gcc -W -Wall badflac.c -lsndfile -o badflac
+
+and try running ./badflac ./badflac.flac. If the program looks locked up, this
+means you should NOT enable flac support. If it works OK, then you can enable
+seek support in audiolab by commenting the following lines in
+pysndfile.py.in (take care to modify the pysndfile.py.in, and not the
+pysndfile.py file), in sndfile.__init__ (around line 500):
+
+if self.get_file_format() == 'flac':
+    def SeekNotEnabled(self, *args):
+        raise FlacUnsupported("seek not supported on Flac by default, because"\
+            "\n some version of FLAC libraries are buggy. Read FLAC_SUPPORT.txt")
+    self.seek   = SeekNotEnabled 
+
+Then install the package.
+
+The pre releases version 1.0.18pre7 of libsndfile is known to work, libsndfile
+1.0.17 and 1.0.16 known NOT to work (those version rely on an installed FLAC
+library, whether starting from 1.0.18, libsndfile will include the FLAC library
+instead of using an externally supplied one).
diff --git a/telemeta/util/audiolab/INSTALL.txt b/telemeta/util/audiolab/INSTALL.txt
new file mode 100644 (file)
index 0000000..b812afa
--- /dev/null
@@ -0,0 +1,36 @@
+Suported platforms:
+-------------------
+
+audiolab has been successfully run and tested on the following platforms:
+
+        - windows
+        - mac OS X (intel and ppc) 
+        - linux (intel and ppc). 
+
+This may work on other platforms: in particular, I expect the package to work
+on most recent Unices.
+
+Requirements
+------------
+
+To run correctly, audiolab requires the following softwares:
+
+        - python (> 2.3): http://www.python.org
+        - setuptools:
+          http://peak.telecommunity.com/DevCenter/setuptools#installing-setuptools
+        - ctypes (included in python starting from version 2.5)
+        - numpy: http://www.scipy.org/Numpy
+        - libsndfile: http://www.mega-nerd.com/libsndfile/
+
+On Ubuntu, you can ensure to get the necessary packages by doing apt-get
+install python python-setuptools libsndfile-dev python-numpy
+
+Installing
+----------
+
+Installing is easy: once in the audiolab directory, simply do: python setup.py
+install. If the installation failed because libsndfile was not found, check
+that you have correctly installed libsndfile, including its headers
+(sndfile.h). On windows, as there is no standard for 3rd party libraries and
+header location, you can put them wherever you want, as long as the
+corresponding directories are in site.cfg (see site.cfg.win32 for an example).
diff --git a/telemeta/util/audiolab/MANIFEST.in b/telemeta/util/audiolab/MANIFEST.in
new file mode 100644 (file)
index 0000000..2288cf9
--- /dev/null
@@ -0,0 +1,7 @@
+include scikits/audiolab/pysndfile.py.in
+include site.cfg
+include site.cfg.win32
+include COPYING.txt
+include FLAC_SUPPORT.txt
+include header_parser.py
+include generate_const.py
diff --git a/telemeta/util/audiolab/Makefile b/telemeta/util/audiolab/Makefile
new file mode 100644 (file)
index 0000000..94b2f8a
--- /dev/null
@@ -0,0 +1,114 @@
+# Last Change: Tue Jul 17 11:00 AM 2007 J
+#
+# This makefile is used to do all the "tricky things" before a release,
+# including updating the doc, installing and testing the package, uploading the
+# release to the website, etc...
+#
+# TODO: not fake dependencies....
+
+PKG_VER        = $(shell cat scikits/audiolab/info.py | grep __version__ | tr -s " " | cut -f 3 -d" " \
+                         | cut -f 2 -d\')
+
+BASEPATH       = $(PWD)
+DATAPATH       = $(PWD)/scikits/audiolab/test_data/
+DOCPATH                = $(PWD)/scikits/audiolab/docs/
+EXAMPATH       = $(DOCPATH)/examples
+
+SCIPYPATH      = $(HOME)/local/lib/python2.5/site-packages
+TMPPATH                = $(CURDIR)/../tmp
+
+PYTHONCMD      = PYTHONPATH=$(TMPPATH)/lib/python2.5/site-packages:$(SCIPYPATH) python -c 
+PYTHONRUN      = PYTHONPATH=$(TMPPATH)/lib/python2.5/site-packages:$(SCIPYPATH) python 
+
+RELEASELOC     = $(WWWHOMEDIR)/archives/audiolab/releases
+
+do_release: clean src examples tests
+
+release: do_release upload_release
+
+upload_release:  dist/audiolab-$(PKG_VER).tar.gz \
+       dist/audiolab-$(PKG_VER).tar.bz2 \
+       dist/audiolab-$(PKG_VER).zip 
+       @echo "Uploading version $(PKG_VER) ..."
+       @read n
+       rcp dist/audiolab-$(PKG_VER).tar.gz $(RELEASELOC)
+       rcp dist/audiolab-$(PKG_VER).tar.bz2 $(RELEASELOC)
+       rcp dist/audiolab-$(PKG_VER).zip $(RELEASELOC)
+
+src: build_src
+
+build_src: dist/audiolab-$(PKG_VER).tar.gz \
+       dist/audiolab-$(PKG_VER).tar.bz2 \
+       dist/audiolab-$(PKG_VER).zip 
+
+dist/audiolab-$(PKG_VER).tar.gz: doc
+               python setup.py sdist --format=gztar
+
+dist/audiolab-$(PKG_VER).zip: doc
+               python setup.py sdist --format=zip
+
+dist/audiolab-$(PKG_VER).tar.bz2: doc
+               python setup.py sdist --format=bztar
+
+#=======================================================
+# Code related to building audiolab in a tmp directory
+#=======================================================
+# Install the package in a tmp directory
+$(TMPPATH): build_test
+
+build_test:
+       $(PYTHONRUN) setup.py install --prefix=$(TMPPATH)
+
+# Clean the tmp dir
+clean_before_run:
+       rm -rf $(TMPPATH)
+
+#===========================
+# Code related to examples
+#===========================
+examples: run_examples
+
+# Run examples in docs/examples
+run_examples:  $(TMPPATH)
+       #for i in $(BASEPATH)/docs/examples/*.py; do\
+       #       echo "========== runing example $$i ==========";\
+       #       $(PYTHONRUN) $$i; \
+       #done;
+       # Why when using the above loop, Make does not stop when one script fails ?
+       @echo "---------- runing example quick1.py ----------";
+       cd $(DATAPATH) && $(PYTHONRUN) $(EXAMPATH)/quick1.py
+       @echo "---------- runing example usage1.py ----------";
+       cd $(DATAPATH) && $(PYTHONRUN) $(EXAMPATH)/usage1.py
+       @echo "---------- runing example usage2.py ----------";
+       cd $(DATAPATH) && $(PYTHONRUN) $(EXAMPATH)/usage2.py
+       @echo "---------- runing example format1.py ----------";
+       cd $(DATAPATH) && $(PYTHONRUN) $(EXAMPATH)/format1.py
+       @echo "---------- runing example format2.py ----------";
+       cd $(DATAPATH) && $(PYTHONRUN) $(EXAMPATH)/format2.py
+       @echo "---------- runing example write1.py ----------";
+       cd $(DATAPATH) && $(PYTHONRUN) $(EXAMPATH)/write1.py
+       @echo "---------- runing example matlab1.py ----------";
+       cd $(DATAPATH) && $(PYTHONRUN) $(EXAMPATH)/matlab1.py
+
+#=====================
+# Code related to test
+#=====================
+tests: run_tests examples
+       @echo "=================================="
+       @echo " RELEASE $(PKG_VER) IS OK !"
+       @echo "=================================="
+
+# Run all tests
+run_tests: $(TMPPATH)
+       @echo "=============== running test ============"
+       cd .. && $(PYTHONCMD) "import scikits.audiolab as audiolab; print audiolab; audiolab.test()"
+       @echo "=============== Done ============"
+
+#=====================
+# Code related to doc
+#=====================
+doc:
+       cd $(DOCPATH) && $(MAKE)
+
+clean: clean_before_run
+       cd $(DOCPATH) && $(MAKE) clean
diff --git a/telemeta/util/audiolab/README.txt b/telemeta/util/audiolab/README.txt
new file mode 100644 (file)
index 0000000..7c6a3f4
--- /dev/null
@@ -0,0 +1,22 @@
+audiolab: a small toolbox to read, write and play audio to and from
+numpy arrays.
+
+audiolab provides two API:
+    - one similar to matlab: this gives you wavread/wavwrite/auread/auwrite
+      functions similar to matlab's ones.
+    - a more complete API, which can be used to read, write to many audio files
+      (including wav, aiff, flac, au, IRCAM, htk, etc...), with IO capabilities
+      not available to matlab (seek, append data, etc...)
+
+It is a thin wrapper around libsndfile from Erik Castro Lopo.
+
+See the docs directory for more details
+
+LICENSE:
+
+audiolab itself is licensed under the LGPL license
+(see COPYING.txt in main source directory)
+
+audiolab depends on libsndfile to work; libsndfile is licensed under LGPL.
+
+See http://www.mega-nerd.com/libsndfile/ for details.
diff --git a/telemeta/util/audiolab/TODO b/telemeta/util/audiolab/TODO
new file mode 100644 (file)
index 0000000..8dd984a
--- /dev/null
@@ -0,0 +1,28 @@
+.. vim:syntax=rest
+
+Things to do before a release
+-----------------------------
+    - better error reporting (support error logging of sndfile ?): the
+      exceptions launched are pretty random...
+    - add inout argument in read method to avoid recreating a buffer.
+    - more tests
+    - add an audio player for at least linux/windows/mac os x (0.8-0.9) -> This
+      will be done in a different branch
+
+Pending issues
+--------------
+    - There is no check for supported format, the way get_supported_format is
+      implemented now it totally broken. Instead of using values from the
+      header, should use sf_command
+    - removing most warning from pylint
+    - handling in audiolab when first is not 0 (now, we have seek :))
+
+Maybe ?
+-------
+    - change array layout convention to numpy's ones (eg row major, not column
+      major), and add an axis argument. -> this is a bit tricky, actually, as
+      sndfile only supports interleaved data, where F order actually make sense. 
+      Not sure what to do
+    - ogg vorbis support ? libsndfile does not support ogg (yet). Maybe use the
+      reference lib, but this may be a bit complicated to support both library
+      at the same time.
diff --git a/telemeta/util/audiolab/build/lib/scikits/__init__.py b/telemeta/util/audiolab/build/lib/scikits/__init__.py
new file mode 100644 (file)
index 0000000..de40ea7
--- /dev/null
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)
diff --git a/telemeta/util/audiolab/build/lib/scikits/audiolab/__init__.py b/telemeta/util/audiolab/build/lib/scikits/audiolab/__init__.py
new file mode 100644 (file)
index 0000000..1291159
--- /dev/null
@@ -0,0 +1,35 @@
+#! /usr/bin/env python
+# Last Change: Mon Sep 10 07:00 PM 2007 J
+"""
+audiolab: a small toolbox to read, write and play audio to and from
+numpy arrays.
+
+audiolab provides two API:
+    - one similar to matlab: this gives you wavread, wavwrite functions really
+      similar to matlab's functions.
+    - a more complete API, which can be used to read, write to many audio file
+      (including wav, aiff, flac, au, IRCAM, htk, etc...), with IO capabilities
+      not available to matlab (seek, append data, etc...)
+
+It is a thin wrapper around libsndfile from Erik Castro Lopo.
+     
+Copyright (C) 2006-2007 Cournapeau David <cournape@gmail.com>
+
+LICENSE: audiolab is licensed under the LGPL, as is libsndfile itself. See
+COPYING.txt for details.  """
+
+from info import VERSION
+__version__ = VERSION
+
+from pysndfile import formatinfo, sndfile
+from pysndfile import supported_format, supported_endianness, \
+                                       supported_encoding
+#from scikits.audiolab.matapi import wavread, aiffread, flacread, auread, \
+#        sdifread, wavwrite, aiffwrite, flacwrite, auwrite, sdifwrite
+from matapi import *
+
+__all__ = filter(lambda s:not s.startswith('_'),dir())
+
+from numpy.testing import NumpyTest
+def test():
+    return NumpyTest().test()
diff --git a/telemeta/util/audiolab/build/lib/scikits/audiolab/info.py b/telemeta/util/audiolab/build/lib/scikits/audiolab/info.py
new file mode 100644 (file)
index 0000000..47dd67f
--- /dev/null
@@ -0,0 +1,2 @@
+VERSION = '0.8dev'
+ignore  = False
diff --git a/telemeta/util/audiolab/build/lib/scikits/audiolab/matapi.py b/telemeta/util/audiolab/build/lib/scikits/audiolab/matapi.py
new file mode 100644 (file)
index 0000000..1568fe9
--- /dev/null
@@ -0,0 +1,148 @@
+#! /usr/bin/env python
+# Last Change: Mon Sep 10 07:00 PM 2007 J
+
+# Copyright (C) 2006-2007 Cournapeau David <cournape@gmail.com>
+#
+# 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.1 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+"""This module implements functions to read and write to audio files easily
+(ala matlab: wavread, etc...)."""
+
+import numpy as N
+
+from pysndfile import formatinfo, sndfile
+from pysndfile import PyaudioException, FlacUnsupported
+
+__all__ = []
+_MATAPI_FORMAT = ['wav', 'aiff', 'au', 'sdif', 'flac']
+for i in _MATAPI_FORMAT:
+    __all__.extend(['%sread' % i, '%swrite' % i])
+
+# writer function factory
+def _writer_factory(name, format, def_fs, descr):
+    """ Create a writer function with fileformat described by format, default
+    sampling rate def_fs, and docstring descr."""
+    def basic_writer(data, filename, fs = def_fs, enc = format.get_encoding()):
+        """Common "template" to all write functions."""
+        if N.ndim(data) <= 1:
+            nc      = 1
+            nframes = N.size(data)
+        elif N.ndim(data) == 2: 
+            nc      = data.shape[1]
+            nframes = data.shape[0]
+        else:
+            RuntimeError("Only rank 0, 1, and 2 arrays supported as audio data")
+
+        hdl = sndfile(filename, 'write', format, nc, fs)
+        try:
+            hdl.write_frames(data, nframes)
+        finally:
+            hdl.close()
+    doc = \
+    """ wrapper around pysndfile to write %s file,
+    in a similar manner to matlab's wavwrite/auwrite and the likes.
+
+    OVERWRITES EXISTING FILE !
+
+    Args:
+        - data: a rank 0, 1 (mono) or 2 (one channel per col) numpy array
+        - filename: a string for the audio file name 
+        - fs: the sampling rate in Hz (%d Hz by default).
+        - enc: a string for the encoding such as 'pcm16', etc...(%s by
+          default). Not supported yet !
+
+    For a total control over options, such as endianness, append data to an
+    existing file, etc...  you should use sndfile class instances instead""" \
+            % (str(descr), def_fs, format.get_encoding())
+    basic_writer.__doc__    = doc
+    basic_writer.__name__   = name
+    return basic_writer
+    
+# template for reader functions
+def _reader_factory(name, filetype, descr):
+    """Factory for reader functions ala matlab."""
+    def basic_reader(filename, last = None, first = 0):
+        """Common "template" to all read functions."""
+        hdl = sndfile(filename, 'read')
+        try:
+            if not hdl.get_file_format() == filetype:
+                raise PyaudioException("%s is not a %s file (is %s)" \
+                        % (filename, filetype, hdl.get_file_format()))
+
+            fs = hdl.get_samplerate()
+            enc = hdl.get_encoding()
+            # Set the pointer to start position
+            nf  = hdl.seek(first, 1)
+            if not nf == first:
+                raise IOError("Error while seeking at starting position")
+
+            if last is None:
+                nframes = hdl.get_nframes() - first
+                data    = hdl.read_frames(nframes)
+            else:
+                data    = hdl.read_frames(last)
+        finally:
+            hdl.close()
+
+        return data, fs, enc
+    doc = \
+    """ wrapper around pysndfile to read a %s file in float64,
+    in a similar manner to matlab wavread/auread/etc...
+
+    Returns a tuple (data, fs, enc), where :
+        - data are the read data (one column per channel)
+        - fs, the sampling rate
+        - enc, a string which is the encoding of the file, such as 'pcm16', 
+        'float32', etc...
+
+    For a total control over options, such as output's dtype, etc..., 
+    you should use sndfile class instances instead""" % (str(descr),)
+    basic_reader.__doc__    = doc
+    basic_reader.__name__   = name
+    return basic_reader
+    
+wavread     = _reader_factory('wavread', 'wav', 
+                    formatinfo('wav', 'pcm16').get_major_str())
+auread      = _reader_factory('auread', 'au',
+                    formatinfo('au', 'pcm16').get_major_str())
+aiffread    = _reader_factory('aiffread', 'aiff', 
+                    formatinfo('aiff', 'pcm16').get_major_str())
+sdifread    = _reader_factory('sdifread', 'ircam', 
+                    formatinfo('ircam', 'pcm16').get_major_str())
+
+_f1          = formatinfo('wav', 'pcm16')
+wavwrite    = _writer_factory('wavwrite', _f1, 8000, _f1.get_major_str())
+
+_f2          = formatinfo('au', 'ulaw')
+auwrite     = _writer_factory('auwrite', _f2, 8000, _f2.get_major_str())
+
+_f3          = formatinfo('aiff', 'pcm16')
+aiffwrite   = _writer_factory('aiffwrite', _f3, 8000, _f3.get_major_str())
+
+_f4          = formatinfo('ircam', 'pcm16')
+sdifwrite   = _writer_factory('sdifwrite', _f4, 44100, _f4.get_major_str())
+
+try:
+    flacread    = _reader_factory('flacread', 'flac', 
+                        formatinfo('flac', 'pcm16').get_major_str())
+    _f5          = formatinfo('flac', 'pcm16')
+    flacwrite   = _writer_factory('flacwrite', _f5, 44100, _f5.get_major_str())
+except FlacUnsupported,e:
+    print e
+    print "Matlab API for FLAC is disabled"
+    def missing_flacread(*args):
+        raise UnimplementedError("Matlab API for FLAC is disabled on your "\
+                                 "installation")
+    flacread    = missing_flacread
+    flacwrite   = missing_flacread
diff --git a/telemeta/util/audiolab/build/lib/scikits/audiolab/pyaudioio.py b/telemeta/util/audiolab/build/lib/scikits/audiolab/pyaudioio.py
new file mode 100644 (file)
index 0000000..94c1e9f
--- /dev/null
@@ -0,0 +1,68 @@
+#! /usr/bin/env python
+# Last Change: Tue May 22 10:00 AM 2007 J
+
+# Copyright (C) 2006-2007 Cournapeau David <cournape@gmail.com>
+#
+# 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.1 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., 51
+# Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+# TODO:
+#   - find out why finally does not work with KeyboardInterrupt instances
+
+from tempfile import mkstemp
+from os import remove, popen
+
+from pysndfile import sndfile, formatinfo as format
+
+def play(input, sr = 22050):
+    """play(input, sr = 22050): "play" a numpy array input
+    to the audio device using aplay command, @ sampling rate
+    sr. 
+    
+    Warning: This is really crude, as it copies the numpy array
+    into an audio file before writing: I am too lazy to write
+    interfaces to also, windows and co..."""
+    # Check inputs are OK
+    if input.ndim   == 1:
+        nc      = 1
+        nframes = input.size
+    else:
+        (nframes, nc)   = input.shape
+
+    # Create tmp file
+    fd, filename    = mkstemp('py_player')
+
+    # Copy the data into it
+    b       = sndfile(filename, 'write', format('wav', 'pcm16'), nc, sr)
+    b.write_frames(input, nframes)
+    b.close()
+
+    # Play using an audio command
+    try:
+        cmd = "aplay %s" % filename
+        popen(cmd)
+        remove(filename)
+    except KeyboardInterrupt, inst:
+        remove(filename)
+        raise inst
+
+if __name__ == '__main__':
+    # Read the content of a file into numpy array, and play the numpy
+    # array using the play command
+    import numpy as N
+    sr      = 22050
+    # Play a really small noise to avoid screaming in loudspeakers
+    # or headphones.
+    noise   = 0.0001 * N.random.randn((sr))
+    play(noise, sr)
diff --git a/telemeta/util/audiolab/build/lib/scikits/audiolab/pysndfile.py b/telemeta/util/audiolab/build/lib/scikits/audiolab/pysndfile.py
new file mode 100644 (file)
index 0000000..2fea1fe
--- /dev/null
@@ -0,0 +1,992 @@
+#! /usr/bin/env python
+# Last Change: Wed Oct 03 05:00 PM 2007 J
+
+# Copyright (C) 2006-2007 Cournapeau David <cournape@gmail.com>
+#
+# 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.1 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+# vim:syntax=python
+
+# TODO:
+#   - import format classes so that we get meaningful information from an
+#   existing format
+#   - better API for reader/writer, including integer formats and partial
+#   reading
+#   - ability to get log of sndfile ?
+#   - check how to play sound under windows, OS X and other UNIX
+
+"""This module implements the wrappers around libsndfile."""
+
+__docformat__ = 'restructuredtext'
+
+#__all__ = ['sndfile', 'formatinfo']
+
+import copy
+import warnings
+
+#================
+# Load libsndfile
+#================
+import ctypes
+from ctypes import cdll, Structure, c_int, pointer, POINTER, \
+        create_string_buffer, c_char_p, sizeof, string_at
+try:
+    from ctypes import c_int64
+except ImportError, e:
+    print "Cannot import c_int64 from ctypes: if you are on ubuntu/debian," +\
+        " this is likely because ctypes was compiled with libffi. see" +\
+        " https://launchpad.net/ubuntu/+source/python2.5/+bug/71914"
+    raise e
+
+from numpy.ctypeslib import ndpointer
+CTYPES_MAJOR    = int(ctypes.__version__.split('.')[0])
+CTYPES_MINOR    = int(ctypes.__version__.split('.')[1])
+CTYPES_MICRO    = int(ctypes.__version__.split('.')[2])
+if CTYPES_MAJOR < 1 or (CTYPES_MINOR == 0 and CTYPES_MICRO < 1):
+    raise ImportError("version of ctypes is %s, expected at least %s" \
+            % (ctypes.__version__, '1.0.1'))
+import numpy as N
+
+_SND = cdll.LoadLibrary('/usr/lib/libsndfile.so.1')
+
+#=========================
+# Definition of constants
+#=========================
+# READ/WRITE Mode
+SFM = {
+       'SFM_WRITE'     : 0x20,
+       'SFM_RDWR'      : 0x30,
+       'SFM_READ'      : 0x10
+}
+
+# SF BOOL
+SF_BOOL = {
+       'SF_TRUE'       : 1,
+       'SF_FALSE'      : 0
+}
+
+# Format
+SF_FORMAT = {
+       'SF_FORMAT_VOX_ADPCM'   : 0x0021,
+       'SF_FORMAT_FLOAT'       : 0x0006,
+       'SF_FORMAT_PCM_S8'      : 0x0001,
+       'SF_FORMAT_IMA_ADPCM'   : 0x0012,
+       'SF_FORMAT_SVX' : 0x060000,
+       'SF_FORMAT_VOC' : 0x080000,
+       'SF_FORMAT_PCM_U8'      : 0x0005,
+       'SF_FORMAT_ALAW'        : 0x0011,
+       'SF_FORMAT_G721_32'     : 0x0030,
+       'SF_FORMAT_DWVW_N'      : 0x0043,
+       'SF_FORMAT_WAV' : 0x010000,
+       'SF_FORMAT_SD2' : 0x160000,
+       'SF_FORMAT_HTK' : 0x100000,
+       'SF_FORMAT_ENDMASK'     : 0x30000000,
+       'SF_FORMAT_DPCM_16'     : 0x0051,
+       'SF_FORMAT_DWVW_24'     : 0x0042,
+       'SF_FORMAT_PCM_32'      : 0x0004,
+       'SF_FORMAT_WAVEX'       : 0x130000,
+       'SF_FORMAT_DOUBLE'      : 0x0007,
+       'SF_FORMAT_NIST'        : 0x070000,
+       'SF_FORMAT_PCM_16'      : 0x0002,
+       'SF_FORMAT_RAW' : 0x040000,
+       'SF_FORMAT_W64' : 0x0B0000,
+       'SF_FORMAT_PVF' : 0x0E0000,
+       'SF_FORMAT_AU'  : 0x030000,
+       'SF_FORMAT_GSM610'      : 0x0020,
+       'SF_FORMAT_CAF' : 0x180000,
+       'SF_FORMAT_PAF' : 0x050000,
+       'SF_FORMAT_ULAW'        : 0x0010,
+       'SF_FORMAT_MAT4'        : 0x0C0000,
+       'SF_FORMAT_MAT5'        : 0x0D0000,
+       'SF_FORMAT_XI'  : 0x0F0000,
+       'SF_FORMAT_SUBMASK'     : 0x0000FFFF,
+       'SF_FORMAT_DPCM_8'      : 0x0050,
+       'SF_FORMAT_G723_24'     : 0x0031,
+       'SF_FORMAT_G723_40'     : 0x0032,
+       'SF_FORMAT_DWVW_16'     : 0x0041,
+       'SF_FORMAT_AIFF'        : 0x020000,
+       'SF_FORMAT_DWVW_12'     : 0x0040,
+       'SF_FORMAT_TYPEMASK'    : 0x0FFF0000,
+       'SF_FORMAT_FLAC'        : 0x170000,
+       'SF_FORMAT_PCM_24'      : 0x0003,
+       'SF_FORMAT_SDS' : 0x110000,
+       'SF_FORMAT_IRCAM'       : 0x0A0000,
+       'SF_FORMAT_MS_ADPCM'    : 0x0013,
+       'SF_FORMAT_AVR' : 0x120000
+}
+
+# ENDIANESS
+SF_ENDIAN = {
+       'SF_ENDIAN_BIG' : 0x20000000,
+       'SF_ENDIAN_FILE'        : 0x00000000,
+       'SF_ENDIAN_LITTLE'      : 0x10000000,
+       'SF_ENDIAN_CPU' : 0x30000000
+}
+
+# Commands
+SF_COMMAND = {
+       'SFC_GET_LIB_VERSION'   : 0x1000,
+       'SFC_CALC_SIGNAL_MAX'   : 0x1040,
+       'SFC_GET_DITHER_INFO'   : 0x10A3,
+       'SFC_GET_LOG_INFO'      : 0x1001,
+       'SFC_GET_FORMAT_SUBTYPE_COUNT'  : 0x1032,
+       'SFC_FILE_TRUNCATE'     : 0x1080,
+       'SFC_GET_INSTRUMENT'    : 0x10D0,
+       'SFC_UPDATE_HEADER_NOW' : 0x1060,
+       'SFC_SET_DITHER_ON_WRITE'       : 0x10A0,
+       'SFC_SET_NORM_DOUBLE'   : 0x1012,
+       'SFC_GET_CLIPPING'      : 0x10C1,
+       'SFC_SET_RAW_START_OFFSET'      : 0x1090,
+       'SFC_CALC_NORM_MAX_ALL_CHANNELS'        : 0x1043,
+       'SFC_SET_NORM_FLOAT'    : 0x1013,
+       'SFC_SET_ADD_DITHER_ON_WRITE'   : 0x1070,
+       'SFC_GET_NORM_FLOAT'    : 0x1011,
+       'SFC_GET_SIGNAL_MAX'    : 0x1044,
+       'SFC_GET_MAX_ALL_CHANNELS'      : 0x1045,
+       'SFC_GET_FORMAT_MAJOR'  : 0x1031,
+       'SFC_SET_INSTRUMENT'    : 0x10D1,
+       'SFC_CALC_MAX_ALL_CHANNELS'     : 0x1042,
+       'SFC_GET_DITHER_INFO_COUNT'     : 0x10A2,
+       'SFC_SET_BROADCAST_INFO'        : 0x10F1,
+       'SFC_SET_DITHER_ON_READ'        : 0x10A1,
+       'SFC_GET_FORMAT_MAJOR_COUNT'    : 0x1030,
+       'SFC_GET_FORMAT_INFO'   : 0x1028,
+       'SFC_GET_SIMPLE_FORMAT_COUNT'   : 0x1020,
+       'SFC_CALC_NORM_SIGNAL_MAX'      : 0x1041,
+       'SFC_GET_LOOP_INFO'     : 0x10E0,
+       'SFC_SET_ADD_PEAK_CHUNK'        : 0x1050,
+       'SFC_SET_ADD_DITHER_ON_READ'    : 0x1071,
+       'SFC_SET_SCALE_FLOAT_INT_READ'  : 0x1014,
+       'SFC_GET_FORMAT_SUBTYPE'        : 0x1033,
+       'SFC_TEST_IEEE_FLOAT_REPLACE'   : 0x6001,
+       'SFC_SET_UPDATE_HEADER_AUTO'    : 0x1061,
+       'SFC_GET_SIMPLE_FORMAT' : 0x1021,
+       'SFC_SET_CLIPPING'      : 0x10C0,
+       'SFC_GET_EMBED_FILE_INFO'       : 0x10B0,
+       'SFC_GET_BROADCAST_INFO'        : 0x10F0,
+       'SFC_GET_NORM_DOUBLE'   : 0x1010
+}
+
+SF_ERRORS = {
+       'SF_ERR_UNRECOGNISED_FORMAT'    : 1,
+       'SF_ERR_NO_ERROR'       : 0,
+       'SF_ERR_SYSTEM' : 2,
+       'SF_ERR_UNSUPPORTED_ENCODING'   : 4,
+       'SF_ERR_MALFORMED_FILE' : 3
+}
+
+# format equivalence: dic used to create internally
+# the right enum values from user friendly strings
+py_to_snd_encoding_dic    = {
+    'pcms8' : SF_FORMAT['SF_FORMAT_PCM_S8'],      
+    'pcm16' : SF_FORMAT['SF_FORMAT_PCM_16'],     
+    'pcm24' : SF_FORMAT['SF_FORMAT_PCM_24'],    
+    'pcm32' : SF_FORMAT['SF_FORMAT_PCM_32'],    
+
+    'pcmu8' : SF_FORMAT['SF_FORMAT_PCM_U8'],  
+
+    'float32' : SF_FORMAT['SF_FORMAT_FLOAT'],
+    'float64' : SF_FORMAT['SF_FORMAT_DOUBLE'],
+
+    'ulaw'      : SF_FORMAT['SF_FORMAT_ULAW'],
+    'alaw'      : SF_FORMAT['SF_FORMAT_ALAW'],
+    'ima_adpcm' : SF_FORMAT['SF_FORMAT_IMA_ADPCM'],
+    'ms_adpcm'  : SF_FORMAT['SF_FORMAT_MS_ADPCM'],
+
+    'gsm610'    : SF_FORMAT['SF_FORMAT_GSM610'],
+    'vox_adpcm' : SF_FORMAT['SF_FORMAT_VOX_ADPCM'],
+
+    'g721_32'   : SF_FORMAT['SF_FORMAT_G721_32'], 
+    'g723_24'   : SF_FORMAT['SF_FORMAT_G723_24'],
+    'g723_40'   : SF_FORMAT['SF_FORMAT_G723_40'],
+
+    'dww12' : SF_FORMAT['SF_FORMAT_DWVW_12'],
+    'dww16' : SF_FORMAT['SF_FORMAT_DWVW_16'],
+    'dww24' : SF_FORMAT['SF_FORMAT_DWVW_24'],
+    'dwwN'  : SF_FORMAT['SF_FORMAT_DWVW_N'],
+
+    'dpcm8' : SF_FORMAT['SF_FORMAT_DPCM_8'],
+    'dpcm16': SF_FORMAT['SF_FORMAT_DPCM_16']
+}
+
+py_to_snd_file_format_dic = {
+    'wav'   : SF_FORMAT['SF_FORMAT_WAV'],
+    'aiff'  : SF_FORMAT['SF_FORMAT_AIFF'],
+    'au'    : SF_FORMAT['SF_FORMAT_AU'],
+    'raw'   : SF_FORMAT['SF_FORMAT_RAW'],
+    'paf'   : SF_FORMAT['SF_FORMAT_PAF'],
+    'svx'   : SF_FORMAT['SF_FORMAT_SVX'],
+    'nist'  : SF_FORMAT['SF_FORMAT_NIST'],
+    'voc'   : SF_FORMAT['SF_FORMAT_VOC'],
+    'ircam' : SF_FORMAT['SF_FORMAT_IRCAM'],
+    'wav64' : SF_FORMAT['SF_FORMAT_W64'],
+    'mat4'  : SF_FORMAT['SF_FORMAT_MAT4'],
+    'mat5'  : SF_FORMAT['SF_FORMAT_MAT5'],
+    'pvf'   : SF_FORMAT['SF_FORMAT_PVF'],
+    'xi'    : SF_FORMAT['SF_FORMAT_XI'],
+    'htk'   : SF_FORMAT['SF_FORMAT_HTK'],
+    'sds'   : SF_FORMAT['SF_FORMAT_SDS'],
+    'avr'   : SF_FORMAT['SF_FORMAT_AVR'],
+    'wavex' : SF_FORMAT['SF_FORMAT_WAVEX'],
+    'sd2'   : SF_FORMAT['SF_FORMAT_SD2'],
+    'flac'  : SF_FORMAT['SF_FORMAT_FLAC'],
+    'caf'   : SF_FORMAT['SF_FORMAT_CAF']
+}
+
+py_to_snd_endianness_dic = {
+    'file'      : SF_ENDIAN['SF_ENDIAN_FILE'], 
+    'little'    : SF_ENDIAN['SF_ENDIAN_LITTLE'], 
+    'big'       : SF_ENDIAN['SF_ENDIAN_BIG'], 
+    'cpu'       : SF_ENDIAN['SF_ENDIAN_CPU']
+}
+
+# Those following dic are used internally to get user-friendly values from
+# sndfile enum
+SND_TO_PY_ENCODING = \
+        dict([(i, j) for j, i in py_to_snd_encoding_dic.items()])
+SND_TO_PY_FILE_FORMAT = \
+        dict([(i, j) for j, i in py_to_snd_file_format_dic.items()])
+SND_TO_PY_ENDIANNESS = \
+        dict([(i, j) for j, i in py_to_snd_endianness_dic.items()])
+
+#==========================================
+# Check that libsndfile is expected version
+#==========================================
+def get_libsndfile_version():
+    nverbuff = 256
+    verbuff = create_string_buffer(nverbuff)
+    n = _SND.sf_command(c_int(0), c_int(SF_COMMAND['SFC_GET_LIB_VERSION']), 
+            verbuff, nverbuff)
+    if n < 1:
+        raise Exception("Error while getting version of libsndfile")
+
+    # Transform the buffer into a string
+    ver = ""
+    for i in range(n):
+        ver += verbuff[i]
+
+    # Get major, minor and micro from version
+    version     = ver.split('-')[1]
+    prerelease  = 0
+    major, minor, micro = [i for i in version.split('.')]
+    try:
+        micro   = int(micro)
+    except ValueError,e:
+        print "micro is "  + str(micro) 
+        micro, prerelease   = micro.split('pre')
+
+    return int(major), int(minor), int(micro), prerelease
+
+MAJOR, MINOR, MICRO, PRERELEASE = get_libsndfile_version()
+if not(MAJOR == 1):
+    raise Exception("audiolab expects major version %d of libsndfile" % 1)
+if not(MICRO == 17):
+    if PRERELEASE == 0: 
+        prestr  = "No"
+    else:
+        prestr  = "%s" % PRERELEASE
+    print "WARNING libsndfile-%d.%d.%d (prerelease: %s) "\
+        "this has only been tested with libsndfile 1.0.17 for now, "\
+        "use at your own risk !" % (MAJOR, MINOR, MICRO, prestr)
+
+#================
+# Python wrappers
+#================
+
+#+++++++++++++++++
+# Public exception
+#+++++++++++++++++
+class PyaudioException(Exception):
+    pass
+
+class InvalidFormat(PyaudioException):
+    pass
+
+class PyaudioIOError(PyaudioException, IOError):
+    pass
+
+class WrappingError(PyaudioException):
+    pass
+
+class FlacUnsupported(RuntimeError, PyaudioException):
+    pass
+
+#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+# Private classes/function (Should not be used outside this file)
+#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+class _sf_info(Structure):
+    """Structure representing C structure SF_INFO"""
+    _fields_    = [('frames', c_int64),
+                ('samplerate', c_int),
+                ('channels', c_int),
+                ('format', c_int),
+                ('sections', c_int),
+                ('seekable', c_int)]
+    def __str__(self):
+        return "%d frames, sr = %d Hz, %d channels, format is %d" % \
+                (self.frames, self.samplerate, self.channels, self.format)
+
+class _sf_format_info(Structure):
+    """Structure representing C structure SF_FORMAT_INFO (useful for
+    sf_command )"""
+    _fields_    = [('format', c_int),
+                ('name', c_char_p),
+                ('extension', c_char_p)]
+    def __str__(self):
+        return "format hex is %#010x, name is %s, extension is %s" %  \
+                (self.format, self.name, self.extension)
+
+    def __repr__(self):
+        print self.__str__()
+
+class _sndfile(Structure):
+    pass
+
+sf_info_p = POINTER(_sf_info)
+sndfile_p = POINTER(_sndfile)
+
+# functions args
+# TODO: is there a way to ensure that arg1 is the right kind of pointer ?
+arg1    = c_char_p
+arg2    = c_int
+arg3    = sf_info_p
+_SND.sf_open.argtypes   = [arg1, arg2, arg3]
+_SND.sf_open.restype    = sndfile_p
+
+arg1    = sndfile_p
+_SND.sf_close.argtypes  = [arg1]
+_SND.sf_close.restype  = c_int
+
+arg1    = c_int
+arg2    = c_int
+arg3    = sf_info_p
+arg4    = c_int
+_SND.sf_open_fd.argtypes   = [arg1, arg2, arg3, arg4]
+_SND.sf_open_fd.restype    = sndfile_p
+
+arg1    = sndfile_p
+arg2    = ndpointer(dtype=N.float64)
+arg3    = c_int64
+
+# double function
+_SND.sf_readf_double.argtypes    = [arg1, arg2, arg3]
+_SND.sf_readf_double.restype     = c_int64
+
+_SND.sf_writef_double.argtypes    = [arg1, arg2, arg3]
+_SND.sf_writef_double.restype     = c_int64
+
+# float function
+arg1    = sndfile_p
+arg2    = ndpointer(dtype=N.float32)
+arg3    = c_int64
+_SND.sf_readf_float.argtypes    = [arg1, arg2, arg3]
+_SND.sf_readf_float.restype     = c_int64
+
+_SND.sf_writef_float.argtypes    = [arg1, arg2, arg3]
+_SND.sf_writef_float.restype     = c_int64
+
+# int function
+arg1    = sndfile_p
+arg2    = ndpointer(dtype=N.int32)
+arg3    = c_int64
+_SND.sf_readf_int.argtypes    = [arg1, arg2, arg3]
+_SND.sf_readf_int.restype     = c_int64
+
+_SND.sf_writef_int.argtypes    = [arg1, arg2, arg3]
+_SND.sf_writef_int.restype     = c_int64
+
+# short function
+arg1    = sndfile_p
+arg2    = ndpointer(dtype=N.int16)
+arg3    = c_int64
+_SND.sf_readf_short.argtypes    = [arg1, arg2, arg3]
+_SND.sf_readf_short.restype     = c_int64
+
+_SND.sf_writef_short.argtypes    = [arg1, arg2, arg3]
+_SND.sf_writef_short.restype     = c_int64
+
+# Error functions
+arg1    = sndfile_p
+_SND.sf_strerror.argtypes   = [arg1]
+_SND.sf_strerror.restype    = c_char_p
+
+# Function to sync data to file
+arg1    = sndfile_p
+_SND.sf_write_sync.argtypes = [arg1]
+
+# Function to seek
+arg1    = sndfile_p
+arg2    = c_int64
+arg3    = c_int
+_SND.sf_seek.argtypes = [arg1, arg2, arg3]
+_SND.sf_seek.restype  = c_int64
+
+# To pass when a C function needs a NULL arg
+_cNULL = POINTER(c_int)()
+
+class _format_from_internal:
+    """Class to handle audio format with sndfile. 
+    
+    DO NOT USE THIS CLASS OUTSIDE pysndfile.py MODULE: YOU MAY CRASH YOUR
+    INTERPRETER !
+    
+    Basically, we have 3 classes of parameters:
+        - the main format: (major format), like wav, aiff, etc...
+        - the subtype format: pcm, bits resolution
+        - endianness: little, big, as the cpu, default of the format
+
+    This class encapsulates those parameters, and can build a representation of
+    them from the format integer of sf_info. This should *NOT* be used, use
+    format instead, which inherits this class to build a valid format from user
+    friendly arguments.  """
+    def __init__(self, format_integer):
+        # Get the internal values which corresponds to the values libsndfile
+        # can understand
+        self._int_type = format_integer & SF_FORMAT['SF_FORMAT_TYPEMASK']
+        self._int_encoding = format_integer & SF_FORMAT['SF_FORMAT_SUBMASK']
+        self._int_endianness = format_integer & SF_FORMAT['SF_FORMAT_ENDMASK']
+
+        assert format_integer == self._int_type | self._int_encoding |\
+            self._int_endianness
+        self._format    = format_integer
+
+        # Now, we need to test if the combination of format, encoding and 
+        # endianness is valid. sf_format_check needs also samplerate and
+        # channel information, so just give a fake samplerate and channel
+        # number. Looking at sndfile.c, it looks like samplerate is never
+        # actually checked, and that when channels is checked, it is only
+        # checked against values different than 1 or 2, so giving a value of
+        # 1 to channel should be ok.
+        self._sfinfo            = _sf_info()
+        self._sfinfo.channels   = 1
+        self._sfinfo.samplerate = 8000
+        self._sfinfo.format     = self._format
+
+        ret = _SND.sf_format_check(pointer(self._sfinfo))
+        if ret is not SF_BOOL['SF_TRUE']:
+            raise InvalidFormat()
+
+        # Get the sndfile string description of the format type
+        blop = _sf_format_info()
+        blop.format = self._int_type
+        st = _SND.sf_command(_cNULL, SF_COMMAND['SFC_GET_FORMAT_INFO'], \
+                pointer(blop), sizeof(blop))
+        if st is not 0:
+            if SND_TO_PY_FILE_FORMAT[self._int_type] == 'flac':
+                raise FlacUnsupported("Flac is not supported by your version"\
+                        " of libsndfile")
+            else:
+                raise WrappingError("Could not get format string for format "\
+                        "%d, " % blop.format + "please report this problem "\
+                        "to the maintainer")
+                    
+        self.format_str = blop.name
+
+        # Get the sndfile string description of the format subtype
+        blop.format = self._int_encoding
+        st = _SND.sf_command(_cNULL, SF_COMMAND['SFC_GET_FORMAT_INFO'], \
+                pointer(blop), sizeof(blop))
+        if st is not 0:
+            raise WrappingError()
+                    
+        self.encoding_str   = blop.name
+
+    def get_format_raw(self):
+        """Do not use this function !"""
+        return self._format
+
+    def get_major_str(self):
+        """Do not use this function !"""
+        return self.format_str
+
+    def get_encoding_str(self):
+        """Do not use this function !"""
+        return self.encoding_str
+
+    def get_file_format(self):
+        """return user friendly file format string"""
+        return SND_TO_PY_FILE_FORMAT[self._int_type]
+
+    def get_encoding(self):
+        """return user friendly encoding string"""
+        return SND_TO_PY_ENCODING[self._int_encoding]
+
+    def get_endianness(self):
+        """return user friendly file format string"""
+        return SND_TO_PY_ENDIANNESS[self._int_endianness]
+
+    # Various function
+    def is_type(self, t):
+        return (self._format & SF_FORMAT['SF_FORMAT_TYPEMASK']) \
+                == py_to_snd_file_format_dic[t]
+
+    # Syntactic sugar
+    def __str__(self):
+        return  "Major Format: %s, Encoding Format: %s" % \
+                (self.format_str, self.encoding_str)
+
+    def __repr__(self):
+        return self.__str__()
+
+#+++++++++++
+# Public API
+#+++++++++++
+
+class formatinfo(_format_from_internal):
+    def __init__(self, type = 'wav', encoding = 'pcm16', endianness = 'file'):
+        """Build a valid format usable by the sndfile class when opening an
+        audio file for writing. 
+        
+        Blah blah
+
+        :Parameters:
+            type : string
+                represents the major file format (wav, etc...).
+            encoding : string
+                represents the encoding (pcm16, etc..).
+            endianness : string
+                represents the endianess.
+            
+        Notes
+        -----
+        
+        Valid type strings are listed by file_format_dic.keys() Valid encoding
+        strings are listed by encoding_dic.keys() Valid endianness strings are
+        listed by endianness_dic.keys() """
+        # Keep the arguments
+        self.type       = type
+        self.encoding   = encoding
+        self.endianness = endianness
+
+        # Get the internal values which corresponds to the values libsndfile
+        # can understand
+        self._int_type          = py_to_snd_file_format_dic[type]
+        self._int_encoding      = py_to_snd_encoding_dic[encoding]
+        self._int_endianness    = py_to_snd_endianness_dic[endianness]
+
+        # Build the internal integer from parameters, and pass it to the super
+        # class, which will do all the work
+        format  = self._int_type | self._int_encoding | self._int_endianness
+
+        _format_from_internal.__init__(self, format)
+
+class sndfile:
+    """Main class to open, read and write audio files"""
+    def __init__(self, filename, mode = 'read', format = None, channels = 0, \
+            samplerate = 0):
+        """Create an instance of sndfile.
+
+        :Parameters:
+            filename : string or int
+                name of the file to open (string), or file descriptor (integer)
+            mode : string
+                'read' for read, 'write' for write, or 'rwrite' for read and
+                write.
+            format : formatinfo
+                when opening a new file for writing, give the format to write
+                in.
+            channels : int
+                number of channels.
+            samplerate : int
+                sampling rate.
+
+        :Returns:
+            sndfile: a valid sndfile object 
+            
+        Notes
+        -----
+        
+        format, channels and samplerate need to be given only in the write
+        modes and for raw files.  """
+        # Check the mode is one of the expected values
+        if mode == 'read':
+            sfmode  = SFM['SFM_READ']
+        elif mode == 'write':
+            sfmode  = SFM['SFM_WRITE']
+            if format == None:
+                raise Exception("For write mode, you should provide"\
+                        "a format argument !")
+        elif mode == 'rwrite':
+            sfmode  = SFM['SFM_RDWR']
+            if format == None:
+                raise Exception("For write mode, you should provide"\
+                        "a format argument !")
+        else:
+            raise Exception("mode %s not recognized" % str(mode))
+
+        sfinfo = _sf_info()
+        sfinfo_p = pointer(sfinfo)
+
+        # Fill the sfinfo struct
+        sfinfo.frames       = c_int64(0)
+        if type(channels) is not int:
+            print "Warning, channels is converted to int, was %s" % \
+                    str(type(channels))
+            sfinfo.channels     = int(channels)
+        else:
+            sfinfo.channels     = channels
+
+        if type(samplerate) is not int:
+            print "Warning, sampling rate is converted to int, was %s" % \
+                    str(type(samplerate))
+            sfinfo.samplerate   = int(samplerate)
+        else:
+            sfinfo.samplerate   = samplerate
+
+        sfinfo.sections     = 0
+        sfinfo.seekable     = False
+        if mode == 'read' and format == None:
+            sfinfo.format   = 0
+        else:
+            if sfinfo.channels > 256 or sfinfo.channels < 1:
+                msg = "number of channels is %d, expected " \
+                        "between 1 and 256" % sfinfo.channels
+                raise RuntimeError(msg)
+            sfinfo.format   = format.get_format_raw()
+            if not _SND.sf_format_check(sfinfo_p):
+                msg = "unknown error in format specification ?" +\
+                        " Please report this to the author"
+                raise WrappingError()
+
+        sfinfo_p = pointer(sfinfo)
+        self._sfmode = sfmode
+        self.hdl = 0
+
+        if type(filename) == int:
+            res = _SND.sf_open_fd(filename, self._sfmode, sfinfo_p, 
+                                  SF_BOOL['SF_FALSE'])
+            self._byfd = True
+            self.fd = filename
+            self.filename = ""
+        else:
+            res = _SND.sf_open(filename, self._sfmode, sfinfo_p)
+            self._byfd = False
+            self.filename = filename
+
+        try:
+            # If res is NULL, this statement will raise a ValueError exception
+            a = res[0]
+        except ValueError:
+            if self._byfd:
+                msg = "error while opening file descriptor %d\n\t->" % self.fd
+            else:
+                msg = "error while opening file %s\n\t-> " % self.filename
+            msg += _SND.sf_strerror(res)
+            if self._byfd:
+                msg += """
+(Check that the mode argument passed to sndfile is the same than the one used
+when getting the file descriptor, eg do not pass 'read' to sndfile if you
+passed 'write' to open to get the file descriptor. If you are on win32, you are
+out of luck, because its implementation of POSIX open is broken)"""
+            raise IOError("error while opening %s\n\t->%s" % (filename, msg))
+
+        if mode == 'read':
+            tmp = _format_from_internal(sfinfo.format)
+            self._format = formatinfo(tmp.get_file_format(), \
+                    tmp.get_encoding(), tmp.get_endianness())
+        else:
+            self._format     = format
+
+        self._sfinfo    = sfinfo
+        self.hdl        = res
+
+        if self.get_file_format() == 'flac':
+            def SeekNotEnabled(self, *args):
+                raise FlacUnsupported("seek not supported on Flac by default,"\
+                        " because\n some version of FLAC libraries are buggy."\
+                        " Read FLAC_SUPPORT.txt")
+            self.seek   = SeekNotEnabled 
+        else:
+            self.seek = self._seek
+
+    def __del__(self, close_func = _SND.sf_close):
+        # Stupid python needs the close_func, otherwise
+        # it may clean ctypes before calling here
+        if hasattr(self,'hdl'):
+            if not(self.hdl == 0):
+                close_func(self.hdl)
+                self.hdl    = 0
+
+    def close(self):
+        """close the file."""
+        self.__del__()
+
+    def sync(self):
+        """call the operating system's function to force the writing of all
+        file cache buffers to disk the file. 
+        
+        No effect if file is open as read"""
+        _SND.sf_write_sync(self.hdl)
+
+    def _seek(self, offset, whence = 0, mode = 'rw'):
+        """similar to python seek function, taking only in account audio data.
+        
+        :Parameters:
+            offset : int
+                the number of frames (eg two samples for stereo files) to move
+                relatively to position set by whence.
+            whence : int
+                only 0 (beginning), 1 (current) and 2 (end of the file) are
+                valid.
+            mode : string
+                If set to 'rw', both read and write pointers are updated. If
+                'r' is given, only read pointer is updated, if 'w', only the
+                write one is (this may of course make sense only if you open
+                the file in a certain mode).
+
+        Notes
+        -----
+        
+        - one only takes into accound audio data. 
+        - if an invalid seek is given (beyond or before the file), a
+          PyaudioIOError is launched."""
+        c_offset    = _num2int64(offset)
+        if mode == 'rw':
+            # Update both read and write pointers
+            st  = _SND.sf_seek(self.hdl, c_offset, whence)
+        elif mode == 'r':
+            whence = whence | SFM['SFM_READ']
+            st  = _SND.sf_seek(self.hdl, c_offset, whence)
+        elif mode == 'w':
+            whence = whence | SFM['SFM_WRITE']
+            st  = _SND.sf_seek(self.hdl, c_offset, whence)
+        else:
+            raise ValueError("mode should be one of 'r', 'w' or 'rw' only")
+
+        if st == -1:
+            msg = "Error while seeking, libsndfile error is %s" \
+                    % (_SND.sf_strerror(self.hdl))
+            raise PyaudioIOError(msg)
+        return st
+
+    # Functions to get informations about the file
+    def get_nframes(self):
+        """ Return the number of frames of the file"""
+        if self._sfmode == SFM['SFM_READ']:
+            # XXX: is this reliable for any file (think pipe and co ?)
+            return self._sfinfo.frames
+        else:
+            # In write/rwrite mode, the only reliable way to get the number of
+            # frames is to use seek.
+            raise NotImplementedError("Sorry, getting the current number of"
+                    "frames in write modes is not supported yet")
+    
+    def get_samplerate(self):
+        """ Return the samplerate in Hz of the file"""
+        return self._sfinfo.samplerate
+    
+    def get_channels(self):
+        """ Return the number of channels of the file"""
+        return self._sfinfo.channels
+    
+    def get_file_format(self):
+        """return user friendly file format string"""
+        return SND_TO_PY_FILE_FORMAT[self._format._int_type]
+
+    def get_encoding(self):
+        """return user friendly encoding string"""
+        return SND_TO_PY_ENCODING[self._format._int_encoding]
+
+    def get_endianness(self):
+        """return user friendly file format string"""
+        return SND_TO_PY_ENDIANNESS[self._format._int_endianness]
+
+    #------------------
+    # Functions to read
+    #------------------
+    def read_frames(self, nframes, dtype = N.float64):
+        """Read nframes frames of the file.
+        
+        :Parameters:
+            nframes : int
+                number of frames to read.
+            dtype : numpy dtype
+                dtype of the returned array containing read data (see note).
+        
+        Notes
+        -----
+        
+        - read_frames updates the read pointer.
+        - One column is one channel.
+        - if float are requested when the file contains integer data, you will
+          get normalized data (that is the max possible integer will be 1.0,
+          and the minimal possible value -1.0).
+        - if integers are requested when the file contains floating point data,
+          it may give wrong results because there is an ambiguity: if the
+          floating data are normalized, you can get a file with only 0 !
+          Getting integer data from files encoded in normalized floating point
+          is not supported (yet: sndfile supports it).""" 
+        c_nframes   = _num2int64(nframes)
+        if c_nframes < 0:
+            raise ValueError("number of frames has to be >= 0")
+
+        # XXX: inout argument
+        if self._sfinfo.channels > 1:
+            y           = N.zeros((nframes, self._sfinfo.channels), dtype)
+        else:
+            y           = N.zeros(nframes, dtype)
+
+        if dtype == N.float64:
+            res         = _SND.sf_readf_double(self.hdl, y, c_nframes)
+        elif dtype == N.float32:
+            res         = _SND.sf_readf_float(self.hdl, y, c_nframes)
+        elif dtype == N.int32:
+            res         = _SND.sf_readf_int(self.hdl, y, c_nframes)
+        elif dtype == N.int16:
+            res         = _SND.sf_readf_short(self.hdl, y, c_nframes)
+        else:
+            RuntimeError("Sorry, only float, double, int and short read " + \
+                    "supported for now")
+
+        if not(res == nframes):
+            msg = "Read %d frames, expected to read %d" % (res, nframes)
+            msg += ", libsndfile last msg is \n\t%s" \
+                    % _SND.sf_strerror(self.hdl)
+            raise IOError(msg)
+
+        return y
+
+    #-------------------
+    # Functions to write
+    #-------------------
+    # TODO: Think about overflow vs type of input, etc...
+    def write_frames(self, input, nframes = -1):
+        """write data to file.
+        
+        :Parameters:
+            input : ndarray
+                array containing data to write.  
+            nframes : int
+                number of frames to write.
+
+        Notes
+        -----
+
+        - one channel is one column
+        - updates the write pointer.
+        - if float are given when the file contains integer data, you should
+          put normalized data (that is the range [-1..1] will be written as the
+          maximum range allowed by the integer bitwidth)."""
+        # First, get the number of channels and frames from input
+        if input.ndim   == 1:
+            nc      = 1
+        else:
+            if input.ndim > 2:
+                raise Exception("Expect array of rank <= 2, got %d" \
+                        % input.ndim)
+            nc = input.shape[1]
+
+        if nframes == -1:
+            nframes = N.size(input)
+        # Number of channels should be the one expected
+        if not(nc == self._sfinfo.channels):
+            raise Exception("Expected %d channels, got %d" % \
+                    (self._sfinfo.channels, nc))
+
+        # Writing to the file
+        c_nframes   = _num2int64(nframes)
+        if c_nframes < 0:
+            raise ValueError("number of frames has to be >= 0")
+
+        input = N.require(input, requirements = 'C')
+
+        if input.dtype == N.float32:
+            if self._check_overflow(input):
+                warnings.warn("Warning, overflow detected when writing.")
+            res         = _SND.sf_writef_float(self.hdl, input, c_nframes)
+        elif input.dtype == N.float64:
+            self._check_overflow(input)
+            if self._check_overflow(input):
+                warnings.warn("Warning, overflow detected when writing.")
+            res         = _SND.sf_writef_double(self.hdl, input, c_nframes)
+        elif input.dtype == N.int32:
+            res         = _SND.sf_writef_int(self.hdl, input, c_nframes)
+        elif input.dtype == N.int16:
+            res         = _SND.sf_writef_short(self.hdl, input, c_nframes)
+        else:
+            raise Exception("type of input not understood: input should"
+                " be float64 or float32""")
+
+        if not(res == nframes):
+            raise IOError("write %d frames, expected to write %d" \
+                    % res, nframes)
+
+    def _check_overflow(self, data):
+        if N.max(data ** 2) >= 1.:
+            return True
+        return False
+
+    # Syntactic sugar
+    def __repr__(self):
+        return self.__str__()
+
+    def __str__(self):
+        repstr = "----------------------------------------\n"
+        if self._byfd:
+            repstr  += "File        : %d (opened by file descriptor)\n" % self.fd
+        else:
+            repstr  += "File        : %s\n" % self.filename
+        repstr  += "Channels    : %d\n" % self._sfinfo.channels
+        repstr  += "Sample rate : %d\n" % self._sfinfo.samplerate
+        repstr  += "Frames      : %d\n" % self._sfinfo.frames
+        repstr  += "Raw Format  : %#010x -> %s\n" % \
+                (self._format.get_format_raw(), self._format.get_major_str())
+        repstr  += "File format : %s\n" % self.get_file_format()
+        repstr  += "Encoding    : %s\n" % self.get_encoding()
+        repstr  += "Endianness  : %s\n" % self.get_endianness()
+        repstr  += "Sections    : %d\n" % self._sfinfo.sections
+        if self._sfinfo.seekable:
+            seek    = 'True'
+        else:
+            seek    = 'False'
+        repstr  += "Seekable    : %s\n" % seek
+        repstr  += "Duration    : %s\n" % self._generate_duration_str()
+        return repstr
+
+    def _generate_duration_str(self):
+        if self._sfinfo.samplerate < 1:
+            return None
+        tsec    = self._sfinfo.frames / self._sfinfo.samplerate
+        hrs     = tsec / 60 / 60
+        tsec    = tsec % (60 ** 2)
+        mins    = tsec / 60
+        tsec    = tsec % 60
+        secs    = tsec
+        ms      = 1000 * self._sfinfo.frames / self._sfinfo.samplerate % 1000
+
+        return "%02d:%02d:%02d.%3d" % (hrs, mins, secs, ms)
+
+def supported_format():
+    # XXX: broken
+    return py_to_snd_file_format_dic.keys()
+
+def supported_endianness():
+    # XXX: broken
+    return py_to_snd_endianness_dic.keys()
+
+def supported_encoding():
+    # XXX: broken
+    return py_to_snd_encoding_dic.keys()
+
+def _num2int64(value):
+    """ Convert a python objet to a c_int64, safely."""
+    if not (type(value) == int or type(value) == long):
+        value = long(value)
+        print "Warning, converting %s to long" % str(value)
+    c_value = c_int64(value)
+    if not c_value.value == value:
+        raise RuntimeError("Error while converting %s to a c_int64"\
+            ", maybe %s is too big ?" % str(value))
+    return c_value
diff --git a/telemeta/util/audiolab/build/lib/scikits/audiolab/tests/__init__.py b/telemeta/util/audiolab/build/lib/scikits/audiolab/tests/__init__.py
new file mode 100644 (file)
index 0000000..7f2fbc0
--- /dev/null
@@ -0,0 +1,2 @@
+#! /usr/bin/env python
+# Last Change: Mon May 21 12:00 PM 2007 J
diff --git a/telemeta/util/audiolab/build/lib/scikits/audiolab/tests/test_matapi.py b/telemeta/util/audiolab/build/lib/scikits/audiolab/tests/test_matapi.py
new file mode 100644 (file)
index 0000000..fe17b8e
--- /dev/null
@@ -0,0 +1,164 @@
+#! /usr/bin/env python
+# Last Change: Tue Jul 17 11:00 AM 2007 J
+from os.path import join, dirname
+from os import remove
+from tempfile import mkstemp
+
+from numpy.testing import *
+import numpy as N
+
+set_package_path()
+from audiolab.matapi import wavread, auread, aiffread, sdifread, flacread
+from audiolab.matapi import wavwrite, auwrite, aiffwrite, sdifwrite, flacwrite
+from audiolab.pysndfile import PyaudioException, sndfile, formatinfo as audio_format
+from audiolab.pysndfile import FlacUnsupported
+restore_path()
+
+#Optional:
+set_local_path()
+# import modules that are located in the same directory as this file.
+from testcommon import open_tmp_file, close_tmp_file
+restore_path()
+
+class test_audiolab(NumpyTestCase):
+    def _test_read(self, func, format, filext):
+       # Create a tmp audio file, write some random data into it, and check it
+       # is the expected data when read from a function from the matapi.
+        rfd, fd, cfilename   = open_tmp_file('pysndfiletest.' + filext)
+        try:
+            nbuff = 22050
+            noise = 0.1 * N.random.randn(nbuff)
+
+            # Open the copy file for writing
+            b = sndfile(cfilename, 'write', format, 1, nbuff)
+            b.write_frames(noise, nbuff)
+            b.close()
+
+            # Reread the data
+            b = sndfile(cfilename, 'read')
+            rcnoise = b.read_frames(nbuff)
+            b.close()
+
+            rnoise  = func(cfilename)[0]
+
+            assert_array_equal(rnoise, rcnoise)
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_wavread(self):
+        """ Check wavread """
+        self._test_read(wavread, audio_format('wav', 'pcm16', 'file'), 'wav') 
+
+    def test_flacread(self):
+        """ Check flacread """
+        try:
+            self._test_read(flacread, audio_format('flac', 'pcm16', 'file'), 'flac') 
+        except FlacUnsupported:
+            print "Flac unsupported, flacread not tested"
+
+    def test_auread(self):
+        """ Check auread """
+        self._test_read(auread, audio_format('au', 'ulaw', 'file'), 'au') 
+
+    def test_aiffread(self):
+        """ Check aiffread """
+        self._test_read(aiffread, audio_format('aiff', 'pcm16', 'file'), 'aiff') 
+
+    def test_sdifread(self):
+        """ Check sdifread (ircam format) """
+        self._test_read(sdifread, audio_format('ircam', 'pcm16', 'file'), 'sdif') 
+
+    def test_bad_wavread(self):
+        """ Check wavread on bad file"""
+        # Create a tmp audio file with non wav format, write some random data into it, 
+        # and check it can not be opened by wavread
+        rfd, fd, cfilename   = open_tmp_file('pysndfiletest.wav')
+        try:
+            nbuff   = 22050
+            noise   = 0.1 * N.random.randn(nbuff)
+
+            # Open the copy file for writing
+            format  = audio_format('aiff', 'pcm16')
+            b       = sndfile(cfilename, 'write', format, 1, nbuff)
+
+            b.write_frames(noise, nbuff)
+
+            b.close()
+
+            b   = sndfile(cfilename, 'read')
+            rcnoise = b.read_frames(nbuff)
+            b.close()
+
+            try:
+                rnoise  = wavread(cfilename)[0]
+                raise Exception("wavread on non wav file succeded, expected to fail")
+            except PyaudioException, e:
+                pass
+                #print str(e) + ", as expected"
+
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def _test_write(self, func, format, filext):
+        """ Check *write functions from matpi """
+        rfd1, fd1, cfilename1  = open_tmp_file('pysndfiletest.' + filext)
+        rfd2, fd2, cfilename2  = open_tmp_file('pysndfiletest.' + filext)
+        try:
+            nbuff   = 22050
+            fs      = nbuff
+            noise   = 0.1 * N.random.randn(nbuff)
+
+            # Open the first file for writing with sndfile
+            b       = sndfile(cfilename1, 'write', format, 1, fs)
+
+            b.write_frames(noise, nbuff)
+
+            b.close()
+
+            # Write same data with wavwrite
+            func(noise, cfilename2, fs)
+
+            # Compare if both files have same hash
+            f1  = open(cfilename1)
+            f2  = open(cfilename2)
+
+            import md5
+
+            m1  = md5.new()
+            m2  = md5.new()
+
+            m1.update(f1.read())
+            m2.update(f2.read())
+
+           f1.close()
+           f2.close()
+            assert m1.hexdigest() == m2.hexdigest()
+        finally:
+            close_tmp_file(rfd1, cfilename1)
+            close_tmp_file(rfd2, cfilename2)
+
+    def test_wavwrite(self):
+        """ Check wavwrite """
+        self._test_write(wavwrite, audio_format('wav', 'pcm16', 'file'), 'wav')
+
+    def test_aiffwrite(self):
+        """ Check aiffwrite """
+        self._test_write(aiffwrite, audio_format('aiff', 'pcm16', 'file'), 'aiff')
+
+    def test_auwrite(self):
+        """ Check wavwrite """
+        self._test_write(auwrite, audio_format('au', 'ulaw', 'file'), 'au')
+
+    def test_sdifwrite(self):
+        """ Check wavwrite """
+        self._test_write(sdifwrite, audio_format('ircam', 'pcm16', 'file'), 'sdif')
+
+    def test_flacwrite(self):
+        """ Check flacwrite """
+        try:
+            self._test_write(flacwrite, audio_format('flac', 'pcm16', 'file'), 'flac')
+        except FlacUnsupported:
+            print "Flac unsupported, flacwrite not tested"
+
+if __name__ == "__main__":
+    NumpyTest().run()
diff --git a/telemeta/util/audiolab/build/lib/scikits/audiolab/tests/test_pysndfile.py b/telemeta/util/audiolab/build/lib/scikits/audiolab/tests/test_pysndfile.py
new file mode 100644 (file)
index 0000000..632a4bc
--- /dev/null
@@ -0,0 +1,396 @@
+#! /usr/bin/env python
+# Last Change: Tue Jul 17 11:00 AM 2007 J
+"""Test for the sndfile class."""
+from os.path import join, dirname
+import os
+import sys
+
+from numpy.testing import NumpyTestCase, assert_array_equal, NumpyTest, \
+        assert_array_almost_equal, set_package_path, restore_path, set_local_path
+import numpy as N
+
+set_package_path()
+from audiolab import pysndfile
+from audiolab.pysndfile import sndfile, formatinfo as audio_format
+restore_path()
+
+set_local_path()
+from testcommon import open_tmp_file, close_tmp_file
+restore_path()
+
+# XXX: there is a lot to refactor here
+class test_pysndfile(NumpyTestCase):
+    def test_basic_io(self):
+        """ Check open, close and basic read/write"""
+        # dirty !
+        ofilename = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+        rfd, fd, cfilename = open_tmp_file('pysndfiletest.wav')
+        try:
+            nbuff = 22050
+
+            # Open the test file for reading
+            a       = sndfile(ofilename, 'read')
+            nframes = a.get_nframes()
+
+            # Open the copy file for writing
+            format  = audio_format('wav', 'pcm16')
+            b = sndfile(fd, 'write', format, a.get_channels(),
+                    a.get_samplerate())
+
+            # Copy the data
+            for i in range(nframes / nbuff):
+                tmpa    = a.read_frames(nbuff)
+                assert tmpa.dtype == N.float
+                b.write_frames(tmpa, nbuff)
+            nrem    = nframes % nbuff
+            tmpa    = a.read_frames(nrem)
+            assert tmpa.dtype == N.float
+            b.write_frames(tmpa, nrem)
+
+            a.close()
+            b.close()
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+
+    def test_basic_io_fd(self):
+        """ Check open from fd works"""
+        # dirty !
+        if sys.platform == 'win32':
+            print "Not testing opening by fd because does not work on win32"
+        else:
+            ofilename = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+            fd = os.open(ofilename, os.O_RDONLY)
+            hdl = sndfile(fd, 'read')
+            hdl.close()
+
+    def test_raw(self):
+        rawname = join(dirname(pysndfile.__file__), 'test_data', 'test.raw')
+        format  = audio_format('raw', 'pcm16', 'little')
+        a       = sndfile(rawname, 'read', format, 1, 11025)
+        assert a.get_nframes() == 11290
+        a.close()
+
+    def test_float64(self):
+        """Check float64 write/read works"""
+        # dirty !
+        ofilename = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+        rfd, fd, cfilename   = open_tmp_file('pysndfiletest.wav')
+        try:
+            nbuff           = 22050
+
+            # Open the test file for reading
+            a       = sndfile(ofilename, 'read')
+            nframes = a.get_nframes()
+
+            # Open the copy file for writing
+            format  = audio_format('wav', 'float64')
+            b       = sndfile(fd, 'write', format, a.get_channels(), 
+                    a.get_samplerate())
+
+            # Copy the data in the wav file
+            for i in range(nframes / nbuff):
+                tmpa    = a.read_frames(nbuff, dtype = N.float64)
+                assert tmpa.dtype == N.float64
+                b.write_frames(tmpa, nbuff)
+            nrem    = nframes % nbuff
+            tmpa    = a.read_frames(nrem)
+            b.write_frames(tmpa, nrem)
+
+            a.close()
+            b.close()
+
+            # Now, reopen both files in for reading, and check data are
+            # the same
+            a       = sndfile(ofilename, 'read')
+            b       = sndfile(cfilename, 'read')
+            for i in range(nframes / nbuff):
+                tmpa    = a.read_frames(nbuff, dtype = N.float64)
+                tmpb    = b.read_frames(nbuff, dtype = N.float64)
+                assert_array_equal(tmpa, tmpb)
+            
+            a.close()
+            b.close()
+
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_float32(self):
+        """Check float write/read works"""
+        # dirty !
+        ofilename = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+        rfd, fd, cfilename = open_tmp_file('pysndfiletest.wav')
+        try:
+            nbuff           = 22050
+
+            # Open the test file for reading
+            a       = sndfile(ofilename, 'read')
+            nframes = a.get_nframes()
+
+            # Open the copy file for writing
+            format  = audio_format('wav', 'float32')
+            b       = sndfile(fd, 'write', format, a.get_channels(), 
+                    a.get_samplerate())
+
+            # Copy the data in the wav file
+            for i in range(nframes / nbuff):
+                tmpa    = a.read_frames(nbuff, dtype = N.float32)
+                assert tmpa.dtype == N.float32
+                b.write_frames(tmpa, nbuff)
+            nrem    = nframes % nbuff
+            tmpa    = a.read_frames(nrem)
+            b.write_frames(tmpa, nrem)
+
+            a.close()
+            b.close()
+
+            # Now, reopen both files in for reading, and check data are
+            # the same
+            a       = sndfile(ofilename, 'read')
+            b       = sndfile(cfilename, 'read')
+            for i in range(nframes / nbuff):
+                tmpa    = a.read_frames(nbuff, dtype = N.float32)
+                tmpb    = b.read_frames(nbuff, dtype = N.float32)
+                assert_array_equal(tmpa, tmpb)
+            
+            a.close()
+            b.close()
+
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_supported_features(self):
+        msg = "\nsupported file format are : this test is broken FIXME"
+        #for i in pysndfile.supported_format():
+        #    msg += str(i) + ', '
+        #print msg
+        #msg = "supported encoding format are : "
+        #for i in pysndfile.supported_encoding():
+        #    msg += str(i) + ', '
+        #print msg
+        #msg = "supported endianness are : "
+        #for i in pysndfile.supported_endianness():
+        #    msg += str(i) + ', '
+        print msg
+
+    def test_short_io(self):
+        # TODO: check if neg or pos value is the highest in abs
+        rfd, fd, cfilename   = open_tmp_file('pysndfiletest.wav')
+        try:
+            nb      = 2 ** 14
+            nbuff   = 22050
+            fs      = 22050
+            a       = N.random.random_integers(-nb, nb, nbuff)
+            a       = a.astype(N.short)
+
+            # Open the file for writing
+            format  = audio_format('wav', 'pcm16')
+            b       = sndfile(fd, 'write', format, 1, fs)
+
+            b.write_frames(a, nbuff)
+            b.close()
+
+            b       = sndfile(cfilename, 'read')
+
+            read_a  = b.read_frames(nbuff, dtype = N.short)
+            b.close()
+
+            assert_array_equal(a, read_a)
+            
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_int_io(self):
+        # TODO: check if neg or pos value is the highest in abs
+        rfd, fd, cfilename   = open_tmp_file('pysndfiletest.wav')
+        try:
+            nb      = 2 ** 25
+            nbuff   = 22050
+            fs      = 22050
+            a       = N.random.random_integers(-nb, nb, nbuff)
+            a       = a.astype(N.int32)
+
+            # Open the file for writing
+            format  = audio_format('wav', 'pcm32')
+            b       = sndfile(fd, 'write', format, 1, fs)
+
+            b.write_frames(a, nbuff)
+            b.close()
+
+            b       = sndfile(cfilename, 'read')
+
+            read_a  = b.read_frames(nbuff, dtype = N.int32)
+            b.close()
+
+            assert_array_equal(a, read_a)
+            
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_mismatch(self):
+        # This test open a file for writing, but with bad args (channels and
+        # nframes inverted) 
+        rfd, fd, cfilename = open_tmp_file('pysndfiletest.wav')
+        try:
+            # Open the file for writing
+            format  = audio_format('wav', 'pcm16')
+            try:
+                b = sndfile(fd, 'write', \
+                        format, channels = 22000, samplerate = 1)
+                raise Exception("Try to open a file with more than 256 "\
+                        "channels, this should not succeed !")
+            except RuntimeError, e:
+                #print "Gave %d channels, error detected is \"%s\"" % (22000, e)
+                pass
+
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_bigframes(self):
+        """ Try to seek really far"""
+        rawname = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+        a       = sndfile(rawname, 'read')
+        try:
+            try:
+                a.seek(2 ** 60)
+                raise Exception("Seek really succeded ! This should not happen")
+            except pysndfile.PyaudioIOError, e:
+                pass
+        finally:
+            a.close()
+
+    def test_float_frames(self):
+        """ Check nframes can be a float"""
+        rfd, fd, cfilename   = open_tmp_file('pysndfiletest.wav')
+        try:
+            # Open the file for writing
+            format = audio_format('wav', 'pcm16')
+            a = sndfile(fd, 'rwrite', format, channels = 1, 
+                    samplerate = 22050)
+            tmp = N.random.random_integers(-100, 100, 1000)
+            tmp = tmp.astype(N.short)
+            a.write_frames(tmp, tmp.size)
+            a.seek(0)
+            a.sync()
+            ctmp    = a.read_frames(1e2, dtype = N.short)
+            a.close()
+
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_nofile(self):
+        """ Check the failure when opening a non existing file."""
+        try:
+            f = sndfile("floupi.wav", "read")
+            raise AssertionError("call to non existing file should not succeed")
+        except IOError:
+            pass
+        except Exception, e:
+            raise AssertionError("opening non existing file should raise a IOError exception, got %s instead" % e.__class__)
+
+class test_seek(NumpyTestCase):
+    def test_simple(self):
+        ofilename = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+        # Open the test file for reading
+        a       = sndfile(ofilename, 'read')
+        nframes = a.get_nframes()
+
+        buffsize    = 1024
+        buffsize    = min(nframes, buffsize)
+
+        # First, read some frames, go back, and compare buffers
+        buff    = a.read_frames(buffsize)
+        a.seek(0)
+        buff2   = a.read_frames(buffsize)
+        assert_array_equal(buff, buff2)
+
+        a.close()
+
+        # Now, read some frames, go back, and compare buffers
+        # (check whence == 1 == SEEK_CUR)
+        a       = sndfile(ofilename, 'read')
+        a.read_frames(buffsize)
+        buff    = a.read_frames(buffsize)
+        a.seek(-buffsize, 1)
+        buff2   = a.read_frames(buffsize)
+        assert_array_equal(buff, buff2)
+
+        a.close()
+
+        # Now, read some frames, go back, and compare buffers
+        # (check whence == 2 == SEEK_END)
+        a       = sndfile(ofilename, 'read')
+        buff    = a.read_frames(nframes)
+        a.seek(-buffsize, 2)
+        buff2   = a.read_frames(buffsize)
+        assert_array_equal(buff[-buffsize:], buff2)
+
+    def test_rw(self):
+        """Test read/write pointers for seek."""
+        ofilename = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+        rfd, fd, cfilename   = open_tmp_file('rwseektest.wav')
+        try:
+            ref = sndfile(ofilename, 'read')
+            test = sndfile(fd, 'rwrite', format = ref._format, channels =
+                    ref.get_channels(), samplerate = ref.get_samplerate())
+            n = 1024
+
+            rbuff = ref.read_frames(n, dtype = N.int16)
+            test.write_frames(rbuff)
+            tbuff = test.read_frames(n, dtype = N.int16)
+
+            assert_array_equal(rbuff, tbuff)
+
+            # Test seeking both read and write pointers
+            test.seek(0, 0)
+            test.write_frames(rbuff)
+            tbuff = test.read_frames(n, dtype = N.int16)
+            assert_array_equal(rbuff, tbuff)
+
+            # Test seeking only read pointer
+            rbuff1 = rbuff.copy()
+            rbuff2 = rbuff1 * 2 + 1
+            rbuff2.clip(-30000, 30000)
+            test.seek(0, 0, 'r')
+            test.write_frames(rbuff2)
+            tbuff1 = test.read_frames(n, dtype = N.int16)
+            try:
+                tbuff2 = test.read_frames(n, dtype = N.int16)
+            except IOError, e:
+                msg = "write pointer was updated in read seek !"
+                msg += "\n(msg is %s)" % e
+                raise AssertionError(msg) 
+
+            assert_array_equal(rbuff1, tbuff1)
+            assert_array_equal(rbuff2, tbuff2)
+            if N.all(rbuff2 == tbuff1):
+                raise AssertionError("write pointer was updated"\
+                        " in read seek !") 
+
+            # Test seeking only write pointer
+            rbuff3 = rbuff1 * 2 - 1
+            rbuff3.clip(-30000, 30000)
+            test.seek(0, 0, 'rw')
+            test.seek(n, 0, 'w')
+            test.write_frames(rbuff3)
+            tbuff1 = test.read_frames(n, N.int16)
+            try:
+                assert_array_equal(tbuff1, rbuff1)
+            except AssertionError:
+                raise AssertionError("read pointer was updated in write seek !")
+
+            try:
+                tbuff3 = test.read_frames(n, N.int16)
+            except IOError, e:
+                msg = "read pointer was updated in write seek !"
+                msg += "\n(msg is %s)" % e
+                raise AssertionError(msg) 
+
+            assert_array_equal(tbuff3, rbuff3)
+            test.close()
+
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+if __name__ == "__main__":
+    NumpyTest().run()
diff --git a/telemeta/util/audiolab/build/lib/scikits/audiolab/tests/testcommon.py b/telemeta/util/audiolab/build/lib/scikits/audiolab/tests/testcommon.py
new file mode 100644 (file)
index 0000000..dd8c4a4
--- /dev/null
@@ -0,0 +1,20 @@
+import os
+from tempfile import mkstemp
+import sys
+
+def open_tmp_file(name):
+    """On any sane platforms, return a fd on a tmp file. On windows, returns
+    the filename, and as such, is not secure (someone else can reopen the file
+    in between)."""
+    fd, cfilename = mkstemp('pysndfiletest.wav')
+    if sys.platform == 'win32':
+        return fd, cfilename, cfilename
+    else:
+        return fd, fd, cfilename
+
+def close_tmp_file(fd, filename):
+    """On any sane platforms, remove the file . On windows, only close the
+    file."""
+    os.close(fd)
+    os.remove(filename)
+    
diff --git a/telemeta/util/audiolab/generate.sh b/telemeta/util/audiolab/generate.sh
new file mode 100644 (file)
index 0000000..e89b011
--- /dev/null
@@ -0,0 +1,4 @@
+#! /bin/sh
+# Last Change: Fri May 25 10:00 AM 2007 J
+EPYDOCOPTS="--latex -v --no-private --exclude test_*"
+PYTHONPATH=/home/david/local/lib/python2.5/site-packages/ /home/david/local/bin/epydoc $EPYDOCOPTS scikits/pyaudiolab/
diff --git a/telemeta/util/audiolab/generate_const.py b/telemeta/util/audiolab/generate_const.py
new file mode 100644 (file)
index 0000000..eb17431
--- /dev/null
@@ -0,0 +1,54 @@
+#! /usr/bin/env python
+# Last Change: Thu May 24 02:00 PM 2007 J
+
+# David Cournapeau 2006
+
+# TODO:
+#   args with the header file to extract info from
+
+from header_parser import get_dict, put_dict_file
+
+def generate_enum_dicts(header = '/usr/include/sndfile.h'):
+    # Open the file and get the content, without trailing '\n'
+    hdct    = [i.split('\n')[0] for i in open(header, 'r').readlines()]
+
+    # Get sf boolean
+    sf_bool     = {}
+    nameregex   = '(SF_FALSE)'
+    sf          = get_dict(hdct, nameregex)
+    sf_bool['SF_FALSE'] = sf['SF_FALSE']
+    nameregex   = '(SF_TRUE)'
+    sf           = get_dict(hdct, nameregex)
+    sf_bool['SF_TRUE'] = sf['SF_TRUE']
+
+    # Get mode constants
+    nameregex   = '(SFM_[\S]*)'
+    sfm         = get_dict(hdct, nameregex)
+
+    # Get format constants
+    nameregex   = '(SF_FORMAT_[\S]*)'
+    sf_format   = get_dict(hdct, nameregex)
+
+    # Get endianness 
+    nameregex   = '(SF_ENDIAN_[\S]*)'
+    sf_endian   = get_dict(hdct, nameregex)
+
+    # Get command constants
+    nameregex   = '(SFC_[\S]*)'
+    sf_command  = get_dict(hdct, nameregex)
+
+    # Get (public) errors
+    nameregex   = '(SF_ERR_[\S]*)'
+    sf_errors   = get_dict(hdct, nameregex)
+
+    # Replace dict:
+    repdict = {
+        '%SFM%' : put_dict_file(sfm, 'SFM'),
+        '%SF_BOOL%' : put_dict_file(sf_bool, 'SF_BOOL'),
+        '%SF_FORMAT%' : put_dict_file(sf_format, 'SF_FORMAT'),
+        '%SF_ENDIAN%' : put_dict_file(sf_endian, 'SF_ENDIAN'),
+        '%SF_COMMAND%' : put_dict_file(sf_command, 'SF_COMMAND'),
+        '%SF_ERR%' : put_dict_file(sf_errors, 'SF_ERRORS')
+    }
+
+    return repdict
diff --git a/telemeta/util/audiolab/generate_const.pyc b/telemeta/util/audiolab/generate_const.pyc
new file mode 100644 (file)
index 0000000..28f8b90
Binary files /dev/null and b/telemeta/util/audiolab/generate_const.pyc differ
diff --git a/telemeta/util/audiolab/header_parser.py b/telemeta/util/audiolab/header_parser.py
new file mode 100644 (file)
index 0000000..5640422
--- /dev/null
@@ -0,0 +1,50 @@
+#! /usr/bin/env python
+# Last Change: Thu Nov 02 12:00 PM 2006 J
+
+# Small module to parse header files, and other tools to use libraries with ctype
+# David Cournapeau 2006
+
+import re
+
+def get_dict(content, nameregex, valueregex = '([ABCDEF\dx]*)'):
+    """Read the content of a header file, parse for a regex nameregex,
+    and get the corresponding value (HEX values 0x by default)
+    
+    This is useful to parse enumerations in header files"""
+    sf_dict     = {}
+    regex       = re.compile(nameregex + '[\s]*= ' + valueregex)
+    for i in content:
+        m   = regex.search(i)
+        if m:
+            sf_dict[m.group(1)]    = m.group(2)
+    return sf_dict
+
+def put_dict_file(dict, name):
+    items   = dict.items()
+    string  = name + ' = {\n\t' + '\'' + items[0][0] + '\'\t: ' + items[0][1]
+    for i in range(1, len(items)):
+        #print "Putting key %s, value %s" % (items[i][0], items[i][1])
+        string  += ',\n\t\'' + items[i][0] + '\'\t: ' + items[i][1]
+    string  += '\n}'
+    return string
+
+# Functions used to substitute values in File.
+# Kind of like config.h and autotools 
+import re
+def do_subst_in_file(sourcefile, targetfile, dict):
+    """Replace all instances of the keys of dict with their values.
+    For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'},
+    then all instances of %VERSION% in the file will be replaced with 1.2345 etc.
+    """
+    #print "sourcefile is %s, target is %s" % (sourcefile, targetfile)
+    f = open(sourcefile, 'rb')
+    contents = f.read()
+    f.close()
+
+    for (k,v) in dict.items():
+        contents = re.sub(k, v, contents)
+        
+    f = open(targetfile, 'wb')
+    f.write(contents)
+    f.close()
+
diff --git a/telemeta/util/audiolab/header_parser.pyc b/telemeta/util/audiolab/header_parser.pyc
new file mode 100644 (file)
index 0000000..36fd4ac
Binary files /dev/null and b/telemeta/util/audiolab/header_parser.pyc differ
diff --git a/telemeta/util/audiolab/scikits.audiolab.egg-info/PKG-INFO b/telemeta/util/audiolab/scikits.audiolab.egg-info/PKG-INFO
new file mode 100644 (file)
index 0000000..f3e9e52
--- /dev/null
@@ -0,0 +1,31 @@
+Metadata-Version: 1.0
+Name: scikits.audiolab
+Version: 0.8dev.dev
+Summary: A python module to make noise from numpy arrays
+Home-page: http://www.ar.media.kyoto-u.ac.jp/members/david/softwares/audiolab
+Author: David Cournapeau
+Author-email: david@ar.media.kyoto-u.ac.jp
+License: LGPL
+Download-URL: http://www.ar.media.kyoto-u.ac.jp/members/david/softwares/audiolab
+Description: audiolab is a small python package to import data from audio
+        files to numpy arrays and export data from numpy arrays to audio files. It uses
+        libsndfile from Erik Castro de Lopo for the underlying IO, which supports many
+        different audio formats: http://www.mega-nerd.com/libsndfile/
+        
+        For now, the python api for audio IO should be stable; a matlab-like API is
+        also available for quick read/write (ala wavread, wavwrite, etc...). For 1.0
+        release, I hope to add support for simple read/write to soundcard, to be able
+        to record and listen to data in numpy arrays.
+        
+        2006-2007, David Cournapeau
+        
+        LICENSE: audiolab is licensed under the LGPL, as is libsndfile itself. See
+        COPYING.txt for details.
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Environment :: Console
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: Science/Research
+Classifier: License :: OSI Approved :: LGPL License
+Classifier: Topic :: Multimedia :: Sound/Audio
+Classifier: Topic :: Scientific/Engineering
diff --git a/telemeta/util/audiolab/scikits.audiolab.egg-info/SOURCES.txt b/telemeta/util/audiolab/scikits.audiolab.egg-info/SOURCES.txt
new file mode 100644 (file)
index 0000000..a155f47
--- /dev/null
@@ -0,0 +1,27 @@
+COPYING.txt
+FLAC_SUPPORT.txt
+MANIFEST.in
+README.txt
+generate_const.py
+header_parser.py
+setup.cfg
+setup.py
+site.cfg.win32
+scikits/__init__.py
+scikits.audiolab.egg-info/PKG-INFO
+scikits.audiolab.egg-info/SOURCES.txt
+scikits.audiolab.egg-info/dependency_links.txt
+scikits.audiolab.egg-info/namespace_packages.txt
+scikits.audiolab.egg-info/requires.txt
+scikits.audiolab.egg-info/top_level.txt
+scikits.audiolab.egg-info/zip-safe
+scikits/audiolab/__init__.py
+scikits/audiolab/info.py
+scikits/audiolab/matapi.py
+scikits/audiolab/pyaudioio.py
+scikits/audiolab/pysndfile.py
+scikits/audiolab/pysndfile.py.in
+scikits/audiolab/tests/__init__.py
+scikits/audiolab/tests/test_matapi.py
+scikits/audiolab/tests/test_pysndfile.py
+scikits/audiolab/tests/testcommon.py
\ No newline at end of file
diff --git a/telemeta/util/audiolab/scikits.audiolab.egg-info/dependency_links.txt b/telemeta/util/audiolab/scikits.audiolab.egg-info/dependency_links.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/telemeta/util/audiolab/scikits.audiolab.egg-info/namespace_packages.txt b/telemeta/util/audiolab/scikits.audiolab.egg-info/namespace_packages.txt
new file mode 100644 (file)
index 0000000..4fc9b05
--- /dev/null
@@ -0,0 +1 @@
+scikits
diff --git a/telemeta/util/audiolab/scikits.audiolab.egg-info/requires.txt b/telemeta/util/audiolab/scikits.audiolab.egg-info/requires.txt
new file mode 100644 (file)
index 0000000..296d654
--- /dev/null
@@ -0,0 +1 @@
+numpy
\ No newline at end of file
diff --git a/telemeta/util/audiolab/scikits.audiolab.egg-info/top_level.txt b/telemeta/util/audiolab/scikits.audiolab.egg-info/top_level.txt
new file mode 100644 (file)
index 0000000..4fc9b05
--- /dev/null
@@ -0,0 +1 @@
+scikits
diff --git a/telemeta/util/audiolab/scikits.audiolab.egg-info/zip-safe b/telemeta/util/audiolab/scikits.audiolab.egg-info/zip-safe
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/telemeta/util/audiolab/scikits/__init__.py b/telemeta/util/audiolab/scikits/__init__.py
new file mode 100644 (file)
index 0000000..de40ea7
--- /dev/null
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)
diff --git a/telemeta/util/audiolab/scikits/__init__.pyc b/telemeta/util/audiolab/scikits/__init__.pyc
new file mode 100644 (file)
index 0000000..68749af
Binary files /dev/null and b/telemeta/util/audiolab/scikits/__init__.pyc differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/__init__.py b/telemeta/util/audiolab/scikits/audiolab/__init__.py
new file mode 100644 (file)
index 0000000..1291159
--- /dev/null
@@ -0,0 +1,35 @@
+#! /usr/bin/env python
+# Last Change: Mon Sep 10 07:00 PM 2007 J
+"""
+audiolab: a small toolbox to read, write and play audio to and from
+numpy arrays.
+
+audiolab provides two API:
+    - one similar to matlab: this gives you wavread, wavwrite functions really
+      similar to matlab's functions.
+    - a more complete API, which can be used to read, write to many audio file
+      (including wav, aiff, flac, au, IRCAM, htk, etc...), with IO capabilities
+      not available to matlab (seek, append data, etc...)
+
+It is a thin wrapper around libsndfile from Erik Castro Lopo.
+     
+Copyright (C) 2006-2007 Cournapeau David <cournape@gmail.com>
+
+LICENSE: audiolab is licensed under the LGPL, as is libsndfile itself. See
+COPYING.txt for details.  """
+
+from info import VERSION
+__version__ = VERSION
+
+from pysndfile import formatinfo, sndfile
+from pysndfile import supported_format, supported_endianness, \
+                                       supported_encoding
+#from scikits.audiolab.matapi import wavread, aiffread, flacread, auread, \
+#        sdifread, wavwrite, aiffwrite, flacwrite, auwrite, sdifwrite
+from matapi import *
+
+__all__ = filter(lambda s:not s.startswith('_'),dir())
+
+from numpy.testing import NumpyTest
+def test():
+    return NumpyTest().test()
diff --git a/telemeta/util/audiolab/scikits/audiolab/__init__.pyc b/telemeta/util/audiolab/scikits/audiolab/__init__.pyc
new file mode 100644 (file)
index 0000000..31e6dca
Binary files /dev/null and b/telemeta/util/audiolab/scikits/audiolab/__init__.pyc differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/docs/Makefile b/telemeta/util/audiolab/scikits/audiolab/docs/Makefile
new file mode 100644 (file)
index 0000000..5ea6c55
--- /dev/null
@@ -0,0 +1,54 @@
+py2tex = PYTHONPATH=/home/david/local/lib/python2.5/site-packages pygmentize -l python -f tex
+rst2tex        = PYTHONPATH=/home/david/local/lib/python2.5/site-packages rst2newlatex.py \
+                 --stylesheet-path base.tex --user-stylesheet user.tex 
+
+pytexfiles     = audiolab.tex quick1.tex \
+                         usage1.tex \
+                         usage2.tex \
+                         format1.tex \
+                         format2.tex \
+                         write1.tex \
+                         matlab1.tex 
+
+SOURCEPATH     = $(PWD)
+
+EXTTOCLEAN=.chk .dvi .log .aux .bbl .blg .blig .ilg .toc .lof .lot .idx .ind .out .bak .ps .pdf .bm
+
+audiolab.pdf: $(pytexfiles)
+       pdflatex $<
+       pdflatex $<
+       pdflatex $<
+
+audiolab.tex: index.txt
+       $(rst2tex) $< > $@
+
+quick1.tex: examples/quick1.py
+       $(py2tex) $< > $@
+
+usage1.tex: examples/usage1.py
+       $(py2tex) $< > $@
+
+usage2.tex: examples/usage2.py
+       $(py2tex) $< > $@
+
+format1.tex: examples/format1.py
+       $(py2tex) $< > $@
+
+format2.tex: examples/format2.py
+       $(py2tex) $< > $@
+
+write1.tex: examples/write1.py
+       $(py2tex) $< > $@
+
+matlab1.tex: examples/matlab1.py
+       $(py2tex) $< > $@
+
+clean:
+       for i in $(pytexfiles); do \
+               rm -f `echo $$i`; \
+       done;
+       for i in $(SOURCEPATH); do \
+               for j in $(EXTTOCLEAN); do \
+                       rm -f  `echo $$i/*$$j`; \
+               done; \
+       done;
diff --git a/telemeta/util/audiolab/scikits/audiolab/docs/audiolab1.png b/telemeta/util/audiolab/scikits/audiolab/docs/audiolab1.png
new file mode 100644 (file)
index 0000000..c88e46f
Binary files /dev/null and b/telemeta/util/audiolab/scikits/audiolab/docs/audiolab1.png differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/docs/base.tex b/telemeta/util/audiolab/scikits/audiolab/docs/base.tex
new file mode 100644 (file)
index 0000000..b10ea72
--- /dev/null
@@ -0,0 +1,1182 @@
+% System stylesheet for the new LaTeX writer, newlatex2e.
+
+% Major parts of the rendering are done in this stylesheet and not in the
+% Python module.
+
+% For development notes, see notes.txt.
+
+% User documentation (in the stylesheet for now; that may change though):
+
+% Naming conventions:
+% All uppercase letters in macro names have a specific meaning.
+% \D...: All macros introduced by the Docutils LaTeX writer start with "D".
+% \DS<name>: Setup function (called at the bottom of this stylesheet).
+% \DN<nodename>{<contents>}: Handler for Docutils document tree node `node`; called by
+%                            the Python module.
+% \DEV<name>: External variable, set by the Python module.
+% \DEC<name>: External command.  It is called by the Python module and must be
+%             defined in this stylesheet.
+% \DN<nodename>A<attribute>{<number>}{<attribute>}{<value>}{<nodename>}{<contents>}:
+%     Attribute handler for `attribute` set on nodes of type `nodename`.
+%     See below for a discussion of attribute handlers.
+% \DA<attribute>{<number>}{<attribute>}{<value>}{<nodename>}{<contents>}:
+%     Attribute handler for all `attribute`.  Called only when no specific
+%     \DN<nodename>A<attribute> handler is defined.
+% \DN<nodename>C<class>{<contents>}:
+%     Handler for `class`, when set on nodes of type `nodename`.
+% \DC<class>{<contents>}:
+%     Handler for `class`.  Called only when no specific \DN<nodename>C<class>
+%     handler is defined.
+% \D<name>: Generic variable or function.
+
+% Attribute handlers:
+% TODO
+
+% ---------------------------------------------------------------------------
+
+% Having to intersperse code with \makeatletter-\makeatother pairs is very
+% annoying, so we call \makeatletter at the top and \makeatother at the
+% bottom.   Just be aware that you cannot use "@" as a text character inside
+% this stylesheet.
+\makeatletter
+
+% Print-mode (as opposed to online mode e.g. with Adobe Reader).
+% This causes for example blue hyperlinks.
+\providecommand{\Dprinting}{false}
+
+% \DSearly is called right after \documentclass.
+\providecommand{\DSearly}{}
+% \DSlate is called at the end of the stylesheet (right before the document
+% tree).
+\providecommand{\DSlate}{}
+
+% Use the KOMA script article class.
+\providecommand{\Ddocumentclass}{scrartcl}
+\providecommand{\Ddocumentoptions}{a4paper}
+\providecommand{\DSdocumentclass}{
+  \documentclass[\Ddocumentoptions]{\Ddocumentclass} }
+
+% Todo: This should be movable to the bottom, but it isn't as long as
+% we use \usepackage commands at the top level of this stylesheet
+% (which we shouldn't).
+\DSdocumentclass
+
+\providecommand{\DSpackages}{
+  % Load miscellaneous packages.
+  % Note 1: Many of the packages loaded here are used throughout this stylesheet.
+  % If one of these packages does not work on your system or in your scenario,
+  % please let us know, so we can consider making the package optional.
+  % Note 2: It would appear cleaner to load packages where they are used.
+  % However, since using a wrong package loading order can lead to *very*
+  % subtle bugs, we centralize the loading of most packages here.
+  \DSfontencoding % load font encoding packages
+  \DSlanguage % load babel
+  % Using \ifthenelse conditionals.
+  \usepackage{ifthen} % before hyperref (really!)
+  % There is not support for *not* using hyperref because it's used in many
+  % places.  If this is a problem (e.g. because hyperref doesn't work on your
+  % system), please let us know.
+  \usepackage[colorlinks=false,pdfborder={0 0 0}]{hyperref}
+  % Get color, e.g. for links and system messages.
+  \usepackage{color}
+  % Get \textnhtt macro (non-hyphenating type writer).
+  \usepackage{hyphenat}
+  % For sidebars.
+  \usepackage{picins}
+  % We use longtable to create tables.
+  \usepackage{longtable}
+  % Images.
+  \usepackage{graphicx}
+  % These packages might be useful (some just add magic pixie dust), so
+  % evaluate them:
+  %\usepackage{fixmath}
+  %\usepackage{amsmath}
+  % Add some missing symbols like \textonehalf.
+  \usepackage{textcomp}
+}
+
+\providecommand{\DSfontencoding}{
+  % Set up font encoding.  Called by \DSpackages.
+  % AE is a T1 emulation.  It provides mostly the same characters and
+  % features as T1-encoded fonts but doesn't use bitmap fonts (which are
+  % unsuitable for online reading and subtle for printers).
+  \usepackage{ae}
+  % Provide the characters not contained in AE from EC bitmap fonts.
+  \usepackage{aecompl}
+  % Guillemets ("<<", ">>") in AE.
+  \usepackage{aeguill}
+}
+
+\providecommand{\DSsymbols}{%
+  % Fix up symbols.
+  % The Euro symbol in Computer Modern looks, um, funny.  Let's get a
+  % proper Euro symbol.
+  \usepackage{eurosym}%
+  \renewcommand{\texteuro}{\euro}%
+}
+
+% Taken from
+% <http://groups.google.de/groups?selm=1i0n5tgtplti420e1omp4pctlv19jpuhbb%404ax.com>
+% and modified.  Used with permission.
+\providecommand{\Dprovidelength}[2]{%
+  \begingroup%
+    \escapechar\m@ne%
+    \xdef\@gtempa{{\string#1}}%
+  \endgroup%
+  \expandafter\@ifundefined\@gtempa%
+  {\newlength{#1}\setlength{#1}{#2}}%
+  {}%
+}
+
+\providecommand{\Dprovidecounter}[2]{%
+  % Like \newcounter except that it doesn't crash if the counter
+  % already exists.
+  \@ifundefined{c@#1}{\newcounter{#1}\setcounter{#1}{#2}}{}
+}
+
+\Dprovidelength{\Dboxparindent}{\parindent}
+
+\providecommand{\Dmakebox}[1]{%
+  % Make a centered, frameless box.  Useful e.g. for block quotes.
+  % Do not use minipages here, but create pseudo-lists to allow
+  % page-breaking.  (Don't use KOMA-script's addmargin environment
+  % because it messes up bullet lists.)
+  \Dmakelistenvironment{}{}{%
+    \setlength{\parskip}{0pt}%
+    \setlength{\parindent}{\Dboxparindent}%
+    \item{#1}%
+  }%
+}
+
+\providecommand{\Dmakefbox}[1]{%
+  % Make a centered, framed box.  Useful e.g. for admonitions.
+  \vspace{0.4\baselineskip}%
+  \begin{center}%
+    \fbox{%
+      \begin{minipage}[t]{0.9\linewidth}%
+        \setlength{\parindent}{\Dboxparindent}%
+        #1%
+      \end{minipage}%
+    }%
+  \end{center}%
+  \vspace{0.4\baselineskip}%
+}
+
+% We do not currently recognize the difference between an end-sentence and a
+% mid-sentence period (".  " vs. ". " in plain text).  So \frenchspacing is
+% appropriate.
+\providecommand{\DSfrenchspacing}{\frenchspacing}
+
+
+\Dprovidelength{\Dblocklevelvspace}{%
+  % Space between block-level elements other than paragraphs.
+  0.7\baselineskip plus 0.3\baselineskip minus 0.2\baselineskip%
+}
+\providecommand{\DECauxiliaryspace}{%
+  \ifthenelse{\equal{\Dneedvspace}{true}}{\vspace{\Dblocklevelvspace}}{}%
+  \par\noindent%
+}
+\providecommand{\DECparagraphspace}{\par}
+\providecommand{\Dneedvspace}{true}
+
+\providecommand{\DSlanguage}{%
+  % Set up babel.
+  \usepackage[\DEVlanguagebabel]{babel}
+}
+
+\providecommand{\Difdefined}[3]{\@ifundefined{#1}{#3}{#2}}
+
+% Handler for 'classes' attribute (called for each class attribute).
+\providecommand{\DAclasses}[5]{%
+  % Dispatch to \DN<nodename>C<class>.
+  \Difdefined{DN#4C#3}{%
+    % Pass only contents, nothing else!
+    \csname DN#4C#3\endcsname{#5}%
+  }{%
+    % Otherwise, dispatch to \DC<class>.
+    \Difdefined{DC#3}{%
+      \csname DC#3\endcsname{#5}%
+    }{%
+      #5%
+    }%
+  }%
+}
+
+\providecommand{\DECattr}[5]{%
+  % Global attribute dispatcher, called inside the document tree.
+  % Parameters:
+  % 1. Attribute number.
+  % 2. Attribute name.
+  % 3. Attribute value.
+  % 4. Node name.
+  % 5. Node contents.
+  \Difdefined{DN#4A#2}{%
+    % Dispatch to \DN<nodename>A<attribute>.
+    \csname DN#4A#2\endcsname{#1}{#2}{#3}{#4}{#5}%
+  }{\Difdefined{DA#2}{%
+    % Otherwise dispatch to \DA<attribute>.
+    \csname DA#2\endcsname{#1}{#2}{#3}{#4}{#5}%
+  }{%
+    % Otherwise simply run the contents without calling a handler.
+    #5%
+  }}%
+}
+
+% ---------- Link handling ----------
+% Targets and references.
+
+\providecommand{\Draisedlink}[1]{%
+  % Anchors are placed on the base line by default.  This is a bad thing for
+  % inline context, so we raise the anchor (normally by \baselineskip).
+  \Hy@raisedlink{#1}%
+}
+
+% References.
+% We're assuming here that the "refid" and "refuri" attributes occur
+% only in inline context (in TextElements).
+\providecommand{\DArefid}[5]{%
+  \ifthenelse{\equal{#4}{reference}}{%
+    \Dexplicitreference{\##3}{#5}%
+  }{%
+    % If this is not a target node (targets with refids are
+    % uninteresting and should be silently dropped).
+    \ifthenelse{\not\equal{#4}{target}}{%
+      % If this is a footnote reference, call special macro.
+      \ifthenelse{\equal{#4}{footnotereference}}{%
+        \Dimplicitfootnotereference{\##3}{#5}%
+      }{%
+        \ifthenelse{\equal{#4}{citationreference}}{%
+          \Dimplicitcitationreference{\##3}{#5}%
+        }{%
+          \Dimplicitreference{\##3}{#5}%
+        }%
+      }%
+    }{}%
+  }%
+}
+\providecommand{\DArefuri}[5]{%
+  \ifthenelse{\equal{#4}{target}}{%
+    % The node name is 'target', so this is a hyperlink target, like this:
+    % .. _mytarget: URI
+    % Hyperlink targets are ignored because they are invisible.
+  }{%
+    % If a non-target node has a refuri attribute, it must be an explicit URI
+    % reference (i.e. node name is 'reference').
+    \Durireference{#3}{#5}%
+  }%
+}
+% Targets.
+\providecommand{\DAids}[5]{%
+  \label{#3}%
+  \ifthenelse{\equal{#4}{footnotereference}}{%
+    {%
+      \renewcommand{\HyperRaiseLinkDefault}{%
+        % Dirty hack to make backrefs to footnote references work.
+        % For some reason, \baselineskip is 0pt in fn references.
+        0.5\Doriginalbaselineskip%
+      }%
+      \Draisedlink{\hypertarget{#3}{}}#5%
+    }%
+  }{%
+    \Draisedlink{\hypertarget{#3}{}}#5%
+  }%
+}
+\providecommand{\Dimplicitreference}[2]{%
+  % Create implicit reference to ID.  Implicit references occur
+  % e.g. in TOC-backlinks of section titles.  Parameters:
+  % 1. Target.
+  % 2. Link text.
+  \href{#1}{#2}%
+}
+\providecommand{\Dimplicitfootnotereference}[2]{%
+  % Ditto, but for the special case of footnotes.
+  % We want them to be rendered like explicit references.
+  \Dexplicitreference{#1}{#2}%
+}
+\providecommand{\Dimplicitcitationreference}[2]{%
+  % Ditto for citation references.
+  \Dimplicitfootnotereference{#1}{#2}%
+}
+\providecommand{\Dcolorexplicitreference}{%
+  \ifthenelse{\equal{\Dprinting}{true}}{\color{black}}{\color{blue}}%
+}
+\providecommand{\Dexplicitreference}[2]{%
+  % Create explicit reference to ID, e.g. created with "foo_".
+  % Parameters:
+  % 1. Target.
+  % 2. Link text.
+  \href{#1}{{\Dcolorexplicitreference#2}}%
+}
+\providecommand{\Dcolorurireference}{\Dcolorexplicitreference}
+\providecommand{\Durireference}[2]{%
+  % Create reference to URI.  Parameters:
+  % 1. Target.
+  % 2. Link text.
+  \href{#1}{{\Dcolorurireference#2}}%
+}
+
+\Dprovidecounter{Dpdfbookmarkid}{0}%
+\providecommand{\Dpdfbookmark}[1]{%
+  % Temporarily decrement Desctionlevel counter.
+  \addtocounter{Dsectionlevel}{-1}%
+  %\typeout{\arabic{Dsectionlevel}}%
+  %\typeout{#1}%
+  %\typeout{docutils\roman{Dpdfbookmarkid}}%
+  %\typeout{}%
+  \pdfbookmark[\arabic{Dsectionlevel}]{#1}{docutils\arabic{Dpdfbookmarkid}}%
+  \addtocounter{Dsectionlevel}{1}%
+  \addtocounter{Dpdfbookmarkid}{1}%
+}
+% ---------- End of Link Handling ----------
+
+\providecommand{\DNparagraph}[1]{%
+  \ifthenelse{\equal{\DEVparagraphindented}{true}}{\indent}{\noindent}%
+  #1%
+}
+\providecommand{\Dformatboxtitle}[1]{{\Large\textbf{#1}}}
+\providecommand{\Dformatboxsubtitle}[1]{{\large\textbf{#1}}}
+\providecommand{\Dtopictitle}[1]{%
+  \Difinsidetoc{\vspace{1em}\par}{}%
+  \noindent\Dformatboxtitle{#1}%
+  \ifthenelse{\equal{\DEVhassubtitle}{false}}{\vspace{1em}}{\vspace{0.5em}}%
+  \par%
+}
+\providecommand{\Dadmonitiontitle}[1]{%
+  \Dtopictitle{#1}%
+}
+\providecommand{\Dtopicsubtitle}[1]{%
+  \noindent\Dformatboxsubtitle{#1}%
+  \vspace{1em}%
+  \par%
+}
+\providecommand{\Dsidebartitle}[1]{\Dtopictitle{#1}}
+\providecommand{\Dsidebarsubtitle}[1]{\Dtopicsubtitle{#1}}
+\providecommand{\Ddocumenttitle}[1]{%
+  \begin{center}{\Huge#1}\end{center}%
+  \ifthenelse{\equal{\DEVhassubtitle}{true}}{\vspace{0.1cm}}{\vspace{1cm}}%
+}
+\providecommand{\Ddocumentsubtitle}[1]{%
+  \begin{center}{\huge#1}\end{center}%
+  \vspace{1cm}%
+}
+% Can be overwritten by user stylesheet.
+\providecommand{\Dformatsectiontitle}[1]{#1}
+\providecommand{\Dformatsectionsubtitle}[1]{\Dformatsectiontitle{#1}}
+\providecommand{\Dbookmarksectiontitle}[1]{%
+  % Return text suitable for use in \section*, \subsection*, etc.,
+  % containing a PDF bookmark.  Parameter:  The title (as node tree).
+  \Draisedlink{\Dpdfbookmark{\DEVtitleastext}}%
+  #1%
+}
+\providecommand{\Dsectiontitlehook}[1]{#1}
+\providecommand{\Dsectiontitle}[1]{%
+  \Dsectiontitlehook{%
+    \Ddispatchsectiontitle{\Dbookmarksectiontitle{\Dformatsectiontitle{#1}}}%
+  }%
+}
+\providecommand{\Ddispatchsectiontitle}[1]{%
+  \@ifundefined{Dsectiontitle\roman{Dsectionlevel}}{%
+    \Ddeepsectiontitle{#1}%
+  }{%
+    \csname Dsectiontitle\roman{Dsectionlevel}\endcsname{#1}%
+  }%
+}
+\providecommand{\Ddispatchsectionsubtitle}[1]{%
+  \Ddispatchsectiontitle{#1}%
+}
+\providecommand{\Dsectiontitlei}[1]{\section*{#1}}
+\providecommand{\Dsectiontitleii}[1]{\subsection*{#1}}
+\providecommand{\Ddeepsectiontitle}[1]{%
+  % Anything below \subsubsection (like \paragraph or \subparagraph)
+  % is useless because it uses the same font.  The only way to
+  % (visually) distinguish such deeply nested sections is to use
+  % section numbering.
+  \subsubsection*{#1}%
+}
+\providecommand{\Dsectionsubtitlehook}[1]{#1}
+\Dprovidelength{\Dsectionsubtitleraisedistance}{0.7em}
+\providecommand{\Dsectionsubtitlescaling}{0.85}
+\providecommand{\Dsectionsubtitle}[1]{%
+  \Dsectionsubtitlehook{%
+    % Move the subtitle nearer to the title.
+    \vspace{-\Dsectionsubtitleraisedistance}%
+    % Don't create a PDF bookmark.
+    \Ddispatchsectionsubtitle{%
+      \Dformatsectionsubtitle{\scalebox{\Dsectionsubtitlescaling}{#1}}%
+    }%
+  }%
+}
+\providecommand{\DNtitle}[1]{%
+  % Dispatch to \D<parent>title.
+  \csname D\DEVparent title\endcsname{#1}%
+}
+\providecommand{\DNsubtitle}[1]{%
+  % Dispatch to \D<parent>subtitle.
+  \csname D\DEVparent subtitle\endcsname{#1}%
+}
+
+\providecommand{\DNliteralblock}[1]{%
+  \Dmakelistenvironment{}{%
+    \ifthenelse{\equal{\Dinsidetabular}{true}}{%
+      \setlength{\leftmargin}{0pt}%
+    }{}%
+    \setlength{\rightmargin}{0pt}%
+  }{%
+    \raggedright\item\noindent\nohyphens{\textnhtt{#1\Dfinalstrut}}%
+  }%
+}
+\providecommand{\DNdoctestblock}[1]{\DNliteralblock{#1}}
+\providecommand{\DNliteral}[1]{\textnhtt{#1}}
+\providecommand{\DNemphasis}[1]{\emph{#1}}
+\providecommand{\DNstrong}[1]{\textbf{#1}}
+\providecommand{\DECvisitdocument}{\begin{document}\noindent}
+\providecommand{\DECdepartdocument}{\end{document}}
+\providecommand{\DNtopic}[1]{%
+  \ifthenelse{\equal{\DEVcurrentNtopicAcontents}{1}}{%
+    \addtocounter{Dtoclevel}{1}%
+    \par\noindent%
+    #1%
+    \addtocounter{Dtoclevel}{-1}%
+  }{%
+    \par\noindent%
+    \Dmakebox{#1}%
+  }%
+}
+\providecommand{\DNadmonition}[1]{%
+  \DNtopic{#1}%
+}
+\providecommand{\Dformatrubric}[1]{\textbf{#1}}
+\Dprovidelength{\Dprerubricspace}{0.3em}
+\providecommand{\DNrubric}[1]{%
+  \vspace{\Dprerubricspace}\par\noindent\Dformatrubric{#1}\par%
+}
+
+\providecommand{\Dbullet}{}
+\providecommand{\DECsetbullet}[1]{\renewcommand{\Dbullet}{#1}}
+\providecommand{\DNbulletlist}[1]{%
+  \Difinsidetoc{%
+    \Dtocbulletlist{#1}%
+  }{%
+    \Dmakelistenvironment{\Dbullet}{}{#1}%
+  }%
+}
+% Todo: So what on earth is @pnumwidth?
+\renewcommand{\@pnumwidth}{2.2em}
+\providecommand{\DNlistitem}[1]{%
+  \Difinsidetoc{%
+    \ifthenelse{\equal{\theDtoclevel}{1}\and\equal{\Dlocaltoc}{false}}{%
+      {%
+        \par\addvspace{1em}\noindent%
+        \sectfont%
+        #1\hfill\pageref{\DEVcurrentNlistitemAtocrefid}%
+      }%
+    }{%
+      \@dottedtocline{0}{\Dtocindent}{0em}{#1}{%
+        \pageref{\DEVcurrentNlistitemAtocrefid}%
+      }%
+    }%
+  }{%
+    \item{#1}%
+  }%
+}
+\providecommand{\DNenumeratedlist}[1]{#1}
+\Dprovidecounter{Dsectionlevel}{0}
+\providecommand{\Dvisitsectionhook}{}
+\providecommand{\Ddepartsectionhook}{}
+\providecommand{\DECvisitsection}{%
+  \addtocounter{Dsectionlevel}{1}%
+  \Dvisitsectionhook%
+}
+\providecommand{\DECdepartsection}{%
+  \Ddepartsectionhook%
+  \addtocounter{Dsectionlevel}{-1}%
+}
+
+% Using \_ will cause hyphenation after _ even in \textnhtt-typewriter
+% because the hyphenat package redefines \_.  So we use
+% \textunderscore here.
+\providecommand{\DECtextunderscore}{\textunderscore}
+
+\providecommand{\Dtextinlineliteralfirstspace}{{ }}
+\providecommand{\Dtextinlineliteralsecondspace}{{~}}
+
+\Dprovidelength{\Dlistspacing}{0.8\baselineskip}
+
+\providecommand{\Dsetlistrightmargin}{%
+  \ifthenelse{\lengthtest{\linewidth>12em}}{%
+    % Equal margins.
+    \setlength{\rightmargin}{\leftmargin}%
+  }{%
+    % If the line is narrower than 10em, we don't remove any further
+    % space from the right.
+    \setlength{\rightmargin}{0pt}%
+  }%
+}
+\providecommand{\Dresetlistdepth}{false}
+\Dprovidelength{\Doriginallabelsep}{\labelsep}
+\providecommand{\Dmakelistenvironment}[3]{%
+  % Make list environment with support for unlimited nesting and with
+  % reasonable default lengths.  Parameters:
+  % 1. Label (same as in list environment).
+  % 2. Spacing (same as in list environment).
+  % 3. List contents (contents of list environment).
+  \ifthenelse{\equal{\Dinsidetabular}{true}}{%
+    % Unfortunately, vertical spacing doesn't work correctly when
+    % using lists inside tabular environments, so we use a minipage.
+    \begin{minipage}[t]{\linewidth}%
+  }{}%
+    {%
+      \renewcommand{\Dneedvspace}{false}%
+      % \parsep0.5\baselineskip
+      \renewcommand{\Dresetlistdepth}{false}%
+      \ifnum \@listdepth>5%
+      \protect\renewcommand{\Dresetlistdepth}{true}%
+      \@listdepth=5%
+      \fi%
+      \begin{list}{%
+          #1%
+        }{%
+          \setlength{\itemsep}{0pt}%
+          \setlength{\partopsep}{0pt}%
+          \setlength{\topsep}{0pt}%
+                                  % List should take 90% of total width.
+          \setlength{\leftmargin}{0.05\linewidth}%
+          \ifthenelse{\lengthtest{\leftmargin<1.8em}}{%
+            \setlength{\leftmargin}{1.8em}%
+          }{}%
+          \setlength{\labelsep}{\Doriginallabelsep}%
+          \Dsetlistrightmargin%
+          #2%
+        }{%
+          #3%
+        }%
+      \end{list}%
+      \ifthenelse{\equal{\Dresetlistdepth}{true}}{\@listdepth=5}{}%
+    }%
+  \ifthenelse{\equal{\Dinsidetabular}{true}}{\end{minipage}}{}%
+}
+\providecommand{\Dfinalstrut}{\@finalstrut\@arstrutbox}
+\providecommand{\DAlastitem}[5]{#5\Dfinalstrut}
+
+\Dprovidelength{\Ditemsep}{0pt}
+\providecommand{\DECmakeenumeratedlist}[6]{%
+  % Make enumerated list.
+  % Parameters:
+  % - prefix
+  % - type (\arabic, \roman, ...)
+  % - suffix
+  % - suggested counter name
+  % - start number - 1
+  % - list contents
+  \newcounter{#4}%
+  \Dmakelistenvironment{#1#2{#4}#3}{%
+    % Use as much space as needed for the label.
+    \setlength{\labelwidth}{10em}%
+    % Reserve enough space so that the label doesn't go beyond the
+    % left margin of preceding paragraphs.  Like that:
+    %
+    %    A paragraph.
+    %
+    %   1. First item.
+    \setlength{\leftmargin}{2.5em}%
+    \Dsetlistrightmargin%
+    \setlength{\itemsep}{\Ditemsep}%
+    % Use counter recommended by Python module.
+    \usecounter{#4}%
+    % Set start value.
+    \addtocounter{#4}{#5}%
+  }{%
+    % The list contents.
+    #6%
+  }%
+}
+
+
+% Single quote in literal mode.  \textquotesingle from package
+% textcomp has wrong width when using package ae, so we use a normal
+% single curly quote here.
+\providecommand{\DECtextliteralsinglequote}{'}
+
+
+% "Tabular lists" are field lists and options lists (not definition
+% lists because there the term always appears on its own line).  We'll
+% use the terminology of field lists now ("field", "field name",
+% "field body"), but the same is also analogously applicable to option
+% lists.
+%
+% We want these lists to be breakable across pages.  We cannot
+% automatically get the narrowest possible size for the left column
+% (i.e. the field names or option groups) because tabularx does not
+% support multi-page tables, ltxtable needs to have the table in an
+% external file and we don't want to clutter the user's directories
+% with auxiliary files created by the filecontents environment, and
+% ltablex is not included in teTeX.
+%
+% Thus we set a fixed length for the left column and use list
+% environments.  This also has the nice side effect that breaking is
+% now possible anywhere, not just between fields.
+%
+% Note that we are creating a distinct list environment for each
+% field.  There is no macro for a whole tabular list!
+\Dprovidelength{\Dtabularlistfieldnamewidth}{6em}
+\Dprovidelength{\Dtabularlistfieldnamesep}{0.5em}
+\providecommand{\Dinsidetabular}{false}
+\providecommand{\Dsavefieldname}{}
+\providecommand{\Dsavefieldbody}{}
+\Dprovidelength{\Dusedfieldnamewidth}{0pt}
+\Dprovidelength{\Drealfieldnamewidth}{0pt}
+\providecommand{\Dtabularlistfieldname}[1]{\renewcommand{\Dsavefieldname}{#1}}
+\providecommand{\Dtabularlistfieldbody}[1]{\renewcommand{\Dsavefieldbody}{#1}}
+\Dprovidelength{\Dparskiptemp}{0pt}
+\providecommand{\Dtabularlistfield}[1]{%
+  {%
+    % This only saves field name and field body in \Dsavefieldname and
+    % \Dsavefieldbody, resp.  It does not insert any text into the
+    % document.
+    #1%
+    % Recalculate the real field name width everytime we encounter a
+    % tabular list field because it may have been changed using a
+    % "raw" node.
+    \setlength{\Drealfieldnamewidth}{\Dtabularlistfieldnamewidth}%
+    \addtolength{\Drealfieldnamewidth}{\Dtabularlistfieldnamesep}%
+    \Dmakelistenvironment{%
+      \makebox[\Drealfieldnamewidth][l]{\Dsavefieldname}%
+    }{%
+      \setlength{\labelwidth}{\Drealfieldnamewidth}%
+      \setlength{\leftmargin}{\Drealfieldnamewidth}%
+      \setlength{\rightmargin}{0pt}%
+      \setlength{\labelsep}{0pt}%
+    }{%
+      \item%
+      \settowidth{\Dusedfieldnamewidth}{\Dsavefieldname}%
+      \setlength{\Dparskiptemp}{\parskip}%
+      \ifthenelse{%
+        \lengthtest{\Dusedfieldnamewidth>\Dtabularlistfieldnamewidth}%
+      }{%
+        \mbox{}\par%
+        \setlength{\parskip}{0pt}%
+      }{}%
+      \Dsavefieldbody%
+      \setlength{\parskip}{\Dparskiptemp}%
+      %XXX Why did we need this?
+      %\@finalstrut\@arstrutbox%
+    }%
+    \par%
+  }%
+}
+
+\providecommand{\Dformatfieldname}[1]{\textbf{#1:}}
+\providecommand{\DNfieldlist}[1]{#1}
+\providecommand{\DNfield}[1]{\Dtabularlistfield{#1}}
+\providecommand{\DNfieldname}[1]{%
+  \Dtabularlistfieldname{%
+    \Dformatfieldname{#1}%
+  }%
+}
+\providecommand{\DNfieldbody}[1]{\Dtabularlistfieldbody{#1}}
+
+\providecommand{\Dformatoptiongroup}[1]{%
+  % Format option group, e.g. "-f file, --input file".
+  \texttt{#1}%
+}
+\providecommand{\Dformatoption}[1]{%
+  % Format option, e.g. "-f file".
+  % Put into mbox to avoid line-breaking at spaces.
+  \mbox{#1}%
+}
+\providecommand{\Dformatoptionstring}[1]{%
+  % Format option string, e.g. "-f".
+  #1%
+}
+\providecommand{\Dformatoptionargument}[1]{%
+  % Format option argument, e.g. "file".
+  \textsl{#1}%
+}
+\providecommand{\Dformatoptiondescription}[1]{%
+  % Format option description, e.g.
+  % "\DNparagraph{Read input data from file.}"
+  #1%
+}
+\providecommand{\DNoptionlist}[1]{#1}
+\providecommand{\Doptiongroupjoiner}{,{ }}
+\providecommand{\Disfirstoption}{%
+  % Auxiliary macro indicating if a given option is the first child
+  % of its option group (if it's not, it has to preceded by
+  % \Doptiongroupjoiner).
+  false%
+}
+\providecommand{\DNoptionlistitem}[1]{%
+  \Dtabularlistfield{#1}%
+}
+\providecommand{\DNoptiongroup}[1]{%
+  \renewcommand{\Disfirstoption}{true}%
+  \Dtabularlistfieldname{\Dformatoptiongroup{#1}}%
+}
+\providecommand{\DNoption}[1]{%
+  % If this is not the first option in this option group, add a
+  % joiner.
+  \ifthenelse{\equal{\Disfirstoption}{true}}{%
+    \renewcommand{\Disfirstoption}{false}%
+  }{%
+    \Doptiongroupjoiner%
+  }%
+  \Dformatoption{#1}%
+}
+\providecommand{\DNoptionstring}[1]{\Dformatoptionstring{#1}}
+\providecommand{\DNoptionargument}[1]{{ }\Dformatoptionargument{#1}}
+\providecommand{\DNdescription}[1]{%
+  \Dtabularlistfieldbody{\Dformatoptiondescription{#1}}%
+}
+
+\providecommand{\DNdefinitionlist}[1]{%
+  \begin{description}%
+    \parskip0pt%
+    #1%
+  \end{description}%
+}
+\providecommand{\DNdefinitionlistitem}[1]{%
+  % LaTeX expects the label in square brackets; we provide an empty
+  % label.
+  \item[]#1%
+}
+\providecommand{\Dformatterm}[1]{#1}
+\providecommand{\DNterm}[1]{\hspace{-5pt}\Dformatterm{#1}}
+% I'm still not sure what's the best rendering for classifiers.  The
+% colon syntax is used by reStructuredText, so it's at least WYSIWYG.
+% Use slanted text because italic would cause too much emphasis.
+\providecommand{\Dformatclassifier}[1]{\textsl{#1}}
+\providecommand{\DNclassifier}[1]{~:~\Dformatclassifier{#1}}
+\providecommand{\Dformatdefinition}[1]{#1}
+\providecommand{\DNdefinition}[1]{\par\Dformatdefinition{#1}}
+
+\providecommand{\Dlineblockindentation}{2.5em}
+\providecommand{\DNlineblock}[1]{%
+  \Dmakelistenvironment{}{%
+    \ifthenelse{\equal{\DEVparent}{lineblock}}{%
+      % Parent is a line block, so indent.
+      \setlength{\leftmargin}{\Dlineblockindentation}%
+    }{%
+      % At top level; don't indent.
+      \setlength{\leftmargin}{0pt}%
+    }%
+    \setlength{\rightmargin}{0pt}%
+    \setlength{\parsep}{0pt}%
+  }{%
+    #1%
+  }%
+}
+\providecommand{\DNline}[1]{\item#1}
+
+\providecommand{\DNtransition}{%
+  \raisebox{0.25em}{\parbox{\linewidth}{\hspace*{\fill}\hrulefill\hrulefill\hspace*{\fill}}}%
+}
+
+\providecommand{\Dformatblockquote}[1]{%
+  % Format contents of block quote.
+  % This occurs in block-level context, so we cannot use \textsl.
+  {\slshape#1}%
+}
+\providecommand{\Dformatattribution}[1]{---\textup{#1}}
+\providecommand{\DNblockquote}[1]{%
+  \Dmakebox{%
+    \Dformatblockquote{#1}
+  }%
+}
+\providecommand{\DNattribution}[1]{%
+  \par%
+  \begin{flushright}\Dformatattribution{#1}\end{flushright}%
+}
+
+
+% Sidebars:
+% Vertical and horizontal margins.
+\Dprovidelength{\Dsidebarvmargin}{0.5em}
+\Dprovidelength{\Dsidebarhmargin}{1em}
+% Padding (space between contents and frame).
+\Dprovidelength{\Dsidebarpadding}{1em}
+% Frame width.
+\Dprovidelength{\Dsidebarframewidth}{2\fboxrule}
+% Position ("l" or "r").
+\providecommand{\Dsidebarposition}{r}
+% Width.
+\Dprovidelength{\Dsidebarwidth}{0.45\linewidth}
+\providecommand{\DNsidebar}[1]{
+  \parpic[\Dsidebarposition]{%
+    \begin{minipage}[t]{\Dsidebarwidth}%
+      % Doing this with nested minipages is ugly, but I haven't found
+      % another way to place vertical space before and after the fbox.
+      \vspace{\Dsidebarvmargin}%
+      {%
+        \setlength{\fboxrule}{\Dsidebarframewidth}%
+        \setlength{\fboxsep}{\Dsidebarpadding}%
+        \fbox{%
+          \begin{minipage}[t]{\linewidth}%
+            \setlength{\parindent}{\Dboxparindent}%
+            #1%
+          \end{minipage}%
+        }%
+      }%
+      \vspace{\Dsidebarvmargin}%
+    \end{minipage}%
+  }%
+}
+
+
+% Citations and footnotes.
+\providecommand{\Dformatfootnote}[1]{%
+  % Format footnote.
+  {%
+    \footnotesize#1%
+    % \par is necessary for LaTeX to adjust baselineskip to the
+    % changed font size.
+    \par%
+  }%
+}
+\providecommand{\Dformatcitation}[1]{\Dformatfootnote{#1}}
+\Dprovidelength{\Doriginalbaselineskip}{0pt}
+\providecommand{\DNfootnotereference}[1]{%
+  {%
+    % \baselineskip is 0pt in \textsuperscript, so we save it here.
+    \setlength{\Doriginalbaselineskip}{\baselineskip}%
+    \textsuperscript{#1}%
+  }%
+}
+\providecommand{\DNcitationreference}[1]{{[}#1{]}}
+\Dprovidelength{\Dfootnotesep}{3.5pt}
+\providecommand{\Dsetfootnotespacing}{%
+  % Spacing commands executed at the beginning of footnotes.
+  \setlength{\parindent}{0pt}%
+  \hspace{1em}%
+}
+\providecommand{\DNfootnote}[1]{%
+  % See ltfloat.dtx for details.
+  {%
+    \insert\footins{%
+      % BUG: This is too small if the user adds
+      % \onehalfspacing or \doublespace.
+      \vspace{\Dfootnotesep}%
+      \Dsetfootnotespacing%
+      \Dformatfootnote{#1}%
+    }%
+  }%
+}
+\providecommand{\DNcitation}[1]{\DNfootnote{#1}}
+\providecommand{\Dformatfootnotelabel}[1]{%
+  % Keep \footnotesize in footnote labels (\textsuperscript would
+  % reduce the font size even more).
+  \textsuperscript{\footnotesize#1{ }}%
+}
+\providecommand{\Dformatcitationlabel}[1]{{[}#1{]}{ }}
+\providecommand{\Dformatmultiplebackrefs}[1]{%
+  % If in printing mode, do not write out multiple backrefs.
+  \ifthenelse{\equal{\Dprinting}{true}}{}{\textsl{#1}}%
+}
+\providecommand{\Dthislabel}{}
+\providecommand{\DNlabel}[1]{%
+  % Footnote or citatation label.
+  \renewcommand{\Dthislabel}{#1}%
+  \ifthenelse{\not\equal{\DEVsinglebackref}{}}{%
+    \let\Doriginallabel=\Dthislabel%
+    \def\Dthislabel{%
+      \Dsinglefootnotebacklink{\DEVsinglebackref}{\Doriginallabel}%
+    }%
+  }{}%
+  \ifthenelse{\equal{\DEVparent}{footnote}}{%
+    % Footnote label.
+    \Dformatfootnotelabel{\Dthislabel}%
+  }{%
+    \ifthenelse{\equal{\DEVparent}{citation}}{%
+      % Citation label.
+      \Dformatcitationlabel{\Dthislabel}%
+    }{}%
+  }%
+  % If there are multiple backrefs, add them now.
+  \Dformatmultiplebackrefs{\DEVmultiplebackrefs}%
+}
+\providecommand{\Dsinglefootnotebacklink}[2]{%
+  % Create normal backlink of a footnote label.  Parameters:
+  % 1. ID.
+  % 2. Link text.
+  % Treat like a footnote reference.
+  \Dimplicitfootnotereference{\##1}{#2}%
+}
+\providecommand{\DECmultifootnotebacklink}[2]{%
+  % Create generated backlink, as in (1, 2).  Parameters:
+  % 1. ID.
+  % 2. Link text.
+  % Treat like a footnote reference.
+  \Dimplicitfootnotereference{\##1}{#2}%
+}
+\providecommand{\Dsinglecitationbacklink}[2]{\Dsinglefootnotebacklink{#1}{#2}}
+\providecommand{\DECmulticitationbacklink}[2]{\DECmultifootnotebacklink{#1}{#2}}
+
+
+\providecommand{\DECmaketable}[2]{%
+  % Make table.  Parameters:
+  % 1. Table spec (like "|p|p|").
+  % 2. Table contents.
+  {%
+    \ifthenelse{\equal{\Dinsidetabular}{true}}{%
+      % Inside longtable; we cannot have nested longtables.
+      \begin{tabular}{#1}%
+        \hline%
+        #2%
+      \end{tabular}%
+    }{%
+      \renewcommand{\Dinsidetabular}{true}%
+      \begin{longtable}{#1}%
+        \hline%
+        #2%
+      \end{longtable}%
+    }%
+  }%
+}
+\providecommand{\DNthead}[1]{%
+  #1%
+  \endhead%
+}
+\providecommand{\DNrow}[1]{%
+  #1\tabularnewline%
+  \hline%
+}
+\providecommand{\Dinsidemulticolumn}{false}
+\providecommand{\Dcompensatingmulticol}[3]{%
+  \multicolumn{#1}{#2}{%
+    {%
+      \renewcommand{\Dinsidemulticolumn}{true}%
+      % Compensate for weird missing vertical space at top of paragraph.
+      \raisebox{-2.5pt}{#3}%
+    }%
+  }%
+}
+\providecommand{\DECcolspan}[2]{%
+  % Take care of the morecols attribute (but incremented by 1).
+  &%
+  \Dcompensatingmulticol{#1}{l|}{#2}%
+}
+\providecommand{\DECcolspanleft}[2]{%
+  % Like \Dmorecols, but called for the leftmost entries in a table
+  % row.
+  \Dcompensatingmulticol{#1}{|l|}{#2}%
+}
+\providecommand{\DECsubsequententry}[1]{%
+  &#1%
+}
+\providecommand{\DNentry}[1]{%
+  % The following sequence adds minimal vertical space above the top
+  % lines of the first cell paragraph, so that vertical space is
+  % balanced at the top and bottom of table cells.
+  \ifthenelse{\equal{\Dinsidemulticolumn}{false}}{%
+    \vspace{-1em}\vspace{-\parskip}\par%
+  }{}%
+  #1%
+  % No need to add an ampersand ("&"); that's done by \DECsubsequententry.
+}
+\providecommand{\DAtableheaderentry}[5]{\Dformattableheaderentry{#5}}
+\providecommand{\Dformattableheaderentry}[1]{{\bfseries#1}}
+
+
+\providecommand{\DNsystemmessage}[1]{%
+  {%
+    \ifthenelse{\equal{\Dprinting}{false}}{\color{red}}{}%
+    \bfseries%
+    #1%
+  }%
+}
+
+
+\providecommand{\Dinsidehalign}{false}
+\newsavebox{\Dalignedimagebox}
+\Dprovidelength{\Dalignedimagewidth}{0pt}
+\providecommand{\Dhalign}[2]{%
+  % Horizontally align the contents to the left or right so that the
+  % text flows around it.
+  % Parameters:
+  % 1. l or r
+  % 2. Contents.
+  \renewcommand{\Dinsidehalign}{true}%
+  % For some obscure reason \parpic consumes some vertical space.
+  \vspace{-3pt}%
+  % Now we do something *really* ugly, but this enables us to wrap the
+  % image in a minipage while still allowing tight frames when
+  % class=border (see \DNimageCborder).
+  \sbox{\Dalignedimagebox}{#2}%
+  \settowidth{\Dalignedimagewidth}{\usebox{\Dalignedimagebox}}%
+  \parpic[#1]{%
+    \begin{minipage}[b]{\Dalignedimagewidth}%
+      % Compensate for previously added space, but not entirely.
+      \vspace*{2.0pt}%
+      \vspace*{\Dfloatimagetopmargin}%
+      \usebox{\Dalignedimagebox}%
+      \vspace*{1.5pt}%
+      \vspace*{\Dfloatimagebottommargin}%
+    \end{minipage}%
+  }%
+  \renewcommand{\Dinsidehalign}{false}%
+}
+
+
+% Maximum width of an image.
+\providecommand{\Dimagemaxwidth}{\linewidth}
+\providecommand{\Dfloatimagemaxwidth}{0.5\linewidth}
+% Auxiliary variable.
+\Dprovidelength{\Dcurrentimagewidth}{0pt}
+\providecommand{\DNimageAalign}[5]{%
+  \ifthenelse{\equal{#3}{left}}{%
+    \Dhalign{l}{#5}%
+  }{%
+    \ifthenelse{\equal{#3}{right}}{%
+      \Dhalign{r}{#5}%
+    }{%
+      \ifthenelse{\equal{#3}{center}}{%
+        % Text floating around centered figures is a bad idea.  Thus
+        % we use a center environment.  Note that no extra space is
+        % added by the writer, so the space added by the center
+        % environment is fine.
+        \begin{center}#5\end{center}%
+      }{%
+        #5%
+      }%
+    }%
+  }%
+}
+% Base path for images.
+\providecommand{\Dimagebase}{}
+% Auxiliary command.  Current image path.
+\providecommand{\Dimagepath}{}
+\providecommand{\DNimageAuri}[5]{%
+  % Insert image.  We treat the URI like a path here.
+  \renewcommand{\Dimagepath}{\Dimagebase#3}%
+  \Difdefined{DcurrentNimageAwidth}{%
+    \Dwidthimage{\DEVcurrentNimageAwidth}{\Dimagepath}%
+  }{%
+    \Dsimpleimage{\Dimagepath}%
+  }%
+}
+\Dprovidelength{\Dfloatimagevmargin}{0pt}
+\providecommand{\Dfloatimagetopmargin}{\Dfloatimagevmargin}
+\providecommand{\Dfloatimagebottommargin}{\Dfloatimagevmargin}
+\providecommand{\Dwidthimage}[2]{%
+  % Image with specified width.
+  % Parameters:
+  % 1. Image width.
+  % 2. Image path.
+  % Need to make bottom-alignment dependent on align attribute (add
+  % functional test first).  Need to observe height attribute.
+  %\begin{minipage}[b]{#1}%
+    \includegraphics[width=#1,height=\textheight,keepaspectratio]{#2}%
+  %\end{minipage}%
+}  
+\providecommand{\Dcurrentimagemaxwidth}{}
+\providecommand{\Dsimpleimage}[1]{%
+  % Insert image, without much parametrization.
+  \settowidth{\Dcurrentimagewidth}{\includegraphics{#1}}%
+  \ifthenelse{\equal{\Dinsidehalign}{true}}{%
+    \renewcommand{\Dcurrentimagemaxwidth}{\Dfloatimagemaxwidth}%
+  }{%
+    \renewcommand{\Dcurrentimagemaxwidth}{\Dimagemaxwidth}%
+  }%
+  \ifthenelse{\lengthtest{\Dcurrentimagewidth>\Dcurrentimagemaxwidth}}{%
+    \Dwidthimage{\Dcurrentimagemaxwidth}{#1}%
+  }{%
+    \Dwidthimage{\Dcurrentimagewidth}{#1}%
+  }%
+}
+\providecommand{\Dwidthimage}[2]{%
+  % Image with specified width.
+  % Parameters:
+  % 1. Image width.
+  % 2. Image path.
+  \Dwidthimage{#1}{#2}%
+}
+
+% Figures.
+\providecommand{\DNfigureAalign}[5]{%
+  % Hack to make it work Right Now.
+  %\def\DEVcurrentNimageAwidth{\DEVcurrentNfigureAwidth}%
+  %
+    %\def\DEVcurrentNimageAwidth{\linewidth}%
+    \DNimageAalign{#1}{#2}{#3}{#4}{%
+      \begin{minipage}[b]{0.4\linewidth}#5\end{minipage}}%
+    %\let\DEVcurrentNimageAwidth=\relax%
+  %
+  %\let\DEVcurrentNimageAwidth=\relax%
+}
+\providecommand{\DNcaption}[1]{\par\noindent{\slshape#1}}
+\providecommand{\DNlegend}[1]{\DECauxiliaryspace#1}
+
+\providecommand{\DCborder}[1]{\fbox{#1}}
+% No padding between image and border.
+\providecommand{\DNimageCborder}[1]{\frame{#1}}
+
+
+% Need to replace with language-specific stuff.  Maybe look at
+% csquotes.sty and ask the author for permission to use parts of it.
+\providecommand{\DECtextleftdblquote}{``}
+\providecommand{\DECtextrightdblquote}{''}
+
+% Table of contents:
+\Dprovidelength{\Dtocininitialsectnumwidth}{2.4em}
+\Dprovidelength{\Dtocadditionalsectnumwidth}{0.7em}
+% Level inside a table of contents.  While this is at -1, we are not
+% inside a TOC.
+\Dprovidecounter{Dtoclevel}{-1}%
+\providecommand{\Dlocaltoc}{false}%
+\providecommand{\DNtopicClocal}[1]{%
+  \renewcommand{\Dlocaltoc}{true}%
+  \addtolength{\Dtocsectnumwidth}{2\Dtocadditionalsectnumwidth}%
+  \addtolength{\Dtocindent}{-2\Dtocadditionalsectnumwidth}%
+  #1%
+  \addtolength{\Dtocindent}{2\Dtocadditionalsectnumwidth}%
+  \addtolength{\Dtocsectnumwidth}{-2\Dtocadditionalsectnumwidth}%
+  \renewcommand{\Dlocaltoc}{false}%
+}
+\Dprovidelength{\Dtocindent}{0pt}%
+\Dprovidelength{\Dtocsectnumwidth}{\Dtocininitialsectnumwidth}
+% Compensate for one additional TOC indentation space so that the
+% top-level is unindented.
+\addtolength{\Dtocsectnumwidth}{-\Dtocadditionalsectnumwidth}
+\addtolength{\Dtocindent}{-\Dtocsectnumwidth}
+\providecommand{\Difinsidetoc}[2]{%
+  \ifthenelse{\not\equal{\theDtoclevel}{-1}}{#1}{#2}%
+}
+\providecommand{\DNgeneratedCsectnum}[1]{%
+  \Difinsidetoc{%
+    % Section number inside TOC.
+    \makebox[\Dtocsectnumwidth][l]{#1}%
+  }{%
+    % Section number inside section title.
+    #1\quad%
+  }%
+}
+\providecommand{\Dtocbulletlist}[1]{%
+  \addtocounter{Dtoclevel}{1}%
+  \addtolength{\Dtocindent}{\Dtocsectnumwidth}%
+  \addtolength{\Dtocsectnumwidth}{\Dtocadditionalsectnumwidth}%
+  #1%
+  \addtolength{\Dtocsectnumwidth}{-\Dtocadditionalsectnumwidth}%
+  \addtolength{\Dtocindent}{-\Dtocsectnumwidth}%
+  \addtocounter{Dtoclevel}{-1}%
+}
+
+
+% For \DECpixelunit, the length value is pre-multiplied with 0.75, so by
+% specifying "pt" we get the same notion of "pixel" as graphicx.
+\providecommand{\DECpixelunit}{pt}
+% Normally lengths are relative to the current linewidth.
+\providecommand{\DECrelativeunit}{\linewidth}
+
+
+% ACTION: These commands actually *do* something.
+% Ultimately, everything should be done here, and no active content should be
+% above (not even \usepackage).
+
+\DSearly
+\DSpackages
+\DSfrenchspacing
+\DSsymbols
+\DSlate
+
+\makeatother
+
+  \usepackage{fancyvrb}
diff --git a/telemeta/util/audiolab/scikits/audiolab/docs/examples/format1.py b/telemeta/util/audiolab/scikits/audiolab/docs/examples/format1.py
new file mode 100644 (file)
index 0000000..f9166f9
--- /dev/null
@@ -0,0 +1,7 @@
+from scikits.audiolab import formatinfo as format
+
+f = format('aiff', 'ulaw')
+print f
+
+f = format('ircam', 'float32')
+print f
diff --git a/telemeta/util/audiolab/scikits/audiolab/docs/examples/format2.py b/telemeta/util/audiolab/scikits/audiolab/docs/examples/format2.py
new file mode 100644 (file)
index 0000000..6b176a6
--- /dev/null
@@ -0,0 +1,6 @@
+from scikits.audiolab import supported_format, supported_encoding, \
+            supported_endianness
+
+print supported_format()
+print supported_encoding()
+print supported_endianness()
diff --git a/telemeta/util/audiolab/scikits/audiolab/docs/examples/matlab1.py b/telemeta/util/audiolab/scikits/audiolab/docs/examples/matlab1.py
new file mode 100644 (file)
index 0000000..fe1e8fa
--- /dev/null
@@ -0,0 +1,20 @@
+from tempfile import mkstemp
+from os.path import join, dirname
+from os import remove
+
+from scikits.audiolab import wavread, wavwrite
+
+(tmp, fs, enc)  = wavread('test.wav')
+if tmp.ndim < 2:
+    nc  = 1
+else:
+    nc  = tmp.shape[1]
+
+print "The file has %d frames, %d channel(s)" % (tmp.shape[0], nc)
+print "FS is %f, encoding is %s" % (fs, enc)
+
+fd, cfilename   = mkstemp('pysndfiletest.wav')
+try:
+    wavwrite(tmp, cfilename, fs = 16000, enc = 'pcm24')
+finally:
+    remove(cfilename)
diff --git a/telemeta/util/audiolab/scikits/audiolab/docs/examples/quick1.py b/telemeta/util/audiolab/scikits/audiolab/docs/examples/quick1.py
new file mode 100644 (file)
index 0000000..1d3c473
--- /dev/null
@@ -0,0 +1,5 @@
+import scikits.audiolab as  audiolab
+
+a       = audiolab.sndfile('test.flac', 'read')
+data    = a.read_frames(1000)
+a.close()
diff --git a/telemeta/util/audiolab/scikits/audiolab/docs/examples/usage1.py b/telemeta/util/audiolab/scikits/audiolab/docs/examples/usage1.py
new file mode 100644 (file)
index 0000000..a689a01
--- /dev/null
@@ -0,0 +1,6 @@
+import scikits.audiolab as audiolab
+
+filename    = 'test.flac'
+a           = audiolab.sndfile(filename, 'read')
+
+print a
diff --git a/telemeta/util/audiolab/scikits/audiolab/docs/examples/usage2.py b/telemeta/util/audiolab/scikits/audiolab/docs/examples/usage2.py
new file mode 100644 (file)
index 0000000..0117e26
--- /dev/null
@@ -0,0 +1,12 @@
+import numpy as N
+
+import scikits.audiolab as audiolab
+
+filename    = 'test.flac'
+a           = audiolab.sndfile(filename, 'read')
+
+tmp         = a.read_frames(1e4)
+float_tmp   = a.read_frames(1e4, dtype = N.float32)
+
+import pylab as P
+P.plot(tmp[:])
diff --git a/telemeta/util/audiolab/scikits/audiolab/docs/examples/write1.py b/telemeta/util/audiolab/scikits/audiolab/docs/examples/write1.py
new file mode 100644 (file)
index 0000000..b0fd136
--- /dev/null
@@ -0,0 +1,34 @@
+from tempfile import mkstemp
+from os import remove
+
+import numpy as N
+from scikits.audiolab import formatinfo as format
+import scikits.audiolab as audiolab
+
+# Create a temp file in the system temporary dir, and always remove
+# it at the end
+cd, filename    = mkstemp('tmptest.wav')
+try:
+    fmt         = format('wav', 'pcm24')
+    nchannels   = 2
+    fs          = 44100
+
+    afile =  audiolab.sndfile(filename, 'write', fmt, nchannels, fs)
+
+    # Create a stereo white noise, with Gaussian distribution
+    tmp = 0.1 * N.random.randn(1000, nchannels)
+
+    # Write the first 500 frames of the signal
+    # Note that the write_frames method uses tmp's numpy dtype to determine how
+    # to write to the file; sndfile also converts the data on the fly if necessary
+    afile.write_frames(tmp, 500)
+
+    afile.close()
+
+    # Let's check that the written file has the expected meta data
+    afile = audiolab.sndfile(filename, 'read')
+    assert(afile.get_samplerate() == fs)
+    assert(afile.get_channels() == nchannels)
+    assert(afile.get_nframes() == 500)
+finally:
+    remove(filename)
diff --git a/telemeta/util/audiolab/scikits/audiolab/docs/index.txt b/telemeta/util/audiolab/scikits/audiolab/docs/index.txt
new file mode 100644 (file)
index 0000000..5411017
--- /dev/null
@@ -0,0 +1,264 @@
+..
+    restindex
+        page-title: audiolab
+        crumb: audiolab
+        link-title: audiolab
+        encoding: utf-8
+        output-encoding: None 
+        file: audiolab1.png
+        file: quick1.py
+        file: usage1.py
+        file: usage2.py
+        file: format1.py
+        file: format2.py
+        file: write1.py
+        file: matlab1.py
+        file: audiolab.pdf
+    /restindex
+
+.. vim:syntax=rest
+.. Last Change: Tue Jul 17 11:00 AM 2007 J
+
+===============================================================
+ Pyaudiolab, a python package to make noise with numpy arrays
+===============================================================
+
+Introduction
+============
+
+.. _scipy: http://www.scipy.org
+.. _libsndfile: http://www.mega-nerd.com/libsndfile/
+
+For people doing audio processing, it is useful to be able to import data from
+audio files, and export them back, as well as listening to the results of some
+processing; matlab have functions such as wavread, wavwrite, soundsc, etc...
+for that purposes.  The goal of audiolab is to give those capabilities to the
+`scipy`_ environment by wrapping the excellent library `libsndfile`_ from Erik
+Castro de Lopo. Pyaudio supports all format supported by libsndfile, including
+wav, aiff, ircam files, and flac (an open source lossless compressed format);
+see `here <http://www.mega-nerd.com/libsndfile/#Features">`_ for a complete
+list.
+
+    **Note**: The library is still in beta stage: reading and writing 
+    data is possible, but only in frames, not per item.
+    Also, the ability to play data on the system's soundcard is not there yet.
+    I have never encountered any data corruption, except when using the buggy
+    ctypes included in Ubuntu's python 2.5 (bug which was solved recently).
+
+    **Note**: The online version of this document is not always up to date. The
+    pdf included in the package is the reference, and always in sync with the
+    package. If something does not work, please refer first to the pdf included in
+    the package.
+
+.. contents:: Tables of contents
+
+Download and installation
+=========================
+                
+Download
+--------
+
+audiolab is part of scikits: its source can be downloaded directly from the
+scikits svn repository: svn co http://svn.scipy.org/svn/scikits/trunk/audiolab
+
+Requirements
+------------
+
+audiolab requires the following softwares:
+
+ - a python interpreter.
+ - libsndfile (including the header sndfile.h, which means linux users should
+   download the libsndfile-dev package).
+ - numpy (any version >= 1.0 should work).
+ - ctypes (version >= 1.0.1)
+
+Starting with version 2.5, python include ctypes in its standart library, so you
+don't need to install ctypes separately in this case.
+
+It has been run succesfully on the following platforms:
+
+    - linux ubuntu (32 and 64 bits)
+    - windows XP
+
+I would be interested to hear anyone who succeesfully used it on other
+plateforms (Mac Os X, solaris, etc...).
+
+    **Note**: the ctypes used in python2.5 package in ubuntu (and maybe debian
+    as well) *had* a nasty bug which makes it impossible to use 64 bits integers. You
+    should NOT use this package with audiolab (importing audiolab should fail,
+    but if the version is not correctly detected, you will have file corruption when
+    writing data to audio files). Run the test to check everything is working (a
+    test case tests this issue).
+
+    `<https://launchpad.net/ubuntu/+source/python2.5/+bug/71914>`_
+
+
+Installation
+------------
+
+For unix users, if libsndfile is installed in standart location (eg /usr/lib,
+/usr/local/lib), the installer should be able to find them automatically, and
+you only need to do a "python setup.py install". In other cases, you need to
+create a file site.cfg to set the location of libsndfile and its header (there
+are site.cfg examples which should give you an idea how to use them on your
+platform).
+
+For windows users: the library distributed by Erik Castro de Lopo cannot be
+used directly; you need to follow the instructions given in libsndfile
+distribution in the file README-precompiled-dll.txt. See also site.cfg.win32.
+
+License
+-------
+            
+audiolab is released under the LGPL, which forces you to release back the
+modifications you may make in the version of audiolab you are distributing,
+but you can still use it in closed softwares.
+
+Quick view
+==========
+
+The following code shows you how to open a file for read, reading the first
+1000 frames, and closing it:
+
+.. raw:: html
+
+    {mycolorize;input/softwares/audiolab/quick1.py}
+
+.. raw:: latex
+
+    \input{quick1.tex}
+
+Usage
+=====
+            
+Opening a file and getting its parameters
+-----------------------------------------
+
+Once imported, audiolab gives you access the sndfile class, which is the
+class of audiolab use to open audio files. 
+You create a sndfile instance when you want
+to open a file for reading or writing (the file test.flac is included
+in the audiolab package, in the test_data directory):
+            
+.. raw:: html
+
+    {mycolorize;input/softwares/audiolab/usage1.py}
+
+.. raw:: latex
+
+    \input{usage1.tex}
+
+Prints you the informations related to the file, like its sampling rate, 
+the number of frames, etc... You can of course get each parameter 
+individually by using the corresponding sndfile.get* accessors.
+
+Importing audio data
+--------------------
+
+Now that we've opened a file, we would like to read its audio content, 
+right ? For now, you can only import the data as floating point data, 
+float  (32 bits) or double (64 bits). The function 
+sndfile.read_frames read n frames,
+where a frame contains a sample of each channel (one in mono, 2 in stereo,
+etc...):
+
+.. raw:: html
+
+    {mycolorize;input/softwares/audiolab/usage2.py}
+
+.. raw:: latex
+
+    \input{usage2.tex}
+
+The above code import 10000 frames, and plot the first channel using matplotlib
+(see below). A frame holds one sample from each channel: 1000 frames of a stereo
+file is 2000 samples. Each channel is one column of the numpy array. The read
+functions follow numpy conventions, that is by default, the data are read as
+double, but you can give a dtype argument to the function.
+
+.. image:: audiolab1.png
+    :width: 500
+    :height: 400
+
+The format class
+----------------
+
+When opening a file for writing, you need to give various parameters related to
+the format such as the file format, the encoding.  The format class is used to
+create valid formats from those parameters  By default, the format class creates
+a format object with file type wav, and 16 bits pcm encoding: 
+
+.. raw:: html
+
+    {mycolorize;input/softwares/audiolab/format1.py}
+
+.. raw:: latex
+
+    \input{format1.tex}
+
+prints back "Major Format: AIFF (Apple/SGI), Encoding Format: U-Law"
+and "Major Format: SF (Berkeley/IRCAM/CARL), Encoding Format: 32 bit float". 
+
+To get a list of all possible file format and encoding, the function
+supported_* are available:
+
+.. raw:: html
+
+    {mycolorize;input/softwares/audiolab/format2.py}
+
+.. raw:: latex
+
+    \input{format2.tex}
+
+    **Note**: not all combination of encoding, endianness and format are possible.
+    If you try to create a format with incompatible values, you will get an error
+    while creating an instance of format.
+
+Writing data to a file
+----------------------
+
+Opening a file for writing is a bit more complicated than reading; you need to
+say which format you are requesting, the number of channels and the sampling
+rate (in Hz) you are requesting; all thoses information are mandatory !  The
+class format is used to build a format understable by libsndfile from
+'user-friendly' values. Let's see how it works.
+
+.. raw:: html
+
+    {mycolorize;input/softwares/audiolab/write1.py}
+
+.. raw:: latex
+
+    \input{write1.tex}
+
+Matlab-like API
+---------------
+
+audiolab also have a matlab-like API for audio IO. Its usage is as similar as it
+can get using python:
+
+.. raw:: html
+
+    {mycolorize;input/softwares/audiolab/matlab1.py}
+
+.. raw:: latex
+
+    \input{matlab1.tex}
+
+Known bugs:
+===========
+
+ - there seems to be a problem when using libsndfile fseek facilities with flac
+   files (which are necessary for the functions flacread/flacwrite). The
+   problem seems to be with libFLAC; for this reason, seek in flac files is not
+   enabled by default for now. See FLAC_SUPPORT.txt for more informations.
+    
+TODO
+====
+
+audiolab is still in early stages. Before a release, I would like to implement the
+follwings:
+
+ - support (at least some) meta-data embedded in some audio files format.
+ - support the libsndfile's error system
+ - player on all major plateforms (at least linux/windows/max OS X)
diff --git a/telemeta/util/audiolab/scikits/audiolab/docs/user.tex b/telemeta/util/audiolab/scikits/audiolab/docs/user.tex
new file mode 100644 (file)
index 0000000..6ea7099
--- /dev/null
@@ -0,0 +1,64 @@
+% Last Change: Wed Jan 31 08:00 PM 2007 J
+% vim:syntax=tex
+
+\newcommand\at{@}
+\newcommand\lb{[}
+\newcommand\rb{]}
+\newcommand\Cba[1]{\textcolor[rgb]{0.67,0.13,1.00}{\textbf{#1}}}
+\newcommand\Caz[1]{\textcolor[rgb]{0.00,0.25,0.82}{#1}}
+\newcommand\Cay[1]{\textcolor[rgb]{0.67,0.13,1.00}{#1}}
+\newcommand\Cax[1]{\textcolor[rgb]{0.00,0.63,0.00}{#1}}
+\newcommand\Cbc[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
+\newcommand\Cas[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
+\newcommand\Car[1]{\textcolor[rgb]{0.72,0.53,0.04}{#1}}
+\newcommand\Caq[1]{\textcolor[rgb]{0.73,0.27,0.27}{\textit{#1}}}
+\newcommand\Cap[1]{\textcolor[rgb]{0.72,0.53,0.04}{#1}}
+\newcommand\Caw[1]{\textcolor[rgb]{0.67,0.13,1.00}{\textbf{#1}}}
+\newcommand\Cav[1]{\textcolor[rgb]{0.60,0.60,0.60}{\textbf{#1}}}
+\newcommand\Cau[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
+\newcommand\Cat[1]{\textcolor[rgb]{0.67,0.13,1.00}{\textbf{#1}}}
+\newcommand\Cak[1]{\textbf{#1}}
+\newcommand\Caj[1]{\textcolor[rgb]{0.73,0.40,0.53}{#1}}
+\newcommand\Cai[1]{\textcolor[rgb]{0.72,0.53,0.04}{#1}}
+\newcommand\Cah[1]{\textcolor[rgb]{0.63,0.63,0.00}{#1}}
+\newcommand\Cao[1]{\textcolor[rgb]{0.53,0.00,0.00}{#1}}
+\newcommand\Can[1]{\textcolor[rgb]{0.00,0.50,0.00}{#1}}
+\newcommand\Cam[1]{\textcolor[rgb]{0.73,0.40,0.13}{\textbf{#1}}}
+\newcommand\Cal[1]{\textcolor[rgb]{0.67,0.13,1.00}{\textbf{#1}}}
+\newcommand\Cac[1]{\textcolor[rgb]{0.73,0.27,0.27}{#1}}
+\newcommand\Cab[1]{\textit{#1}}
+\newcommand\Caa[1]{\textcolor[rgb]{0.50,0.50,0.50}{#1}}
+\newcommand\Cag[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
+\newcommand\Caf[1]{\textcolor[rgb]{0.00,0.53,0.00}{\textit{#1}}}
+\newcommand\Cae[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
+\newcommand\Cad[1]{\textcolor[rgb]{0.73,0.27,0.27}{#1}}
+\newcommand\Cbb[1]{\textcolor[rgb]{0.73,0.27,0.27}{#1}}
+\newcommand\CaZ[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
+\newcommand\CaY[1]{\textcolor[rgb]{0.00,0.00,0.50}{\textbf{#1}}}
+\newcommand\CaX[1]{\textcolor[rgb]{0.00,0.50,0.00}{\textbf{#1}}}
+\newcommand\Cbd[1]{\textcolor[rgb]{0.73,0.40,0.53}{\textbf{#1}}}
+\newcommand\Cbe[1]{\textcolor[rgb]{0.67,0.13,1.00}{\textbf{#1}}}
+\newcommand\CaS[1]{\textcolor[rgb]{0.50,0.00,0.50}{\textbf{#1}}}
+\newcommand\CaR[1]{\textcolor[rgb]{0.00,0.53,0.00}{\textit{#1}}}
+\newcommand\CaQ[1]{\textcolor[rgb]{0.72,0.53,0.04}{#1}}
+\newcommand\CaP[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
+\newcommand\CaW[1]{\textcolor[rgb]{0.73,0.27,0.27}{#1}}
+\newcommand\CaV[1]{\textcolor[rgb]{0.67,0.13,1.00}{#1}}
+\newcommand\CaU[1]{\textcolor[rgb]{0.73,0.27,0.27}{#1}}
+\newcommand\CaT[1]{\textcolor[rgb]{0.00,0.00,1.00}{\textbf{#1}}}
+\newcommand\CaK[1]{\textcolor[rgb]{0.67,0.13,1.00}{#1}}
+\newcommand\CaJ[1]{\textcolor[rgb]{0.00,0.63,0.00}{#1}}
+\newcommand\CaI[1]{\textcolor[rgb]{0.73,0.27,0.27}{#1}}
+\newcommand\CaH[1]{\textcolor[rgb]{0.67,0.13,1.00}{\textbf{#1}}}
+\newcommand\CaO[1]{\textcolor[rgb]{0.73,0.27,0.27}{#1}}
+\newcommand\CaN[1]{\textcolor[rgb]{0.00,0.00,0.50}{\textbf{#1}}}
+\newcommand\CaM[1]{\textcolor[rgb]{0.00,0.00,1.00}{#1}}
+\newcommand\CaL[1]{\textcolor[rgb]{0.00,0.53,0.00}{#1}}
+\newcommand\CaC[1]{\textcolor[rgb]{0.00,0.53,0.00}{\textit{#1}}}
+\newcommand\CaB[1]{\textcolor[rgb]{0.82,0.25,0.23}{\textbf{#1}}}
+\newcommand\CaA[1]{\textcolor[rgb]{0.67,0.13,1.00}{#1}}
+\newcommand\CaG[1]{\fcolorbox[rgb]{1.00,0.00,0.00}{1,1,1}{#1}}
+\newcommand\CaF[1]{\textcolor[rgb]{0.72,0.53,0.04}{#1}}
+\newcommand\CaE[1]{\textcolor[rgb]{1.00,0.00,0.00}{#1}}
+\newcommand\CaD[1]{\textcolor[rgb]{0.63,0.00,0.00}{#1}}
+
diff --git a/telemeta/util/audiolab/scikits/audiolab/info.py b/telemeta/util/audiolab/scikits/audiolab/info.py
new file mode 100644 (file)
index 0000000..47dd67f
--- /dev/null
@@ -0,0 +1,2 @@
+VERSION = '0.8dev'
+ignore  = False
diff --git a/telemeta/util/audiolab/scikits/audiolab/info.pyc b/telemeta/util/audiolab/scikits/audiolab/info.pyc
new file mode 100644 (file)
index 0000000..08186b2
Binary files /dev/null and b/telemeta/util/audiolab/scikits/audiolab/info.pyc differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/matapi.py b/telemeta/util/audiolab/scikits/audiolab/matapi.py
new file mode 100644 (file)
index 0000000..1568fe9
--- /dev/null
@@ -0,0 +1,148 @@
+#! /usr/bin/env python
+# Last Change: Mon Sep 10 07:00 PM 2007 J
+
+# Copyright (C) 2006-2007 Cournapeau David <cournape@gmail.com>
+#
+# 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.1 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+"""This module implements functions to read and write to audio files easily
+(ala matlab: wavread, etc...)."""
+
+import numpy as N
+
+from pysndfile import formatinfo, sndfile
+from pysndfile import PyaudioException, FlacUnsupported
+
+__all__ = []
+_MATAPI_FORMAT = ['wav', 'aiff', 'au', 'sdif', 'flac']
+for i in _MATAPI_FORMAT:
+    __all__.extend(['%sread' % i, '%swrite' % i])
+
+# writer function factory
+def _writer_factory(name, format, def_fs, descr):
+    """ Create a writer function with fileformat described by format, default
+    sampling rate def_fs, and docstring descr."""
+    def basic_writer(data, filename, fs = def_fs, enc = format.get_encoding()):
+        """Common "template" to all write functions."""
+        if N.ndim(data) <= 1:
+            nc      = 1
+            nframes = N.size(data)
+        elif N.ndim(data) == 2: 
+            nc      = data.shape[1]
+            nframes = data.shape[0]
+        else:
+            RuntimeError("Only rank 0, 1, and 2 arrays supported as audio data")
+
+        hdl = sndfile(filename, 'write', format, nc, fs)
+        try:
+            hdl.write_frames(data, nframes)
+        finally:
+            hdl.close()
+    doc = \
+    """ wrapper around pysndfile to write %s file,
+    in a similar manner to matlab's wavwrite/auwrite and the likes.
+
+    OVERWRITES EXISTING FILE !
+
+    Args:
+        - data: a rank 0, 1 (mono) or 2 (one channel per col) numpy array
+        - filename: a string for the audio file name 
+        - fs: the sampling rate in Hz (%d Hz by default).
+        - enc: a string for the encoding such as 'pcm16', etc...(%s by
+          default). Not supported yet !
+
+    For a total control over options, such as endianness, append data to an
+    existing file, etc...  you should use sndfile class instances instead""" \
+            % (str(descr), def_fs, format.get_encoding())
+    basic_writer.__doc__    = doc
+    basic_writer.__name__   = name
+    return basic_writer
+    
+# template for reader functions
+def _reader_factory(name, filetype, descr):
+    """Factory for reader functions ala matlab."""
+    def basic_reader(filename, last = None, first = 0):
+        """Common "template" to all read functions."""
+        hdl = sndfile(filename, 'read')
+        try:
+            if not hdl.get_file_format() == filetype:
+                raise PyaudioException("%s is not a %s file (is %s)" \
+                        % (filename, filetype, hdl.get_file_format()))
+
+            fs = hdl.get_samplerate()
+            enc = hdl.get_encoding()
+            # Set the pointer to start position
+            nf  = hdl.seek(first, 1)
+            if not nf == first:
+                raise IOError("Error while seeking at starting position")
+
+            if last is None:
+                nframes = hdl.get_nframes() - first
+                data    = hdl.read_frames(nframes)
+            else:
+                data    = hdl.read_frames(last)
+        finally:
+            hdl.close()
+
+        return data, fs, enc
+    doc = \
+    """ wrapper around pysndfile to read a %s file in float64,
+    in a similar manner to matlab wavread/auread/etc...
+
+    Returns a tuple (data, fs, enc), where :
+        - data are the read data (one column per channel)
+        - fs, the sampling rate
+        - enc, a string which is the encoding of the file, such as 'pcm16', 
+        'float32', etc...
+
+    For a total control over options, such as output's dtype, etc..., 
+    you should use sndfile class instances instead""" % (str(descr),)
+    basic_reader.__doc__    = doc
+    basic_reader.__name__   = name
+    return basic_reader
+    
+wavread     = _reader_factory('wavread', 'wav', 
+                    formatinfo('wav', 'pcm16').get_major_str())
+auread      = _reader_factory('auread', 'au',
+                    formatinfo('au', 'pcm16').get_major_str())
+aiffread    = _reader_factory('aiffread', 'aiff', 
+                    formatinfo('aiff', 'pcm16').get_major_str())
+sdifread    = _reader_factory('sdifread', 'ircam', 
+                    formatinfo('ircam', 'pcm16').get_major_str())
+
+_f1          = formatinfo('wav', 'pcm16')
+wavwrite    = _writer_factory('wavwrite', _f1, 8000, _f1.get_major_str())
+
+_f2          = formatinfo('au', 'ulaw')
+auwrite     = _writer_factory('auwrite', _f2, 8000, _f2.get_major_str())
+
+_f3          = formatinfo('aiff', 'pcm16')
+aiffwrite   = _writer_factory('aiffwrite', _f3, 8000, _f3.get_major_str())
+
+_f4          = formatinfo('ircam', 'pcm16')
+sdifwrite   = _writer_factory('sdifwrite', _f4, 44100, _f4.get_major_str())
+
+try:
+    flacread    = _reader_factory('flacread', 'flac', 
+                        formatinfo('flac', 'pcm16').get_major_str())
+    _f5          = formatinfo('flac', 'pcm16')
+    flacwrite   = _writer_factory('flacwrite', _f5, 44100, _f5.get_major_str())
+except FlacUnsupported,e:
+    print e
+    print "Matlab API for FLAC is disabled"
+    def missing_flacread(*args):
+        raise UnimplementedError("Matlab API for FLAC is disabled on your "\
+                                 "installation")
+    flacread    = missing_flacread
+    flacwrite   = missing_flacread
diff --git a/telemeta/util/audiolab/scikits/audiolab/matapi.pyc b/telemeta/util/audiolab/scikits/audiolab/matapi.pyc
new file mode 100644 (file)
index 0000000..d1abc0b
Binary files /dev/null and b/telemeta/util/audiolab/scikits/audiolab/matapi.pyc differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/misc/Makefile b/telemeta/util/audiolab/scikits/audiolab/misc/Makefile
new file mode 100644 (file)
index 0000000..2fcbde2
--- /dev/null
@@ -0,0 +1,23 @@
+CC     = colorgcc
+LD     = gcc
+
+CFLAGS = -Wall -W
+
+winfdopen: winfdopen.o
+       $(LD) $< -o $@ -lsndfile
+
+winfdopen.o: winfdopen.c
+       $(CC) $(CFLAGS) -c $< -o $@
+
+badflac: badflac.o
+       $(LD) $< -o $@ -lsndfile
+
+badflac.o: badflac.c
+       $(CC) $(CFLAGS) -c $< -o $@
+
+test_badflac: badflac badflac.flac
+       ./badflac badflac.flac
+
+clean:
+       rm -f *.o
+       rm -f badflac
diff --git a/telemeta/util/audiolab/scikits/audiolab/misc/Sconstruct b/telemeta/util/audiolab/scikits/audiolab/misc/Sconstruct
new file mode 100644 (file)
index 0000000..6c29ab3
--- /dev/null
@@ -0,0 +1,5 @@
+# vim:syntax=python
+# Last Change: Fri Jun 01 12:00 PM 2007 J
+#
+mainobj = Object('winfdopen.c')
+winfd = Program(mainobj, LIBS = ['sndfile'])
diff --git a/telemeta/util/audiolab/scikits/audiolab/misc/badflac.c b/telemeta/util/audiolab/scikits/audiolab/misc/badflac.c
new file mode 100644 (file)
index 0000000..906ad44
--- /dev/null
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sndfile.h>
+
+int main(int argc, char *argv[])
+{
+    SF_INFO     info;
+    SNDFILE*    file;
+    sf_count_t  nf;
+
+    char  buffer [2048] ;
+    if (argc < 2) {
+        fprintf(stderr, "usage: badflac filename \n");
+        exit(EXIT_FAILURE);
+    } 
+
+    info.format = 0;
+    file        = sf_open(argv[1], SFM_READ, &info);
+    if (file == NULL) {
+        fprintf(stderr, "%s:%s failed opening file %s\n", __FILE__, __func__, argv[1]);
+        sf_command (file, SFC_GET_LOG_INFO, buffer, sizeof (buffer)) ;
+        fprintf(stderr, "sndfile error is %s:\n", buffer);
+        exit(EXIT_FAILURE);
+    }
+
+    fprintf(stderr, "Values of seek are on this platform: SET %d, CUR %d, END %d\n",
+            SEEK_SET, SEEK_CUR, SEEK_END);
+
+    fprintf(stderr, "trying to seek %lld frames\n", (long long)1);
+    nf  = sf_seek(file, 1, SEEK_CUR);
+    fprintf(stderr, "seeked through %lld frames\n", nf);
+
+    sf_close(file);
+
+    return 0;
+}
diff --git a/telemeta/util/audiolab/scikits/audiolab/misc/badflac.flac b/telemeta/util/audiolab/scikits/audiolab/misc/badflac.flac
new file mode 100644 (file)
index 0000000..70d0a65
Binary files /dev/null and b/telemeta/util/audiolab/scikits/audiolab/misc/badflac.flac differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/misc/winfdopen.c b/telemeta/util/audiolab/scikits/audiolab/misc/winfdopen.c
new file mode 100644 (file)
index 0000000..de95e45
--- /dev/null
@@ -0,0 +1,82 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include <sndfile.h>
+
+#ifdef _MSC_VER
+#define __func__ __FUNCTION__
+#else
+#include <unistd.h>
+#endif
+
+int test(const char* filename, int byfd);
+
+int main(int argc, char *argv[])
+{
+    int st;
+
+    if (argc < 2) {
+        fprintf(stderr, "usage: %s filename \n", argv[0]);
+        exit(EXIT_FAILURE);
+    } 
+
+    st = test(argv[1], 0);
+    if (st) {
+        fprintf(stderr, "Error while opening directly\n");
+    } else {
+        fprintf(stderr, "Opening directly is fine\n");
+    }
+
+    st = test(argv[1], 1);
+    if (st) {
+        fprintf(stderr, "Error while opening by fd\n");
+    } else {
+        fprintf(stderr, "Opening by fd is fine\n");
+    }
+
+    return 0;
+}
+
+/* If byfd is true, try to open the file with sf_open_fd */
+int test(const char* filename, int byfd)
+{
+    SF_INFO     info;
+    SNDFILE*    file;
+    int         fid, flags, st;
+    char        buffer [2048];
+
+    st  = 0;
+
+    flags = O_RDONLY;
+#if (defined (WIN32) || defined (_WIN32))
+    flags |= O_BINARY;
+#endif
+
+    info.format = 0;
+    if (byfd) {
+        fid = open(filename, flags);
+        if (fid < 0) {
+            fprintf(stderr, "%s:%s failed opening file %s\n", __FILE__, __func__, filename);
+            return -1;
+        }
+
+        file = sf_open_fd(fid, SFM_READ, &info, SF_TRUE);
+    } else {
+        file = sf_open(filename, SFM_READ, &info);
+    }
+
+    if (file == NULL) {
+        fprintf(stderr, "%s:%s failed opening file %s\n", __FILE__, __func__, filename);
+        sf_command (file, SFC_GET_LOG_INFO, buffer, sizeof (buffer)) ;
+        fprintf(stderr, "sndfile error is %s:\n", buffer);
+        close(fid);
+        exit(EXIT_FAILURE);
+    } else {
+        fprintf(stderr, "%s:%s file %s has %d frames \n", __FILE__, __func__, filename, info.frames);
+    }
+
+    sf_close(file);
+
+    return st;
+}
diff --git a/telemeta/util/audiolab/scikits/audiolab/pyaudioio.py b/telemeta/util/audiolab/scikits/audiolab/pyaudioio.py
new file mode 100644 (file)
index 0000000..94c1e9f
--- /dev/null
@@ -0,0 +1,68 @@
+#! /usr/bin/env python
+# Last Change: Tue May 22 10:00 AM 2007 J
+
+# Copyright (C) 2006-2007 Cournapeau David <cournape@gmail.com>
+#
+# 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.1 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., 51
+# Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+# TODO:
+#   - find out why finally does not work with KeyboardInterrupt instances
+
+from tempfile import mkstemp
+from os import remove, popen
+
+from pysndfile import sndfile, formatinfo as format
+
+def play(input, sr = 22050):
+    """play(input, sr = 22050): "play" a numpy array input
+    to the audio device using aplay command, @ sampling rate
+    sr. 
+    
+    Warning: This is really crude, as it copies the numpy array
+    into an audio file before writing: I am too lazy to write
+    interfaces to also, windows and co..."""
+    # Check inputs are OK
+    if input.ndim   == 1:
+        nc      = 1
+        nframes = input.size
+    else:
+        (nframes, nc)   = input.shape
+
+    # Create tmp file
+    fd, filename    = mkstemp('py_player')
+
+    # Copy the data into it
+    b       = sndfile(filename, 'write', format('wav', 'pcm16'), nc, sr)
+    b.write_frames(input, nframes)
+    b.close()
+
+    # Play using an audio command
+    try:
+        cmd = "aplay %s" % filename
+        popen(cmd)
+        remove(filename)
+    except KeyboardInterrupt, inst:
+        remove(filename)
+        raise inst
+
+if __name__ == '__main__':
+    # Read the content of a file into numpy array, and play the numpy
+    # array using the play command
+    import numpy as N
+    sr      = 22050
+    # Play a really small noise to avoid screaming in loudspeakers
+    # or headphones.
+    noise   = 0.0001 * N.random.randn((sr))
+    play(noise, sr)
diff --git a/telemeta/util/audiolab/scikits/audiolab/pysndfile.py b/telemeta/util/audiolab/scikits/audiolab/pysndfile.py
new file mode 100644 (file)
index 0000000..2fea1fe
--- /dev/null
@@ -0,0 +1,992 @@
+#! /usr/bin/env python
+# Last Change: Wed Oct 03 05:00 PM 2007 J
+
+# Copyright (C) 2006-2007 Cournapeau David <cournape@gmail.com>
+#
+# 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.1 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+# vim:syntax=python
+
+# TODO:
+#   - import format classes so that we get meaningful information from an
+#   existing format
+#   - better API for reader/writer, including integer formats and partial
+#   reading
+#   - ability to get log of sndfile ?
+#   - check how to play sound under windows, OS X and other UNIX
+
+"""This module implements the wrappers around libsndfile."""
+
+__docformat__ = 'restructuredtext'
+
+#__all__ = ['sndfile', 'formatinfo']
+
+import copy
+import warnings
+
+#================
+# Load libsndfile
+#================
+import ctypes
+from ctypes import cdll, Structure, c_int, pointer, POINTER, \
+        create_string_buffer, c_char_p, sizeof, string_at
+try:
+    from ctypes import c_int64
+except ImportError, e:
+    print "Cannot import c_int64 from ctypes: if you are on ubuntu/debian," +\
+        " this is likely because ctypes was compiled with libffi. see" +\
+        " https://launchpad.net/ubuntu/+source/python2.5/+bug/71914"
+    raise e
+
+from numpy.ctypeslib import ndpointer
+CTYPES_MAJOR    = int(ctypes.__version__.split('.')[0])
+CTYPES_MINOR    = int(ctypes.__version__.split('.')[1])
+CTYPES_MICRO    = int(ctypes.__version__.split('.')[2])
+if CTYPES_MAJOR < 1 or (CTYPES_MINOR == 0 and CTYPES_MICRO < 1):
+    raise ImportError("version of ctypes is %s, expected at least %s" \
+            % (ctypes.__version__, '1.0.1'))
+import numpy as N
+
+_SND = cdll.LoadLibrary('/usr/lib/libsndfile.so.1')
+
+#=========================
+# Definition of constants
+#=========================
+# READ/WRITE Mode
+SFM = {
+       'SFM_WRITE'     : 0x20,
+       'SFM_RDWR'      : 0x30,
+       'SFM_READ'      : 0x10
+}
+
+# SF BOOL
+SF_BOOL = {
+       'SF_TRUE'       : 1,
+       'SF_FALSE'      : 0
+}
+
+# Format
+SF_FORMAT = {
+       'SF_FORMAT_VOX_ADPCM'   : 0x0021,
+       'SF_FORMAT_FLOAT'       : 0x0006,
+       'SF_FORMAT_PCM_S8'      : 0x0001,
+       'SF_FORMAT_IMA_ADPCM'   : 0x0012,
+       'SF_FORMAT_SVX' : 0x060000,
+       'SF_FORMAT_VOC' : 0x080000,
+       'SF_FORMAT_PCM_U8'      : 0x0005,
+       'SF_FORMAT_ALAW'        : 0x0011,
+       'SF_FORMAT_G721_32'     : 0x0030,
+       'SF_FORMAT_DWVW_N'      : 0x0043,
+       'SF_FORMAT_WAV' : 0x010000,
+       'SF_FORMAT_SD2' : 0x160000,
+       'SF_FORMAT_HTK' : 0x100000,
+       'SF_FORMAT_ENDMASK'     : 0x30000000,
+       'SF_FORMAT_DPCM_16'     : 0x0051,
+       'SF_FORMAT_DWVW_24'     : 0x0042,
+       'SF_FORMAT_PCM_32'      : 0x0004,
+       'SF_FORMAT_WAVEX'       : 0x130000,
+       'SF_FORMAT_DOUBLE'      : 0x0007,
+       'SF_FORMAT_NIST'        : 0x070000,
+       'SF_FORMAT_PCM_16'      : 0x0002,
+       'SF_FORMAT_RAW' : 0x040000,
+       'SF_FORMAT_W64' : 0x0B0000,
+       'SF_FORMAT_PVF' : 0x0E0000,
+       'SF_FORMAT_AU'  : 0x030000,
+       'SF_FORMAT_GSM610'      : 0x0020,
+       'SF_FORMAT_CAF' : 0x180000,
+       'SF_FORMAT_PAF' : 0x050000,
+       'SF_FORMAT_ULAW'        : 0x0010,
+       'SF_FORMAT_MAT4'        : 0x0C0000,
+       'SF_FORMAT_MAT5'        : 0x0D0000,
+       'SF_FORMAT_XI'  : 0x0F0000,
+       'SF_FORMAT_SUBMASK'     : 0x0000FFFF,
+       'SF_FORMAT_DPCM_8'      : 0x0050,
+       'SF_FORMAT_G723_24'     : 0x0031,
+       'SF_FORMAT_G723_40'     : 0x0032,
+       'SF_FORMAT_DWVW_16'     : 0x0041,
+       'SF_FORMAT_AIFF'        : 0x020000,
+       'SF_FORMAT_DWVW_12'     : 0x0040,
+       'SF_FORMAT_TYPEMASK'    : 0x0FFF0000,
+       'SF_FORMAT_FLAC'        : 0x170000,
+       'SF_FORMAT_PCM_24'      : 0x0003,
+       'SF_FORMAT_SDS' : 0x110000,
+       'SF_FORMAT_IRCAM'       : 0x0A0000,
+       'SF_FORMAT_MS_ADPCM'    : 0x0013,
+       'SF_FORMAT_AVR' : 0x120000
+}
+
+# ENDIANESS
+SF_ENDIAN = {
+       'SF_ENDIAN_BIG' : 0x20000000,
+       'SF_ENDIAN_FILE'        : 0x00000000,
+       'SF_ENDIAN_LITTLE'      : 0x10000000,
+       'SF_ENDIAN_CPU' : 0x30000000
+}
+
+# Commands
+SF_COMMAND = {
+       'SFC_GET_LIB_VERSION'   : 0x1000,
+       'SFC_CALC_SIGNAL_MAX'   : 0x1040,
+       'SFC_GET_DITHER_INFO'   : 0x10A3,
+       'SFC_GET_LOG_INFO'      : 0x1001,
+       'SFC_GET_FORMAT_SUBTYPE_COUNT'  : 0x1032,
+       'SFC_FILE_TRUNCATE'     : 0x1080,
+       'SFC_GET_INSTRUMENT'    : 0x10D0,
+       'SFC_UPDATE_HEADER_NOW' : 0x1060,
+       'SFC_SET_DITHER_ON_WRITE'       : 0x10A0,
+       'SFC_SET_NORM_DOUBLE'   : 0x1012,
+       'SFC_GET_CLIPPING'      : 0x10C1,
+       'SFC_SET_RAW_START_OFFSET'      : 0x1090,
+       'SFC_CALC_NORM_MAX_ALL_CHANNELS'        : 0x1043,
+       'SFC_SET_NORM_FLOAT'    : 0x1013,
+       'SFC_SET_ADD_DITHER_ON_WRITE'   : 0x1070,
+       'SFC_GET_NORM_FLOAT'    : 0x1011,
+       'SFC_GET_SIGNAL_MAX'    : 0x1044,
+       'SFC_GET_MAX_ALL_CHANNELS'      : 0x1045,
+       'SFC_GET_FORMAT_MAJOR'  : 0x1031,
+       'SFC_SET_INSTRUMENT'    : 0x10D1,
+       'SFC_CALC_MAX_ALL_CHANNELS'     : 0x1042,
+       'SFC_GET_DITHER_INFO_COUNT'     : 0x10A2,
+       'SFC_SET_BROADCAST_INFO'        : 0x10F1,
+       'SFC_SET_DITHER_ON_READ'        : 0x10A1,
+       'SFC_GET_FORMAT_MAJOR_COUNT'    : 0x1030,
+       'SFC_GET_FORMAT_INFO'   : 0x1028,
+       'SFC_GET_SIMPLE_FORMAT_COUNT'   : 0x1020,
+       'SFC_CALC_NORM_SIGNAL_MAX'      : 0x1041,
+       'SFC_GET_LOOP_INFO'     : 0x10E0,
+       'SFC_SET_ADD_PEAK_CHUNK'        : 0x1050,
+       'SFC_SET_ADD_DITHER_ON_READ'    : 0x1071,
+       'SFC_SET_SCALE_FLOAT_INT_READ'  : 0x1014,
+       'SFC_GET_FORMAT_SUBTYPE'        : 0x1033,
+       'SFC_TEST_IEEE_FLOAT_REPLACE'   : 0x6001,
+       'SFC_SET_UPDATE_HEADER_AUTO'    : 0x1061,
+       'SFC_GET_SIMPLE_FORMAT' : 0x1021,
+       'SFC_SET_CLIPPING'      : 0x10C0,
+       'SFC_GET_EMBED_FILE_INFO'       : 0x10B0,
+       'SFC_GET_BROADCAST_INFO'        : 0x10F0,
+       'SFC_GET_NORM_DOUBLE'   : 0x1010
+}
+
+SF_ERRORS = {
+       'SF_ERR_UNRECOGNISED_FORMAT'    : 1,
+       'SF_ERR_NO_ERROR'       : 0,
+       'SF_ERR_SYSTEM' : 2,
+       'SF_ERR_UNSUPPORTED_ENCODING'   : 4,
+       'SF_ERR_MALFORMED_FILE' : 3
+}
+
+# format equivalence: dic used to create internally
+# the right enum values from user friendly strings
+py_to_snd_encoding_dic    = {
+    'pcms8' : SF_FORMAT['SF_FORMAT_PCM_S8'],      
+    'pcm16' : SF_FORMAT['SF_FORMAT_PCM_16'],     
+    'pcm24' : SF_FORMAT['SF_FORMAT_PCM_24'],    
+    'pcm32' : SF_FORMAT['SF_FORMAT_PCM_32'],    
+
+    'pcmu8' : SF_FORMAT['SF_FORMAT_PCM_U8'],  
+
+    'float32' : SF_FORMAT['SF_FORMAT_FLOAT'],
+    'float64' : SF_FORMAT['SF_FORMAT_DOUBLE'],
+
+    'ulaw'      : SF_FORMAT['SF_FORMAT_ULAW'],
+    'alaw'      : SF_FORMAT['SF_FORMAT_ALAW'],
+    'ima_adpcm' : SF_FORMAT['SF_FORMAT_IMA_ADPCM'],
+    'ms_adpcm'  : SF_FORMAT['SF_FORMAT_MS_ADPCM'],
+
+    'gsm610'    : SF_FORMAT['SF_FORMAT_GSM610'],
+    'vox_adpcm' : SF_FORMAT['SF_FORMAT_VOX_ADPCM'],
+
+    'g721_32'   : SF_FORMAT['SF_FORMAT_G721_32'], 
+    'g723_24'   : SF_FORMAT['SF_FORMAT_G723_24'],
+    'g723_40'   : SF_FORMAT['SF_FORMAT_G723_40'],
+
+    'dww12' : SF_FORMAT['SF_FORMAT_DWVW_12'],
+    'dww16' : SF_FORMAT['SF_FORMAT_DWVW_16'],
+    'dww24' : SF_FORMAT['SF_FORMAT_DWVW_24'],
+    'dwwN'  : SF_FORMAT['SF_FORMAT_DWVW_N'],
+
+    'dpcm8' : SF_FORMAT['SF_FORMAT_DPCM_8'],
+    'dpcm16': SF_FORMAT['SF_FORMAT_DPCM_16']
+}
+
+py_to_snd_file_format_dic = {
+    'wav'   : SF_FORMAT['SF_FORMAT_WAV'],
+    'aiff'  : SF_FORMAT['SF_FORMAT_AIFF'],
+    'au'    : SF_FORMAT['SF_FORMAT_AU'],
+    'raw'   : SF_FORMAT['SF_FORMAT_RAW'],
+    'paf'   : SF_FORMAT['SF_FORMAT_PAF'],
+    'svx'   : SF_FORMAT['SF_FORMAT_SVX'],
+    'nist'  : SF_FORMAT['SF_FORMAT_NIST'],
+    'voc'   : SF_FORMAT['SF_FORMAT_VOC'],
+    'ircam' : SF_FORMAT['SF_FORMAT_IRCAM'],
+    'wav64' : SF_FORMAT['SF_FORMAT_W64'],
+    'mat4'  : SF_FORMAT['SF_FORMAT_MAT4'],
+    'mat5'  : SF_FORMAT['SF_FORMAT_MAT5'],
+    'pvf'   : SF_FORMAT['SF_FORMAT_PVF'],
+    'xi'    : SF_FORMAT['SF_FORMAT_XI'],
+    'htk'   : SF_FORMAT['SF_FORMAT_HTK'],
+    'sds'   : SF_FORMAT['SF_FORMAT_SDS'],
+    'avr'   : SF_FORMAT['SF_FORMAT_AVR'],
+    'wavex' : SF_FORMAT['SF_FORMAT_WAVEX'],
+    'sd2'   : SF_FORMAT['SF_FORMAT_SD2'],
+    'flac'  : SF_FORMAT['SF_FORMAT_FLAC'],
+    'caf'   : SF_FORMAT['SF_FORMAT_CAF']
+}
+
+py_to_snd_endianness_dic = {
+    'file'      : SF_ENDIAN['SF_ENDIAN_FILE'], 
+    'little'    : SF_ENDIAN['SF_ENDIAN_LITTLE'], 
+    'big'       : SF_ENDIAN['SF_ENDIAN_BIG'], 
+    'cpu'       : SF_ENDIAN['SF_ENDIAN_CPU']
+}
+
+# Those following dic are used internally to get user-friendly values from
+# sndfile enum
+SND_TO_PY_ENCODING = \
+        dict([(i, j) for j, i in py_to_snd_encoding_dic.items()])
+SND_TO_PY_FILE_FORMAT = \
+        dict([(i, j) for j, i in py_to_snd_file_format_dic.items()])
+SND_TO_PY_ENDIANNESS = \
+        dict([(i, j) for j, i in py_to_snd_endianness_dic.items()])
+
+#==========================================
+# Check that libsndfile is expected version
+#==========================================
+def get_libsndfile_version():
+    nverbuff = 256
+    verbuff = create_string_buffer(nverbuff)
+    n = _SND.sf_command(c_int(0), c_int(SF_COMMAND['SFC_GET_LIB_VERSION']), 
+            verbuff, nverbuff)
+    if n < 1:
+        raise Exception("Error while getting version of libsndfile")
+
+    # Transform the buffer into a string
+    ver = ""
+    for i in range(n):
+        ver += verbuff[i]
+
+    # Get major, minor and micro from version
+    version     = ver.split('-')[1]
+    prerelease  = 0
+    major, minor, micro = [i for i in version.split('.')]
+    try:
+        micro   = int(micro)
+    except ValueError,e:
+        print "micro is "  + str(micro) 
+        micro, prerelease   = micro.split('pre')
+
+    return int(major), int(minor), int(micro), prerelease
+
+MAJOR, MINOR, MICRO, PRERELEASE = get_libsndfile_version()
+if not(MAJOR == 1):
+    raise Exception("audiolab expects major version %d of libsndfile" % 1)
+if not(MICRO == 17):
+    if PRERELEASE == 0: 
+        prestr  = "No"
+    else:
+        prestr  = "%s" % PRERELEASE
+    print "WARNING libsndfile-%d.%d.%d (prerelease: %s) "\
+        "this has only been tested with libsndfile 1.0.17 for now, "\
+        "use at your own risk !" % (MAJOR, MINOR, MICRO, prestr)
+
+#================
+# Python wrappers
+#================
+
+#+++++++++++++++++
+# Public exception
+#+++++++++++++++++
+class PyaudioException(Exception):
+    pass
+
+class InvalidFormat(PyaudioException):
+    pass
+
+class PyaudioIOError(PyaudioException, IOError):
+    pass
+
+class WrappingError(PyaudioException):
+    pass
+
+class FlacUnsupported(RuntimeError, PyaudioException):
+    pass
+
+#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+# Private classes/function (Should not be used outside this file)
+#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+class _sf_info(Structure):
+    """Structure representing C structure SF_INFO"""
+    _fields_    = [('frames', c_int64),
+                ('samplerate', c_int),
+                ('channels', c_int),
+                ('format', c_int),
+                ('sections', c_int),
+                ('seekable', c_int)]
+    def __str__(self):
+        return "%d frames, sr = %d Hz, %d channels, format is %d" % \
+                (self.frames, self.samplerate, self.channels, self.format)
+
+class _sf_format_info(Structure):
+    """Structure representing C structure SF_FORMAT_INFO (useful for
+    sf_command )"""
+    _fields_    = [('format', c_int),
+                ('name', c_char_p),
+                ('extension', c_char_p)]
+    def __str__(self):
+        return "format hex is %#010x, name is %s, extension is %s" %  \
+                (self.format, self.name, self.extension)
+
+    def __repr__(self):
+        print self.__str__()
+
+class _sndfile(Structure):
+    pass
+
+sf_info_p = POINTER(_sf_info)
+sndfile_p = POINTER(_sndfile)
+
+# functions args
+# TODO: is there a way to ensure that arg1 is the right kind of pointer ?
+arg1    = c_char_p
+arg2    = c_int
+arg3    = sf_info_p
+_SND.sf_open.argtypes   = [arg1, arg2, arg3]
+_SND.sf_open.restype    = sndfile_p
+
+arg1    = sndfile_p
+_SND.sf_close.argtypes  = [arg1]
+_SND.sf_close.restype  = c_int
+
+arg1    = c_int
+arg2    = c_int
+arg3    = sf_info_p
+arg4    = c_int
+_SND.sf_open_fd.argtypes   = [arg1, arg2, arg3, arg4]
+_SND.sf_open_fd.restype    = sndfile_p
+
+arg1    = sndfile_p
+arg2    = ndpointer(dtype=N.float64)
+arg3    = c_int64
+
+# double function
+_SND.sf_readf_double.argtypes    = [arg1, arg2, arg3]
+_SND.sf_readf_double.restype     = c_int64
+
+_SND.sf_writef_double.argtypes    = [arg1, arg2, arg3]
+_SND.sf_writef_double.restype     = c_int64
+
+# float function
+arg1    = sndfile_p
+arg2    = ndpointer(dtype=N.float32)
+arg3    = c_int64
+_SND.sf_readf_float.argtypes    = [arg1, arg2, arg3]
+_SND.sf_readf_float.restype     = c_int64
+
+_SND.sf_writef_float.argtypes    = [arg1, arg2, arg3]
+_SND.sf_writef_float.restype     = c_int64
+
+# int function
+arg1    = sndfile_p
+arg2    = ndpointer(dtype=N.int32)
+arg3    = c_int64
+_SND.sf_readf_int.argtypes    = [arg1, arg2, arg3]
+_SND.sf_readf_int.restype     = c_int64
+
+_SND.sf_writef_int.argtypes    = [arg1, arg2, arg3]
+_SND.sf_writef_int.restype     = c_int64
+
+# short function
+arg1    = sndfile_p
+arg2    = ndpointer(dtype=N.int16)
+arg3    = c_int64
+_SND.sf_readf_short.argtypes    = [arg1, arg2, arg3]
+_SND.sf_readf_short.restype     = c_int64
+
+_SND.sf_writef_short.argtypes    = [arg1, arg2, arg3]
+_SND.sf_writef_short.restype     = c_int64
+
+# Error functions
+arg1    = sndfile_p
+_SND.sf_strerror.argtypes   = [arg1]
+_SND.sf_strerror.restype    = c_char_p
+
+# Function to sync data to file
+arg1    = sndfile_p
+_SND.sf_write_sync.argtypes = [arg1]
+
+# Function to seek
+arg1    = sndfile_p
+arg2    = c_int64
+arg3    = c_int
+_SND.sf_seek.argtypes = [arg1, arg2, arg3]
+_SND.sf_seek.restype  = c_int64
+
+# To pass when a C function needs a NULL arg
+_cNULL = POINTER(c_int)()
+
+class _format_from_internal:
+    """Class to handle audio format with sndfile. 
+    
+    DO NOT USE THIS CLASS OUTSIDE pysndfile.py MODULE: YOU MAY CRASH YOUR
+    INTERPRETER !
+    
+    Basically, we have 3 classes of parameters:
+        - the main format: (major format), like wav, aiff, etc...
+        - the subtype format: pcm, bits resolution
+        - endianness: little, big, as the cpu, default of the format
+
+    This class encapsulates those parameters, and can build a representation of
+    them from the format integer of sf_info. This should *NOT* be used, use
+    format instead, which inherits this class to build a valid format from user
+    friendly arguments.  """
+    def __init__(self, format_integer):
+        # Get the internal values which corresponds to the values libsndfile
+        # can understand
+        self._int_type = format_integer & SF_FORMAT['SF_FORMAT_TYPEMASK']
+        self._int_encoding = format_integer & SF_FORMAT['SF_FORMAT_SUBMASK']
+        self._int_endianness = format_integer & SF_FORMAT['SF_FORMAT_ENDMASK']
+
+        assert format_integer == self._int_type | self._int_encoding |\
+            self._int_endianness
+        self._format    = format_integer
+
+        # Now, we need to test if the combination of format, encoding and 
+        # endianness is valid. sf_format_check needs also samplerate and
+        # channel information, so just give a fake samplerate and channel
+        # number. Looking at sndfile.c, it looks like samplerate is never
+        # actually checked, and that when channels is checked, it is only
+        # checked against values different than 1 or 2, so giving a value of
+        # 1 to channel should be ok.
+        self._sfinfo            = _sf_info()
+        self._sfinfo.channels   = 1
+        self._sfinfo.samplerate = 8000
+        self._sfinfo.format     = self._format
+
+        ret = _SND.sf_format_check(pointer(self._sfinfo))
+        if ret is not SF_BOOL['SF_TRUE']:
+            raise InvalidFormat()
+
+        # Get the sndfile string description of the format type
+        blop = _sf_format_info()
+        blop.format = self._int_type
+        st = _SND.sf_command(_cNULL, SF_COMMAND['SFC_GET_FORMAT_INFO'], \
+                pointer(blop), sizeof(blop))
+        if st is not 0:
+            if SND_TO_PY_FILE_FORMAT[self._int_type] == 'flac':
+                raise FlacUnsupported("Flac is not supported by your version"\
+                        " of libsndfile")
+            else:
+                raise WrappingError("Could not get format string for format "\
+                        "%d, " % blop.format + "please report this problem "\
+                        "to the maintainer")
+                    
+        self.format_str = blop.name
+
+        # Get the sndfile string description of the format subtype
+        blop.format = self._int_encoding
+        st = _SND.sf_command(_cNULL, SF_COMMAND['SFC_GET_FORMAT_INFO'], \
+                pointer(blop), sizeof(blop))
+        if st is not 0:
+            raise WrappingError()
+                    
+        self.encoding_str   = blop.name
+
+    def get_format_raw(self):
+        """Do not use this function !"""
+        return self._format
+
+    def get_major_str(self):
+        """Do not use this function !"""
+        return self.format_str
+
+    def get_encoding_str(self):
+        """Do not use this function !"""
+        return self.encoding_str
+
+    def get_file_format(self):
+        """return user friendly file format string"""
+        return SND_TO_PY_FILE_FORMAT[self._int_type]
+
+    def get_encoding(self):
+        """return user friendly encoding string"""
+        return SND_TO_PY_ENCODING[self._int_encoding]
+
+    def get_endianness(self):
+        """return user friendly file format string"""
+        return SND_TO_PY_ENDIANNESS[self._int_endianness]
+
+    # Various function
+    def is_type(self, t):
+        return (self._format & SF_FORMAT['SF_FORMAT_TYPEMASK']) \
+                == py_to_snd_file_format_dic[t]
+
+    # Syntactic sugar
+    def __str__(self):
+        return  "Major Format: %s, Encoding Format: %s" % \
+                (self.format_str, self.encoding_str)
+
+    def __repr__(self):
+        return self.__str__()
+
+#+++++++++++
+# Public API
+#+++++++++++
+
+class formatinfo(_format_from_internal):
+    def __init__(self, type = 'wav', encoding = 'pcm16', endianness = 'file'):
+        """Build a valid format usable by the sndfile class when opening an
+        audio file for writing. 
+        
+        Blah blah
+
+        :Parameters:
+            type : string
+                represents the major file format (wav, etc...).
+            encoding : string
+                represents the encoding (pcm16, etc..).
+            endianness : string
+                represents the endianess.
+            
+        Notes
+        -----
+        
+        Valid type strings are listed by file_format_dic.keys() Valid encoding
+        strings are listed by encoding_dic.keys() Valid endianness strings are
+        listed by endianness_dic.keys() """
+        # Keep the arguments
+        self.type       = type
+        self.encoding   = encoding
+        self.endianness = endianness
+
+        # Get the internal values which corresponds to the values libsndfile
+        # can understand
+        self._int_type          = py_to_snd_file_format_dic[type]
+        self._int_encoding      = py_to_snd_encoding_dic[encoding]
+        self._int_endianness    = py_to_snd_endianness_dic[endianness]
+
+        # Build the internal integer from parameters, and pass it to the super
+        # class, which will do all the work
+        format  = self._int_type | self._int_encoding | self._int_endianness
+
+        _format_from_internal.__init__(self, format)
+
+class sndfile:
+    """Main class to open, read and write audio files"""
+    def __init__(self, filename, mode = 'read', format = None, channels = 0, \
+            samplerate = 0):
+        """Create an instance of sndfile.
+
+        :Parameters:
+            filename : string or int
+                name of the file to open (string), or file descriptor (integer)
+            mode : string
+                'read' for read, 'write' for write, or 'rwrite' for read and
+                write.
+            format : formatinfo
+                when opening a new file for writing, give the format to write
+                in.
+            channels : int
+                number of channels.
+            samplerate : int
+                sampling rate.
+
+        :Returns:
+            sndfile: a valid sndfile object 
+            
+        Notes
+        -----
+        
+        format, channels and samplerate need to be given only in the write
+        modes and for raw files.  """
+        # Check the mode is one of the expected values
+        if mode == 'read':
+            sfmode  = SFM['SFM_READ']
+        elif mode == 'write':
+            sfmode  = SFM['SFM_WRITE']
+            if format == None:
+                raise Exception("For write mode, you should provide"\
+                        "a format argument !")
+        elif mode == 'rwrite':
+            sfmode  = SFM['SFM_RDWR']
+            if format == None:
+                raise Exception("For write mode, you should provide"\
+                        "a format argument !")
+        else:
+            raise Exception("mode %s not recognized" % str(mode))
+
+        sfinfo = _sf_info()
+        sfinfo_p = pointer(sfinfo)
+
+        # Fill the sfinfo struct
+        sfinfo.frames       = c_int64(0)
+        if type(channels) is not int:
+            print "Warning, channels is converted to int, was %s" % \
+                    str(type(channels))
+            sfinfo.channels     = int(channels)
+        else:
+            sfinfo.channels     = channels
+
+        if type(samplerate) is not int:
+            print "Warning, sampling rate is converted to int, was %s" % \
+                    str(type(samplerate))
+            sfinfo.samplerate   = int(samplerate)
+        else:
+            sfinfo.samplerate   = samplerate
+
+        sfinfo.sections     = 0
+        sfinfo.seekable     = False
+        if mode == 'read' and format == None:
+            sfinfo.format   = 0
+        else:
+            if sfinfo.channels > 256 or sfinfo.channels < 1:
+                msg = "number of channels is %d, expected " \
+                        "between 1 and 256" % sfinfo.channels
+                raise RuntimeError(msg)
+            sfinfo.format   = format.get_format_raw()
+            if not _SND.sf_format_check(sfinfo_p):
+                msg = "unknown error in format specification ?" +\
+                        " Please report this to the author"
+                raise WrappingError()
+
+        sfinfo_p = pointer(sfinfo)
+        self._sfmode = sfmode
+        self.hdl = 0
+
+        if type(filename) == int:
+            res = _SND.sf_open_fd(filename, self._sfmode, sfinfo_p, 
+                                  SF_BOOL['SF_FALSE'])
+            self._byfd = True
+            self.fd = filename
+            self.filename = ""
+        else:
+            res = _SND.sf_open(filename, self._sfmode, sfinfo_p)
+            self._byfd = False
+            self.filename = filename
+
+        try:
+            # If res is NULL, this statement will raise a ValueError exception
+            a = res[0]
+        except ValueError:
+            if self._byfd:
+                msg = "error while opening file descriptor %d\n\t->" % self.fd
+            else:
+                msg = "error while opening file %s\n\t-> " % self.filename
+            msg += _SND.sf_strerror(res)
+            if self._byfd:
+                msg += """
+(Check that the mode argument passed to sndfile is the same than the one used
+when getting the file descriptor, eg do not pass 'read' to sndfile if you
+passed 'write' to open to get the file descriptor. If you are on win32, you are
+out of luck, because its implementation of POSIX open is broken)"""
+            raise IOError("error while opening %s\n\t->%s" % (filename, msg))
+
+        if mode == 'read':
+            tmp = _format_from_internal(sfinfo.format)
+            self._format = formatinfo(tmp.get_file_format(), \
+                    tmp.get_encoding(), tmp.get_endianness())
+        else:
+            self._format     = format
+
+        self._sfinfo    = sfinfo
+        self.hdl        = res
+
+        if self.get_file_format() == 'flac':
+            def SeekNotEnabled(self, *args):
+                raise FlacUnsupported("seek not supported on Flac by default,"\
+                        " because\n some version of FLAC libraries are buggy."\
+                        " Read FLAC_SUPPORT.txt")
+            self.seek   = SeekNotEnabled 
+        else:
+            self.seek = self._seek
+
+    def __del__(self, close_func = _SND.sf_close):
+        # Stupid python needs the close_func, otherwise
+        # it may clean ctypes before calling here
+        if hasattr(self,'hdl'):
+            if not(self.hdl == 0):
+                close_func(self.hdl)
+                self.hdl    = 0
+
+    def close(self):
+        """close the file."""
+        self.__del__()
+
+    def sync(self):
+        """call the operating system's function to force the writing of all
+        file cache buffers to disk the file. 
+        
+        No effect if file is open as read"""
+        _SND.sf_write_sync(self.hdl)
+
+    def _seek(self, offset, whence = 0, mode = 'rw'):
+        """similar to python seek function, taking only in account audio data.
+        
+        :Parameters:
+            offset : int
+                the number of frames (eg two samples for stereo files) to move
+                relatively to position set by whence.
+            whence : int
+                only 0 (beginning), 1 (current) and 2 (end of the file) are
+                valid.
+            mode : string
+                If set to 'rw', both read and write pointers are updated. If
+                'r' is given, only read pointer is updated, if 'w', only the
+                write one is (this may of course make sense only if you open
+                the file in a certain mode).
+
+        Notes
+        -----
+        
+        - one only takes into accound audio data. 
+        - if an invalid seek is given (beyond or before the file), a
+          PyaudioIOError is launched."""
+        c_offset    = _num2int64(offset)
+        if mode == 'rw':
+            # Update both read and write pointers
+            st  = _SND.sf_seek(self.hdl, c_offset, whence)
+        elif mode == 'r':
+            whence = whence | SFM['SFM_READ']
+            st  = _SND.sf_seek(self.hdl, c_offset, whence)
+        elif mode == 'w':
+            whence = whence | SFM['SFM_WRITE']
+            st  = _SND.sf_seek(self.hdl, c_offset, whence)
+        else:
+            raise ValueError("mode should be one of 'r', 'w' or 'rw' only")
+
+        if st == -1:
+            msg = "Error while seeking, libsndfile error is %s" \
+                    % (_SND.sf_strerror(self.hdl))
+            raise PyaudioIOError(msg)
+        return st
+
+    # Functions to get informations about the file
+    def get_nframes(self):
+        """ Return the number of frames of the file"""
+        if self._sfmode == SFM['SFM_READ']:
+            # XXX: is this reliable for any file (think pipe and co ?)
+            return self._sfinfo.frames
+        else:
+            # In write/rwrite mode, the only reliable way to get the number of
+            # frames is to use seek.
+            raise NotImplementedError("Sorry, getting the current number of"
+                    "frames in write modes is not supported yet")
+    
+    def get_samplerate(self):
+        """ Return the samplerate in Hz of the file"""
+        return self._sfinfo.samplerate
+    
+    def get_channels(self):
+        """ Return the number of channels of the file"""
+        return self._sfinfo.channels
+    
+    def get_file_format(self):
+        """return user friendly file format string"""
+        return SND_TO_PY_FILE_FORMAT[self._format._int_type]
+
+    def get_encoding(self):
+        """return user friendly encoding string"""
+        return SND_TO_PY_ENCODING[self._format._int_encoding]
+
+    def get_endianness(self):
+        """return user friendly file format string"""
+        return SND_TO_PY_ENDIANNESS[self._format._int_endianness]
+
+    #------------------
+    # Functions to read
+    #------------------
+    def read_frames(self, nframes, dtype = N.float64):
+        """Read nframes frames of the file.
+        
+        :Parameters:
+            nframes : int
+                number of frames to read.
+            dtype : numpy dtype
+                dtype of the returned array containing read data (see note).
+        
+        Notes
+        -----
+        
+        - read_frames updates the read pointer.
+        - One column is one channel.
+        - if float are requested when the file contains integer data, you will
+          get normalized data (that is the max possible integer will be 1.0,
+          and the minimal possible value -1.0).
+        - if integers are requested when the file contains floating point data,
+          it may give wrong results because there is an ambiguity: if the
+          floating data are normalized, you can get a file with only 0 !
+          Getting integer data from files encoded in normalized floating point
+          is not supported (yet: sndfile supports it).""" 
+        c_nframes   = _num2int64(nframes)
+        if c_nframes < 0:
+            raise ValueError("number of frames has to be >= 0")
+
+        # XXX: inout argument
+        if self._sfinfo.channels > 1:
+            y           = N.zeros((nframes, self._sfinfo.channels), dtype)
+        else:
+            y           = N.zeros(nframes, dtype)
+
+        if dtype == N.float64:
+            res         = _SND.sf_readf_double(self.hdl, y, c_nframes)
+        elif dtype == N.float32:
+            res         = _SND.sf_readf_float(self.hdl, y, c_nframes)
+        elif dtype == N.int32:
+            res         = _SND.sf_readf_int(self.hdl, y, c_nframes)
+        elif dtype == N.int16:
+            res         = _SND.sf_readf_short(self.hdl, y, c_nframes)
+        else:
+            RuntimeError("Sorry, only float, double, int and short read " + \
+                    "supported for now")
+
+        if not(res == nframes):
+            msg = "Read %d frames, expected to read %d" % (res, nframes)
+            msg += ", libsndfile last msg is \n\t%s" \
+                    % _SND.sf_strerror(self.hdl)
+            raise IOError(msg)
+
+        return y
+
+    #-------------------
+    # Functions to write
+    #-------------------
+    # TODO: Think about overflow vs type of input, etc...
+    def write_frames(self, input, nframes = -1):
+        """write data to file.
+        
+        :Parameters:
+            input : ndarray
+                array containing data to write.  
+            nframes : int
+                number of frames to write.
+
+        Notes
+        -----
+
+        - one channel is one column
+        - updates the write pointer.
+        - if float are given when the file contains integer data, you should
+          put normalized data (that is the range [-1..1] will be written as the
+          maximum range allowed by the integer bitwidth)."""
+        # First, get the number of channels and frames from input
+        if input.ndim   == 1:
+            nc      = 1
+        else:
+            if input.ndim > 2:
+                raise Exception("Expect array of rank <= 2, got %d" \
+                        % input.ndim)
+            nc = input.shape[1]
+
+        if nframes == -1:
+            nframes = N.size(input)
+        # Number of channels should be the one expected
+        if not(nc == self._sfinfo.channels):
+            raise Exception("Expected %d channels, got %d" % \
+                    (self._sfinfo.channels, nc))
+
+        # Writing to the file
+        c_nframes   = _num2int64(nframes)
+        if c_nframes < 0:
+            raise ValueError("number of frames has to be >= 0")
+
+        input = N.require(input, requirements = 'C')
+
+        if input.dtype == N.float32:
+            if self._check_overflow(input):
+                warnings.warn("Warning, overflow detected when writing.")
+            res         = _SND.sf_writef_float(self.hdl, input, c_nframes)
+        elif input.dtype == N.float64:
+            self._check_overflow(input)
+            if self._check_overflow(input):
+                warnings.warn("Warning, overflow detected when writing.")
+            res         = _SND.sf_writef_double(self.hdl, input, c_nframes)
+        elif input.dtype == N.int32:
+            res         = _SND.sf_writef_int(self.hdl, input, c_nframes)
+        elif input.dtype == N.int16:
+            res         = _SND.sf_writef_short(self.hdl, input, c_nframes)
+        else:
+            raise Exception("type of input not understood: input should"
+                " be float64 or float32""")
+
+        if not(res == nframes):
+            raise IOError("write %d frames, expected to write %d" \
+                    % res, nframes)
+
+    def _check_overflow(self, data):
+        if N.max(data ** 2) >= 1.:
+            return True
+        return False
+
+    # Syntactic sugar
+    def __repr__(self):
+        return self.__str__()
+
+    def __str__(self):
+        repstr = "----------------------------------------\n"
+        if self._byfd:
+            repstr  += "File        : %d (opened by file descriptor)\n" % self.fd
+        else:
+            repstr  += "File        : %s\n" % self.filename
+        repstr  += "Channels    : %d\n" % self._sfinfo.channels
+        repstr  += "Sample rate : %d\n" % self._sfinfo.samplerate
+        repstr  += "Frames      : %d\n" % self._sfinfo.frames
+        repstr  += "Raw Format  : %#010x -> %s\n" % \
+                (self._format.get_format_raw(), self._format.get_major_str())
+        repstr  += "File format : %s\n" % self.get_file_format()
+        repstr  += "Encoding    : %s\n" % self.get_encoding()
+        repstr  += "Endianness  : %s\n" % self.get_endianness()
+        repstr  += "Sections    : %d\n" % self._sfinfo.sections
+        if self._sfinfo.seekable:
+            seek    = 'True'
+        else:
+            seek    = 'False'
+        repstr  += "Seekable    : %s\n" % seek
+        repstr  += "Duration    : %s\n" % self._generate_duration_str()
+        return repstr
+
+    def _generate_duration_str(self):
+        if self._sfinfo.samplerate < 1:
+            return None
+        tsec    = self._sfinfo.frames / self._sfinfo.samplerate
+        hrs     = tsec / 60 / 60
+        tsec    = tsec % (60 ** 2)
+        mins    = tsec / 60
+        tsec    = tsec % 60
+        secs    = tsec
+        ms      = 1000 * self._sfinfo.frames / self._sfinfo.samplerate % 1000
+
+        return "%02d:%02d:%02d.%3d" % (hrs, mins, secs, ms)
+
+def supported_format():
+    # XXX: broken
+    return py_to_snd_file_format_dic.keys()
+
+def supported_endianness():
+    # XXX: broken
+    return py_to_snd_endianness_dic.keys()
+
+def supported_encoding():
+    # XXX: broken
+    return py_to_snd_encoding_dic.keys()
+
+def _num2int64(value):
+    """ Convert a python objet to a c_int64, safely."""
+    if not (type(value) == int or type(value) == long):
+        value = long(value)
+        print "Warning, converting %s to long" % str(value)
+    c_value = c_int64(value)
+    if not c_value.value == value:
+        raise RuntimeError("Error while converting %s to a c_int64"\
+            ", maybe %s is too big ?" % str(value))
+    return c_value
diff --git a/telemeta/util/audiolab/scikits/audiolab/pysndfile.py.in b/telemeta/util/audiolab/scikits/audiolab/pysndfile.py.in
new file mode 100644 (file)
index 0000000..574e5bb
--- /dev/null
@@ -0,0 +1,886 @@
+#! /usr/bin/env python
+# Last Change: Wed Oct 03 05:00 PM 2007 J
+
+# Copyright (C) 2006-2007 Cournapeau David <cournape@gmail.com>
+#
+# 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.1 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+# vim:syntax=python
+
+# TODO:
+#   - import format classes so that we get meaningful information from an
+#   existing format
+#   - better API for reader/writer, including integer formats and partial
+#   reading
+#   - ability to get log of sndfile ?
+#   - check how to play sound under windows, OS X and other UNIX
+
+"""This module implements the wrappers around libsndfile."""
+
+__docformat__ = 'restructuredtext'
+
+#__all__ = ['sndfile', 'formatinfo']
+
+import copy
+import warnings
+
+#================
+# Load libsndfile
+#================
+import ctypes
+from ctypes import cdll, Structure, c_int, pointer, POINTER, \
+        create_string_buffer, c_char_p, sizeof, string_at
+try:
+    from ctypes import c_int64
+except ImportError, e:
+    print "Cannot import c_int64 from ctypes: if you are on ubuntu/debian," +\
+        " this is likely because ctypes was compiled with libffi. see" +\
+        " https://launchpad.net/ubuntu/+source/python2.5/+bug/71914"
+    raise e
+
+from numpy.ctypeslib import ndpointer
+CTYPES_MAJOR    = int(ctypes.__version__.split('.')[0])
+CTYPES_MINOR    = int(ctypes.__version__.split('.')[1])
+CTYPES_MICRO    = int(ctypes.__version__.split('.')[2])
+if CTYPES_MAJOR < 1 or (CTYPES_MINOR == 0 and CTYPES_MICRO < 1):
+    raise ImportError("version of ctypes is %s, expected at least %s" \
+            % (ctypes.__version__, '1.0.1'))
+import numpy as N
+
+_SND = cdll.LoadLibrary('%SHARED_LOCATION%')
+
+#=========================
+# Definition of constants
+#=========================
+# READ/WRITE Mode
+%SFM%
+
+# SF BOOL
+%SF_BOOL%
+
+# Format
+%SF_FORMAT%
+
+# ENDIANESS
+%SF_ENDIAN%
+
+# Commands
+%SF_COMMAND%
+
+%SF_ERR%
+
+# format equivalence: dic used to create internally
+# the right enum values from user friendly strings
+py_to_snd_encoding_dic    = {
+    'pcms8' : SF_FORMAT['SF_FORMAT_PCM_S8'],      
+    'pcm16' : SF_FORMAT['SF_FORMAT_PCM_16'],     
+    'pcm24' : SF_FORMAT['SF_FORMAT_PCM_24'],    
+    'pcm32' : SF_FORMAT['SF_FORMAT_PCM_32'],    
+
+    'pcmu8' : SF_FORMAT['SF_FORMAT_PCM_U8'],  
+
+    'float32' : SF_FORMAT['SF_FORMAT_FLOAT'],
+    'float64' : SF_FORMAT['SF_FORMAT_DOUBLE'],
+
+    'ulaw'      : SF_FORMAT['SF_FORMAT_ULAW'],
+    'alaw'      : SF_FORMAT['SF_FORMAT_ALAW'],
+    'ima_adpcm' : SF_FORMAT['SF_FORMAT_IMA_ADPCM'],
+    'ms_adpcm'  : SF_FORMAT['SF_FORMAT_MS_ADPCM'],
+
+    'gsm610'    : SF_FORMAT['SF_FORMAT_GSM610'],
+    'vox_adpcm' : SF_FORMAT['SF_FORMAT_VOX_ADPCM'],
+
+    'g721_32'   : SF_FORMAT['SF_FORMAT_G721_32'], 
+    'g723_24'   : SF_FORMAT['SF_FORMAT_G723_24'],
+    'g723_40'   : SF_FORMAT['SF_FORMAT_G723_40'],
+
+    'dww12' : SF_FORMAT['SF_FORMAT_DWVW_12'],
+    'dww16' : SF_FORMAT['SF_FORMAT_DWVW_16'],
+    'dww24' : SF_FORMAT['SF_FORMAT_DWVW_24'],
+    'dwwN'  : SF_FORMAT['SF_FORMAT_DWVW_N'],
+
+    'dpcm8' : SF_FORMAT['SF_FORMAT_DPCM_8'],
+    'dpcm16': SF_FORMAT['SF_FORMAT_DPCM_16']
+}
+
+py_to_snd_file_format_dic = {
+    'wav'   : SF_FORMAT['SF_FORMAT_WAV'],
+    'aiff'  : SF_FORMAT['SF_FORMAT_AIFF'],
+    'au'    : SF_FORMAT['SF_FORMAT_AU'],
+    'raw'   : SF_FORMAT['SF_FORMAT_RAW'],
+    'paf'   : SF_FORMAT['SF_FORMAT_PAF'],
+    'svx'   : SF_FORMAT['SF_FORMAT_SVX'],
+    'nist'  : SF_FORMAT['SF_FORMAT_NIST'],
+    'voc'   : SF_FORMAT['SF_FORMAT_VOC'],
+    'ircam' : SF_FORMAT['SF_FORMAT_IRCAM'],
+    'wav64' : SF_FORMAT['SF_FORMAT_W64'],
+    'mat4'  : SF_FORMAT['SF_FORMAT_MAT4'],
+    'mat5'  : SF_FORMAT['SF_FORMAT_MAT5'],
+    'pvf'   : SF_FORMAT['SF_FORMAT_PVF'],
+    'xi'    : SF_FORMAT['SF_FORMAT_XI'],
+    'htk'   : SF_FORMAT['SF_FORMAT_HTK'],
+    'sds'   : SF_FORMAT['SF_FORMAT_SDS'],
+    'avr'   : SF_FORMAT['SF_FORMAT_AVR'],
+    'wavex' : SF_FORMAT['SF_FORMAT_WAVEX'],
+    'sd2'   : SF_FORMAT['SF_FORMAT_SD2'],
+    'flac'  : SF_FORMAT['SF_FORMAT_FLAC'],
+    'caf'   : SF_FORMAT['SF_FORMAT_CAF']
+}
+
+py_to_snd_endianness_dic = {
+    'file'      : SF_ENDIAN['SF_ENDIAN_FILE'], 
+    'little'    : SF_ENDIAN['SF_ENDIAN_LITTLE'], 
+    'big'       : SF_ENDIAN['SF_ENDIAN_BIG'], 
+    'cpu'       : SF_ENDIAN['SF_ENDIAN_CPU']
+}
+
+# Those following dic are used internally to get user-friendly values from
+# sndfile enum
+SND_TO_PY_ENCODING = \
+        dict([(i, j) for j, i in py_to_snd_encoding_dic.items()])
+SND_TO_PY_FILE_FORMAT = \
+        dict([(i, j) for j, i in py_to_snd_file_format_dic.items()])
+SND_TO_PY_ENDIANNESS = \
+        dict([(i, j) for j, i in py_to_snd_endianness_dic.items()])
+
+#==========================================
+# Check that libsndfile is expected version
+#==========================================
+def get_libsndfile_version():
+    nverbuff = 256
+    verbuff = create_string_buffer(nverbuff)
+    n = _SND.sf_command(c_int(0), c_int(SF_COMMAND['SFC_GET_LIB_VERSION']), 
+            verbuff, nverbuff)
+    if n < 1:
+        raise Exception("Error while getting version of libsndfile")
+
+    # Transform the buffer into a string
+    ver = ""
+    for i in range(n):
+        ver += verbuff[i]
+
+    # Get major, minor and micro from version
+    version     = ver.split('-')[1]
+    prerelease  = 0
+    major, minor, micro = [i for i in version.split('.')]
+    try:
+        micro   = int(micro)
+    except ValueError,e:
+        print "micro is "  + str(micro) 
+        micro, prerelease   = micro.split('pre')
+
+    return int(major), int(minor), int(micro), prerelease
+
+MAJOR, MINOR, MICRO, PRERELEASE = get_libsndfile_version()
+if not(MAJOR == 1):
+    raise Exception("audiolab expects major version %d of libsndfile" % 1)
+if not(MICRO == 17):
+    if PRERELEASE == 0: 
+        prestr  = "No"
+    else:
+        prestr  = "%s" % PRERELEASE
+    print "WARNING libsndfile-%d.%d.%d (prerelease: %s) "\
+        "this has only been tested with libsndfile 1.0.17 for now, "\
+        "use at your own risk !" % (MAJOR, MINOR, MICRO, prestr)
+
+#================
+# Python wrappers
+#================
+
+#+++++++++++++++++
+# Public exception
+#+++++++++++++++++
+class PyaudioException(Exception):
+    pass
+
+class InvalidFormat(PyaudioException):
+    pass
+
+class PyaudioIOError(PyaudioException, IOError):
+    pass
+
+class WrappingError(PyaudioException):
+    pass
+
+class FlacUnsupported(RuntimeError, PyaudioException):
+    pass
+
+#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+# Private classes/function (Should not be used outside this file)
+#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+class _sf_info(Structure):
+    """Structure representing C structure SF_INFO"""
+    _fields_    = [('frames', c_int64),
+                ('samplerate', c_int),
+                ('channels', c_int),
+                ('format', c_int),
+                ('sections', c_int),
+                ('seekable', c_int)]
+    def __str__(self):
+        return "%d frames, sr = %d Hz, %d channels, format is %d" % \
+                (self.frames, self.samplerate, self.channels, self.format)
+
+class _sf_format_info(Structure):
+    """Structure representing C structure SF_FORMAT_INFO (useful for
+    sf_command )"""
+    _fields_    = [('format', c_int),
+                ('name', c_char_p),
+                ('extension', c_char_p)]
+    def __str__(self):
+        return "format hex is %#010x, name is %s, extension is %s" %  \
+                (self.format, self.name, self.extension)
+
+    def __repr__(self):
+        print self.__str__()
+
+class _sndfile(Structure):
+    pass
+
+sf_info_p = POINTER(_sf_info)
+sndfile_p = POINTER(_sndfile)
+
+# functions args
+# TODO: is there a way to ensure that arg1 is the right kind of pointer ?
+arg1    = c_char_p
+arg2    = c_int
+arg3    = sf_info_p
+_SND.sf_open.argtypes   = [arg1, arg2, arg3]
+_SND.sf_open.restype    = sndfile_p
+
+arg1    = sndfile_p
+_SND.sf_close.argtypes  = [arg1]
+_SND.sf_close.restype  = c_int
+
+arg1    = c_int
+arg2    = c_int
+arg3    = sf_info_p
+arg4    = c_int
+_SND.sf_open_fd.argtypes   = [arg1, arg2, arg3, arg4]
+_SND.sf_open_fd.restype    = sndfile_p
+
+arg1    = sndfile_p
+arg2    = ndpointer(dtype=N.float64)
+arg3    = c_int64
+
+# double function
+_SND.sf_readf_double.argtypes    = [arg1, arg2, arg3]
+_SND.sf_readf_double.restype     = c_int64
+
+_SND.sf_writef_double.argtypes    = [arg1, arg2, arg3]
+_SND.sf_writef_double.restype     = c_int64
+
+# float function
+arg1    = sndfile_p
+arg2    = ndpointer(dtype=N.float32)
+arg3    = c_int64
+_SND.sf_readf_float.argtypes    = [arg1, arg2, arg3]
+_SND.sf_readf_float.restype     = c_int64
+
+_SND.sf_writef_float.argtypes    = [arg1, arg2, arg3]
+_SND.sf_writef_float.restype     = c_int64
+
+# int function
+arg1    = sndfile_p
+arg2    = ndpointer(dtype=N.int32)
+arg3    = c_int64
+_SND.sf_readf_int.argtypes    = [arg1, arg2, arg3]
+_SND.sf_readf_int.restype     = c_int64
+
+_SND.sf_writef_int.argtypes    = [arg1, arg2, arg3]
+_SND.sf_writef_int.restype     = c_int64
+
+# short function
+arg1    = sndfile_p
+arg2    = ndpointer(dtype=N.int16)
+arg3    = c_int64
+_SND.sf_readf_short.argtypes    = [arg1, arg2, arg3]
+_SND.sf_readf_short.restype     = c_int64
+
+_SND.sf_writef_short.argtypes    = [arg1, arg2, arg3]
+_SND.sf_writef_short.restype     = c_int64
+
+# Error functions
+arg1    = sndfile_p
+_SND.sf_strerror.argtypes   = [arg1]
+_SND.sf_strerror.restype    = c_char_p
+
+# Function to sync data to file
+arg1    = sndfile_p
+_SND.sf_write_sync.argtypes = [arg1]
+
+# Function to seek
+arg1    = sndfile_p
+arg2    = c_int64
+arg3    = c_int
+_SND.sf_seek.argtypes = [arg1, arg2, arg3]
+_SND.sf_seek.restype  = c_int64
+
+# To pass when a C function needs a NULL arg
+_cNULL = POINTER(c_int)()
+
+class _format_from_internal:
+    """Class to handle audio format with sndfile. 
+    
+    DO NOT USE THIS CLASS OUTSIDE pysndfile.py MODULE: YOU MAY CRASH YOUR
+    INTERPRETER !
+    
+    Basically, we have 3 classes of parameters:
+        - the main format: (major format), like wav, aiff, etc...
+        - the subtype format: pcm, bits resolution
+        - endianness: little, big, as the cpu, default of the format
+
+    This class encapsulates those parameters, and can build a representation of
+    them from the format integer of sf_info. This should *NOT* be used, use
+    format instead, which inherits this class to build a valid format from user
+    friendly arguments.  """
+    def __init__(self, format_integer):
+        # Get the internal values which corresponds to the values libsndfile
+        # can understand
+        self._int_type = format_integer & SF_FORMAT['SF_FORMAT_TYPEMASK']
+        self._int_encoding = format_integer & SF_FORMAT['SF_FORMAT_SUBMASK']
+        self._int_endianness = format_integer & SF_FORMAT['SF_FORMAT_ENDMASK']
+
+        assert format_integer == self._int_type | self._int_encoding |\
+            self._int_endianness
+        self._format    = format_integer
+
+        # Now, we need to test if the combination of format, encoding and 
+        # endianness is valid. sf_format_check needs also samplerate and
+        # channel information, so just give a fake samplerate and channel
+        # number. Looking at sndfile.c, it looks like samplerate is never
+        # actually checked, and that when channels is checked, it is only
+        # checked against values different than 1 or 2, so giving a value of
+        # 1 to channel should be ok.
+        self._sfinfo            = _sf_info()
+        self._sfinfo.channels   = 1
+        self._sfinfo.samplerate = 8000
+        self._sfinfo.format     = self._format
+
+        ret = _SND.sf_format_check(pointer(self._sfinfo))
+        if ret is not SF_BOOL['SF_TRUE']:
+            raise InvalidFormat()
+
+        # Get the sndfile string description of the format type
+        blop = _sf_format_info()
+        blop.format = self._int_type
+        st = _SND.sf_command(_cNULL, SF_COMMAND['SFC_GET_FORMAT_INFO'], \
+                pointer(blop), sizeof(blop))
+        if st is not 0:
+            if SND_TO_PY_FILE_FORMAT[self._int_type] == 'flac':
+                raise FlacUnsupported("Flac is not supported by your version"\
+                        " of libsndfile")
+            else:
+                raise WrappingError("Could not get format string for format "\
+                        "%d, " % blop.format + "please report this problem "\
+                        "to the maintainer")
+                    
+        self.format_str = blop.name
+
+        # Get the sndfile string description of the format subtype
+        blop.format = self._int_encoding
+        st = _SND.sf_command(_cNULL, SF_COMMAND['SFC_GET_FORMAT_INFO'], \
+                pointer(blop), sizeof(blop))
+        if st is not 0:
+            raise WrappingError()
+                    
+        self.encoding_str   = blop.name
+
+    def get_format_raw(self):
+        """Do not use this function !"""
+        return self._format
+
+    def get_major_str(self):
+        """Do not use this function !"""
+        return self.format_str
+
+    def get_encoding_str(self):
+        """Do not use this function !"""
+        return self.encoding_str
+
+    def get_file_format(self):
+        """return user friendly file format string"""
+        return SND_TO_PY_FILE_FORMAT[self._int_type]
+
+    def get_encoding(self):
+        """return user friendly encoding string"""
+        return SND_TO_PY_ENCODING[self._int_encoding]
+
+    def get_endianness(self):
+        """return user friendly file format string"""
+        return SND_TO_PY_ENDIANNESS[self._int_endianness]
+
+    # Various function
+    def is_type(self, t):
+        return (self._format & SF_FORMAT['SF_FORMAT_TYPEMASK']) \
+                == py_to_snd_file_format_dic[t]
+
+    # Syntactic sugar
+    def __str__(self):
+        return  "Major Format: %s, Encoding Format: %s" % \
+                (self.format_str, self.encoding_str)
+
+    def __repr__(self):
+        return self.__str__()
+
+#+++++++++++
+# Public API
+#+++++++++++
+
+class formatinfo(_format_from_internal):
+    def __init__(self, type = 'wav', encoding = 'pcm16', endianness = 'file'):
+        """Build a valid format usable by the sndfile class when opening an
+        audio file for writing. 
+        
+        Blah blah
+
+        :Parameters:
+            type : string
+                represents the major file format (wav, etc...).
+            encoding : string
+                represents the encoding (pcm16, etc..).
+            endianness : string
+                represents the endianess.
+            
+        Notes
+        -----
+        
+        Valid type strings are listed by file_format_dic.keys() Valid encoding
+        strings are listed by encoding_dic.keys() Valid endianness strings are
+        listed by endianness_dic.keys() """
+        # Keep the arguments
+        self.type       = type
+        self.encoding   = encoding
+        self.endianness = endianness
+
+        # Get the internal values which corresponds to the values libsndfile
+        # can understand
+        self._int_type          = py_to_snd_file_format_dic[type]
+        self._int_encoding      = py_to_snd_encoding_dic[encoding]
+        self._int_endianness    = py_to_snd_endianness_dic[endianness]
+
+        # Build the internal integer from parameters, and pass it to the super
+        # class, which will do all the work
+        format  = self._int_type | self._int_encoding | self._int_endianness
+
+        _format_from_internal.__init__(self, format)
+
+class sndfile:
+    """Main class to open, read and write audio files"""
+    def __init__(self, filename, mode = 'read', format = None, channels = 0, \
+            samplerate = 0):
+        """Create an instance of sndfile.
+
+        :Parameters:
+            filename : string or int
+                name of the file to open (string), or file descriptor (integer)
+            mode : string
+                'read' for read, 'write' for write, or 'rwrite' for read and
+                write.
+            format : formatinfo
+                when opening a new file for writing, give the format to write
+                in.
+            channels : int
+                number of channels.
+            samplerate : int
+                sampling rate.
+
+        :Returns:
+            sndfile: a valid sndfile object 
+            
+        Notes
+        -----
+        
+        format, channels and samplerate need to be given only in the write
+        modes and for raw files.  """
+        # Check the mode is one of the expected values
+        if mode == 'read':
+            sfmode  = SFM['SFM_READ']
+        elif mode == 'write':
+            sfmode  = SFM['SFM_WRITE']
+            if format == None:
+                raise Exception("For write mode, you should provide"\
+                        "a format argument !")
+        elif mode == 'rwrite':
+            sfmode  = SFM['SFM_RDWR']
+            if format == None:
+                raise Exception("For write mode, you should provide"\
+                        "a format argument !")
+        else:
+            raise Exception("mode %s not recognized" % str(mode))
+
+        sfinfo = _sf_info()
+        sfinfo_p = pointer(sfinfo)
+
+        # Fill the sfinfo struct
+        sfinfo.frames       = c_int64(0)
+        if type(channels) is not int:
+            print "Warning, channels is converted to int, was %s" % \
+                    str(type(channels))
+            sfinfo.channels     = int(channels)
+        else:
+            sfinfo.channels     = channels
+
+        if type(samplerate) is not int:
+            print "Warning, sampling rate is converted to int, was %s" % \
+                    str(type(samplerate))
+            sfinfo.samplerate   = int(samplerate)
+        else:
+            sfinfo.samplerate   = samplerate
+
+        sfinfo.sections     = 0
+        sfinfo.seekable     = False
+        if mode == 'read' and format == None:
+            sfinfo.format   = 0
+        else:
+            if sfinfo.channels > 256 or sfinfo.channels < 1:
+                msg = "number of channels is %d, expected " \
+                        "between 1 and 256" % sfinfo.channels
+                raise RuntimeError(msg)
+            sfinfo.format   = format.get_format_raw()
+            if not _SND.sf_format_check(sfinfo_p):
+                msg = "unknown error in format specification ?" +\
+                        " Please report this to the author"
+                raise WrappingError()
+
+        sfinfo_p = pointer(sfinfo)
+        self._sfmode = sfmode
+        self.hdl = 0
+
+        if type(filename) == int:
+            res = _SND.sf_open_fd(filename, self._sfmode, sfinfo_p, 
+                                  SF_BOOL['SF_FALSE'])
+            self._byfd = True
+            self.fd = filename
+            self.filename = ""
+        else:
+            res = _SND.sf_open(filename, self._sfmode, sfinfo_p)
+            self._byfd = False
+            self.filename = filename
+
+        try:
+            # If res is NULL, this statement will raise a ValueError exception
+            a = res[0]
+        except ValueError:
+            if self._byfd:
+                msg = "error while opening file descriptor %d\n\t->" % self.fd
+            else:
+                msg = "error while opening file %s\n\t-> " % self.filename
+            msg += _SND.sf_strerror(res)
+            if self._byfd:
+                msg += """
+(Check that the mode argument passed to sndfile is the same than the one used
+when getting the file descriptor, eg do not pass 'read' to sndfile if you
+passed 'write' to open to get the file descriptor. If you are on win32, you are
+out of luck, because its implementation of POSIX open is broken)"""
+            raise IOError("error while opening %s\n\t->%s" % (filename, msg))
+
+        if mode == 'read':
+            tmp = _format_from_internal(sfinfo.format)
+            self._format = formatinfo(tmp.get_file_format(), \
+                    tmp.get_encoding(), tmp.get_endianness())
+        else:
+            self._format     = format
+
+        self._sfinfo    = sfinfo
+        self.hdl        = res
+
+        if self.get_file_format() == 'flac':
+            def SeekNotEnabled(self, *args):
+                raise FlacUnsupported("seek not supported on Flac by default,"\
+                        " because\n some version of FLAC libraries are buggy."\
+                        " Read FLAC_SUPPORT.txt")
+            self.seek   = SeekNotEnabled 
+        else:
+            self.seek = self._seek
+
+    def __del__(self, close_func = _SND.sf_close):
+        # Stupid python needs the close_func, otherwise
+        # it may clean ctypes before calling here
+        if hasattr(self,'hdl'):
+            if not(self.hdl == 0):
+                close_func(self.hdl)
+                self.hdl    = 0
+
+    def close(self):
+        """close the file."""
+        self.__del__()
+
+    def sync(self):
+        """call the operating system's function to force the writing of all
+        file cache buffers to disk the file. 
+        
+        No effect if file is open as read"""
+        _SND.sf_write_sync(self.hdl)
+
+    def _seek(self, offset, whence = 0, mode = 'rw'):
+        """similar to python seek function, taking only in account audio data.
+        
+        :Parameters:
+            offset : int
+                the number of frames (eg two samples for stereo files) to move
+                relatively to position set by whence.
+            whence : int
+                only 0 (beginning), 1 (current) and 2 (end of the file) are
+                valid.
+            mode : string
+                If set to 'rw', both read and write pointers are updated. If
+                'r' is given, only read pointer is updated, if 'w', only the
+                write one is (this may of course make sense only if you open
+                the file in a certain mode).
+
+        Notes
+        -----
+        
+        - one only takes into accound audio data. 
+        - if an invalid seek is given (beyond or before the file), a
+          PyaudioIOError is launched."""
+        c_offset    = _num2int64(offset)
+        if mode == 'rw':
+            # Update both read and write pointers
+            st  = _SND.sf_seek(self.hdl, c_offset, whence)
+        elif mode == 'r':
+            whence = whence | SFM['SFM_READ']
+            st  = _SND.sf_seek(self.hdl, c_offset, whence)
+        elif mode == 'w':
+            whence = whence | SFM['SFM_WRITE']
+            st  = _SND.sf_seek(self.hdl, c_offset, whence)
+        else:
+            raise ValueError("mode should be one of 'r', 'w' or 'rw' only")
+
+        if st == -1:
+            msg = "Error while seeking, libsndfile error is %s" \
+                    % (_SND.sf_strerror(self.hdl))
+            raise PyaudioIOError(msg)
+        return st
+
+    # Functions to get informations about the file
+    def get_nframes(self):
+        """ Return the number of frames of the file"""
+        if self._sfmode == SFM['SFM_READ']:
+            # XXX: is this reliable for any file (think pipe and co ?)
+            return self._sfinfo.frames
+        else:
+            # In write/rwrite mode, the only reliable way to get the number of
+            # frames is to use seek.
+            raise NotImplementedError("Sorry, getting the current number of"
+                    "frames in write modes is not supported yet")
+    
+    def get_samplerate(self):
+        """ Return the samplerate in Hz of the file"""
+        return self._sfinfo.samplerate
+    
+    def get_channels(self):
+        """ Return the number of channels of the file"""
+        return self._sfinfo.channels
+    
+    def get_file_format(self):
+        """return user friendly file format string"""
+        return SND_TO_PY_FILE_FORMAT[self._format._int_type]
+
+    def get_encoding(self):
+        """return user friendly encoding string"""
+        return SND_TO_PY_ENCODING[self._format._int_encoding]
+
+    def get_endianness(self):
+        """return user friendly file format string"""
+        return SND_TO_PY_ENDIANNESS[self._format._int_endianness]
+
+    #------------------
+    # Functions to read
+    #------------------
+    def read_frames(self, nframes, dtype = N.float64):
+        """Read nframes frames of the file.
+        
+        :Parameters:
+            nframes : int
+                number of frames to read.
+            dtype : numpy dtype
+                dtype of the returned array containing read data (see note).
+        
+        Notes
+        -----
+        
+        - read_frames updates the read pointer.
+        - One column is one channel.
+        - if float are requested when the file contains integer data, you will
+          get normalized data (that is the max possible integer will be 1.0,
+          and the minimal possible value -1.0).
+        - if integers are requested when the file contains floating point data,
+          it may give wrong results because there is an ambiguity: if the
+          floating data are normalized, you can get a file with only 0 !
+          Getting integer data from files encoded in normalized floating point
+          is not supported (yet: sndfile supports it).""" 
+        c_nframes   = _num2int64(nframes)
+        if c_nframes < 0:
+            raise ValueError("number of frames has to be >= 0")
+
+        # XXX: inout argument
+        if self._sfinfo.channels > 1:
+            y           = N.zeros((nframes, self._sfinfo.channels), dtype)
+        else:
+            y           = N.zeros(nframes, dtype)
+
+        if dtype == N.float64:
+            res         = _SND.sf_readf_double(self.hdl, y, c_nframes)
+        elif dtype == N.float32:
+            res         = _SND.sf_readf_float(self.hdl, y, c_nframes)
+        elif dtype == N.int32:
+            res         = _SND.sf_readf_int(self.hdl, y, c_nframes)
+        elif dtype == N.int16:
+            res         = _SND.sf_readf_short(self.hdl, y, c_nframes)
+        else:
+            RuntimeError("Sorry, only float, double, int and short read " + \
+                    "supported for now")
+
+        if not(res == nframes):
+            msg = "Read %d frames, expected to read %d" % (res, nframes)
+            msg += ", libsndfile last msg is \n\t%s" \
+                    % _SND.sf_strerror(self.hdl)
+            raise IOError(msg)
+
+        return y
+
+    #-------------------
+    # Functions to write
+    #-------------------
+    # TODO: Think about overflow vs type of input, etc...
+    def write_frames(self, input, nframes = -1):
+        """write data to file.
+        
+        :Parameters:
+            input : ndarray
+                array containing data to write.  
+            nframes : int
+                number of frames to write.
+
+        Notes
+        -----
+
+        - one channel is one column
+        - updates the write pointer.
+        - if float are given when the file contains integer data, you should
+          put normalized data (that is the range [-1..1] will be written as the
+          maximum range allowed by the integer bitwidth)."""
+        # First, get the number of channels and frames from input
+        if input.ndim   == 1:
+            nc      = 1
+        else:
+            if input.ndim > 2:
+                raise Exception("Expect array of rank <= 2, got %d" \
+                        % input.ndim)
+            nc = input.shape[1]
+
+        if nframes == -1:
+            nframes = N.size(input)
+        # Number of channels should be the one expected
+        if not(nc == self._sfinfo.channels):
+            raise Exception("Expected %d channels, got %d" % \
+                    (self._sfinfo.channels, nc))
+
+        # Writing to the file
+        c_nframes   = _num2int64(nframes)
+        if c_nframes < 0:
+            raise ValueError("number of frames has to be >= 0")
+
+        input = N.require(input, requirements = 'C')
+
+        if input.dtype == N.float32:
+            if self._check_overflow(input):
+                warnings.warn("Warning, overflow detected when writing.")
+            res         = _SND.sf_writef_float(self.hdl, input, c_nframes)
+        elif input.dtype == N.float64:
+            self._check_overflow(input)
+            if self._check_overflow(input):
+                warnings.warn("Warning, overflow detected when writing.")
+            res         = _SND.sf_writef_double(self.hdl, input, c_nframes)
+        elif input.dtype == N.int32:
+            res         = _SND.sf_writef_int(self.hdl, input, c_nframes)
+        elif input.dtype == N.int16:
+            res         = _SND.sf_writef_short(self.hdl, input, c_nframes)
+        else:
+            raise Exception("type of input not understood: input should"
+                " be float64 or float32""")
+
+        if not(res == nframes):
+            raise IOError("write %d frames, expected to write %d" \
+                    % res, nframes)
+
+    def _check_overflow(self, data):
+        if N.max(data ** 2) >= 1.:
+            return True
+        return False
+
+    # Syntactic sugar
+    def __repr__(self):
+        return self.__str__()
+
+    def __str__(self):
+        repstr = "----------------------------------------\n"
+        if self._byfd:
+            repstr  += "File        : %d (opened by file descriptor)\n" % self.fd
+        else:
+            repstr  += "File        : %s\n" % self.filename
+        repstr  += "Channels    : %d\n" % self._sfinfo.channels
+        repstr  += "Sample rate : %d\n" % self._sfinfo.samplerate
+        repstr  += "Frames      : %d\n" % self._sfinfo.frames
+        repstr  += "Raw Format  : %#010x -> %s\n" % \
+                (self._format.get_format_raw(), self._format.get_major_str())
+        repstr  += "File format : %s\n" % self.get_file_format()
+        repstr  += "Encoding    : %s\n" % self.get_encoding()
+        repstr  += "Endianness  : %s\n" % self.get_endianness()
+        repstr  += "Sections    : %d\n" % self._sfinfo.sections
+        if self._sfinfo.seekable:
+            seek    = 'True'
+        else:
+            seek    = 'False'
+        repstr  += "Seekable    : %s\n" % seek
+        repstr  += "Duration    : %s\n" % self._generate_duration_str()
+        return repstr
+
+    def _generate_duration_str(self):
+        if self._sfinfo.samplerate < 1:
+            return None
+        tsec    = self._sfinfo.frames / self._sfinfo.samplerate
+        hrs     = tsec / 60 / 60
+        tsec    = tsec % (60 ** 2)
+        mins    = tsec / 60
+        tsec    = tsec % 60
+        secs    = tsec
+        ms      = 1000 * self._sfinfo.frames / self._sfinfo.samplerate % 1000
+
+        return "%02d:%02d:%02d.%3d" % (hrs, mins, secs, ms)
+
+def supported_format():
+    # XXX: broken
+    return py_to_snd_file_format_dic.keys()
+
+def supported_endianness():
+    # XXX: broken
+    return py_to_snd_endianness_dic.keys()
+
+def supported_encoding():
+    # XXX: broken
+    return py_to_snd_encoding_dic.keys()
+
+def _num2int64(value):
+    """ Convert a python objet to a c_int64, safely."""
+    if not (type(value) == int or type(value) == long):
+        value = long(value)
+        print "Warning, converting %s to long" % str(value)
+    c_value = c_int64(value)
+    if not c_value.value == value:
+        raise RuntimeError("Error while converting %s to a c_int64"\
+            ", maybe %s is too big ?" % str(value))
+    return c_value
diff --git a/telemeta/util/audiolab/scikits/audiolab/pysndfile.pyc b/telemeta/util/audiolab/scikits/audiolab/pysndfile.pyc
new file mode 100644 (file)
index 0000000..a162db4
Binary files /dev/null and b/telemeta/util/audiolab/scikits/audiolab/pysndfile.pyc differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/soundio/SConstruct b/telemeta/util/audiolab/scikits/audiolab/soundio/SConstruct
new file mode 100644 (file)
index 0000000..1d1b221
--- /dev/null
@@ -0,0 +1,2 @@
+Program('main', source = ['simple.c'], LIBS = ['asound'])
+Program('main2', source = ['simple2.c'], LIBS = ['asound'])
diff --git a/telemeta/util/audiolab/scikits/audiolab/soundio/_alsa.pyx b/telemeta/util/audiolab/scikits/audiolab/soundio/_alsa.pyx
new file mode 100644 (file)
index 0000000..5fb6a11
--- /dev/null
@@ -0,0 +1,198 @@
+cdef extern from "alsa/asoundlib.h":
+        ctypedef enum snd_pcm_stream_t:
+               SND_PCM_STREAM_PLAYBACK
+               SND_PCM_STREAM_CAPTURE
+        ctypedef enum snd_pcm_access_t :
+                SND_PCM_ACCESS_MMAP_INTERLEAVED
+                SND_PCM_ACCESS_MMAP_NONINTERLEAVED
+                SND_PCM_ACCESS_MMAP_COMPLEX
+                SND_PCM_ACCESS_RW_INTERLEAVED
+                SND_PCM_ACCESS_RW_NONINTERLEAVED
+        ctypedef enum snd_pcm_format_t :
+                SND_PCM_FORMAT_UNKNOWN
+                SND_PCM_FORMAT_S8
+                SND_PCM_FORMAT_U8
+                SND_PCM_FORMAT_S16_LE
+                SND_PCM_FORMAT_S16_BE
+                SND_PCM_FORMAT_U16_LE
+                SND_PCM_FORMAT_U16_BE
+                SND_PCM_FORMAT_S24_LE
+                SND_PCM_FORMAT_S24_BE
+                SND_PCM_FORMAT_U24_LE
+                SND_PCM_FORMAT_U24_BE
+                SND_PCM_FORMAT_S32_LE
+                SND_PCM_FORMAT_S32_BE
+                SND_PCM_FORMAT_U32_LE
+                SND_PCM_FORMAT_U32_BE
+                SND_PCM_FORMAT_FLOAT_LE
+                SND_PCM_FORMAT_FLOAT_BE
+                SND_PCM_FORMAT_FLOAT64_LE
+                SND_PCM_FORMAT_FLOAT64_BE
+                SND_PCM_FORMAT_IEC958_SUBFRAME_LE
+                SND_PCM_FORMAT_IEC958_SUBFRAME_BE
+                SND_PCM_FORMAT_MU_LAW
+                SND_PCM_FORMAT_A_LAW
+                SND_PCM_FORMAT_IMA_ADPCM
+                SND_PCM_FORMAT_MPEG
+                SND_PCM_FORMAT_GSM
+                SND_PCM_FORMAT_SPECIAL
+                SND_PCM_FORMAT_S24_3LE
+                SND_PCM_FORMAT_S24_3BE
+                SND_PCM_FORMAT_U24_3LE
+                SND_PCM_FORMAT_U24_3BE
+                SND_PCM_FORMAT_S20_3LE
+                SND_PCM_FORMAT_S20_3BE
+                SND_PCM_FORMAT_U20_3LE
+                SND_PCM_FORMAT_U20_3BE
+                SND_PCM_FORMAT_S18_3LE
+                SND_PCM_FORMAT_S18_3BE
+                SND_PCM_FORMAT_U18_3LE
+                SND_PCM_FORMAT_U18_3BE
+                SND_PCM_FORMAT_S16
+                SND_PCM_FORMAT_U16
+                SND_PCM_FORMAT_S24
+                SND_PCM_FORMAT_U24
+                SND_PCM_FORMAT_S32
+                SND_PCM_FORMAT_U32
+                SND_PCM_FORMAT_FLOAT
+                SND_PCM_FORMAT_FLOAT64
+                SND_PCM_FORMAT_IEC958_SUBFRAME
+
+        ctypedef struct snd_pcm_t
+        # XXX: how to make sure the typedef is OK ?
+        ctypedef unsigned long snd_pcm_uframes_t
+
+        int snd_pcm_open(snd_pcm_t **, char*, int, int)
+        int snd_pcm_close(snd_pcm_t *)
+        int snd_pcm_drain(snd_pcm_t *)
+
+        int snd_pcm_set_params(snd_pcm_t *, snd_pcm_format_t,
+                        snd_pcm_access_t, unsigned int,
+                        unsigned int, int, unsigned int)
+
+        int snd_pcm_writei(snd_pcm_t *, void*, snd_pcm_uframes_t)
+
+        char* snd_strerror(int error)
+
+        int snd_card_next(int *icard)
+        int snd_card_get_name(int icard, char** name)
+        char* snd_asoundlib_version()
+
+cdef extern from "numpy/arrayobject.h":
+        ctypedef int intp
+        ctypedef extern class numpy.ndarray [object PyArrayObject]:
+                cdef char *data
+                cdef int nd
+                cdef intp *dimensions
+                cdef intp *strides
+                cdef int flags
+
+cdef extern from "stdlib.h":
+        ctypedef unsigned long size_t
+        void free(void *ptr)
+        void *malloc(size_t size)
+        void *realloc(void *ptr, size_t size)
+        size_t strlen(char *s)
+        char *strcpy(char *dest, char *src)
+
+cdef extern from "stdint.h":
+        ctypedef unsigned short int16_t
+
+cdef extern from "Python.h":
+        object PyString_FromStringAndSize(char *v, int len)
+
+class AlsaException(Exception):
+        pass
+
+def asoundlib_version():
+        return snd_asoundlib_version()
+
+def card_indexes():
+        """Returns a list containing index of cards recognized by alsa."""
+        cdef int icur = -1
+
+        cards = []
+        while 1:
+                st = snd_card_next(&icur)
+                if st < 0:
+                        raise AlsaException("Could not get next card")
+                if icur < 0:
+                        break
+                cards.append(icur)
+        return tuple(cards)
+
+def card_name(index):
+        """Get the name of the card corresponding to the given index."""
+        cdef char* sptr
+        st = snd_card_get_name(index, &sptr)
+        if st < 0:
+                raise AlsaException("Error while getting card name %d: alsa error "\
+                                    "was %s" % (index, snd_strerror(st)))
+        else:
+                cardname = PyString_FromStringAndSize(sptr, len(sptr))
+                free(sptr)
+        return cardname
+
+cdef class _PCM:
+        cdef snd_pcm_t* pcmhdl
+        cdef public char* name
+
+        def __new__(self, device = "default", stream = SND_PCM_STREAM_PLAYBACK):
+                self.pcmhdl = NULL
+
+                st = snd_pcm_open(&self.pcmhdl, device, stream, 0)
+                if st < 0:
+                        raise AlsaException("Cannot open device %s: %s" % (device, snd_strerror(st)))
+
+        def __init__(self, device = "default", stream = SND_PCM_STREAM_PLAYBACK):
+                self.name = device
+
+        def __dealloc__(self):
+                if self.pcmhdl:
+                        snd_pcm_close(self.pcmhdl)
+
+cdef class Device:
+        cdef _PCM pcm
+        cdef unsigned int samplerate
+        # XXX: set property instead
+        cdef public unsigned int channels
+        cdef snd_pcm_format_t format
+        cdef snd_pcm_access_t access
+        def __init__(self, samplerate = 48000, channels = 1,
+                     format = SND_PCM_FORMAT_S16,
+                     access = SND_PCM_ACCESS_RW_INTERLEAVED):
+                self.pcm = _PCM()
+
+                self.samplerate = samplerate
+                self.channels = channels
+
+                self.access = access
+                self.format = format
+
+                st = snd_pcm_set_params(self.pcm.pcmhdl, format, access, channels,
+                                        samplerate, 1, 1000000)
+                if st < 0:
+                        raise AlsaException()
+
+        def play_short(self, ndarray input):
+                cdef int16_t* p = <int16_t*>input.data
+                cdef int16_t* buff = NULL
+                #cdef int n = input.dimensions[0]
+                cdef int n = input.dimensions[0]
+                cdef int nb = n / 1024 / 16
+                cdef snd_pcm_uframes_t bufsz = 1024 * 16
+
+                assert self.format == SND_PCM_FORMAT_S16
+                assert self.access == SND_PCM_ACCESS_RW_INTERLEAVED
+
+                for i from 0 <= i  < nb:
+                        st =  snd_pcm_writei(self.pcm.pcmhdl, &p[i * bufsz], bufsz)
+                        if not st == bufsz:
+                                print "Error while writing to device", st
+                                print snd_strerror(st)
+
+                snd_pcm_drain(self.pcm.pcmhdl)
+
+        def _get_name(self):
+                return self.pcm.name
+        name = property(_get_name)
diff --git a/telemeta/util/audiolab/scikits/audiolab/soundio/alsa.py b/telemeta/util/audiolab/scikits/audiolab/soundio/alsa.py
new file mode 100644 (file)
index 0000000..15754de
--- /dev/null
@@ -0,0 +1,35 @@
+import numpy as np
+
+from _alsa import card_name, card_indexes, asoundlib_version
+from _alsa import Device, AlsaException
+
+def play(input, samplerate = 48000):
+    if input.ndim == 1:
+        n = input.size
+        nc = 1
+    elif input.ndim == 2:
+        n, nc = input.shape
+    else:
+        raise ValueError("Only ndim 1 or 2 supported")
+
+    if not input.dtype in (np.float32, np.float64):
+        raise ValueError("input should be array of float32 or float64 !")
+
+    try:
+        dev = Device(samplerate = samplerate, channels = nc)
+        dev.play_short((16384 * input).astype(np.int16))
+    except AlsaException, e:
+        raise IOError(str(e))
+
+if __name__ == '__main__':
+    print "Asoundlib version is", asoundlib_version()
+    for i in card_indexes():
+        print card_name(i)
+
+    dev = Device()
+    print "Device name:", dev.name
+
+    a = 0.2 * np.random.randn(4e4)
+    play(a, 16000)
+    play(a, 8000)
+    play(a, 22050)
diff --git a/telemeta/util/audiolab/scikits/audiolab/soundio/alsa_ctypes.py b/telemeta/util/audiolab/scikits/audiolab/soundio/alsa_ctypes.py
new file mode 100644 (file)
index 0000000..d1c65fc
--- /dev/null
@@ -0,0 +1,440 @@
+#! /usr/bin/env python
+# Last Change: Fri Sep 07 02:00 PM 2007 J
+
+# Copyright (C) 2006-2007 Cournapeau David <cournape@gmail.com>
+#
+# 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.1 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+# vim:syntax=python
+
+"""This is a small module to wrap basic functionalities of alsa: it uses ctypes
+for the wrapping."""
+
+__docformat__ = 'restructuredtext'
+
+__all__ = ['asoundlib_version', 'asoundlib_version_numbers', 'card_indexes', \
+        'card_name', 'card_longname']
+#================
+# Load alsa lib
+#================
+import ctypes
+from ctypes import cdll, Structure, c_int, pointer, POINTER, c_uint,\
+        create_string_buffer, c_char_p, sizeof, byref, string_at, c_size_t,\
+        c_void_p, c_ulong, c_uint16, c_long, c_uint8, c_int16, c_float
+try:
+    from ctypes import c_int64
+except ImportError, e:
+    print "Cannot import c_int64 from ctypes: if you are on ubuntu/debian," +\
+        " this is likely because ctypes was compiled with libffi. see" +\
+        " https://launchpad.net/ubuntu/+source/python2.5/+bug/71914"
+    raise e
+
+from numpy.ctypeslib import ndpointer
+CTYPES_MAJOR    = int(ctypes.__version__.split('.')[0])
+CTYPES_MINOR    = int(ctypes.__version__.split('.')[1])
+CTYPES_MICRO    = int(ctypes.__version__.split('.')[2])
+if CTYPES_MAJOR < 1 or (CTYPES_MINOR == 0 and CTYPES_MICRO < 1):
+    raise ImportError("version of ctypes is %s, expected at least %s" \
+            % (ctypes.__version__, '1.0.1'))
+import numpy as N
+
+ALSALOC = 'libasound.so.2'
+_ALSA = cdll.LoadLibrary(ALSALOC)
+# XXX: alsa means linux, normally. How to locate the glibc ?
+_C = cdll.LoadLibrary("libc.so.6")
+
+# Check version
+_ALSA.snd_asoundlib_version.args = []
+_ALSA.snd_asoundlib_version.restype = c_char_p
+
+def asoundlib_version():
+    """Return the version of asoundlib as a string"""
+    version = _ALSA.snd_asoundlib_version()
+    return version
+
+def asoundlib_version_numbers():
+    """Return the version of asoundlib as a tuple(major, minor, micro)."""
+    version = asoundlib_version()
+    return tuple(int(i) for i in version.split('.'))
+
+major, minor, micro = asoundlib_version_numbers()
+if not (major == 1 and minor == 0):
+    raise RuntimeError("Expected 1.0.x version, got %s instead" % asoundlib_version())
+
+# Define pointers to opaque structures
+class snd_pcm_t(Structure):
+    pass
+
+class snd_pcm_hw_params_t(Structure):
+    pass
+
+class snd_pcm_sw_params_t(Structure):
+    pass
+
+class snd_output_t(Structure):
+    pass
+
+snd_pcm_t_p = POINTER(snd_pcm_t)
+snd_pcm_hw_params_t_p = POINTER(snd_pcm_hw_params_t)
+snd_pcm_sw_params_t_p = POINTER(snd_pcm_sw_params_t)
+snd_output_t_p = POINTER(snd_output_t)
+
+#------------
+# Define enum
+#------------
+SND_PCM_STREAM = {'SND_PCM_STREAM_PLAYBACK' : 0,
+        'SND_PCM_STREAM_CAPTURE' : 1}
+
+#-----------------------------------------------
+# Define all the function we need from asoundlib
+#-----------------------------------------------
+arg1    = c_int
+arg2    = POINTER(c_char_p)
+_ALSA.snd_card_get_name.argtypes    = [arg1, arg2]
+_ALSA.snd_card_get_name.restype     = c_int
+
+arg1    = c_int
+arg2    = POINTER(c_char_p)
+_ALSA.snd_card_get_longname.argtypes    = [arg1, arg2]
+_ALSA.snd_card_get_longname.restype     = c_int
+
+arg1    = POINTER(c_int)
+_ALSA.snd_card_next.argtypes    = [arg1]
+_ALSA.snd_card_next.restype     = c_int
+
+arg1    = c_int
+_ALSA.snd_strerror.argtypes    = [arg1]
+_ALSA.snd_strerror.restype     = c_char_p
+
+# output related functions
+arg1    = POINTER(snd_output_t_p)
+_ALSA.snd_output_buffer_open.argtypes = [arg1]
+_ALSA.snd_output_buffer_open.restype  = c_int
+
+arg1    = snd_output_t_p
+_ALSA.snd_output_close.argtypes = [arg1]
+_ALSA.snd_output_close.restype  = c_int
+
+arg1    = snd_output_t_p
+arg2    = POINTER(c_char_p)
+_ALSA.snd_output_buffer_string.argtypes = [arg1, arg2]
+_ALSA.snd_output_buffer_string.restype  = c_size_t
+
+arg1    = snd_pcm_t_p
+arg2    = snd_output_t_p
+_ALSA.snd_pcm_dump.argtypes = [arg1, arg2]
+_ALSA.snd_pcm_dump.restype  = c_int
+
+# pcm related functions
+arg1    = POINTER(POINTER(snd_pcm_t))
+arg2    = c_char_p
+arg3    = c_int
+arg4    = c_int
+_ALSA.snd_pcm_open.argtypes = [arg1, arg2, arg3, arg4]
+_ALSA.snd_pcm_open.restype  = c_int
+
+arg1    = POINTER(snd_pcm_t)
+_ALSA.snd_pcm_close.argtypes = [arg1]
+_ALSA.snd_pcm_close.restype  = c_int
+
+arg1    = POINTER(snd_pcm_t)
+_ALSA.snd_pcm_reset.argtypes = [arg1]
+_ALSA.snd_pcm_reset.restype  = c_int
+
+arg1    = POINTER(snd_pcm_t)
+_ALSA.snd_pcm_drain.argtypes = [arg1]
+_ALSA.snd_pcm_drain.restype  = c_int
+
+arg1    = POINTER(snd_pcm_hw_params_t_p)
+_ALSA.snd_pcm_hw_params_malloc.argtypes = [arg1]
+_ALSA.snd_pcm_hw_params_malloc.restype  = c_int
+
+arg1    = snd_pcm_hw_params_t_p
+_ALSA.snd_pcm_hw_params_free.argtypes = [arg1]
+_ALSA.snd_pcm_hw_params_free.restype  = c_int
+
+arg1    = snd_pcm_t_p
+arg2    = snd_pcm_hw_params_t_p
+_ALSA.snd_pcm_hw_params_any.argtypes = [arg1, arg2]
+_ALSA.snd_pcm_hw_params_any.restype  = c_int
+
+arg1    = snd_pcm_t_p
+arg2    = snd_pcm_hw_params_t_p
+_ALSA.snd_pcm_hw_params.argtypes = [arg1, arg2]
+_ALSA.snd_pcm_hw_params.restype  = c_int
+
+arg1    = snd_pcm_t_p
+arg2    = snd_pcm_hw_params_t_p
+arg3    = c_int
+_ALSA.snd_pcm_hw_params_set_access.argtypes = [arg1, arg2, arg3]
+_ALSA.snd_pcm_hw_params_set_access.restype  = c_int
+
+arg1    = snd_pcm_t_p
+arg2    = snd_pcm_hw_params_t_p
+arg3    = POINTER(c_uint)
+arg4    = c_int
+_ALSA.snd_pcm_hw_params_set_rate_near.argtypes = [arg1, arg2, arg3, arg4]
+_ALSA.snd_pcm_hw_params_set_rate_near.restype  = c_int
+
+arg1    = snd_pcm_t_p
+arg2    = snd_pcm_hw_params_t_p
+arg3    = c_uint
+_ALSA.snd_pcm_hw_params_set_channels.argtypes = [arg1, arg2, arg3]
+_ALSA.snd_pcm_hw_params_set_channels.restype  = c_int
+
+arg1    = snd_pcm_t_p
+arg2    = snd_pcm_hw_params_t_p
+arg3    = c_int
+_ALSA.snd_pcm_hw_params_set_format.argtypes = [arg1, arg2, arg3]
+_ALSA.snd_pcm_hw_params_set_format.restype  = c_int
+
+arg1    = snd_pcm_t_p
+arg2    = snd_pcm_hw_params_t_p
+arg3    = POINTER(c_ulong)
+_ALSA.snd_pcm_hw_params_set_buffer_size_near.argtypes = [arg1, arg2, arg3]
+_ALSA.snd_pcm_hw_params_set_buffer_size_near.restype  = c_int
+
+arg1    = snd_pcm_t_p
+arg2    = snd_pcm_hw_params_t_p
+arg3    = POINTER(c_ulong)
+arg4    = c_int
+_ALSA.snd_pcm_hw_params_set_period_size_near.argtypes = [arg1, arg2, arg3, arg4]
+_ALSA.snd_pcm_hw_params_set_period_size_near.restype  = c_int
+
+# write
+arg1    = snd_pcm_t_p
+arg2    = c_void_p
+arg3    = c_ulong
+_ALSA.snd_pcm_writei.argtypes = [arg1, arg2, arg3]
+_ALSA.snd_pcm_writei.restype = c_ulong
+
+#==================
+# General functions
+#==================
+class AlsaException(Exception):
+    pass
+    
+class OutputBuffer():
+    def __init__(self):
+        ohdl = snd_output_t_p()
+        st = _ALSA.snd_output_buffer_open(byref(ohdl))
+        if st:
+            raise AlsaException("Error creating output buffer")
+        self._hdl = ohdl
+
+    def __del__(self, close_func = _ALSA.snd_output_close):
+        if hasattr(self, '_hdl'):
+            if not(self._hdl == 0):
+                close_func(self._hdl)
+                self._hdl = 0
+
+
+OHDL = OutputBuffer()
+
+#========================
+# Cards related functions
+#========================
+def card_indexes():
+    """Returns a list containing index of cards recognized by alsa."""
+    cards = []
+    cur = c_int(-1)
+    while 1:
+        st = _ALSA.snd_card_next(byref(cur))
+        if st < 0:
+            raise AlsaException("Could not get next card")
+        if cur.value < 0:
+            break
+        cards.append(cur.value)
+    return tuple(cards)
+
+def card_name(index):
+    """Get the name of the card corresponding to the given index."""
+    sptr = c_char_p(0)
+    st = _ALSA.snd_card_get_name(index, byref(sptr))
+    if st < 0:
+        raise AlsaException("Error while getting card name %d: alsa error "\
+                            "was %s" % (index, _ALSA.snd_strerror(st)))
+    cardname = string_at(sptr)
+    _C.free(sptr)
+    return cardname
+
+def card_longname(index):
+    """Get the long name of the card corresponding to the given index."""
+    sptr = c_char_p(0)
+    st = _ALSA.snd_card_get_longname(index, byref(sptr))
+    if st < 0:
+        raise AlsaException("Error while getting card longname %d: alsa error "\
+                            "was %s" % (index, _ALSA.snd_strerror(st)))
+    cardname = string_at(sptr)
+    _C.free(sptr)
+    return cardname
+
+#=======================
+# Pcm related functions
+#=======================
+class _HwParams:
+    """Small class to assure that the hw parmas are always freed."""
+    def __init__(self):
+        self._hdl = snd_pcm_hw_params_t_p()
+        st = _ALSA.snd_pcm_hw_params_malloc(byref(self._hdl))
+        if st:
+            raise AlsaException("error while creating hw params %s" \
+                                % _ALSA.snd_strerror(st))
+
+    def __del__(self, close_func = _ALSA.snd_pcm_hw_params_free):
+        if hasattr(self, '_hdl'):
+            if not(self._hdl == 0):
+                close_func(self._hdl)
+                self._hdl = 0
+
+class Pcm:
+    def __init__(self, device = 'default', samplerate = 48000, channels = 1):
+        self._pcmhdl = POINTER(snd_pcm_t)()
+
+        # Open the pcm device
+        st = _ALSA.snd_pcm_open(byref(self._pcmhdl), device, 
+                                 SND_PCM_STREAM['SND_PCM_STREAM_PLAYBACK'], 0)
+        if st:
+            raise AlsaException("error while opening pcm device %s; alsa error is %s"\
+                                % (device, _ALSA.snd_strerror(st)))
+
+        # Set hw params
+        self._set_hw_params(samplerate, channels)
+
+        # Reset the pcm device
+        st = _ALSA.snd_pcm_reset(self._pcmhdl)
+        if st:
+            raise AlsaException("error while resetting pcm : %s" \
+                                % _ALSA.snd_strerror(st))
+
+        self.nc = channels
+        self.samplerate = samplerate
+
+    def _set_hw_params(self, samplerate, channels):
+        # XXX: Parameters copied from sndfile-play.c from libsndfile. Check the
+        # meaning
+        alsa_period_size = c_ulong(1024)
+        alsa_buffer_frames = c_ulong(alsa_period_size.value * 4)
+
+        hw = _HwParams()
+        hwhdl = hw._hdl
+        st = _ALSA.snd_pcm_hw_params_any(self._pcmhdl, hwhdl)
+        if st < 0:
+            raise AlsaException("cannot initialize hw st: %s" \
+                                % _ALSA.snd_strerror(st))
+
+        st = _ALSA.snd_pcm_hw_params_set_access(self._pcmhdl, hwhdl, 3)
+        if st < 0:
+            raise AlsaException("cannot initialize hw st: %s" \
+                                % _ALSA.snd_strerror(st))
+
+        rrate = c_uint(samplerate)
+        st = _ALSA.snd_pcm_hw_params_set_rate_near(self._pcmhdl, hwhdl, byref(rrate), 0)
+        if st < 0:
+            raise AlsaException("cannot set samplerate : %s" \
+                                % _ALSA.snd_strerror(st))
+
+        st = _ALSA.snd_pcm_hw_params_set_format(self._pcmhdl, hwhdl, 14)
+        if st < 0:
+            raise AlsaException("cannot set format : %s" \
+                                % _ALSA.snd_strerror(st))
+
+        st = _ALSA.snd_pcm_hw_params_set_channels(self._pcmhdl, hwhdl, channels)
+        if st < 0:
+            raise AlsaException("cannot set number of channels : %s" \
+                                % _ALSA.snd_strerror(st))
+
+        st = _ALSA.snd_pcm_hw_params_set_buffer_size_near(self._pcmhdl, hwhdl, 
+                                                          byref(alsa_buffer_frames))
+        if st < 0:
+            raise AlsaException("cannot set buffer size: %s" \
+                                % _ALSA.snd_strerror(st))
+
+        st = _ALSA.snd_pcm_hw_params_set_period_size_near(self._pcmhdl, hwhdl, 
+                                                          byref(alsa_period_size), 0)
+        if st < 0:
+            raise AlsaException("cannot set period size: %s" \
+                                % _ALSA.snd_strerror(st))
+
+        st = _ALSA.snd_pcm_hw_params(self._pcmhdl, hwhdl)
+        if st < 0:
+            raise AlsaException("cannot set params : %s" \
+                                % _ALSA.snd_strerror(st))
+
+    def __del__(self, close_func = _ALSA.snd_pcm_close):
+        if hasattr(self, '_pcmhdl'):
+            try:
+                self._pcmhdl[0]
+                close_func(self._pcmhdl)
+                self._pcmhdl = POINTER(snd_pcm_t)()
+            except ValueError:
+                pass
+
+    def __str__(self):
+        buf = c_char_p()
+        msg = "Pcm device: "
+        if self._pcmhdl > 0:
+            msg += " Opened\n"
+            # XXX error checking
+            st = _ALSA.snd_pcm_dump(self._pcmhdl, OHDL._hdl)
+            st = _ALSA.snd_output_buffer_string(OHDL._hdl, byref(buf))
+            if st > 0:
+                msg += string_at(buf)
+        return msg
+
+    def __repr__(self):
+        return self.__str__()
+
+    def write_float(self, data):
+        bufsz = 1024 * 2
+        nb = data.size / bufsz / self.nc
+        for i in range(nb):
+            b = a[i * bufsz: (i+1) * bufsz]
+            st =  _ALSA.snd_pcm_writei(self._pcmhdl, 
+                                 b.ctypes.data_as(POINTER(c_float)), bufsz)
+            if not st == bufsz:
+                print "Error while writing to device"
+        b = a[nb * bufsz: -1]
+        reframes = b.size / self.nc
+        st =  _ALSA.snd_pcm_writei(self._pcmhdl, 
+                             b.ctypes.data_as(POINTER(c_float)), reframes)
+        if not st == reframes:
+            print "Error while writing to device"
+
+        _ALSA.snd_pcm_drain(self._pcmhdl)
+#class AlsaPlayer:
+#    def __init__(self, device = "default"):
+#        pcm = _Pcm(device)
+#        hw = _HwParams()
+#        err = _ALSA.snd_pcm_hw_params_any(pcm.pcmhdl, hw.hwparamshdl)
+#        if err:
+#            raise AlsaException("
+
+if __name__ == '__main__':
+    print card_indexes()
+    print [card_name(i) for i in card_indexes()]
+    print [card_longname(i) for i in card_indexes()]
+    print asoundlib_version()
+    print asoundlib_version_numbers()
+    from scikits.audiolab import wavread
+    a, fs = wavread('test.wav')[:2]
+    if a.ndim > 1:
+        nc = a.shape[1]
+    else: 
+        nc = 1
+    a = a.astype(N.float32)
+    pcm = Pcm("default:1", 22050, channels = nc)
+    print pcm
+    pcm.write_float(a)
diff --git a/telemeta/util/audiolab/scikits/audiolab/soundio/setup.py b/telemeta/util/audiolab/scikits/audiolab/soundio/setup.py
new file mode 100644 (file)
index 0000000..a223451
--- /dev/null
@@ -0,0 +1,12 @@
+from distutils.core import setup
+from distutils.extension import Extension
+from Cython.Distutils import build_ext
+from numpy.distutils.misc_util import get_numpy_include_dirs
+
+setup(name = "PyrexGuide",
+      ext_modules=[ 
+          Extension("_alsa", ["_alsa.pyx"], 
+                    libraries = ['asound'], 
+                    include_dirs = get_numpy_include_dirs())],
+      cmdclass = {'build_ext': build_ext})
+
diff --git a/telemeta/util/audiolab/scikits/audiolab/soundio/simple.c b/telemeta/util/audiolab/scikits/audiolab/soundio/simple.c
new file mode 100644 (file)
index 0000000..96e1c37
--- /dev/null
@@ -0,0 +1,74 @@
+#include <stdio.h>
+
+#include <alsa/asoundlib.h>
+
+int main()
+{
+        snd_pcm_t *pcm;
+        snd_pcm_hw_params_t *hw;
+
+        int st;
+        unsigned int rrate = 44100;
+        snd_output_t *output;
+
+        st = snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0);
+        if (st) {
+                fprintf(stderr, "Error opening pcm\n");
+                return -1;
+        }
+
+        st = snd_pcm_hw_params_malloc(&hw);
+        if (st) {
+                fprintf(stderr, "Error while allocating hw\n");
+                return -1;
+        }
+
+        st = snd_pcm_hw_params_any(pcm, hw);
+        if (st) {
+                fprintf(stderr, "Error while allocating hw\n");
+                return -1;
+        }
+
+        st = snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED);
+        if (st) {
+                fprintf(stderr, "Error while allocating hw\n");
+                return -1;
+        }
+
+        st = snd_pcm_hw_params_set_rate_near(pcm, hw, &rrate, 0);
+        if (st) {
+                fprintf(stderr, "Error while allocating hw\n");
+                return -1;
+        }
+        fprintf(stdout, "rate is %d\n", rrate);
+
+        st = snd_pcm_hw_params(pcm, hw);
+        if (st) {
+                fprintf(stderr, "Error while allocating hw\n");
+                return -1;
+        }
+
+        //st = snd_output_stdio_attach(&output, stdout, 0);
+        //if (st < 0) {
+        //        printf("Output failed: %s\n", snd_strerror(st));
+        //        return 0;
+        //}
+        st = snd_output_buffer_open(&output);
+        if (st < 0) {
+                printf("Output buffer open failed: %s\n", snd_strerror(st));
+                return 0;
+        }
+        char* buf;
+        snd_pcm_dump(pcm, output);
+        st = snd_output_buffer_string(output, &buf);
+        fprintf(stdout, "%d chars\n", st);
+        fprintf(stdout, "%s", buf);
+
+        //snd_output_close(output);
+        //snd_pcm_hw_params_free(hw);
+        snd_pcm_close(pcm);
+
+        snd_config_update_free_global();
+
+        return 0;
+}
diff --git a/telemeta/util/audiolab/scikits/audiolab/soundio/simple2.c b/telemeta/util/audiolab/scikits/audiolab/soundio/simple2.c
new file mode 100644 (file)
index 0000000..401d78d
--- /dev/null
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <stdint.h>
+
+#include <alsa/asoundlib.h>
+
+int play(snd_pcm_t *pcm)
+{
+        int16_t buff[1024 * 16];
+        int i, j;
+        snd_pcm_uframes_t frames;
+
+        for (i = 0; i < 4; ++i) {
+            for (j = 0; j < 1024 * 16; ++j) {
+                buff[j] = random() & 0xff;
+            }
+            frames = snd_pcm_writei(pcm, buff, 1024 * 16); 
+            fprintf(stderr, "%lu\n", frames);
+        }
+
+        return 0;
+}
+
+int set(snd_pcm_t *pcm, snd_pcm_format_t format, snd_pcm_access_t access, 
+        unsigned int channels, unsigned int samplerate)
+{
+        int st;
+
+        st = snd_pcm_set_params(pcm, format, access, channels, samplerate,
+                                1, 1000000);      
+        if (st < 0) {
+                printf("Output failed: %s\n", snd_strerror(st));
+                return st;
+        }
+
+        return 0;
+}
+
+int main()
+{
+        snd_pcm_t *pcm;
+        snd_pcm_hw_params_t *hw;
+
+        int st;
+        unsigned int rrate = 48000;
+        unsigned int nc = 1;
+        snd_output_t *output;
+
+        int i, j;
+        snd_pcm_sframes_t frames;
+
+        st = snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0);
+        if (st) {
+                fprintf(stderr, "Error opening pcm\n");
+                return -1;
+        }
+
+        st = snd_output_stdio_attach(&output, stdout, 0);
+        if (st < 0) {
+                printf("Output failed: %s\n", snd_strerror(st));
+                return -1;
+        }
+
+        set(pcm, SND_PCM_FORMAT_S16, SND_PCM_ACCESS_RW_INTERLEAVED, 1, 44100);
+
+        play(pcm);
+        snd_pcm_drain(pcm);
+
+        set(pcm, SND_PCM_FORMAT_S16, SND_PCM_ACCESS_RW_INTERLEAVED, 1, 8000);
+
+        play(pcm);
+
+        //snd_pcm_dump(pcm, output);
+
+        snd_output_close(output);
+        snd_pcm_close(pcm);
+
+        snd_config_update_free_global();
+
+        return 0;
+}
diff --git a/telemeta/util/audiolab/scikits/audiolab/test_data/original.aif b/telemeta/util/audiolab/scikits/audiolab/test_data/original.aif
new file mode 100644 (file)
index 0000000..457a12c
Binary files /dev/null and b/telemeta/util/audiolab/scikits/audiolab/test_data/original.aif differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/test_data/test.aiff b/telemeta/util/audiolab/scikits/audiolab/test_data/test.aiff
new file mode 100644 (file)
index 0000000..93bc793
Binary files /dev/null and b/telemeta/util/audiolab/scikits/audiolab/test_data/test.aiff differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/test_data/test.au b/telemeta/util/audiolab/scikits/audiolab/test_data/test.au
new file mode 100644 (file)
index 0000000..8311e38
Binary files /dev/null and b/telemeta/util/audiolab/scikits/audiolab/test_data/test.au differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/test_data/test.flac b/telemeta/util/audiolab/scikits/audiolab/test_data/test.flac
new file mode 100644 (file)
index 0000000..64074f9
Binary files /dev/null and b/telemeta/util/audiolab/scikits/audiolab/test_data/test.flac differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/test_data/test.raw b/telemeta/util/audiolab/scikits/audiolab/test_data/test.raw
new file mode 100644 (file)
index 0000000..fb2a04c
Binary files /dev/null and b/telemeta/util/audiolab/scikits/audiolab/test_data/test.raw differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/test_data/test.sdif b/telemeta/util/audiolab/scikits/audiolab/test_data/test.sdif
new file mode 100644 (file)
index 0000000..0125b89
Binary files /dev/null and b/telemeta/util/audiolab/scikits/audiolab/test_data/test.sdif differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/test_data/test.wav b/telemeta/util/audiolab/scikits/audiolab/test_data/test.wav
new file mode 100644 (file)
index 0000000..d6c8012
Binary files /dev/null and b/telemeta/util/audiolab/scikits/audiolab/test_data/test.wav differ
diff --git a/telemeta/util/audiolab/scikits/audiolab/tests/__init__.py b/telemeta/util/audiolab/scikits/audiolab/tests/__init__.py
new file mode 100644 (file)
index 0000000..7f2fbc0
--- /dev/null
@@ -0,0 +1,2 @@
+#! /usr/bin/env python
+# Last Change: Mon May 21 12:00 PM 2007 J
diff --git a/telemeta/util/audiolab/scikits/audiolab/tests/test_matapi.py b/telemeta/util/audiolab/scikits/audiolab/tests/test_matapi.py
new file mode 100644 (file)
index 0000000..fe17b8e
--- /dev/null
@@ -0,0 +1,164 @@
+#! /usr/bin/env python
+# Last Change: Tue Jul 17 11:00 AM 2007 J
+from os.path import join, dirname
+from os import remove
+from tempfile import mkstemp
+
+from numpy.testing import *
+import numpy as N
+
+set_package_path()
+from audiolab.matapi import wavread, auread, aiffread, sdifread, flacread
+from audiolab.matapi import wavwrite, auwrite, aiffwrite, sdifwrite, flacwrite
+from audiolab.pysndfile import PyaudioException, sndfile, formatinfo as audio_format
+from audiolab.pysndfile import FlacUnsupported
+restore_path()
+
+#Optional:
+set_local_path()
+# import modules that are located in the same directory as this file.
+from testcommon import open_tmp_file, close_tmp_file
+restore_path()
+
+class test_audiolab(NumpyTestCase):
+    def _test_read(self, func, format, filext):
+       # Create a tmp audio file, write some random data into it, and check it
+       # is the expected data when read from a function from the matapi.
+        rfd, fd, cfilename   = open_tmp_file('pysndfiletest.' + filext)
+        try:
+            nbuff = 22050
+            noise = 0.1 * N.random.randn(nbuff)
+
+            # Open the copy file for writing
+            b = sndfile(cfilename, 'write', format, 1, nbuff)
+            b.write_frames(noise, nbuff)
+            b.close()
+
+            # Reread the data
+            b = sndfile(cfilename, 'read')
+            rcnoise = b.read_frames(nbuff)
+            b.close()
+
+            rnoise  = func(cfilename)[0]
+
+            assert_array_equal(rnoise, rcnoise)
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_wavread(self):
+        """ Check wavread """
+        self._test_read(wavread, audio_format('wav', 'pcm16', 'file'), 'wav') 
+
+    def test_flacread(self):
+        """ Check flacread """
+        try:
+            self._test_read(flacread, audio_format('flac', 'pcm16', 'file'), 'flac') 
+        except FlacUnsupported:
+            print "Flac unsupported, flacread not tested"
+
+    def test_auread(self):
+        """ Check auread """
+        self._test_read(auread, audio_format('au', 'ulaw', 'file'), 'au') 
+
+    def test_aiffread(self):
+        """ Check aiffread """
+        self._test_read(aiffread, audio_format('aiff', 'pcm16', 'file'), 'aiff') 
+
+    def test_sdifread(self):
+        """ Check sdifread (ircam format) """
+        self._test_read(sdifread, audio_format('ircam', 'pcm16', 'file'), 'sdif') 
+
+    def test_bad_wavread(self):
+        """ Check wavread on bad file"""
+        # Create a tmp audio file with non wav format, write some random data into it, 
+        # and check it can not be opened by wavread
+        rfd, fd, cfilename   = open_tmp_file('pysndfiletest.wav')
+        try:
+            nbuff   = 22050
+            noise   = 0.1 * N.random.randn(nbuff)
+
+            # Open the copy file for writing
+            format  = audio_format('aiff', 'pcm16')
+            b       = sndfile(cfilename, 'write', format, 1, nbuff)
+
+            b.write_frames(noise, nbuff)
+
+            b.close()
+
+            b   = sndfile(cfilename, 'read')
+            rcnoise = b.read_frames(nbuff)
+            b.close()
+
+            try:
+                rnoise  = wavread(cfilename)[0]
+                raise Exception("wavread on non wav file succeded, expected to fail")
+            except PyaudioException, e:
+                pass
+                #print str(e) + ", as expected"
+
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def _test_write(self, func, format, filext):
+        """ Check *write functions from matpi """
+        rfd1, fd1, cfilename1  = open_tmp_file('pysndfiletest.' + filext)
+        rfd2, fd2, cfilename2  = open_tmp_file('pysndfiletest.' + filext)
+        try:
+            nbuff   = 22050
+            fs      = nbuff
+            noise   = 0.1 * N.random.randn(nbuff)
+
+            # Open the first file for writing with sndfile
+            b       = sndfile(cfilename1, 'write', format, 1, fs)
+
+            b.write_frames(noise, nbuff)
+
+            b.close()
+
+            # Write same data with wavwrite
+            func(noise, cfilename2, fs)
+
+            # Compare if both files have same hash
+            f1  = open(cfilename1)
+            f2  = open(cfilename2)
+
+            import md5
+
+            m1  = md5.new()
+            m2  = md5.new()
+
+            m1.update(f1.read())
+            m2.update(f2.read())
+
+           f1.close()
+           f2.close()
+            assert m1.hexdigest() == m2.hexdigest()
+        finally:
+            close_tmp_file(rfd1, cfilename1)
+            close_tmp_file(rfd2, cfilename2)
+
+    def test_wavwrite(self):
+        """ Check wavwrite """
+        self._test_write(wavwrite, audio_format('wav', 'pcm16', 'file'), 'wav')
+
+    def test_aiffwrite(self):
+        """ Check aiffwrite """
+        self._test_write(aiffwrite, audio_format('aiff', 'pcm16', 'file'), 'aiff')
+
+    def test_auwrite(self):
+        """ Check wavwrite """
+        self._test_write(auwrite, audio_format('au', 'ulaw', 'file'), 'au')
+
+    def test_sdifwrite(self):
+        """ Check wavwrite """
+        self._test_write(sdifwrite, audio_format('ircam', 'pcm16', 'file'), 'sdif')
+
+    def test_flacwrite(self):
+        """ Check flacwrite """
+        try:
+            self._test_write(flacwrite, audio_format('flac', 'pcm16', 'file'), 'flac')
+        except FlacUnsupported:
+            print "Flac unsupported, flacwrite not tested"
+
+if __name__ == "__main__":
+    NumpyTest().run()
diff --git a/telemeta/util/audiolab/scikits/audiolab/tests/test_pysndfile.py b/telemeta/util/audiolab/scikits/audiolab/tests/test_pysndfile.py
new file mode 100644 (file)
index 0000000..632a4bc
--- /dev/null
@@ -0,0 +1,396 @@
+#! /usr/bin/env python
+# Last Change: Tue Jul 17 11:00 AM 2007 J
+"""Test for the sndfile class."""
+from os.path import join, dirname
+import os
+import sys
+
+from numpy.testing import NumpyTestCase, assert_array_equal, NumpyTest, \
+        assert_array_almost_equal, set_package_path, restore_path, set_local_path
+import numpy as N
+
+set_package_path()
+from audiolab import pysndfile
+from audiolab.pysndfile import sndfile, formatinfo as audio_format
+restore_path()
+
+set_local_path()
+from testcommon import open_tmp_file, close_tmp_file
+restore_path()
+
+# XXX: there is a lot to refactor here
+class test_pysndfile(NumpyTestCase):
+    def test_basic_io(self):
+        """ Check open, close and basic read/write"""
+        # dirty !
+        ofilename = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+        rfd, fd, cfilename = open_tmp_file('pysndfiletest.wav')
+        try:
+            nbuff = 22050
+
+            # Open the test file for reading
+            a       = sndfile(ofilename, 'read')
+            nframes = a.get_nframes()
+
+            # Open the copy file for writing
+            format  = audio_format('wav', 'pcm16')
+            b = sndfile(fd, 'write', format, a.get_channels(),
+                    a.get_samplerate())
+
+            # Copy the data
+            for i in range(nframes / nbuff):
+                tmpa    = a.read_frames(nbuff)
+                assert tmpa.dtype == N.float
+                b.write_frames(tmpa, nbuff)
+            nrem    = nframes % nbuff
+            tmpa    = a.read_frames(nrem)
+            assert tmpa.dtype == N.float
+            b.write_frames(tmpa, nrem)
+
+            a.close()
+            b.close()
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+
+    def test_basic_io_fd(self):
+        """ Check open from fd works"""
+        # dirty !
+        if sys.platform == 'win32':
+            print "Not testing opening by fd because does not work on win32"
+        else:
+            ofilename = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+            fd = os.open(ofilename, os.O_RDONLY)
+            hdl = sndfile(fd, 'read')
+            hdl.close()
+
+    def test_raw(self):
+        rawname = join(dirname(pysndfile.__file__), 'test_data', 'test.raw')
+        format  = audio_format('raw', 'pcm16', 'little')
+        a       = sndfile(rawname, 'read', format, 1, 11025)
+        assert a.get_nframes() == 11290
+        a.close()
+
+    def test_float64(self):
+        """Check float64 write/read works"""
+        # dirty !
+        ofilename = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+        rfd, fd, cfilename   = open_tmp_file('pysndfiletest.wav')
+        try:
+            nbuff           = 22050
+
+            # Open the test file for reading
+            a       = sndfile(ofilename, 'read')
+            nframes = a.get_nframes()
+
+            # Open the copy file for writing
+            format  = audio_format('wav', 'float64')
+            b       = sndfile(fd, 'write', format, a.get_channels(), 
+                    a.get_samplerate())
+
+            # Copy the data in the wav file
+            for i in range(nframes / nbuff):
+                tmpa    = a.read_frames(nbuff, dtype = N.float64)
+                assert tmpa.dtype == N.float64
+                b.write_frames(tmpa, nbuff)
+            nrem    = nframes % nbuff
+            tmpa    = a.read_frames(nrem)
+            b.write_frames(tmpa, nrem)
+
+            a.close()
+            b.close()
+
+            # Now, reopen both files in for reading, and check data are
+            # the same
+            a       = sndfile(ofilename, 'read')
+            b       = sndfile(cfilename, 'read')
+            for i in range(nframes / nbuff):
+                tmpa    = a.read_frames(nbuff, dtype = N.float64)
+                tmpb    = b.read_frames(nbuff, dtype = N.float64)
+                assert_array_equal(tmpa, tmpb)
+            
+            a.close()
+            b.close()
+
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_float32(self):
+        """Check float write/read works"""
+        # dirty !
+        ofilename = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+        rfd, fd, cfilename = open_tmp_file('pysndfiletest.wav')
+        try:
+            nbuff           = 22050
+
+            # Open the test file for reading
+            a       = sndfile(ofilename, 'read')
+            nframes = a.get_nframes()
+
+            # Open the copy file for writing
+            format  = audio_format('wav', 'float32')
+            b       = sndfile(fd, 'write', format, a.get_channels(), 
+                    a.get_samplerate())
+
+            # Copy the data in the wav file
+            for i in range(nframes / nbuff):
+                tmpa    = a.read_frames(nbuff, dtype = N.float32)
+                assert tmpa.dtype == N.float32
+                b.write_frames(tmpa, nbuff)
+            nrem    = nframes % nbuff
+            tmpa    = a.read_frames(nrem)
+            b.write_frames(tmpa, nrem)
+
+            a.close()
+            b.close()
+
+            # Now, reopen both files in for reading, and check data are
+            # the same
+            a       = sndfile(ofilename, 'read')
+            b       = sndfile(cfilename, 'read')
+            for i in range(nframes / nbuff):
+                tmpa    = a.read_frames(nbuff, dtype = N.float32)
+                tmpb    = b.read_frames(nbuff, dtype = N.float32)
+                assert_array_equal(tmpa, tmpb)
+            
+            a.close()
+            b.close()
+
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_supported_features(self):
+        msg = "\nsupported file format are : this test is broken FIXME"
+        #for i in pysndfile.supported_format():
+        #    msg += str(i) + ', '
+        #print msg
+        #msg = "supported encoding format are : "
+        #for i in pysndfile.supported_encoding():
+        #    msg += str(i) + ', '
+        #print msg
+        #msg = "supported endianness are : "
+        #for i in pysndfile.supported_endianness():
+        #    msg += str(i) + ', '
+        print msg
+
+    def test_short_io(self):
+        # TODO: check if neg or pos value is the highest in abs
+        rfd, fd, cfilename   = open_tmp_file('pysndfiletest.wav')
+        try:
+            nb      = 2 ** 14
+            nbuff   = 22050
+            fs      = 22050
+            a       = N.random.random_integers(-nb, nb, nbuff)
+            a       = a.astype(N.short)
+
+            # Open the file for writing
+            format  = audio_format('wav', 'pcm16')
+            b       = sndfile(fd, 'write', format, 1, fs)
+
+            b.write_frames(a, nbuff)
+            b.close()
+
+            b       = sndfile(cfilename, 'read')
+
+            read_a  = b.read_frames(nbuff, dtype = N.short)
+            b.close()
+
+            assert_array_equal(a, read_a)
+            
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_int_io(self):
+        # TODO: check if neg or pos value is the highest in abs
+        rfd, fd, cfilename   = open_tmp_file('pysndfiletest.wav')
+        try:
+            nb      = 2 ** 25
+            nbuff   = 22050
+            fs      = 22050
+            a       = N.random.random_integers(-nb, nb, nbuff)
+            a       = a.astype(N.int32)
+
+            # Open the file for writing
+            format  = audio_format('wav', 'pcm32')
+            b       = sndfile(fd, 'write', format, 1, fs)
+
+            b.write_frames(a, nbuff)
+            b.close()
+
+            b       = sndfile(cfilename, 'read')
+
+            read_a  = b.read_frames(nbuff, dtype = N.int32)
+            b.close()
+
+            assert_array_equal(a, read_a)
+            
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_mismatch(self):
+        # This test open a file for writing, but with bad args (channels and
+        # nframes inverted) 
+        rfd, fd, cfilename = open_tmp_file('pysndfiletest.wav')
+        try:
+            # Open the file for writing
+            format  = audio_format('wav', 'pcm16')
+            try:
+                b = sndfile(fd, 'write', \
+                        format, channels = 22000, samplerate = 1)
+                raise Exception("Try to open a file with more than 256 "\
+                        "channels, this should not succeed !")
+            except RuntimeError, e:
+                #print "Gave %d channels, error detected is \"%s\"" % (22000, e)
+                pass
+
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_bigframes(self):
+        """ Try to seek really far"""
+        rawname = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+        a       = sndfile(rawname, 'read')
+        try:
+            try:
+                a.seek(2 ** 60)
+                raise Exception("Seek really succeded ! This should not happen")
+            except pysndfile.PyaudioIOError, e:
+                pass
+        finally:
+            a.close()
+
+    def test_float_frames(self):
+        """ Check nframes can be a float"""
+        rfd, fd, cfilename   = open_tmp_file('pysndfiletest.wav')
+        try:
+            # Open the file for writing
+            format = audio_format('wav', 'pcm16')
+            a = sndfile(fd, 'rwrite', format, channels = 1, 
+                    samplerate = 22050)
+            tmp = N.random.random_integers(-100, 100, 1000)
+            tmp = tmp.astype(N.short)
+            a.write_frames(tmp, tmp.size)
+            a.seek(0)
+            a.sync()
+            ctmp    = a.read_frames(1e2, dtype = N.short)
+            a.close()
+
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+    def test_nofile(self):
+        """ Check the failure when opening a non existing file."""
+        try:
+            f = sndfile("floupi.wav", "read")
+            raise AssertionError("call to non existing file should not succeed")
+        except IOError:
+            pass
+        except Exception, e:
+            raise AssertionError("opening non existing file should raise a IOError exception, got %s instead" % e.__class__)
+
+class test_seek(NumpyTestCase):
+    def test_simple(self):
+        ofilename = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+        # Open the test file for reading
+        a       = sndfile(ofilename, 'read')
+        nframes = a.get_nframes()
+
+        buffsize    = 1024
+        buffsize    = min(nframes, buffsize)
+
+        # First, read some frames, go back, and compare buffers
+        buff    = a.read_frames(buffsize)
+        a.seek(0)
+        buff2   = a.read_frames(buffsize)
+        assert_array_equal(buff, buff2)
+
+        a.close()
+
+        # Now, read some frames, go back, and compare buffers
+        # (check whence == 1 == SEEK_CUR)
+        a       = sndfile(ofilename, 'read')
+        a.read_frames(buffsize)
+        buff    = a.read_frames(buffsize)
+        a.seek(-buffsize, 1)
+        buff2   = a.read_frames(buffsize)
+        assert_array_equal(buff, buff2)
+
+        a.close()
+
+        # Now, read some frames, go back, and compare buffers
+        # (check whence == 2 == SEEK_END)
+        a       = sndfile(ofilename, 'read')
+        buff    = a.read_frames(nframes)
+        a.seek(-buffsize, 2)
+        buff2   = a.read_frames(buffsize)
+        assert_array_equal(buff[-buffsize:], buff2)
+
+    def test_rw(self):
+        """Test read/write pointers for seek."""
+        ofilename = join(dirname(pysndfile.__file__), 'test_data', 'test.wav')
+        rfd, fd, cfilename   = open_tmp_file('rwseektest.wav')
+        try:
+            ref = sndfile(ofilename, 'read')
+            test = sndfile(fd, 'rwrite', format = ref._format, channels =
+                    ref.get_channels(), samplerate = ref.get_samplerate())
+            n = 1024
+
+            rbuff = ref.read_frames(n, dtype = N.int16)
+            test.write_frames(rbuff)
+            tbuff = test.read_frames(n, dtype = N.int16)
+
+            assert_array_equal(rbuff, tbuff)
+
+            # Test seeking both read and write pointers
+            test.seek(0, 0)
+            test.write_frames(rbuff)
+            tbuff = test.read_frames(n, dtype = N.int16)
+            assert_array_equal(rbuff, tbuff)
+
+            # Test seeking only read pointer
+            rbuff1 = rbuff.copy()
+            rbuff2 = rbuff1 * 2 + 1
+            rbuff2.clip(-30000, 30000)
+            test.seek(0, 0, 'r')
+            test.write_frames(rbuff2)
+            tbuff1 = test.read_frames(n, dtype = N.int16)
+            try:
+                tbuff2 = test.read_frames(n, dtype = N.int16)
+            except IOError, e:
+                msg = "write pointer was updated in read seek !"
+                msg += "\n(msg is %s)" % e
+                raise AssertionError(msg) 
+
+            assert_array_equal(rbuff1, tbuff1)
+            assert_array_equal(rbuff2, tbuff2)
+            if N.all(rbuff2 == tbuff1):
+                raise AssertionError("write pointer was updated"\
+                        " in read seek !") 
+
+            # Test seeking only write pointer
+            rbuff3 = rbuff1 * 2 - 1
+            rbuff3.clip(-30000, 30000)
+            test.seek(0, 0, 'rw')
+            test.seek(n, 0, 'w')
+            test.write_frames(rbuff3)
+            tbuff1 = test.read_frames(n, N.int16)
+            try:
+                assert_array_equal(tbuff1, rbuff1)
+            except AssertionError:
+                raise AssertionError("read pointer was updated in write seek !")
+
+            try:
+                tbuff3 = test.read_frames(n, N.int16)
+            except IOError, e:
+                msg = "read pointer was updated in write seek !"
+                msg += "\n(msg is %s)" % e
+                raise AssertionError(msg) 
+
+            assert_array_equal(tbuff3, rbuff3)
+            test.close()
+
+        finally:
+            close_tmp_file(rfd, cfilename)
+
+if __name__ == "__main__":
+    NumpyTest().run()
diff --git a/telemeta/util/audiolab/scikits/audiolab/tests/testcommon.py b/telemeta/util/audiolab/scikits/audiolab/tests/testcommon.py
new file mode 100644 (file)
index 0000000..dd8c4a4
--- /dev/null
@@ -0,0 +1,20 @@
+import os
+from tempfile import mkstemp
+import sys
+
+def open_tmp_file(name):
+    """On any sane platforms, return a fd on a tmp file. On windows, returns
+    the filename, and as such, is not secure (someone else can reopen the file
+    in between)."""
+    fd, cfilename = mkstemp('pysndfiletest.wav')
+    if sys.platform == 'win32':
+        return fd, cfilename, cfilename
+    else:
+        return fd, fd, cfilename
+
+def close_tmp_file(fd, filename):
+    """On any sane platforms, remove the file . On windows, only close the
+    file."""
+    os.close(fd)
+    os.remove(filename)
+    
diff --git a/telemeta/util/audiolab/setup.cfg b/telemeta/util/audiolab/setup.cfg
new file mode 100644 (file)
index 0000000..7b3b6f1
--- /dev/null
@@ -0,0 +1,4 @@
+[egg_info]
+#tag_svn_revision = 1
+tag_build = .dev
+
diff --git a/telemeta/util/audiolab/setup.py b/telemeta/util/audiolab/setup.py
new file mode 100644 (file)
index 0000000..0963848
--- /dev/null
@@ -0,0 +1,222 @@
+#! /usr/bin/env python
+# Last Change: Tue Jul 29 12:00 PM 2008 J
+
+# Copyright (C) 2006-2007 Cournapeau David <cournape@gmail.com>
+#
+# 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.1 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., 51
+# Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+# TODO:
+#   - check how to handle cmd line build options with distutils and use
+#   it in the building process
+
+descr   = """ audiolab is a small python package to import data from audio
+files to numpy arrays and export data from numpy arrays to audio files. It uses
+libsndfile from Erik Castro de Lopo for the underlying IO, which supports many
+different audio formats: http://www.mega-nerd.com/libsndfile/
+
+For now, the python api for audio IO should be stable; a matlab-like API is
+also available for quick read/write (ala wavread, wavwrite, etc...). For 1.0
+release, I hope to add support for simple read/write to soundcard, to be able
+to record and listen to data in numpy arrays.
+
+2006-2007, David Cournapeau
+
+LICENSE: audiolab is licensed under the LGPL, as is libsndfile itself. See
+COPYING.txt for details.  """
+
+from os.path import join
+import os
+import sys
+
+DISTNAME            = 'scikits.audiolab'
+DESCRIPTION         = 'A python module to make noise from numpy arrays'
+LONG_DESCRIPTION    = descr
+MAINTAINER          = 'David Cournapeau',
+MAINTAINER_EMAIL    = 'david@ar.media.kyoto-u.ac.jp',
+URL                 = 'http://www.ar.media.kyoto-u.ac.jp/members/david/softwares/audiolab',
+LICENSE             = 'LGPL'
+DOWNLOAD_URL        = URL
+
+SNDFILE_MAJ_VERSION = 1
+
+# The following is more or less random copy/paste from numpy.distutils ...
+import setuptools
+from distutils.errors import DistutilsError
+from numpy.distutils.system_info import system_info, NotFoundError, dict_append, so_ext
+from numpy.distutils.core import setup, Extension
+
+class SndfileNotFoundError(NotFoundError):
+    """ sndfile (http://www.mega-nerd.com/libsndfile/) library not found.
+    Directories to search for the libraries can be specified in the
+    site.cfg file (section [sndfile])."""
+
+class sndfile_info(system_info):
+    #variables to override
+    section         = 'sndfile'
+    notfounderror   = SndfileNotFoundError
+    libname         = 'sndfile'
+    header          = 'sndfile.h'
+
+    def __init__(self):
+        system_info.__init__(self)
+
+    def library_extensions(self):
+        # We rewrite library_extension
+        exts = system_info.library_extensions(self)
+        if sys.platform == 'win32':
+            exts.insert(0, '.dll')
+        return exts
+
+    def calc_info(self):
+        """ Compute the informations of the library """
+        prefix  = 'lib'
+
+        # Look for the shared library
+        sndfile_libs    = self.get_libs('sndfile_libs', self.libname)
+        lib_dirs        = self.get_lib_dirs()
+        tmp             = None
+        for i in lib_dirs:
+            tmp = self.check_libs(i, sndfile_libs)
+            if tmp is not None:
+                info    = tmp
+                break
+        if tmp is None:
+            raise SndfileNotFoundError("sndfile library not found")
+
+        # Look for the header file
+        include_dirs    = self.get_include_dirs()
+        inc_dir         = None
+        for d in include_dirs:
+            p = self.combine_paths(d,self.header)
+            if p:
+                inc_dir     = os.path.dirname(p[0])
+                headername  = os.path.abspath(p[0])
+                break
+
+        if inc_dir is None:
+            raise SndfileNotFoundError("header not found")
+
+        if inc_dir is not None and tmp is not None:
+            if sys.platform == 'win32':
+                # win32 case
+                fullname    = prefix + tmp['libraries'][0] + \
+                        '.dll'
+            elif sys.platform == 'darwin':
+                # Mac Os X case
+                fullname    = prefix + tmp['libraries'][0] + '.' + \
+                        str(SNDFILE_MAJ_VERSION) + '.dylib'
+            else:
+                # All others (Linux for sure; what about solaris) ?
+                fullname    = prefix + tmp['libraries'][0] + '.so' + \
+                        '.' + str(SNDFILE_MAJ_VERSION)
+            fullname    = os.path.join(info['library_dirs'][0], fullname)
+            dict_append(info, include_dirs=[inc_dir],
+                    fullheadloc = headername,
+                    fulllibloc  = fullname)
+        else:
+            raise RuntimeError("This is a bug")
+
+        #print self
+        self.set_info(**info)
+        return
+
+from header_parser import do_subst_in_file
+def configuration(parent_package='',top_path=None, package_name=DISTNAME):
+    if os.path.exists('MANIFEST'): os.remove('MANIFEST')
+    if os.path.exists('scikits/audiolab/pysndfile.py'): os.remove('scikits/audiolab/pysndfile.py')
+
+    pkg_prefix_dir = os.path.join('scikits', 'audiolab')
+    # Check that sndfile can be found and get necessary informations
+    # (assume only one header and one library file)
+    sf_info     = sndfile_info()
+    sf_config   = sf_info.get_info(2)
+    headername  = sf_config['fullheadloc']
+    libname     = sf_config['fulllibloc']
+
+    # Now, generate pysndfile.py.in
+    from generate_const import generate_enum_dicts
+    repdict = generate_enum_dicts(headername)
+    repdict['%SHARED_LOCATION%'] = libname
+    #do_subst_in_file('pysndfile.py.in', 'pysndfile.py', repdict)
+    do_subst_in_file(os.path.join(pkg_prefix_dir, 'pysndfile.py.in'),
+            os.path.join(pkg_prefix_dir, 'pysndfile.py'),
+            repdict)
+
+    # Get the version
+    from scikits.audiolab.info import VERSION as audiolab_version
+
+    from numpy.distutils.misc_util import Configuration
+    config = Configuration(package_name,parent_package,top_path,
+        version     = audiolab_version,
+        maintainer  = MAINTAINER,
+        maintainer_email = MAINTAINER_EMAIL,
+        description = DESCRIPTION,
+        license = LICENSE,
+        url = URL,
+        download_url = DOWNLOAD_URL,
+        long_description = LONG_DESCRIPTION)
+
+    # XXX: once in SVN, should add svn version...
+    #print config.make_svn_version_py()
+
+    # package_data does not work with sdist for setuptools 0.5 (setuptools bug),
+    # so we need to add them here while the bug is not solved...
+    config.add_data_files(('docs', \
+            ['scikits/audiolab/docs/' + i for i in DOC_FILES]))
+
+    config.add_data_files(('test_data', \
+            ['scikits/audiolab/test_data/' + i
+                for i in TEST_DATA_FILES]))
+
+    config.add_data_files(('misc', \
+            ['scikits/audiolab/misc/' + i
+                for i in BAD_FLAC_FILES]))
+
+    config.add_data_dir(('examples', 'scikits/audiolab/docs/examples'))
+
+    return config
+
+TEST_DATA_FILES = ['test.raw', 'test.flac', 'test.wav', 'test.au',
+        'test.sdif']
+DOC_FILES = ['audiolab.pdf', 'index.txt']
+BAD_FLAC_FILES = ['Makefile', 'badflac.flac', 'badflac.c']
+
+if __name__ == "__main__":
+    # setuptools version of config script
+
+    # package_data does not work with sdist for setuptools 0.5 (setuptools bug)
+    # So we cannot add data files via setuptools yet.
+
+    #data_files = ['test_data/' + i for i in TEST_DATA_FILES]
+    #data_files.extend(['docs/' + i for i in doc_files])
+
+    setup(configuration = configuration,
+        install_requires='numpy', # can also add version specifiers
+        namespace_packages=['scikits'],
+        packages=setuptools.find_packages(),
+        include_package_data = True,
+        #package_data = {'scikits.audiolab': data_files},
+        test_suite="tester", # for python setup.py test
+        zip_safe=True, # the package can run out of an .egg file
+        #FIXME url, download_url, ext_modules
+        classifiers =
+            [ 'Development Status :: 4 - Beta',
+              'Environment :: Console',
+              'Intended Audience :: Developers',
+              'Intended Audience :: Science/Research',
+              'License :: OSI Approved :: LGPL License',
+              'Topic :: Multimedia :: Sound/Audio',
+              'Topic :: Scientific/Engineering']
+    )
diff --git a/telemeta/util/audiolab/site.cfg.win32 b/telemeta/util/audiolab/site.cfg.win32
new file mode 100644 (file)
index 0000000..f9bdd91
--- /dev/null
@@ -0,0 +1,5 @@
+# Check Win32 info for using audiolab on windows
+[sndfile]
+include_dirs = c:\local\include
+library_dirs = c:\local\lib
+sndfile_libs = sndfile-1
diff --git a/telemeta/util/audiolab/site.cfg_noflac b/telemeta/util/audiolab/site.cfg_noflac
new file mode 100644 (file)
index 0000000..66adc49
--- /dev/null
@@ -0,0 +1,8 @@
+[sndfile]
+include_dirs = /usr/media/boulot/src/sigtools/pyaudio/local/include
+library_dirs = /usr/media/boulot/src/sigtools/pyaudio/local/lib
+sndfile_libs = sndfile
+#include_dirs = /home/david/local/include
+#library_dirs = /home/david/local/lib
+#libraries = sndfile
+
diff --git a/telemeta/util/audiolab/tester.py b/telemeta/util/audiolab/tester.py
new file mode 100644 (file)
index 0000000..e0f2262
--- /dev/null
@@ -0,0 +1,13 @@
+#! /usr/bin/env python
+# Last Change: Sat Jul 21 03:00 PM 2007 J
+
+"""Mini script useful for top level testing of the learn package."""
+
+from numpy.testing import NumpyTest
+
+def additional_tests():
+    # XXX: does this guarantee that the package is the one in the dev trunk, and
+    # not scikits.foo installed somewhere else ?
+    import scikits.audiolab
+    np = NumpyTest(scikits.audiolab)
+    return np._test_suite_from_all_tests(np.package, level = 10, verbosity = 1)
index 0664dc474a7d77517bdda8ccaaaf394dd905389f..cb8f44753c2e3e9482d7bda1d9821903de713bd3 100644 (file)
@@ -47,8 +47,6 @@ class OctaveCoreVisualizer(Component):
         mFile_tmp = open(mFile_name,'w')
         self.pngFile = NamedTemporaryFile(suffix='.png')
         command = ['octave', mFile_name]
-        print command
-        print self.pngFile.name
 
         for line in self.get_mFile_line():
             mFile_tmp.write(line)
@@ -71,6 +69,6 @@ class OctaveCoreVisualizer(Component):
 
         self.ppmFile.close()
         self.pngFile.close()
-        #os.remove(mFile_name)
+        os.remove(mFile_name)
         
         
index fa990c71cb12283751d216158a5f3808583c7de6..0930f502e05b65e36019df1668844b613e9dddf2 100644 (file)
@@ -18,9 +18,6 @@ class SpectrogramVisualizer3(Component):
 
     implements(IMediaItemVisualizer)
 
-    def __init__(self):
-        pass
-    
     def get_id(self):
         return "spectrogram3"
 
index bc6eaf562209edaec6da1fdbc40896e5b61345f6..4d2e806c0802407b6d15a59e4c4bca299265e384 100644 (file)
@@ -18,9 +18,6 @@ class WaveFormVisualizer(Component):
 
     implements(IMediaItemVisualizer)
 
-    def __init__(self):
-        pass
-    
     def get_id(self):
         return "waveform3"
 
@@ -47,5 +44,3 @@ class WaveFormVisualizer(Component):
         pngFile_w.close()
         pngFile_s.close()
 
-
-
index af14cd8fd265a171b050d530f62af904ddfb2e51..9f332ef11220abdd49ed5613c152b97bd2c66fc1 100644 (file)
@@ -47,12 +47,12 @@ class WebView(Component):
             formats.append({'name': exporter.get_format(), 'extension': exporter.get_file_extension()})
         visualizers = []
         for visualizer in self.visualizers:
-            visualizers.append({'name':visualizer.get_name(), 'id': 
+            visualizers.append({'name':visualizer.get_name(), 'id':
                 visualizer.get_id()})
         if request.REQUEST.has_key('visualizer_id'):
             visualizer_id = request.REQUEST['visualizer_id']
         else:
-            visualizer_id = 'waveform'
+            visualizer_id = 'waveform3'
 
         return render_to_response(template, 
                     {'item': item, 'export_formats': formats, 
@@ -302,10 +302,3 @@ class WebView(Component):
             template_name='geo_country_collections.html', paginate_by=20,
             extra_context={'country': country, 'continent': continent})
 
-        
-
-        
-    
-    
-
-