Added libsndfile

This commit is contained in:
Sergii Pylypenko
2013-03-20 15:53:45 +02:00
parent 08e24c12c0
commit 121a3ae133
110 changed files with 57569 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
The main author of libsndfile is Erik de Castro Lopo <erikd@mega-nerd.com>
apart from code in the following directories:
- src/GSM610 : Written by Jutta Degener <jutta@cs.tu-berlin.de> and Carsten
Bormann <cabo@cs.tu-berlin.de>. They should not be contacted in relation to
libsndfile or the GSM 6.10 code that is part of libsndfile. Their original
code can be found at:
http://kbs.cs.tu-berlin.de/~jutta/toast.html
- src/G72x : Released by Sun Microsystems, Inc. to the public domain. Minor
modifications were required to integrate these files into libsndfile. The
changes are listed in src/G72x/ChangeLog.

View File

@@ -0,0 +1,22 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := sndfile
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/src $(LOCAL_PATH)/../ogg/include $(LOCAL_PATH)/../vorbis/include $(LOCAL_PATH)/../flac/include
LOCAL_CFLAGS := -DHAVE_CONFIG_H
LOCAL_CPP_EXTENSION := .cpp
APP_SUBDIRS := $(patsubst $(LOCAL_PATH)/%, %, $(shell find $(LOCAL_PATH)/src -type d))
LOCAL_SRC_FILES := $(foreach F, $(APP_SUBDIRS), $(addprefix $(F)/,$(notdir $(wildcard $(LOCAL_PATH)/$(F)/*.cpp))))
LOCAL_SRC_FILES += $(foreach F, $(APP_SUBDIRS), $(addprefix $(F)/,$(notdir $(wildcard $(LOCAL_PATH)/$(F)/*.c))))
LOCAL_STATIC_LIBRARIES := flac vorbis ogg
LOCAL_SHARED_LIBRARIES :=
LOCAL_LDLIBS :=
include $(BUILD_SHARED_LIBRARY)

503
project/jni/sndfile/COPYING Normal file
View File

@@ -0,0 +1,503 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
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.
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.
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.
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.
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.
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.
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.
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
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

File diff suppressed because it is too large Load Diff

182
project/jni/sndfile/INSTALL Normal file
View File

@@ -0,0 +1,182 @@
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.
The file `configure.in' is used to create `configure' by a program
called `autoconf'. You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. You can give `configure'
initial values for variables by setting them in the environment. Using
a Bourne-compatible shell, you can do that on the command line like
this:
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not supports the `VPATH'
variable, you have to compile the package for one architecture at a time
in the source code directory. After you have installed the package for
one architecture, use `make distclean' before reconfiguring for another
architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' can not figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it can not guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.
If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
produce code for and the `--build=TYPE' option to select the type of
system on which you are compiling the package.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.

175
project/jni/sndfile/NEWS Normal file
View File

@@ -0,0 +1,175 @@
Version 1.0.25 (2011-07-13)
* Fix for Secunia Advisory SA45125, heap overflow in PAF file handler.
* Accept broken WAV files with blockalign == 0.
* Minor bug fixes and improvements.
Version 1.0.24 (2011-03-23)
* WAV files now have an 18 byte u-law and A-law fmt chunk.
* Document virtual I/O functionality.
* Two new methods rawHandle() and takeOwnership() in sndfile.hh.
* AIFF fix for non-zero offset value in SSND chunk.
* Minor bug fixes and improvements.
Version 1.0.23 (2010-10-10)
* Add version metadata to Windows DLL.
* Add a missing 'inline' to sndfile.hh.
* Update docs.
* Minor bug fixes and improvements.
Version 1.0.22 (2010-10-04)
* Couple of fixes for SDS file writer.
* Fixes arising from static analysis.
* Handle FLAC files with ID3 meta data at start of file.
* Handle FLAC files which report zero length.
* Other minor bug fixes and improvements.
Version 1.0.21 (2009-12-13)
* Add a couple of new binary programs to programs/ dir.
* Remove sndfile-jackplay (now in sndfile-tools package).
* Add windows only function sf_wchar_open().
* Bunch of minor bug fixes.
Version 1.0.20 (2009-05-14)
* Fix potential heap overflow in VOC file parser (Tobias Klein, http://www.trapkit.de/).
Version 1.0.19 (2009-03-02)
* Fix for CVE-2009-0186 (Alin Rad Pop, Secunia Research).
* Huge number of minor bug fixes as a result of static analysis.
Version 1.0.18 (2009-02-07)
* Add Ogg/Vorbis support (thanks to John ffitch).
* Remove captive FLAC library.
* Many new features and bug fixes.
* Generate Win32 and Win64 pre-compiled binaries.
Version 1.0.17 (2006-08-31)
* Add sndfile.hh C++ wrapper.
* Update Win32 MinGW build instructions.
* Minor bug fixes and cleanups.
Version 1.0.16 (2006-04-30)
* Add support for Broadcast (BEXT) chunks in WAV files.
* Implement new commands SFC_GET_SIGNAL_MAX and SFC_GET_MAX_ALL_CHANNELS.
* Add support for RIFX (big endian WAV variant).
* Fix configure script bugs.
* Fix bug in INST and MARK chunk writing for AIFF files.
Version 1.0.15 (2006-03-16)
* Fix some ia64 issues.
* Fix precompiled DLL.
* Minor bug fixes.
Version 1.0.14 (2006-02-19)
* Really fix MinGW compile problems.
* Minor bug fixes.
Version 1.0.13 (2006-01-21)
* Fix for MinGW compiler problems.
* Allow readin/write of instrument chunks from WAV and AIFF files.
* Compile problem fix for Solaris compiler.
* Minor cleanups and bug fixes.
Version 1.0.12 (2005-09-30)
* Add support for FLAC and Apple's Core Audio Format (CAF).
* Add virtual I/O interface (still needs docs).
* Cygwin and other Win32 fixes.
* Minor bug fixes and cleanups.
Version 1.0.11 (2004-11-15)
* Add support for SD2 files.
* Add read support for loop info in WAV and AIFF files.
* Add more tests.
* Improve type safety.
* Minor optimisations and bug fixes.
Version 1.0.10 (2004-06-15)
* Fix AIFF read/write mode bugs.
* Add support for compiling Win32 DLLS using MinGW.
* Fix problems resulting in failed compiles with gcc-2.95.
* Improve test suite.
* Minor bug fixes.
Version 1.0.9 (2004-03-30)
* Add handling of AVR (Audio Visual Research) files.
* Improve handling of WAVEFORMATEXTENSIBLE WAV files.
* Fix for using pipes on Win32.
Version 1.0.8 (2004-03-14)
* Correct peak chunk handing for files with > 16 tracks.
* Fix for WAV files with huge number of CUE chunks.
Version 1.0.7 (2004-02-25)
* Fix clip mode detection on ia64, MIPS and other CPUs.
* Fix two MacOSX build problems.
Version 1.0.6 (2004-02-08)
* Added support for native Win32 file access API (Ross Bencina).
* New mode to add clippling then a converting from float/double to integer
would otherwise wrap around.
* Fixed a bug in reading/writing files > 2Gig on Linux, Solaris and others.
* Many minor bug fixes.
* Other random fixes for Win32.
Version 1.0.5 (2003-05-03)
* Added support for HTK files.
* Added new function sf_open_fd() to allow for secure opening of temporary
files as well as reading/writing sound files embedded within larger
container files.
* Added string support for AIFF files.
* Minor bug fixes and code cleanups.
Version 1.0.4 (2003-02-02)
* Added suport of PVF and XI files.
* Added functionality for setting and retreiving strings from sound files.
* Minor code cleanups and bug fixes.
Version 1.0.3 (2002-12-09)
* Minor bug fixes.
Version 1.0.2 (2002-11-24)
* Added support for VOX ADPCM.
* Improved error reporting.
* Added version scripting on Linux and Solaris.
* Minor bug fixes.
Version 1.0.1 (2002-09-14)
* Added MAT and MAT5 file formats.
* Minor bug fixes.
Version 1.0.0 (2002-08-16)
* Final release for 1.0.0.
Version 1.0.0rc6 (2002-08-14)
* Release candidate 6 for the 1.0.0 series.
* MacOS9 fixes.
Version 1.0.0rc5 (2002-08-10)
* Release candidate 5 for the 1.0.0 series.
* Changed the definition of sf_count_t which was causing problems when
libsndfile was compiled with other libraries (ie WxWindows).
* Minor bug fixes.
* Documentation cleanup.
Version 1.0.0rc4 (2002-08-03)
* Release candidate 4 for the 1.0.0 series.
* Minor bug fixes.
* Fix broken Win32 "make check".
Version 1.0.0rc3 (2002-08-02)
* Release candidate 3 for the 1.0.0 series.
* Fix bug where libsndfile was reading beyond the end of the data chunk.
* Added on-the-fly header updates on write.
* Fix a couple of documentation issues.
Version 1.0.0rc2 (2002-06-24)
* Release candidate 2 for the 1.0.0 series.
* Fix compile problem for Win32.
Version 1.0.0rc1 (2002-06-24)
* Release candidate 1 for the 1.0.0 series.
Version 0.0.28 (2002-04-27)
* Last offical release of 0.0.X series of the library.
Version 0.0.8 (1999-02-16)
* First offical release.

View File

@@ -0,0 +1,65 @@
This is libsndfile, 1.0.25
libsndfile is a library of C routines for reading and writing
files containing sampled audio data.
The src/ directory contains the source code for library itself.
The doc/ directory contains the libsndfile documentation.
The examples/ directory contains examples of how to write code using
libsndfile.
The tests/ directory contains programs which link against libsndfile
and test its functionality.
The src/GSM610 directory contains code written by Jutta Degener and Carsten
Bormann. Their original code can be found at :
http://kbs.cs.tu-berlin.de/~jutta/toast.html
The src/G72x directory contains code written and released by Sun Microsystems
under a suitably free license.
LINUX
-----
Whereever possible, you should use the packages supplied by your Linux
distribution.
If you really do need to compile from source it should be as easy as:
./configure
make
make install
Since libsndfile optionally links against libFLAC, libogg and libvorbis, you
will need to install appropriate versions of these libraries before running
configure as above.
UNIX
----
Compile as for Linux.
Win32/Win64
-----------
The default Windows compilers are nowhere near compliant with the 1999 ISO
C Standard and hence not able to compile libsndfile.
Please use the libsndfile binaries available on the libsndfile web site.
MacOSX
------
Building on MacOSX should be the same as building it on any other Unix.
CONTACTS
--------
libsndfile was written by Erik de Castro Lopo (erikd AT mega-nerd DOT com).
The libsndfile home page is at :
http://www.mega-nerd.com/libsndfile/

View File

@@ -0,0 +1 @@
../src/sndfile.h

View File

@@ -0,0 +1 @@
../src/sndfile.hh

View File

@@ -0,0 +1,50 @@
2001-06-05 Erik de Castro Lopo <erikd@mega-nerd.com>
* g72x.c
Added {} in function update () to prevent 'ambiguous else' warning messages.
2000-07-14 Erik de Castro Lopo <erikd@mega-nerd.com>
* g72x.c
Modified g72x_init_state () to fit in with the new structure of the code.
Implemented g72x_encode_block () and g72x_decode_block ().
2000-07-12 Erik de Castro Lopo <erikd@mega-nerd.com>
* g72x.h
Moved nearly all definitions and function prototypes from this file have been
moved to private.h.
Added an enum defining the 4 different G72x ADPCM codecs.
Added new function prototypes to define a cleaner interface to the encoder
and decoder. This new interface also allows samples to be processed in blocks
rather than on a sample by sample basis like the original code.
* private.h
Added prototypes moved from g72x.h.
Changed struct g72x_state to a typedef struct { .. } G72x_PRIVATE.
Added fields to G72x_PRIVATE required for working on blocks of samples.
2000-06-07 Erik de Castro Lopo <erikd@mega-nerd.com>
* g72x.c
Fixed all compiler warnings.
Removed functions tandem_adjust() which is not required by libsndfile.
* g721.c
Fixed all compiler warnings.
Removed functions tandem_adjust_alaw() and tandem_adjust_ulaw () which are not
required by libsndfile.
Removed second parameter to g721_encoder () which is not required.
* g72x.h
Removed in_coding and out_coding parameters from all functions. These allowed
g72x encoding/decoding to/from A-law or u-law and are not required by libsndfile.
Removed unneeded defines for A-law, u-law and linear encoding.
* g723_16.c
Removed second parameter (in_coding) for g723_16_encoder().
Removed second parameter (out_coding) for g723_16_decoder().
* private.h
New file containing prototypes and tyepdefs private to G72x code.

View File

View File

@@ -0,0 +1,94 @@
The files in this directory comprise ANSI-C language reference implementations
of the CCITT (International Telegraph and Telephone Consultative Committee)
G.711, G.721 and G.723 voice compressions. They have been tested on Sun
SPARCstations and passed 82 out of 84 test vectors published by CCITT
(Dec. 20, 1988) for G.721 and G.723. [The two remaining test vectors,
which the G.721 decoder implementation for u-law samples did not pass,
may be in error because they are identical to two other vectors for G.723_40.]
This source code is released by Sun Microsystems, Inc. to the public domain.
Please give your acknowledgement in product literature if this code is used
in your product implementation.
Sun Microsystems supports some CCITT audio formats in Solaris 2.0 system
software. However, Sun's implementations have been optimized for higher
performance on SPARCstations.
The source files for CCITT conversion routines in this directory are:
g72x.h header file for g721.c, g723_24.c and g723_40.c
g711.c CCITT G.711 u-law and A-law compression
g72x.c common denominator of G.721 and G.723 ADPCM codes
g721.c CCITT G.721 32Kbps ADPCM coder (with g72x.c)
g723_24.c CCITT G.723 24Kbps ADPCM coder (with g72x.c)
g723_40.c CCITT G.723 40Kbps ADPCM coder (with g72x.c)
Simple conversions between u-law, A-law, and 16-bit linear PCM are invoked
as follows:
unsigned char ucode, acode;
short pcm_val;
ucode = linear2ulaw(pcm_val);
ucode = alaw2ulaw(acode);
acode = linear2alaw(pcm_val);
acode = ulaw2alaw(ucode);
pcm_val = ulaw2linear(ucode);
pcm_val = alaw2linear(acode);
The other CCITT compression routines are invoked as follows:
#include "g72x.h"
struct g72x_state state;
int sample, code;
g72x_init_state(&state);
code = {g721,g723_24,g723_40}_encoder(sample, coding, &state);
sample = {g721,g723_24,g723_40}_decoder(code, coding, &state);
where
coding = AUDIO_ENCODING_ULAW for 8-bit u-law samples
AUDIO_ENCODING_ALAW for 8-bit A-law samples
AUDIO_ENCODING_LINEAR for 16-bit linear PCM samples
This directory also includes the following sample programs:
encode.c CCITT ADPCM encoder
decode.c CCITT ADPCM decoder
Makefile makefile for the sample programs
The sample programs contain examples of how to call the various compression
routines and pack/unpack the bits. The sample programs read byte streams from
stdin and write to stdout. The input/output data is raw data (no file header
or other identifying information is embedded). The sample programs are
invoked as follows:
encode [-3|4|5] [-a|u|l] <infile >outfile
decode [-3|4|5] [-a|u|l] <infile >outfile
where:
-3 encode to (decode from) G.723 24kbps (3-bit) data
-4 encode to (decode from) G.721 32kbps (4-bit) data [the default]
-5 encode to (decode from) G.723 40kbps (5-bit) data
-a encode from (decode to) A-law data
-u encode from (decode to) u-law data [the default]
-l encode from (decode to) 16-bit linear data
Examples:
# Read 16-bit linear and output G.721
encode -4 -l <pcmfile >g721file
# Read 40Kbps G.723 and output A-law
decode -5 -a <g723file >alawfile
# Compress and then decompress u-law data using 24Kbps G.723
encode -3 <ulawin | deoced -3 >ulawout

View File

@@ -0,0 +1,155 @@
/*
* This source code is a product of Sun Microsystems, Inc. and is provided
* for unrestricted use. Users may copy or modify this source code without
* charge.
*
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun source code is provided with no support and without any obligation on
* the part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
/*
* g721.c
*
* Description:
*
* g721_encoder(), g721_decoder()
*
* These routines comprise an implementation of the CCITT G.721 ADPCM
* coding algorithm. Essentially, this implementation is identical to
* the bit level description except for a few deviations which
* take advantage of work station attributes, such as hardware 2's
* complement arithmetic and large memory. Specifically, certain time
* consuming operations such as multiplications are replaced
* with lookup tables and software 2's complement operations are
* replaced with hardware 2's complement.
*
* The deviation from the bit level specification (lookup tables)
* preserves the bit level performance specifications.
*
* As outlined in the G.721 Recommendation, the algorithm is broken
* down into modules. Each section of code below is preceded by
* the name of the module which it is implementing.
*
*/
#include "g72x.h"
#include "g72x_priv.h"
static short qtab_721[7] = {-124, 80, 178, 246, 300, 349, 400};
/*
* Maps G.721 code word to reconstructed scale factor normalized log
* magnitude values.
*/
static short _dqlntab[16] = {-2048, 4, 135, 213, 273, 323, 373, 425,
425, 373, 323, 273, 213, 135, 4, -2048};
/* Maps G.721 code word to log of scale factor multiplier. */
static short _witab[16] = {-12, 18, 41, 64, 112, 198, 355, 1122,
1122, 355, 198, 112, 64, 41, 18, -12};
/*
* Maps G.721 code words to a set of values whose long and short
* term averages are computed and then compared to give an indication
* how stationary (steady state) the signal is.
*/
static short _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00,
0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0};
/*
* g721_encoder()
*
* Encodes the input vale of linear PCM, A-law or u-law data sl and returns
* the resulting code. -1 is returned for unknown input coding value.
*/
int
g721_encoder(
int sl,
G72x_STATE *state_ptr)
{
short sezi, se, sez; /* ACCUM */
short d; /* SUBTA */
short sr; /* ADDB */
short y; /* MIX */
short dqsez; /* ADDC */
short dq, i;
/* linearize input sample to 14-bit PCM */
sl >>= 2; /* 14-bit dynamic range */
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
se = (sezi + predictor_pole(state_ptr)) >> 1; /* estimated signal */
d = sl - se; /* estimation difference */
/* quantize the prediction difference */
y = step_size(state_ptr); /* quantizer step size */
i = quantize(d, y, qtab_721, 7); /* i = ADPCM code */
dq = reconstruct(i & 8, _dqlntab[i], y); /* quantized est diff */
sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconst. signal */
dqsez = sr + sez - se; /* pole prediction diff. */
update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
return (i);
}
/*
* g721_decoder()
*
* Description:
*
* Decodes a 4-bit code of G.721 encoded data of i and
* returns the resulting linear PCM, A-law or u-law value.
* return -1 for unknown out_coding value.
*/
int
g721_decoder(
int i,
G72x_STATE *state_ptr)
{
short sezi, sei, sez, se; /* ACCUM */
short y; /* MIX */
short sr; /* ADDB */
short dq;
short dqsez;
i &= 0x0f; /* mask to get proper bits */
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
y = step_size(state_ptr); /* dynamic quantizer step size */
dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */
sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */
dqsez = sr - se + sez; /* pole prediction diff. */
update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
/* sr was 14-bit dynamic range */
return (sr << 2);
}

View File

@@ -0,0 +1,162 @@
/*
* This source code is a product of Sun Microsystems, Inc. and is provided
* for unrestricted use. Users may copy or modify this source code without
* charge.
*
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun source code is provided with no support and without any obligation on
* the part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
/* 16kbps version created, used 24kbps code and changing as little as possible.
* G.726 specs are available from ITU's gopher or WWW site (http://www.itu.ch)
* If any errors are found, please contact me at mrand@tamu.edu
* -Marc Randolph
*/
/*
* g723_16.c
*
* Description:
*
* g723_16_encoder(), g723_16_decoder()
*
* These routines comprise an implementation of the CCITT G.726 16 Kbps
* ADPCM coding algorithm. Essentially, this implementation is identical to
* the bit level description except for a few deviations which take advantage
* of workstation attributes, such as hardware 2's complement arithmetic.
*
*/
#include "g72x.h"
#include "g72x_priv.h"
/*
* Maps G.723_16 code word to reconstructed scale factor normalized log
* magnitude values. Comes from Table 11/G.726
*/
static short _dqlntab[4] = { 116, 365, 365, 116};
/* Maps G.723_16 code word to log of scale factor multiplier.
*
* _witab[4] is actually {-22 , 439, 439, -22}, but FILTD wants it
* as WI << 5 (multiplied by 32), so we'll do that here
*/
static short _witab[4] = {-704, 14048, 14048, -704};
/*
* Maps G.723_16 code words to a set of values whose long and short
* term averages are computed and then compared to give an indication
* how stationary (steady state) the signal is.
*/
/* Comes from FUNCTF */
static short _fitab[4] = {0, 0xE00, 0xE00, 0};
/* Comes from quantizer decision level tables (Table 7/G.726)
*/
static short qtab_723_16[1] = {261};
/*
* g723_16_encoder()
*
* Encodes a linear PCM, A-law or u-law input sample and returns its 2-bit code.
* Returns -1 if invalid input coding value.
*/
int
g723_16_encoder(
int sl,
G72x_STATE *state_ptr)
{
short sei, sezi, se, sez; /* ACCUM */
short d; /* SUBTA */
short y; /* MIX */
short sr; /* ADDB */
short dqsez; /* ADDC */
short dq, i;
/* linearize input sample to 14-bit PCM */
sl >>= 2; /* sl of 14-bit dynamic range */
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
d = sl - se; /* d = estimation diff. */
/* quantize prediction difference d */
y = step_size(state_ptr); /* quantizer step size */
i = quantize(d, y, qtab_723_16, 1); /* i = ADPCM code */
/* Since quantize() only produces a three level output
* (1, 2, or 3), we must create the fourth one on our own
*/
if (i == 3) /* i code for the zero region */
if ((d & 0x8000) == 0) /* If d > 0, i=3 isn't right... */
i = 0;
dq = reconstruct(i & 2, _dqlntab[i], y); /* quantized diff. */
sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconstructed signal */
dqsez = sr + sez - se; /* pole prediction diff. */
update(2, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
return (i);
}
/*
* g723_16_decoder()
*
* Decodes a 2-bit CCITT G.723_16 ADPCM code and returns
* the resulting 16-bit linear PCM, A-law or u-law sample value.
* -1 is returned if the output coding is unknown.
*/
int
g723_16_decoder(
int i,
G72x_STATE *state_ptr)
{
short sezi, sei, sez, se; /* ACCUM */
short y; /* MIX */
short sr; /* ADDB */
short dq;
short dqsez;
i &= 0x03; /* mask to get proper bits */
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
y = step_size(state_ptr); /* adaptive quantizer step size */
dq = reconstruct(i & 0x02, _dqlntab[i], y); /* unquantize pred diff */
sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); /* reconst. signal */
dqsez = sr - se + sez; /* pole prediction diff. */
update(2, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
/* sr was of 14-bit dynamic range */
return (sr << 2);
}

View File

@@ -0,0 +1,139 @@
/*
* This source code is a product of Sun Microsystems, Inc. and is provided
* for unrestricted use. Users may copy or modify this source code without
* charge.
*
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun source code is provided with no support and without any obligation on
* the part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
/*
* g723_24.c
*
* Description:
*
* g723_24_encoder(), g723_24_decoder()
*
* These routines comprise an implementation of the CCITT G.723 24 Kbps
* ADPCM coding algorithm. Essentially, this implementation is identical to
* the bit level description except for a few deviations which take advantage
* of workstation attributes, such as hardware 2's complement arithmetic.
*
*/
#include "g72x.h"
#include "g72x_priv.h"
/*
* Maps G.723_24 code word to reconstructed scale factor normalized log
* magnitude values.
*/
static short _dqlntab[8] = {-2048, 135, 273, 373, 373, 273, 135, -2048};
/* Maps G.723_24 code word to log of scale factor multiplier. */
static short _witab[8] = {-128, 960, 4384, 18624, 18624, 4384, 960, -128};
/*
* Maps G.723_24 code words to a set of values whose long and short
* term averages are computed and then compared to give an indication
* how stationary (steady state) the signal is.
*/
static short _fitab[8] = {0, 0x200, 0x400, 0xE00, 0xE00, 0x400, 0x200, 0};
static short qtab_723_24[3] = {8, 218, 331};
/*
* g723_24_encoder()
*
* Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code.
* Returns -1 if invalid input coding value.
*/
int
g723_24_encoder(
int sl,
G72x_STATE *state_ptr)
{
short sei, sezi, se, sez; /* ACCUM */
short d; /* SUBTA */
short y; /* MIX */
short sr; /* ADDB */
short dqsez; /* ADDC */
short dq, i;
/* linearize input sample to 14-bit PCM */
sl >>= 2; /* sl of 14-bit dynamic range */
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
d = sl - se; /* d = estimation diff. */
/* quantize prediction difference d */
y = step_size(state_ptr); /* quantizer step size */
i = quantize(d, y, qtab_723_24, 3); /* i = ADPCM code */
dq = reconstruct(i & 4, _dqlntab[i], y); /* quantized diff. */
sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconstructed signal */
dqsez = sr + sez - se; /* pole prediction diff. */
update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
return (i);
}
/*
* g723_24_decoder()
*
* Decodes a 3-bit CCITT G.723_24 ADPCM code and returns
* the resulting 16-bit linear PCM, A-law or u-law sample value.
* -1 is returned if the output coding is unknown.
*/
int
g723_24_decoder(
int i,
G72x_STATE *state_ptr)
{
short sezi, sei, sez, se; /* ACCUM */
short y; /* MIX */
short sr; /* ADDB */
short dq;
short dqsez;
i &= 0x07; /* mask to get proper bits */
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
y = step_size(state_ptr); /* adaptive quantizer step size */
dq = reconstruct(i & 0x04, _dqlntab[i], y); /* unquantize pred diff */
sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); /* reconst. signal */
dqsez = sr - se + sez; /* pole prediction diff. */
update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
return (sr << 2); /* sr was of 14-bit dynamic range */
}

View File

@@ -0,0 +1,153 @@
/*
* This source code is a product of Sun Microsystems, Inc. and is provided
* for unrestricted use. Users may copy or modify this source code without
* charge.
*
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun source code is provided with no support and without any obligation on
* the part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
/*
* g723_40.c
*
* Description:
*
* g723_40_encoder(), g723_40_decoder()
*
* These routines comprise an implementation of the CCITT G.723 40Kbps
* ADPCM coding algorithm. Essentially, this implementation is identical to
* the bit level description except for a few deviations which
* take advantage of workstation attributes, such as hardware 2's
* complement arithmetic.
*
* The deviation from the bit level specification (lookup tables),
* preserves the bit level performance specifications.
*
* As outlined in the G.723 Recommendation, the algorithm is broken
* down into modules. Each section of code below is preceded by
* the name of the module which it is implementing.
*
*/
#include "g72x.h"
#include "g72x_priv.h"
/*
* Maps G.723_40 code word to ructeconstructed scale factor normalized log
* magnitude values.
*/
static short _dqlntab[32] = {-2048, -66, 28, 104, 169, 224, 274, 318,
358, 395, 429, 459, 488, 514, 539, 566,
566, 539, 514, 488, 459, 429, 395, 358,
318, 274, 224, 169, 104, 28, -66, -2048};
/* Maps G.723_40 code word to log of scale factor multiplier. */
static short _witab[32] = {448, 448, 768, 1248, 1280, 1312, 1856, 3200,
4512, 5728, 7008, 8960, 11456, 14080, 16928, 22272,
22272, 16928, 14080, 11456, 8960, 7008, 5728, 4512,
3200, 1856, 1312, 1280, 1248, 768, 448, 448};
/*
* Maps G.723_40 code words to a set of values whose long and short
* term averages are computed and then compared to give an indication
* how stationary (steady state) the signal is.
*/
static short _fitab[32] = {0, 0, 0, 0, 0, 0x200, 0x200, 0x200,
0x200, 0x200, 0x400, 0x600, 0x800, 0xA00, 0xC00, 0xC00,
0xC00, 0xC00, 0xA00, 0x800, 0x600, 0x400, 0x200, 0x200,
0x200, 0x200, 0x200, 0, 0, 0, 0, 0};
static short qtab_723_40[15] = {-122, -16, 68, 139, 198, 250, 298, 339,
378, 413, 445, 475, 502, 528, 553};
/*
* g723_40_encoder()
*
* Encodes a 16-bit linear PCM, A-law or u-law input sample and retuens
* the resulting 5-bit CCITT G.723 40Kbps code.
* Returns -1 if the input coding value is invalid.
*/
int g723_40_encoder (int sl, G72x_STATE *state_ptr)
{
short sei, sezi, se, sez; /* ACCUM */
short d; /* SUBTA */
short y; /* MIX */
short sr; /* ADDB */
short dqsez; /* ADDC */
short dq, i;
/* linearize input sample to 14-bit PCM */
sl >>= 2; /* sl of 14-bit dynamic range */
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
d = sl - se; /* d = estimation difference */
/* quantize prediction difference */
y = step_size(state_ptr); /* adaptive quantizer step size */
i = quantize(d, y, qtab_723_40, 15); /* i = ADPCM code */
dq = reconstruct(i & 0x10, _dqlntab[i], y); /* quantized diff */
sr = (dq < 0) ? se - (dq & 0x7FFF) : se + dq; /* reconstructed signal */
dqsez = sr + sez - se; /* dqsez = pole prediction diff. */
update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
return (i);
}
/*
* g723_40_decoder()
*
* Decodes a 5-bit CCITT G.723 40Kbps code and returns
* the resulting 16-bit linear PCM, A-law or u-law sample value.
* -1 is returned if the output coding is unknown.
*/
int g723_40_decoder (int i, G72x_STATE *state_ptr)
{
short sezi, sei, sez, se; /* ACCUM */
short y ; /* MIX */
short sr; /* ADDB */
short dq;
short dqsez;
i &= 0x1f; /* mask to get proper bits */
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
y = step_size(state_ptr); /* adaptive quantizer step size */
dq = reconstruct(i & 0x10, _dqlntab[i], y); /* estimation diff. */
sr = (dq < 0) ? (se - (dq & 0x7FFF)) : (se + dq); /* reconst. signal */
dqsez = sr - se + sez; /* pole prediction diff. */
update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
return (sr << 2); /* sr was of 14-bit dynamic range */
}

View File

@@ -0,0 +1,644 @@
/*
* This source code is a product of Sun Microsystems, Inc. and is provided
* for unrestricted use. Users may copy or modify this source code without
* charge.
*
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun source code is provided with no support and without any obligation on
* the part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
/*
* g72x.c
*
* Common routines for G.721 and G.723 conversions.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "g72x.h"
#include "g72x_priv.h"
static G72x_STATE * g72x_state_new (void) ;
static int unpack_bytes (int bits, int blocksize, const unsigned char * block, short * samples) ;
static int pack_bytes (int bits, const short * samples, unsigned char * block) ;
static
short power2 [15] =
{ 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000
} ;
/*
* quan()
*
* quantizes the input val against the table of size short integers.
* It returns i if table[i - 1] <= val < table[i].
*
* Using linear search for simple coding.
*/
static
int quan (int val, short *table, int size)
{
int i;
for (i = 0; i < size; i++)
if (val < *table++)
break;
return (i);
}
/*
* fmult()
*
* returns the integer product of the 14-bit integer "an" and
* "floating point" representation (4-bit exponent, 6-bit mantessa) "srn".
*/
static
int fmult (int an, int srn)
{
short anmag, anexp, anmant;
short wanexp, wanmant;
short retval;
anmag = (an > 0) ? an : ((-an) & 0x1FFF);
anexp = quan(anmag, power2, 15) - 6;
anmant = (anmag == 0) ? 32 :
(anexp >= 0) ? anmag >> anexp : anmag << -anexp;
wanexp = anexp + ((srn >> 6) & 0xF) - 13;
/*
** The original was :
** wanmant = (anmant * (srn & 0x3F) + 0x30) >> 4 ;
** but could see no valid reason for the + 0x30.
** Removed it and it improved the SNR of the codec.
*/
wanmant = (anmant * (srn & 0x3F)) >> 4 ;
retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) :
(wanmant >> -wanexp);
return (((an ^ srn) < 0) ? -retval : retval);
}
static G72x_STATE * g72x_state_new (void)
{ return calloc (1, sizeof (G72x_STATE)) ;
}
/*
* private_init_state()
*
* This routine initializes and/or resets the G72x_PRIVATE structure
* pointed to by 'state_ptr'.
* All the initial state values are specified in the CCITT G.721 document.
*/
void private_init_state (G72x_STATE *state_ptr)
{
int cnta;
state_ptr->yl = 34816;
state_ptr->yu = 544;
state_ptr->dms = 0;
state_ptr->dml = 0;
state_ptr->ap = 0;
for (cnta = 0; cnta < 2; cnta++) {
state_ptr->a[cnta] = 0;
state_ptr->pk[cnta] = 0;
state_ptr->sr[cnta] = 32;
}
for (cnta = 0; cnta < 6; cnta++) {
state_ptr->b[cnta] = 0;
state_ptr->dq[cnta] = 32;
}
state_ptr->td = 0;
} /* private_init_state */
struct g72x_state * g72x_reader_init (int codec, int *blocksize, int *samplesperblock)
{ G72x_STATE *pstate ;
if ((pstate = g72x_state_new ()) == NULL)
return NULL ;
private_init_state (pstate) ;
pstate->encoder = NULL ;
switch (codec)
{ case G723_16_BITS_PER_SAMPLE : /* 2 bits per sample. */
pstate->decoder = g723_16_decoder ;
*blocksize = G723_16_BYTES_PER_BLOCK ;
*samplesperblock = G723_16_SAMPLES_PER_BLOCK ;
pstate->codec_bits = 2 ;
pstate->blocksize = G723_16_BYTES_PER_BLOCK ;
pstate->samplesperblock = G723_16_SAMPLES_PER_BLOCK ;
break ;
case G723_24_BITS_PER_SAMPLE : /* 3 bits per sample. */
pstate->decoder = g723_24_decoder ;
*blocksize = G723_24_BYTES_PER_BLOCK ;
*samplesperblock = G723_24_SAMPLES_PER_BLOCK ;
pstate->codec_bits = 3 ;
pstate->blocksize = G723_24_BYTES_PER_BLOCK ;
pstate->samplesperblock = G723_24_SAMPLES_PER_BLOCK ;
break ;
case G721_32_BITS_PER_SAMPLE : /* 4 bits per sample. */
pstate->decoder = g721_decoder ;
*blocksize = G721_32_BYTES_PER_BLOCK ;
*samplesperblock = G721_32_SAMPLES_PER_BLOCK ;
pstate->codec_bits = 4 ;
pstate->blocksize = G721_32_BYTES_PER_BLOCK ;
pstate->samplesperblock = G721_32_SAMPLES_PER_BLOCK ;
break ;
case G721_40_BITS_PER_SAMPLE : /* 5 bits per sample. */
pstate->decoder = g723_40_decoder ;
*blocksize = G721_40_BYTES_PER_BLOCK ;
*samplesperblock = G721_40_SAMPLES_PER_BLOCK ;
pstate->codec_bits = 5 ;
pstate->blocksize = G721_40_BYTES_PER_BLOCK ;
pstate->samplesperblock = G721_40_SAMPLES_PER_BLOCK ;
break ;
default :
free (pstate) ;
return NULL ;
} ;
return pstate ;
} /* g72x_reader_init */
struct g72x_state * g72x_writer_init (int codec, int *blocksize, int *samplesperblock)
{ G72x_STATE *pstate ;
if ((pstate = g72x_state_new ()) == NULL)
return NULL ;
private_init_state (pstate) ;
pstate->decoder = NULL ;
switch (codec)
{ case G723_16_BITS_PER_SAMPLE : /* 2 bits per sample. */
pstate->encoder = g723_16_encoder ;
*blocksize = G723_16_BYTES_PER_BLOCK ;
*samplesperblock = G723_16_SAMPLES_PER_BLOCK ;
pstate->codec_bits = 2 ;
pstate->blocksize = G723_16_BYTES_PER_BLOCK ;
pstate->samplesperblock = G723_16_SAMPLES_PER_BLOCK ;
break ;
case G723_24_BITS_PER_SAMPLE : /* 3 bits per sample. */
pstate->encoder = g723_24_encoder ;
*blocksize = G723_24_BYTES_PER_BLOCK ;
*samplesperblock = G723_24_SAMPLES_PER_BLOCK ;
pstate->codec_bits = 3 ;
pstate->blocksize = G723_24_BYTES_PER_BLOCK ;
pstate->samplesperblock = G723_24_SAMPLES_PER_BLOCK ;
break ;
case G721_32_BITS_PER_SAMPLE : /* 4 bits per sample. */
pstate->encoder = g721_encoder ;
*blocksize = G721_32_BYTES_PER_BLOCK ;
*samplesperblock = G721_32_SAMPLES_PER_BLOCK ;
pstate->codec_bits = 4 ;
pstate->blocksize = G721_32_BYTES_PER_BLOCK ;
pstate->samplesperblock = G721_32_SAMPLES_PER_BLOCK ;
break ;
case G721_40_BITS_PER_SAMPLE : /* 5 bits per sample. */
pstate->encoder = g723_40_encoder ;
*blocksize = G721_40_BYTES_PER_BLOCK ;
*samplesperblock = G721_40_SAMPLES_PER_BLOCK ;
pstate->codec_bits = 5 ;
pstate->blocksize = G721_40_BYTES_PER_BLOCK ;
pstate->samplesperblock = G721_40_SAMPLES_PER_BLOCK ;
break ;
default :
free (pstate) ;
return NULL ;
} ;
return pstate ;
} /* g72x_writer_init */
int g72x_decode_block (G72x_STATE *pstate, const unsigned char *block, short *samples)
{ int k, count ;
count = unpack_bytes (pstate->codec_bits, pstate->blocksize, block, samples) ;
for (k = 0 ; k < count ; k++)
samples [k] = pstate->decoder (samples [k], pstate) ;
return 0 ;
} /* g72x_decode_block */
int g72x_encode_block (G72x_STATE *pstate, short *samples, unsigned char *block)
{ int k, count ;
for (k = 0 ; k < pstate->samplesperblock ; k++)
samples [k] = pstate->encoder (samples [k], pstate) ;
count = pack_bytes (pstate->codec_bits, samples, block) ;
return count ;
} /* g72x_encode_block */
/*
* predictor_zero()
*
* computes the estimated signal from 6-zero predictor.
*
*/
int predictor_zero (G72x_STATE *state_ptr)
{
int i;
int sezi;
sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]);
for (i = 1; i < 6; i++) /* ACCUM */
sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]);
return (sezi);
}
/*
* predictor_pole()
*
* computes the estimated signal from 2-pole predictor.
*
*/
int predictor_pole(G72x_STATE *state_ptr)
{
return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) +
fmult(state_ptr->a[0] >> 2, state_ptr->sr[0]));
}
/*
* step_size()
*
* computes the quantization step size of the adaptive quantizer.
*
*/
int step_size (G72x_STATE *state_ptr)
{
int y;
int dif;
int al;
if (state_ptr->ap >= 256)
return (state_ptr->yu);
else {
y = state_ptr->yl >> 6;
dif = state_ptr->yu - y;
al = state_ptr->ap >> 2;
if (dif > 0)
y += (dif * al) >> 6;
else if (dif < 0)
y += (dif * al + 0x3F) >> 6;
return (y);
}
}
/*
* quantize()
*
* Given a raw sample, 'd', of the difference signal and a
* quantization step size scale factor, 'y', this routine returns the
* ADPCM codeword to which that sample gets quantized. The step
* size scale factor division operation is done in the log base 2 domain
* as a subtraction.
*/
int quantize(
int d, /* Raw difference signal sample */
int y, /* Step size multiplier */
short *table, /* quantization table */
int size) /* table size of short integers */
{
short dqm; /* Magnitude of 'd' */
short expon; /* Integer part of base 2 log of 'd' */
short mant; /* Fractional part of base 2 log */
short dl; /* Log of magnitude of 'd' */
short dln; /* Step size scale factor normalized log */
int i;
/*
* LOG
*
* Compute base 2 log of 'd', and store in 'dl'.
*/
dqm = abs(d);
expon = quan(dqm >> 1, power2, 15);
mant = ((dqm << 7) >> expon) & 0x7F; /* Fractional portion. */
dl = (expon << 7) + mant;
/*
* SUBTB
*
* "Divide" by step size multiplier.
*/
dln = dl - (y >> 2);
/*
* QUAN
*
* Obtain codword i for 'd'.
*/
i = quan(dln, table, size);
if (d < 0) /* take 1's complement of i */
return ((size << 1) + 1 - i);
else if (i == 0) /* take 1's complement of 0 */
return ((size << 1) + 1); /* new in 1988 */
else
return (i);
}
/*
* reconstruct()
*
* Returns reconstructed difference signal 'dq' obtained from
* codeword 'i' and quantization step size scale factor 'y'.
* Multiplication is performed in log base 2 domain as addition.
*/
int
reconstruct(
int sign, /* 0 for non-negative value */
int dqln, /* G.72x codeword */
int y) /* Step size multiplier */
{
short dql; /* Log of 'dq' magnitude */
short dex; /* Integer part of log */
short dqt;
short dq; /* Reconstructed difference signal sample */
dql = dqln + (y >> 2); /* ADDA */
if (dql < 0) {
return ((sign) ? -0x8000 : 0);
} else { /* ANTILOG */
dex = (dql >> 7) & 15;
dqt = 128 + (dql & 127);
dq = (dqt << 7) >> (14 - dex);
return ((sign) ? (dq - 0x8000) : dq);
}
}
/*
* update()
*
* updates the state variables for each output code
*/
void
update(
int code_size, /* distinguish 723_40 with others */
int y, /* quantizer step size */
int wi, /* scale factor multiplier */
int fi, /* for long/short term energies */
int dq, /* quantized prediction difference */
int sr, /* reconstructed signal */
int dqsez, /* difference from 2-pole predictor */
G72x_STATE *state_ptr) /* coder state pointer */
{
int cnt;
short mag, expon; /* Adaptive predictor, FLOAT A */
short a2p = 0; /* LIMC */
short a1ul; /* UPA1 */
short pks1; /* UPA2 */
short fa1;
char tr; /* tone/transition detector */
short ylint, thr2, dqthr;
short ylfrac, thr1;
short pk0;
pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */
mag = dq & 0x7FFF; /* prediction difference magnitude */
/* TRANS */
ylint = state_ptr->yl >> 15; /* exponent part of yl */
ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */
thr1 = (32 + ylfrac) << ylint; /* threshold */
thr2 = (ylint > 9) ? 31 << 10 : thr1; /* limit thr2 to 31 << 10 */
dqthr = (thr2 + (thr2 >> 1)) >> 1; /* dqthr = 0.75 * thr2 */
if (state_ptr->td == 0) /* signal supposed voice */
tr = 0;
else if (mag <= dqthr) /* supposed data, but small mag */
tr = 0; /* treated as voice */
else /* signal is data (modem) */
tr = 1;
/*
* Quantizer scale factor adaptation.
*/
/* FUNCTW & FILTD & DELAY */
/* update non-steady state step size multiplier */
state_ptr->yu = y + ((wi - y) >> 5);
/* LIMB */
if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */
state_ptr->yu = 544;
else if (state_ptr->yu > 5120)
state_ptr->yu = 5120;
/* FILTE & DELAY */
/* update steady state step size multiplier */
state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6);
/*
* Adaptive predictor coefficients.
*/
if (tr == 1) { /* reset a's and b's for modem signal */
state_ptr->a[0] = 0;
state_ptr->a[1] = 0;
state_ptr->b[0] = 0;
state_ptr->b[1] = 0;
state_ptr->b[2] = 0;
state_ptr->b[3] = 0;
state_ptr->b[4] = 0;
state_ptr->b[5] = 0;
} else { /* update a's and b's */
pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */
/* update predictor pole a[1] */
a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7);
if (dqsez != 0) {
fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0];
if (fa1 < -8191) /* a2p = function of fa1 */
a2p -= 0x100;
else if (fa1 > 8191)
a2p += 0xFF;
else
a2p += fa1 >> 5;
if (pk0 ^ state_ptr->pk[1])
{ /* LIMC */
if (a2p <= -12160)
a2p = -12288;
else if (a2p >= 12416)
a2p = 12288;
else
a2p -= 0x80;
}
else if (a2p <= -12416)
a2p = -12288;
else if (a2p >= 12160)
a2p = 12288;
else
a2p += 0x80;
}
/* TRIGB & DELAY */
state_ptr->a[1] = a2p;
/* UPA1 */
/* update predictor pole a[0] */
state_ptr->a[0] -= state_ptr->a[0] >> 8;
if (dqsez != 0)
{ if (pks1 == 0)
state_ptr->a[0] += 192;
else
state_ptr->a[0] -= 192;
} ;
/* LIMD */
a1ul = 15360 - a2p;
if (state_ptr->a[0] < -a1ul)
state_ptr->a[0] = -a1ul;
else if (state_ptr->a[0] > a1ul)
state_ptr->a[0] = a1ul;
/* UPB : update predictor zeros b[6] */
for (cnt = 0; cnt < 6; cnt++) {
if (code_size == 5) /* for 40Kbps G.723 */
state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9;
else /* for G.721 and 24Kbps G.723 */
state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8;
if (dq & 0x7FFF) { /* XOR */
if ((dq ^ state_ptr->dq[cnt]) >= 0)
state_ptr->b[cnt] += 128;
else
state_ptr->b[cnt] -= 128;
}
}
}
for (cnt = 5; cnt > 0; cnt--)
state_ptr->dq[cnt] = state_ptr->dq[cnt-1];
/* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */
if (mag == 0) {
state_ptr->dq[0] = (dq >= 0) ? 0x20 : 0xFC20;
} else {
expon = quan(mag, power2, 15);
state_ptr->dq[0] = (dq >= 0) ?
(expon << 6) + ((mag << 6) >> expon) :
(expon << 6) + ((mag << 6) >> expon) - 0x400;
}
state_ptr->sr[1] = state_ptr->sr[0];
/* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */
if (sr == 0) {
state_ptr->sr[0] = 0x20;
} else if (sr > 0) {
expon = quan(sr, power2, 15);
state_ptr->sr[0] = (expon << 6) + ((sr << 6) >> expon);
} else if (sr > -32768) {
mag = -sr;
expon = quan(mag, power2, 15);
state_ptr->sr[0] = (expon << 6) + ((mag << 6) >> expon) - 0x400;
} else
state_ptr->sr[0] = (short) 0xFC20;
/* DELAY A */
state_ptr->pk[1] = state_ptr->pk[0];
state_ptr->pk[0] = pk0;
/* TONE */
if (tr == 1) /* this sample has been treated as data */
state_ptr->td = 0; /* next one will be treated as voice */
else if (a2p < -11776) /* small sample-to-sample correlation */
state_ptr->td = 1; /* signal may be data */
else /* signal is voice */
state_ptr->td = 0;
/*
* Adaptation speed control.
*/
state_ptr->dms += (fi - state_ptr->dms) >> 5; /* FILTA */
state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */
if (tr == 1)
state_ptr->ap = 256;
else if (y < 1536) /* SUBTC */
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
else if (state_ptr->td == 1)
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
else if (abs((state_ptr->dms << 2) - state_ptr->dml) >=
(state_ptr->dml >> 3))
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
else
state_ptr->ap += (-state_ptr->ap) >> 4;
return ;
} /* update */
/*------------------------------------------------------------------------------
*/
static int
unpack_bytes (int bits, int blocksize, const unsigned char * block, short * samples)
{ unsigned int in_buffer = 0 ;
unsigned char in_byte ;
int k, in_bits = 0, bindex = 0 ;
for (k = 0 ; bindex <= blocksize && k < G72x_BLOCK_SIZE ; k++)
{ if (in_bits < bits)
{ in_byte = block [bindex++] ;
in_buffer |= (in_byte << in_bits);
in_bits += 8;
}
samples [k] = in_buffer & ((1 << bits) - 1);
in_buffer >>= bits;
in_bits -= bits;
} ;
return k ;
} /* unpack_bytes */
static int
pack_bytes (int bits, const short * samples, unsigned char * block)
{
unsigned int out_buffer = 0 ;
int k, bindex = 0, out_bits = 0 ;
unsigned char out_byte ;
for (k = 0 ; k < G72x_BLOCK_SIZE ; k++)
{ out_buffer |= (samples [k] << out_bits) ;
out_bits += bits ;
if (out_bits >= 8)
{ out_byte = out_buffer & 0xFF ;
out_bits -= 8 ;
out_buffer >>= 8 ;
block [bindex++] = out_byte ;
}
} ;
return bindex ;
} /* pack_bytes */

View File

@@ -0,0 +1,91 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
** This file is not the same as the original file from Sun Microsystems. Nearly
** all the original definitions and function prototypes that were in the file
** of this name have been moved to g72x_priv.h.
*/
#ifndef G72X_HEADER_FILE
#define G72X_HEADER_FILE
/*
** Number of samples per block to process.
** Must be a common multiple of possible bits per sample : 2, 3, 4, 5 and 8.
*/
#define G72x_BLOCK_SIZE (3 * 5 * 8)
/*
** Identifiers for the differing kinds of G72x ADPCM codecs.
** The identifiers also define the number of encoded bits per sample.
*/
enum
{ G723_16_BITS_PER_SAMPLE = 2,
G723_24_BITS_PER_SAMPLE = 3,
G723_40_BITS_PER_SAMPLE = 5,
G721_32_BITS_PER_SAMPLE = 4,
G721_40_BITS_PER_SAMPLE = 5,
G723_16_SAMPLES_PER_BLOCK = G72x_BLOCK_SIZE,
G723_24_SAMPLES_PER_BLOCK = G723_24_BITS_PER_SAMPLE * (G72x_BLOCK_SIZE / G723_24_BITS_PER_SAMPLE),
G723_40_SAMPLES_PER_BLOCK = G723_40_BITS_PER_SAMPLE * (G72x_BLOCK_SIZE / G723_40_BITS_PER_SAMPLE),
G721_32_SAMPLES_PER_BLOCK = G72x_BLOCK_SIZE,
G721_40_SAMPLES_PER_BLOCK = G721_40_BITS_PER_SAMPLE * (G72x_BLOCK_SIZE / G721_40_BITS_PER_SAMPLE),
G723_16_BYTES_PER_BLOCK = (G723_16_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8,
G723_24_BYTES_PER_BLOCK = (G723_24_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8,
G723_40_BYTES_PER_BLOCK = (G723_40_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8,
G721_32_BYTES_PER_BLOCK = (G721_32_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8,
G721_40_BYTES_PER_BLOCK = (G721_40_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8
} ;
/* Forward declaration of of g72x_state. */
struct g72x_state ;
/* External function definitions. */
struct g72x_state * g72x_reader_init (int codec, int *blocksize, int *samplesperblock) ;
struct g72x_state * g72x_writer_init (int codec, int *blocksize, int *samplesperblock) ;
/*
** Initialize the ADPCM state table for the given codec.
** Return 0 on success, 1 on fail.
*/
int g72x_decode_block (struct g72x_state *pstate, const unsigned char *block, short *samples) ;
/*
** The caller fills data->block with data->bytes bytes before calling the
** function. The value data->bytes must be an integer multiple of
** data->blocksize and be <= data->max_bytes.
** When it returns, the caller can read out data->samples samples.
*/
int g72x_encode_block (struct g72x_state *pstate, short *samples, unsigned char *block) ;
/*
** The caller fills state->samples some integer multiple data->samples_per_block
** (up to G72x_BLOCK_SIZE) samples before calling the function.
** When it returns, the caller can read out bytes encoded bytes.
*/
#endif /* !G72X_HEADER_FILE */

View File

@@ -0,0 +1,109 @@
/*
* This source code is a product of Sun Microsystems, Inc. and is provided
* for unrestricted use. Users may copy or modify this source code without
* charge.
*
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun source code is provided with no support and without any obligation on
* the part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
#ifndef G72X_PRIVATE_H
#define G72X_PRIVATE_H
#ifdef __cplusplus
#error "This code is not designed to be compiled with a C++ compiler."
#endif
/*
** The following is the definition of the state structure used by the
** G.721/G.723 encoder and decoder to preserve their internal state
** between successive calls. The meanings of the majority of the state
** structure fields are explained in detail in the CCITT Recommendation
** G.721. The field names are essentially identical to variable names
** in the bit level description of the coding algorithm included in this
** Recommendation.
*/
struct g72x_state
{ long yl; /* Locked or steady state step size multiplier. */
short yu; /* Unlocked or non-steady state step size multiplier. */
short dms; /* Short term energy estimate. */
short dml; /* Long term energy estimate. */
short ap; /* Linear weighting coefficient of 'yl' and 'yu'. */
short a[2]; /* Coefficients of pole portion of prediction filter. */
short b[6]; /* Coefficients of zero portion of prediction filter. */
short pk[2]; /*
** Signs of previous two samples of a partially
** reconstructed signal.
**/
short dq[6]; /*
** Previous 6 samples of the quantized difference
** signal represented in an internal floating point
** format.
**/
short sr[2]; /*
** Previous 2 samples of the quantized difference
** signal represented in an internal floating point
** format.
*/
char td; /* delayed tone detect, new in 1988 version */
/* The following struct members were added for libsndfile. The original
** code worked by calling a set of functions on a sample by sample basis
** which is slow on architectures like Intel x86. For libsndfile, this
** was changed so that the encoding and decoding routines could work on
** a block of samples at a time to reduce the function call overhead.
*/
int (*encoder) (int, struct g72x_state* state) ;
int (*decoder) (int, struct g72x_state* state) ;
int codec_bits, blocksize, samplesperblock ;
} ;
typedef struct g72x_state G72x_STATE ;
int predictor_zero (G72x_STATE *state_ptr);
int predictor_pole (G72x_STATE *state_ptr);
int step_size (G72x_STATE *state_ptr);
int quantize (int d, int y, short *table, int size);
int reconstruct (int sign, int dqln, int y);
void update (int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, G72x_STATE *state_ptr);
int g721_encoder (int sample, G72x_STATE *state_ptr);
int g721_decoder (int code, G72x_STATE *state_ptr);
int g723_16_encoder (int sample, G72x_STATE *state_ptr);
int g723_16_decoder (int code, G72x_STATE *state_ptr);
int g723_24_encoder (int sample, G72x_STATE *state_ptr);
int g723_24_decoder (int code, G72x_STATE *state_ptr);
int g723_40_encoder (int sample, G72x_STATE *state_ptr);
int g723_40_decoder (int code, G72x_STATE *state_ptr);
void private_init_state (G72x_STATE *state_ptr) ;
#endif /* G72X_PRIVATE_H */

View File

@@ -0,0 +1,16 @@
Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
Technische Universitaet Berlin
Any use of this software is permitted provided that this notice is not
removed and that neither the authors nor the Technische Universitaet Berlin
are deemed to have made any representations as to the suitability of this
software for any purpose nor are held responsible for any defects of
this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
As a matter of courtesy, the authors request to be informed about uses
this software has found, about bugs in this software, and about any
improvements that may be of general interest.
Berlin, 28.11.1994
Jutta Degener
Carsten Bormann

View File

@@ -0,0 +1,56 @@
2004-05-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
* gsm610_priv.h
Replace ugly macros with inline functions.
* *.c
Remove temporary variables used by macros and other minor fixes required by
above change.
2003-06-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
* rpe.c
Renamed variables "exp" to "expon" to avoid shadowed parameter warnigns.
2002-06-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
* long_term.c
Changes tp removed compiler warnings about shadowed parameters.
2002-06-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
* private.h
Made declarations of gsm_A, gsm_B, gsm_MIC etc extern. This fixed a compile
problem on MacOSX.
2002-05-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
* *.[ch]
Removed all pre-ANSI prototype kludges. Removed proto.h and unproto.h.
Started work on making GSM 6.10 files seekable. Currently they are not.
* code.c private.h
Function Gsm_Coder () used a statically defined array. This was obviously
not re-entrant so moved it to struct gsm_state.
2001-09-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
* code.c
Added #includes for string.h and stdlib.h.
2000-10-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
* config.h
Removed some commented out #defines (ie //*efine) which were causing problems on
the Sun cc compiler.
2000-02-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
* private.h
Added #defines to emulate normal compile time options.
2000-02-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
* everthing
Created this directory and copied files from libgsm.
http://kbs.cs.tu-berlin.de/~jutta/toast.html

View File

@@ -0,0 +1,36 @@
GSM 06.10 13 kbit/s RPE/LTP speech codec
----------------------------------------
All the file in this directory were written by Jutta Degener
and Carsten Borman for The Communications and Operating Systems
Research Group (KBS) at the Technische Universitaet Berlin.
Their work was released under the following license which is
assumed to be compatible with The GNU Lesser General Public License.
----------------------------------------------------------------------------
Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
Technische Universitaet Berlin
Any use of this software is permitted provided that this notice is not
removed and that neither the authors nor the Technische Universitaet Berlin
are deemed to have made any representations as to the suitability of this
software for any purpose nor are held responsible for any defects of
this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
As a matter of courtesy, the authors request to be informed about uses
this software has found, about bugs in this software, and about any
improvements that may be of general interest.
Berlin, 28.11.1994
Jutta Degener (jutta@cs.tu-berlin.de)
Carsten Bormann (cabo@cs.tu-berlin.de)
----------------------------------------------------------------------------
Jutta Degener and Carsten Bormann's work can be found on their homepage
at:
http://kbs.cs.tu-berlin.de/~jutta/toast.html

View File

@@ -0,0 +1,240 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
/*
* See private.h for the more commonly used macro versions.
*/
#include <stdio.h>
#include <assert.h>
#include "gsm610_priv.h"
#define saturate(x) \
((x) < MIN_WORD ? MIN_WORD : (x) > MAX_WORD ? MAX_WORD: (x))
word gsm_add ( word a, word b)
{
longword sum = (longword)a + (longword)b;
return saturate(sum);
}
word gsm_sub ( word a, word b)
{
longword diff = (longword)a - (longword)b;
return saturate(diff);
}
word gsm_mult ( word a, word b)
{
if (a == MIN_WORD && b == MIN_WORD)
return MAX_WORD;
return SASR_L( (longword)a * (longword)b, 15 );
}
word gsm_mult_r ( word a, word b)
{
if (b == MIN_WORD && a == MIN_WORD) return MAX_WORD;
else {
longword prod = (longword)a * (longword)b + 16384;
prod >>= 15;
return prod & 0xFFFF;
}
}
word gsm_abs (word a)
{
return a < 0 ? (a == MIN_WORD ? MAX_WORD : -a) : a;
}
longword gsm_L_mult (word a, word b)
{
assert( a != MIN_WORD || b != MIN_WORD );
return ((longword)a * (longword)b) << 1;
}
longword gsm_L_add ( longword a, longword b)
{
if (a < 0) {
if (b >= 0) return a + b;
else {
ulongword A = (ulongword)-(a + 1) + (ulongword)-(b + 1);
return A >= MAX_LONGWORD ? MIN_LONGWORD :-(longword)A-2;
}
}
else if (b <= 0) return a + b;
else {
ulongword A = (ulongword)a + (ulongword)b;
return A > MAX_LONGWORD ? MAX_LONGWORD : A;
}
}
longword gsm_L_sub ( longword a, longword b)
{
if (a >= 0) {
if (b >= 0) return a - b;
else {
/* a>=0, b<0 */
ulongword A = (ulongword)a + -(b + 1);
return A >= MAX_LONGWORD ? MAX_LONGWORD : (A + 1);
}
}
else if (b <= 0) return a - b;
else {
/* a<0, b>0 */
ulongword A = (ulongword)-(a + 1) + b;
return A >= MAX_LONGWORD ? MIN_LONGWORD : -(longword)A - 1;
}
}
static unsigned char const bitoff[ 256 ] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
word gsm_norm (longword a )
/*
* the number of left shifts needed to normalize the 32 bit
* variable L_var1 for positive values on the interval
*
* with minimum of
* minimum of 1073741824 (01000000000000000000000000000000) and
* maximum of 2147483647 (01111111111111111111111111111111)
*
*
* and for negative values on the interval with
* minimum of -2147483648 (-10000000000000000000000000000000) and
* maximum of -1073741824 ( -1000000000000000000000000000000).
*
* in order to normalize the result, the following
* operation must be done: L_norm_var1 = L_var1 << norm( L_var1 );
*
* (That's 'ffs', only from the left, not the right..)
*/
{
assert(a != 0);
if (a < 0) {
if (a <= -1073741824) return 0;
a = ~a;
}
return a & 0xffff0000
? ( a & 0xff000000
? -1 + bitoff[ 0xFF & (a >> 24) ]
: 7 + bitoff[ 0xFF & (a >> 16) ] )
: ( a & 0xff00
? 15 + bitoff[ 0xFF & (a >> 8) ]
: 23 + bitoff[ 0xFF & a ] );
}
longword gsm_L_asl (longword a, int n)
{
if (n >= 32) return 0;
if (n <= -32) return -(a < 0);
if (n < 0) return gsm_L_asr(a, -n);
return a << n;
}
word gsm_asr (word a, int n)
{
if (n >= 16) return -(a < 0);
if (n <= -16) return 0;
if (n < 0) return a << -n;
return SASR_W (a, (word) n);
}
word gsm_asl (word a, int n)
{
if (n >= 16) return 0;
if (n <= -16) return -(a < 0);
if (n < 0) return gsm_asr(a, -n);
return a << n;
}
longword gsm_L_asr (longword a, int n)
{
if (n >= 32) return -(a < 0);
if (n <= -32) return 0;
if (n < 0) return a << -n;
return SASR_L (a, (word) n);
}
/*
** word gsm_asr (word a, int n)
** {
** if (n >= 16) return -(a < 0);
** if (n <= -16) return 0;
** if (n < 0) return a << -n;
**
** # ifdef SASR_W
** return a >> n;
** # else
** if (a >= 0) return a >> n;
** else return -(word)( -(uword)a >> n );
** # endif
** }
**
*/
/*
* (From p. 46, end of section 4.2.5)
*
* NOTE: The following lines gives [sic] one correct implementation
* of the div(num, denum) arithmetic operation. Compute div
* which is the integer division of num by denum: with denum
* >= num > 0
*/
word gsm_div (word num, word denum)
{
longword L_num = num;
longword L_denum = denum;
word div = 0;
int k = 15;
/* The parameter num sometimes becomes zero.
* Although this is explicitly guarded against in 4.2.5,
* we assume that the result should then be zero as well.
*/
/* assert(num != 0); */
assert(num >= 0 && denum >= num);
if (num == 0)
return 0;
while (k--) {
div <<= 1;
L_num <<= 1;
if (L_num >= L_denum) {
L_num -= L_denum;
div++;
}
}
return div;
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include "gsm610_priv.h"
/*
* 4.2 FIXED POINT IMPLEMENTATION OF THE RPE-LTP CODER
*/
void Gsm_Coder (
struct gsm_state * State,
word * s, /* [0..159] samples IN */
/*
* The RPE-LTD coder works on a frame by frame basis. The length of
* the frame is equal to 160 samples. Some computations are done
* once per frame to produce at the output of the coder the
* LARc[1..8] parameters which are the coded LAR coefficients and
* also to realize the inverse filtering operation for the entire
* frame (160 samples of signal d[0..159]). These parts produce at
* the output of the coder:
*/
word * LARc, /* [0..7] LAR coefficients OUT */
/*
* Procedure 4.2.11 to 4.2.18 are to be executed four times per
* frame. That means once for each sub-segment RPE-LTP analysis of
* 40 samples. These parts produce at the output of the coder:
*/
word * Nc, /* [0..3] LTP lag OUT */
word * bc, /* [0..3] coded LTP gain OUT */
word * Mc, /* [0..3] RPE grid selection OUT */
word * xmaxc,/* [0..3] Coded maximum amplitude OUT */
word * xMc /* [13*4] normalized RPE samples OUT */
)
{
int k;
word * dp = State->dp0 + 120; /* [ -120...-1 ] */
word * dpp = dp; /* [ 0...39 ] */
word so[160];
Gsm_Preprocess (State, s, so);
Gsm_LPC_Analysis (State, so, LARc);
Gsm_Short_Term_Analysis_Filter (State, LARc, so);
for (k = 0; k <= 3; k++, xMc += 13) {
Gsm_Long_Term_Predictor ( State,
so+k*40, /* d [0..39] IN */
dp, /* dp [-120..-1] IN */
State->e + 5, /* e [0..39] OUT */
dpp, /* dpp [0..39] OUT */
Nc++,
bc++);
Gsm_RPE_Encoding ( /*-S,-*/
State->e + 5, /* e ][0..39][ IN/OUT */
xmaxc++, Mc++, xMc );
/*
* Gsm_Update_of_reconstructed_short_time_residual_signal
* ( dpp, State->e + 5, dp );
*/
{ register int i;
for (i = 0; i <= 39; i++)
dp[ i ] = GSM_ADD( State->e[5 + i], dpp[i] );
}
dp += 40;
dpp += 40;
}
(void)memcpy( (char *)State->dp0, (char *)(State->dp0 + 160),
120 * sizeof(*State->dp0) );
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#ifndef CONFIG_H
#define CONFIG_H
#define HAS_STDLIB_H 1 /* /usr/include/stdlib.h */
#define HAS_FCNTL_H 1 /* /usr/include/fcntl.h */
#define HAS_FSTAT 1 /* fstat syscall */
#define HAS_FCHMOD 1 /* fchmod syscall */
#define HAS_CHMOD 1 /* chmod syscall */
#define HAS_FCHOWN 1 /* fchown syscall */
#define HAS_CHOWN 1 /* chown syscall */
#define HAS_STRING_H 1 /* /usr/include/string.h */
#define HAS_UNISTD_H 1 /* /usr/include/unistd.h */
#define HAS_UTIME 1 /* POSIX utime(path, times) */
#define HAS_UTIME_H 1 /* UTIME header file */
#endif /* CONFIG_H */

View File

@@ -0,0 +1,59 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include <stdio.h>
#include "gsm610_priv.h"
/*
* 4.3 FIXED POINT IMPLEMENTATION OF THE RPE-LTP DECODER
*/
static void Postprocessing (
struct gsm_state * S,
register word * s)
{
register int k;
register word msr = S->msr;
register word tmp;
for (k = 160; k--; s++) {
tmp = GSM_MULT_R( msr, 28180 );
msr = GSM_ADD(*s, tmp); /* Deemphasis */
*s = GSM_ADD(msr, msr) & 0xFFF8; /* Truncation & Upscaling */
}
S->msr = msr;
}
void Gsm_Decoder (
struct gsm_state * S,
word * LARcr, /* [0..7] IN */
word * Ncr, /* [0..3] IN */
word * bcr, /* [0..3] IN */
word * Mcr, /* [0..3] IN */
word * xmaxcr, /* [0..3] IN */
word * xMcr, /* [0..13*4] IN */
word * s) /* [0..159] OUT */
{
int j, k;
word erp[40], wt[160];
word * drp = S->dp0 + 120;
for (j=0; j <= 3; j++, xmaxcr++, bcr++, Ncr++, Mcr++, xMcr += 13) {
Gsm_RPE_Decoding( /*-S,-*/ *xmaxcr, *Mcr, xMcr, erp );
Gsm_Long_Term_Synthesis_Filtering( S, *Ncr, *bcr, erp, drp );
for (k = 0; k <= 39; k++) wt[ j * 40 + k ] = drp[ k ];
}
Gsm_Short_Term_Synthesis_Filter( S, LARcr, wt, s );
Postprocessing(S, s);
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#ifndef GSM_H
#define GSM_H
#include <stdio.h> /* for FILE * */
/*
* Interface
*/
typedef struct gsm_state * gsm;
typedef short gsm_signal; /* signed 16 bit */
typedef unsigned char gsm_byte;
typedef gsm_byte gsm_frame[33]; /* 33 * 8 bits */
#define GSM_MAGIC 0xD /* 13 kbit/s RPE-LTP */
#define GSM_PATCHLEVEL 10
#define GSM_MINOR 0
#define GSM_MAJOR 1
#define GSM_OPT_VERBOSE 1
#define GSM_OPT_FAST 2
#define GSM_OPT_LTP_CUT 3
#define GSM_OPT_WAV49 4
#define GSM_OPT_FRAME_INDEX 5
#define GSM_OPT_FRAME_CHAIN 6
gsm gsm_create (void);
/* Added for libsndfile : May 6, 2002 */
void gsm_init (gsm);
void gsm_destroy (gsm);
int gsm_print (FILE *, gsm, gsm_byte *);
int gsm_option (gsm, int, int *);
void gsm_encode (gsm, gsm_signal *, gsm_byte *);
int gsm_decode (gsm, gsm_byte *, gsm_signal *);
int gsm_explode (gsm, gsm_byte *, gsm_signal *);
void gsm_implode (gsm, gsm_signal *, gsm_byte *);
#endif /* GSM_H */

View File

@@ -0,0 +1,301 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#ifndef PRIVATE_H
#define PRIVATE_H
/* Added by Erik de Castro Lopo */
#define USE_FLOAT_MUL
#define FAST
#define WAV49
#ifdef __cplusplus
#error "This code is not designed to be compiled with a C++ compiler."
#endif
/* Added by Erik de Castro Lopo */
typedef short word; /* 16 bit signed int */
typedef int longword; /* 32 bit signed int */
typedef unsigned short uword; /* unsigned word */
typedef unsigned int ulongword; /* unsigned longword */
struct gsm_state
{ word dp0[ 280 ] ;
word z1; /* preprocessing.c, Offset_com. */
longword L_z2; /* Offset_com. */
int mp; /* Preemphasis */
word u[8] ; /* short_term_aly_filter.c */
word LARpp[2][8] ; /* */
word j; /* */
word ltp_cut; /* long_term.c, LTP crosscorr. */
word nrp; /* 40 */ /* long_term.c, synthesis */
word v[9] ; /* short_term.c, synthesis */
word msr; /* decoder.c, Postprocessing */
char verbose; /* only used if !NDEBUG */
char fast; /* only used if FAST */
char wav_fmt; /* only used if WAV49 defined */
unsigned char frame_index; /* odd/even chaining */
unsigned char frame_chain; /* half-byte to carry forward */
/* Moved here from code.c where it was defined as static */
word e[50] ;
} ;
typedef struct gsm_state GSM_STATE ;
#define MIN_WORD (-32767 - 1)
#define MAX_WORD 32767
#define MIN_LONGWORD (-2147483647 - 1)
#define MAX_LONGWORD 2147483647
/* Signed arithmetic shift right. */
static inline word
SASR_W (word x, word by)
{ return (x >> by) ;
} /* SASR */
static inline longword
SASR_L (longword x, word by)
{ return (x >> by) ;
} /* SASR */
/*
* Prototypes from add.c
*/
word gsm_mult (word a, word b) ;
longword gsm_L_mult (word a, word b) ;
word gsm_mult_r (word a, word b) ;
word gsm_div (word num, word denum) ;
word gsm_add (word a, word b ) ;
longword gsm_L_add (longword a, longword b ) ;
word gsm_sub (word a, word b) ;
longword gsm_L_sub (longword a, longword b) ;
word gsm_abs (word a) ;
word gsm_norm (longword a ) ;
longword gsm_L_asl (longword a, int n) ;
word gsm_asl (word a, int n) ;
longword gsm_L_asr (longword a, int n) ;
word gsm_asr (word a, int n) ;
/*
* Inlined functions from add.h
*/
static inline longword
GSM_MULT_R (word a, word b)
{ return (((longword) (a)) * ((longword) (b)) + 16384) >> 15 ;
} /* GSM_MULT_R */
static inline longword
GSM_MULT (word a, word b)
{ return (((longword) (a)) * ((longword) (b))) >> 15 ;
} /* GSM_MULT */
static inline longword
GSM_L_MULT (word a, word b)
{ return ((longword) (a)) * ((longword) (b)) << 1 ;
} /* GSM_L_MULT */
static inline longword
GSM_L_ADD (longword a, longword b)
{ ulongword utmp ;
if (a < 0 && b < 0)
{ utmp = (ulongword)-((a) + 1) + (ulongword)-((b) + 1) ;
return (utmp >= (ulongword) MAX_LONGWORD) ? MIN_LONGWORD : -(longword)utmp-2 ;
} ;
if (a > 0 && b > 0)
{ utmp = (ulongword) a + (ulongword) b ;
return (utmp >= (ulongword) MAX_LONGWORD) ? MAX_LONGWORD : utmp ;
} ;
return a + b ;
} /* GSM_L_ADD */
static inline longword
GSM_ADD (word a, word b)
{ longword ltmp ;
ltmp = ((longword) a) + ((longword) b) ;
if (ltmp >= MAX_WORD)
return MAX_WORD ;
if (ltmp <= MIN_WORD)
return MIN_WORD ;
return ltmp ;
} /* GSM_ADD */
static inline longword
GSM_SUB (word a, word b)
{ longword ltmp ;
ltmp = ((longword) a) - ((longword) b) ;
if (ltmp >= MAX_WORD)
ltmp = MAX_WORD ;
else if (ltmp <= MIN_WORD)
ltmp = MIN_WORD ;
return ltmp ;
} /* GSM_SUB */
static inline word
GSM_ABS (word a)
{
if (a > 0)
return a ;
if (a == MIN_WORD)
return MAX_WORD ;
return -a ;
} /* GSM_ADD */
/*
* More prototypes from implementations..
*/
void Gsm_Coder (
struct gsm_state * S,
word * s, /* [0..159] samples IN */
word * LARc, /* [0..7] LAR coefficients OUT */
word * Nc, /* [0..3] LTP lag OUT */
word * bc, /* [0..3] coded LTP gain OUT */
word * Mc, /* [0..3] RPE grid selection OUT */
word * xmaxc,/* [0..3] Coded maximum amplitude OUT */
word * xMc) ;/* [13*4] normalized RPE samples OUT */
void Gsm_Long_Term_Predictor ( /* 4x for 160 samples */
struct gsm_state * S,
word * d, /* [0..39] residual signal IN */
word * dp, /* [-120..-1] d' IN */
word * e, /* [0..40] OUT */
word * dpp, /* [0..40] OUT */
word * Nc, /* correlation lag OUT */
word * bc) ; /* gain factor OUT */
void Gsm_LPC_Analysis (
struct gsm_state * S,
word * s, /* 0..159 signals IN/OUT */
word * LARc) ; /* 0..7 LARc's OUT */
void Gsm_Preprocess (
struct gsm_state * S,
word * s, word * so) ;
void Gsm_Encoding (
struct gsm_state * S,
word * e,
word * ep,
word * xmaxc,
word * Mc,
word * xMc) ;
void Gsm_Short_Term_Analysis_Filter (
struct gsm_state * S,
word * LARc, /* coded log area ratio [0..7] IN */
word * d) ; /* st res. signal [0..159] IN/OUT */
void Gsm_Decoder (
struct gsm_state * S,
word * LARcr, /* [0..7] IN */
word * Ncr, /* [0..3] IN */
word * bcr, /* [0..3] IN */
word * Mcr, /* [0..3] IN */
word * xmaxcr, /* [0..3] IN */
word * xMcr, /* [0..13*4] IN */
word * s) ; /* [0..159] OUT */
void Gsm_Decoding (
struct gsm_state * S,
word xmaxcr,
word Mcr,
word * xMcr, /* [0..12] IN */
word * erp) ; /* [0..39] OUT */
void Gsm_Long_Term_Synthesis_Filtering (
struct gsm_state* S,
word Ncr,
word bcr,
word * erp, /* [0..39] IN */
word * drp) ; /* [-120..-1] IN, [0..40] OUT */
void Gsm_RPE_Decoding (
/*-struct gsm_state *S,-*/
word xmaxcr,
word Mcr,
word * xMcr, /* [0..12], 3 bits IN */
word * erp) ; /* [0..39] OUT */
void Gsm_RPE_Encoding (
/*-struct gsm_state * S,-*/
word * e, /* -5..-1][0..39][40..44 IN/OUT */
word * xmaxc, /* OUT */
word * Mc, /* OUT */
word * xMc) ; /* [0..12] OUT */
void Gsm_Short_Term_Synthesis_Filter (
struct gsm_state * S,
word * LARcr, /* log area ratios [0..7] IN */
word * drp, /* received d [0...39] IN */
word * s) ; /* signal s [0..159] OUT */
void Gsm_Update_of_reconstructed_short_time_residual_signal (
word * dpp, /* [0...39] IN */
word * ep, /* [0...39] IN */
word * dp) ; /* [-120...-1] IN/OUT */
/*
* Tables from table.c
*/
#ifndef GSM_TABLE_C
extern word gsm_A [8], gsm_B [8], gsm_MIC [8], gsm_MAC [8] ;
extern word gsm_INVA [8] ;
extern word gsm_DLB [4], gsm_QLB [4] ;
extern word gsm_H [11] ;
extern word gsm_NRFAC [8] ;
extern word gsm_FAC [8] ;
#endif /* GSM_TABLE_C */
/*
* Debugging
*/
#ifdef NDEBUG
# define gsm_debug_words(a, b, c, d) /* nil */
# define gsm_debug_longwords(a, b, c, d) /* nil */
# define gsm_debug_word(a, b) /* nil */
# define gsm_debug_longword(a, b) /* nil */
#else /* !NDEBUG => DEBUG */
void gsm_debug_words (char * name, int, int, word *) ;
void gsm_debug_longwords (char * name, int, int, longword *) ;
void gsm_debug_longword (char * name, longword) ;
void gsm_debug_word (char * name, word) ;
#endif /* !NDEBUG */
#endif /* PRIVATE_H */

View File

@@ -0,0 +1,37 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gsm.h"
#include "gsm610_priv.h"
gsm gsm_create (void)
{
gsm r;
r = malloc (sizeof(struct gsm_state));
if (!r) return r;
memset((char *)r, 0, sizeof (struct gsm_state));
r->nrp = 40;
return r;
}
/* Added for libsndfile : May 6, 2002. Not sure if it works. */
void gsm_init (gsm state)
{
memset (state, 0, sizeof (struct gsm_state)) ;
state->nrp = 40 ;
}

View File

@@ -0,0 +1,359 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include "gsm610_priv.h"
#include "gsm.h"
int gsm_decode (gsm s, gsm_byte * c, gsm_signal * target)
{
word LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4];
#ifdef WAV49
if (s->wav_fmt) {
uword sr = 0;
s->frame_index = !s->frame_index;
if (s->frame_index) {
sr = *c++;
LARc[0] = sr & 0x3f; sr >>= 6;
sr |= (uword)*c++ << 2;
LARc[1] = sr & 0x3f; sr >>= 6;
sr |= (uword)*c++ << 4;
LARc[2] = sr & 0x1f; sr >>= 5;
LARc[3] = sr & 0x1f; sr >>= 5;
sr |= (uword)*c++ << 2;
LARc[4] = sr & 0xf; sr >>= 4;
LARc[5] = sr & 0xf; sr >>= 4;
sr |= (uword)*c++ << 2; /* 5 */
LARc[6] = sr & 0x7; sr >>= 3;
LARc[7] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 4;
Nc[0] = sr & 0x7f; sr >>= 7;
bc[0] = sr & 0x3; sr >>= 2;
Mc[0] = sr & 0x3; sr >>= 2;
sr |= (uword)*c++ << 1;
xmaxc[0] = sr & 0x3f; sr >>= 6;
xmc[0] = sr & 0x7; sr >>= 3;
sr = *c++;
xmc[1] = sr & 0x7; sr >>= 3;
xmc[2] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 2;
xmc[3] = sr & 0x7; sr >>= 3;
xmc[4] = sr & 0x7; sr >>= 3;
xmc[5] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 1; /* 10 */
xmc[6] = sr & 0x7; sr >>= 3;
xmc[7] = sr & 0x7; sr >>= 3;
xmc[8] = sr & 0x7; sr >>= 3;
sr = *c++;
xmc[9] = sr & 0x7; sr >>= 3;
xmc[10] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 2;
xmc[11] = sr & 0x7; sr >>= 3;
xmc[12] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 4;
Nc[1] = sr & 0x7f; sr >>= 7;
bc[1] = sr & 0x3; sr >>= 2;
Mc[1] = sr & 0x3; sr >>= 2;
sr |= (uword)*c++ << 1;
xmaxc[1] = sr & 0x3f; sr >>= 6;
xmc[13] = sr & 0x7; sr >>= 3;
sr = *c++; /* 15 */
xmc[14] = sr & 0x7; sr >>= 3;
xmc[15] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 2;
xmc[16] = sr & 0x7; sr >>= 3;
xmc[17] = sr & 0x7; sr >>= 3;
xmc[18] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 1;
xmc[19] = sr & 0x7; sr >>= 3;
xmc[20] = sr & 0x7; sr >>= 3;
xmc[21] = sr & 0x7; sr >>= 3;
sr = *c++;
xmc[22] = sr & 0x7; sr >>= 3;
xmc[23] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 2;
xmc[24] = sr & 0x7; sr >>= 3;
xmc[25] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 4; /* 20 */
Nc[2] = sr & 0x7f; sr >>= 7;
bc[2] = sr & 0x3; sr >>= 2;
Mc[2] = sr & 0x3; sr >>= 2;
sr |= (uword)*c++ << 1;
xmaxc[2] = sr & 0x3f; sr >>= 6;
xmc[26] = sr & 0x7; sr >>= 3;
sr = *c++;
xmc[27] = sr & 0x7; sr >>= 3;
xmc[28] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 2;
xmc[29] = sr & 0x7; sr >>= 3;
xmc[30] = sr & 0x7; sr >>= 3;
xmc[31] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 1;
xmc[32] = sr & 0x7; sr >>= 3;
xmc[33] = sr & 0x7; sr >>= 3;
xmc[34] = sr & 0x7; sr >>= 3;
sr = *c++; /* 25 */
xmc[35] = sr & 0x7; sr >>= 3;
xmc[36] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 2;
xmc[37] = sr & 0x7; sr >>= 3;
xmc[38] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 4;
Nc[3] = sr & 0x7f; sr >>= 7;
bc[3] = sr & 0x3; sr >>= 2;
Mc[3] = sr & 0x3; sr >>= 2;
sr |= (uword)*c++ << 1;
xmaxc[3] = sr & 0x3f; sr >>= 6;
xmc[39] = sr & 0x7; sr >>= 3;
sr = *c++;
xmc[40] = sr & 0x7; sr >>= 3;
xmc[41] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 2; /* 30 */
xmc[42] = sr & 0x7; sr >>= 3;
xmc[43] = sr & 0x7; sr >>= 3;
xmc[44] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 1;
xmc[45] = sr & 0x7; sr >>= 3;
xmc[46] = sr & 0x7; sr >>= 3;
xmc[47] = sr & 0x7; sr >>= 3;
sr = *c++;
xmc[48] = sr & 0x7; sr >>= 3;
xmc[49] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 2;
xmc[50] = sr & 0x7; sr >>= 3;
xmc[51] = sr & 0x7; sr >>= 3;
s->frame_chain = sr & 0xf;
}
else {
sr = s->frame_chain;
sr |= (uword)*c++ << 4; /* 1 */
LARc[0] = sr & 0x3f; sr >>= 6;
LARc[1] = sr & 0x3f; sr >>= 6;
sr = *c++;
LARc[2] = sr & 0x1f; sr >>= 5;
sr |= (uword)*c++ << 3;
LARc[3] = sr & 0x1f; sr >>= 5;
LARc[4] = sr & 0xf; sr >>= 4;
sr |= (uword)*c++ << 2;
LARc[5] = sr & 0xf; sr >>= 4;
LARc[6] = sr & 0x7; sr >>= 3;
LARc[7] = sr & 0x7; sr >>= 3;
sr = *c++; /* 5 */
Nc[0] = sr & 0x7f; sr >>= 7;
sr |= (uword)*c++ << 1;
bc[0] = sr & 0x3; sr >>= 2;
Mc[0] = sr & 0x3; sr >>= 2;
sr |= (uword)*c++ << 5;
xmaxc[0] = sr & 0x3f; sr >>= 6;
xmc[0] = sr & 0x7; sr >>= 3;
xmc[1] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 1;
xmc[2] = sr & 0x7; sr >>= 3;
xmc[3] = sr & 0x7; sr >>= 3;
xmc[4] = sr & 0x7; sr >>= 3;
sr = *c++;
xmc[5] = sr & 0x7; sr >>= 3;
xmc[6] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 2; /* 10 */
xmc[7] = sr & 0x7; sr >>= 3;
xmc[8] = sr & 0x7; sr >>= 3;
xmc[9] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 1;
xmc[10] = sr & 0x7; sr >>= 3;
xmc[11] = sr & 0x7; sr >>= 3;
xmc[12] = sr & 0x7; sr >>= 3;
sr = *c++;
Nc[1] = sr & 0x7f; sr >>= 7;
sr |= (uword)*c++ << 1;
bc[1] = sr & 0x3; sr >>= 2;
Mc[1] = sr & 0x3; sr >>= 2;
sr |= (uword)*c++ << 5;
xmaxc[1] = sr & 0x3f; sr >>= 6;
xmc[13] = sr & 0x7; sr >>= 3;
xmc[14] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 1; /* 15 */
xmc[15] = sr & 0x7; sr >>= 3;
xmc[16] = sr & 0x7; sr >>= 3;
xmc[17] = sr & 0x7; sr >>= 3;
sr = *c++;
xmc[18] = sr & 0x7; sr >>= 3;
xmc[19] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 2;
xmc[20] = sr & 0x7; sr >>= 3;
xmc[21] = sr & 0x7; sr >>= 3;
xmc[22] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 1;
xmc[23] = sr & 0x7; sr >>= 3;
xmc[24] = sr & 0x7; sr >>= 3;
xmc[25] = sr & 0x7; sr >>= 3;
sr = *c++;
Nc[2] = sr & 0x7f; sr >>= 7;
sr |= (uword)*c++ << 1; /* 20 */
bc[2] = sr & 0x3; sr >>= 2;
Mc[2] = sr & 0x3; sr >>= 2;
sr |= (uword)*c++ << 5;
xmaxc[2] = sr & 0x3f; sr >>= 6;
xmc[26] = sr & 0x7; sr >>= 3;
xmc[27] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 1;
xmc[28] = sr & 0x7; sr >>= 3;
xmc[29] = sr & 0x7; sr >>= 3;
xmc[30] = sr & 0x7; sr >>= 3;
sr = *c++;
xmc[31] = sr & 0x7; sr >>= 3;
xmc[32] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 2;
xmc[33] = sr & 0x7; sr >>= 3;
xmc[34] = sr & 0x7; sr >>= 3;
xmc[35] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 1; /* 25 */
xmc[36] = sr & 0x7; sr >>= 3;
xmc[37] = sr & 0x7; sr >>= 3;
xmc[38] = sr & 0x7; sr >>= 3;
sr = *c++;
Nc[3] = sr & 0x7f; sr >>= 7;
sr |= (uword)*c++ << 1;
bc[3] = sr & 0x3; sr >>= 2;
Mc[3] = sr & 0x3; sr >>= 2;
sr |= (uword)*c++ << 5;
xmaxc[3] = sr & 0x3f; sr >>= 6;
xmc[39] = sr & 0x7; sr >>= 3;
xmc[40] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 1;
xmc[41] = sr & 0x7; sr >>= 3;
xmc[42] = sr & 0x7; sr >>= 3;
xmc[43] = sr & 0x7; sr >>= 3;
sr = *c++; /* 30 */
xmc[44] = sr & 0x7; sr >>= 3;
xmc[45] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 2;
xmc[46] = sr & 0x7; sr >>= 3;
xmc[47] = sr & 0x7; sr >>= 3;
xmc[48] = sr & 0x7; sr >>= 3;
sr |= (uword)*c++ << 1;
xmc[49] = sr & 0x7; sr >>= 3;
xmc[50] = sr & 0x7; sr >>= 3;
xmc[51] = sr & 0x7; sr >>= 3;
}
}
else
#endif
{
/* GSM_MAGIC = (*c >> 4) & 0xF; */
if (((*c >> 4) & 0x0F) != GSM_MAGIC) return -1;
LARc[0] = (*c++ & 0xF) << 2; /* 1 */
LARc[0] |= (*c >> 6) & 0x3;
LARc[1] = *c++ & 0x3F;
LARc[2] = (*c >> 3) & 0x1F;
LARc[3] = (*c++ & 0x7) << 2;
LARc[3] |= (*c >> 6) & 0x3;
LARc[4] = (*c >> 2) & 0xF;
LARc[5] = (*c++ & 0x3) << 2;
LARc[5] |= (*c >> 6) & 0x3;
LARc[6] = (*c >> 3) & 0x7;
LARc[7] = *c++ & 0x7;
Nc[0] = (*c >> 1) & 0x7F;
bc[0] = (*c++ & 0x1) << 1;
bc[0] |= (*c >> 7) & 0x1;
Mc[0] = (*c >> 5) & 0x3;
xmaxc[0] = (*c++ & 0x1F) << 1;
xmaxc[0] |= (*c >> 7) & 0x1;
xmc[0] = (*c >> 4) & 0x7;
xmc[1] = (*c >> 1) & 0x7;
xmc[2] = (*c++ & 0x1) << 2;
xmc[2] |= (*c >> 6) & 0x3;
xmc[3] = (*c >> 3) & 0x7;
xmc[4] = *c++ & 0x7;
xmc[5] = (*c >> 5) & 0x7;
xmc[6] = (*c >> 2) & 0x7;
xmc[7] = (*c++ & 0x3) << 1; /* 10 */
xmc[7] |= (*c >> 7) & 0x1;
xmc[8] = (*c >> 4) & 0x7;
xmc[9] = (*c >> 1) & 0x7;
xmc[10] = (*c++ & 0x1) << 2;
xmc[10] |= (*c >> 6) & 0x3;
xmc[11] = (*c >> 3) & 0x7;
xmc[12] = *c++ & 0x7;
Nc[1] = (*c >> 1) & 0x7F;
bc[1] = (*c++ & 0x1) << 1;
bc[1] |= (*c >> 7) & 0x1;
Mc[1] = (*c >> 5) & 0x3;
xmaxc[1] = (*c++ & 0x1F) << 1;
xmaxc[1] |= (*c >> 7) & 0x1;
xmc[13] = (*c >> 4) & 0x7;
xmc[14] = (*c >> 1) & 0x7;
xmc[15] = (*c++ & 0x1) << 2;
xmc[15] |= (*c >> 6) & 0x3;
xmc[16] = (*c >> 3) & 0x7;
xmc[17] = *c++ & 0x7;
xmc[18] = (*c >> 5) & 0x7;
xmc[19] = (*c >> 2) & 0x7;
xmc[20] = (*c++ & 0x3) << 1;
xmc[20] |= (*c >> 7) & 0x1;
xmc[21] = (*c >> 4) & 0x7;
xmc[22] = (*c >> 1) & 0x7;
xmc[23] = (*c++ & 0x1) << 2;
xmc[23] |= (*c >> 6) & 0x3;
xmc[24] = (*c >> 3) & 0x7;
xmc[25] = *c++ & 0x7;
Nc[2] = (*c >> 1) & 0x7F;
bc[2] = (*c++ & 0x1) << 1; /* 20 */
bc[2] |= (*c >> 7) & 0x1;
Mc[2] = (*c >> 5) & 0x3;
xmaxc[2] = (*c++ & 0x1F) << 1;
xmaxc[2] |= (*c >> 7) & 0x1;
xmc[26] = (*c >> 4) & 0x7;
xmc[27] = (*c >> 1) & 0x7;
xmc[28] = (*c++ & 0x1) << 2;
xmc[28] |= (*c >> 6) & 0x3;
xmc[29] = (*c >> 3) & 0x7;
xmc[30] = *c++ & 0x7;
xmc[31] = (*c >> 5) & 0x7;
xmc[32] = (*c >> 2) & 0x7;
xmc[33] = (*c++ & 0x3) << 1;
xmc[33] |= (*c >> 7) & 0x1;
xmc[34] = (*c >> 4) & 0x7;
xmc[35] = (*c >> 1) & 0x7;
xmc[36] = (*c++ & 0x1) << 2;
xmc[36] |= (*c >> 6) & 0x3;
xmc[37] = (*c >> 3) & 0x7;
xmc[38] = *c++ & 0x7;
Nc[3] = (*c >> 1) & 0x7F;
bc[3] = (*c++ & 0x1) << 1;
bc[3] |= (*c >> 7) & 0x1;
Mc[3] = (*c >> 5) & 0x3;
xmaxc[3] = (*c++ & 0x1F) << 1;
xmaxc[3] |= (*c >> 7) & 0x1;
xmc[39] = (*c >> 4) & 0x7;
xmc[40] = (*c >> 1) & 0x7;
xmc[41] = (*c++ & 0x1) << 2;
xmc[41] |= (*c >> 6) & 0x3;
xmc[42] = (*c >> 3) & 0x7;
xmc[43] = *c++ & 0x7; /* 30 */
xmc[44] = (*c >> 5) & 0x7;
xmc[45] = (*c >> 2) & 0x7;
xmc[46] = (*c++ & 0x3) << 1;
xmc[46] |= (*c >> 7) & 0x1;
xmc[47] = (*c >> 4) & 0x7;
xmc[48] = (*c >> 1) & 0x7;
xmc[49] = (*c++ & 0x1) << 2;
xmc[49] |= (*c >> 6) & 0x3;
xmc[50] = (*c >> 3) & 0x7;
xmc[51] = *c & 0x7; /* 33 */
}
Gsm_Decoder(s, LARc, Nc, bc, Mc, xmaxc, xmc, target);
return 0;
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include "gsm.h"
#include "config.h"
#ifdef HAS_STDLIB_H
# include <stdlib.h>
#else
# ifdef HAS_MALLOC_H
# include <malloc.h>
# else
extern void free();
# endif
#endif
void gsm_destroy (gsm S)
{
if (S) free((char *)S);
}

View File

@@ -0,0 +1,449 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include "gsm610_priv.h"
#include "gsm.h"
void gsm_encode (gsm s, gsm_signal * source, gsm_byte * c)
{
word LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4];
Gsm_Coder(s, source, LARc, Nc, bc, Mc, xmaxc, xmc);
/* variable size
GSM_MAGIC 4
LARc[0] 6
LARc[1] 6
LARc[2] 5
LARc[3] 5
LARc[4] 4
LARc[5] 4
LARc[6] 3
LARc[7] 3
Nc[0] 7
bc[0] 2
Mc[0] 2
xmaxc[0] 6
xmc[0] 3
xmc[1] 3
xmc[2] 3
xmc[3] 3
xmc[4] 3
xmc[5] 3
xmc[6] 3
xmc[7] 3
xmc[8] 3
xmc[9] 3
xmc[10] 3
xmc[11] 3
xmc[12] 3
Nc[1] 7
bc[1] 2
Mc[1] 2
xmaxc[1] 6
xmc[13] 3
xmc[14] 3
xmc[15] 3
xmc[16] 3
xmc[17] 3
xmc[18] 3
xmc[19] 3
xmc[20] 3
xmc[21] 3
xmc[22] 3
xmc[23] 3
xmc[24] 3
xmc[25] 3
Nc[2] 7
bc[2] 2
Mc[2] 2
xmaxc[2] 6
xmc[26] 3
xmc[27] 3
xmc[28] 3
xmc[29] 3
xmc[30] 3
xmc[31] 3
xmc[32] 3
xmc[33] 3
xmc[34] 3
xmc[35] 3
xmc[36] 3
xmc[37] 3
xmc[38] 3
Nc[3] 7
bc[3] 2
Mc[3] 2
xmaxc[3] 6
xmc[39] 3
xmc[40] 3
xmc[41] 3
xmc[42] 3
xmc[43] 3
xmc[44] 3
xmc[45] 3
xmc[46] 3
xmc[47] 3
xmc[48] 3
xmc[49] 3
xmc[50] 3
xmc[51] 3
*/
#ifdef WAV49
if (s->wav_fmt) {
s->frame_index = !s->frame_index;
if (s->frame_index) {
uword sr;
sr = 0;
sr = sr >> 6 | LARc[0] << 10;
sr = sr >> 6 | LARc[1] << 10;
*c++ = sr >> 4;
sr = sr >> 5 | LARc[2] << 11;
*c++ = sr >> 7;
sr = sr >> 5 | LARc[3] << 11;
sr = sr >> 4 | LARc[4] << 12;
*c++ = sr >> 6;
sr = sr >> 4 | LARc[5] << 12;
sr = sr >> 3 | LARc[6] << 13;
*c++ = sr >> 7;
sr = sr >> 3 | LARc[7] << 13;
sr = sr >> 7 | Nc[0] << 9;
*c++ = sr >> 5;
sr = sr >> 2 | bc[0] << 14;
sr = sr >> 2 | Mc[0] << 14;
sr = sr >> 6 | xmaxc[0] << 10;
*c++ = sr >> 3;
sr = sr >> 3 | xmc[0] << 13;
*c++ = sr >> 8;
sr = sr >> 3 | xmc[1] << 13;
sr = sr >> 3 | xmc[2] << 13;
sr = sr >> 3 | xmc[3] << 13;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[4] << 13;
sr = sr >> 3 | xmc[5] << 13;
sr = sr >> 3 | xmc[6] << 13;
*c++ = sr >> 6;
sr = sr >> 3 | xmc[7] << 13;
sr = sr >> 3 | xmc[8] << 13;
*c++ = sr >> 8;
sr = sr >> 3 | xmc[9] << 13;
sr = sr >> 3 | xmc[10] << 13;
sr = sr >> 3 | xmc[11] << 13;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[12] << 13;
sr = sr >> 7 | Nc[1] << 9;
*c++ = sr >> 5;
sr = sr >> 2 | bc[1] << 14;
sr = sr >> 2 | Mc[1] << 14;
sr = sr >> 6 | xmaxc[1] << 10;
*c++ = sr >> 3;
sr = sr >> 3 | xmc[13] << 13;
*c++ = sr >> 8;
sr = sr >> 3 | xmc[14] << 13;
sr = sr >> 3 | xmc[15] << 13;
sr = sr >> 3 | xmc[16] << 13;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[17] << 13;
sr = sr >> 3 | xmc[18] << 13;
sr = sr >> 3 | xmc[19] << 13;
*c++ = sr >> 6;
sr = sr >> 3 | xmc[20] << 13;
sr = sr >> 3 | xmc[21] << 13;
*c++ = sr >> 8;
sr = sr >> 3 | xmc[22] << 13;
sr = sr >> 3 | xmc[23] << 13;
sr = sr >> 3 | xmc[24] << 13;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[25] << 13;
sr = sr >> 7 | Nc[2] << 9;
*c++ = sr >> 5;
sr = sr >> 2 | bc[2] << 14;
sr = sr >> 2 | Mc[2] << 14;
sr = sr >> 6 | xmaxc[2] << 10;
*c++ = sr >> 3;
sr = sr >> 3 | xmc[26] << 13;
*c++ = sr >> 8;
sr = sr >> 3 | xmc[27] << 13;
sr = sr >> 3 | xmc[28] << 13;
sr = sr >> 3 | xmc[29] << 13;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[30] << 13;
sr = sr >> 3 | xmc[31] << 13;
sr = sr >> 3 | xmc[32] << 13;
*c++ = sr >> 6;
sr = sr >> 3 | xmc[33] << 13;
sr = sr >> 3 | xmc[34] << 13;
*c++ = sr >> 8;
sr = sr >> 3 | xmc[35] << 13;
sr = sr >> 3 | xmc[36] << 13;
sr = sr >> 3 | xmc[37] << 13;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[38] << 13;
sr = sr >> 7 | Nc[3] << 9;
*c++ = sr >> 5;
sr = sr >> 2 | bc[3] << 14;
sr = sr >> 2 | Mc[3] << 14;
sr = sr >> 6 | xmaxc[3] << 10;
*c++ = sr >> 3;
sr = sr >> 3 | xmc[39] << 13;
*c++ = sr >> 8;
sr = sr >> 3 | xmc[40] << 13;
sr = sr >> 3 | xmc[41] << 13;
sr = sr >> 3 | xmc[42] << 13;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[43] << 13;
sr = sr >> 3 | xmc[44] << 13;
sr = sr >> 3 | xmc[45] << 13;
*c++ = sr >> 6;
sr = sr >> 3 | xmc[46] << 13;
sr = sr >> 3 | xmc[47] << 13;
*c++ = sr >> 8;
sr = sr >> 3 | xmc[48] << 13;
sr = sr >> 3 | xmc[49] << 13;
sr = sr >> 3 | xmc[50] << 13;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[51] << 13;
sr = sr >> 4;
*c = sr >> 8;
s->frame_chain = *c;
}
else {
uword sr;
sr = 0;
sr = sr >> 4 | s->frame_chain << 12;
sr = sr >> 6 | LARc[0] << 10;
*c++ = sr >> 6;
sr = sr >> 6 | LARc[1] << 10;
*c++ = sr >> 8;
sr = sr >> 5 | LARc[2] << 11;
sr = sr >> 5 | LARc[3] << 11;
*c++ = sr >> 6;
sr = sr >> 4 | LARc[4] << 12;
sr = sr >> 4 | LARc[5] << 12;
*c++ = sr >> 6;
sr = sr >> 3 | LARc[6] << 13;
sr = sr >> 3 | LARc[7] << 13;
*c++ = sr >> 8;
sr = sr >> 7 | Nc[0] << 9;
sr = sr >> 2 | bc[0] << 14;
*c++ = sr >> 7;
sr = sr >> 2 | Mc[0] << 14;
sr = sr >> 6 | xmaxc[0] << 10;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[0] << 13;
sr = sr >> 3 | xmc[1] << 13;
sr = sr >> 3 | xmc[2] << 13;
*c++ = sr >> 6;
sr = sr >> 3 | xmc[3] << 13;
sr = sr >> 3 | xmc[4] << 13;
*c++ = sr >> 8;
sr = sr >> 3 | xmc[5] << 13;
sr = sr >> 3 | xmc[6] << 13;
sr = sr >> 3 | xmc[7] << 13;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[8] << 13;
sr = sr >> 3 | xmc[9] << 13;
sr = sr >> 3 | xmc[10] << 13;
*c++ = sr >> 6;
sr = sr >> 3 | xmc[11] << 13;
sr = sr >> 3 | xmc[12] << 13;
*c++ = sr >> 8;
sr = sr >> 7 | Nc[1] << 9;
sr = sr >> 2 | bc[1] << 14;
*c++ = sr >> 7;
sr = sr >> 2 | Mc[1] << 14;
sr = sr >> 6 | xmaxc[1] << 10;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[13] << 13;
sr = sr >> 3 | xmc[14] << 13;
sr = sr >> 3 | xmc[15] << 13;
*c++ = sr >> 6;
sr = sr >> 3 | xmc[16] << 13;
sr = sr >> 3 | xmc[17] << 13;
*c++ = sr >> 8;
sr = sr >> 3 | xmc[18] << 13;
sr = sr >> 3 | xmc[19] << 13;
sr = sr >> 3 | xmc[20] << 13;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[21] << 13;
sr = sr >> 3 | xmc[22] << 13;
sr = sr >> 3 | xmc[23] << 13;
*c++ = sr >> 6;
sr = sr >> 3 | xmc[24] << 13;
sr = sr >> 3 | xmc[25] << 13;
*c++ = sr >> 8;
sr = sr >> 7 | Nc[2] << 9;
sr = sr >> 2 | bc[2] << 14;
*c++ = sr >> 7;
sr = sr >> 2 | Mc[2] << 14;
sr = sr >> 6 | xmaxc[2] << 10;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[26] << 13;
sr = sr >> 3 | xmc[27] << 13;
sr = sr >> 3 | xmc[28] << 13;
*c++ = sr >> 6;
sr = sr >> 3 | xmc[29] << 13;
sr = sr >> 3 | xmc[30] << 13;
*c++ = sr >> 8;
sr = sr >> 3 | xmc[31] << 13;
sr = sr >> 3 | xmc[32] << 13;
sr = sr >> 3 | xmc[33] << 13;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[34] << 13;
sr = sr >> 3 | xmc[35] << 13;
sr = sr >> 3 | xmc[36] << 13;
*c++ = sr >> 6;
sr = sr >> 3 | xmc[37] << 13;
sr = sr >> 3 | xmc[38] << 13;
*c++ = sr >> 8;
sr = sr >> 7 | Nc[3] << 9;
sr = sr >> 2 | bc[3] << 14;
*c++ = sr >> 7;
sr = sr >> 2 | Mc[3] << 14;
sr = sr >> 6 | xmaxc[3] << 10;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[39] << 13;
sr = sr >> 3 | xmc[40] << 13;
sr = sr >> 3 | xmc[41] << 13;
*c++ = sr >> 6;
sr = sr >> 3 | xmc[42] << 13;
sr = sr >> 3 | xmc[43] << 13;
*c++ = sr >> 8;
sr = sr >> 3 | xmc[44] << 13;
sr = sr >> 3 | xmc[45] << 13;
sr = sr >> 3 | xmc[46] << 13;
*c++ = sr >> 7;
sr = sr >> 3 | xmc[47] << 13;
sr = sr >> 3 | xmc[48] << 13;
sr = sr >> 3 | xmc[49] << 13;
*c++ = sr >> 6;
sr = sr >> 3 | xmc[50] << 13;
sr = sr >> 3 | xmc[51] << 13;
*c++ = sr >> 8;
}
}
else
#endif /* WAV49 */
{
*c++ = ((GSM_MAGIC & 0xF) << 4) /* 1 */
| ((LARc[0] >> 2) & 0xF);
*c++ = ((LARc[0] & 0x3) << 6)
| (LARc[1] & 0x3F);
*c++ = ((LARc[2] & 0x1F) << 3)
| ((LARc[3] >> 2) & 0x7);
*c++ = ((LARc[3] & 0x3) << 6)
| ((LARc[4] & 0xF) << 2)
| ((LARc[5] >> 2) & 0x3);
*c++ = ((LARc[5] & 0x3) << 6)
| ((LARc[6] & 0x7) << 3)
| (LARc[7] & 0x7);
*c++ = ((Nc[0] & 0x7F) << 1)
| ((bc[0] >> 1) & 0x1);
*c++ = ((bc[0] & 0x1) << 7)
| ((Mc[0] & 0x3) << 5)
| ((xmaxc[0] >> 1) & 0x1F);
*c++ = ((xmaxc[0] & 0x1) << 7)
| ((xmc[0] & 0x7) << 4)
| ((xmc[1] & 0x7) << 1)
| ((xmc[2] >> 2) & 0x1);
*c++ = ((xmc[2] & 0x3) << 6)
| ((xmc[3] & 0x7) << 3)
| (xmc[4] & 0x7);
*c++ = ((xmc[5] & 0x7) << 5) /* 10 */
| ((xmc[6] & 0x7) << 2)
| ((xmc[7] >> 1) & 0x3);
*c++ = ((xmc[7] & 0x1) << 7)
| ((xmc[8] & 0x7) << 4)
| ((xmc[9] & 0x7) << 1)
| ((xmc[10] >> 2) & 0x1);
*c++ = ((xmc[10] & 0x3) << 6)
| ((xmc[11] & 0x7) << 3)
| (xmc[12] & 0x7);
*c++ = ((Nc[1] & 0x7F) << 1)
| ((bc[1] >> 1) & 0x1);
*c++ = ((bc[1] & 0x1) << 7)
| ((Mc[1] & 0x3) << 5)
| ((xmaxc[1] >> 1) & 0x1F);
*c++ = ((xmaxc[1] & 0x1) << 7)
| ((xmc[13] & 0x7) << 4)
| ((xmc[14] & 0x7) << 1)
| ((xmc[15] >> 2) & 0x1);
*c++ = ((xmc[15] & 0x3) << 6)
| ((xmc[16] & 0x7) << 3)
| (xmc[17] & 0x7);
*c++ = ((xmc[18] & 0x7) << 5)
| ((xmc[19] & 0x7) << 2)
| ((xmc[20] >> 1) & 0x3);
*c++ = ((xmc[20] & 0x1) << 7)
| ((xmc[21] & 0x7) << 4)
| ((xmc[22] & 0x7) << 1)
| ((xmc[23] >> 2) & 0x1);
*c++ = ((xmc[23] & 0x3) << 6)
| ((xmc[24] & 0x7) << 3)
| (xmc[25] & 0x7);
*c++ = ((Nc[2] & 0x7F) << 1) /* 20 */
| ((bc[2] >> 1) & 0x1);
*c++ = ((bc[2] & 0x1) << 7)
| ((Mc[2] & 0x3) << 5)
| ((xmaxc[2] >> 1) & 0x1F);
*c++ = ((xmaxc[2] & 0x1) << 7)
| ((xmc[26] & 0x7) << 4)
| ((xmc[27] & 0x7) << 1)
| ((xmc[28] >> 2) & 0x1);
*c++ = ((xmc[28] & 0x3) << 6)
| ((xmc[29] & 0x7) << 3)
| (xmc[30] & 0x7);
*c++ = ((xmc[31] & 0x7) << 5)
| ((xmc[32] & 0x7) << 2)
| ((xmc[33] >> 1) & 0x3);
*c++ = ((xmc[33] & 0x1) << 7)
| ((xmc[34] & 0x7) << 4)
| ((xmc[35] & 0x7) << 1)
| ((xmc[36] >> 2) & 0x1);
*c++ = ((xmc[36] & 0x3) << 6)
| ((xmc[37] & 0x7) << 3)
| (xmc[38] & 0x7);
*c++ = ((Nc[3] & 0x7F) << 1)
| ((bc[3] >> 1) & 0x1);
*c++ = ((bc[3] & 0x1) << 7)
| ((Mc[3] & 0x3) << 5)
| ((xmaxc[3] >> 1) & 0x1F);
*c++ = ((xmaxc[3] & 0x1) << 7)
| ((xmc[39] & 0x7) << 4)
| ((xmc[40] & 0x7) << 1)
| ((xmc[41] >> 2) & 0x1);
*c++ = ((xmc[41] & 0x3) << 6) /* 30 */
| ((xmc[42] & 0x7) << 3)
| (xmc[43] & 0x7);
*c++ = ((xmc[44] & 0x7) << 5)
| ((xmc[45] & 0x7) << 2)
| ((xmc[46] >> 1) & 0x3);
*c++ = ((xmc[46] & 0x1) << 7)
| ((xmc[47] & 0x7) << 4)
| ((xmc[48] & 0x7) << 1)
| ((xmc[49] >> 2) & 0x1);
*c++ = ((xmc[49] & 0x3) << 6)
| ((xmc[50] & 0x7) << 3)
| (xmc[51] & 0x7);
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include "gsm610_priv.h"
#include "gsm.h"
int gsm_option (gsm r, int opt, int * val)
{
int result = -1;
switch (opt) {
case GSM_OPT_LTP_CUT:
#ifdef LTP_CUT
result = r->ltp_cut;
if (val) r->ltp_cut = *val;
#endif
break;
case GSM_OPT_VERBOSE:
#ifndef NDEBUG
result = r->verbose;
if (val) r->verbose = *val;
#endif
break;
case GSM_OPT_FAST:
#if defined(FAST) && defined(USE_FLOAT_MUL)
result = r->fast;
if (val) r->fast = !!*val;
#endif
break;
case GSM_OPT_FRAME_CHAIN:
#ifdef WAV49
result = r->frame_chain;
if (val) r->frame_chain = *val;
#endif
break;
case GSM_OPT_FRAME_INDEX:
#ifdef WAV49
result = r->frame_index;
if (val) r->frame_index = *val;
#endif
break;
case GSM_OPT_WAV49:
#ifdef WAV49
result = r->wav_fmt;
if (val) r->wav_fmt = !!*val;
#endif
break;
default:
break;
}
return result;
}

View File

@@ -0,0 +1,959 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include <stdio.h>
#include <assert.h>
#include "gsm610_priv.h"
/*
* 4.2.11 .. 4.2.12 LONG TERM PREDICTOR (LTP) SECTION
*/
/*
* This module computes the LTP gain (bc) and the LTP lag (Nc)
* for the long term analysis filter. This is done by calculating a
* maximum of the cross-correlation function between the current
* sub-segment short term residual signal d[0..39] (output of
* the short term analysis filter; for simplification the index
* of this array begins at 0 and ends at 39 for each sub-segment of the
* RPE-LTP analysis) and the previous reconstructed short term
* residual signal dp[ -120 .. -1 ]. A dynamic scaling must be
* performed to avoid overflow.
*/
/* The next procedure exists in six versions. First two integer
* version (if USE_FLOAT_MUL is not defined); then four floating
* point versions, twice with proper scaling (USE_FLOAT_MUL defined),
* once without (USE_FLOAT_MUL and FAST defined, and fast run-time
* option used). Every pair has first a Cut version (see the -C
* option to toast or the LTP_CUT option to gsm_option()), then the
* uncut one. (For a detailed explanation of why this is altogether
* a bad idea, see Henry Spencer and Geoff Collyer, ``#ifdef Considered
* Harmful''.)
*/
#ifndef USE_FLOAT_MUL
#ifdef LTP_CUT
static void Cut_Calculation_of_the_LTP_parameters (
struct gsm_state * st,
register word * d, /* [0..39] IN */
register word * dp, /* [-120..-1] IN */
word * bc_out, /* OUT */
word * Nc_out /* OUT */
)
{
register int k, lambda;
word Nc, bc;
word wt[40];
longword L_result;
longword L_max, L_power;
word R, S, dmax, scal, best_k;
word ltp_cut;
register word temp, wt_k;
/* Search of the optimum scaling of d[0..39].
*/
dmax = 0;
for (k = 0; k <= 39; k++) {
temp = d[k];
temp = GSM_ABS( temp );
if (temp > dmax) {
dmax = temp;
best_k = k;
}
}
temp = 0;
if (dmax == 0) scal = 0;
else {
assert(dmax > 0);
temp = gsm_norm( (longword)dmax << 16 );
}
if (temp > 6) scal = 0;
else scal = 6 - temp;
assert(scal >= 0);
/* Search for the maximum cross-correlation and coding of the LTP lag
*/
L_max = 0;
Nc = 40; /* index for the maximum cross-correlation */
wt_k = SASR_W(d[best_k], scal);
for (lambda = 40; lambda <= 120; lambda++) {
L_result = (longword)wt_k * dp[best_k - lambda];
if (L_result > L_max) {
Nc = lambda;
L_max = L_result;
}
}
*Nc_out = Nc;
L_max <<= 1;
/* Rescaling of L_max
*/
assert(scal <= 100 && scal >= -100);
L_max = L_max >> (6 - scal); /* sub(6, scal) */
assert( Nc <= 120 && Nc >= 40);
/* Compute the power of the reconstructed short term residual
* signal dp[..]
*/
L_power = 0;
for (k = 0; k <= 39; k++) {
register longword L_temp;
L_temp = SASR_W( dp[k - Nc], 3 );
L_power += L_temp * L_temp;
}
L_power <<= 1; /* from L_MULT */
/* Normalization of L_max and L_power
*/
if (L_max <= 0) {
*bc_out = 0;
return;
}
if (L_max >= L_power) {
*bc_out = 3;
return;
}
temp = gsm_norm( L_power );
R = SASR( L_max << temp, 16 );
S = SASR( L_power << temp, 16 );
/* Coding of the LTP gain
*/
/* Table 4.3a must be used to obtain the level DLB[i] for the
* quantization of the LTP gain b to get the coded version bc.
*/
for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break;
*bc_out = bc;
}
#endif /* LTP_CUT */
static void Calculation_of_the_LTP_parameters (
register word * d, /* [0..39] IN */
register word * dp, /* [-120..-1] IN */
word * bc_out, /* OUT */
word * Nc_out /* OUT */
)
{
register int k, lambda;
word Nc, bc;
word wt[40];
longword L_max, L_power;
word R, S, dmax, scal;
register word temp;
/* Search of the optimum scaling of d[0..39].
*/
dmax = 0;
for (k = 0; k <= 39; k++) {
temp = d[k];
temp = GSM_ABS( temp );
if (temp > dmax) dmax = temp;
}
temp = 0;
if (dmax == 0) scal = 0;
else {
assert(dmax > 0);
temp = gsm_norm( (longword)dmax << 16 );
}
if (temp > 6) scal = 0;
else scal = 6 - temp;
assert(scal >= 0);
/* Initialization of a working array wt
*/
for (k = 0; k <= 39; k++) wt[k] = SASR_W( d[k], scal );
/* Search for the maximum cross-correlation and coding of the LTP lag
*/
L_max = 0;
Nc = 40; /* index for the maximum cross-correlation */
for (lambda = 40; lambda <= 120; lambda++) {
# undef STEP
# define STEP(k) (longword)wt[k] * dp[k - lambda]
register longword L_result;
L_result = STEP(0) ; L_result += STEP(1) ;
L_result += STEP(2) ; L_result += STEP(3) ;
L_result += STEP(4) ; L_result += STEP(5) ;
L_result += STEP(6) ; L_result += STEP(7) ;
L_result += STEP(8) ; L_result += STEP(9) ;
L_result += STEP(10) ; L_result += STEP(11) ;
L_result += STEP(12) ; L_result += STEP(13) ;
L_result += STEP(14) ; L_result += STEP(15) ;
L_result += STEP(16) ; L_result += STEP(17) ;
L_result += STEP(18) ; L_result += STEP(19) ;
L_result += STEP(20) ; L_result += STEP(21) ;
L_result += STEP(22) ; L_result += STEP(23) ;
L_result += STEP(24) ; L_result += STEP(25) ;
L_result += STEP(26) ; L_result += STEP(27) ;
L_result += STEP(28) ; L_result += STEP(29) ;
L_result += STEP(30) ; L_result += STEP(31) ;
L_result += STEP(32) ; L_result += STEP(33) ;
L_result += STEP(34) ; L_result += STEP(35) ;
L_result += STEP(36) ; L_result += STEP(37) ;
L_result += STEP(38) ; L_result += STEP(39) ;
if (L_result > L_max) {
Nc = lambda;
L_max = L_result;
}
}
*Nc_out = Nc;
L_max <<= 1;
/* Rescaling of L_max
*/
assert(scal <= 100 && scal >= -100);
L_max = L_max >> (6 - scal); /* sub(6, scal) */
assert( Nc <= 120 && Nc >= 40);
/* Compute the power of the reconstructed short term residual
* signal dp[..]
*/
L_power = 0;
for (k = 0; k <= 39; k++) {
register longword L_temp;
L_temp = SASR_W( dp[k - Nc], 3 );
L_power += L_temp * L_temp;
}
L_power <<= 1; /* from L_MULT */
/* Normalization of L_max and L_power
*/
if (L_max <= 0) {
*bc_out = 0;
return;
}
if (L_max >= L_power) {
*bc_out = 3;
return;
}
temp = gsm_norm( L_power );
R = SASR_L( L_max << temp, 16 );
S = SASR_L( L_power << temp, 16 );
/* Coding of the LTP gain
*/
/* Table 4.3a must be used to obtain the level DLB[i] for the
* quantization of the LTP gain b to get the coded version bc.
*/
for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break;
*bc_out = bc;
}
#else /* USE_FLOAT_MUL */
#ifdef LTP_CUT
static void Cut_Calculation_of_the_LTP_parameters (
struct gsm_state * st, /* IN */
register word * d, /* [0..39] IN */
register word * dp, /* [-120..-1] IN */
word * bc_out, /* OUT */
word * Nc_out /* OUT */
)
{
register int k, lambda;
word Nc, bc;
word ltp_cut;
float wt_float[40];
float dp_float_base[120], * dp_float = dp_float_base + 120;
longword L_max, L_power;
word R, S, dmax, scal;
register word temp;
/* Search of the optimum scaling of d[0..39].
*/
dmax = 0;
for (k = 0; k <= 39; k++) {
temp = d[k];
temp = GSM_ABS( temp );
if (temp > dmax) dmax = temp;
}
temp = 0;
if (dmax == 0) scal = 0;
else {
assert(dmax > 0);
temp = gsm_norm( (longword)dmax << 16 );
}
if (temp > 6) scal = 0;
else scal = 6 - temp;
assert(scal >= 0);
ltp_cut = (longword)SASR_W(dmax, scal) * st->ltp_cut / 100;
/* Initialization of a working array wt
*/
for (k = 0; k < 40; k++) {
register word w = SASR_W( d[k], scal );
if (w < 0 ? w > -ltp_cut : w < ltp_cut) {
wt_float[k] = 0.0;
}
else {
wt_float[k] = w;
}
}
for (k = -120; k < 0; k++) dp_float[k] = dp[k];
/* Search for the maximum cross-correlation and coding of the LTP lag
*/
L_max = 0;
Nc = 40; /* index for the maximum cross-correlation */
for (lambda = 40; lambda <= 120; lambda += 9) {
/* Calculate L_result for l = lambda .. lambda + 9.
*/
register float *lp = dp_float - lambda;
register float W;
register float a = lp[-8], b = lp[-7], c = lp[-6],
d = lp[-5], e = lp[-4], f = lp[-3],
g = lp[-2], h = lp[-1];
register float E;
register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0,
S5 = 0, S6 = 0, S7 = 0, S8 = 0;
# undef STEP
# define STEP(K, a, b, c, d, e, f, g, h) \
if ((W = wt_float[K]) != 0.0) { \
E = W * a; S8 += E; \
E = W * b; S7 += E; \
E = W * c; S6 += E; \
E = W * d; S5 += E; \
E = W * e; S4 += E; \
E = W * f; S3 += E; \
E = W * g; S2 += E; \
E = W * h; S1 += E; \
a = lp[K]; \
E = W * a; S0 += E; } else (a = lp[K])
# define STEP_A(K) STEP(K, a, b, c, d, e, f, g, h)
# define STEP_B(K) STEP(K, b, c, d, e, f, g, h, a)
# define STEP_C(K) STEP(K, c, d, e, f, g, h, a, b)
# define STEP_D(K) STEP(K, d, e, f, g, h, a, b, c)
# define STEP_E(K) STEP(K, e, f, g, h, a, b, c, d)
# define STEP_F(K) STEP(K, f, g, h, a, b, c, d, e)
# define STEP_G(K) STEP(K, g, h, a, b, c, d, e, f)
# define STEP_H(K) STEP(K, h, a, b, c, d, e, f, g)
STEP_A( 0); STEP_B( 1); STEP_C( 2); STEP_D( 3);
STEP_E( 4); STEP_F( 5); STEP_G( 6); STEP_H( 7);
STEP_A( 8); STEP_B( 9); STEP_C(10); STEP_D(11);
STEP_E(12); STEP_F(13); STEP_G(14); STEP_H(15);
STEP_A(16); STEP_B(17); STEP_C(18); STEP_D(19);
STEP_E(20); STEP_F(21); STEP_G(22); STEP_H(23);
STEP_A(24); STEP_B(25); STEP_C(26); STEP_D(27);
STEP_E(28); STEP_F(29); STEP_G(30); STEP_H(31);
STEP_A(32); STEP_B(33); STEP_C(34); STEP_D(35);
STEP_E(36); STEP_F(37); STEP_G(38); STEP_H(39);
# undef STEP_A
# undef STEP_B
# undef STEP_C
# undef STEP_D
# undef STEP_E
# undef STEP_F
# undef STEP_G
# undef STEP_H
if (S0 > L_max) { L_max = S0; Nc = lambda; }
if (S1 > L_max) { L_max = S1; Nc = lambda + 1; }
if (S2 > L_max) { L_max = S2; Nc = lambda + 2; }
if (S3 > L_max) { L_max = S3; Nc = lambda + 3; }
if (S4 > L_max) { L_max = S4; Nc = lambda + 4; }
if (S5 > L_max) { L_max = S5; Nc = lambda + 5; }
if (S6 > L_max) { L_max = S6; Nc = lambda + 6; }
if (S7 > L_max) { L_max = S7; Nc = lambda + 7; }
if (S8 > L_max) { L_max = S8; Nc = lambda + 8; }
}
*Nc_out = Nc;
L_max <<= 1;
/* Rescaling of L_max
*/
assert(scal <= 100 && scal >= -100);
L_max = L_max >> (6 - scal); /* sub(6, scal) */
assert( Nc <= 120 && Nc >= 40);
/* Compute the power of the reconstructed short term residual
* signal dp[..]
*/
L_power = 0;
for (k = 0; k <= 39; k++) {
register longword L_temp;
L_temp = SASR_W( dp[k - Nc], 3 );
L_power += L_temp * L_temp;
}
L_power <<= 1; /* from L_MULT */
/* Normalization of L_max and L_power
*/
if (L_max <= 0) {
*bc_out = 0;
return;
}
if (L_max >= L_power) {
*bc_out = 3;
return;
}
temp = gsm_norm( L_power );
R = SASR( L_max << temp, 16 );
S = SASR( L_power << temp, 16 );
/* Coding of the LTP gain
*/
/* Table 4.3a must be used to obtain the level DLB[i] for the
* quantization of the LTP gain b to get the coded version bc.
*/
for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break;
*bc_out = bc;
}
#endif /* LTP_CUT */
static void Calculation_of_the_LTP_parameters (
register word * din, /* [0..39] IN */
register word * dp, /* [-120..-1] IN */
word * bc_out, /* OUT */
word * Nc_out /* OUT */
)
{
register int k, lambda;
word Nc, bc;
float wt_float[40];
float dp_float_base[120], * dp_float = dp_float_base + 120;
longword L_max, L_power;
word R, S, dmax, scal;
register word temp;
/* Search of the optimum scaling of d[0..39].
*/
dmax = 0;
for (k = 0; k <= 39; k++) {
temp = din [k] ;
temp = GSM_ABS (temp) ;
if (temp > dmax) dmax = temp;
}
temp = 0;
if (dmax == 0) scal = 0;
else {
assert(dmax > 0);
temp = gsm_norm( (longword)dmax << 16 );
}
if (temp > 6) scal = 0;
else scal = 6 - temp;
assert(scal >= 0);
/* Initialization of a working array wt
*/
for (k = 0; k < 40; k++) wt_float[k] = SASR_W (din [k], scal) ;
for (k = -120; k < 0; k++) dp_float[k] = dp[k];
/* Search for the maximum cross-correlation and coding of the LTP lag
*/
L_max = 0;
Nc = 40; /* index for the maximum cross-correlation */
for (lambda = 40; lambda <= 120; lambda += 9) {
/* Calculate L_result for l = lambda .. lambda + 9.
*/
register float *lp = dp_float - lambda;
register float W;
register float a = lp[-8], b = lp[-7], c = lp[-6],
d = lp[-5], e = lp[-4], f = lp[-3],
g = lp[-2], h = lp[-1];
register float E;
register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0,
S5 = 0, S6 = 0, S7 = 0, S8 = 0;
# undef STEP
# define STEP(K, a, b, c, d, e, f, g, h) \
W = wt_float[K]; \
E = W * a; S8 += E; \
E = W * b; S7 += E; \
E = W * c; S6 += E; \
E = W * d; S5 += E; \
E = W * e; S4 += E; \
E = W * f; S3 += E; \
E = W * g; S2 += E; \
E = W * h; S1 += E; \
a = lp[K]; \
E = W * a; S0 += E
# define STEP_A(K) STEP(K, a, b, c, d, e, f, g, h)
# define STEP_B(K) STEP(K, b, c, d, e, f, g, h, a)
# define STEP_C(K) STEP(K, c, d, e, f, g, h, a, b)
# define STEP_D(K) STEP(K, d, e, f, g, h, a, b, c)
# define STEP_E(K) STEP(K, e, f, g, h, a, b, c, d)
# define STEP_F(K) STEP(K, f, g, h, a, b, c, d, e)
# define STEP_G(K) STEP(K, g, h, a, b, c, d, e, f)
# define STEP_H(K) STEP(K, h, a, b, c, d, e, f, g)
STEP_A( 0); STEP_B( 1); STEP_C( 2); STEP_D( 3);
STEP_E( 4); STEP_F( 5); STEP_G( 6); STEP_H( 7);
STEP_A( 8); STEP_B( 9); STEP_C(10); STEP_D(11);
STEP_E(12); STEP_F(13); STEP_G(14); STEP_H(15);
STEP_A(16); STEP_B(17); STEP_C(18); STEP_D(19);
STEP_E(20); STEP_F(21); STEP_G(22); STEP_H(23);
STEP_A(24); STEP_B(25); STEP_C(26); STEP_D(27);
STEP_E(28); STEP_F(29); STEP_G(30); STEP_H(31);
STEP_A(32); STEP_B(33); STEP_C(34); STEP_D(35);
STEP_E(36); STEP_F(37); STEP_G(38); STEP_H(39);
# undef STEP_A
# undef STEP_B
# undef STEP_C
# undef STEP_D
# undef STEP_E
# undef STEP_F
# undef STEP_G
# undef STEP_H
if (S0 > L_max) { L_max = S0; Nc = lambda; }
if (S1 > L_max) { L_max = S1; Nc = lambda + 1; }
if (S2 > L_max) { L_max = S2; Nc = lambda + 2; }
if (S3 > L_max) { L_max = S3; Nc = lambda + 3; }
if (S4 > L_max) { L_max = S4; Nc = lambda + 4; }
if (S5 > L_max) { L_max = S5; Nc = lambda + 5; }
if (S6 > L_max) { L_max = S6; Nc = lambda + 6; }
if (S7 > L_max) { L_max = S7; Nc = lambda + 7; }
if (S8 > L_max) { L_max = S8; Nc = lambda + 8; }
}
*Nc_out = Nc;
L_max <<= 1;
/* Rescaling of L_max
*/
assert(scal <= 100 && scal >= -100);
L_max = L_max >> (6 - scal); /* sub(6, scal) */
assert( Nc <= 120 && Nc >= 40);
/* Compute the power of the reconstructed short term residual
* signal dp[..]
*/
L_power = 0;
for (k = 0; k <= 39; k++) {
register longword L_temp;
L_temp = SASR_W( dp[k - Nc], 3 );
L_power += L_temp * L_temp;
}
L_power <<= 1; /* from L_MULT */
/* Normalization of L_max and L_power
*/
if (L_max <= 0) {
*bc_out = 0;
return;
}
if (L_max >= L_power) {
*bc_out = 3;
return;
}
temp = gsm_norm( L_power );
R = SASR_L ( L_max << temp, 16 );
S = SASR_L ( L_power << temp, 16 );
/* Coding of the LTP gain
*/
/* Table 4.3a must be used to obtain the level DLB[i] for the
* quantization of the LTP gain b to get the coded version bc.
*/
for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break;
*bc_out = bc;
}
#ifdef FAST
#ifdef LTP_CUT
static void Cut_Fast_Calculation_of_the_LTP_parameters (
struct gsm_state * st, /* IN */
register word * d, /* [0..39] IN */
register word * dp, /* [-120..-1] IN */
word * bc_out, /* OUT */
word * Nc_out /* OUT */
)
{
register int k, lambda;
register float wt_float;
word Nc, bc;
word wt_max, best_k, ltp_cut;
float dp_float_base[120], * dp_float = dp_float_base + 120;
register float L_result, L_max, L_power;
wt_max = 0;
for (k = 0; k < 40; ++k) {
if ( d[k] > wt_max) wt_max = d[best_k = k];
else if (-d[k] > wt_max) wt_max = -d[best_k = k];
}
assert(wt_max >= 0);
wt_float = (float)wt_max;
for (k = -120; k < 0; ++k) dp_float[k] = (float)dp[k];
/* Search for the maximum cross-correlation and coding of the LTP lag
*/
L_max = 0;
Nc = 40; /* index for the maximum cross-correlation */
for (lambda = 40; lambda <= 120; lambda++) {
L_result = wt_float * dp_float[best_k - lambda];
if (L_result > L_max) {
Nc = lambda;
L_max = L_result;
}
}
*Nc_out = Nc;
if (L_max <= 0.) {
*bc_out = 0;
return;
}
/* Compute the power of the reconstructed short term residual
* signal dp[..]
*/
dp_float -= Nc;
L_power = 0;
for (k = 0; k < 40; ++k) {
register float f = dp_float[k];
L_power += f * f;
}
if (L_max >= L_power) {
*bc_out = 3;
return;
}
/* Coding of the LTP gain
* Table 4.3a must be used to obtain the level DLB[i] for the
* quantization of the LTP gain b to get the coded version bc.
*/
lambda = L_max / L_power * 32768.;
for (bc = 0; bc <= 2; ++bc) if (lambda <= gsm_DLB[bc]) break;
*bc_out = bc;
}
#endif /* LTP_CUT */
static void Fast_Calculation_of_the_LTP_parameters (
register word * din, /* [0..39] IN */
register word * dp, /* [-120..-1] IN */
word * bc_out, /* OUT */
word * Nc_out /* OUT */
)
{
register int k, lambda;
word Nc, bc;
float wt_float[40];
float dp_float_base[120], * dp_float = dp_float_base + 120;
register float L_max, L_power;
for (k = 0; k < 40; ++k) wt_float[k] = (float) din [k] ;
for (k = -120; k < 0; ++k) dp_float[k] = (float) dp [k] ;
/* Search for the maximum cross-correlation and coding of the LTP lag
*/
L_max = 0;
Nc = 40; /* index for the maximum cross-correlation */
for (lambda = 40; lambda <= 120; lambda += 9) {
/* Calculate L_result for l = lambda .. lambda + 9.
*/
register float *lp = dp_float - lambda;
register float W;
register float a = lp[-8], b = lp[-7], c = lp[-6],
d = lp[-5], e = lp[-4], f = lp[-3],
g = lp[-2], h = lp[-1];
register float E;
register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0,
S5 = 0, S6 = 0, S7 = 0, S8 = 0;
# undef STEP
# define STEP(K, a, b, c, d, e, f, g, h) \
W = wt_float[K]; \
E = W * a; S8 += E; \
E = W * b; S7 += E; \
E = W * c; S6 += E; \
E = W * d; S5 += E; \
E = W * e; S4 += E; \
E = W * f; S3 += E; \
E = W * g; S2 += E; \
E = W * h; S1 += E; \
a = lp[K]; \
E = W * a; S0 += E
# define STEP_A(K) STEP(K, a, b, c, d, e, f, g, h)
# define STEP_B(K) STEP(K, b, c, d, e, f, g, h, a)
# define STEP_C(K) STEP(K, c, d, e, f, g, h, a, b)
# define STEP_D(K) STEP(K, d, e, f, g, h, a, b, c)
# define STEP_E(K) STEP(K, e, f, g, h, a, b, c, d)
# define STEP_F(K) STEP(K, f, g, h, a, b, c, d, e)
# define STEP_G(K) STEP(K, g, h, a, b, c, d, e, f)
# define STEP_H(K) STEP(K, h, a, b, c, d, e, f, g)
STEP_A( 0); STEP_B( 1); STEP_C( 2); STEP_D( 3);
STEP_E( 4); STEP_F( 5); STEP_G( 6); STEP_H( 7);
STEP_A( 8); STEP_B( 9); STEP_C(10); STEP_D(11);
STEP_E(12); STEP_F(13); STEP_G(14); STEP_H(15);
STEP_A(16); STEP_B(17); STEP_C(18); STEP_D(19);
STEP_E(20); STEP_F(21); STEP_G(22); STEP_H(23);
STEP_A(24); STEP_B(25); STEP_C(26); STEP_D(27);
STEP_E(28); STEP_F(29); STEP_G(30); STEP_H(31);
STEP_A(32); STEP_B(33); STEP_C(34); STEP_D(35);
STEP_E(36); STEP_F(37); STEP_G(38); STEP_H(39);
if (S0 > L_max) { L_max = S0; Nc = lambda; }
if (S1 > L_max) { L_max = S1; Nc = lambda + 1; }
if (S2 > L_max) { L_max = S2; Nc = lambda + 2; }
if (S3 > L_max) { L_max = S3; Nc = lambda + 3; }
if (S4 > L_max) { L_max = S4; Nc = lambda + 4; }
if (S5 > L_max) { L_max = S5; Nc = lambda + 5; }
if (S6 > L_max) { L_max = S6; Nc = lambda + 6; }
if (S7 > L_max) { L_max = S7; Nc = lambda + 7; }
if (S8 > L_max) { L_max = S8; Nc = lambda + 8; }
}
*Nc_out = Nc;
if (L_max <= 0.) {
*bc_out = 0;
return;
}
/* Compute the power of the reconstructed short term residual
* signal dp[..]
*/
dp_float -= Nc;
L_power = 0;
for (k = 0; k < 40; ++k) {
register float f = dp_float[k];
L_power += f * f;
}
if (L_max >= L_power) {
*bc_out = 3;
return;
}
/* Coding of the LTP gain
* Table 4.3a must be used to obtain the level DLB[i] for the
* quantization of the LTP gain b to get the coded version bc.
*/
lambda = L_max / L_power * 32768.;
for (bc = 0; bc <= 2; ++bc) if (lambda <= gsm_DLB[bc]) break;
*bc_out = bc;
}
#endif /* FAST */
#endif /* USE_FLOAT_MUL */
/* 4.2.12 */
static void Long_term_analysis_filtering (
word bc, /* IN */
word Nc, /* IN */
register word * dp, /* previous d [-120..-1] IN */
register word * d, /* d [0..39] IN */
register word * dpp, /* estimate [0..39] OUT */
register word * e /* long term res. signal [0..39] OUT */
)
/*
* In this part, we have to decode the bc parameter to compute
* the samples of the estimate dpp[0..39]. The decoding of bc needs the
* use of table 4.3b. The long term residual signal e[0..39]
* is then calculated to be fed to the RPE encoding section.
*/
{
register int k;
# undef STEP
# define STEP(BP) \
for (k = 0; k <= 39; k++) { \
dpp[k] = GSM_MULT_R( BP, dp[k - Nc]); \
e[k] = GSM_SUB( d[k], dpp[k] ); \
}
switch (bc) {
case 0: STEP( 3277 ); break;
case 1: STEP( 11469 ); break;
case 2: STEP( 21299 ); break;
case 3: STEP( 32767 ); break;
}
}
void Gsm_Long_Term_Predictor ( /* 4x for 160 samples */
struct gsm_state * S,
word * d, /* [0..39] residual signal IN */
word * dp, /* [-120..-1] d' IN */
word * e, /* [0..39] OUT */
word * dpp, /* [0..39] OUT */
word * Nc, /* correlation lag OUT */
word * bc /* gain factor OUT */
)
{
assert( d ); assert( dp ); assert( e );
assert( dpp); assert( Nc ); assert( bc );
#if defined(FAST) && defined(USE_FLOAT_MUL)
if (S->fast)
#if defined (LTP_CUT)
if (S->ltp_cut)
Cut_Fast_Calculation_of_the_LTP_parameters(S,
d, dp, bc, Nc);
else
#endif /* LTP_CUT */
Fast_Calculation_of_the_LTP_parameters(d, dp, bc, Nc );
else
#endif /* FAST & USE_FLOAT_MUL */
#ifdef LTP_CUT
if (S->ltp_cut)
Cut_Calculation_of_the_LTP_parameters(S, d, dp, bc, Nc);
else
#endif
Calculation_of_the_LTP_parameters(d, dp, bc, Nc);
Long_term_analysis_filtering( *bc, *Nc, dp, d, dpp, e );
}
/* 4.3.2 */
void Gsm_Long_Term_Synthesis_Filtering (
struct gsm_state * S,
word Ncr,
word bcr,
register word * erp, /* [0..39] IN */
register word * drp /* [-120..-1] IN, [-120..40] OUT */
)
/*
* This procedure uses the bcr and Ncr parameter to realize the
* long term synthesis filtering. The decoding of bcr needs
* table 4.3b.
*/
{
register int k;
word brp, drpp, Nr;
/* Check the limits of Nr.
*/
Nr = Ncr < 40 || Ncr > 120 ? S->nrp : Ncr;
S->nrp = Nr;
assert(Nr >= 40 && Nr <= 120);
/* Decoding of the LTP gain bcr
*/
brp = gsm_QLB[ bcr ];
/* Computation of the reconstructed short term residual
* signal drp[0..39]
*/
assert(brp != MIN_WORD);
for (k = 0; k <= 39; k++) {
drpp = GSM_MULT_R( brp, drp[ k - Nr ] );
drp[k] = GSM_ADD( erp[k], drpp );
}
/*
* Update of the reconstructed short term residual signal
* drp[ -1..-120 ]
*/
for (k = 0; k <= 119; k++) drp[ -120 + k ] = drp[ -80 + k ];
}

View File

@@ -0,0 +1,331 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include <stdio.h>
#include <assert.h>
#include "gsm610_priv.h"
/*
* 4.2.4 .. 4.2.7 LPC ANALYSIS SECTION
*/
/* 4.2.4 */
static void Autocorrelation (
word * s, /* [0..159] IN/OUT */
longword * L_ACF) /* [0..8] OUT */
/*
* The goal is to compute the array L_ACF[k]. The signal s[i] must
* be scaled in order to avoid an overflow situation.
*/
{
register int k, i;
word temp, smax, scalauto;
#ifdef USE_FLOAT_MUL
float float_s[160];
#endif
/* Dynamic scaling of the array s[0..159]
*/
/* Search for the maximum.
*/
smax = 0;
for (k = 0; k <= 159; k++) {
temp = GSM_ABS( s[k] );
if (temp > smax) smax = temp;
}
/* Computation of the scaling factor.
*/
if (smax == 0) scalauto = 0;
else {
assert(smax > 0);
scalauto = 4 - gsm_norm( (longword)smax << 16 );/* sub(4,..) */
}
/* Scaling of the array s[0...159]
*/
if (scalauto > 0) {
# ifdef USE_FLOAT_MUL
# define SCALE(n) \
case n: for (k = 0; k <= 159; k++) \
float_s[k] = (float) \
(s[k] = GSM_MULT_R(s[k], 16384 >> (n-1)));\
break;
# else
# define SCALE(n) \
case n: for (k = 0; k <= 159; k++) \
s[k] = GSM_MULT_R( s[k], 16384 >> (n-1) );\
break;
# endif /* USE_FLOAT_MUL */
switch (scalauto) {
SCALE(1)
SCALE(2)
SCALE(3)
SCALE(4)
}
# undef SCALE
}
# ifdef USE_FLOAT_MUL
else for (k = 0; k <= 159; k++) float_s[k] = (float) s[k];
# endif
/* Compute the L_ACF[..].
*/
{
# ifdef USE_FLOAT_MUL
register float * sp = float_s;
register float sl = *sp;
# define STEP(k) L_ACF[k] += (longword)(sl * sp[ -(k) ]);
# else
word * sp = s;
word sl = *sp;
# define STEP(k) L_ACF[k] += ((longword)sl * sp[ -(k) ]);
# endif
# define NEXTI sl = *++sp
for (k = 9; k--; L_ACF[k] = 0) ;
STEP (0);
NEXTI;
STEP(0); STEP(1);
NEXTI;
STEP(0); STEP(1); STEP(2);
NEXTI;
STEP(0); STEP(1); STEP(2); STEP(3);
NEXTI;
STEP(0); STEP(1); STEP(2); STEP(3); STEP(4);
NEXTI;
STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5);
NEXTI;
STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5); STEP(6);
NEXTI;
STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5); STEP(6); STEP(7);
for (i = 8; i <= 159; i++) {
NEXTI;
STEP(0);
STEP(1); STEP(2); STEP(3); STEP(4);
STEP(5); STEP(6); STEP(7); STEP(8);
}
for (k = 9; k--; L_ACF[k] <<= 1) ;
}
/* Rescaling of the array s[0..159]
*/
if (scalauto > 0) {
assert(scalauto <= 4);
for (k = 160; k--; *s++ <<= scalauto) ;
}
}
#if defined(USE_FLOAT_MUL) && defined(FAST)
static void Fast_Autocorrelation (
word * s, /* [0..159] IN/OUT */
longword * L_ACF) /* [0..8] OUT */
{
register int k, i;
float f_L_ACF[9];
float scale;
float s_f[160];
register float *sf = s_f;
for (i = 0; i < 160; ++i) sf[i] = s[i];
for (k = 0; k <= 8; k++) {
register float L_temp2 = 0;
register float *sfl = sf - k;
for (i = k; i < 160; ++i) L_temp2 += sf[i] * sfl[i];
f_L_ACF[k] = L_temp2;
}
scale = MAX_LONGWORD / f_L_ACF[0];
for (k = 0; k <= 8; k++) {
L_ACF[k] = f_L_ACF[k] * scale;
}
}
#endif /* defined (USE_FLOAT_MUL) && defined (FAST) */
/* 4.2.5 */
static void Reflection_coefficients (
longword * L_ACF, /* 0...8 IN */
register word * r /* 0...7 OUT */
)
{
register int i, m, n;
register word temp;
word ACF[9]; /* 0..8 */
word P[ 9]; /* 0..8 */
word K[ 9]; /* 2..8 */
/* Schur recursion with 16 bits arithmetic.
*/
if (L_ACF[0] == 0) {
for (i = 8; i--; *r++ = 0) ;
return;
}
assert( L_ACF[0] != 0 );
temp = gsm_norm( L_ACF[0] );
assert(temp >= 0 && temp < 32);
/* ? overflow ? */
for (i = 0; i <= 8; i++) ACF[i] = SASR_L( L_ACF[i] << temp, 16 );
/* Initialize array P[..] and K[..] for the recursion.
*/
for (i = 1; i <= 7; i++) K[ i ] = ACF[ i ];
for (i = 0; i <= 8; i++) P[ i ] = ACF[ i ];
/* Compute reflection coefficients
*/
for (n = 1; n <= 8; n++, r++) {
temp = P[1];
temp = GSM_ABS(temp);
if (P[0] < temp) {
for (i = n; i <= 8; i++) *r++ = 0;
return;
}
*r = gsm_div( temp, P[0] );
assert(*r >= 0);
if (P[1] > 0) *r = -*r; /* r[n] = sub(0, r[n]) */
assert (*r != MIN_WORD);
if (n == 8) return;
/* Schur recursion
*/
temp = GSM_MULT_R( P[1], *r );
P[0] = GSM_ADD( P[0], temp );
for (m = 1; m <= 8 - n; m++) {
temp = GSM_MULT_R( K[ m ], *r );
P[m] = GSM_ADD( P[ m+1 ], temp );
temp = GSM_MULT_R( P[ m+1 ], *r );
K[m] = GSM_ADD( K[ m ], temp );
}
}
}
/* 4.2.6 */
static void Transformation_to_Log_Area_Ratios (
register word * r /* 0..7 IN/OUT */
)
/*
* The following scaling for r[..] and LAR[..] has been used:
*
* r[..] = integer( real_r[..]*32768. ); -1 <= real_r < 1.
* LAR[..] = integer( real_LAR[..] * 16384 );
* with -1.625 <= real_LAR <= 1.625
*/
{
register word temp;
register int i;
/* Computation of the LAR[0..7] from the r[0..7]
*/
for (i = 1; i <= 8; i++, r++) {
temp = *r;
temp = GSM_ABS(temp);
assert(temp >= 0);
if (temp < 22118) {
temp >>= 1;
} else if (temp < 31130) {
assert( temp >= 11059 );
temp -= 11059;
} else {
assert( temp >= 26112 );
temp -= 26112;
temp <<= 2;
}
*r = *r < 0 ? -temp : temp;
assert( *r != MIN_WORD );
}
}
/* 4.2.7 */
static void Quantization_and_coding (
register word * LAR /* [0..7] IN/OUT */
)
{
register word temp;
/* This procedure needs four tables; the following equations
* give the optimum scaling for the constants:
*
* A[0..7] = integer( real_A[0..7] * 1024 )
* B[0..7] = integer( real_B[0..7] * 512 )
* MAC[0..7] = maximum of the LARc[0..7]
* MIC[0..7] = minimum of the LARc[0..7]
*/
# undef STEP
# define STEP( A, B, MAC, MIC ) \
temp = GSM_MULT( A, *LAR ); \
temp = GSM_ADD( temp, B ); \
temp = GSM_ADD( temp, 256 ); \
temp = SASR_W( temp, 9 ); \
*LAR = temp>MAC ? MAC - MIC : (temp<MIC ? 0 : temp - MIC); \
LAR++;
STEP( 20480, 0, 31, -32 );
STEP( 20480, 0, 31, -32 );
STEP( 20480, 2048, 15, -16 );
STEP( 20480, -2560, 15, -16 );
STEP( 13964, 94, 7, -8 );
STEP( 15360, -1792, 7, -8 );
STEP( 8534, -341, 3, -4 );
STEP( 9036, -1144, 3, -4 );
# undef STEP
}
void Gsm_LPC_Analysis (
struct gsm_state *S,
word * s, /* 0..159 signals IN/OUT */
word * LARc) /* 0..7 LARc's OUT */
{
longword L_ACF[9];
#if defined(USE_FLOAT_MUL) && defined(FAST)
if (S->fast) Fast_Autocorrelation (s, L_ACF );
else
#endif
Autocorrelation (s, L_ACF );
Reflection_coefficients (L_ACF, LARc );
Transformation_to_Log_Area_Ratios (LARc);
Quantization_and_coding (LARc);
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include <stdio.h>
#include <assert.h>
#include "gsm610_priv.h"
/* 4.2.0 .. 4.2.3 PREPROCESSING SECTION
*
* After A-law to linear conversion (or directly from the
* Ato D converter) the following scaling is assumed for
* input to the RPE-LTP algorithm:
*
* in: 0.1.....................12
* S.v.v.v.v.v.v.v.v.v.v.v.v.*.*.*
*
* Where S is the sign bit, v a valid bit, and * a "don't care" bit.
* The original signal is called sop[..]
*
* out: 0.1................... 12
* S.S.v.v.v.v.v.v.v.v.v.v.v.v.0.0
*/
void Gsm_Preprocess (
struct gsm_state * S,
word * s,
word * so ) /* [0..159] IN/OUT */
{
word z1 = S->z1;
longword L_z2 = S->L_z2;
word mp = S->mp;
word s1;
longword L_s2;
longword L_temp;
word msp, lsp;
word SO;
register int k = 160;
while (k--) {
/* 4.2.1 Downscaling of the input signal
*/
SO = SASR_W( *s, 3 ) << 2;
s++;
assert (SO >= -0x4000); /* downscaled by */
assert (SO <= 0x3FFC); /* previous routine. */
/* 4.2.2 Offset compensation
*
* This part implements a high-pass filter and requires extended
* arithmetic precision for the recursive part of this filter.
* The input of this procedure is the array so[0...159] and the
* output the array sof[ 0...159 ].
*/
/* Compute the non-recursive part
*/
s1 = SO - z1; /* s1 = gsm_sub( *so, z1 ); */
z1 = SO;
assert(s1 != MIN_WORD);
/* Compute the recursive part
*/
L_s2 = s1;
L_s2 <<= 15;
/* Execution of a 31 bv 16 bits multiplication
*/
msp = SASR_L( L_z2, 15 );
lsp = L_z2-((longword)msp<<15); /* gsm_L_sub(L_z2,(msp<<15)); */
L_s2 += GSM_MULT_R( lsp, 32735 );
L_temp = (longword)msp * 32735; /* GSM_L_MULT(msp,32735) >> 1;*/
L_z2 = GSM_L_ADD( L_temp, L_s2 );
/* Compute sof[k] with rounding
*/
L_temp = GSM_L_ADD( L_z2, 16384 );
/* 4.2.3 Preemphasis
*/
msp = GSM_MULT_R( mp, -28180 );
mp = SASR_L( L_temp, 15 );
*so++ = GSM_ADD( mp, msp );
}
S->z1 = z1;
S->L_z2 = L_z2;
S->mp = mp;
}

View File

@@ -0,0 +1,480 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include <stdio.h>
#include <assert.h>
#include "gsm610_priv.h"
/* 4.2.13 .. 4.2.17 RPE ENCODING SECTION
*/
/* 4.2.13 */
static void Weighting_filter (
register word * e, /* signal [-5..0.39.44] IN */
word * x /* signal [0..39] OUT */
)
/*
* The coefficients of the weighting filter are stored in a table
* (see table 4.4). The following scaling is used:
*
* H[0..10] = integer( real_H[ 0..10] * 8192 );
*/
{
/* word wt[ 50 ]; */
register longword L_result;
register int k /* , i */ ;
/* Initialization of a temporary working array wt[0...49]
*/
/* for (k = 0; k <= 4; k++) wt[k] = 0;
* for (k = 5; k <= 44; k++) wt[k] = *e++;
* for (k = 45; k <= 49; k++) wt[k] = 0;
*
* (e[-5..-1] and e[40..44] are allocated by the caller,
* are initially zero and are not written anywhere.)
*/
e -= 5;
/* Compute the signal x[0..39]
*/
for (k = 0; k <= 39; k++) {
L_result = 8192 >> 1;
/* for (i = 0; i <= 10; i++) {
* L_temp = GSM_L_MULT( wt[k+i], gsm_H[i] );
* L_result = GSM_L_ADD( L_result, L_temp );
* }
*/
#undef STEP
#define STEP( i, H ) (e[ k + i ] * (longword)H)
/* Every one of these multiplications is done twice --
* but I don't see an elegant way to optimize this.
* Do you?
*/
#ifdef STUPID_COMPILER
L_result += STEP( 0, -134 ) ;
L_result += STEP( 1, -374 ) ;
/* + STEP( 2, 0 ) */
L_result += STEP( 3, 2054 ) ;
L_result += STEP( 4, 5741 ) ;
L_result += STEP( 5, 8192 ) ;
L_result += STEP( 6, 5741 ) ;
L_result += STEP( 7, 2054 ) ;
/* + STEP( 8, 0 ) */
L_result += STEP( 9, -374 ) ;
L_result += STEP( 10, -134 ) ;
#else
L_result +=
STEP( 0, -134 )
+ STEP( 1, -374 )
/* + STEP( 2, 0 ) */
+ STEP( 3, 2054 )
+ STEP( 4, 5741 )
+ STEP( 5, 8192 )
+ STEP( 6, 5741 )
+ STEP( 7, 2054 )
/* + STEP( 8, 0 ) */
+ STEP( 9, -374 )
+ STEP(10, -134 )
;
#endif
/* L_result = GSM_L_ADD( L_result, L_result ); (* scaling(x2) *)
* L_result = GSM_L_ADD( L_result, L_result ); (* scaling(x4) *)
*
* x[k] = SASR( L_result, 16 );
*/
/* 2 adds vs. >>16 => 14, minus one shift to compensate for
* those we lost when replacing L_MULT by '*'.
*/
L_result = SASR_L( L_result, 13 );
x[k] = ( L_result < MIN_WORD ? MIN_WORD
: (L_result > MAX_WORD ? MAX_WORD : L_result ));
}
}
/* 4.2.14 */
static void RPE_grid_selection (
word * x, /* [0..39] IN */
word * xM, /* [0..12] OUT */
word * Mc_out /* OUT */
)
/*
* The signal x[0..39] is used to select the RPE grid which is
* represented by Mc.
*/
{
/* register word temp1; */
register int /* m, */ i;
register longword L_result, L_temp;
longword EM; /* xxx should be L_EM? */
word Mc;
longword L_common_0_3;
EM = 0;
Mc = 0;
/* for (m = 0; m <= 3; m++) {
* L_result = 0;
*
*
* for (i = 0; i <= 12; i++) {
*
* temp1 = SASR_W( x[m + 3*i], 2 );
*
* assert(temp1 != MIN_WORD);
*
* L_temp = GSM_L_MULT( temp1, temp1 );
* L_result = GSM_L_ADD( L_temp, L_result );
* }
*
* if (L_result > EM) {
* Mc = m;
* EM = L_result;
* }
* }
*/
#undef STEP
#define STEP( m, i ) L_temp = SASR_W( x[m + 3 * i], 2 ); \
L_result += L_temp * L_temp;
/* common part of 0 and 3 */
L_result = 0;
STEP( 0, 1 ); STEP( 0, 2 ); STEP( 0, 3 ); STEP( 0, 4 );
STEP( 0, 5 ); STEP( 0, 6 ); STEP( 0, 7 ); STEP( 0, 8 );
STEP( 0, 9 ); STEP( 0, 10); STEP( 0, 11); STEP( 0, 12);
L_common_0_3 = L_result;
/* i = 0 */
STEP( 0, 0 );
L_result <<= 1; /* implicit in L_MULT */
EM = L_result;
/* i = 1 */
L_result = 0;
STEP( 1, 0 );
STEP( 1, 1 ); STEP( 1, 2 ); STEP( 1, 3 ); STEP( 1, 4 );
STEP( 1, 5 ); STEP( 1, 6 ); STEP( 1, 7 ); STEP( 1, 8 );
STEP( 1, 9 ); STEP( 1, 10); STEP( 1, 11); STEP( 1, 12);
L_result <<= 1;
if (L_result > EM) {
Mc = 1;
EM = L_result;
}
/* i = 2 */
L_result = 0;
STEP( 2, 0 );
STEP( 2, 1 ); STEP( 2, 2 ); STEP( 2, 3 ); STEP( 2, 4 );
STEP( 2, 5 ); STEP( 2, 6 ); STEP( 2, 7 ); STEP( 2, 8 );
STEP( 2, 9 ); STEP( 2, 10); STEP( 2, 11); STEP( 2, 12);
L_result <<= 1;
if (L_result > EM) {
Mc = 2;
EM = L_result;
}
/* i = 3 */
L_result = L_common_0_3;
STEP( 3, 12 );
L_result <<= 1;
if (L_result > EM) {
Mc = 3;
EM = L_result;
}
/**/
/* Down-sampling by a factor 3 to get the selected xM[0..12]
* RPE sequence.
*/
for (i = 0; i <= 12; i ++) xM[i] = x[Mc + 3*i];
*Mc_out = Mc;
}
/* 4.12.15 */
static void APCM_quantization_xmaxc_to_exp_mant (
word xmaxc, /* IN */
word * expon_out, /* OUT */
word * mant_out ) /* OUT */
{
word expon, mant;
/* Compute expononent and mantissa of the decoded version of xmaxc
*/
expon = 0;
if (xmaxc > 15) expon = SASR_W(xmaxc, 3) - 1;
mant = xmaxc - (expon << 3);
if (mant == 0) {
expon = -4;
mant = 7;
}
else {
while (mant <= 7) {
mant = mant << 1 | 1;
expon--;
}
mant -= 8;
}
assert( expon >= -4 && expon <= 6 );
assert( mant >= 0 && mant <= 7 );
*expon_out = expon;
*mant_out = mant;
}
static void APCM_quantization (
word * xM, /* [0..12] IN */
word * xMc, /* [0..12] OUT */
word * mant_out, /* OUT */
word * expon_out, /* OUT */
word * xmaxc_out /* OUT */
)
{
int i, itest;
word xmax, xmaxc, temp, temp1, temp2;
word expon, mant;
/* Find the maximum absolute value xmax of xM[0..12].
*/
xmax = 0;
for (i = 0; i <= 12; i++) {
temp = xM[i];
temp = GSM_ABS(temp);
if (temp > xmax) xmax = temp;
}
/* Qantizing and coding of xmax to get xmaxc.
*/
expon = 0;
temp = SASR_W( xmax, 9 );
itest = 0;
for (i = 0; i <= 5; i++) {
itest |= (temp <= 0);
temp = SASR_W( temp, 1 );
assert(expon <= 5);
if (itest == 0) expon++; /* expon = add (expon, 1) */
}
assert(expon <= 6 && expon >= 0);
temp = expon + 5;
assert(temp <= 11 && temp >= 0);
xmaxc = gsm_add( SASR_W(xmax, temp), (word) (expon << 3) );
/* Quantizing and coding of the xM[0..12] RPE sequence
* to get the xMc[0..12]
*/
APCM_quantization_xmaxc_to_exp_mant( xmaxc, &expon, &mant );
/* This computation uses the fact that the decoded version of xmaxc
* can be calculated by using the expononent and the mantissa part of
* xmaxc (logarithmic table).
* So, this method avoids any division and uses only a scaling
* of the RPE samples by a function of the expononent. A direct
* multiplication by the inverse of the mantissa (NRFAC[0..7]
* found in table 4.5) gives the 3 bit coded version xMc[0..12]
* of the RPE samples.
*/
/* Direct computation of xMc[0..12] using table 4.5
*/
assert( expon <= 4096 && expon >= -4096);
assert( mant >= 0 && mant <= 7 );
temp1 = 6 - expon; /* normalization by the expononent */
temp2 = gsm_NRFAC[ mant ]; /* inverse mantissa */
for (i = 0; i <= 12; i++) {
assert(temp1 >= 0 && temp1 < 16);
temp = xM[i] << temp1;
temp = GSM_MULT( temp, temp2 );
temp = SASR_W(temp, 12);
xMc[i] = temp + 4; /* see note below */
}
/* NOTE: This equation is used to make all the xMc[i] positive.
*/
*mant_out = mant;
*expon_out = expon;
*xmaxc_out = xmaxc;
}
/* 4.2.16 */
static void APCM_inverse_quantization (
register word * xMc, /* [0..12] IN */
word mant,
word expon,
register word * xMp) /* [0..12] OUT */
/*
* This part is for decoding the RPE sequence of coded xMc[0..12]
* samples to obtain the xMp[0..12] array. Table 4.6 is used to get
* the mantissa of xmaxc (FAC[0..7]).
*/
{
int i;
word temp, temp1, temp2, temp3;
assert( mant >= 0 && mant <= 7 );
temp1 = gsm_FAC[ mant ]; /* see 4.2-15 for mant */
temp2 = gsm_sub( 6, expon ); /* see 4.2-15 for exp */
temp3 = gsm_asl( 1, gsm_sub( temp2, 1 ));
for (i = 13; i--;) {
assert( *xMc <= 7 && *xMc >= 0 ); /* 3 bit unsigned */
/* temp = gsm_sub( *xMc++ << 1, 7 ); */
temp = (*xMc++ << 1) - 7; /* restore sign */
assert( temp <= 7 && temp >= -7 ); /* 4 bit signed */
temp <<= 12; /* 16 bit signed */
temp = GSM_MULT_R( temp1, temp );
temp = GSM_ADD( temp, temp3 );
*xMp++ = gsm_asr( temp, temp2 );
}
}
/* 4.2.17 */
static void RPE_grid_positioning (
word Mc, /* grid position IN */
register word * xMp, /* [0..12] IN */
register word * ep /* [0..39] OUT */
)
/*
* This procedure computes the reconstructed long term residual signal
* ep[0..39] for the LTP analysis filter. The inputs are the Mc
* which is the grid position selection and the xMp[0..12] decoded
* RPE samples which are upsampled by a factor of 3 by inserting zero
* values.
*/
{
int i = 13;
assert(0 <= Mc && Mc <= 3);
switch (Mc) {
case 3: *ep++ = 0;
case 2: do {
*ep++ = 0;
case 1: *ep++ = 0;
case 0: *ep++ = *xMp++;
} while (--i);
}
while (++Mc < 4) *ep++ = 0;
/*
int i, k;
for (k = 0; k <= 39; k++) ep[k] = 0;
for (i = 0; i <= 12; i++) {
ep[ Mc + (3*i) ] = xMp[i];
}
*/
}
/* 4.2.18 */
/* This procedure adds the reconstructed long term residual signal
* ep[0..39] to the estimated signal dpp[0..39] from the long term
* analysis filter to compute the reconstructed short term residual
* signal dp[-40..-1]; also the reconstructed short term residual
* array dp[-120..-41] is updated.
*/
#if 0 /* Has been inlined in code.c */
void Gsm_Update_of_reconstructed_short_time_residual_signal (
word * dpp, /* [0...39] IN */
word * ep, /* [0...39] IN */
word * dp) /* [-120...-1] IN/OUT */
{
int k;
for (k = 0; k <= 79; k++)
dp[ -120 + k ] = dp[ -80 + k ];
for (k = 0; k <= 39; k++)
dp[ -40 + k ] = gsm_add( ep[k], dpp[k] );
}
#endif /* Has been inlined in code.c */
void Gsm_RPE_Encoding (
/*-struct gsm_state * S,-*/
word * e, /* -5..-1][0..39][40..44 IN/OUT */
word * xmaxc, /* OUT */
word * Mc, /* OUT */
word * xMc) /* [0..12] OUT */
{
word x[40];
word xM[13], xMp[13];
word mant, expon;
Weighting_filter(e, x);
RPE_grid_selection(x, xM, Mc);
APCM_quantization( xM, xMc, &mant, &expon, xmaxc);
APCM_inverse_quantization( xMc, mant, expon, xMp);
RPE_grid_positioning( *Mc, xMp, e );
}
void Gsm_RPE_Decoding (
/*-struct gsm_state * S,-*/
word xmaxcr,
word Mcr,
word * xMcr, /* [0..12], 3 bits IN */
word * erp /* [0..39] OUT */
)
{
word expon, mant;
word xMp[ 13 ];
APCM_quantization_xmaxc_to_exp_mant( xmaxcr, &expon, &mant );
APCM_inverse_quantization( xMcr, mant, expon, xMp );
RPE_grid_positioning( Mcr, xMp, erp );
}

View File

@@ -0,0 +1,417 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include <stdio.h>
#include <assert.h>
#include "gsm610_priv.h"
/*
* SHORT TERM ANALYSIS FILTERING SECTION
*/
/* 4.2.8 */
static void Decoding_of_the_coded_Log_Area_Ratios (
word * LARc, /* coded log area ratio [0..7] IN */
word * LARpp) /* out: decoded .. */
{
register word temp1 /* , temp2 */;
/* This procedure requires for efficient implementation
* two tables.
*
* INVA[1..8] = integer( (32768 * 8) / real_A[1..8])
* MIC[1..8] = minimum value of the LARc[1..8]
*/
/* Compute the LARpp[1..8]
*/
/* for (i = 1; i <= 8; i++, B++, MIC++, INVA++, LARc++, LARpp++) {
*
* temp1 = GSM_ADD( *LARc, *MIC ) << 10;
* temp2 = *B << 1;
* temp1 = GSM_SUB( temp1, temp2 );
*
* assert(*INVA != MIN_WORD);
*
* temp1 = GSM_MULT_R( *INVA, temp1 );
* *LARpp = GSM_ADD( temp1, temp1 );
* }
*/
#undef STEP
#define STEP( B, MIC, INVA ) \
temp1 = GSM_ADD( *LARc++, MIC ) << 10; \
temp1 = GSM_SUB( temp1, B << 1 ); \
temp1 = GSM_MULT_R( INVA, temp1 ); \
*LARpp++ = GSM_ADD( temp1, temp1 );
STEP( 0, -32, 13107 );
STEP( 0, -32, 13107 );
STEP( 2048, -16, 13107 );
STEP( -2560, -16, 13107 );
STEP( 94, -8, 19223 );
STEP( -1792, -8, 17476 );
STEP( -341, -4, 31454 );
STEP( -1144, -4, 29708 );
/* NOTE: the addition of *MIC is used to restore
* the sign of *LARc.
*/
}
/* 4.2.9 */
/* Computation of the quantized reflection coefficients
*/
/* 4.2.9.1 Interpolation of the LARpp[1..8] to get the LARp[1..8]
*/
/*
* Within each frame of 160 analyzed speech samples the short term
* analysis and synthesis filters operate with four different sets of
* coefficients, derived from the previous set of decoded LARs(LARpp(j-1))
* and the actual set of decoded LARs (LARpp(j))
*
* (Initial value: LARpp(j-1)[1..8] = 0.)
*/
static void Coefficients_0_12 (
register word * LARpp_j_1,
register word * LARpp_j,
register word * LARp)
{
register int i;
for (i = 1; i <= 8; i++, LARp++, LARpp_j_1++, LARpp_j++) {
*LARp = GSM_ADD( SASR_W( *LARpp_j_1, 2 ), SASR_W( *LARpp_j, 2 ));
*LARp = GSM_ADD( *LARp, SASR_W( *LARpp_j_1, 1));
}
}
static void Coefficients_13_26 (
register word * LARpp_j_1,
register word * LARpp_j,
register word * LARp)
{
register int i;
for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++) {
*LARp = GSM_ADD( SASR_W( *LARpp_j_1, 1), SASR_W( *LARpp_j, 1 ));
}
}
static void Coefficients_27_39 (
register word * LARpp_j_1,
register word * LARpp_j,
register word * LARp)
{
register int i;
for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++) {
*LARp = GSM_ADD( SASR_W( *LARpp_j_1, 2 ), SASR_W( *LARpp_j, 2 ));
*LARp = GSM_ADD( *LARp, SASR_W( *LARpp_j, 1 ));
}
}
static void Coefficients_40_159 (
register word * LARpp_j,
register word * LARp)
{
register int i;
for (i = 1; i <= 8; i++, LARp++, LARpp_j++)
*LARp = *LARpp_j;
}
/* 4.2.9.2 */
static void LARp_to_rp (
register word * LARp) /* [0..7] IN/OUT */
/*
* The input of this procedure is the interpolated LARp[0..7] array.
* The reflection coefficients, rp[i], are used in the analysis
* filter and in the synthesis filter.
*/
{
register int i;
register word temp;
for (i = 1; i <= 8; i++, LARp++) {
/* temp = GSM_ABS( *LARp );
*
* if (temp < 11059) temp <<= 1;
* else if (temp < 20070) temp += 11059;
* else temp = GSM_ADD( temp >> 2, 26112 );
*
* *LARp = *LARp < 0 ? -temp : temp;
*/
if (*LARp < 0) {
temp = *LARp == MIN_WORD ? MAX_WORD : -(*LARp);
*LARp = - ((temp < 11059) ? temp << 1
: ((temp < 20070) ? temp + 11059
: GSM_ADD( (word) (temp >> 2), (word) 26112 )));
} else {
temp = *LARp;
*LARp = (temp < 11059) ? temp << 1
: ((temp < 20070) ? temp + 11059
: GSM_ADD( (word) (temp >> 2), (word) 26112 ));
}
}
}
/* 4.2.10 */
static void Short_term_analysis_filtering (
struct gsm_state * S,
register word * rp, /* [0..7] IN */
register int k_n, /* k_end - k_start */
register word * s /* [0..n-1] IN/OUT */
)
/*
* This procedure computes the short term residual signal d[..] to be fed
* to the RPE-LTP loop from the s[..] signal and from the local rp[..]
* array (quantized reflection coefficients). As the call of this
* procedure can be done in many ways (see the interpolation of the LAR
* coefficient), it is assumed that the computation begins with index
* k_start (for arrays d[..] and s[..]) and stops with index k_end
* (k_start and k_end are defined in 4.2.9.1). This procedure also
* needs to keep the array u[0..7] in memory for each call.
*/
{
register word * u = S->u;
register int i;
register word di, zzz, ui, sav, rpi;
for (; k_n--; s++) {
di = sav = *s;
for (i = 0; i < 8; i++) { /* YYY */
ui = u[i];
rpi = rp[i];
u[i] = sav;
zzz = GSM_MULT_R(rpi, di);
sav = GSM_ADD( ui, zzz);
zzz = GSM_MULT_R(rpi, ui);
di = GSM_ADD( di, zzz );
}
*s = di;
}
}
#if defined(USE_FLOAT_MUL) && defined(FAST)
static void Fast_Short_term_analysis_filtering (
struct gsm_state * S,
register word * rp, /* [0..7] IN */
register int k_n, /* k_end - k_start */
register word * s /* [0..n-1] IN/OUT */
)
{
register word * u = S->u;
register int i;
float uf[8],
rpf[8];
register float scalef = 3.0517578125e-5;
register float sav, di, temp;
for (i = 0; i < 8; ++i) {
uf[i] = u[i];
rpf[i] = rp[i] * scalef;
}
for (; k_n--; s++) {
sav = di = *s;
for (i = 0; i < 8; ++i) {
register float rpfi = rpf[i];
register float ufi = uf[i];
uf[i] = sav;
temp = rpfi * di + ufi;
di += rpfi * ufi;
sav = temp;
}
*s = di;
}
for (i = 0; i < 8; ++i) u[i] = uf[i];
}
#endif /* ! (defined (USE_FLOAT_MUL) && defined (FAST)) */
static void Short_term_synthesis_filtering (
struct gsm_state * S,
register word * rrp, /* [0..7] IN */
register int k, /* k_end - k_start */
register word * wt, /* [0..k-1] IN */
register word * sr /* [0..k-1] OUT */
)
{
register word * v = S->v;
register int i;
register word sri, tmp1, tmp2;
while (k--) {
sri = *wt++;
for (i = 8; i--;) {
/* sri = GSM_SUB( sri, gsm_mult_r( rrp[i], v[i] ) );
*/
tmp1 = rrp[i];
tmp2 = v[i];
tmp2 = ( tmp1 == MIN_WORD && tmp2 == MIN_WORD
? MAX_WORD
: 0x0FFFF & (( (longword)tmp1 * (longword)tmp2
+ 16384) >> 15)) ;
sri = GSM_SUB( sri, tmp2 );
/* v[i+1] = GSM_ADD( v[i], gsm_mult_r( rrp[i], sri ) );
*/
tmp1 = ( tmp1 == MIN_WORD && sri == MIN_WORD
? MAX_WORD
: 0x0FFFF & (( (longword)tmp1 * (longword)sri
+ 16384) >> 15)) ;
v[i+1] = GSM_ADD( v[i], tmp1);
}
*sr++ = v[0] = sri;
}
}
#if defined(FAST) && defined(USE_FLOAT_MUL)
static void Fast_Short_term_synthesis_filtering (
struct gsm_state * S,
register word * rrp, /* [0..7] IN */
register int k, /* k_end - k_start */
register word * wt, /* [0..k-1] IN */
register word * sr /* [0..k-1] OUT */
)
{
register word * v = S->v;
register int i;
float va[9], rrpa[8];
register float scalef = 3.0517578125e-5, temp;
for (i = 0; i < 8; ++i) {
va[i] = v[i];
rrpa[i] = (float)rrp[i] * scalef;
}
while (k--) {
register float sri = *wt++;
for (i = 8; i--;) {
sri -= rrpa[i] * va[i];
if (sri < -32768.) sri = -32768.;
else if (sri > 32767.) sri = 32767.;
temp = va[i] + rrpa[i] * sri;
if (temp < -32768.) temp = -32768.;
else if (temp > 32767.) temp = 32767.;
va[i+1] = temp;
}
*sr++ = va[0] = sri;
}
for (i = 0; i < 9; ++i) v[i] = va[i];
}
#endif /* defined(FAST) && defined(USE_FLOAT_MUL) */
void Gsm_Short_Term_Analysis_Filter (
struct gsm_state * S,
word * LARc, /* coded log area ratio [0..7] IN */
word * s /* signal [0..159] IN/OUT */
)
{
word * LARpp_j = S->LARpp[ S->j ];
word * LARpp_j_1 = S->LARpp[ S->j ^= 1 ];
word LARp[8];
#undef FILTER
#if defined(FAST) && defined(USE_FLOAT_MUL)
# define FILTER (* (S->fast \
? Fast_Short_term_analysis_filtering \
: Short_term_analysis_filtering ))
#else
# define FILTER Short_term_analysis_filtering
#endif
Decoding_of_the_coded_Log_Area_Ratios( LARc, LARpp_j );
Coefficients_0_12( LARpp_j_1, LARpp_j, LARp );
LARp_to_rp( LARp );
FILTER( S, LARp, 13, s);
Coefficients_13_26( LARpp_j_1, LARpp_j, LARp);
LARp_to_rp( LARp );
FILTER( S, LARp, 14, s + 13);
Coefficients_27_39( LARpp_j_1, LARpp_j, LARp);
LARp_to_rp( LARp );
FILTER( S, LARp, 13, s + 27);
Coefficients_40_159( LARpp_j, LARp);
LARp_to_rp( LARp );
FILTER( S, LARp, 120, s + 40);
}
void Gsm_Short_Term_Synthesis_Filter (
struct gsm_state * S,
word * LARcr, /* received log area ratios [0..7] IN */
word * wt, /* received d [0..159] IN */
word * s /* signal s [0..159] OUT */
)
{
word * LARpp_j = S->LARpp[ S->j ];
word * LARpp_j_1 = S->LARpp[ S->j ^=1 ];
word LARp[8];
#undef FILTER
#if defined(FAST) && defined(USE_FLOAT_MUL)
# define FILTER (* (S->fast \
? Fast_Short_term_synthesis_filtering \
: Short_term_synthesis_filtering ))
#else
# define FILTER Short_term_synthesis_filtering
#endif
Decoding_of_the_coded_Log_Area_Ratios( LARcr, LARpp_j );
Coefficients_0_12( LARpp_j_1, LARpp_j, LARp );
LARp_to_rp( LARp );
FILTER( S, LARp, 13, wt, s );
Coefficients_13_26( LARpp_j_1, LARpp_j, LARp);
LARp_to_rp( LARp );
FILTER( S, LARp, 14, wt + 13, s + 13 );
Coefficients_27_39( LARpp_j_1, LARpp_j, LARp);
LARp_to_rp( LARp );
FILTER( S, LARp, 13, wt + 27, s + 27 );
Coefficients_40_159( LARpp_j, LARp );
LARp_to_rp( LARp );
FILTER(S, LARp, 120, wt + 40, s + 40);
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
/* Most of these tables are inlined at their point of use.
*/
/* 4.4 TABLES USED IN THE FIXED POINT IMPLEMENTATION OF THE RPE-LTP
* CODER AND DECODER
*
* (Most of them inlined, so watch out.)
*/
#define GSM_TABLE_C
#include "gsm610_priv.h"
/* Table 4.1 Quantization of the Log.-Area Ratios
*/
/* i 1 2 3 4 5 6 7 8 */
word gsm_A[8] = {20480, 20480, 20480, 20480, 13964, 15360, 8534, 9036};
word gsm_B[8] = { 0, 0, 2048, -2560, 94, -1792, -341, -1144};
word gsm_MIC[8] = { -32, -32, -16, -16, -8, -8, -4, -4 };
word gsm_MAC[8] = { 31, 31, 15, 15, 7, 7, 3, 3 };
/* Table 4.2 Tabulation of 1/A[1..8]
*/
word gsm_INVA[8]={ 13107, 13107, 13107, 13107, 19223, 17476, 31454, 29708 };
/* Table 4.3a Decision level of the LTP gain quantizer
*/
/* bc 0 1 2 3 */
word gsm_DLB[4] = { 6554, 16384, 26214, 32767 };
/* Table 4.3b Quantization levels of the LTP gain quantizer
*/
/* bc 0 1 2 3 */
word gsm_QLB[4] = { 3277, 11469, 21299, 32767 };
/* Table 4.4 Coefficients of the weighting filter
*/
/* i 0 1 2 3 4 5 6 7 8 9 10 */
word gsm_H[11] = {-134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134 };
/* Table 4.5 Normalized inverse mantissa used to compute xM/xmax
*/
/* i 0 1 2 3 4 5 6 7 */
word gsm_NRFAC[8] = { 29128, 26215, 23832, 21846, 20165, 18725, 17476, 16384 };
/* Table 4.6 Normalized direct mantissa used to compute xM/xmax
*/
/* i 0 1 2 3 4 5 6 7 */
word gsm_FAC[8] = { 18431, 20479, 22527, 24575, 26623, 28671, 30719, 32767 };

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,540 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <math.h>
#include "sndfile.h"
#include "common.h"
static sf_count_t alaw_read_alaw2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
static sf_count_t alaw_read_alaw2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
static sf_count_t alaw_read_alaw2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
static sf_count_t alaw_read_alaw2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
static sf_count_t alaw_write_s2alaw (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
static sf_count_t alaw_write_i2alaw (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
static sf_count_t alaw_write_f2alaw (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
static sf_count_t alaw_write_d2alaw (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
static void alaw2s_array (unsigned char *buffer, int count, short *ptr) ;
static void alaw2i_array (unsigned char *buffer, int count, int *ptr) ;
static void alaw2f_array (unsigned char *buffer, int count, float *ptr, float normfact) ;
static void alaw2d_array (unsigned char *buffer, int count, double *ptr, double normfact) ;
static void s2alaw_array (const short *buffer, int count, unsigned char *ptr) ;
static void i2alaw_array (const int *buffer, int count, unsigned char *ptr) ;
static void f2alaw_array (const float *buffer, int count, unsigned char *ptr, float normfact) ;
static void d2alaw_array (const double *buffer, int count, unsigned char *ptr, double normfact) ;
int
alaw_init (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR)
{ psf->read_short = alaw_read_alaw2s ;
psf->read_int = alaw_read_alaw2i ;
psf->read_float = alaw_read_alaw2f ;
psf->read_double = alaw_read_alaw2d ;
} ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ psf->write_short = alaw_write_s2alaw ;
psf->write_int = alaw_write_i2alaw ;
psf->write_float = alaw_write_f2alaw ;
psf->write_double = alaw_write_d2alaw ;
} ;
psf->bytewidth = 1 ;
psf->blockwidth = psf->sf.channels ;
if (psf->filelength > psf->dataoffset)
psf->datalength = (psf->dataend) ? psf->dataend - psf->dataoffset : psf->filelength - psf->dataoffset ;
else
psf->datalength = 0 ;
psf->sf.frames = psf->blockwidth > 0 ? psf->datalength / psf->blockwidth : 0 ;
return 0 ;
} /* alaw_init */
/*==============================================================================
* Private static functions and data.
*/
static
short alaw_decode [256] =
{ -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
-7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
-2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
-3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
-22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
-30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
-11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
-15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
-344, -328, -376, -360, -280, -264, -312, -296,
-472, -456, -504, -488, -408, -392, -440, -424,
-88, -72, -120, -104, -24, -8, -56, -40,
-216, -200, -248, -232, -152, -136, -184, -168,
-1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
-1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
-688, -656, -752, -720, -560, -528, -624, -592,
-944, -912, -1008, -976, -816, -784, -880, -848,
5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
344, 328, 376, 360, 280, 264, 312, 296,
472, 456, 504, 488, 408, 392, 440, 424,
88, 72, 120, 104, 24, 8, 56, 40,
216, 200, 248, 232, 152, 136, 184, 168,
1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
688, 656, 752, 720, 560, 528, 624, 592,
944, 912, 1008, 976, 816, 784, 880, 848
} ; /* alaw_decode */
static
unsigned char alaw_encode [2048 + 1] =
{ 0xd5, 0xd4, 0xd7, 0xd6, 0xd1, 0xd0, 0xd3, 0xd2, 0xdd, 0xdc, 0xdf, 0xde,
0xd9, 0xd8, 0xdb, 0xda, 0xc5, 0xc4, 0xc7, 0xc6, 0xc1, 0xc0, 0xc3, 0xc2,
0xcd, 0xcc, 0xcf, 0xce, 0xc9, 0xc8, 0xcb, 0xca, 0xf5, 0xf5, 0xf4, 0xf4,
0xf7, 0xf7, 0xf6, 0xf6, 0xf1, 0xf1, 0xf0, 0xf0, 0xf3, 0xf3, 0xf2, 0xf2,
0xfd, 0xfd, 0xfc, 0xfc, 0xff, 0xff, 0xfe, 0xfe, 0xf9, 0xf9, 0xf8, 0xf8,
0xfb, 0xfb, 0xfa, 0xfa, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4,
0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1,
0xe0, 0xe0, 0xe0, 0xe0, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2,
0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xef, 0xef, 0xef, 0xef,
0xee, 0xee, 0xee, 0xee, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8,
0xeb, 0xeb, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, 0x95,
0x95, 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96,
0x96, 0x96, 0x96, 0x96, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93,
0x93, 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c,
0x9c, 0x9c, 0x9c, 0x9c, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99,
0x99, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a,
0x9a, 0x9a, 0x9a, 0x9a, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, 0xb5, 0xb5,
0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
0xb5, 0xb5, 0xb5, 0xb5, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6,
0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
0xb6, 0xb6, 0xb6, 0xb6, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3,
0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
0xb3, 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc,
0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
0xbc, 0xbc, 0xbc, 0xbc, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, 0xb9, 0xb9, 0xb9,
0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
0xb9, 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba,
0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
0xba, 0xba, 0xba, 0xba, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a
} ; /* alaw_encode */
static inline void
alaw2s_array (unsigned char *buffer, int count, short *ptr)
{ while (--count >= 0)
ptr [count] = alaw_decode [(int) buffer [count]] ;
} /* alaw2s_array */
static inline void
alaw2i_array (unsigned char *buffer, int count, int *ptr)
{ while (--count >= 0)
ptr [count] = alaw_decode [(int) buffer [count]] << 16 ;
} /* alaw2i_array */
static inline void
alaw2f_array (unsigned char *buffer, int count, float *ptr, float normfact)
{ while (--count >= 0)
ptr [count] = normfact * alaw_decode [(int) buffer [count]] ;
} /* alaw2f_array */
static inline void
alaw2d_array (unsigned char *buffer, int count, double *ptr, double normfact)
{ while (--count >= 0)
ptr [count] = normfact * alaw_decode [(int) buffer [count]] ;
} /* alaw2d_array */
static inline void
s2alaw_array (const short *ptr, int count, unsigned char *buffer)
{ while (--count >= 0)
{ if (ptr [count] >= 0)
buffer [count] = alaw_encode [ptr [count] / 16] ;
else
buffer [count] = 0x7F & alaw_encode [ptr [count] / -16] ;
} ;
} /* s2alaw_array */
static inline void
i2alaw_array (const int *ptr, int count, unsigned char *buffer)
{ while (--count >= 0)
{ if (ptr [count] >= 0)
buffer [count] = alaw_encode [ptr [count] >> (16 + 4)] ;
else
buffer [count] = 0x7F & alaw_encode [- ptr [count] >> (16 + 4)] ;
} ;
} /* i2alaw_array */
static inline void
f2alaw_array (const float *ptr, int count, unsigned char *buffer, float normfact)
{ while (--count >= 0)
{ if (ptr [count] >= 0)
buffer [count] = alaw_encode [lrintf (normfact * ptr [count])] ;
else
buffer [count] = 0x7F & alaw_encode [- lrintf (normfact * ptr [count])] ;
} ;
} /* f2alaw_array */
static inline void
d2alaw_array (const double *ptr, int count, unsigned char *buffer, double normfact)
{ while (--count >= 0)
{ if (ptr [count] >= 0)
buffer [count] = alaw_encode [lrint (normfact * ptr [count])] ;
else
buffer [count] = 0x7F & alaw_encode [- lrint (normfact * ptr [count])] ;
} ;
} /* d2alaw_array */
/*==============================================================================
*/
static sf_count_t
alaw_read_alaw2s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
{ int bufferlen, readcount ;
sf_count_t total = 0 ;
bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ;
alaw2s_array (psf->u.ucbuf, readcount, ptr + total) ;
total += readcount ;
if (readcount < bufferlen)
break ;
len -= readcount ;
} ;
return total ;
} /* alaw_read_alaw2s */
static sf_count_t
alaw_read_alaw2i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
{ int bufferlen, readcount ;
sf_count_t total = 0 ;
bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ;
alaw2i_array (psf->u.ucbuf, readcount, ptr + total) ;
total += readcount ;
if (readcount < bufferlen)
break ;
len -= readcount ;
} ;
return total ;
} /* alaw_read_alaw2i */
static sf_count_t
alaw_read_alaw2f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
{ int bufferlen, readcount ;
sf_count_t total = 0 ;
float normfact ;
normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ;
bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ;
alaw2f_array (psf->u.ucbuf, readcount, ptr + total, normfact) ;
total += readcount ;
if (readcount < bufferlen)
break ;
len -= readcount ;
} ;
return total ;
} /* alaw_read_alaw2f */
static sf_count_t
alaw_read_alaw2d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
{ int bufferlen, readcount ;
sf_count_t total = 0 ;
double normfact ;
normfact = (psf->norm_double) ? 1.0 / ((double) 0x8000) : 1.0 ;
bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ;
alaw2d_array (psf->u.ucbuf, readcount, ptr + total, normfact) ;
total += readcount ;
if (readcount < bufferlen)
break ;
len -= readcount ;
} ;
return total ;
} /* alaw_read_alaw2d */
/*=============================================================================================
*/
static sf_count_t
alaw_write_s2alaw (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
{ int bufferlen, writecount ;
sf_count_t total = 0 ;
bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
s2alaw_array (ptr + total, bufferlen, psf->u.ucbuf) ;
writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ;
total += writecount ;
if (writecount < bufferlen)
break ;
len -= writecount ;
} ;
return total ;
} /* alaw_write_s2alaw */
static sf_count_t
alaw_write_i2alaw (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
{ int bufferlen, writecount ;
sf_count_t total = 0 ;
bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
i2alaw_array (ptr + total, bufferlen, psf->u.ucbuf) ;
writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ;
total += writecount ;
if (writecount < bufferlen)
break ;
len -= writecount ;
} ;
return total ;
} /* alaw_write_i2alaw */
static sf_count_t
alaw_write_f2alaw (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
{ int bufferlen, writecount ;
sf_count_t total = 0 ;
float normfact ;
normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) / 16.0 : 1.0 / 16 ;
bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
f2alaw_array (ptr + total, bufferlen, psf->u.ucbuf, normfact) ;
writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ;
total += writecount ;
if (writecount < bufferlen)
break ;
len -= writecount ;
} ;
return total ;
} /* alaw_write_f2alaw */
static sf_count_t
alaw_write_d2alaw (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
{ int bufferlen, writecount ;
sf_count_t total = 0 ;
double normfact ;
normfact = (psf->norm_double) ? (1.0 * 0x7FFF) / 16.0 : 1.0 / 16.0 ;
bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
d2alaw_array (ptr + total, bufferlen, psf->u.ucbuf, normfact) ;
writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ;
total += writecount ;
if (writecount < bufferlen)
break ;
len -= writecount ;
} ;
return total ;
} /* alaw_write_d2alaw */

View File

@@ -0,0 +1,452 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
/*------------------------------------------------------------------------------
** Macros to handle big/little endian issues.
*/
#define DOTSND_MARKER (MAKE_MARKER ('.', 's', 'n', 'd'))
#define DNSDOT_MARKER (MAKE_MARKER ('d', 'n', 's', '.'))
#define AU_DATA_OFFSET 24
/*------------------------------------------------------------------------------
** Known AU file encoding types.
*/
enum
{ AU_ENCODING_ULAW_8 = 1, /* 8-bit u-law samples */
AU_ENCODING_PCM_8 = 2, /* 8-bit linear samples */
AU_ENCODING_PCM_16 = 3, /* 16-bit linear samples */
AU_ENCODING_PCM_24 = 4, /* 24-bit linear samples */
AU_ENCODING_PCM_32 = 5, /* 32-bit linear samples */
AU_ENCODING_FLOAT = 6, /* floating-point samples */
AU_ENCODING_DOUBLE = 7, /* double-precision float samples */
AU_ENCODING_INDIRECT = 8, /* fragmented sampled data */
AU_ENCODING_NESTED = 9, /* ? */
AU_ENCODING_DSP_CORE = 10, /* DSP program */
AU_ENCODING_DSP_DATA_8 = 11, /* 8-bit fixed-point samples */
AU_ENCODING_DSP_DATA_16 = 12, /* 16-bit fixed-point samples */
AU_ENCODING_DSP_DATA_24 = 13, /* 24-bit fixed-point samples */
AU_ENCODING_DSP_DATA_32 = 14, /* 32-bit fixed-point samples */
AU_ENCODING_DISPLAY = 16, /* non-audio display data */
AU_ENCODING_MULAW_SQUELCH = 17, /* ? */
AU_ENCODING_EMPHASIZED = 18, /* 16-bit linear with emphasis */
AU_ENCODING_NEXT = 19, /* 16-bit linear with compression (NEXT) */
AU_ENCODING_COMPRESSED_EMPHASIZED = 20, /* A combination of the two above */
AU_ENCODING_DSP_COMMANDS = 21, /* Music Kit DSP commands */
AU_ENCODING_DSP_COMMANDS_SAMPLES = 22, /* ? */
AU_ENCODING_ADPCM_G721_32 = 23, /* G721 32 kbs ADPCM - 4 bits per sample. */
AU_ENCODING_ADPCM_G722 = 24, /* G722 64 kbs ADPCM */
AU_ENCODING_ADPCM_G723_24 = 25, /* G723 24 kbs ADPCM - 3 bits per sample. */
AU_ENCODING_ADPCM_G723_40 = 26, /* G723 40 kbs ADPCM - 5 bits per sample. */
AU_ENCODING_ALAW_8 = 27
} ;
/*------------------------------------------------------------------------------
** Typedefs.
*/
typedef struct
{ int dataoffset ;
int datasize ;
int encoding ;
int samplerate ;
int channels ;
} AU_FMT ;
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int au_close (SF_PRIVATE *psf) ;
static int au_format_to_encoding (int format) ;
static int au_write_header (SF_PRIVATE *psf, int calc_length) ;
static int au_read_header (SF_PRIVATE *psf) ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
au_open (SF_PRIVATE *psf)
{ int subformat ;
int error = 0 ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = au_read_header (psf)))
return error ;
} ;
if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_AU)
return SFE_BAD_OPEN_FORMAT ;
subformat = SF_CODEC (psf->sf.format) ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ psf->endian = SF_ENDIAN (psf->sf.format) ;
if (CPU_IS_LITTLE_ENDIAN && psf->endian == SF_ENDIAN_CPU)
psf->endian = SF_ENDIAN_LITTLE ;
else if (psf->endian != SF_ENDIAN_LITTLE)
psf->endian = SF_ENDIAN_BIG ;
if (au_write_header (psf, SF_FALSE))
return psf->error ;
psf->write_header = au_write_header ;
} ;
psf->container_close = au_close ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
switch (subformat)
{ case SF_FORMAT_ULAW : /* 8-bit Ulaw encoding. */
ulaw_init (psf) ;
break ;
case SF_FORMAT_PCM_S8 : /* 8-bit linear PCM. */
error = pcm_init (psf) ;
break ;
case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */
case SF_FORMAT_PCM_24 : /* 24-bit linear PCM */
case SF_FORMAT_PCM_32 : /* 32-bit linear PCM. */
error = pcm_init (psf) ;
break ;
case SF_FORMAT_ALAW : /* 8-bit Alaw encoding. */
alaw_init (psf) ;
break ;
/* Lite remove start */
case SF_FORMAT_FLOAT : /* 32-bit floats. */
error = float32_init (psf) ;
break ;
case SF_FORMAT_DOUBLE : /* 64-bit double precision floats. */
error = double64_init (psf) ;
break ;
case SF_FORMAT_G721_32 :
error = g72x_init (psf) ;
psf->sf.seekable = SF_FALSE ;
break ;
case SF_FORMAT_G723_24 :
error = g72x_init (psf) ;
psf->sf.seekable = SF_FALSE ;
break ;
case SF_FORMAT_G723_40 :
error = g72x_init (psf) ;
psf->sf.seekable = SF_FALSE ;
break ;
/* Lite remove end */
default : break ;
} ;
return error ;
} /* au_open */
/*------------------------------------------------------------------------------
*/
static int
au_close (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
au_write_header (psf, SF_TRUE) ;
return 0 ;
} /* au_close */
static int
au_write_header (SF_PRIVATE *psf, int calc_length)
{ sf_count_t current ;
int encoding, datalength ;
if (psf->pipeoffset > 0)
return 0 ;
current = psf_ftell (psf) ;
if (calc_length)
{ psf->filelength = psf_get_filelen (psf) ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf->dataend)
psf->datalength -= psf->filelength - psf->dataend ;
psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
} ;
encoding = au_format_to_encoding (SF_CODEC (psf->sf.format)) ;
if (! encoding)
return (psf->error = SFE_BAD_OPEN_FORMAT) ;
/* Reset the current header length to zero. */
psf->header [0] = 0 ;
psf->headindex = 0 ;
/*
** Only attempt to seek if we are not writng to a pipe. If we are
** writing to a pipe we shouldn't be here anyway.
*/
if (psf->is_pipe == SF_FALSE)
psf_fseek (psf, 0, SEEK_SET) ;
/*
** AU format files allow a datalength value of -1 if the datalength
** is not know at the time the header is written.
** Also use this value of -1 if the datalength > 2 gigabytes.
*/
if (psf->datalength < 0 || psf->datalength > 0x7FFFFFFF)
datalength = -1 ;
else
datalength = (int) (psf->datalength & 0x7FFFFFFF) ;
if (psf->endian == SF_ENDIAN_BIG)
{ psf_binheader_writef (psf, "Em4", DOTSND_MARKER, AU_DATA_OFFSET) ;
psf_binheader_writef (psf, "E4444", datalength, encoding, psf->sf.samplerate, psf->sf.channels) ;
}
else if (psf->endian == SF_ENDIAN_LITTLE)
{ psf_binheader_writef (psf, "em4", DNSDOT_MARKER, AU_DATA_OFFSET) ;
psf_binheader_writef (psf, "e4444", datalength, encoding, psf->sf.samplerate, psf->sf.channels) ;
}
else
return (psf->error = SFE_BAD_OPEN_FORMAT) ;
/* Header construction complete so write it out. */
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
if (psf->error)
return psf->error ;
psf->dataoffset = psf->headindex ;
if (current > 0)
psf_fseek (psf, current, SEEK_SET) ;
return psf->error ;
} /* au_write_header */
static int
au_format_to_encoding (int format)
{
switch (format)
{ case SF_FORMAT_PCM_S8 : return AU_ENCODING_PCM_8 ;
case SF_FORMAT_PCM_16 : return AU_ENCODING_PCM_16 ;
case SF_FORMAT_PCM_24 : return AU_ENCODING_PCM_24 ;
case SF_FORMAT_PCM_32 : return AU_ENCODING_PCM_32 ;
case SF_FORMAT_FLOAT : return AU_ENCODING_FLOAT ;
case SF_FORMAT_DOUBLE : return AU_ENCODING_DOUBLE ;
case SF_FORMAT_ULAW : return AU_ENCODING_ULAW_8 ;
case SF_FORMAT_ALAW : return AU_ENCODING_ALAW_8 ;
case SF_FORMAT_G721_32 : return AU_ENCODING_ADPCM_G721_32 ;
case SF_FORMAT_G723_24 : return AU_ENCODING_ADPCM_G723_24 ;
case SF_FORMAT_G723_40 : return AU_ENCODING_ADPCM_G723_40 ;
default : break ;
} ;
return 0 ;
} /* au_format_to_encoding */
static int
au_read_header (SF_PRIVATE *psf)
{ AU_FMT au_fmt ;
int marker, dword ;
memset (&au_fmt, 0, sizeof (au_fmt)) ;
psf_binheader_readf (psf, "pm", 0, &marker) ;
psf_log_printf (psf, "%M\n", marker) ;
if (marker == DOTSND_MARKER)
{ psf->endian = SF_ENDIAN_BIG ;
psf_binheader_readf (psf, "E44444", &(au_fmt.dataoffset), &(au_fmt.datasize),
&(au_fmt.encoding), &(au_fmt.samplerate), &(au_fmt.channels)) ;
}
else if (marker == DNSDOT_MARKER)
{ psf->endian = SF_ENDIAN_LITTLE ;
psf_binheader_readf (psf, "e44444", &(au_fmt.dataoffset), &(au_fmt.datasize),
&(au_fmt.encoding), &(au_fmt.samplerate), &(au_fmt.channels)) ;
}
else
return SFE_AU_NO_DOTSND ;
psf_log_printf (psf, " Data Offset : %d\n", au_fmt.dataoffset) ;
if (psf->fileoffset > 0 && au_fmt.datasize == -1)
{ psf_log_printf (psf, " Data Size : -1\n") ;
return SFE_AU_EMBED_BAD_LEN ;
} ;
if (psf->fileoffset > 0)
{ psf->filelength = au_fmt.dataoffset + au_fmt.datasize ;
psf_log_printf (psf, " Data Size : %d\n", au_fmt.datasize) ;
}
else if (au_fmt.datasize == -1 || au_fmt.dataoffset + au_fmt.datasize == psf->filelength)
psf_log_printf (psf, " Data Size : %d\n", au_fmt.datasize) ;
else if (au_fmt.dataoffset + au_fmt.datasize < psf->filelength)
{ psf->filelength = au_fmt.dataoffset + au_fmt.datasize ;
psf_log_printf (psf, " Data Size : %d\n", au_fmt.datasize) ;
}
else
{ dword = psf->filelength - au_fmt.dataoffset ;
psf_log_printf (psf, " Data Size : %d (should be %d)\n", au_fmt.datasize, dword) ;
au_fmt.datasize = dword ;
} ;
psf->dataoffset = au_fmt.dataoffset ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf_ftell (psf) < psf->dataoffset)
psf_binheader_readf (psf, "j", psf->dataoffset - psf_ftell (psf)) ;
psf->sf.samplerate = au_fmt.samplerate ;
psf->sf.channels = au_fmt.channels ;
/* Only fill in type major. */
if (psf->endian == SF_ENDIAN_BIG)
psf->sf.format = SF_FORMAT_AU ;
else if (psf->endian == SF_ENDIAN_LITTLE)
psf->sf.format = SF_ENDIAN_LITTLE | SF_FORMAT_AU ;
psf_log_printf (psf, " Encoding : %d => ", au_fmt.encoding) ;
psf->sf.format = SF_ENDIAN (psf->sf.format) ;
switch (au_fmt.encoding)
{ case AU_ENCODING_ULAW_8 :
psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_ULAW ;
psf->bytewidth = 1 ; /* Before decoding */
psf_log_printf (psf, "8-bit ISDN u-law\n") ;
break ;
case AU_ENCODING_PCM_8 :
psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_PCM_S8 ;
psf->bytewidth = 1 ;
psf_log_printf (psf, "8-bit linear PCM\n") ;
break ;
case AU_ENCODING_PCM_16 :
psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_PCM_16 ;
psf->bytewidth = 2 ;
psf_log_printf (psf, "16-bit linear PCM\n") ;
break ;
case AU_ENCODING_PCM_24 :
psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_PCM_24 ;
psf->bytewidth = 3 ;
psf_log_printf (psf, "24-bit linear PCM\n") ;
break ;
case AU_ENCODING_PCM_32 :
psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_PCM_32 ;
psf->bytewidth = 4 ;
psf_log_printf (psf, "32-bit linear PCM\n") ;
break ;
case AU_ENCODING_FLOAT :
psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_FLOAT ;
psf->bytewidth = 4 ;
psf_log_printf (psf, "32-bit float\n") ;
break ;
case AU_ENCODING_DOUBLE :
psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_DOUBLE ;
psf->bytewidth = 8 ;
psf_log_printf (psf, "64-bit double precision float\n") ;
break ;
case AU_ENCODING_ALAW_8 :
psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_ALAW ;
psf->bytewidth = 1 ; /* Before decoding */
psf_log_printf (psf, "8-bit ISDN A-law\n") ;
break ;
case AU_ENCODING_ADPCM_G721_32 :
psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_G721_32 ;
psf->bytewidth = 0 ;
psf_log_printf (psf, "G721 32kbs ADPCM\n") ;
break ;
case AU_ENCODING_ADPCM_G723_24 :
psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_G723_24 ;
psf->bytewidth = 0 ;
psf_log_printf (psf, "G723 24kbs ADPCM\n") ;
break ;
case AU_ENCODING_ADPCM_G723_40 :
psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_G723_40 ;
psf->bytewidth = 0 ;
psf_log_printf (psf, "G723 40kbs ADPCM\n") ;
break ;
case AU_ENCODING_ADPCM_G722 :
psf_log_printf (psf, "G722 64 kbs ADPCM (unsupported)\n") ;
break ;
case AU_ENCODING_NEXT :
psf_log_printf (psf, "Weird NeXT encoding format (unsupported)\n") ;
break ;
default :
psf_log_printf (psf, "Unknown!!\n") ;
break ;
} ;
psf_log_printf (psf, " Sample Rate : %d\n", au_fmt.samplerate) ;
if (au_fmt.channels < 1)
{ psf_log_printf (psf, " Channels : %d **** should be >= 1\n", au_fmt.channels) ;
return SFE_CHANNEL_COUNT_ZERO ;
}
else
psf_log_printf (psf, " Channels : %d\n", au_fmt.channels) ;
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
if (! psf->sf.frames && psf->blockwidth)
psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ;
return 0 ;
} /* au_read_header */

View File

@@ -0,0 +1,105 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <errno.h>
#include "common.h"
typedef struct
{ int le_float ;
int be_float ;
int le_int_24_32 ;
int be_int_24_32 ;
} VOTE ;
static void vote_for_format (VOTE * vote, const unsigned char * data, int datalen) ;
int
audio_detect (SF_PRIVATE * psf, AUDIO_DETECT *ad, const unsigned char * data, int datalen)
{ VOTE vote ;
if (psf == NULL)
return 0 ;
if (ad == NULL || datalen < 256)
return 0 ;
vote_for_format (&vote, data, datalen) ;
psf_log_printf (psf, "audio_detect :\n"
" le_float : %d\n"
" be_float : %d\n"
" le_int_24_32 : %d\n"
" be_int_24_32 : %d\n",
vote.le_float, vote.be_float, vote.le_int_24_32, vote.be_int_24_32) ;
if (0) puts (psf->logbuffer) ;
if (ad->endianness == SF_ENDIAN_LITTLE && vote.le_float > (3 * datalen) / 4)
{ /* Almost certainly 32 bit floats. */
return SF_FORMAT_FLOAT ;
} ;
if (ad->endianness == SF_ENDIAN_LITTLE && vote.le_int_24_32 > (3 * datalen) / 4)
{ /* Almost certainly 24 bit data stored in 32 bit ints. */
return SF_FORMAT_PCM_32 ;
} ;
return 0 ;
} /* data_detect */
static void
vote_for_format (VOTE * vote, const unsigned char * data, int datalen)
{
int k ;
memset (vote, 0, sizeof (VOTE)) ;
datalen -= datalen % 4 ;
for (k = 0 ; k < datalen ; k ++)
{ if ((k % 4) == 0)
{ if (data [k] == 0 && data [k + 1] != 0)
vote->le_int_24_32 += 4 ;
if (data [2] != 0 && data [3] == 0)
vote->le_int_24_32 += 4 ;
if (data [0] != 0 && data [3] > 0x43 && data [3] < 0x4B)
vote->le_float += 4 ;
if (data [3] != 0 && data [0] > 0x43 && data [0] < 0x4B)
vote->be_float += 4 ;
} ;
} ;
return ;
} /* vote_for_format */

View File

@@ -0,0 +1,247 @@
/*
** Copyright (C) 2004-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <string.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#define TWOBIT_MARKER (MAKE_MARKER ('2', 'B', 'I', 'T'))
#define AVR_HDR_SIZE 128
#define SFE_AVR_X 666
/*
** From: hyc@hanauma.Jpl.Nasa.Gov (Howard Chu)
**
** A lot of PD software exists to play Mac .snd files on the ST. One other
** format that seems pretty popular (used by a number of commercial packages)
** is the AVR format (from Audio Visual Research). This format has a 128 byte
** header that looks like this (its actually packed, but thats not portable):
*/
typedef struct
{ int marker ; /* 2BIT */
char name [8] ; /* null-padded sample name */
short mono ; /* 0 = mono, 0xffff = stereo */
short rez ; /* 8 = 8 bit, 16 = 16 bit */
short sign ; /* 0 = unsigned, 0xffff = signed */
short loop ; /* 0 = no loop, 0xffff = looping sample */
short midi ; /* 0xffff = no MIDI note assigned, */
/* 0xffXX = single key note assignment */
/* 0xLLHH = key split, low/hi note */
int srate ; /* sample frequency in hertz */
int frames ; /* sample length in bytes or words (see rez) */
int lbeg ; /* offset to start of loop in bytes or words. */
/* set to zero if unused */
int lend ; /* offset to end of loop in bytes or words. */
/* set to sample length if unused */
short res1 ; /* Reserved, MIDI keyboard split */
short res2 ; /* Reserved, sample compression */
short res3 ; /* Reserved */
char ext [20] ; /* Additional filename space, used if (name[7] != 0) */
char user [64] ; /* User defined. Typically ASCII message */
} AVR_HEADER ;
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int avr_close (SF_PRIVATE *psf) ;
static int avr_read_header (SF_PRIVATE *psf) ;
static int avr_write_header (SF_PRIVATE *psf, int calc_length) ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
avr_open (SF_PRIVATE *psf)
{ int error = 0 ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = avr_read_header (psf)))
return error ;
} ;
if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_AVR)
return SFE_BAD_OPEN_FORMAT ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ psf->endian = SF_ENDIAN (psf->sf.format) ;
psf->endian = SF_ENDIAN_BIG ;
if (avr_write_header (psf, SF_FALSE))
return psf->error ;
psf->write_header = avr_write_header ;
} ;
psf->container_close = avr_close ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
error = pcm_init (psf) ;
return error ;
} /* avr_open */
static int
avr_read_header (SF_PRIVATE *psf)
{ AVR_HEADER hdr ;
memset (&hdr, 0, sizeof (hdr)) ;
psf_binheader_readf (psf, "pmb", 0, &hdr.marker, &hdr.name, sizeof (hdr.name)) ;
psf_log_printf (psf, "%M\n", hdr.marker) ;
if (hdr.marker != TWOBIT_MARKER)
return SFE_AVR_X ;
psf_log_printf (psf, " Name : %s\n", hdr.name) ;
psf_binheader_readf (psf, "E22222", &hdr.mono, &hdr.rez, &hdr.sign, &hdr.loop, &hdr.midi) ;
psf->sf.channels = (hdr.mono & 1) + 1 ;
psf_log_printf (psf, " Channels : %d\n Bit width : %d\n Signed : %s\n",
(hdr.mono & 1) + 1, hdr.rez, hdr.sign ? "yes" : "no") ;
switch ((hdr.rez << 16) + (hdr.sign & 1))
{ case ((8 << 16) + 0) :
psf->sf.format = SF_FORMAT_AVR | SF_FORMAT_PCM_U8 ;
psf->bytewidth = 1 ;
break ;
case ((8 << 16) + 1) :
psf->sf.format = SF_FORMAT_AVR | SF_FORMAT_PCM_S8 ;
psf->bytewidth = 1 ;
break ;
case ((16 << 16) + 1) :
psf->sf.format = SF_FORMAT_AVR | SF_FORMAT_PCM_16 ;
psf->bytewidth = 2 ;
break ;
default :
psf_log_printf (psf, "Error : bad rez/sign combination.\n") ;
return SFE_AVR_X ;
} ;
psf_binheader_readf (psf, "E4444", &hdr.srate, &hdr.frames, &hdr.lbeg, &hdr.lend) ;
psf->sf.frames = hdr.frames ;
psf->sf.samplerate = hdr.srate ;
psf_log_printf (psf, " Frames : %D\n", psf->sf.frames) ;
psf_log_printf (psf, " Sample rate : %d\n", psf->sf.samplerate) ;
psf_binheader_readf (psf, "E222", &hdr.res1, &hdr.res2, &hdr.res3) ;
psf_binheader_readf (psf, "bb", hdr.ext, sizeof (hdr.ext), hdr.user, sizeof (hdr.user)) ;
psf_log_printf (psf, " Ext : %s\n User : %s\n", hdr.ext, hdr.user) ;
psf->endian = SF_ENDIAN_BIG ;
psf->dataoffset = AVR_HDR_SIZE ;
psf->datalength = hdr.frames * (hdr.rez / 8) ;
if (psf->fileoffset > 0)
psf->filelength = AVR_HDR_SIZE + psf->datalength ;
if (psf_ftell (psf) != psf->dataoffset)
psf_binheader_readf (psf, "j", psf->dataoffset - psf_ftell (psf)) ;
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
if (psf->sf.frames == 0 && psf->blockwidth)
psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ;
return 0 ;
} /* avr_read_header */
static int
avr_write_header (SF_PRIVATE *psf, int calc_length)
{ sf_count_t current ;
int sign ;
if (psf->pipeoffset > 0)
return 0 ;
current = psf_ftell (psf) ;
if (calc_length)
{ psf->filelength = psf_get_filelen (psf) ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf->dataend)
psf->datalength -= psf->filelength - psf->dataend ;
psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
} ;
/* Reset the current header length to zero. */
psf->header [0] = 0 ;
psf->headindex = 0 ;
/*
** Only attempt to seek if we are not writng to a pipe. If we are
** writing to a pipe we shouldn't be here anyway.
*/
if (psf->is_pipe == SF_FALSE)
psf_fseek (psf, 0, SEEK_SET) ;
psf_binheader_writef (psf, "Emz22", TWOBIT_MARKER, make_size_t (8),
psf->sf.channels == 2 ? 0xFFFF : 0, psf->bytewidth * 8) ;
sign = ((SF_CODEC (psf->sf.format)) == SF_FORMAT_PCM_U8) ? 0 : 0xFFFF ;
psf_binheader_writef (psf, "E222", sign, 0, 0xFFFF) ;
psf_binheader_writef (psf, "E4444", psf->sf.samplerate, psf->sf.frames, 0, 0) ;
psf_binheader_writef (psf, "E222zz", 0, 0, 0, make_size_t (20), make_size_t (64)) ;
/* Header construction complete so write it out. */
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
if (psf->error)
return psf->error ;
psf->dataoffset = psf->headindex ;
if (current > 0)
psf_fseek (psf, current, SEEK_SET) ;
return psf->error ;
} /* avr_write_header */
static int
avr_close (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
avr_write_header (psf, SF_TRUE) ;
return 0 ;
} /* avr_close */

View File

@@ -0,0 +1,190 @@
/*
** Copyright (C) 2006-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
** Copyright (C) 2006 Paul Davis <paul@linuxaudiosystems.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include "common.h"
static int gen_coding_history (char * added_history, int added_history_max, const SF_INFO * psfinfo) ;
static inline size_t
bc_min_size (const SF_BROADCAST_INFO* info)
{ if (info == NULL)
return 0 ;
return offsetof (SF_BROADCAST_INFO, coding_history) + info->coding_history_size ;
} /* bc_min_size */
SF_BROADCAST_INFO_16K*
broadcast_var_alloc (void)
{ return calloc (1, sizeof (SF_BROADCAST_INFO_16K)) ;
} /* broadcast_var_alloc */
int
broadcast_var_set (SF_PRIVATE *psf, const SF_BROADCAST_INFO * info, size_t datasize)
{ size_t len ;
if (info == NULL)
return SF_FALSE ;
if (bc_min_size (info) > datasize)
{ psf->error = SFE_BAD_BROADCAST_INFO_SIZE ;
return SF_FALSE ;
} ;
if (datasize >= sizeof (SF_BROADCAST_INFO_16K))
{ psf->error = SFE_BAD_BROADCAST_INFO_TOO_BIG ;
return SF_FALSE ;
} ;
if (psf->broadcast_16k == NULL)
{ if ((psf->broadcast_16k = broadcast_var_alloc ()) == NULL)
{ psf->error = SFE_MALLOC_FAILED ;
return SF_FALSE ;
} ;
} ;
memcpy (psf->broadcast_16k, info, offsetof (SF_BROADCAST_INFO, coding_history)) ;
psf_strlcpy_crlf (psf->broadcast_16k->coding_history, info->coding_history, sizeof (psf->broadcast_16k->coding_history), datasize - offsetof (SF_BROADCAST_INFO, coding_history)) ;
len = strlen (psf->broadcast_16k->coding_history) ;
if (len > 0 && psf->broadcast_16k->coding_history [len - 1] != '\n')
psf_strlcat (psf->broadcast_16k->coding_history, sizeof (psf->broadcast_16k->coding_history), "\r\n") ;
if (psf->file.mode == SFM_WRITE)
{ char added_history [256] ;
gen_coding_history (added_history, sizeof (added_history), &(psf->sf)) ;
psf_strlcat (psf->broadcast_16k->coding_history, sizeof (psf->broadcast_16k->coding_history), added_history) ;
} ;
/* Force coding_history_size to be even. */
len = strlen (psf->broadcast_16k->coding_history) ;
len += (len & 1) ? 1 : 2 ;
psf->broadcast_16k->coding_history_size = len ;
/* Currently writing this version. */
psf->broadcast_16k->version = 1 ;
return SF_TRUE ;
} /* broadcast_var_set */
int
broadcast_var_get (SF_PRIVATE *psf, SF_BROADCAST_INFO * data, size_t datasize)
{ size_t size ;
if (psf->broadcast_16k == NULL)
return SF_FALSE ;
size = SF_MIN (datasize, bc_min_size ((const SF_BROADCAST_INFO *) psf->broadcast_16k)) ;
memcpy (data, psf->broadcast_16k, size) ;
return SF_TRUE ;
} /* broadcast_var_get */
/*------------------------------------------------------------------------------
*/
static int
gen_coding_history (char * added_history, int added_history_max, const SF_INFO * psfinfo)
{ char chnstr [16] ;
int count, width ;
/*
** From : http://www.sr.se/utveckling/tu/bwf/docs/codhist2.htm
**
** Parameter Variable string <allowed option> Unit
** ==========================================================================================
** Coding Algorithm A=<ANALOGUE, PCM, MPEG1L1, MPEG1L2, MPEG1L3,
** MPEG2L1, MPEG2L2, MPEG2L3>
** Sampling frequency F=<11000,22050,24000,32000,44100,48000> [Hz]
** Bit-rate B=<any bit-rate allowed in MPEG 2 (ISO/IEC [kbit/s per channel]
** 13818-3)>
** Word Length W=<8, 12, 14, 16, 18, 20, 22, 24> [bits]
** Mode M=<mono, stereo, dual-mono, joint-stereo>
** Text, free string T=<a free ASCII-text string for in house use.
** This string should contain no commas (ASCII
** 2Chex). Examples of the contents: ID-No; codec
** type; A/D type>
*/
switch (psfinfo->channels)
{ case 0 :
return SF_FALSE ;
case 1 :
psf_strlcpy (chnstr, sizeof (chnstr), "mono") ;
break ;
case 2 :
psf_strlcpy (chnstr, sizeof (chnstr), "stereo") ;
break ;
default :
snprintf (chnstr, sizeof (chnstr), "%uchn", psfinfo->channels) ;
break ;
} ;
switch (SF_CODEC (psfinfo->format))
{ case SF_FORMAT_PCM_U8 :
case SF_FORMAT_PCM_S8 :
width = 8 ;
break ;
case SF_FORMAT_PCM_16 :
width = 16 ;
break ;
case SF_FORMAT_PCM_24 :
width = 24 ;
break ;
case SF_FORMAT_PCM_32 :
width = 32 ;
break ;
case SF_FORMAT_FLOAT :
width = 24 ; /* Bits in the mantissa + 1 */
break ;
case SF_FORMAT_DOUBLE :
width = 53 ; /* Bits in the mantissa + 1 */
break ;
case SF_FORMAT_ULAW :
case SF_FORMAT_ALAW :
width = 12 ;
break ;
default :
width = 42 ;
break ;
} ;
count = snprintf (added_history, added_history_max,
"A=PCM,F=%u,W=%hu,M=%s,T=%s-%s\r\n",
psfinfo->samplerate, width, chnstr, PACKAGE, VERSION) ;
if (count >= added_history_max)
return 0 ;
return count ;
} /* gen_coding_history */

View File

@@ -0,0 +1,620 @@
/*
** Copyright (C) 2005-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <inttypes.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#include "chanmap.h"
/*------------------------------------------------------------------------------
** Macros to handle big/little endian issues.
*/
#define aac_MARKER MAKE_MARKER ('a', 'a', 'c', ' ')
#define alac_MARKER MAKE_MARKER ('a', 'l', 'a', 'c')
#define alaw_MARKER MAKE_MARKER ('a', 'l', 'a', 'w')
#define caff_MARKER MAKE_MARKER ('c', 'a', 'f', 'f')
#define chan_MARKER MAKE_MARKER ('c', 'h', 'a', 'n')
#define data_MARKER MAKE_MARKER ('d', 'a', 't', 'a')
#define desc_MARKER MAKE_MARKER ('d', 'e', 's', 'c')
#define edct_MARKER MAKE_MARKER ('e', 'd', 'c', 't')
#define free_MARKER MAKE_MARKER ('f', 'r', 'e', 'e')
#define ima4_MARKER MAKE_MARKER ('i', 'm', 'a', '4')
#define info_MARKER MAKE_MARKER ('i', 'n', 'f', 'o')
#define inst_MARKER MAKE_MARKER ('i', 'n', 's', 't')
#define kuki_MARKER MAKE_MARKER ('k', 'u', 'k', 'i')
#define lpcm_MARKER MAKE_MARKER ('l', 'p', 'c', 'm')
#define mark_MARKER MAKE_MARKER ('m', 'a', 'r', 'k')
#define midi_MARKER MAKE_MARKER ('m', 'i', 'd', 'i')
#define mp1_MARKER MAKE_MARKER ('.', 'm', 'p', '1')
#define mp2_MARKER MAKE_MARKER ('.', 'm', 'p', '2')
#define mp3_MARKER MAKE_MARKER ('.', 'm', 'p', '3')
#define ovvw_MARKER MAKE_MARKER ('o', 'v', 'v', 'w')
#define pakt_MARKER MAKE_MARKER ('p', 'a', 'k', 't')
#define peak_MARKER MAKE_MARKER ('p', 'e', 'a', 'k')
#define regn_MARKER MAKE_MARKER ('r', 'e', 'g', 'n')
#define strg_MARKER MAKE_MARKER ('s', 't', 'r', 'g')
#define umid_MARKER MAKE_MARKER ('u', 'm', 'i', 'd')
#define uuid_MARKER MAKE_MARKER ('u', 'u', 'i', 'd')
#define ulaw_MARKER MAKE_MARKER ('u', 'l', 'a', 'w')
#define MAC3_MARKER MAKE_MARKER ('M', 'A', 'C', '3')
#define MAC6_MARKER MAKE_MARKER ('M', 'A', 'C', '6')
#define CAF_PEAK_CHUNK_SIZE(ch) ((int) (sizeof (int) + ch * (sizeof (float) + 8)))
#define SFE_CAF_NOT_CAF 666
#define SFE_CAF_NO_DESC 667
#define SFE_CAF_BAD_PEAK 668
/*------------------------------------------------------------------------------
** Typedefs.
*/
typedef struct
{ unsigned char srate [8] ;
unsigned int fmt_id ;
unsigned int fmt_flags ;
unsigned int pkt_bytes ;
unsigned int pkt_frames ;
unsigned int channels_per_frame ;
unsigned int bits_per_chan ;
} DESC_CHUNK ;
typedef struct
{ int chanmap_tag ;
} CAF_PRIVATE ;
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int caf_close (SF_PRIVATE *psf) ;
static int caf_read_header (SF_PRIVATE *psf) ;
static int caf_write_header (SF_PRIVATE *psf, int calc_length) ;
static int caf_command (SF_PRIVATE *psf, int command, void *data, int datasize) ;
static int caf_read_chanmap (SF_PRIVATE * psf, sf_count_t chunk_size) ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
caf_open (SF_PRIVATE *psf)
{ int subformat, format, error = 0 ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = caf_read_header (psf)))
return error ;
} ;
subformat = SF_CODEC (psf->sf.format) ;
if ((psf->container_data = calloc (1, sizeof (CAF_PRIVATE))) == NULL)
return SFE_MALLOC_FAILED ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if (psf->is_pipe)
return SFE_NO_PIPE_WRITE ;
format = SF_CONTAINER (psf->sf.format) ;
if (format != SF_FORMAT_CAF)
return SFE_BAD_OPEN_FORMAT ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
if (psf->file.mode != SFM_RDWR || psf->filelength < 44)
{ psf->filelength = 0 ;
psf->datalength = 0 ;
psf->dataoffset = 0 ;
psf->sf.frames = 0 ;
} ;
psf->str_flags = SF_STR_ALLOW_START ;
/*
** By default, add the peak chunk to floating point files. Default behaviour
** can be switched off using sf_command (SFC_SET_PEAK_CHUNK, SF_FALSE).
*/
if (psf->file.mode == SFM_WRITE && (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE))
{ if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL)
return SFE_MALLOC_FAILED ;
psf->peak_info->peak_loc = SF_PEAK_START ;
} ;
if ((error = caf_write_header (psf, SF_FALSE)) != 0)
return error ;
psf->write_header = caf_write_header ;
} ;
psf->container_close = caf_close ;
psf->command = caf_command ;
switch (subformat)
{ case SF_FORMAT_PCM_S8 :
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_24 :
case SF_FORMAT_PCM_32 :
error = pcm_init (psf) ;
break ;
case SF_FORMAT_ULAW :
error = ulaw_init (psf) ;
break ;
case SF_FORMAT_ALAW :
error = alaw_init (psf) ;
break ;
/* Lite remove start */
case SF_FORMAT_FLOAT :
error = float32_init (psf) ;
break ;
case SF_FORMAT_DOUBLE :
error = double64_init (psf) ;
break ;
/* Lite remove end */
default :
return SFE_UNSUPPORTED_ENCODING ;
} ;
return error ;
} /* caf_open */
static int
caf_close (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
caf_write_header (psf, SF_TRUE) ;
return 0 ;
} /* caf_close */
static int
caf_command (SF_PRIVATE * psf, int command, void * UNUSED (data), int UNUSED (datasize))
{ CAF_PRIVATE *pcaf ;
if ((pcaf = psf->container_data) == NULL)
return SFE_INTERNAL ;
switch (command)
{ case SFC_SET_CHANNEL_MAP_INFO :
pcaf->chanmap_tag = aiff_caf_find_channel_layout_tag (psf->channel_map, psf->sf.channels) ;
return (pcaf->chanmap_tag != 0) ;
default :
break ;
} ;
return 0 ;
} /* caf_command */
/*------------------------------------------------------------------------------
*/
static int
decode_desc_chunk (SF_PRIVATE *psf, const DESC_CHUNK *desc)
{ int format ;
psf->sf.channels = desc->channels_per_frame ;
format = SF_FORMAT_CAF | (psf->endian == SF_ENDIAN_LITTLE ? SF_ENDIAN_LITTLE : 0) ;
if (desc->fmt_id == lpcm_MARKER && desc->fmt_flags & 1)
{ /* Floating point data. */
if (desc->bits_per_chan == 32 && desc->pkt_bytes == 4 * desc->channels_per_frame)
{ psf->bytewidth = 4 ;
return format | SF_FORMAT_FLOAT ;
} ;
if (desc->bits_per_chan == 64 && desc->pkt_bytes == 8 * desc->channels_per_frame)
{ psf->bytewidth = 8 ;
return format | SF_FORMAT_DOUBLE ;
} ;
} ;
if ((desc->fmt_flags & 1) != 0)
{ psf_log_printf (psf, "**** Ooops, 'desc' chunk suggests float data, but other info invalid.\n") ;
return 0 ;
} ;
if (desc->fmt_id == lpcm_MARKER)
{ /* Integer data. */
if (desc->bits_per_chan == 32 && desc->pkt_bytes == 4 * desc->channels_per_frame)
{ psf->bytewidth = 4 ;
return format | SF_FORMAT_PCM_32 ;
} ;
if (desc->bits_per_chan == 24 && desc->pkt_bytes == 3 * desc->channels_per_frame)
{ psf->bytewidth = 3 ;
return format | SF_FORMAT_PCM_24 ;
} ;
if (desc->bits_per_chan == 16 && desc->pkt_bytes == 2 * desc->channels_per_frame)
{ psf->bytewidth = 2 ;
return format | SF_FORMAT_PCM_16 ;
} ;
if (desc->bits_per_chan == 8 && desc->pkt_bytes == 1 * desc->channels_per_frame)
{ psf->bytewidth = 1 ;
return format | SF_FORMAT_PCM_S8 ;
} ;
} ;
if (desc->fmt_id == alaw_MARKER && desc->bits_per_chan == 8)
{ psf->bytewidth = 1 ;
return format | SF_FORMAT_ALAW ;
} ;
if (desc->fmt_id == ulaw_MARKER && desc->bits_per_chan == 8)
{ psf->bytewidth = 1 ;
return format | SF_FORMAT_ULAW ;
} ;
return 0 ;
} /* decode_desc_chunk */
static int
caf_read_header (SF_PRIVATE *psf)
{ DESC_CHUNK desc ;
sf_count_t chunk_size ;
double srate ;
short version, flags ;
int marker, k, have_data = 0, error ;
memset (&desc, 0, sizeof (desc)) ;
/* Set position to start of file to begin reading header. */
psf_binheader_readf (psf, "pmE2E2", 0, &marker, &version, &flags) ;
psf_log_printf (psf, "%M\n Version : %d\n Flags : %x\n", marker, version, flags) ;
if (marker != caff_MARKER)
return SFE_CAF_NOT_CAF ;
psf_binheader_readf (psf, "mE8b", &marker, &chunk_size, psf->u.ucbuf, 8) ;
srate = double64_be_read (psf->u.ucbuf) ;
snprintf (psf->u.cbuf, sizeof (psf->u.cbuf), "%5.3f", srate) ;
psf_log_printf (psf, "%M : %D\n Sample rate : %s\n", marker, chunk_size, psf->u.cbuf) ;
if (marker != desc_MARKER)
return SFE_CAF_NO_DESC ;
if (chunk_size < SIGNED_SIZEOF (DESC_CHUNK))
{ psf_log_printf (psf, "**** Chunk size too small. Should be > 32 bytes.\n") ;
return SFE_MALFORMED_FILE ;
} ;
psf->sf.samplerate = lrint (srate) ;
psf_binheader_readf (psf, "mE44444", &desc.fmt_id, &desc.fmt_flags, &desc.pkt_bytes, &desc.pkt_frames,
&desc.channels_per_frame, &desc.bits_per_chan) ;
psf_log_printf (psf, " Format id : %M\n Format flags : %x\n Bytes / packet : %u\n"
" Frames / packet : %u\n Channels / frame : %u\n Bits / channel : %u\n",
desc.fmt_id, desc.fmt_flags, desc.pkt_bytes, desc.pkt_frames, desc.channels_per_frame, desc.bits_per_chan) ;
if (desc.channels_per_frame > SF_MAX_CHANNELS)
{ psf_log_printf (psf, "**** Bad channels per frame value %u.\n", desc.channels_per_frame) ;
return SFE_MALFORMED_FILE ;
} ;
if (chunk_size > SIGNED_SIZEOF (DESC_CHUNK))
psf_binheader_readf (psf, "j", (int) (chunk_size - sizeof (DESC_CHUNK))) ;
psf->sf.channels = desc.channels_per_frame ;
while (have_data == 0 && psf_ftell (psf) < psf->filelength - SIGNED_SIZEOF (marker))
{ psf_binheader_readf (psf, "mE8", &marker, &chunk_size) ;
switch (marker)
{ case peak_MARKER :
psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
if (chunk_size != CAF_PEAK_CHUNK_SIZE (psf->sf.channels))
{ psf_binheader_readf (psf, "j", (int) chunk_size) ;
psf_log_printf (psf, "*** File PEAK chunk %D should be %d.\n", chunk_size, CAF_PEAK_CHUNK_SIZE (psf->sf.channels)) ;
return SFE_CAF_BAD_PEAK ;
} ;
if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL)
return SFE_MALLOC_FAILED ;
/* read in rest of PEAK chunk. */
psf_binheader_readf (psf, "E4", & (psf->peak_info->edit_number)) ;
psf_log_printf (psf, " edit count : %d\n", psf->peak_info->edit_number) ;
psf_log_printf (psf, " Ch Position Value\n") ;
for (k = 0 ; k < psf->sf.channels ; k++)
{ sf_count_t position ;
float value ;
psf_binheader_readf (psf, "Ef8", &value, &position) ;
psf->peak_info->peaks [k].value = value ;
psf->peak_info->peaks [k].position = position ;
snprintf (psf->u.cbuf, sizeof (psf->u.cbuf), " %2d %-12" PRId64 " %g\n", k, position, value) ;
psf_log_printf (psf, psf->u.cbuf) ;
} ;
psf->peak_info->peak_loc = SF_PEAK_START ;
break ;
case chan_MARKER :
if (chunk_size < 12)
{ psf_log_printf (psf, "%M : %D (should be >= 12)\n", marker, chunk_size) ;
psf_binheader_readf (psf, "j", (int) chunk_size) ;
break ;
}
psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
if ((error = caf_read_chanmap (psf, chunk_size)))
return error ;
break ;
case free_MARKER :
psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
psf_binheader_readf (psf, "j", (int) chunk_size) ;
break ;
case data_MARKER :
if (psf->filelength > 0 && chunk_size + psf->headindex != psf->filelength)
psf_log_printf (psf, "%M : %D (should be %D)\n", marker, chunk_size, chunk_size + 4) ;
else
psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
psf_binheader_readf (psf, "E4", &k) ;
psf_log_printf (psf, " edit : %u\n", k) ;
have_data = 1 ;
break ;
default :
psf_log_printf (psf, " %M : %D (skipped)\n", marker, chunk_size) ;
psf_binheader_readf (psf, "j", (int) chunk_size) ;
break ;
} ;
} ;
if (have_data == 0)
{ psf_log_printf (psf, "**** Error, could not find 'data' chunk.\n") ;
return SFE_MALFORMED_FILE ;
} ;
psf_log_printf (psf, "End\n") ;
psf->dataoffset = psf_ftell (psf) ;
psf->datalength = psf->filelength - psf->dataoffset ;
psf->endian = (desc.fmt_flags & 2) ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG ;
if ((psf->sf.format = decode_desc_chunk (psf, &desc)) == 0)
return SFE_UNSUPPORTED_ENCODING ;
if (psf->bytewidth > 0)
psf->sf.frames = psf->datalength / psf->bytewidth ;
return 0 ;
} /* caf_read_header */
/*------------------------------------------------------------------------------
*/
static int
caf_write_header (SF_PRIVATE *psf, int calc_length)
{ CAF_PRIVATE *pcaf ;
DESC_CHUNK desc ;
sf_count_t current, free_len ;
int subformat ;
if ((pcaf = psf->container_data) == NULL)
return SFE_INTERNAL ;
memset (&desc, 0, sizeof (desc)) ;
current = psf_ftell (psf) ;
if (calc_length)
{ psf->filelength = psf_get_filelen (psf) ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf->dataend)
psf->datalength -= psf->filelength - psf->dataend ;
if (psf->bytewidth > 0)
psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
} ;
/* Reset the current header length to zero. */
psf->header [0] = 0 ;
psf->headindex = 0 ;
psf_fseek (psf, 0, SEEK_SET) ;
/* 'caff' marker, version and flags. */
psf_binheader_writef (psf, "Em22", caff_MARKER, 1, 0) ;
/* 'desc' marker and chunk size. */
psf_binheader_writef (psf, "Em8", desc_MARKER, (sf_count_t) (sizeof (DESC_CHUNK))) ;
double64_be_write (1.0 * psf->sf.samplerate, psf->u.ucbuf) ;
psf_binheader_writef (psf, "b", psf->u.ucbuf, make_size_t (8)) ;
subformat = SF_CODEC (psf->sf.format) ;
psf->endian = SF_ENDIAN (psf->sf.format) ;
if (CPU_IS_BIG_ENDIAN && (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU))
psf->endian = SF_ENDIAN_BIG ;
else if (CPU_IS_LITTLE_ENDIAN && (psf->endian == SF_ENDIAN_LITTLE || psf->endian == SF_ENDIAN_CPU))
psf->endian = SF_ENDIAN_LITTLE ;
if (psf->endian == SF_ENDIAN_LITTLE)
desc.fmt_flags = 2 ;
else
psf->endian = SF_ENDIAN_BIG ;
/* initial section (same for all, it appears) */
switch (subformat)
{ case SF_FORMAT_PCM_S8 :
desc.fmt_id = lpcm_MARKER ;
psf->bytewidth = 1 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.pkt_frames = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 8 ;
break ;
case SF_FORMAT_PCM_16 :
desc.fmt_id = lpcm_MARKER ;
psf->bytewidth = 2 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.pkt_frames = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 16 ;
break ;
case SF_FORMAT_PCM_24 :
psf->bytewidth = 3 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.pkt_frames = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 24 ;
desc.fmt_id = lpcm_MARKER ;
break ;
case SF_FORMAT_PCM_32 :
desc.fmt_id = lpcm_MARKER ;
psf->bytewidth = 4 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.pkt_frames = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 32 ;
break ;
case SF_FORMAT_FLOAT :
desc.fmt_id = lpcm_MARKER ;
desc.fmt_flags |= 1 ;
psf->bytewidth = 4 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.pkt_frames = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 32 ;
break ;
case SF_FORMAT_DOUBLE :
desc.fmt_id = lpcm_MARKER ;
desc.fmt_flags |= 1 ;
psf->bytewidth = 8 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.pkt_frames = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 64 ;
break ;
case SF_FORMAT_ALAW :
desc.fmt_id = alaw_MARKER ;
psf->bytewidth = 1 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.pkt_frames = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 8 ;
break ;
case SF_FORMAT_ULAW :
desc.fmt_id = ulaw_MARKER ;
psf->bytewidth = 1 ;
desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
desc.pkt_frames = 1 ;
desc.channels_per_frame = psf->sf.channels ;
desc.bits_per_chan = 8 ;
break ;
default :
return SFE_UNIMPLEMENTED ;
} ;
psf_binheader_writef (psf, "mE44444", desc.fmt_id, desc.fmt_flags, desc.pkt_bytes, desc.pkt_frames, desc.channels_per_frame, desc.bits_per_chan) ;
#if 0
if (psf->str_flags & SF_STR_LOCATE_START)
caf_write_strings (psf, SF_STR_LOCATE_START) ;
#endif
if (psf->peak_info != NULL)
{ int k ;
psf_binheader_writef (psf, "Em84", peak_MARKER, (sf_count_t) CAF_PEAK_CHUNK_SIZE (psf->sf.channels), psf->peak_info->edit_number) ;
for (k = 0 ; k < psf->sf.channels ; k++)
psf_binheader_writef (psf, "Ef8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ;
} ;
if (psf->channel_map && pcaf->chanmap_tag)
psf_binheader_writef (psf, "Em8444", chan_MARKER, (sf_count_t) 12, pcaf->chanmap_tag, 0, 0) ;
/* Add free chunk so that the actual audio data starts at a multiple 0x1000. */
free_len = 0x1000 - psf->headindex - 16 - 12 ;
while (free_len < 0)
free_len += 0x1000 ;
psf_binheader_writef (psf, "Em8z", free_MARKER, free_len, (int) free_len) ;
psf_binheader_writef (psf, "Em84", data_MARKER, psf->datalength + 4, 0) ;
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
if (psf->error)
return psf->error ;
psf->dataoffset = psf->headindex ;
if (current < psf->dataoffset)
psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
else if (current > 0)
psf_fseek (psf, current, SEEK_SET) ;
return psf->error ;
} /* caf_write_header */
static int
caf_read_chanmap (SF_PRIVATE * psf, sf_count_t chunk_size)
{ const AIFF_CAF_CHANNEL_MAP * map_info ;
unsigned channel_bitmap, channel_decriptions, bytesread ;
int layout_tag ;
bytesread = psf_binheader_readf (psf, "E444", &layout_tag, &channel_bitmap, &channel_decriptions) ;
map_info = aiff_caf_of_channel_layout_tag (layout_tag) ;
psf_log_printf (psf, " Tag : %x\n", layout_tag) ;
if (map_info)
psf_log_printf (psf, " Layout : %s\n", map_info->name) ;
if (bytesread < chunk_size)
psf_binheader_readf (psf, "j", chunk_size - bytesread) ;
if (map_info->channel_map != NULL)
{ size_t chanmap_size = psf->sf.channels * sizeof (psf->channel_map [0]) ;
free (psf->channel_map) ;
if ((psf->channel_map = malloc (chanmap_size)) == NULL)
return SFE_MALLOC_FAILED ;
memcpy (psf->channel_map, map_info->channel_map, chanmap_size) ;
} ;
return 0 ;
} /* caf_read_chanmap */

View File

@@ -0,0 +1,262 @@
/*
** Copyright (C) 2009-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
** Mostly from "Apple Core Audio Format Specification 1.0":
**
** http://developer.apple.com/documentation/MusicAudio/Reference/CAFSpec/CAFSpec.pdf
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sndfile.h"
#include "common.h"
#include "chanmap.h"
static const AIFF_CAF_CHANNEL_MAP zero_chan [] =
{ { (0 << 16) | 0, NULL, "Use channel descriptions." },
{ (1 << 16) | 0, NULL, "Use channel bitmap." }
} ; /* zero_chan */
static const int one_chan_mono [1] = { SF_CHANNEL_MAP_MONO } ;
static const AIFF_CAF_CHANNEL_MAP one_chan [] =
{ { (100 << 16) | 1, one_chan_mono, "mono" }
} ; /* one_chan */
static const int two_channel_stereo [2] = { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT } ;
static const AIFF_CAF_CHANNEL_MAP two_chan [] =
{ { (101 << 16) | 2, two_channel_stereo, "stereo (L, R)" },
{ (102 << 16) | 2, two_channel_stereo, "stereo headphones (L, R)" },
#if 0
{ (103 << 16) | 2, NULL, "matrix stereo (Lt, Rt)" },
{ (104 << 16) | 2, NULL, "2 channels (mid, side)" },
{ (105 << 16) | 2, NULL, "coincident mic pair" },
{ (106 << 16) | 2, NULL, "binaural stereo (L, R)"
}
#endif
} ; /* two_chan */
static const int three_channel_mpeg_30a [3] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER } ;
static const int three_channel_mpeg_30b [3] =
{ SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT } ;
static const int three_channel_itu_21 [3] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_CENTER } ;
static const int three_channel_dvd_4 [3] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_LFE } ;
static const AIFF_CAF_CHANNEL_MAP three_chan [] =
{ { (113 << 16) | 3, three_channel_mpeg_30a, "MPEG 3 0 A (L, R, C)" },
{ (114 << 16) | 3, three_channel_mpeg_30b, "MPEG 3 0 B (C, L, R)" },
{ (131 << 16) | 3, three_channel_itu_21, "ITU 2.1 (L, R, Cs)" },
{ (133 << 16) | 3, three_channel_dvd_4, "DVD 4 (L, R, LFE)" }
} ; /* three_chan */
static const int four_channel_ambisonc_b [4] =
{ SF_CHANNEL_MAP_AMBISONIC_B_W, SF_CHANNEL_MAP_AMBISONIC_B_X, SF_CHANNEL_MAP_AMBISONIC_B_Y, SF_CHANNEL_MAP_AMBISONIC_B_Z } ;
static const int four_channel_quad [4] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ;
static const int four_channel_mpeg_40a [4] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_REAR_CENTER } ;
static const int four_channel_mpeg_40b [4] =
{ SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_CENTER } ;
static const int four_channel_itu_23 [4] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ;
static const int four_channel_dvd_5 [4] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_CENTER } ;
static const int four_channel_dvd_10 [4] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE } ;
static const AIFF_CAF_CHANNEL_MAP four_chan [] =
{ { (107 << 16) | 4, four_channel_ambisonc_b, "ambisonic B (W, X, Y, Z)" },
{ (108 << 16) | 4, four_channel_quad, "quad (Lfront, Rfront, Lrear, Rrear)" },
{ (115 << 16) | 4, four_channel_mpeg_40a, "MPEG 4.0 A (L, R, C, Cs)" },
{ (116 << 16) | 4, four_channel_mpeg_40b, "MPEG 4.0 B (C, L, R, Cs)" },
{ (132 << 16) | 4, four_channel_itu_23, "ITU 2.3 (L, R, Ls, Rs)" },
{ (134 << 16) | 4, four_channel_dvd_5, "DVD 5 (L, R, LFE, Cs)" },
{ (136 << 16) | 4, four_channel_dvd_10, "DVD 10 (L, R, C, LFE)" }
} ; /* four_chan */
static const int five_channel_pentagonal [5] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_CENTER } ;
static const int five_channel_mpeg_50_a [5] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ;
static const int five_channel_mpeg_50_b [5] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_CENTER } ;
static const int five_channel_mpeg_50_c [5] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ;
static const int five_channel_mpeg_50_d [5] =
{ SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ;
static const int five_channel_dvd_6 [5] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ;
static const int five_channel_dvd_11 [5] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_CENTER } ;
static const int five_channel_dvd_18 [5] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_LFE } ;
static const AIFF_CAF_CHANNEL_MAP five_chan [] =
{ { (109 << 16) | 5, five_channel_pentagonal, "pentagonal (L, R, Lrear, Rrear, C)" },
{ (117 << 16) | 5, five_channel_mpeg_50_a, "MPEG 5.0 A (L, R, C, Ls, Rs)" },
{ (118 << 16) | 5, five_channel_mpeg_50_b, "MPEG 5.0 B (L, R, Ls, Rs, C)" },
{ (119 << 16) | 5, five_channel_mpeg_50_c, "MPEG 5.0 C (L, C, R, Ls, Rs,)" },
{ (120 << 16) | 5, five_channel_mpeg_50_d, "MPEG 5.0 D (C, L, R, Ls, Rs)" },
{ (135 << 16) | 5, five_channel_dvd_6, "DVD 6 (L, R, LFE, Ls, Rs)" },
{ (137 << 16) | 5, five_channel_dvd_11, "DVD 11 (L, R, C, LFE, Cs)" },
{ (138 << 16) | 5, five_channel_dvd_18, "DVD 18 (L, R, Ls, Rs, LFE)" }
} ; /* five_chan */
static const int six_channel_mpeg_51_a [6] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ;
static const int six_channel_mpeg_51_b [6] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE } ;
static const int six_channel_mpeg_51_c [6] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_LFE } ;
static const int six_channel_mpeg_51_d [6] =
{ SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_LFE } ;
static const int six_channel_audio_unit_60 [6] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_REAR_CENTER } ;
static const int six_channel_aac_60 [6] =
{ SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_REAR_CENTER } ;
static const AIFF_CAF_CHANNEL_MAP six_chan [] =
{ { (110 << 16) | 6, NULL, "hexagonal (L, R, Lr, Rr, C, Rear)" },
{ (121 << 16) | 6, six_channel_mpeg_51_a, "MPEG 5.1 A (L, R, C, LFE, Ls, Rs)" },
{ (122 << 16) | 6, six_channel_mpeg_51_b, "MPEG 5.1 B (L, R, Ls, Rs, C, LFE)" },
{ (123 << 16) | 6, six_channel_mpeg_51_c, "MPEG 5.1 C (L, C, R, Ls, Rs, LFE)" },
{ (124 << 16) | 6, six_channel_mpeg_51_d, "MPEG 5.1 D (C, L, R, Ls, Rs, LFE)" },
{ (139 << 16) | 6, six_channel_audio_unit_60, "AudioUnit 6.0 (L, R, Ls, Rs, C, Cs)" },
{ (141 << 16) | 6, six_channel_aac_60, "AAC 6.0 (C, L, R, Ls, Rs, Cs)" }
} ; /* six_chan */
static const int six_channel_mpeg_61a [7] =
{ SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_REAR_CENTER } ;
static const int six_channel_aac_61 [7] =
{ SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_REAR_CENTER, SF_CHANNEL_MAP_LFE } ;
static const AIFF_CAF_CHANNEL_MAP seven_chan [] =
{ { (125 << 16) | 7, six_channel_mpeg_61a, "MPEG 6.1 A (L, R, C, LFE, Ls, Rs, Cs)" },
{ (140 << 16) | 7, NULL, "AudioUnit 7.0 (L, R, Ls, Rs, C, Rls, Rrs)" },
{ (142 << 16) | 7, six_channel_aac_61, "AAC 6.1 (C, L, R, Ls, Rs, Cs, Lfe)" },
{ (143 << 16) | 7, NULL, "AAC 7.0 (C, L, R, Ls, Rs, Rls, Rrs,)" }
} ; /* seven_chan */
static const AIFF_CAF_CHANNEL_MAP eight_chan [] =
{ { (111 << 16) | 8, NULL,
// front left, front right, rear left, rear right,
// front center, rear center, side left, side right
"octagonal (Lf, Rf, Lr, Rr, Cf, Cr, Ls, Rs)"
},
{ (112 << 16) | 8, NULL,
// left, right, rear left, rear right
// top left, top right, top rear left, top rear right
"cube (L, R, Lrear, Rrear, Ltop, Rtop, Ltoprear, Rtoprear)"
},
{ (126 << 16) | 8, NULL, "MPEG 7.1 A (L, R, C, LFE, Ls, Rs, Lc, Rc)" },
{ (127 << 16) | 8, NULL, "MPEG 7.1 B (C, Lc, Rc, L, R, Ls, Rs, LFE)" },
{ (128 << 16) | 8, NULL, "MPEG 7.1 C (L, R, C, LFE, Ls, R, Rls, Rrs)" },
{ (129 << 16) | 8, NULL, "Emagic Default 7.1 (L, R, Ls, Rs, C, LFE, Lc, Rc)" },
{ (130 << 16) | 8, NULL,
// (ITU_5_1 plus a matrix encoded stereo mix)
"SMPTE DTV (L, R, C, LFE, Ls, Rs, Lt, Rt)"
},
{ (144 << 16) | 8, NULL, "AAC octagonal (C, L, R, Ls, Rs, Rls, Rrs, Cs)" }
} ; /* eight_chan */
#if 0
TMH_10_2_std = (145 << 16) | 16,
// L R C Vhc Lsd Rsd Ls Rs Vhl Vhr Lw Rw Csd Cs LFE1 LFE2
TMH_10_2_full = (146 << 16) | 21,
// TMH_10_2_std plus: Lc Rc HI VI Haptic
#endif
typedef struct
{ const AIFF_CAF_CHANNEL_MAP * map ;
int len ;
} MAP_MAP ;
static const MAP_MAP map [] =
{ { zero_chan, ARRAY_LEN (zero_chan) },
{ one_chan, ARRAY_LEN (one_chan) },
{ two_chan, ARRAY_LEN (two_chan) },
{ three_chan, ARRAY_LEN (three_chan) },
{ four_chan, ARRAY_LEN (four_chan) },
{ five_chan, ARRAY_LEN (five_chan) },
{ six_chan, ARRAY_LEN (six_chan) },
{ seven_chan, ARRAY_LEN (seven_chan) },
{ eight_chan, ARRAY_LEN (eight_chan) }
} ; /* map */
int
aiff_caf_find_channel_layout_tag (const int *chan_map, int channels)
{ const AIFF_CAF_CHANNEL_MAP * curr_map ;
unsigned k, len ;
if (channels < 1 || channels > ARRAY_LEN (map))
return 0 ;
curr_map = map [channels].map ;
len = map [channels].len ;
for (k = 0 ; k < len ; k++)
if (curr_map [k].channel_map != NULL)
if (memcmp (chan_map, curr_map [k].channel_map, channels * sizeof (chan_map [0])) == 0)
return curr_map [k].channel_layout_tag ;
return 0 ;
} /* aiff_caf_find_channel_layout_tag */
const AIFF_CAF_CHANNEL_MAP *
aiff_caf_of_channel_layout_tag (int tag)
{ const AIFF_CAF_CHANNEL_MAP * curr_map ;
unsigned k, len ;
int channels = tag & 0xffff ;
if (channels < 0 || channels > ARRAY_LEN (map))
return NULL ;
curr_map = map [channels].map ;
len = map [channels].len ;
for (k = 0 ; k < len ; k++)
if (curr_map [k].channel_layout_tag == tag)
return curr_map + k ;
return NULL ;
} /* aiff_caf_of_channel_layout_tag */

View File

@@ -0,0 +1,32 @@
/*
** Copyright (C) 2009-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
typedef struct
{ /* The tag in the AIFF or CAF file. */
int channel_layout_tag ;
/* The equivalent array of SF_CHANNEL_MAP_* entries. */
const int * channel_map ;
const char * name ;
} AIFF_CAF_CHANNEL_MAP ;
int aiff_caf_find_channel_layout_tag (const int *chan_map, int channels) ;
const AIFF_CAF_CHANNEL_MAP * aiff_caf_of_channel_layout_tag (int tag) ;

View File

@@ -0,0 +1,54 @@
/*
** Copyright (C) 2008-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdlib.h>
#include <string.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
void
pchk4_store (PRIV_CHUNK4 * pchk, int marker, sf_count_t offset, sf_count_t len)
{
if (pchk->count >= ARRAY_LEN (pchk->l))
return ;
pchk->l [pchk->count].chunk = marker ;
pchk->l [pchk->count].offset = offset ;
pchk->l [pchk->count].len = len ;
pchk->count ++ ;
return ;
} /* pchk4_store */
int
pchk4_find (PRIV_CHUNK4 * pchk, int marker)
{ int k ;
for (k = 0 ; k < pchk->count ; k++)
if (pchk->l [k].chunk == marker)
return k ;
return -1 ;
} /* pchk4_find */

View File

@@ -0,0 +1,376 @@
/*
** Copyright (C) 2001-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "sndfile.h"
#include "common.h"
static SF_FORMAT_INFO const simple_formats [] =
{
{ SF_FORMAT_AIFF | SF_FORMAT_PCM_16,
"AIFF (Apple/SGI 16 bit PCM)", "aiff"
},
{ SF_FORMAT_AIFF | SF_FORMAT_FLOAT,
"AIFF (Apple/SGI 32 bit float)", "aifc"
},
{ SF_FORMAT_AIFF | SF_FORMAT_PCM_S8,
"AIFF (Apple/SGI 8 bit PCM)", "aiff"
},
{ SF_FORMAT_AU | SF_FORMAT_PCM_16,
"AU (Sun/Next 16 bit PCM)", "au"
},
{ SF_FORMAT_AU | SF_FORMAT_ULAW,
"AU (Sun/Next 8-bit u-law)", "au"
},
{ SF_FORMAT_CAF | SF_FORMAT_PCM_16,
"CAF (Apple 16 bit PCM)", "caf"
},
#if HAVE_EXTERNAL_LIBS
{ SF_FORMAT_FLAC | SF_FORMAT_PCM_16,
"FLAC 16 bit", "flac"
},
#endif
{ SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM,
"OKI Dialogic VOX ADPCM", "vox"
},
#if HAVE_EXTERNAL_LIBS
{ SF_FORMAT_OGG | SF_FORMAT_VORBIS,
"Ogg Vorbis (Xiph Foundation)", "oga"
},
#endif
{ SF_FORMAT_WAV | SF_FORMAT_PCM_16,
"WAV (Microsoft 16 bit PCM)", "wav"
},
{ SF_FORMAT_WAV | SF_FORMAT_FLOAT,
"WAV (Microsoft 32 bit float)", "wav"
},
{ SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM,
"WAV (Microsoft 4 bit IMA ADPCM)", "wav"
},
{ SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM,
"WAV (Microsoft 4 bit MS ADPCM)", "wav"
},
{ SF_FORMAT_WAV | SF_FORMAT_PCM_U8,
"WAV (Microsoft 8 bit PCM)", "wav"
},
} ; /* simple_formats */
int
psf_get_format_simple_count (void)
{ return (sizeof (simple_formats) / sizeof (SF_FORMAT_INFO)) ;
} /* psf_get_format_simple_count */
int
psf_get_format_simple (SF_FORMAT_INFO *data)
{ int indx ;
if (data->format < 0 || data->format >= (SIGNED_SIZEOF (simple_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO)))
return SFE_BAD_COMMAND_PARAM ;
indx = data->format ;
memcpy (data, &(simple_formats [indx]), SIGNED_SIZEOF (SF_FORMAT_INFO)) ;
return 0 ;
} /* psf_get_format_simple */
/*============================================================================
** Major format info.
*/
static SF_FORMAT_INFO const major_formats [] =
{
{ SF_FORMAT_AIFF, "AIFF (Apple/SGI)", "aiff" },
{ SF_FORMAT_AU, "AU (Sun/NeXT)", "au" },
{ SF_FORMAT_AVR, "AVR (Audio Visual Research)", "avr" },
{ SF_FORMAT_CAF, "CAF (Apple Core Audio File)", "caf" },
#if HAVE_EXTERNAL_LIBS
{ SF_FORMAT_FLAC, "FLAC (FLAC Lossless Audio Codec)", "flac" },
#endif
{ SF_FORMAT_HTK, "HTK (HMM Tool Kit)", "htk" },
{ SF_FORMAT_SVX, "IFF (Amiga IFF/SVX8/SV16)", "iff" },
{ SF_FORMAT_MAT4, "MAT4 (GNU Octave 2.0 / Matlab 4.2)", "mat" },
{ SF_FORMAT_MAT5, "MAT5 (GNU Octave 2.1 / Matlab 5.0)", "mat" },
{ SF_FORMAT_MPC2K, "MPC (Akai MPC 2k)", "mpc" },
#if HAVE_EXTERNAL_LIBS
{ SF_FORMAT_OGG, "OGG (OGG Container format)", "oga" },
#endif
{ SF_FORMAT_PAF, "PAF (Ensoniq PARIS)", "paf" },
{ SF_FORMAT_PVF, "PVF (Portable Voice Format)", "pvf" },
{ SF_FORMAT_RAW, "RAW (header-less)", "raw" },
{ SF_FORMAT_RF64, "RF64 (RIFF 64)", "rf64" },
{ SF_FORMAT_SD2, "SD2 (Sound Designer II)", "sd2" },
{ SF_FORMAT_SDS, "SDS (Midi Sample Dump Standard)", "sds" },
{ SF_FORMAT_IRCAM, "SF (Berkeley/IRCAM/CARL)", "sf" },
{ SF_FORMAT_VOC, "VOC (Creative Labs)", "voc" },
{ SF_FORMAT_W64, "W64 (SoundFoundry WAVE 64)", "w64" },
{ SF_FORMAT_WAV, "WAV (Microsoft)", "wav" },
{ SF_FORMAT_NIST, "WAV (NIST Sphere)", "wav" },
{ SF_FORMAT_WAVEX, "WAVEX (Microsoft)", "wav" },
{ SF_FORMAT_WVE, "WVE (Psion Series 3)", "wve" },
{ SF_FORMAT_XI, "XI (FastTracker 2)", "xi" },
} ; /* major_formats */
int
psf_get_format_major_count (void)
{ return (sizeof (major_formats) / sizeof (SF_FORMAT_INFO)) ;
} /* psf_get_format_major_count */
int
psf_get_format_major (SF_FORMAT_INFO *data)
{ int indx ;
if (data->format < 0 || data->format >= (SIGNED_SIZEOF (major_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO)))
return SFE_BAD_COMMAND_PARAM ;
indx = data->format ;
memcpy (data, &(major_formats [indx]), SIGNED_SIZEOF (SF_FORMAT_INFO)) ;
return 0 ;
} /* psf_get_format_major */
/*============================================================================
** Subtype format info.
*/
static SF_FORMAT_INFO subtype_formats [] =
{
{ SF_FORMAT_PCM_S8, "Signed 8 bit PCM", NULL },
{ SF_FORMAT_PCM_16, "Signed 16 bit PCM", NULL },
{ SF_FORMAT_PCM_24, "Signed 24 bit PCM", NULL },
{ SF_FORMAT_PCM_32, "Signed 32 bit PCM", NULL },
{ SF_FORMAT_PCM_U8, "Unsigned 8 bit PCM", NULL },
{ SF_FORMAT_FLOAT, "32 bit float", NULL },
{ SF_FORMAT_DOUBLE, "64 bit float", NULL },
{ SF_FORMAT_ULAW, "U-Law", NULL },
{ SF_FORMAT_ALAW, "A-Law", NULL },
{ SF_FORMAT_IMA_ADPCM, "IMA ADPCM", NULL },
{ SF_FORMAT_MS_ADPCM, "Microsoft ADPCM", NULL },
{ SF_FORMAT_GSM610, "GSM 6.10", NULL },
{ SF_FORMAT_G721_32, "32kbs G721 ADPCM", NULL },
{ SF_FORMAT_G723_24, "24kbs G723 ADPCM", NULL },
{ SF_FORMAT_DWVW_12, "12 bit DWVW", NULL },
{ SF_FORMAT_DWVW_16, "16 bit DWVW", NULL },
{ SF_FORMAT_DWVW_24, "24 bit DWVW", NULL },
{ SF_FORMAT_VOX_ADPCM, "VOX ADPCM", "vox" },
{ SF_FORMAT_DPCM_16, "16 bit DPCM", NULL },
{ SF_FORMAT_DPCM_8, "8 bit DPCM", NULL },
#if HAVE_EXTERNAL_LIBS
{ SF_FORMAT_VORBIS, "Vorbis", NULL },
#endif
} ; /* subtype_formats */
int
psf_get_format_subtype_count (void)
{ return (sizeof (subtype_formats) / sizeof (SF_FORMAT_INFO)) ;
} /* psf_get_format_subtype_count */
int
psf_get_format_subtype (SF_FORMAT_INFO *data)
{ int indx ;
if (data->format < 0 || data->format >= (SIGNED_SIZEOF (subtype_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO)))
return SFE_BAD_COMMAND_PARAM ;
indx = data->format ;
memcpy (data, &(subtype_formats [indx]), sizeof (SF_FORMAT_INFO)) ;
return 0 ;
} /* psf_get_format_subtype */
/*==============================================================================
*/
int
psf_get_format_info (SF_FORMAT_INFO *data)
{ int k, format ;
if (SF_CONTAINER (data->format))
{ format = SF_CONTAINER (data->format) ;
for (k = 0 ; k < (SIGNED_SIZEOF (major_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO)) ; k++)
{ if (format == major_formats [k].format)
{ memcpy (data, &(major_formats [k]), sizeof (SF_FORMAT_INFO)) ;
return 0 ;
} ;
} ;
}
else if (SF_CODEC (data->format))
{ format = SF_CODEC (data->format) ;
for (k = 0 ; k < (SIGNED_SIZEOF (subtype_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO)) ; k++)
{ if (format == subtype_formats [k].format)
{ memcpy (data, &(subtype_formats [k]), sizeof (SF_FORMAT_INFO)) ;
return 0 ;
} ;
} ;
} ;
memset (data, 0, sizeof (SF_FORMAT_INFO)) ;
return SFE_BAD_COMMAND_PARAM ;
} /* psf_get_format_info */
/*==============================================================================
*/
double
psf_calc_signal_max (SF_PRIVATE *psf, int normalize)
{ sf_count_t position ;
double max_val, temp, *data ;
int k, len, readcount, save_state ;
/* If the file is not seekable, there is nothing we can do. */
if (! psf->sf.seekable)
{ psf->error = SFE_NOT_SEEKABLE ;
return 0.0 ;
} ;
if (! psf->read_double)
{ psf->error = SFE_UNIMPLEMENTED ;
return 0.0 ;
} ;
save_state = sf_command ((SNDFILE*) psf, SFC_GET_NORM_DOUBLE, NULL, 0) ;
sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, normalize) ;
/* Brute force. Read the whole file and find the biggest sample. */
/* Get current position in file */
position = sf_seek ((SNDFILE*) psf, 0, SEEK_CUR) ;
/* Go to start of file. */
sf_seek ((SNDFILE*) psf, 0, SEEK_SET) ;
data = psf->u.dbuf ;
len = ARRAY_LEN (psf->u.dbuf) ;
for (readcount = 1, max_val = 0.0 ; readcount > 0 ; /* nothing */)
{ readcount = sf_read_double ((SNDFILE*) psf, data, len) ;
for (k = 0 ; k < readcount ; k++)
{ temp = fabs (data [k]) ;
max_val = temp > max_val ? temp : max_val ;
} ;
} ;
/* Return to SNDFILE to original state. */
sf_seek ((SNDFILE*) psf, position, SEEK_SET) ;
sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, save_state) ;
return max_val ;
} /* psf_calc_signal_max */
int
psf_calc_max_all_channels (SF_PRIVATE *psf, double *peaks, int normalize)
{ sf_count_t position ;
double temp, *data ;
int k, len, readcount, save_state ;
int chan ;
/* If the file is not seekable, there is nothing we can do. */
if (! psf->sf.seekable)
return (psf->error = SFE_NOT_SEEKABLE) ;
if (! psf->read_double)
return (psf->error = SFE_UNIMPLEMENTED) ;
save_state = sf_command ((SNDFILE*) psf, SFC_GET_NORM_DOUBLE, NULL, 0) ;
sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, normalize) ;
memset (peaks, 0, sizeof (double) * psf->sf.channels) ;
/* Brute force. Read the whole file and find the biggest sample for each channel. */
position = sf_seek ((SNDFILE*) psf, 0, SEEK_CUR) ; /* Get current position in file */
sf_seek ((SNDFILE*) psf, 0, SEEK_SET) ; /* Go to start of file. */
len = ARRAY_LEN (psf->u.dbuf) ;
data = psf->u.dbuf ;
chan = 0 ;
readcount = len ;
while (readcount > 0)
{ readcount = sf_read_double ((SNDFILE*) psf, data, len) ;
for (k = 0 ; k < readcount ; k++)
{ temp = fabs (data [k]) ;
peaks [chan] = temp > peaks [chan] ? temp : peaks [chan] ;
chan = (chan + 1) % psf->sf.channels ;
} ;
} ;
sf_seek ((SNDFILE*) psf, position, SEEK_SET) ; /* Return to original position. */
sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, save_state) ;
return 0 ;
} /* psf_calc_max_all_channels */
int
psf_get_signal_max (SF_PRIVATE *psf, double *peak)
{ int k ;
if (psf->peak_info == NULL)
return SF_FALSE ;
peak [0] = psf->peak_info->peaks [0].value ;
for (k = 1 ; k < psf->sf.channels ; k++)
peak [0] = SF_MAX (peak [0], psf->peak_info->peaks [k].value) ;
return SF_TRUE ;
} /* psf_get_signal_max */
int
psf_get_max_all_channels (SF_PRIVATE *psf, double *peaks)
{ int k ;
if (psf->peak_info == NULL)
return SF_FALSE ;
for (k = 0 ; k < psf->sf.channels ; k++)
peaks [k] = psf->peak_info->peaks [k].value ;
return SF_TRUE ;
} /* psf_get_max_all_channels */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,919 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef SNDFILE_COMMON_H
#define SNDFILE_COMMON_H
#include "sfconfig.h"
#include <stdlib.h>
#include <string.h>
#if HAVE_STDINT_H
#include <stdint.h>
#elif HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#ifndef SNDFILE_H
#include "sndfile.h"
#endif
#ifdef __cplusplus
#error "This code is not designed to be compiled with a C++ compiler."
#endif
#if (SIZEOF_LONG == 8)
# define SF_PLATFORM_S64(x) x##l
#elif (SIZEOF_LONG_LONG == 8)
# define SF_PLATFORM_S64(x) x##ll
#elif COMPILER_IS_GCC
# define SF_PLATFORM_S64(x) x##ll
#elif OS_IS_WIN32
# define SF_PLATFORM_S64(x) x##I64
#else
# error "Don't know how to define a 64 bit integer constant."
#endif
/*
** Inspiration : http://sourcefrog.net/weblog/software/languages/C/unused.html
*/
#ifdef UNUSED
#elif defined (__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__ ((unused))
#elif defined (__LCLINT__)
# define UNUSED(x) /*@unused@*/ x
#else
# define UNUSED(x) x
#endif
#ifdef __GNUC__
# define WARN_UNUSED __attribute__ ((warn_unused_result))
#else
# define WARN_UNUSED
#endif
#define SF_BUFFER_LEN (8192*2)
#define SF_FILENAME_LEN (512)
#define SF_SYSERR_LEN (256)
#define SF_MAX_STRINGS (32)
#define SF_STR_BUFFER_LEN (8192)
#define SF_HEADER_LEN (4100 + SF_STR_BUFFER_LEN)
#define PSF_SEEK_ERROR ((sf_count_t) -1)
#define BITWIDTH2BYTES(x) (((x) + 7) / 8)
/* For some reason sizeof returns an unsigned value which causes
** a warning when that value is added or subtracted from a signed
** value. Use SIGNED_SIZEOF instead.
*/
#define SIGNED_SIZEOF(x) ((int) sizeof (x))
#define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof ((x) [0])))
#define NOT(x) (! (x))
#if (COMPILER_IS_GCC == 1)
#define SF_MAX(x,y) ({ \
typeof (x) sf_max_x1 = (x) ; \
typeof (y) sf_max_y1 = (y) ; \
(void) (&sf_max_x1 == &sf_max_y1) ; \
sf_max_x1 > sf_max_y1 ? sf_max_x1 : sf_max_y1 ; })
#define SF_MIN(x,y) ({ \
typeof (x) sf_min_x2 = (x) ; \
typeof (y) sf_min_y2 = (y) ; \
(void) (&sf_min_x2 == &sf_min_y2) ; \
sf_min_x2 < sf_min_y2 ? sf_min_x2 : sf_min_y2 ; })
#else
#define SF_MAX(a,b) ((a) > (b) ? (a) : (b))
#define SF_MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#define SF_MAX_CHANNELS 256
/*
* Macros for spliting the format file of SF_INFI into contrainer type,
** codec type and endian-ness.
*/
#define SF_CONTAINER(x) ((x) & SF_FORMAT_TYPEMASK)
#define SF_CODEC(x) ((x) & SF_FORMAT_SUBMASK)
#define SF_ENDIAN(x) ((x) & SF_FORMAT_ENDMASK)
enum
{ /* PEAK chunk location. */
SF_PEAK_START = 42,
SF_PEAK_END = 43,
/* PEAK chunk location. */
SF_SCALE_MAX = 52,
SF_SCALE_MIN = 53,
/* str_flags values. */
SF_STR_ALLOW_START = 0x0100,
SF_STR_ALLOW_END = 0x0200,
/* Location of strings. */
SF_STR_LOCATE_START = 0x0400,
SF_STR_LOCATE_END = 0x0800,
SFD_TYPEMASK = 0x0FFFFFFF
} ;
#define SFM_MASK (SFM_READ | SFM_WRITE | SFM_RDWR)
#define SFM_UNMASK (~SFM_MASK)
/*---------------------------------------------------------------------------------------
** Formats that may be supported at some time in the future.
** When support is finalised, these values move to src/sndfile.h.
*/
enum
{ /* Work in progress. */
SF_FORMAT_SPEEX = 0x5000000,
SF_FORMAT_OGGFLAC = 0x5000001,
/* Formats supported read only. */
SF_FORMAT_TXW = 0x4030000, /* Yamaha TX16 sampler file */
SF_FORMAT_DWD = 0x4040000, /* DiamondWare Digirized */
/* Following are detected but not supported. */
SF_FORMAT_REX = 0x40A0000, /* Propellorheads Rex/Rcy */
SF_FORMAT_REX2 = 0x40D0000, /* Propellorheads Rex2 */
SF_FORMAT_KRZ = 0x40E0000, /* Kurzweil sampler file */
SF_FORMAT_WMA = 0x4100000, /* Windows Media Audio. */
SF_FORMAT_SHN = 0x4110000, /* Shorten. */
/* Unsupported encodings. */
SF_FORMAT_SVX_FIB = 0x1020, /* SVX Fibonacci Delta encoding. */
SF_FORMAT_SVX_EXP = 0x1021, /* SVX Exponential Delta encoding. */
SF_FORMAT_PCM_N = 0x1030
} ;
/*---------------------------------------------------------------------------------------
** PEAK_CHUNK - This chunk type is common to both AIFF and WAVE files although their
** endian encodings are different.
*/
typedef struct
{ double value ; /* signed value of peak */
sf_count_t position ; /* the sample frame for the peak */
} PEAK_POS ;
typedef struct
{ /* libsndfile internal : write a PEAK chunk at the start or end of the file? */
int peak_loc ;
/* WAV/AIFF */
unsigned int version ; /* version of the PEAK chunk */
unsigned int timestamp ; /* secs since 1/1/1970 */
/* CAF */
unsigned int edit_number ;
#if HAVE_FLEXIBLE_ARRAY
/* the per channel peak info */
PEAK_POS peaks [] ;
#else
/*
** This is not ISO compliant C. It works on some compilers which
** don't support the ISO standard flexible struct array which is
** used above. If your compiler doesn't like this I suggest you find
** youself a 1999 ISO C standards compilant compiler. GCC-3.X is
** highly recommended.
*/
PEAK_POS peaks [0] ;
#endif
} PEAK_INFO ;
static inline PEAK_INFO *
peak_info_calloc (int channels)
{ return calloc (1, sizeof (PEAK_INFO) + channels * sizeof (PEAK_POS)) ;
} /* peak_info_calloc */
typedef struct
{ int type ;
int flags ;
char *str ;
} STR_DATA ;
static inline size_t
make_size_t (int x)
{ return (size_t) x ;
} /* size_t_of_int */
typedef SF_BROADCAST_INFO_VAR (16 * 1024) SF_BROADCAST_INFO_16K ;
#if SIZEOF_WCHAR_T == 2
typedef wchar_t sfwchar_t ;
#else
typedef int16_t sfwchar_t ;
#endif
/*
** This version of isprint specifically ignores any locale info. Its used for
** determining which characters can be printed in things like hexdumps.
*/
static inline int
psf_isprint (int ch)
{ return (ch >= ' ' && ch <= '~') ;
} /* psf_isprint */
/*=======================================================================================
** SF_PRIVATE stuct - a pointer to this struct is passed back to the caller of the
** sf_open_XXXX functions. The caller however has no knowledge of the struct's
** contents.
*/
typedef struct
{
union
{ char c [SF_FILENAME_LEN] ;
sfwchar_t wc [SF_FILENAME_LEN] ;
} path ;
union
{ char c [SF_FILENAME_LEN] ;
sfwchar_t wc [SF_FILENAME_LEN] ;
} dir ;
union
{ char c [SF_FILENAME_LEN / 4] ;
sfwchar_t wc [SF_FILENAME_LEN / 4] ;
} name ;
#if USE_WINDOWS_API
/*
** These fields can only be used in src/file_io.c.
** They are basically the same as a windows file HANDLE.
*/
void *handle, *hsaved ;
int use_wchar ;
#else
/* These fields can only be used in src/file_io.c. */
int filedes, savedes ;
#endif
int do_not_close_descriptor ;
int mode ; /* Open mode : SFM_READ, SFM_WRITE or SFM_RDWR. */
} PSF_FILE ;
typedef struct sf_private_tag
{
/* Canary in a coal mine. */
union
{ /* Place a double here to encourage double alignment. */
double d [2] ;
char c [16] ;
} canary ;
/* Force the compiler to double align the start of buffer. */
union
{ double dbuf [SF_BUFFER_LEN / sizeof (double)] ;
#if (defined (SIZEOF_INT64_T) && (SIZEOF_INT64_T == 8))
int64_t lbuf [SF_BUFFER_LEN / sizeof (int64_t)] ;
#else
long lbuf [SF_BUFFER_LEN / sizeof (double)] ;
#endif
float fbuf [SF_BUFFER_LEN / sizeof (float)] ;
int ibuf [SF_BUFFER_LEN / sizeof (int)] ;
short sbuf [SF_BUFFER_LEN / sizeof (short)] ;
char cbuf [SF_BUFFER_LEN / sizeof (char)] ;
signed char scbuf [SF_BUFFER_LEN / sizeof (signed char)] ;
unsigned char ucbuf [SF_BUFFER_LEN / sizeof (signed char)] ;
} u ;
PSF_FILE file, rsrc ;
char syserr [SF_SYSERR_LEN] ;
/* logbuffer and logindex should only be changed within the logging functions
** of common.c
*/
char logbuffer [SF_BUFFER_LEN] ;
unsigned char header [SF_HEADER_LEN] ; /* Must be unsigned */
int rwf_endian ; /* Header endian-ness flag. */
/* Storage and housekeeping data for adding/reading strings from
** sound files.
*/
STR_DATA strings [SF_MAX_STRINGS] ;
char str_storage [SF_STR_BUFFER_LEN] ;
char *str_end ;
int str_flags ;
/* Guard value. If this changes the buffers above have overflowed. */
int Magick ;
unsigned unique_id ;
/* Index variables for maintaining logbuffer and header above. */
int logindex ;
int headindex, headend ;
int has_text ;
int error ;
int endian ; /* File endianness : SF_ENDIAN_LITTLE or SF_ENDIAN_BIG. */
int data_endswap ; /* Need to endswap data? */
/*
** Maximum float value for calculating the multiplier for
** float/double to short/int conversions.
*/
int float_int_mult ;
float float_max ;
int scale_int_float ;
/* Vairables for handling pipes. */
int is_pipe ; /* True if file is a pipe. */
sf_count_t pipeoffset ; /* Number of bytes read from a pipe. */
/* True if clipping must be performed on float->int conversions. */
int add_clipping ;
SF_INFO sf ;
int have_written ; /* Has a single write been done to the file? */
PEAK_INFO *peak_info ;
/* Loop Info */
SF_LOOP_INFO *loop_info ;
SF_INSTRUMENT *instrument ;
/* Broadcast (EBU) Info */
SF_BROADCAST_INFO_16K *broadcast_16k ;
/* Channel map data (if present) : an array of ints. */
int *channel_map ;
sf_count_t filelength ; /* Overall length of (embedded) file. */
sf_count_t fileoffset ; /* Offset in number of bytes from beginning of file. */
sf_count_t rsrclength ; /* Length of the resource fork (if it exists). */
sf_count_t dataoffset ; /* Offset in number of bytes from beginning of file. */
sf_count_t datalength ; /* Length in bytes of the audio data. */
sf_count_t dataend ; /* Offset to file tailer. */
int blockwidth ; /* Size in bytes of one set of interleaved samples. */
int bytewidth ; /* Size in bytes of one sample (one channel). */
void *dither ;
void *interleave ;
int last_op ; /* Last operation; either SFM_READ or SFM_WRITE */
sf_count_t read_current ;
sf_count_t write_current ;
void *container_data ; /* This is a pointer to dynamically allocated file
** container format specific data.
*/
void *codec_data ; /* This is a pointer to dynamically allocated file
** codec format specific data.
*/
SF_DITHER_INFO write_dither ;
SF_DITHER_INFO read_dither ;
int norm_double ;
int norm_float ;
int auto_header ;
int ieee_replace ;
/* A set of file specific function pointers */
sf_count_t (*read_short) (struct sf_private_tag*, short *ptr, sf_count_t len) ;
sf_count_t (*read_int) (struct sf_private_tag*, int *ptr, sf_count_t len) ;
sf_count_t (*read_float) (struct sf_private_tag*, float *ptr, sf_count_t len) ;
sf_count_t (*read_double) (struct sf_private_tag*, double *ptr, sf_count_t len) ;
sf_count_t (*write_short) (struct sf_private_tag*, const short *ptr, sf_count_t len) ;
sf_count_t (*write_int) (struct sf_private_tag*, const int *ptr, sf_count_t len) ;
sf_count_t (*write_float) (struct sf_private_tag*, const float *ptr, sf_count_t len) ;
sf_count_t (*write_double) (struct sf_private_tag*, const double *ptr, sf_count_t len) ;
sf_count_t (*seek) (struct sf_private_tag*, int mode, sf_count_t samples_from_start) ;
int (*write_header) (struct sf_private_tag*, int calc_length) ;
int (*command) (struct sf_private_tag*, int command, void *data, int datasize) ;
/*
** Separate close functions for the codec and the container.
** The codec close function is always called first.
*/
int (*codec_close) (struct sf_private_tag*) ;
int (*container_close) (struct sf_private_tag*) ;
char *format_desc ;
/* Virtual I/O functions. */
int virtual_io ;
SF_VIRTUAL_IO vio ;
void *vio_user_data ;
} SF_PRIVATE ;
enum
{ SFE_NO_ERROR = SF_ERR_NO_ERROR,
SFE_BAD_OPEN_FORMAT = SF_ERR_UNRECOGNISED_FORMAT,
SFE_SYSTEM = SF_ERR_SYSTEM,
SFE_MALFORMED_FILE = SF_ERR_MALFORMED_FILE,
SFE_UNSUPPORTED_ENCODING = SF_ERR_UNSUPPORTED_ENCODING,
SFE_ZERO_MAJOR_FORMAT,
SFE_ZERO_MINOR_FORMAT,
SFE_BAD_FILE,
SFE_BAD_FILE_READ,
SFE_OPEN_FAILED,
SFE_BAD_SNDFILE_PTR,
SFE_BAD_SF_INFO_PTR,
SFE_BAD_SF_INCOMPLETE,
SFE_BAD_FILE_PTR,
SFE_BAD_INT_PTR,
SFE_BAD_STAT_SIZE,
SFE_MALLOC_FAILED,
SFE_UNIMPLEMENTED,
SFE_BAD_READ_ALIGN,
SFE_BAD_WRITE_ALIGN,
SFE_UNKNOWN_FORMAT,
SFE_NOT_READMODE,
SFE_NOT_WRITEMODE,
SFE_BAD_MODE_RW,
SFE_BAD_SF_INFO,
SFE_BAD_OFFSET,
SFE_NO_EMBED_SUPPORT,
SFE_NO_EMBEDDED_RDWR,
SFE_NO_PIPE_WRITE,
SFE_INTERNAL,
SFE_BAD_COMMAND_PARAM,
SFE_BAD_ENDIAN,
SFE_CHANNEL_COUNT_ZERO,
SFE_CHANNEL_COUNT,
SFE_BAD_VIRTUAL_IO,
SFE_INTERLEAVE_MODE,
SFE_INTERLEAVE_SEEK,
SFE_INTERLEAVE_READ,
SFE_BAD_SEEK,
SFE_NOT_SEEKABLE,
SFE_AMBIGUOUS_SEEK,
SFE_WRONG_SEEK,
SFE_SEEK_FAILED,
SFE_BAD_OPEN_MODE,
SFE_OPEN_PIPE_RDWR,
SFE_RDWR_POSITION,
SFE_RDWR_BAD_HEADER,
SFE_CMD_HAS_DATA,
SFE_BAD_BROADCAST_INFO_SIZE,
SFE_BAD_BROADCAST_INFO_TOO_BIG,
SFE_STR_NO_SUPPORT,
SFE_STR_NOT_WRITE,
SFE_STR_MAX_DATA,
SFE_STR_MAX_COUNT,
SFE_STR_BAD_TYPE,
SFE_STR_NO_ADD_END,
SFE_STR_BAD_STRING,
SFE_STR_WEIRD,
SFE_WAV_NO_RIFF,
SFE_WAV_NO_WAVE,
SFE_WAV_NO_FMT,
SFE_WAV_BAD_FMT,
SFE_WAV_FMT_SHORT,
SFE_WAV_BAD_FACT,
SFE_WAV_BAD_PEAK,
SFE_WAV_PEAK_B4_FMT,
SFE_WAV_BAD_FORMAT,
SFE_WAV_BAD_BLOCKALIGN,
SFE_WAV_NO_DATA,
SFE_WAV_BAD_LIST,
SFE_WAV_ADPCM_NOT4BIT,
SFE_WAV_ADPCM_CHANNELS,
SFE_WAV_GSM610_FORMAT,
SFE_WAV_UNKNOWN_CHUNK,
SFE_WAV_WVPK_DATA,
SFE_AIFF_NO_FORM,
SFE_AIFF_AIFF_NO_FORM,
SFE_AIFF_COMM_NO_FORM,
SFE_AIFF_SSND_NO_COMM,
SFE_AIFF_UNKNOWN_CHUNK,
SFE_AIFF_COMM_CHUNK_SIZE,
SFE_AIFF_BAD_COMM_CHUNK,
SFE_AIFF_PEAK_B4_COMM,
SFE_AIFF_BAD_PEAK,
SFE_AIFF_NO_SSND,
SFE_AIFF_NO_DATA,
SFE_AIFF_RW_SSND_NOT_LAST,
SFE_AU_UNKNOWN_FORMAT,
SFE_AU_NO_DOTSND,
SFE_AU_EMBED_BAD_LEN,
SFE_RAW_READ_BAD_SPEC,
SFE_RAW_BAD_BITWIDTH,
SFE_RAW_BAD_FORMAT,
SFE_PAF_NO_MARKER,
SFE_PAF_VERSION,
SFE_PAF_UNKNOWN_FORMAT,
SFE_PAF_SHORT_HEADER,
SFE_PAF_BAD_CHANNELS,
SFE_SVX_NO_FORM,
SFE_SVX_NO_BODY,
SFE_SVX_NO_DATA,
SFE_SVX_BAD_COMP,
SFE_SVX_BAD_NAME_LENGTH,
SFE_NIST_BAD_HEADER,
SFE_NIST_CRLF_CONVERISON,
SFE_NIST_BAD_ENCODING,
SFE_VOC_NO_CREATIVE,
SFE_VOC_BAD_FORMAT,
SFE_VOC_BAD_VERSION,
SFE_VOC_BAD_MARKER,
SFE_VOC_BAD_SECTIONS,
SFE_VOC_MULTI_SAMPLERATE,
SFE_VOC_MULTI_SECTION,
SFE_VOC_MULTI_PARAM,
SFE_VOC_SECTION_COUNT,
SFE_VOC_NO_PIPE,
SFE_IRCAM_NO_MARKER,
SFE_IRCAM_BAD_CHANNELS,
SFE_IRCAM_UNKNOWN_FORMAT,
SFE_W64_64_BIT,
SFE_W64_NO_RIFF,
SFE_W64_NO_WAVE,
SFE_W64_NO_DATA,
SFE_W64_ADPCM_NOT4BIT,
SFE_W64_ADPCM_CHANNELS,
SFE_W64_GSM610_FORMAT,
SFE_MAT4_BAD_NAME,
SFE_MAT4_NO_SAMPLERATE,
SFE_MAT5_BAD_ENDIAN,
SFE_MAT5_NO_BLOCK,
SFE_MAT5_SAMPLE_RATE,
SFE_PVF_NO_PVF1,
SFE_PVF_BAD_HEADER,
SFE_PVF_BAD_BITWIDTH,
SFE_DWVW_BAD_BITWIDTH,
SFE_G72X_NOT_MONO,
SFE_XI_BAD_HEADER,
SFE_XI_EXCESS_SAMPLES,
SFE_XI_NO_PIPE,
SFE_HTK_NO_PIPE,
SFE_SDS_NOT_SDS,
SFE_SDS_BAD_BIT_WIDTH,
SFE_SD2_FD_DISALLOWED,
SFE_SD2_BAD_DATA_OFFSET,
SFE_SD2_BAD_MAP_OFFSET,
SFE_SD2_BAD_DATA_LENGTH,
SFE_SD2_BAD_MAP_LENGTH,
SFE_SD2_BAD_RSRC,
SFE_SD2_BAD_SAMPLE_SIZE,
SFE_FLAC_BAD_HEADER,
SFE_FLAC_NEW_DECODER,
SFE_FLAC_INIT_DECODER,
SFE_FLAC_LOST_SYNC,
SFE_FLAC_BAD_SAMPLE_RATE,
SFE_FLAC_UNKOWN_ERROR,
SFE_WVE_NOT_WVE,
SFE_WVE_NO_PIPE,
SFE_VORBIS_ENCODER_BUG,
SFE_RF64_NOT_RF64,
SFE_MAX_ERROR /* This must be last in list. */
} ;
int subformat_to_bytewidth (int format) ;
int s_bitwidth_to_subformat (int bits) ;
int u_bitwidth_to_subformat (int bits) ;
/* Functions for reading and writing floats and doubles on processors
** with non-IEEE floats/doubles.
*/
float float32_be_read (unsigned char *cptr) ;
float float32_le_read (unsigned char *cptr) ;
void float32_be_write (float in, unsigned char *out) ;
void float32_le_write (float in, unsigned char *out) ;
double double64_be_read (unsigned char *cptr) ;
double double64_le_read (unsigned char *cptr) ;
void double64_be_write (double in, unsigned char *out) ;
void double64_le_write (double in, unsigned char *out) ;
/* Functions for writing to the internal logging buffer. */
void psf_log_printf (SF_PRIVATE *psf, const char *format, ...) ;
void psf_log_SF_INFO (SF_PRIVATE *psf) ;
int32_t psf_rand_int32 (void) ;
void append_snprintf (char * dest, size_t maxlen, const char * fmt, ...) ;
void psf_strlcpy_crlf (char *dest, const char *src, size_t destmax, size_t srcmax) ;
/* Functions used when writing file headers. */
int psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...) ;
void psf_asciiheader_printf (SF_PRIVATE *psf, const char *format, ...) ;
/* Functions used when reading file headers. */
int psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) ;
/* Functions used in the write function for updating the peak chunk. */
void peak_update_short (SF_PRIVATE *psf, short *ptr, size_t items) ;
void peak_update_int (SF_PRIVATE *psf, int *ptr, size_t items) ;
void peak_update_double (SF_PRIVATE *psf, double *ptr, size_t items) ;
/* Functions defined in command.c. */
int psf_get_format_simple_count (void) ;
int psf_get_format_simple (SF_FORMAT_INFO *data) ;
int psf_get_format_info (SF_FORMAT_INFO *data) ;
int psf_get_format_major_count (void) ;
int psf_get_format_major (SF_FORMAT_INFO *data) ;
int psf_get_format_subtype_count (void) ;
int psf_get_format_subtype (SF_FORMAT_INFO *data) ;
void psf_generate_format_desc (SF_PRIVATE *psf) ;
double psf_calc_signal_max (SF_PRIVATE *psf, int normalize) ;
int psf_calc_max_all_channels (SF_PRIVATE *psf, double *peaks, int normalize) ;
int psf_get_signal_max (SF_PRIVATE *psf, double *peak) ;
int psf_get_max_all_channels (SF_PRIVATE *psf, double *peaks) ;
/* Functions in strings.c. */
const char* psf_get_string (SF_PRIVATE *psf, int str_type) ;
int psf_set_string (SF_PRIVATE *psf, int str_type, const char *str) ;
int psf_store_string (SF_PRIVATE *psf, int str_type, const char *str) ;
int psf_location_string_count (const SF_PRIVATE * psf, int location) ;
/* Default seek function. Use for PCM and float encoded data. */
sf_count_t psf_default_seek (SF_PRIVATE *psf, int mode, sf_count_t samples_from_start) ;
int macos_guess_file_type (SF_PRIVATE *psf, const char *filename) ;
/*------------------------------------------------------------------------------------
** File I/O functions which will allow access to large files (> 2 Gig) on
** some 32 bit OSes. Implementation in file_io.c.
*/
int psf_fopen (SF_PRIVATE *psf) ;
int psf_set_stdio (SF_PRIVATE *psf) ;
int psf_file_valid (SF_PRIVATE *psf) ;
void psf_set_file (SF_PRIVATE *psf, int fd) ;
void psf_init_files (SF_PRIVATE *psf) ;
void psf_use_rsrc (SF_PRIVATE *psf, int on_off) ;
SNDFILE * psf_open_file (SF_PRIVATE *psf, SF_INFO *sfinfo) ;
sf_count_t psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence) ;
sf_count_t psf_fread (void *ptr, sf_count_t bytes, sf_count_t count, SF_PRIVATE *psf) ;
sf_count_t psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t count, SF_PRIVATE *psf) ;
sf_count_t psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf) ;
sf_count_t psf_ftell (SF_PRIVATE *psf) ;
sf_count_t psf_get_filelen (SF_PRIVATE *psf) ;
void psf_fsync (SF_PRIVATE *psf) ;
int psf_is_pipe (SF_PRIVATE *psf) ;
int psf_ftruncate (SF_PRIVATE *psf, sf_count_t len) ;
int psf_fclose (SF_PRIVATE *psf) ;
/* Open and close the resource fork of a file. */
int psf_open_rsrc (SF_PRIVATE *psf) ;
int psf_close_rsrc (SF_PRIVATE *psf) ;
/*
void psf_fclearerr (SF_PRIVATE *psf) ;
int psf_ferror (SF_PRIVATE *psf) ;
*/
/*------------------------------------------------------------------------------------
** Functions for reading and writing different file formats.
*/
int aiff_open (SF_PRIVATE *psf) ;
int au_open (SF_PRIVATE *psf) ;
int avr_open (SF_PRIVATE *psf) ;
int htk_open (SF_PRIVATE *psf) ;
int ircam_open (SF_PRIVATE *psf) ;
int mat4_open (SF_PRIVATE *psf) ;
int mat5_open (SF_PRIVATE *psf) ;
int nist_open (SF_PRIVATE *psf) ;
int paf_open (SF_PRIVATE *psf) ;
int pvf_open (SF_PRIVATE *psf) ;
int raw_open (SF_PRIVATE *psf) ;
int sd2_open (SF_PRIVATE *psf) ;
int sds_open (SF_PRIVATE *psf) ;
int svx_open (SF_PRIVATE *psf) ;
int voc_open (SF_PRIVATE *psf) ;
int w64_open (SF_PRIVATE *psf) ;
int wav_open (SF_PRIVATE *psf) ;
int xi_open (SF_PRIVATE *psf) ;
int flac_open (SF_PRIVATE *psf) ;
int caf_open (SF_PRIVATE *psf) ;
int mpc2k_open (SF_PRIVATE *psf) ;
int rf64_open (SF_PRIVATE *psf) ;
/* In progress. Do not currently work. */
int ogg_vorbis_open (SF_PRIVATE *psf) ;
int ogg_speex_open (SF_PRIVATE *psf) ;
int ogg_pcm_open (SF_PRIVATE *psf) ;
int mpeg_open (SF_PRIVATE *psf) ;
int ogg_open (SF_PRIVATE *psf) ;
int rx2_open (SF_PRIVATE *psf) ;
int txw_open (SF_PRIVATE *psf) ;
int wve_open (SF_PRIVATE *psf) ;
int dwd_open (SF_PRIVATE *psf) ;
int macbinary3_open (SF_PRIVATE *psf) ;
/*------------------------------------------------------------------------------------
** Init functions for a number of common data encodings.
*/
int pcm_init (SF_PRIVATE *psf) ;
int ulaw_init (SF_PRIVATE *psf) ;
int alaw_init (SF_PRIVATE *psf) ;
int float32_init (SF_PRIVATE *psf) ;
int double64_init (SF_PRIVATE *psf) ;
int dwvw_init (SF_PRIVATE *psf, int bitwidth) ;
int gsm610_init (SF_PRIVATE *psf) ;
int vox_adpcm_init (SF_PRIVATE *psf) ;
int flac_init (SF_PRIVATE *psf) ;
int g72x_init (SF_PRIVATE * psf) ;
int dither_init (SF_PRIVATE *psf, int mode) ;
int wav_w64_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ;
int wav_w64_msadpcm_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ;
int aiff_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ;
int interleave_init (SF_PRIVATE *psf) ;
/*------------------------------------------------------------------------------------
** Chunk logging functions.
*/
typedef struct
{ struct
{ int chunk ;
sf_count_t offset ;
sf_count_t len ;
} l [100] ;
int count ;
} PRIV_CHUNK4 ;
void pchk4_store (PRIV_CHUNK4 * pchk, int marker, sf_count_t offset, sf_count_t len) ;
int pchk4_find (PRIV_CHUNK4 * pchk, int marker) ;
/*------------------------------------------------------------------------------------
** Functions that work like OpenBSD's strlcpy/strlcat to replace strncpy/strncat.
**
** See : http://www.gratisoft.us/todd/papers/strlcpy.html
**
** These functions are available on *BSD, but are not avaialble everywhere so we
** implement them here.
**
** The argument order has been changed to that of strncpy/strncat to cause
** compiler errors if code is carelessly converted from one to the other.
*/
static inline void
psf_strlcat (char *dest, size_t n, const char *src)
{ strncat (dest, src, n - strlen (dest) - 1) ;
dest [n - 1] = 0 ;
} /* psf_strlcat */
static inline void
psf_strlcpy (char *dest, size_t n, const char *src)
{ strncpy (dest, src, n - 1) ;
dest [n - 1] = 0 ;
} /* psf_strlcpy */
/*------------------------------------------------------------------------------------
** Other helper functions.
*/
void *psf_memset (void *s, int c, sf_count_t n) ;
SF_INSTRUMENT * psf_instrument_alloc (void) ;
void psf_sanitize_string (char * cptr, int len) ;
/* Generate the current date as a string. */
void psf_get_date_str (char *str, int maxlen) ;
SF_BROADCAST_INFO_16K * broadcast_var_alloc (void) ;
int broadcast_var_set (SF_PRIVATE *psf, const SF_BROADCAST_INFO * data, size_t datasize) ;
int broadcast_var_get (SF_PRIVATE *psf, SF_BROADCAST_INFO * data, size_t datasize) ;
typedef struct
{ int channels ;
int endianness ;
} AUDIO_DETECT ;
int audio_detect (SF_PRIVATE * psf, AUDIO_DETECT *ad, const unsigned char * data, int datalen) ;
int id3_skip (SF_PRIVATE * psf) ;
/*------------------------------------------------------------------------------------
** Helper/debug functions.
*/
void psf_hexdump (const void *ptr, int len) ;
const char * str_of_major_format (int format) ;
const char * str_of_minor_format (int format) ;
const char * str_of_open_mode (int mode) ;
const char * str_of_endianness (int end) ;
/*------------------------------------------------------------------------------------
** Extra commands for sf_command(). Not for public use yet.
*/
enum
{ SFC_TEST_AIFF_ADD_INST_CHUNK = 0x2000,
SFC_TEST_WAV_ADD_INFO_CHUNK = 0x2010
} ;
/*
** Maybe, one day, make these functions or something like them, public.
**
** Buffer to buffer dithering. Pointer in and out are allowed to point
** to the same buffer for in-place dithering.
*/
#if 0
int sf_dither_short (const SF_DITHER_INFO *dither, const short *in, short *out, int count) ;
int sf_dither_int (const SF_DITHER_INFO *dither, const int *in, int *out, int count) ;
int sf_dither_float (const SF_DITHER_INFO *dither, const float *in, float *out, int count) ;
int sf_dither_double (const SF_DITHER_INFO *dither, const double *in, double *out, int count) ;
#endif
#endif /* SNDFILE_COMMON_H */

View File

@@ -0,0 +1,291 @@
/* src/config.h. Generated from config.h.in by configure. */
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* Set to 1 if the compile is GNU GCC. */
#define COMPILER_IS_GCC 1
/* Target processor clips on negative float to int conversion. */
#define CPU_CLIPS_NEGATIVE 0
/* Target processor clips on positive float to int conversion. */
#define CPU_CLIPS_POSITIVE 0
/* Target processor is big endian. */
#define CPU_IS_BIG_ENDIAN 0
/* Target processor is little endian. */
#define CPU_IS_LITTLE_ENDIAN 1
/* Set to 1 to enable experimental code. */
#define ENABLE_EXPERIMENTAL_CODE 0
/* Define to 1 if you have the <alsa/asoundlib.h> header file. */
/* #define HAVE_ALSA_ASOUNDLIB_H 1 */
/* Define to 1 if you have the <byteswap.h> header file. */
#define HAVE_BYTESWAP_H 1
/* Define to 1 if you have the `calloc' function. */
#define HAVE_CALLOC 1
/* Define to 1 if you have the `ceil' function. */
#define HAVE_CEIL 1
/* Set to 1 if S_IRGRP is defined. */
#define HAVE_DECL_S_IRGRP 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the <endian.h> header file. */
#define HAVE_ENDIAN_H 1
/* Will be set to 1 if flac, ogg and vorbis are available. */
/* #define HAVE_EXTERNAL_LIBS 1 */
/* Set to 1 if the compile supports the struct hack. */
#define HAVE_FLEXIBLE_ARRAY 1
/* Define to 1 if you have the `floor' function. */
#define HAVE_FLOOR 1
/* Define to 1 if you have the `fmod' function. */
#define HAVE_FMOD 1
/* Define to 1 if you have the `free' function. */
#define HAVE_FREE 1
/* Define to 1 if you have the `fstat' function. */
#define HAVE_FSTAT 1
/* Define to 1 if you have the `fsync' function. */
#define HAVE_FSYNC 1
/* Define to 1 if you have the `ftruncate' function. */
#define HAVE_FTRUNCATE 1
/* Define to 1 if you have the `getpagesize' function. */
#define HAVE_GETPAGESIZE 1
/* Define to 1 if you have the `gettimeofday' function. */
#define HAVE_GETTIMEOFDAY 1
/* Define to 1 if you have the `gmtime' function. */
#define HAVE_GMTIME 1
/* Define to 1 if you have the `gmtime_r' function. */
#define HAVE_GMTIME_R 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `m' library (-lm). */
#define HAVE_LIBM 1
/* Define to 1 if you have the <locale.h> header file. */
/* #define HAVE_LOCALE_H 1 */
/* Define to 1 if you have the `localtime' function. */
#define HAVE_LOCALTIME 1
/* Define to 1 if you have the `localtime_r' function. */
#define HAVE_LOCALTIME_R 1
/* Define if you have C99's lrint function. */
#define HAVE_LRINT 1
/* Define if you have C99's lrintf function. */
#define HAVE_LRINTF 1
/* Define to 1 if you have the `lseek' function. */
#define HAVE_LSEEK 1
/* Define to 1 if you have the `malloc' function. */
#define HAVE_MALLOC 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `mmap' function. */
#define HAVE_MMAP 1
/* Define to 1 if you have the `open' function. */
#define HAVE_OPEN 1
/* Define to 1 if you have the `pipe' function. */
#define HAVE_PIPE 1
/* Define to 1 if you have the `pread' function. */
#define HAVE_PREAD 1
/* Define to 1 if you have the `pwrite' function. */
#define HAVE_PWRITE 1
/* Define to 1 if you have the `read' function. */
#define HAVE_READ 1
/* Define to 1 if you have the `realloc' function. */
#define HAVE_REALLOC 1
/* Define to 1 if you have the `setlocale' function. */
/* #define HAVE_SETLOCALE 1 */
/* Define to 1 if you have the <sndio.h> header file. */
/* #undef HAVE_SNDIO_H */
/* Define to 1 if you have the `snprintf' function. */
#define HAVE_SNPRINTF 1
/* Set to 1 if you have libsqlite3. */
#define HAVE_SQLITE3 0
/* Define to 1 if the system has the type `ssize_t'. */
#define HAVE_SSIZE_T 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
#define HAVE_SYS_WAIT_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the `vsnprintf' function. */
#define HAVE_VSNPRINTF 1
/* Define to 1 if you have the `waitpid' function. */
#define HAVE_WAITPID 1
/* Define to 1 if you have the `write' function. */
#define HAVE_WRITE 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
/* #undef NO_MINUS_C_MINUS_O */
/* Set to 1 if compiling for MacOSX */
#define OS_IS_MACOSX 0
/* Set to 1 if compiling for Win32 */
#define OS_IS_WIN32 0
/* Name of package */
#define PACKAGE "libsndfile"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "sndfile@mega-nerd.com"
/* Define to the full name of this package. */
#define PACKAGE_NAME "libsndfile"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "libsndfile 1.0.25"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libsndfile"
/* Define to the home page for this package. */
#define PACKAGE_URL "http://www.mega-nerd.com/libsndfile/"
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.0.25"
/* Set to maximum allowed value of sf_count_t type. */
#define SF_COUNT_MAX 0x7FFFFFFFFFFFFFFFLL
/* The size of `double', as computed by sizeof. */
#define SIZEOF_DOUBLE 8
/* The size of `float', as computed by sizeof. */
#define SIZEOF_FLOAT 4
/* The size of `int', as computed by sizeof. */
#define SIZEOF_INT 4
/* The size of `int64_t', as computed by sizeof. */
#define SIZEOF_INT64_T 8
/* The size of `loff_t', as computed by sizeof. */
/* #undef SIZEOF_LOFF_T */
/* The size of `long', as computed by sizeof. */
#define SIZEOF_LONG 4
/* The size of `long long', as computed by sizeof. */
#define SIZEOF_LONG_LONG 8
/* The size of `off64_t', as computed by sizeof. */
#define SIZEOF_OFF64_T 8
/* The size of `off_t', as computed by sizeof. */
#define SIZEOF_OFF_T 4
/* Set to sizeof (long) if unknown. */
#define SIZEOF_SF_COUNT_T 8
/* The size of `short', as computed by sizeof. */
#define SIZEOF_SHORT 2
/* The size of `size_t', as computed by sizeof. */
#define SIZEOF_SIZE_T 4
/* The size of `ssize_t', as computed by sizeof. */
#define SIZEOF_SSIZE_T 4
/* The size of `void*', as computed by sizeof. */
#define SIZEOF_VOIDP 4
/* The size of `wchar_t', as computed by sizeof. */
#define SIZEOF_WCHAR_T 4
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Set to long if unknown. */
#define TYPEOF_SF_COUNT_T int64_t
/* Set to 1 to use the native windows API */
#define USE_WINDOWS_API 0
/* Version number of package */
#define VERSION "1.0.25"
/* Set to 1 if windows DLL is being built. */
#define WIN32_TARGET_DLL 0
/* Target processor is big endian. */
#define WORDS_BIGENDIAN 0
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
/* Define to make fseeko etc. visible, on some hosts. */
/* #undef _LARGEFILE_SOURCE */
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
/* Set to 1 to use C99 printf/snprintf in MinGW. */
/* #undef __USE_MINGW_ANSI_STDIO */

View File

@@ -0,0 +1,290 @@
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* Set to 1 if the compile is GNU GCC. */
#undef COMPILER_IS_GCC
/* Target processor clips on negative float to int conversion. */
#undef CPU_CLIPS_NEGATIVE
/* Target processor clips on positive float to int conversion. */
#undef CPU_CLIPS_POSITIVE
/* Target processor is big endian. */
#undef CPU_IS_BIG_ENDIAN
/* Target processor is little endian. */
#undef CPU_IS_LITTLE_ENDIAN
/* Set to 1 to enable experimental code. */
#undef ENABLE_EXPERIMENTAL_CODE
/* Define to 1 if you have the <alsa/asoundlib.h> header file. */
#undef HAVE_ALSA_ASOUNDLIB_H
/* Define to 1 if you have the <byteswap.h> header file. */
#undef HAVE_BYTESWAP_H
/* Define to 1 if you have the `calloc' function. */
#undef HAVE_CALLOC
/* Define to 1 if you have the `ceil' function. */
#undef HAVE_CEIL
/* Set to 1 if S_IRGRP is defined. */
#undef HAVE_DECL_S_IRGRP
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <endian.h> header file. */
#undef HAVE_ENDIAN_H
/* Will be set to 1 if flac, ogg and vorbis are available. */
#undef HAVE_EXTERNAL_LIBS
/* Set to 1 if the compile supports the struct hack. */
#undef HAVE_FLEXIBLE_ARRAY
/* Define to 1 if you have the `floor' function. */
#undef HAVE_FLOOR
/* Define to 1 if you have the `fmod' function. */
#undef HAVE_FMOD
/* Define to 1 if you have the `free' function. */
#undef HAVE_FREE
/* Define to 1 if you have the `fstat' function. */
#undef HAVE_FSTAT
/* Define to 1 if you have the `fsync' function. */
#undef HAVE_FSYNC
/* Define to 1 if you have the `ftruncate' function. */
#undef HAVE_FTRUNCATE
/* Define to 1 if you have the `getpagesize' function. */
#undef HAVE_GETPAGESIZE
/* Define to 1 if you have the `gettimeofday' function. */
#undef HAVE_GETTIMEOFDAY
/* Define to 1 if you have the `gmtime' function. */
#undef HAVE_GMTIME
/* Define to 1 if you have the `gmtime_r' function. */
#undef HAVE_GMTIME_R
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM
/* Define to 1 if you have the <locale.h> header file. */
#undef HAVE_LOCALE_H
/* Define to 1 if you have the `localtime' function. */
#undef HAVE_LOCALTIME
/* Define to 1 if you have the `localtime_r' function. */
#undef HAVE_LOCALTIME_R
/* Define if you have C99's lrint function. */
#undef HAVE_LRINT
/* Define if you have C99's lrintf function. */
#undef HAVE_LRINTF
/* Define to 1 if you have the `lseek' function. */
#undef HAVE_LSEEK
/* Define to 1 if you have the `malloc' function. */
#undef HAVE_MALLOC
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `mmap' function. */
#undef HAVE_MMAP
/* Define to 1 if you have the `open' function. */
#undef HAVE_OPEN
/* Define to 1 if you have the `pipe' function. */
#undef HAVE_PIPE
/* Define to 1 if you have the `pread' function. */
#undef HAVE_PREAD
/* Define to 1 if you have the `pwrite' function. */
#undef HAVE_PWRITE
/* Define to 1 if you have the `read' function. */
#undef HAVE_READ
/* Define to 1 if you have the `realloc' function. */
#undef HAVE_REALLOC
/* Define to 1 if you have the `setlocale' function. */
#undef HAVE_SETLOCALE
/* Define to 1 if you have the <sndio.h> header file. */
#undef HAVE_SNDIO_H
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
/* Set to 1 if you have libsqlite3. */
#undef HAVE_SQLITE3
/* Define to 1 if the system has the type `ssize_t'. */
#undef HAVE_SSIZE_T
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
#undef HAVE_SYS_WAIT_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `vsnprintf' function. */
#undef HAVE_VSNPRINTF
/* Define to 1 if you have the `waitpid' function. */
#undef HAVE_WAITPID
/* Define to 1 if you have the `write' function. */
#undef HAVE_WRITE
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
#undef NO_MINUS_C_MINUS_O
/* Set to 1 if compiling for MacOSX */
#undef OS_IS_MACOSX
/* Set to 1 if compiling for Win32 */
#undef OS_IS_WIN32
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Set to maximum allowed value of sf_count_t type. */
#undef SF_COUNT_MAX
/* The size of `double', as computed by sizeof. */
#undef SIZEOF_DOUBLE
/* The size of `float', as computed by sizeof. */
#undef SIZEOF_FLOAT
/* The size of `int', as computed by sizeof. */
#undef SIZEOF_INT
/* The size of `int64_t', as computed by sizeof. */
#undef SIZEOF_INT64_T
/* The size of `loff_t', as computed by sizeof. */
#undef SIZEOF_LOFF_T
/* The size of `long', as computed by sizeof. */
#undef SIZEOF_LONG
/* The size of `long long', as computed by sizeof. */
#undef SIZEOF_LONG_LONG
/* The size of `off64_t', as computed by sizeof. */
#undef SIZEOF_OFF64_T
/* The size of `off_t', as computed by sizeof. */
#undef SIZEOF_OFF_T
/* Set to sizeof (long) if unknown. */
#undef SIZEOF_SF_COUNT_T
/* The size of `short', as computed by sizeof. */
#undef SIZEOF_SHORT
/* The size of `size_t', as computed by sizeof. */
#undef SIZEOF_SIZE_T
/* The size of `ssize_t', as computed by sizeof. */
#undef SIZEOF_SSIZE_T
/* The size of `void*', as computed by sizeof. */
#undef SIZEOF_VOIDP
/* The size of `wchar_t', as computed by sizeof. */
#undef SIZEOF_WCHAR_T
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Set to long if unknown. */
#undef TYPEOF_SF_COUNT_T
/* Set to 1 to use the native windows API */
#undef USE_WINDOWS_API
/* Version number of package */
#undef VERSION
/* Set to 1 if windows DLL is being built. */
#undef WIN32_TARGET_DLL
/* Target processor is big endian. */
#undef WORDS_BIGENDIAN
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Define to make fseeko etc. visible, on some hosts. */
#undef _LARGEFILE_SOURCE
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
/* Set to 1 to use C99 printf/snprintf in MinGW. */
#undef __USE_MINGW_ANSI_STDIO

View File

@@ -0,0 +1,534 @@
/*
** Copyright (C) 2003-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdlib.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
/*============================================================================
** Rule number 1 is to only apply dither when going from a larger bitwidth
** to a smaller bitwidth. This can happen on both read and write.
**
** Need to apply dither on all conversions marked X below.
**
** Dither on write:
**
** Input
** | short int float double
** --------+-----------------------------------------------
** O 8 bit | X X X X
** u 16 bit | none X X X
** t 24 bit | none X X X
** p 32 bit | none none X X
** u float | none none none none
** t double | none none none none
**
** Dither on read:
**
** Input
** O | 8 bit 16 bit 24 bit 32 bit float double
** u --------+-------------------------------------------------
** t short | none none X X X X
** p int | none none none X X X
** u float | none none none none none none
** t double | none none none none none none
*/
#define SFE_DITHER_BAD_PTR 666
#define SFE_DITHER_BAD_TYPE 667
typedef struct
{ int read_short_dither_bits, read_int_dither_bits ;
int write_short_dither_bits, write_int_dither_bits ;
double read_float_dither_scale, read_double_dither_bits ;
double write_float_dither_scale, write_double_dither_bits ;
sf_count_t (*read_short) (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
sf_count_t (*read_int) (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
sf_count_t (*read_float) (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
sf_count_t (*read_double) (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
sf_count_t (*write_short) (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
sf_count_t (*write_int) (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
sf_count_t (*write_float) (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
sf_count_t (*write_double) (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
double buffer [SF_BUFFER_LEN / sizeof (double)] ;
} DITHER_DATA ;
static sf_count_t dither_read_short (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
static sf_count_t dither_read_int (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
static sf_count_t dither_write_short (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
static sf_count_t dither_write_int (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
static sf_count_t dither_write_float (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
static sf_count_t dither_write_double (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
int
dither_init (SF_PRIVATE *psf, int mode)
{ DITHER_DATA *pdither ;
pdither = psf->dither ; /* This may be NULL. */
/* Turn off dither on read. */
if (mode == SFM_READ && psf->read_dither.type == SFD_NO_DITHER)
{ if (pdither == NULL)
return 0 ; /* Dither is already off, so just return. */
if (pdither->read_short)
psf->read_short = pdither->read_short ;
if (pdither->read_int)
psf->read_int = pdither->read_int ;
if (pdither->read_float)
psf->read_float = pdither->read_float ;
if (pdither->read_double)
psf->read_double = pdither->read_double ;
return 0 ;
} ;
/* Turn off dither on write. */
if (mode == SFM_WRITE && psf->write_dither.type == SFD_NO_DITHER)
{ if (pdither == NULL)
return 0 ; /* Dither is already off, so just return. */
if (pdither->write_short)
psf->write_short = pdither->write_short ;
if (pdither->write_int)
psf->write_int = pdither->write_int ;
if (pdither->write_float)
psf->write_float = pdither->write_float ;
if (pdither->write_double)
psf->write_double = pdither->write_double ;
return 0 ;
} ;
/* Turn on dither on read if asked. */
if (mode == SFM_READ && psf->read_dither.type != 0)
{ if (pdither == NULL)
pdither = psf->dither = calloc (1, sizeof (DITHER_DATA)) ;
if (pdither == NULL)
return SFE_MALLOC_FAILED ;
switch (SF_CODEC (psf->sf.format))
{ case SF_FORMAT_DOUBLE :
case SF_FORMAT_FLOAT :
pdither->read_int = psf->read_int ;
psf->read_int = dither_read_int ;
break ;
case SF_FORMAT_PCM_32 :
case SF_FORMAT_PCM_24 :
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_S8 :
case SF_FORMAT_PCM_U8 :
pdither->read_short = psf->read_short ;
psf->read_short = dither_read_short ;
break ;
default : break ;
} ;
} ;
/* Turn on dither on write if asked. */
if (mode == SFM_WRITE && psf->write_dither.type != 0)
{ if (pdither == NULL)
pdither = psf->dither = calloc (1, sizeof (DITHER_DATA)) ;
if (pdither == NULL)
return SFE_MALLOC_FAILED ;
switch (SF_CODEC (psf->sf.format))
{ case SF_FORMAT_DOUBLE :
case SF_FORMAT_FLOAT :
pdither->write_int = psf->write_int ;
psf->write_int = dither_write_int ;
break ;
case SF_FORMAT_PCM_32 :
case SF_FORMAT_PCM_24 :
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_S8 :
case SF_FORMAT_PCM_U8 :
break ;
default : break ;
} ;
pdither->write_short = psf->write_short ;
psf->write_short = dither_write_short ;
pdither->write_int = psf->write_int ;
psf->write_int = dither_write_int ;
pdither->write_float = psf->write_float ;
psf->write_float = dither_write_float ;
pdither->write_double = psf->write_double ;
psf->write_double = dither_write_double ;
} ;
return 0 ;
} /* dither_init */
/*==============================================================================
*/
static void dither_short (const short *in, short *out, int frames, int channels) ;
static void dither_int (const int *in, int *out, int frames, int channels) ;
static void dither_float (const float *in, float *out, int frames, int channels) ;
static void dither_double (const double *in, double *out, int frames, int channels) ;
static sf_count_t
dither_read_short (SF_PRIVATE * UNUSED (psf), short * UNUSED (ptr), sf_count_t len)
{
return len ;
} /* dither_read_short */
static sf_count_t
dither_read_int (SF_PRIVATE * UNUSED (psf), int * UNUSED (ptr), sf_count_t len)
{
return len ;
} /* dither_read_int */
/*------------------------------------------------------------------------------
*/
static sf_count_t
dither_write_short (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
{ DITHER_DATA *pdither ;
int bufferlen, writecount, thiswrite ;
sf_count_t total = 0 ;
if ((pdither = psf->dither) == NULL)
{ psf->error = SFE_DITHER_BAD_PTR ;
return 0 ;
} ;
switch (SF_CODEC (psf->sf.format))
{ case SF_FORMAT_PCM_S8 :
case SF_FORMAT_PCM_U8 :
case SF_FORMAT_DPCM_8 :
break ;
default :
return pdither->write_short (psf, ptr, len) ;
} ;
bufferlen = sizeof (pdither->buffer) / sizeof (short) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : (int) len ;
writecount /= psf->sf.channels ;
writecount *= psf->sf.channels ;
dither_short (ptr, (short*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ;
thiswrite = pdither->write_short (psf, (short*) pdither->buffer, writecount) ;
total += thiswrite ;
len -= thiswrite ;
if (thiswrite < writecount)
break ;
} ;
return total ;
} /* dither_write_short */
static sf_count_t
dither_write_int (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
{ DITHER_DATA *pdither ;
int bufferlen, writecount, thiswrite ;
sf_count_t total = 0 ;
if ((pdither = psf->dither) == NULL)
{ psf->error = SFE_DITHER_BAD_PTR ;
return 0 ;
} ;
switch (SF_CODEC (psf->sf.format))
{ case SF_FORMAT_PCM_S8 :
case SF_FORMAT_PCM_U8 :
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_24 :
break ;
case SF_FORMAT_DPCM_8 :
case SF_FORMAT_DPCM_16 :
break ;
default :
return pdither->write_int (psf, ptr, len) ;
} ;
bufferlen = sizeof (pdither->buffer) / sizeof (int) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : (int) len ;
writecount /= psf->sf.channels ;
writecount *= psf->sf.channels ;
dither_int (ptr, (int*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ;
thiswrite = pdither->write_int (psf, (int*) pdither->buffer, writecount) ;
total += thiswrite ;
len -= thiswrite ;
if (thiswrite < writecount)
break ;
} ;
return total ;
} /* dither_write_int */
static sf_count_t
dither_write_float (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
{ DITHER_DATA *pdither ;
int bufferlen, writecount, thiswrite ;
sf_count_t total = 0 ;
if ((pdither = psf->dither) == NULL)
{ psf->error = SFE_DITHER_BAD_PTR ;
return 0 ;
} ;
switch (SF_CODEC (psf->sf.format))
{ case SF_FORMAT_PCM_S8 :
case SF_FORMAT_PCM_U8 :
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_24 :
break ;
case SF_FORMAT_DPCM_8 :
case SF_FORMAT_DPCM_16 :
break ;
default :
return pdither->write_float (psf, ptr, len) ;
} ;
bufferlen = sizeof (pdither->buffer) / sizeof (float) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : (float) len ;
writecount /= psf->sf.channels ;
writecount *= psf->sf.channels ;
dither_float (ptr, (float*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ;
thiswrite = pdither->write_float (psf, (float*) pdither->buffer, writecount) ;
total += thiswrite ;
len -= thiswrite ;
if (thiswrite < writecount)
break ;
} ;
return total ;
} /* dither_write_float */
static sf_count_t
dither_write_double (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
{ DITHER_DATA *pdither ;
int bufferlen, writecount, thiswrite ;
sf_count_t total = 0 ;
if ((pdither = psf->dither) == NULL)
{ psf->error = SFE_DITHER_BAD_PTR ;
return 0 ;
} ;
switch (SF_CODEC (psf->sf.format))
{ case SF_FORMAT_PCM_S8 :
case SF_FORMAT_PCM_U8 :
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_24 :
break ;
case SF_FORMAT_DPCM_8 :
case SF_FORMAT_DPCM_16 :
break ;
default :
return pdither->write_double (psf, ptr, len) ;
} ;
bufferlen = sizeof (pdither->buffer) / sizeof (double) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : (double) len ;
writecount /= psf->sf.channels ;
writecount *= psf->sf.channels ;
dither_double (ptr, (double*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ;
thiswrite = pdither->write_double (psf, (double*) pdither->buffer, writecount) ;
total += thiswrite ;
len -= thiswrite ;
if (thiswrite < writecount)
break ;
} ;
return total ;
} /* dither_write_double */
/*==============================================================================
*/
static void
dither_short (const short *in, short *out, int frames, int channels)
{ int ch, k ;
for (ch = 0 ; ch < channels ; ch++)
for (k = ch ; k < channels * frames ; k += channels)
out [k] = in [k] ;
} /* dither_short */
static void
dither_int (const int *in, int *out, int frames, int channels)
{ int ch, k ;
for (ch = 0 ; ch < channels ; ch++)
for (k = ch ; k < channels * frames ; k += channels)
out [k] = in [k] ;
} /* dither_int */
static void
dither_float (const float *in, float *out, int frames, int channels)
{ int ch, k ;
for (ch = 0 ; ch < channels ; ch++)
for (k = ch ; k < channels * frames ; k += channels)
out [k] = in [k] ;
} /* dither_float */
static void
dither_double (const double *in, double *out, int frames, int channels)
{ int ch, k ;
for (ch = 0 ; ch < channels ; ch++)
for (k = ch ; k < channels * frames ; k += channels)
out [k] = in [k] ;
} /* dither_double */
/*==============================================================================
*/
#if 0
/*
** Not made public because this (maybe) requires storage of state information.
**
** Also maybe need separate state info for each channel!!!!
*/
int
DO_NOT_USE_sf_dither_short (const SF_DITHER_INFO *dither, const short *in, short *out, int frames, int channels)
{ int ch, k ;
if (! dither)
return SFE_DITHER_BAD_PTR ;
switch (dither->type & SFD_TYPEMASK)
{ case SFD_WHITE :
case SFD_TRIANGULAR_PDF :
for (ch = 0 ; ch < channels ; ch++)
for (k = ch ; k < channels * frames ; k += channels)
out [k] = in [k] ;
break ;
default :
return SFE_DITHER_BAD_TYPE ;
} ;
return 0 ;
} /* DO_NOT_USE_sf_dither_short */
int
DO_NOT_USE_sf_dither_int (const SF_DITHER_INFO *dither, const int *in, int *out, int frames, int channels)
{ int ch, k ;
if (! dither)
return SFE_DITHER_BAD_PTR ;
switch (dither->type & SFD_TYPEMASK)
{ case SFD_WHITE :
case SFD_TRIANGULAR_PDF :
for (ch = 0 ; ch < channels ; ch++)
for (k = ch ; k < channels * frames ; k += channels)
out [k] = in [k] ;
break ;
default :
return SFE_DITHER_BAD_TYPE ;
} ;
return 0 ;
} /* DO_NOT_USE_sf_dither_int */
int
DO_NOT_USE_sf_dither_float (const SF_DITHER_INFO *dither, const float *in, float *out, int frames, int channels)
{ int ch, k ;
if (! dither)
return SFE_DITHER_BAD_PTR ;
switch (dither->type & SFD_TYPEMASK)
{ case SFD_WHITE :
case SFD_TRIANGULAR_PDF :
for (ch = 0 ; ch < channels ; ch++)
for (k = ch ; k < channels * frames ; k += channels)
out [k] = in [k] ;
break ;
default :
return SFE_DITHER_BAD_TYPE ;
} ;
return 0 ;
} /* DO_NOT_USE_sf_dither_float */
int
DO_NOT_USE_sf_dither_double (const SF_DITHER_INFO *dither, const double *in, double *out, int frames, int channels)
{ int ch, k ;
if (! dither)
return SFE_DITHER_BAD_PTR ;
switch (dither->type & SFD_TYPEMASK)
{ case SFD_WHITE :
case SFD_TRIANGULAR_PDF :
for (ch = 0 ; ch < channels ; ch++)
for (k = ch ; k < channels * frames ; k += channels)
out [k] = in [k] ;
break ;
default :
return SFE_DITHER_BAD_TYPE ;
} ;
return 0 ;
} /* DO_NOT_USE_sf_dither_double */
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,200 @@
/*
** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#if (ENABLE_EXPERIMENTAL_CODE == 0)
int
dwd_open (SF_PRIVATE *psf)
{ if (psf)
return SFE_UNIMPLEMENTED ;
return 0 ;
} /* dwd_open */
#else
/*------------------------------------------------------------------------------
** Macros to handle big/little endian issues.
*/
#define SFE_DWD_NO_DWD 1666
#define SFE_DWD_BAND_BIT_WIDTH 1667
#define SFE_DWD_COMPRESSION 1668
#define DWD_IDENTIFIER "DiamondWare Digitized\n\0\x1a"
#define DWD_IDENTIFIER_LEN 24
#define DWD_HEADER_LEN 57
/*------------------------------------------------------------------------------
** Typedefs.
*/
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int dwd_read_header (SF_PRIVATE *psf) ;
static int dwd_close (SF_PRIVATE *psf) ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
dwd_open (SF_PRIVATE *psf)
{ int error = 0 ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = dwd_read_header (psf)))
return error ;
} ;
if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_DWD)
return SFE_BAD_OPEN_FORMAT ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{
/*-psf->endian = SF_ENDIAN (psf->sf.format) ;
if (CPU_IS_LITTLE_ENDIAN && psf->endian == SF_ENDIAN_CPU)
psf->endian = SF_ENDIAN_LITTLE ;
else if (psf->endian != SF_ENDIAN_LITTLE)
psf->endian = SF_ENDIAN_BIG ;
if (! (encoding = dwd_write_header (psf, SF_FALSE)))
return psf->error ;
psf->write_header = dwd_write_header ;
-*/
} ;
psf->container_close = dwd_close ;
/*-psf->blockwidth = psf->bytewidth * psf->sf.channels ;-*/
return error ;
} /* dwd_open */
/*------------------------------------------------------------------------------
*/
static int
dwd_close (SF_PRIVATE * UNUSED (psf))
{
return 0 ;
} /* dwd_close */
/* This struct contains all the fields of interest om the DWD header, but does not
** do so in the same order and layout as the actual file, header.
** No assumptions are made about the packing of this struct.
*/
typedef struct
{ unsigned char major, minor, compression, channels, bitwidth ;
unsigned short srate, maxval ;
unsigned int id, datalen, frames, offset ;
} DWD_HEADER ;
static int
dwd_read_header (SF_PRIVATE *psf)
{ DWD_HEADER dwdh ;
memset (psf->u.cbuf, 0, sizeof (psf->u.cbuf)) ;
/* Set position to start of file to begin reading header. */
psf_binheader_readf (psf, "pb", 0, psf->u.cbuf, DWD_IDENTIFIER_LEN) ;
if (memcmp (psf->u.cbuf, DWD_IDENTIFIER, DWD_IDENTIFIER_LEN) != 0)
return SFE_DWD_NO_DWD ;
psf_log_printf (psf, "Read only : DiamondWare Digitized (.dwd)\n", psf->u.cbuf) ;
psf_binheader_readf (psf, "11", &dwdh.major, &dwdh.minor) ;
psf_binheader_readf (psf, "e4j1", &dwdh.id, 1, &dwdh.compression) ;
psf_binheader_readf (psf, "e211", &dwdh.srate, &dwdh.channels, &dwdh.bitwidth) ;
psf_binheader_readf (psf, "e24", &dwdh.maxval, &dwdh.datalen) ;
psf_binheader_readf (psf, "e44", &dwdh.frames, &dwdh.offset) ;
psf_log_printf (psf, " Version Major : %d\n Version Minor : %d\n Unique ID : %08X\n",
dwdh.major, dwdh.minor, dwdh.id) ;
psf_log_printf (psf, " Compression : %d => ", dwdh.compression) ;
if (dwdh.compression != 0)
{ psf_log_printf (psf, "Unsupported compression\n") ;
return SFE_DWD_COMPRESSION ;
}
else
psf_log_printf (psf, "None\n") ;
psf_log_printf (psf, " Sample Rate : %d\n Channels : %d\n"
" Bit Width : %d\n",
dwdh.srate, dwdh.channels, dwdh.bitwidth) ;
switch (dwdh.bitwidth)
{ case 8 :
psf->sf.format = SF_FORMAT_DWD | SF_FORMAT_PCM_S8 ;
psf->bytewidth = 1 ;
break ;
case 16 :
psf->sf.format = SF_FORMAT_DWD | SF_FORMAT_PCM_16 ;
psf->bytewidth = 2 ;
break ;
default :
psf_log_printf (psf, "*** Bad bit width %d\n", dwdh.bitwidth) ;
return SFE_DWD_BAND_BIT_WIDTH ;
} ;
if (psf->filelength != dwdh.offset + dwdh.datalen)
{ psf_log_printf (psf, " Data Length : %d (should be %D)\n", dwdh.datalen, psf->filelength - dwdh.offset) ;
dwdh.datalen = (unsigned int) (psf->filelength - dwdh.offset) ;
}
else
psf_log_printf (psf, " Data Length : %d\n", dwdh.datalen) ;
psf_log_printf (psf, " Max Value : %d\n", dwdh.maxval) ;
psf_log_printf (psf, " Frames : %d\n", dwdh.frames) ;
psf_log_printf (psf, " Data Offset : %d\n", dwdh.offset) ;
psf->datalength = dwdh.datalen ;
psf->dataoffset = dwdh.offset ;
psf->endian = SF_ENDIAN_LITTLE ;
psf->sf.samplerate = dwdh.srate ;
psf->sf.channels = dwdh.channels ;
psf->sf.sections = 1 ;
return pcm_init (psf) ;
} /* dwd_read_header */
/*------------------------------------------------------------------------------
*/
#endif

View File

@@ -0,0 +1,662 @@
/*
** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*===========================================================================
** Delta Word Variable Width
**
** This decoder and encoder were implemented using information found in this
** document : http://home.swbell.net/rubywand/R011SNDFMTS.TXT
**
** According to the document, the algorithm "was invented 1991 by Magnus
** Lidstrom and is copyright 1993 by NuEdge Development".
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
typedef struct
{ int dwm_maxsize, bit_width, max_delta, span ;
int samplecount ;
int bit_count, bits, last_delta_width, last_sample ;
struct
{ int index, end ;
unsigned char buffer [256] ;
} b ;
} DWVW_PRIVATE ;
/*============================================================================================
*/
static sf_count_t dwvw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
static sf_count_t dwvw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
static sf_count_t dwvw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
static sf_count_t dwvw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
static sf_count_t dwvw_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
static sf_count_t dwvw_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
static sf_count_t dwvw_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
static sf_count_t dwvw_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
static sf_count_t dwvw_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
static int dwvw_close (SF_PRIVATE *psf) ;
static int dwvw_decode_data (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int *ptr, int len) ;
static int dwvw_decode_load_bits (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int bit_count) ;
static int dwvw_encode_data (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, const int *ptr, int len) ;
static void dwvw_encode_store_bits (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int data, int new_bits) ;
static void dwvw_read_reset (DWVW_PRIVATE *pdwvw) ;
/*============================================================================================
** DWVW initialisation function.
*/
int
dwvw_init (SF_PRIVATE *psf, int bitwidth)
{ DWVW_PRIVATE *pdwvw ;
if (psf->codec_data != NULL)
{ psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ;
return SFE_INTERNAL ;
} ;
if (bitwidth > 24)
return SFE_DWVW_BAD_BITWIDTH ;
if (psf->file.mode == SFM_RDWR)
return SFE_BAD_MODE_RW ;
if ((pdwvw = calloc (1, sizeof (DWVW_PRIVATE))) == NULL)
return SFE_MALLOC_FAILED ;
psf->codec_data = (void*) pdwvw ;
pdwvw->bit_width = bitwidth ;
pdwvw->dwm_maxsize = bitwidth / 2 ;
pdwvw->max_delta = 1 << (bitwidth - 1) ;
pdwvw->span = 1 << bitwidth ;
dwvw_read_reset (pdwvw) ;
if (psf->file.mode == SFM_READ)
{ psf->read_short = dwvw_read_s ;
psf->read_int = dwvw_read_i ;
psf->read_float = dwvw_read_f ;
psf->read_double = dwvw_read_d ;
} ;
if (psf->file.mode == SFM_WRITE)
{ psf->write_short = dwvw_write_s ;
psf->write_int = dwvw_write_i ;
psf->write_float = dwvw_write_f ;
psf->write_double = dwvw_write_d ;
} ;
psf->codec_close = dwvw_close ;
psf->seek = dwvw_seek ;
/* FIXME : This is bogus. */
psf->sf.frames = SF_COUNT_MAX ;
psf->datalength = psf->sf.frames ;
/* EMXIF : This is bogus. */
return 0 ;
} /* dwvw_init */
/*--------------------------------------------------------------------------------------------
*/
static int
dwvw_close (SF_PRIVATE *psf)
{ DWVW_PRIVATE *pdwvw ;
if (psf->codec_data == NULL)
return 0 ;
pdwvw = (DWVW_PRIVATE*) psf->codec_data ;
if (psf->file.mode == SFM_WRITE)
{ static int last_values [12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ;
/* Write 8 zero samples to fully flush output. */
dwvw_encode_data (psf, pdwvw, last_values, 12) ;
/* Write the last buffer worth of data to disk. */
psf_fwrite (pdwvw->b.buffer, 1, pdwvw->b.index, psf) ;
if (psf->write_header)
psf->write_header (psf, SF_TRUE) ;
} ;
return 0 ;
} /* dwvw_close */
static sf_count_t
dwvw_seek (SF_PRIVATE *psf, int UNUSED (mode), sf_count_t offset)
{ DWVW_PRIVATE *pdwvw ;
if (! psf->codec_data)
{ psf->error = SFE_INTERNAL ;
return PSF_SEEK_ERROR ;
} ;
pdwvw = (DWVW_PRIVATE*) psf->codec_data ;
if (offset == 0)
{ psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
dwvw_read_reset (pdwvw) ;
return 0 ;
} ;
psf->error = SFE_BAD_SEEK ;
return PSF_SEEK_ERROR ;
} /* dwvw_seek */
/*==============================================================================
*/
static sf_count_t
dwvw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
{ DWVW_PRIVATE *pdwvw ;
int *iptr ;
int k, bufferlen, readcount = 0, count ;
sf_count_t total = 0 ;
if (! psf->codec_data)
return 0 ;
pdwvw = (DWVW_PRIVATE*) psf->codec_data ;
iptr = psf->u.ibuf ;
bufferlen = ARRAY_LEN (psf->u.ibuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = dwvw_decode_data (psf, pdwvw, iptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = iptr [k] >> 16 ;
total += count ;
len -= readcount ;
if (count != readcount)
break ;
} ;
return total ;
} /* dwvw_read_s */
static sf_count_t
dwvw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
{ DWVW_PRIVATE *pdwvw ;
int readcount, count ;
sf_count_t total = 0 ;
if (! psf->codec_data)
return 0 ;
pdwvw = (DWVW_PRIVATE*) psf->codec_data ;
while (len > 0)
{ readcount = (len > 0x10000000) ? 0x10000000 : (int) len ;
count = dwvw_decode_data (psf, pdwvw, ptr, readcount) ;
total += count ;
len -= count ;
if (count != readcount)
break ;
} ;
return total ;
} /* dwvw_read_i */
static sf_count_t
dwvw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
{ DWVW_PRIVATE *pdwvw ;
int *iptr ;
int k, bufferlen, readcount = 0, count ;
sf_count_t total = 0 ;
float normfact ;
if (! psf->codec_data)
return 0 ;
pdwvw = (DWVW_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80000000) : 1.0 ;
iptr = psf->u.ibuf ;
bufferlen = ARRAY_LEN (psf->u.ibuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = dwvw_decode_data (psf, pdwvw, iptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = normfact * (float) (iptr [k]) ;
total += count ;
len -= readcount ;
if (count != readcount)
break ;
} ;
return total ;
} /* dwvw_read_f */
static sf_count_t
dwvw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
{ DWVW_PRIVATE *pdwvw ;
int *iptr ;
int k, bufferlen, readcount = 0, count ;
sf_count_t total = 0 ;
double normfact ;
if (! psf->codec_data)
return 0 ;
pdwvw = (DWVW_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80000000) : 1.0 ;
iptr = psf->u.ibuf ;
bufferlen = ARRAY_LEN (psf->u.ibuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = dwvw_decode_data (psf, pdwvw, iptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = normfact * (double) (iptr [k]) ;
total += count ;
len -= readcount ;
if (count != readcount)
break ;
} ;
return total ;
} /* dwvw_read_d */
static int
dwvw_decode_data (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int *ptr, int len)
{ int count ;
int delta_width_modifier, delta_width, delta_negative, delta, sample ;
/* Restore state from last decode call. */
delta_width = pdwvw->last_delta_width ;
sample = pdwvw->last_sample ;
for (count = 0 ; count < len ; count++)
{ /* If bit_count parameter is zero get the delta_width_modifier. */
delta_width_modifier = dwvw_decode_load_bits (psf, pdwvw, -1) ;
/* Check for end of input bit stream. Break loop if end. */
if (delta_width_modifier < 0)
break ;
if (delta_width_modifier && dwvw_decode_load_bits (psf, pdwvw, 1))
delta_width_modifier = - delta_width_modifier ;
/* Calculate the current word width. */
delta_width = (delta_width + delta_width_modifier + pdwvw->bit_width) % pdwvw->bit_width ;
/* Load the delta. */
delta = 0 ;
if (delta_width)
{ delta = dwvw_decode_load_bits (psf, pdwvw, delta_width - 1) | (1 << (delta_width - 1)) ;
delta_negative = dwvw_decode_load_bits (psf, pdwvw, 1) ;
if (delta == pdwvw->max_delta - 1)
delta += dwvw_decode_load_bits (psf, pdwvw, 1) ;
if (delta_negative)
delta = -delta ;
} ;
/* Calculate the sample */
sample += delta ;
if (sample >= pdwvw->max_delta)
sample -= pdwvw->span ;
else if (sample < - pdwvw->max_delta)
sample += pdwvw->span ;
/* Store the sample justifying to the most significant bit. */
ptr [count] = sample << (32 - pdwvw->bit_width) ;
if (pdwvw->b.end == 0 && pdwvw->bit_count == 0)
break ;
} ;
pdwvw->last_delta_width = delta_width ;
pdwvw->last_sample = sample ;
pdwvw->samplecount += count ;
return count ;
} /* dwvw_decode_data */
static int
dwvw_decode_load_bits (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int bit_count)
{ int output = 0, get_dwm = SF_FALSE ;
/*
** Depending on the value of parameter bit_count, either get the
** required number of bits (ie bit_count > 0) or the
** delta_width_modifier (otherwise).
*/
if (bit_count < 0)
{ get_dwm = SF_TRUE ;
/* modify bit_count to ensure we have enought bits for finding dwm. */
bit_count = pdwvw->dwm_maxsize ;
} ;
/* Load bits in bit reseviour. */
while (pdwvw->bit_count < bit_count)
{ if (pdwvw->b.index >= pdwvw->b.end)
{ pdwvw->b.end = psf_fread (pdwvw->b.buffer, 1, sizeof (pdwvw->b.buffer), psf) ;
pdwvw->b.index = 0 ;
} ;
/* Check for end of input stream. */
if (bit_count < 8 && pdwvw->b.end == 0)
return -1 ;
pdwvw->bits = (pdwvw->bits << 8) ;
if (pdwvw->b.index < pdwvw->b.end)
{ pdwvw->bits |= pdwvw->b.buffer [pdwvw->b.index] ;
pdwvw->b.index ++ ;
} ;
pdwvw->bit_count += 8 ;
} ;
/* If asked to get bits do so. */
if (! get_dwm)
{ output = (pdwvw->bits >> (pdwvw->bit_count - bit_count)) & ((1 << bit_count) - 1) ;
pdwvw->bit_count -= bit_count ;
return output ;
} ;
/* Otherwise must have been asked to get delta_width_modifier. */
while (output < (pdwvw->dwm_maxsize))
{ pdwvw->bit_count -= 1 ;
if (pdwvw->bits & (1 << pdwvw->bit_count))
break ;
output += 1 ;
} ;
return output ;
} /* dwvw_decode_load_bits */
static void
dwvw_read_reset (DWVW_PRIVATE *pdwvw)
{ pdwvw->samplecount = 0 ;
pdwvw->b.index = 0 ;
pdwvw->b.end = 0 ;
pdwvw->bit_count = 0 ;
pdwvw->bits = 0 ;
pdwvw->last_delta_width = 0 ;
pdwvw->last_sample = 0 ;
} /* dwvw_read_reset */
static void
dwvw_encode_store_bits (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int data, int new_bits)
{ int byte ;
/* Shift the bits into the resevoir. */
pdwvw->bits = (pdwvw->bits << new_bits) | (data & ((1 << new_bits) - 1)) ;
pdwvw->bit_count += new_bits ;
/* Transfer bit to buffer. */
while (pdwvw->bit_count >= 8)
{ byte = pdwvw->bits >> (pdwvw->bit_count - 8) ;
pdwvw->bit_count -= 8 ;
pdwvw->b.buffer [pdwvw->b.index] = byte & 0xFF ;
pdwvw->b.index ++ ;
} ;
if (pdwvw->b.index > SIGNED_SIZEOF (pdwvw->b.buffer) - 4)
{ psf_fwrite (pdwvw->b.buffer, 1, pdwvw->b.index, psf) ;
pdwvw->b.index = 0 ;
} ;
return ;
} /* dwvw_encode_store_bits */
#if 0
/* Debigging routine. */
static void
dump_bits (DWVW_PRIVATE *pdwvw)
{ int k, mask ;
for (k = 0 ; k < 10 && k < pdwvw->b.index ; k++)
{ mask = 0x80 ;
while (mask)
{ putchar (mask & pdwvw->b.buffer [k] ? '1' : '0') ;
mask >>= 1 ;
} ;
putchar (' ') ;
}
for (k = pdwvw->bit_count - 1 ; k >= 0 ; k --)
putchar (pdwvw->bits & (1 << k) ? '1' : '0') ;
putchar ('\n') ;
} /* dump_bits */
#endif
#define HIGHEST_BIT(x,count) \
{ int y = x ; \
(count) = 0 ; \
while (y) \
{ (count) ++ ; \
y >>= 1 ; \
} ; \
} ;
static int
dwvw_encode_data (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, const int *ptr, int len)
{ int count ;
int delta_width_modifier, delta, delta_negative, delta_width, extra_bit ;
for (count = 0 ; count < len ; count++)
{ delta = (ptr [count] >> (32 - pdwvw->bit_width)) - pdwvw->last_sample ;
/* Calculate extra_bit if needed. */
extra_bit = -1 ;
delta_negative = 0 ;
if (delta < -pdwvw->max_delta)
delta = pdwvw->max_delta + (delta % pdwvw->max_delta) ;
else if (delta == -pdwvw->max_delta)
{ extra_bit = 1 ;
delta_negative = 1 ;
delta = pdwvw->max_delta - 1 ;
}
else if (delta > pdwvw->max_delta)
{ delta_negative = 1 ;
delta = pdwvw->span - delta ;
delta = abs (delta) ;
}
else if (delta == pdwvw->max_delta)
{ extra_bit = 1 ;
delta = pdwvw->max_delta - 1 ;
}
else if (delta < 0)
{ delta_negative = 1 ;
delta = abs (delta) ;
} ;
if (delta == pdwvw->max_delta - 1 && extra_bit == -1)
extra_bit = 0 ;
/* Find width in bits of delta */
HIGHEST_BIT (delta, delta_width) ;
/* Calculate the delta_width_modifier */
delta_width_modifier = (delta_width - pdwvw->last_delta_width) % pdwvw->bit_width ;
if (delta_width_modifier > pdwvw->dwm_maxsize)
delta_width_modifier -= pdwvw->bit_width ;
if (delta_width_modifier < -pdwvw->dwm_maxsize)
delta_width_modifier += pdwvw->bit_width ;
/* Write delta_width_modifier zeros, followed by terminating '1'. */
dwvw_encode_store_bits (psf, pdwvw, 0, abs (delta_width_modifier)) ;
if (abs (delta_width_modifier) != pdwvw->dwm_maxsize)
dwvw_encode_store_bits (psf, pdwvw, 1, 1) ;
/* Write delta_width_modifier sign. */
if (delta_width_modifier < 0)
dwvw_encode_store_bits (psf, pdwvw, 1, 1) ;
if (delta_width_modifier > 0)
dwvw_encode_store_bits (psf, pdwvw, 0, 1) ;
/* Write delta and delta sign bit. */
if (delta_width)
{ dwvw_encode_store_bits (psf, pdwvw, delta, abs (delta_width) - 1) ;
dwvw_encode_store_bits (psf, pdwvw, (delta_negative ? 1 : 0), 1) ;
} ;
/* Write extra bit!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
if (extra_bit >= 0)
dwvw_encode_store_bits (psf, pdwvw, extra_bit, 1) ;
pdwvw->last_sample = ptr [count] >> (32 - pdwvw->bit_width) ;
pdwvw->last_delta_width = delta_width ;
} ;
pdwvw->samplecount += count ;
return count ;
} /* dwvw_encode_data */
static sf_count_t
dwvw_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
{ DWVW_PRIVATE *pdwvw ;
int *iptr ;
int k, bufferlen, writecount = 0, count ;
sf_count_t total = 0 ;
if (! psf->codec_data)
return 0 ;
pdwvw = (DWVW_PRIVATE*) psf->codec_data ;
iptr = psf->u.ibuf ;
bufferlen = ARRAY_LEN (psf->u.ibuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
iptr [k] = ptr [total + k] << 16 ;
count = dwvw_encode_data (psf, pdwvw, iptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* dwvw_write_s */
static sf_count_t
dwvw_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
{ DWVW_PRIVATE *pdwvw ;
int writecount, count ;
sf_count_t total = 0 ;
if (! psf->codec_data)
return 0 ;
pdwvw = (DWVW_PRIVATE*) psf->codec_data ;
while (len > 0)
{ writecount = (len > 0x10000000) ? 0x10000000 : (int) len ;
count = dwvw_encode_data (psf, pdwvw, ptr, writecount) ;
total += count ;
len -= count ;
if (count != writecount)
break ;
} ;
return total ;
} /* dwvw_write_i */
static sf_count_t
dwvw_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
{ DWVW_PRIVATE *pdwvw ;
int *iptr ;
int k, bufferlen, writecount = 0, count ;
sf_count_t total = 0 ;
float normfact ;
if (! psf->codec_data)
return 0 ;
pdwvw = (DWVW_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : 1.0 ;
iptr = psf->u.ibuf ;
bufferlen = ARRAY_LEN (psf->u.ibuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
iptr [k] = lrintf (normfact * ptr [total + k]) ;
count = dwvw_encode_data (psf, pdwvw, iptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* dwvw_write_f */
static sf_count_t
dwvw_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
{ DWVW_PRIVATE *pdwvw ;
int *iptr ;
int k, bufferlen, writecount = 0, count ;
sf_count_t total = 0 ;
double normfact ;
if (! psf->codec_data)
return 0 ;
pdwvw = (DWVW_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : 1.0 ;
iptr = psf->u.ibuf ;
bufferlen = ARRAY_LEN (psf->u.ibuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
iptr [k] = lrint (normfact * ptr [total + k]) ;
count = dwvw_encode_data (psf, pdwvw, iptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* dwvw_write_d */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,996 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <math.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#if CPU_IS_LITTLE_ENDIAN
#define FLOAT32_READ float32_le_read
#define FLOAT32_WRITE float32_le_write
#elif CPU_IS_BIG_ENDIAN
#define FLOAT32_READ float32_be_read
#define FLOAT32_WRITE float32_be_write
#endif
/*--------------------------------------------------------------------------------------------
** Processor floating point capabilities. float32_get_capability () returns one of the
** latter four values.
*/
enum
{ FLOAT_UNKNOWN = 0x00,
FLOAT_CAN_RW_LE = 0x12,
FLOAT_CAN_RW_BE = 0x23,
FLOAT_BROKEN_LE = 0x34,
FLOAT_BROKEN_BE = 0x45
} ;
/*--------------------------------------------------------------------------------------------
** Prototypes for private functions.
*/
static sf_count_t host_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
static sf_count_t host_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
static sf_count_t host_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
static sf_count_t host_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
static sf_count_t host_write_s2f (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
static sf_count_t host_write_i2f (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
static sf_count_t host_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
static sf_count_t host_write_d2f (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
static void float32_peak_update (SF_PRIVATE *psf, const float *buffer, int count, sf_count_t indx) ;
static sf_count_t replace_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
static sf_count_t replace_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
static sf_count_t replace_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
static sf_count_t replace_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
static sf_count_t replace_write_s2f (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
static sf_count_t replace_write_i2f (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
static sf_count_t replace_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
static sf_count_t replace_write_d2f (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
static void bf2f_array (float *buffer, int count) ;
static void f2bf_array (float *buffer, int count) ;
static int float32_get_capability (SF_PRIVATE *psf) ;
/*--------------------------------------------------------------------------------------------
** Exported functions.
*/
int
float32_init (SF_PRIVATE *psf)
{ static int float_caps ;
float_caps = float32_get_capability (psf) ;
psf->blockwidth = sizeof (float) * psf->sf.channels ;
if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR)
{ switch (psf->endian + float_caps)
{ case (SF_ENDIAN_BIG + FLOAT_CAN_RW_BE) :
psf->data_endswap = SF_FALSE ;
psf->read_short = host_read_f2s ;
psf->read_int = host_read_f2i ;
psf->read_float = host_read_f ;
psf->read_double = host_read_f2d ;
break ;
case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_LE) :
psf->data_endswap = SF_FALSE ;
psf->read_short = host_read_f2s ;
psf->read_int = host_read_f2i ;
psf->read_float = host_read_f ;
psf->read_double = host_read_f2d ;
break ;
case (SF_ENDIAN_BIG + FLOAT_CAN_RW_LE) :
psf->data_endswap = SF_TRUE ;
psf->read_short = host_read_f2s ;
psf->read_int = host_read_f2i ;
psf->read_float = host_read_f ;
psf->read_double = host_read_f2d ;
break ;
case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_BE) :
psf->data_endswap = SF_TRUE ;
psf->read_short = host_read_f2s ;
psf->read_int = host_read_f2i ;
psf->read_float = host_read_f ;
psf->read_double = host_read_f2d ;
break ;
/* When the CPU is not IEEE compatible. */
case (SF_ENDIAN_BIG + FLOAT_BROKEN_LE) :
psf->data_endswap = SF_TRUE ;
psf->read_short = replace_read_f2s ;
psf->read_int = replace_read_f2i ;
psf->read_float = replace_read_f ;
psf->read_double = replace_read_f2d ;
break ;
case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_LE) :
psf->data_endswap = SF_FALSE ;
psf->read_short = replace_read_f2s ;
psf->read_int = replace_read_f2i ;
psf->read_float = replace_read_f ;
psf->read_double = replace_read_f2d ;
break ;
case (SF_ENDIAN_BIG + FLOAT_BROKEN_BE) :
psf->data_endswap = SF_FALSE ;
psf->read_short = replace_read_f2s ;
psf->read_int = replace_read_f2i ;
psf->read_float = replace_read_f ;
psf->read_double = replace_read_f2d ;
break ;
case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_BE) :
psf->data_endswap = SF_TRUE ;
psf->read_short = replace_read_f2s ;
psf->read_int = replace_read_f2i ;
psf->read_float = replace_read_f ;
psf->read_double = replace_read_f2d ;
break ;
default : break ;
} ;
} ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ switch (psf->endian + float_caps)
{ case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_LE) :
psf->data_endswap = SF_FALSE ;
psf->write_short = host_write_s2f ;
psf->write_int = host_write_i2f ;
psf->write_float = host_write_f ;
psf->write_double = host_write_d2f ;
break ;
case (SF_ENDIAN_BIG + FLOAT_CAN_RW_BE) :
psf->data_endswap = SF_FALSE ;
psf->write_short = host_write_s2f ;
psf->write_int = host_write_i2f ;
psf->write_float = host_write_f ;
psf->write_double = host_write_d2f ;
break ;
case (SF_ENDIAN_BIG + FLOAT_CAN_RW_LE) :
psf->data_endswap = SF_TRUE ;
psf->write_short = host_write_s2f ;
psf->write_int = host_write_i2f ;
psf->write_float = host_write_f ;
psf->write_double = host_write_d2f ;
break ;
case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_BE) :
psf->data_endswap = SF_TRUE ;
psf->write_short = host_write_s2f ;
psf->write_int = host_write_i2f ;
psf->write_float = host_write_f ;
psf->write_double = host_write_d2f ;
break ;
/* When the CPU is not IEEE compatible. */
case (SF_ENDIAN_BIG + FLOAT_BROKEN_LE) :
psf->data_endswap = SF_TRUE ;
psf->write_short = replace_write_s2f ;
psf->write_int = replace_write_i2f ;
psf->write_float = replace_write_f ;
psf->write_double = replace_write_d2f ;
break ;
case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_LE) :
psf->data_endswap = SF_FALSE ;
psf->write_short = replace_write_s2f ;
psf->write_int = replace_write_i2f ;
psf->write_float = replace_write_f ;
psf->write_double = replace_write_d2f ;
break ;
case (SF_ENDIAN_BIG + FLOAT_BROKEN_BE) :
psf->data_endswap = SF_FALSE ;
psf->write_short = replace_write_s2f ;
psf->write_int = replace_write_i2f ;
psf->write_float = replace_write_f ;
psf->write_double = replace_write_d2f ;
break ;
case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_BE) :
psf->data_endswap = SF_TRUE ;
psf->write_short = replace_write_s2f ;
psf->write_int = replace_write_i2f ;
psf->write_float = replace_write_f ;
psf->write_double = replace_write_d2f ;
break ;
default : break ;
} ;
} ;
if (psf->filelength > psf->dataoffset)
{ psf->datalength = (psf->dataend > 0) ? psf->dataend - psf->dataoffset :
psf->filelength - psf->dataoffset ;
}
else
psf->datalength = 0 ;
psf->sf.frames = psf->blockwidth > 0 ? psf->datalength / psf->blockwidth : 0 ;
return 0 ;
} /* float32_init */
float
float32_be_read (unsigned char *cptr)
{ int exponent, mantissa, negative ;
float fvalue ;
negative = cptr [0] & 0x80 ;
exponent = ((cptr [0] & 0x7F) << 1) | ((cptr [1] & 0x80) ? 1 : 0) ;
mantissa = ((cptr [1] & 0x7F) << 16) | (cptr [2] << 8) | (cptr [3]) ;
if (! (exponent || mantissa))
return 0.0 ;
mantissa |= 0x800000 ;
exponent = exponent ? exponent - 127 : 0 ;
fvalue = mantissa ? ((float) mantissa) / ((float) 0x800000) : 0.0 ;
if (negative)
fvalue *= -1 ;
if (exponent > 0)
fvalue *= pow (2.0, exponent) ;
else if (exponent < 0)
fvalue /= pow (2.0, abs (exponent)) ;
return fvalue ;
} /* float32_be_read */
float
float32_le_read (unsigned char *cptr)
{ int exponent, mantissa, negative ;
float fvalue ;
negative = cptr [3] & 0x80 ;
exponent = ((cptr [3] & 0x7F) << 1) | ((cptr [2] & 0x80) ? 1 : 0) ;
mantissa = ((cptr [2] & 0x7F) << 16) | (cptr [1] << 8) | (cptr [0]) ;
if (! (exponent || mantissa))
return 0.0 ;
mantissa |= 0x800000 ;
exponent = exponent ? exponent - 127 : 0 ;
fvalue = mantissa ? ((float) mantissa) / ((float) 0x800000) : 0.0 ;
if (negative)
fvalue *= -1 ;
if (exponent > 0)
fvalue *= pow (2.0, exponent) ;
else if (exponent < 0)
fvalue /= pow (2.0, abs (exponent)) ;
return fvalue ;
} /* float32_le_read */
void
float32_le_write (float in, unsigned char *out)
{ int exponent, mantissa, negative = 0 ;
memset (out, 0, sizeof (int)) ;
if (fabs (in) < 1e-30)
return ;
if (in < 0.0)
{ in *= -1.0 ;
negative = 1 ;
} ;
in = frexp (in, &exponent) ;
exponent += 126 ;
in *= (float) 0x1000000 ;
mantissa = (((int) in) & 0x7FFFFF) ;
if (negative)
out [3] |= 0x80 ;
if (exponent & 0x01)
out [2] |= 0x80 ;
out [0] = mantissa & 0xFF ;
out [1] = (mantissa >> 8) & 0xFF ;
out [2] |= (mantissa >> 16) & 0x7F ;
out [3] |= (exponent >> 1) & 0x7F ;
return ;
} /* float32_le_write */
void
float32_be_write (float in, unsigned char *out)
{ int exponent, mantissa, negative = 0 ;
memset (out, 0, sizeof (int)) ;
if (fabs (in) < 1e-30)
return ;
if (in < 0.0)
{ in *= -1.0 ;
negative = 1 ;
} ;
in = frexp (in, &exponent) ;
exponent += 126 ;
in *= (float) 0x1000000 ;
mantissa = (((int) in) & 0x7FFFFF) ;
if (negative)
out [0] |= 0x80 ;
if (exponent & 0x01)
out [1] |= 0x80 ;
out [3] = mantissa & 0xFF ;
out [2] = (mantissa >> 8) & 0xFF ;
out [1] |= (mantissa >> 16) & 0x7F ;
out [0] |= (exponent >> 1) & 0x7F ;
return ;
} /* float32_be_write */
/*==============================================================================================
** Private functions.
*/
static void
float32_peak_update (SF_PRIVATE *psf, const float *buffer, int count, sf_count_t indx)
{ int chan ;
int k, position ;
float fmaxval ;
for (chan = 0 ; chan < psf->sf.channels ; chan++)
{ fmaxval = fabs (buffer [chan]) ;
position = 0 ;
for (k = chan ; k < count ; k += psf->sf.channels)
if (fmaxval < fabs (buffer [k]))
{ fmaxval = fabs (buffer [k]) ;
position = k ;
} ;
if (fmaxval > psf->peak_info->peaks [chan].value)
{ psf->peak_info->peaks [chan].value = fmaxval ;
psf->peak_info->peaks [chan].position = psf->write_current + indx + (position / psf->sf.channels) ;
} ;
} ;
return ;
} /* float32_peak_update */
static int
float32_get_capability (SF_PRIVATE *psf)
{ union
{ float f ;
int i ;
unsigned char c [4] ;
} data ;
data.f = (float) 1.23456789 ; /* Some abitrary value. */
if (! psf->ieee_replace)
{ /* If this test is true ints and floats are compatible and little endian. */
if (data.c [0] == 0x52 && data.c [1] == 0x06 && data.c [2] == 0x9e && data.c [3] == 0x3f)
return FLOAT_CAN_RW_LE ;
/* If this test is true ints and floats are compatible and big endian. */
if (data.c [3] == 0x52 && data.c [2] == 0x06 && data.c [1] == 0x9e && data.c [0] == 0x3f)
return FLOAT_CAN_RW_BE ;
} ;
/* Floats are broken. Don't expect reading or writing to be fast. */
psf_log_printf (psf, "Using IEEE replacement code for float.\n") ;
return (CPU_IS_LITTLE_ENDIAN) ? FLOAT_BROKEN_LE : FLOAT_BROKEN_BE ;
} /* float32_get_capability */
/*=======================================================================================
*/
static void
f2s_array (const float *src, int count, short *dest, float scale)
{
while (--count >= 0)
{ dest [count] = lrintf (scale * src [count]) ;
} ;
} /* f2s_array */
static void
f2s_clip_array (const float *src, int count, short *dest, float scale)
{ while (--count >= 0)
{ float tmp = scale * src [count] ;
if (CPU_CLIPS_POSITIVE == 0 && tmp > 32767.0)
dest [count] = SHRT_MAX ;
else if (CPU_CLIPS_NEGATIVE == 0 && tmp < -32768.0)
dest [count] = SHRT_MIN ;
else
dest [count] = lrintf (tmp) ;
} ;
} /* f2s_clip_array */
static inline void
f2i_array (const float *src, int count, int *dest, float scale)
{ while (--count >= 0)
{ dest [count] = lrintf (scale * src [count]) ;
} ;
} /* f2i_array */
static inline void
f2i_clip_array (const float *src, int count, int *dest, float scale)
{ while (--count >= 0)
{ float tmp = scale * src [count] ;
if (CPU_CLIPS_POSITIVE == 0 && tmp > (1.0 * INT_MAX))
dest [count] = INT_MAX ;
else if (CPU_CLIPS_NEGATIVE == 0 && tmp < (-1.0 * INT_MAX))
dest [count] = INT_MIN ;
else
dest [count] = lrintf (tmp) ;
} ;
} /* f2i_clip_array */
static inline void
f2d_array (const float *src, int count, double *dest)
{ while (--count >= 0)
{ dest [count] = src [count] ;
} ;
} /* f2d_array */
static inline void
s2f_array (const short *src, float *dest, int count, float scale)
{ while (--count >= 0)
{ dest [count] = scale * src [count] ;
} ;
} /* s2f_array */
static inline void
i2f_array (const int *src, float *dest, int count, float scale)
{ while (--count >= 0)
{ dest [count] = scale * src [count] ;
} ;
} /* i2f_array */
static inline void
d2f_array (const double *src, float *dest, int count)
{ while (--count >= 0)
{ dest [count] = src [count] ;
} ;
} /* d2f_array */
/*----------------------------------------------------------------------------------------------
*/
static sf_count_t
host_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
{ void (*convert) (const float *, int, short *, float) ;
int bufferlen, readcount ;
sf_count_t total = 0 ;
float scale ;
convert = (psf->add_clipping) ? f2s_clip_array : f2s_array ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
/* Fix me : Need lef2s_array */
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
convert (psf->u.fbuf, readcount, ptr + total, scale) ;
total += readcount ;
if (readcount < bufferlen)
break ;
len -= readcount ;
} ;
return total ;
} /* host_read_f2s */
static sf_count_t
host_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
{ void (*convert) (const float *, int, int *, float) ;
int bufferlen, readcount ;
sf_count_t total = 0 ;
float scale ;
convert = (psf->add_clipping) ? f2i_clip_array : f2i_array ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFFFFFF / psf->float_max ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
convert (psf->u.fbuf, readcount, ptr + total, scale) ;
total += readcount ;
if (readcount < bufferlen)
break ;
len -= readcount ;
} ;
return total ;
} /* host_read_f2i */
static sf_count_t
host_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
{ int bufferlen, readcount ;
sf_count_t total = 0 ;
if (psf->data_endswap != SF_TRUE)
return psf_fread (ptr, sizeof (float), len, psf) ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
endswap_int_copy ((int*) (ptr + total), psf->u.ibuf, readcount) ;
total += readcount ;
if (readcount < bufferlen)
break ;
len -= readcount ;
} ;
return total ;
} /* host_read_f */
static sf_count_t
host_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
{ int bufferlen, readcount ;
sf_count_t total = 0 ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
/* Fix me : Need lef2d_array */
f2d_array (psf->u.fbuf, readcount, ptr + total) ;
total += readcount ;
if (readcount < bufferlen)
break ;
len -= readcount ;
} ;
return total ;
} /* host_read_f2d */
static sf_count_t
host_write_s2f (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
{ int bufferlen, writecount ;
sf_count_t total = 0 ;
float scale ;
/* Erik */
scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / 0x8000 ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
s2f_array (ptr + total, psf->u.fbuf, bufferlen, scale) ;
if (psf->peak_info)
float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ;
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
writecount = psf_fwrite (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
total += writecount ;
if (writecount < bufferlen)
break ;
len -= writecount ;
} ;
return total ;
} /* host_write_s2f */
static sf_count_t
host_write_i2f (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
{ int bufferlen, writecount ;
sf_count_t total = 0 ;
float scale ;
scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / (8.0 * 0x10000000) ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
i2f_array (ptr + total, psf->u.fbuf, bufferlen, scale) ;
if (psf->peak_info)
float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ;
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
writecount = psf_fwrite (psf->u.fbuf, sizeof (float) , bufferlen, psf) ;
total += writecount ;
if (writecount < bufferlen)
break ;
len -= writecount ;
} ;
return total ;
} /* host_write_i2f */
static sf_count_t
host_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
{ int bufferlen, writecount ;
sf_count_t total = 0 ;
if (psf->peak_info)
float32_peak_update (psf, ptr, len, 0) ;
if (psf->data_endswap != SF_TRUE)
return psf_fwrite (ptr, sizeof (float), len, psf) ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
endswap_int_copy (psf->u.ibuf, (const int*) (ptr + total), bufferlen) ;
writecount = psf_fwrite (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
total += writecount ;
if (writecount < bufferlen)
break ;
len -= writecount ;
} ;
return total ;
} /* host_write_f */
static sf_count_t
host_write_d2f (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
{ int bufferlen, writecount ;
sf_count_t total = 0 ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
d2f_array (ptr + total, psf->u.fbuf, bufferlen) ;
if (psf->peak_info)
float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ;
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
writecount = psf_fwrite (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
total += writecount ;
if (writecount < bufferlen)
break ;
len -= writecount ;
} ;
return total ;
} /* host_write_d2f */
/*=======================================================================================
*/
static sf_count_t
replace_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
{ int bufferlen, readcount ;
sf_count_t total = 0 ;
float scale ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
bf2f_array (psf->u.fbuf, bufferlen) ;
f2s_array (psf->u.fbuf, readcount, ptr + total, scale) ;
total += readcount ;
if (readcount < bufferlen)
break ;
len -= readcount ;
} ;
return total ;
} /* replace_read_f2s */
static sf_count_t
replace_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
{ int bufferlen, readcount ;
sf_count_t total = 0 ;
float scale ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
bf2f_array (psf->u.fbuf, bufferlen) ;
f2i_array (psf->u.fbuf, readcount, ptr + total, scale) ;
total += readcount ;
if (readcount < bufferlen)
break ;
len -= readcount ;
} ;
return total ;
} /* replace_read_f2i */
static sf_count_t
replace_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
{ int bufferlen, readcount ;
sf_count_t total = 0 ;
/* FIX THIS */
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
bf2f_array (psf->u.fbuf, bufferlen) ;
memcpy (ptr + total, psf->u.fbuf, bufferlen * sizeof (float)) ;
total += readcount ;
if (readcount < bufferlen)
break ;
len -= readcount ;
} ;
return total ;
} /* replace_read_f */
static sf_count_t
replace_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
{ int bufferlen, readcount ;
sf_count_t total = 0 ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
bf2f_array (psf->u.fbuf, bufferlen) ;
f2d_array (psf->u.fbuf, readcount, ptr + total) ;
total += readcount ;
if (readcount < bufferlen)
break ;
len -= readcount ;
} ;
return total ;
} /* replace_read_f2d */
static sf_count_t
replace_write_s2f (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
{ int bufferlen, writecount ;
sf_count_t total = 0 ;
float scale ;
scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / 0x8000 ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
s2f_array (ptr + total, psf->u.fbuf, bufferlen, scale) ;
if (psf->peak_info)
float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ;
f2bf_array (psf->u.fbuf, bufferlen) ;
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
writecount = psf_fwrite (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
total += writecount ;
if (writecount < bufferlen)
break ;
len -= writecount ;
} ;
return total ;
} /* replace_write_s2f */
static sf_count_t
replace_write_i2f (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
{ int bufferlen, writecount ;
sf_count_t total = 0 ;
float scale ;
scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / (8.0 * 0x10000000) ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
i2f_array (ptr + total, psf->u.fbuf, bufferlen, scale) ;
if (psf->peak_info)
float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ;
f2bf_array (psf->u.fbuf, bufferlen) ;
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
writecount = psf_fwrite (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
total += writecount ;
if (writecount < bufferlen)
break ;
len -= writecount ;
} ;
return total ;
} /* replace_write_i2f */
static sf_count_t
replace_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
{ int bufferlen, writecount ;
sf_count_t total = 0 ;
/* FIX THIS */
if (psf->peak_info)
float32_peak_update (psf, ptr, len, 0) ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
memcpy (psf->u.fbuf, ptr + total, bufferlen * sizeof (float)) ;
f2bf_array (psf->u.fbuf, bufferlen) ;
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
writecount = psf_fwrite (psf->u.fbuf, sizeof (float) , bufferlen, psf) ;
total += writecount ;
if (writecount < bufferlen)
break ;
len -= writecount ;
} ;
return total ;
} /* replace_write_f */
static sf_count_t
replace_write_d2f (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
{ int bufferlen, writecount ;
sf_count_t total = 0 ;
bufferlen = ARRAY_LEN (psf->u.fbuf) ;
while (len > 0)
{ if (len < bufferlen)
bufferlen = (int) len ;
d2f_array (ptr + total, psf->u.fbuf, bufferlen) ;
if (psf->peak_info)
float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ;
f2bf_array (psf->u.fbuf, bufferlen) ;
if (psf->data_endswap == SF_TRUE)
endswap_int_array (psf->u.ibuf, bufferlen) ;
writecount = psf_fwrite (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
total += writecount ;
if (writecount < bufferlen)
break ;
len -= writecount ;
} ;
return total ;
} /* replace_write_d2f */
/*----------------------------------------------------------------------------------------------
*/
static void
bf2f_array (float *buffer, int count)
{ while (--count >= 0)
{ buffer [count] = FLOAT32_READ ((unsigned char *) (buffer + count)) ;
} ;
} /* bf2f_array */
static void
f2bf_array (float *buffer, int count)
{ while (--count >= 0)
{ FLOAT32_WRITE (buffer [count], (unsigned char*) (buffer + count)) ;
} ;
} /* f2bf_array */

View File

@@ -0,0 +1,604 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#include "G72x/g72x.h"
/* This struct is private to the G72x code. */
struct g72x_state ;
typedef struct g72x_state G72x_STATE ;
typedef struct
{ /* Private data. Don't mess with it. */
struct g72x_state * private ;
/* Public data. Read only. */
int blocksize, samplesperblock, bytesperblock ;
/* Public data. Read and write. */
int blocks_total, block_curr, sample_curr ;
unsigned char block [G72x_BLOCK_SIZE] ;
short samples [G72x_BLOCK_SIZE] ;
} G72x_PRIVATE ;
static int psf_g72x_decode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x) ;
static int psf_g72x_encode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x) ;
static sf_count_t g72x_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
static sf_count_t g72x_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
static sf_count_t g72x_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
static sf_count_t g72x_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
static sf_count_t g72x_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
static sf_count_t g72x_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
static sf_count_t g72x_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
static sf_count_t g72x_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
static sf_count_t g72x_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
static int g72x_close (SF_PRIVATE *psf) ;
/*============================================================================================
** WAV G721 Reader initialisation function.
*/
int
g72x_init (SF_PRIVATE * psf)
{ G72x_PRIVATE *pg72x ;
int bitspersample, bytesperblock, codec ;
if (psf->codec_data != NULL)
{ psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ;
return SFE_INTERNAL ;
} ;
psf->sf.seekable = SF_FALSE ;
if (psf->sf.channels != 1)
return SFE_G72X_NOT_MONO ;
if ((pg72x = calloc (1, sizeof (G72x_PRIVATE))) == NULL)
return SFE_MALLOC_FAILED ;
psf->codec_data = (void*) pg72x ;
pg72x->block_curr = 0 ;
pg72x->sample_curr = 0 ;
switch (SF_CODEC (psf->sf.format))
{ case SF_FORMAT_G721_32 :
codec = G721_32_BITS_PER_SAMPLE ;
bytesperblock = G721_32_BYTES_PER_BLOCK ;
bitspersample = G721_32_BITS_PER_SAMPLE ;
break ;
case SF_FORMAT_G723_24:
codec = G723_24_BITS_PER_SAMPLE ;
bytesperblock = G723_24_BYTES_PER_BLOCK ;
bitspersample = G723_24_BITS_PER_SAMPLE ;
break ;
case SF_FORMAT_G723_40:
codec = G723_40_BITS_PER_SAMPLE ;
bytesperblock = G723_40_BYTES_PER_BLOCK ;
bitspersample = G723_40_BITS_PER_SAMPLE ;
break ;
default : return SFE_UNIMPLEMENTED ;
} ;
psf->blockwidth = psf->bytewidth = 1 ;
psf->filelength = psf_get_filelen (psf) ;
if (psf->filelength < psf->dataoffset)
psf->filelength = psf->dataoffset ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf->dataend > 0)
psf->datalength -= psf->filelength - psf->dataend ;
if (psf->file.mode == SFM_READ)
{ pg72x->private = g72x_reader_init (codec, &(pg72x->blocksize), &(pg72x->samplesperblock)) ;
if (pg72x->private == NULL)
return SFE_MALLOC_FAILED ;
pg72x->bytesperblock = bytesperblock ;
psf->read_short = g72x_read_s ;
psf->read_int = g72x_read_i ;
psf->read_float = g72x_read_f ;
psf->read_double = g72x_read_d ;
psf->seek = g72x_seek ;
if (psf->datalength % pg72x->blocksize)
{ psf_log_printf (psf, "*** Odd psf->datalength (%D) should be a multiple of %d\n", psf->datalength, pg72x->blocksize) ;
pg72x->blocks_total = (psf->datalength / pg72x->blocksize) + 1 ;
}
else
pg72x->blocks_total = psf->datalength / pg72x->blocksize ;
psf->sf.frames = pg72x->blocks_total * pg72x->samplesperblock ;
psf_g72x_decode_block (psf, pg72x) ;
}
else if (psf->file.mode == SFM_WRITE)
{ pg72x->private = g72x_writer_init (codec, &(pg72x->blocksize), &(pg72x->samplesperblock)) ;
if (pg72x->private == NULL)
return SFE_MALLOC_FAILED ;
pg72x->bytesperblock = bytesperblock ;
psf->write_short = g72x_write_s ;
psf->write_int = g72x_write_i ;
psf->write_float = g72x_write_f ;
psf->write_double = g72x_write_d ;
if (psf->datalength % pg72x->blocksize)
pg72x->blocks_total = (psf->datalength / pg72x->blocksize) + 1 ;
else
pg72x->blocks_total = psf->datalength / pg72x->blocksize ;
if (psf->datalength > 0)
psf->sf.frames = (8 * psf->datalength) / bitspersample ;
if ((psf->sf.frames * bitspersample) / 8 != psf->datalength)
psf_log_printf (psf, "*** Warning : weird psf->datalength.\n") ;
} ;
psf->codec_close = g72x_close ;
return 0 ;
} /* g72x_init */
/*============================================================================================
** G721 Read Functions.
*/
static int
psf_g72x_decode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x)
{ int k ;
pg72x->block_curr ++ ;
pg72x->sample_curr = 0 ;
if (pg72x->block_curr > pg72x->blocks_total)
{ memset (pg72x->samples, 0, G72x_BLOCK_SIZE * sizeof (short)) ;
return 1 ;
} ;
if ((k = psf_fread (pg72x->block, 1, pg72x->bytesperblock, psf)) != pg72x->bytesperblock)
psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pg72x->bytesperblock) ;
pg72x->blocksize = k ;
g72x_decode_block (pg72x->private, pg72x->block, pg72x->samples) ;
return 1 ;
} /* psf_g72x_decode_block */
static int
g72x_read_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x, short *ptr, int len)
{ int count, total = 0, indx = 0 ;
while (indx < len)
{ if (pg72x->block_curr > pg72x->blocks_total)
{ memset (&(ptr [indx]), 0, (len - indx) * sizeof (short)) ;
return total ;
} ;
if (pg72x->sample_curr >= pg72x->samplesperblock)
psf_g72x_decode_block (psf, pg72x) ;
count = pg72x->samplesperblock - pg72x->sample_curr ;
count = (len - indx > count) ? count : len - indx ;
memcpy (&(ptr [indx]), &(pg72x->samples [pg72x->sample_curr]), count * sizeof (short)) ;
indx += count ;
pg72x->sample_curr += count ;
total = indx ;
} ;
return total ;
} /* g72x_read_block */
static sf_count_t
g72x_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
{ G72x_PRIVATE *pg72x ;
int readcount, count ;
sf_count_t total = 0 ;
if (psf->codec_data == NULL)
return 0 ;
pg72x = (G72x_PRIVATE*) psf->codec_data ;
while (len > 0)
{ readcount = (len > 0x10000000) ? 0x10000000 : (int) len ;
count = g72x_read_block (psf, pg72x, ptr, readcount) ;
total += count ;
len -= count ;
if (count != readcount)
break ;
} ;
return total ;
} /* g72x_read_s */
static sf_count_t
g72x_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
{ G72x_PRIVATE *pg72x ;
short *sptr ;
int k, bufferlen, readcount = 0, count ;
sf_count_t total = 0 ;
if (psf->codec_data == NULL)
return 0 ;
pg72x = (G72x_PRIVATE*) psf->codec_data ;
sptr = psf->u.sbuf ;
bufferlen = SF_BUFFER_LEN / sizeof (short) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = g72x_read_block (psf, pg72x, sptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = sptr [k] << 16 ;
total += count ;
len -= readcount ;
if (count != readcount)
break ;
} ;
return total ;
} /* g72x_read_i */
static sf_count_t
g72x_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
{ G72x_PRIVATE *pg72x ;
short *sptr ;
int k, bufferlen, readcount = 0, count ;
sf_count_t total = 0 ;
float normfact ;
if (psf->codec_data == NULL)
return 0 ;
pg72x = (G72x_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ;
sptr = psf->u.sbuf ;
bufferlen = SF_BUFFER_LEN / sizeof (short) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = g72x_read_block (psf, pg72x, sptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = normfact * sptr [k] ;
total += count ;
len -= readcount ;
if (count != readcount)
break ;
} ;
return total ;
} /* g72x_read_f */
static sf_count_t
g72x_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
{ G72x_PRIVATE *pg72x ;
short *sptr ;
int k, bufferlen, readcount = 0, count ;
sf_count_t total = 0 ;
double normfact ;
if (psf->codec_data == NULL)
return 0 ;
pg72x = (G72x_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ;
sptr = psf->u.sbuf ;
bufferlen = SF_BUFFER_LEN / sizeof (short) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = g72x_read_block (psf, pg72x, sptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = normfact * (double) (sptr [k]) ;
total += count ;
len -= readcount ;
if (count != readcount)
break ;
} ;
return total ;
} /* g72x_read_d */
static sf_count_t
g72x_seek (SF_PRIVATE *psf, int UNUSED (mode), sf_count_t UNUSED (offset))
{
psf_log_printf (psf, "seek unsupported\n") ;
/* No simple solution. To do properly, would need to seek
** to start of file and decode everything up to seek position.
** Maybe implement SEEK_SET to 0 only?
*/
return 0 ;
/*
** G72x_PRIVATE *pg72x ;
** int newblock, newsample, sample_curr ;
**
** if (psf->codec_data == NULL)
** return 0 ;
** pg72x = (G72x_PRIVATE*) psf->codec_data ;
**
** if (! (psf->datalength && psf->dataoffset))
** { psf->error = SFE_BAD_SEEK ;
** return PSF_SEEK_ERROR ;
** } ;
**
** sample_curr = (8 * psf->datalength) / G721_32_BITS_PER_SAMPLE ;
**
** switch (whence)
** { case SEEK_SET :
** if (offset < 0 || offset > sample_curr)
** { psf->error = SFE_BAD_SEEK ;
** return PSF_SEEK_ERROR ;
** } ;
** newblock = offset / pg72x->samplesperblock ;
** newsample = offset % pg72x->samplesperblock ;
** break ;
**
** case SEEK_CUR :
** if (psf->current + offset < 0 || psf->current + offset > sample_curr)
** { psf->error = SFE_BAD_SEEK ;
** return PSF_SEEK_ERROR ;
** } ;
** newblock = (8 * (psf->current + offset)) / pg72x->samplesperblock ;
** newsample = (8 * (psf->current + offset)) % pg72x->samplesperblock ;
** break ;
**
** case SEEK_END :
** if (offset > 0 || sample_curr + offset < 0)
** { psf->error = SFE_BAD_SEEK ;
** return PSF_SEEK_ERROR ;
** } ;
** newblock = (sample_curr + offset) / pg72x->samplesperblock ;
** newsample = (sample_curr + offset) % pg72x->samplesperblock ;
** break ;
**
** default :
** psf->error = SFE_BAD_SEEK ;
** return PSF_SEEK_ERROR ;
** } ;
**
** if (psf->file.mode == SFM_READ)
** { psf_fseek (psf, psf->dataoffset + newblock * pg72x->blocksize, SEEK_SET) ;
** pg72x->block_curr = newblock ;
** psf_g72x_decode_block (psf, pg72x) ;
** pg72x->sample_curr = newsample ;
** }
** else
** { /+* What to do about write??? *+/
** psf->error = SFE_BAD_SEEK ;
** return PSF_SEEK_ERROR ;
** } ;
**
** psf->current = newblock * pg72x->samplesperblock + newsample ;
** return psf->current ;
**
*/
} /* g72x_seek */
/*==========================================================================================
** G72x Write Functions.
*/
static int
psf_g72x_encode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x)
{ int k ;
/* Encode the samples. */
g72x_encode_block (pg72x->private, pg72x->samples, pg72x->block) ;
/* Write the block to disk. */
if ((k = psf_fwrite (pg72x->block, 1, pg72x->blocksize, psf)) != pg72x->blocksize)
psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pg72x->blocksize) ;
pg72x->sample_curr = 0 ;
pg72x->block_curr ++ ;
/* Set samples to zero for next block. */
memset (pg72x->samples, 0, G72x_BLOCK_SIZE * sizeof (short)) ;
return 1 ;
} /* psf_g72x_encode_block */
static int
g72x_write_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x, const short *ptr, int len)
{ int count, total = 0, indx = 0 ;
while (indx < len)
{ count = pg72x->samplesperblock - pg72x->sample_curr ;
if (count > len - indx)
count = len - indx ;
memcpy (&(pg72x->samples [pg72x->sample_curr]), &(ptr [indx]), count * sizeof (short)) ;
indx += count ;
pg72x->sample_curr += count ;
total = indx ;
if (pg72x->sample_curr >= pg72x->samplesperblock)
psf_g72x_encode_block (psf, pg72x) ;
} ;
return total ;
} /* g72x_write_block */
static sf_count_t
g72x_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
{ G72x_PRIVATE *pg72x ;
int writecount, count ;
sf_count_t total = 0 ;
if (psf->codec_data == NULL)
return 0 ;
pg72x = (G72x_PRIVATE*) psf->codec_data ;
while (len > 0)
{ writecount = (len > 0x10000000) ? 0x10000000 : (int) len ;
count = g72x_write_block (psf, pg72x, ptr, writecount) ;
total += count ;
len -= count ;
if (count != writecount)
break ;
} ;
return total ;
} /* g72x_write_s */
static sf_count_t
g72x_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
{ G72x_PRIVATE *pg72x ;
short *sptr ;
int k, bufferlen, writecount = 0, count ;
sf_count_t total = 0 ;
if (psf->codec_data == NULL)
return 0 ;
pg72x = (G72x_PRIVATE*) psf->codec_data ;
sptr = psf->u.sbuf ;
bufferlen = ((SF_BUFFER_LEN / psf->blockwidth) * psf->blockwidth) / sizeof (short) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
sptr [k] = ptr [total + k] >> 16 ;
count = g72x_write_block (psf, pg72x, sptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* g72x_write_i */
static sf_count_t
g72x_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
{ G72x_PRIVATE *pg72x ;
short *sptr ;
int k, bufferlen, writecount = 0, count ;
sf_count_t total = 0 ;
float normfact ;
if (psf->codec_data == NULL)
return 0 ;
pg72x = (G72x_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x8000) : 1.0 ;
sptr = psf->u.sbuf ;
bufferlen = ((SF_BUFFER_LEN / psf->blockwidth) * psf->blockwidth) / sizeof (short) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
sptr [k] = lrintf (normfact * ptr [total + k]) ;
count = g72x_write_block (psf, pg72x, sptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* g72x_write_f */
static sf_count_t
g72x_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
{ G72x_PRIVATE *pg72x ;
short *sptr ;
int k, bufferlen, writecount = 0, count ;
sf_count_t total = 0 ;
double normfact ;
if (psf->codec_data == NULL)
return 0 ;
pg72x = (G72x_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x8000) : 1.0 ;
sptr = psf->u.sbuf ;
bufferlen = ((SF_BUFFER_LEN / psf->blockwidth) * psf->blockwidth) / sizeof (short) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
sptr [k] = lrint (normfact * ptr [total + k]) ;
count = g72x_write_block (psf, pg72x, sptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* g72x_write_d */
static int
g72x_close (SF_PRIVATE *psf)
{ G72x_PRIVATE *pg72x ;
pg72x = (G72x_PRIVATE*) psf->codec_data ;
if (psf->file.mode == SFM_WRITE)
{ /* If a block has been partially assembled, write it out
** as the final block.
*/
if (pg72x->sample_curr && pg72x->sample_curr < G72x_BLOCK_SIZE)
psf_g72x_encode_block (psf, pg72x) ;
if (psf->write_header)
psf->write_header (psf, SF_FALSE) ;
} ;
/* Only free the pointer allocated by g72x_(reader|writer)_init. */
free (pg72x->private) ;
return 0 ;
} /* g72x_close */

View File

@@ -0,0 +1,621 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#include "wav_w64.h"
#include "GSM610/gsm.h"
#define GSM610_BLOCKSIZE 33
#define GSM610_SAMPLES 160
typedef struct gsm610_tag
{ int blocks ;
int blockcount, samplecount ;
int samplesperblock, blocksize ;
int (*decode_block) (SF_PRIVATE *psf, struct gsm610_tag *pgsm610) ;
int (*encode_block) (SF_PRIVATE *psf, struct gsm610_tag *pgsm610) ;
short samples [WAV_W64_GSM610_SAMPLES] ;
unsigned char block [WAV_W64_GSM610_BLOCKSIZE] ;
/* Damn I hate typedef-ed pointers; yes, gsm is a pointer type. */
gsm gsm_data ;
} GSM610_PRIVATE ;
static sf_count_t gsm610_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
static sf_count_t gsm610_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
static sf_count_t gsm610_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
static sf_count_t gsm610_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
static sf_count_t gsm610_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
static sf_count_t gsm610_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
static sf_count_t gsm610_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
static sf_count_t gsm610_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
static int gsm610_read_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, short *ptr, int len) ;
static int gsm610_write_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, const short *ptr, int len) ;
static int gsm610_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ;
static int gsm610_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ;
static int gsm610_wav_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ;
static int gsm610_wav_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ;
static sf_count_t gsm610_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
static int gsm610_close (SF_PRIVATE *psf) ;
/*============================================================================================
** WAV GSM610 initialisation function.
*/
int
gsm610_init (SF_PRIVATE *psf)
{ GSM610_PRIVATE *pgsm610 ;
int true_flag = 1 ;
if (psf->codec_data != NULL)
{ psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ;
return SFE_INTERNAL ;
} ;
if (psf->file.mode == SFM_RDWR)
return SFE_BAD_MODE_RW ;
psf->sf.seekable = SF_FALSE ;
if ((pgsm610 = calloc (1, sizeof (GSM610_PRIVATE))) == NULL)
return SFE_MALLOC_FAILED ;
psf->codec_data = pgsm610 ;
memset (pgsm610, 0, sizeof (GSM610_PRIVATE)) ;
/*============================================================
Need separate gsm_data structs for encode and decode.
============================================================*/
if ((pgsm610->gsm_data = gsm_create ()) == NULL)
return SFE_MALLOC_FAILED ;
switch (SF_CONTAINER (psf->sf.format))
{ case SF_FORMAT_WAV :
case SF_FORMAT_WAVEX :
case SF_FORMAT_W64 :
gsm_option (pgsm610->gsm_data, GSM_OPT_WAV49, &true_flag) ;
pgsm610->encode_block = gsm610_wav_encode_block ;
pgsm610->decode_block = gsm610_wav_decode_block ;
pgsm610->samplesperblock = WAV_W64_GSM610_SAMPLES ;
pgsm610->blocksize = WAV_W64_GSM610_BLOCKSIZE ;
break ;
case SF_FORMAT_AIFF :
case SF_FORMAT_RAW :
pgsm610->encode_block = gsm610_encode_block ;
pgsm610->decode_block = gsm610_decode_block ;
pgsm610->samplesperblock = GSM610_SAMPLES ;
pgsm610->blocksize = GSM610_BLOCKSIZE ;
break ;
default :
return SFE_INTERNAL ;
break ;
} ;
if (psf->file.mode == SFM_READ)
{ if (psf->datalength % pgsm610->blocksize == 0)
pgsm610->blocks = psf->datalength / pgsm610->blocksize ;
else if (psf->datalength % pgsm610->blocksize == 1 && pgsm610->blocksize == GSM610_BLOCKSIZE)
{ /*
** Weird AIFF specific case.
** AIFF chunks must be at an even offset from the start of file and
** GSM610_BLOCKSIZE is odd which can result in an odd length SSND
** chunk. The SSND chunk then gets padded on write which means that
** when it is read the datalength is too big by 1.
*/
pgsm610->blocks = psf->datalength / pgsm610->blocksize ;
}
else
{ psf_log_printf (psf, "*** Warning : data chunk seems to be truncated.\n") ;
pgsm610->blocks = psf->datalength / pgsm610->blocksize + 1 ;
} ;
psf->sf.frames = pgsm610->samplesperblock * pgsm610->blocks ;
psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
pgsm610->decode_block (psf, pgsm610) ; /* Read first block. */
psf->read_short = gsm610_read_s ;
psf->read_int = gsm610_read_i ;
psf->read_float = gsm610_read_f ;
psf->read_double = gsm610_read_d ;
} ;
if (psf->file.mode == SFM_WRITE)
{ pgsm610->blockcount = 0 ;
pgsm610->samplecount = 0 ;
psf->write_short = gsm610_write_s ;
psf->write_int = gsm610_write_i ;
psf->write_float = gsm610_write_f ;
psf->write_double = gsm610_write_d ;
} ;
psf->codec_close = gsm610_close ;
psf->seek = gsm610_seek ;
psf->filelength = psf_get_filelen (psf) ;
psf->datalength = psf->filelength - psf->dataoffset ;
return 0 ;
} /* gsm610_init */
/*============================================================================================
** GSM 6.10 Read Functions.
*/
static int
gsm610_wav_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610)
{ int k ;
pgsm610->blockcount ++ ;
pgsm610->samplecount = 0 ;
if (pgsm610->blockcount > pgsm610->blocks)
{ memset (pgsm610->samples, 0, WAV_W64_GSM610_SAMPLES * sizeof (short)) ;
return 1 ;
} ;
if ((k = psf_fread (pgsm610->block, 1, WAV_W64_GSM610_BLOCKSIZE, psf)) != WAV_W64_GSM610_BLOCKSIZE)
psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, WAV_W64_GSM610_BLOCKSIZE) ;
if (gsm_decode (pgsm610->gsm_data, pgsm610->block, pgsm610->samples) < 0)
{ psf_log_printf (psf, "Error from WAV gsm_decode() on frame : %d\n", pgsm610->blockcount) ;
return 0 ;
} ;
if (gsm_decode (pgsm610->gsm_data, pgsm610->block + (WAV_W64_GSM610_BLOCKSIZE + 1) / 2, pgsm610->samples + WAV_W64_GSM610_SAMPLES / 2) < 0)
{ psf_log_printf (psf, "Error from WAV gsm_decode() on frame : %d.5\n", pgsm610->blockcount) ;
return 0 ;
} ;
return 1 ;
} /* gsm610_wav_decode_block */
static int
gsm610_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610)
{ int k ;
pgsm610->blockcount ++ ;
pgsm610->samplecount = 0 ;
if (pgsm610->blockcount > pgsm610->blocks)
{ memset (pgsm610->samples, 0, GSM610_SAMPLES * sizeof (short)) ;
return 1 ;
} ;
if ((k = psf_fread (pgsm610->block, 1, GSM610_BLOCKSIZE, psf)) != GSM610_BLOCKSIZE)
psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, GSM610_BLOCKSIZE) ;
if (gsm_decode (pgsm610->gsm_data, pgsm610->block, pgsm610->samples) < 0)
{ psf_log_printf (psf, "Error from standard gsm_decode() on frame : %d\n", pgsm610->blockcount) ;
return 0 ;
} ;
return 1 ;
} /* gsm610_decode_block */
static int
gsm610_read_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, short *ptr, int len)
{ int count, total = 0, indx = 0 ;
while (indx < len)
{ if (pgsm610->blockcount >= pgsm610->blocks && pgsm610->samplecount >= pgsm610->samplesperblock)
{ memset (&(ptr [indx]), 0, (len - indx) * sizeof (short)) ;
return total ;
} ;
if (pgsm610->samplecount >= pgsm610->samplesperblock)
pgsm610->decode_block (psf, pgsm610) ;
count = pgsm610->samplesperblock - pgsm610->samplecount ;
count = (len - indx > count) ? count : len - indx ;
memcpy (&(ptr [indx]), &(pgsm610->samples [pgsm610->samplecount]), count * sizeof (short)) ;
indx += count ;
pgsm610->samplecount += count ;
total = indx ;
} ;
return total ;
} /* gsm610_read_block */
static sf_count_t
gsm610_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
{ GSM610_PRIVATE *pgsm610 ;
int readcount, count ;
sf_count_t total = 0 ;
if (psf->codec_data == NULL)
return 0 ;
pgsm610 = (GSM610_PRIVATE*) psf->codec_data ;
while (len > 0)
{ readcount = (len > 0x10000000) ? 0x1000000 : (int) len ;
count = gsm610_read_block (psf, pgsm610, ptr, readcount) ;
total += count ;
len -= count ;
if (count != readcount)
break ;
} ;
return total ;
} /* gsm610_read_s */
static sf_count_t
gsm610_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
{ GSM610_PRIVATE *pgsm610 ;
short *sptr ;
int k, bufferlen, readcount = 0, count ;
sf_count_t total = 0 ;
if (psf->codec_data == NULL)
return 0 ;
pgsm610 = (GSM610_PRIVATE*) psf->codec_data ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = gsm610_read_block (psf, pgsm610, sptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = sptr [k] << 16 ;
total += count ;
len -= readcount ;
} ;
return total ;
} /* gsm610_read_i */
static sf_count_t
gsm610_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
{ GSM610_PRIVATE *pgsm610 ;
short *sptr ;
int k, bufferlen, readcount = 0, count ;
sf_count_t total = 0 ;
float normfact ;
if (psf->codec_data == NULL)
return 0 ;
pgsm610 = (GSM610_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = gsm610_read_block (psf, pgsm610, sptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = normfact * sptr [k] ;
total += count ;
len -= readcount ;
} ;
return total ;
} /* gsm610_read_f */
static sf_count_t
gsm610_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
{ GSM610_PRIVATE *pgsm610 ;
short *sptr ;
int k, bufferlen, readcount = 0, count ;
sf_count_t total = 0 ;
double normfact ;
normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ;
if (psf->codec_data == NULL)
return 0 ;
pgsm610 = (GSM610_PRIVATE*) psf->codec_data ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = gsm610_read_block (psf, pgsm610, sptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = normfact * sptr [k] ;
total += count ;
len -= readcount ;
} ;
return total ;
} /* gsm610_read_d */
static sf_count_t
gsm610_seek (SF_PRIVATE *psf, int UNUSED (mode), sf_count_t offset)
{ GSM610_PRIVATE *pgsm610 ;
int newblock, newsample ;
if (psf->codec_data == NULL)
return 0 ;
pgsm610 = (GSM610_PRIVATE*) psf->codec_data ;
if (psf->dataoffset < 0)
{ psf->error = SFE_BAD_SEEK ;
return PSF_SEEK_ERROR ;
} ;
if (offset == 0)
{ int true_flag = 1 ;
psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
pgsm610->blockcount = 0 ;
gsm_init (pgsm610->gsm_data) ;
if ((SF_CONTAINER (psf->sf.format)) == SF_FORMAT_WAV ||
(SF_CONTAINER (psf->sf.format)) == SF_FORMAT_W64)
gsm_option (pgsm610->gsm_data, GSM_OPT_WAV49, &true_flag) ;
pgsm610->decode_block (psf, pgsm610) ;
pgsm610->samplecount = 0 ;
return 0 ;
} ;
if (offset < 0 || offset > pgsm610->blocks * pgsm610->samplesperblock)
{ psf->error = SFE_BAD_SEEK ;
return PSF_SEEK_ERROR ;
} ;
newblock = offset / pgsm610->samplesperblock ;
newsample = offset % pgsm610->samplesperblock ;
if (psf->file.mode == SFM_READ)
{ if (psf->read_current != newblock * pgsm610->samplesperblock + newsample)
{ psf_fseek (psf, psf->dataoffset + newblock * pgsm610->samplesperblock, SEEK_SET) ;
pgsm610->blockcount = newblock ;
pgsm610->decode_block (psf, pgsm610) ;
pgsm610->samplecount = newsample ;
} ;
return newblock * pgsm610->samplesperblock + newsample ;
} ;
/* What to do about write??? */
psf->error = SFE_BAD_SEEK ;
return PSF_SEEK_ERROR ;
} /* gsm610_seek */
/*==========================================================================================
** GSM 6.10 Write Functions.
*/
static int
gsm610_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610)
{ int k ;
/* Encode the samples. */
gsm_encode (pgsm610->gsm_data, pgsm610->samples, pgsm610->block) ;
/* Write the block to disk. */
if ((k = psf_fwrite (pgsm610->block, 1, GSM610_BLOCKSIZE, psf)) != GSM610_BLOCKSIZE)
psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, GSM610_BLOCKSIZE) ;
pgsm610->samplecount = 0 ;
pgsm610->blockcount ++ ;
/* Set samples to zero for next block. */
memset (pgsm610->samples, 0, WAV_W64_GSM610_SAMPLES * sizeof (short)) ;
return 1 ;
} /* gsm610_encode_block */
static int
gsm610_wav_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610)
{ int k ;
/* Encode the samples. */
gsm_encode (pgsm610->gsm_data, pgsm610->samples, pgsm610->block) ;
gsm_encode (pgsm610->gsm_data, pgsm610->samples+WAV_W64_GSM610_SAMPLES/2, pgsm610->block+WAV_W64_GSM610_BLOCKSIZE/2) ;
/* Write the block to disk. */
if ((k = psf_fwrite (pgsm610->block, 1, WAV_W64_GSM610_BLOCKSIZE, psf)) != WAV_W64_GSM610_BLOCKSIZE)
psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, WAV_W64_GSM610_BLOCKSIZE) ;
pgsm610->samplecount = 0 ;
pgsm610->blockcount ++ ;
/* Set samples to zero for next block. */
memset (pgsm610->samples, 0, WAV_W64_GSM610_SAMPLES * sizeof (short)) ;
return 1 ;
} /* gsm610_wav_encode_block */
static int
gsm610_write_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, const short *ptr, int len)
{ int count, total = 0, indx = 0 ;
while (indx < len)
{ count = pgsm610->samplesperblock - pgsm610->samplecount ;
if (count > len - indx)
count = len - indx ;
memcpy (&(pgsm610->samples [pgsm610->samplecount]), &(ptr [indx]), count * sizeof (short)) ;
indx += count ;
pgsm610->samplecount += count ;
total = indx ;
if (pgsm610->samplecount >= pgsm610->samplesperblock)
pgsm610->encode_block (psf, pgsm610) ;
} ;
return total ;
} /* gsm610_write_block */
static sf_count_t
gsm610_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
{ GSM610_PRIVATE *pgsm610 ;
int writecount, count ;
sf_count_t total = 0 ;
if (psf->codec_data == NULL)
return 0 ;
pgsm610 = (GSM610_PRIVATE*) psf->codec_data ;
while (len > 0)
{ writecount = (len > 0x10000000) ? 0x10000000 : (int) len ;
count = gsm610_write_block (psf, pgsm610, ptr, writecount) ;
total += count ;
len -= count ;
if (count != writecount)
break ;
} ;
return total ;
} /* gsm610_write_s */
static sf_count_t
gsm610_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
{ GSM610_PRIVATE *pgsm610 ;
short *sptr ;
int k, bufferlen, writecount = 0, count ;
sf_count_t total = 0 ;
if (psf->codec_data == NULL)
return 0 ;
pgsm610 = (GSM610_PRIVATE*) psf->codec_data ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
sptr [k] = ptr [total + k] >> 16 ;
count = gsm610_write_block (psf, pgsm610, sptr, writecount) ;
total += count ;
len -= writecount ;
} ;
return total ;
} /* gsm610_write_i */
static sf_count_t
gsm610_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
{ GSM610_PRIVATE *pgsm610 ;
short *sptr ;
int k, bufferlen, writecount = 0, count ;
sf_count_t total = 0 ;
float normfact ;
if (psf->codec_data == NULL)
return 0 ;
pgsm610 = (GSM610_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
sptr [k] = lrintf (normfact * ptr [total + k]) ;
count = gsm610_write_block (psf, pgsm610, sptr, writecount) ;
total += count ;
len -= writecount ;
} ;
return total ;
} /* gsm610_write_f */
static sf_count_t
gsm610_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
{ GSM610_PRIVATE *pgsm610 ;
short *sptr ;
int k, bufferlen, writecount = 0, count ;
sf_count_t total = 0 ;
double normfact ;
if (psf->codec_data == NULL)
return 0 ;
pgsm610 = (GSM610_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
sptr [k] = lrint (normfact * ptr [total + k]) ;
count = gsm610_write_block (psf, pgsm610, sptr, writecount) ;
total += count ;
len -= writecount ;
} ;
return total ;
} /* gsm610_write_d */
static int
gsm610_close (SF_PRIVATE *psf)
{ GSM610_PRIVATE *pgsm610 ;
if (psf->codec_data == NULL)
return 0 ;
pgsm610 = (GSM610_PRIVATE*) psf->codec_data ;
if (psf->file.mode == SFM_WRITE)
{ /* If a block has been partially assembled, write it out
** as the final block.
*/
if (pgsm610->samplecount && pgsm610->samplecount < pgsm610->samplesperblock)
pgsm610->encode_block (psf, pgsm610) ;
} ;
if (pgsm610->gsm_data)
gsm_destroy (pgsm610->gsm_data) ;
return 0 ;
} /* gsm610_close */

View File

@@ -0,0 +1,226 @@
/*
** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
/*------------------------------------------------------------------------------
** Macros to handle big/little endian issues.
*/
#define SFE_HTK_BAD_FILE_LEN 1666
#define SFE_HTK_NOT_WAVEFORM 1667
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int htk_close (SF_PRIVATE *psf) ;
static int htk_write_header (SF_PRIVATE *psf, int calc_length) ;
static int htk_read_header (SF_PRIVATE *psf) ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
htk_open (SF_PRIVATE *psf)
{ int subformat ;
int error = 0 ;
if (psf->is_pipe)
return SFE_HTK_NO_PIPE ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = htk_read_header (psf)))
return error ;
} ;
subformat = SF_CODEC (psf->sf.format) ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_HTK)
return SFE_BAD_OPEN_FORMAT ;
psf->endian = SF_ENDIAN_BIG ;
if (htk_write_header (psf, SF_FALSE))
return psf->error ;
psf->write_header = htk_write_header ;
} ;
psf->container_close = htk_close ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
switch (subformat)
{ case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */
error = pcm_init (psf) ;
break ;
default : break ;
} ;
return error ;
} /* htk_open */
/*------------------------------------------------------------------------------
*/
static int
htk_close (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
htk_write_header (psf, SF_TRUE) ;
return 0 ;
} /* htk_close */
static int
htk_write_header (SF_PRIVATE *psf, int calc_length)
{ sf_count_t current ;
int sample_count, sample_period ;
current = psf_ftell (psf) ;
if (calc_length)
psf->filelength = psf_get_filelen (psf) ;
/* Reset the current header length to zero. */
psf->header [0] = 0 ;
psf->headindex = 0 ;
psf_fseek (psf, 0, SEEK_SET) ;
if (psf->filelength > 12)
sample_count = (psf->filelength - 12) / 2 ;
else
sample_count = 0 ;
sample_period = 10000000 / psf->sf.samplerate ;
psf_binheader_writef (psf, "E444", sample_count, sample_period, 0x20000) ;
/* Header construction complete so write it out. */
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
if (psf->error)
return psf->error ;
psf->dataoffset = psf->headindex ;
if (current > 0)
psf_fseek (psf, current, SEEK_SET) ;
return psf->error ;
} /* htk_write_header */
/*
** Found the following info in a comment block within Bill Schottstaedt's
** sndlib library.
**
** HTK format files consist of a contiguous sequence of samples preceded by a
** header. Each sample is a vector of either 2-byte integers or 4-byte floats.
** 2-byte integers are used for compressed forms as described below and for
** vector quantised data as described later in section 5.11. HTK format data
** files can also be used to store speech waveforms as described in section 5.8.
**
** The HTK file format header is 12 bytes long and contains the following data
** nSamples -- number of samples in file (4-byte integer)
** sampPeriod -- sample period in 100ns units (4-byte integer)
** sampSize -- number of bytes per sample (2-byte integer)
** parmKind -- a code indicating the sample kind (2-byte integer)
**
** The parameter kind consists of a 6 bit code representing the basic
** parameter kind plus additional bits for each of the possible qualifiers.
** The basic parameter kind codes are
**
** 0 WAVEFORM sampled waveform
** 1 LPC linear prediction filter coefficients
** 2 LPREFC linear prediction reflection coefficients
** 3 LPCEPSTRA LPC cepstral coefficients
** 4 LPDELCEP LPC cepstra plus delta coefficients
** 5 IREFC LPC reflection coef in 16 bit integer format
** 6 MFCC mel-frequency cepstral coefficients
** 7 FBANK log mel-filter bank channel outputs
** 8 MELSPEC linear mel-filter bank channel outputs
** 9 USER user defined sample kind
** 10 DISCRETE vector quantised data
**
** and the bit-encoding for the qualifiers (in octal) is
** _E 000100 has energy
** _N 000200 absolute energy suppressed
** _D 000400 has delta coefficients
** _A 001000 has acceleration coefficients
** _C 002000 is compressed
** _Z 004000 has zero mean static coef.
** _K 010000 has CRC checksum
** _O 020000 has 0'th cepstral coef.
*/
static int
htk_read_header (SF_PRIVATE *psf)
{ int sample_count, sample_period, marker ;
psf_binheader_readf (psf, "pE444", 0, &sample_count, &sample_period, &marker) ;
if (2 * sample_count + 12 != psf->filelength)
return SFE_HTK_BAD_FILE_LEN ;
if (marker != 0x20000)
return SFE_HTK_NOT_WAVEFORM ;
psf->sf.channels = 1 ;
if (sample_period > 0)
{ psf->sf.samplerate = 10000000 / sample_period ;
psf_log_printf (psf, "HTK Waveform file\n Sample Count : %d\n Sample Period : %d => %d Hz\n",
sample_count, sample_period, psf->sf.samplerate) ;
}
else
{ psf->sf.samplerate = 16000 ;
psf_log_printf (psf, "HTK Waveform file\n Sample Count : %d\n Sample Period : %d (should be > 0) => Guessed sample rate %d Hz\n",
sample_count, sample_period, psf->sf.samplerate) ;
} ;
psf->sf.format = SF_FORMAT_HTK | SF_FORMAT_PCM_16 ;
psf->bytewidth = 2 ;
/* HTK always has a 12 byte header. */
psf->dataoffset = 12 ;
psf->endian = SF_ENDIAN_BIG ;
psf->datalength = psf->filelength - psf->dataoffset ;
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
if (! psf->sf.frames && psf->blockwidth)
psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ;
return 0 ;
} /* htk_read_header */

View File

@@ -0,0 +1,52 @@
/*
** Copyright (C) 2010-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
int
id3_skip (SF_PRIVATE * psf)
{ unsigned char buf [10] ;
memset (buf, 0, sizeof (buf)) ;
psf_binheader_readf (psf, "pb", 0, buf, 10) ;
if (buf [0] == 'I' && buf [1] == 'D' && buf [2] == '3')
{ int offset = buf [6] & 0x7f ;
offset = (offset << 7) | (buf [7] & 0x7f) ;
offset = (offset << 7) | (buf [8] & 0x7f) ;
offset = (offset << 7) | (buf [9] & 0x7f) ;
psf_binheader_readf (psf, "j", make_size_t (offset)) ;
psf_log_printf (psf, "ID3 length : %d\n--------------------\n", offset) ;
psf->fileoffset = 10 + offset ;
return 1 ;
} ;
return 0 ;
} /* id3_skip */

View File

@@ -0,0 +1,946 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
typedef struct IMA_ADPCM_PRIVATE_tag
{ int (*decode_block) (SF_PRIVATE *psf, struct IMA_ADPCM_PRIVATE_tag *pima) ;
int (*encode_block) (SF_PRIVATE *psf, struct IMA_ADPCM_PRIVATE_tag *pima) ;
int channels, blocksize, samplesperblock, blocks ;
int blockcount, samplecount ;
int previous [2] ;
int stepindx [2] ;
unsigned char *block ;
short *samples ;
#if HAVE_FLEXIBLE_ARRAY
short data [] ; /* ISO C99 struct flexible array. */
#else
short data [0] ; /* This is a hack and might not work. */
#endif
} IMA_ADPCM_PRIVATE ;
/*============================================================================================
** Predefined IMA ADPCM data.
*/
static int ima_indx_adjust [16] =
{ -1, -1, -1, -1, /* +0 - +3, decrease the step size */
2, 4, 6, 8, /* +4 - +7, increase the step size */
-1, -1, -1, -1, /* -0 - -3, decrease the step size */
2, 4, 6, 8, /* -4 - -7, increase the step size */
} ;
static int ima_step_size [89] =
{ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230,
253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963,
1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442,
11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
32767
} ;
static int ima_reader_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ;
static int ima_writer_init (SF_PRIVATE *psf, int blockalign) ;
static int ima_read_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima, short *ptr, int len) ;
static int ima_write_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima, const short *ptr, int len) ;
static sf_count_t ima_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
static sf_count_t ima_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
static sf_count_t ima_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
static sf_count_t ima_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
static sf_count_t ima_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
static sf_count_t ima_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
static sf_count_t ima_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
static sf_count_t ima_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
static sf_count_t ima_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
static int ima_close (SF_PRIVATE *psf) ;
static int wav_w64_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) ;
static int wav_w64_ima_encode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) ;
/*-static int aiff_ima_reader_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ;-*/
static int aiff_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) ;
static int aiff_ima_encode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) ;
static inline int
clamp_ima_step_index (int indx)
{ if (indx < 0)
return 0 ;
if (indx >= ARRAY_LEN (ima_step_size))
return ARRAY_LEN (ima_step_size) - 1 ;
return indx ;
} /* clamp_ima_step_index */
/*============================================================================================
** IMA ADPCM Reader initialisation function.
*/
int
wav_w64_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock)
{ int error ;
if (psf->codec_data != NULL)
{ psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ;
return SFE_INTERNAL ;
} ;
if (psf->file.mode == SFM_RDWR)
return SFE_BAD_MODE_RW ;
if (psf->file.mode == SFM_READ)
if ((error = ima_reader_init (psf, blockalign, samplesperblock)))
return error ;
if (psf->file.mode == SFM_WRITE)
if ((error = ima_writer_init (psf, blockalign)))
return error ;
psf->codec_close = ima_close ;
psf->seek = ima_seek ;
return 0 ;
} /* wav_w64_ima_init */
int
aiff_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock)
{ int error ;
if (psf->file.mode == SFM_RDWR)
return SFE_BAD_MODE_RW ;
if (psf->file.mode == SFM_READ)
if ((error = ima_reader_init (psf, blockalign, samplesperblock)))
return error ;
if (psf->file.mode == SFM_WRITE)
if ((error = ima_writer_init (psf, blockalign)))
return error ;
psf->codec_close = ima_close ;
return 0 ;
} /* aiff_ima_init */
static int
ima_close (SF_PRIVATE *psf)
{ IMA_ADPCM_PRIVATE *pima ;
pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ;
if (psf->file.mode == SFM_WRITE)
{ /* If a block has been partially assembled, write it out
** as the final block.
*/
if (pima->samplecount && pima->samplecount < pima->samplesperblock)
pima->encode_block (psf, pima) ;
psf->sf.frames = pima->samplesperblock * pima->blockcount / psf->sf.channels ;
} ;
return 0 ;
} /* ima_close */
/*============================================================================================
** IMA ADPCM Read Functions.
*/
static int
ima_reader_init (SF_PRIVATE *psf, int blockalign, int samplesperblock)
{ IMA_ADPCM_PRIVATE *pima ;
int pimasize, count ;
if (psf->file.mode != SFM_READ)
return SFE_BAD_MODE_RW ;
pimasize = sizeof (IMA_ADPCM_PRIVATE) + blockalign * psf->sf.channels + 3 * psf->sf.channels * samplesperblock ;
if (! (pima = calloc (1, pimasize)))
return SFE_MALLOC_FAILED ;
psf->codec_data = (void*) pima ;
pima->samples = pima->data ;
pima->block = (unsigned char*) (pima->data + samplesperblock * psf->sf.channels) ;
pima->channels = psf->sf.channels ;
pima->blocksize = blockalign ;
pima->samplesperblock = samplesperblock ;
psf->filelength = psf_get_filelen (psf) ;
psf->datalength = (psf->dataend) ? psf->dataend - psf->dataoffset :
psf->filelength - psf->dataoffset ;
if (pima->blocksize == 0)
{ psf_log_printf (psf, "*** Error : pima->blocksize should not be zero.\n") ;
return SFE_INTERNAL ;
} ;
if (psf->datalength % pima->blocksize)
pima->blocks = psf->datalength / pima->blocksize + 1 ;
else
pima->blocks = psf->datalength / pima->blocksize ;
switch (SF_CONTAINER (psf->sf.format))
{ case SF_FORMAT_WAV :
case SF_FORMAT_W64 :
count = 2 * (pima->blocksize - 4 * pima->channels) / pima->channels + 1 ;
if (pima->samplesperblock != count)
{ psf_log_printf (psf, "*** Error : samplesperblock should be %d.\n", count) ;
return SFE_INTERNAL ;
} ;
pima->decode_block = wav_w64_ima_decode_block ;
psf->sf.frames = pima->samplesperblock * pima->blocks ;
break ;
case SF_FORMAT_AIFF :
psf_log_printf (psf, "still need to check block count\n") ;
pima->decode_block = aiff_ima_decode_block ;
psf->sf.frames = pima->samplesperblock * pima->blocks / pima->channels ;
break ;
default :
psf_log_printf (psf, "ima_reader_init: bad psf->sf.format\n") ;
return SFE_INTERNAL ;
} ;
pima->decode_block (psf, pima) ; /* Read first block. */
psf->read_short = ima_read_s ;
psf->read_int = ima_read_i ;
psf->read_float = ima_read_f ;
psf->read_double = ima_read_d ;
return 0 ;
} /* ima_reader_init */
static int
aiff_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima)
{ unsigned char *blockdata ;
int chan, k, diff, bytecode, predictor ;
short step, stepindx, *sampledata ;
static int count = 0 ;
count ++ ;
pima->blockcount += pima->channels ;
pima->samplecount = 0 ;
if (pima->blockcount > pima->blocks)
{ memset (pima->samples, 0, pima->samplesperblock * pima->channels * sizeof (short)) ;
return 1 ;
} ;
if ((k = psf_fread (pima->block, 1, pima->blocksize * pima->channels, psf)) != pima->blocksize * pima->channels)
psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pima->blocksize) ;
/* Read and check the block header. */
for (chan = 0 ; chan < pima->channels ; chan++)
{ blockdata = pima->block + chan * 34 ;
sampledata = pima->samples + chan ;
predictor = (blockdata [0] << 8) | (blockdata [1] & 0x80) ;
stepindx = blockdata [1] & 0x7F ;
stepindx = clamp_ima_step_index (stepindx) ;
/*
** Pull apart the packed 4 bit samples and store them in their
** correct sample positions.
*/
for (k = 0 ; k < pima->blocksize - 2 ; k++)
{ bytecode = blockdata [k + 2] ;
sampledata [pima->channels * (2 * k + 0)] = bytecode & 0xF ;
sampledata [pima->channels * (2 * k + 1)] = (bytecode >> 4) & 0xF ;
} ;
/* Decode the encoded 4 bit samples. */
for (k = 0 ; k < pima->samplesperblock ; k ++)
{ step = ima_step_size [stepindx] ;
bytecode = pima->samples [pima->channels * k + chan] ;
stepindx += ima_indx_adjust [bytecode] ;
stepindx = clamp_ima_step_index (stepindx) ;
diff = step >> 3 ;
if (bytecode & 1) diff += step >> 2 ;
if (bytecode & 2) diff += step >> 1 ;
if (bytecode & 4) diff += step ;
if (bytecode & 8) diff = -diff ;
predictor += diff ;
if (predictor < -32768)
predictor = -32768 ;
else if (predictor > 32767)
predictor = 32767 ;
pima->samples [pima->channels * k + chan] = predictor ;
} ;
} ;
return 1 ;
} /* aiff_ima_decode_block */
static int
aiff_ima_encode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima)
{ int chan, k, step, diff, vpdiff, blockindx, indx ;
short bytecode, mask ;
/* Encode the block header. */
for (chan = 0 ; chan < pima->channels ; chan ++)
{ blockindx = chan * pima->blocksize ;
pima->block [blockindx] = (pima->samples [chan] >> 8) & 0xFF ;
pima->block [blockindx + 1] = (pima->samples [chan] & 0x80) + (pima->stepindx [chan] & 0x7F) ;
pima->previous [chan] = pima->samples [chan] ;
} ;
/* Encode second and later samples for every block as a 4 bit value. */
for (k = pima->channels ; k < (pima->samplesperblock * pima->channels) ; k ++)
{ chan = (pima->channels > 1) ? (k % 2) : 0 ;
diff = pima->samples [k] - pima->previous [chan] ;
bytecode = 0 ;
step = ima_step_size [pima->stepindx [chan]] ;
vpdiff = step >> 3 ;
if (diff < 0)
{ bytecode = 8 ;
diff = -diff ;
} ;
mask = 4 ;
while (mask)
{ if (diff >= step)
{ bytecode |= mask ;
diff -= step ;
vpdiff += step ;
} ;
step >>= 1 ;
mask >>= 1 ;
} ;
if (bytecode & 8)
pima->previous [chan] -= vpdiff ;
else
pima->previous [chan] += vpdiff ;
if (pima->previous [chan] > 32767)
pima->previous [chan] = 32767 ;
else if (pima->previous [chan] < -32768)
pima->previous [chan] = -32768 ;
pima->stepindx [chan] += ima_indx_adjust [bytecode] ;
pima->stepindx [chan] = clamp_ima_step_index (pima->stepindx [chan]) ;
pima->samples [k] = bytecode ;
} ;
/* Pack the 4 bit encoded samples. */
for (chan = 0 ; chan < pima->channels ; chan ++)
{ for (indx = pima->channels ; indx < pima->channels * pima->samplesperblock ; indx += 2 * pima->channels)
{ blockindx = chan * pima->blocksize + 2 + indx / 2 ;
pima->block [blockindx] = pima->samples [indx] & 0x0F ;
pima->block [blockindx] |= (pima->samples [indx + chan] << 4) & 0xF0 ;
} ;
} ;
/* Write the block to disk. */
if ((k = psf_fwrite (pima->block, 1, pima->channels * pima->blocksize, psf)) != pima->channels * pima->blocksize)
psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pima->channels * pima->blocksize) ;
memset (pima->samples, 0, pima->channels * pima->samplesperblock * sizeof (short)) ;
pima->samplecount = 0 ;
pima->blockcount ++ ;
return 1 ;
} /* aiff_ima_encode_block */
static int
wav_w64_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima)
{ int chan, k, predictor, blockindx, indx, indxstart, diff ;
short step, bytecode, stepindx [2] ;
pima->blockcount ++ ;
pima->samplecount = 0 ;
if (pima->blockcount > pima->blocks)
{ memset (pima->samples, 0, pima->samplesperblock * pima->channels * sizeof (short)) ;
return 1 ;
} ;
if ((k = psf_fread (pima->block, 1, pima->blocksize, psf)) != pima->blocksize)
psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pima->blocksize) ;
/* Read and check the block header. */
for (chan = 0 ; chan < pima->channels ; chan++)
{ predictor = pima->block [chan*4] | (pima->block [chan*4+1] << 8) ;
if (predictor & 0x8000)
predictor -= 0x10000 ;
stepindx [chan] = pima->block [chan*4+2] ;
stepindx [chan] = clamp_ima_step_index (stepindx [chan]) ;
if (pima->block [chan*4+3] != 0)
psf_log_printf (psf, "IMA ADPCM synchronisation error.\n") ;
pima->samples [chan] = predictor ;
} ;
/*
** Pull apart the packed 4 bit samples and store them in their
** correct sample positions.
*/
blockindx = 4 * pima->channels ;
indxstart = pima->channels ;
while (blockindx < pima->blocksize)
{ for (chan = 0 ; chan < pima->channels ; chan++)
{ indx = indxstart + chan ;
for (k = 0 ; k < 4 ; k++)
{ bytecode = pima->block [blockindx++] ;
pima->samples [indx] = bytecode & 0x0F ;
indx += pima->channels ;
pima->samples [indx] = (bytecode >> 4) & 0x0F ;
indx += pima->channels ;
} ;
} ;
indxstart += 8 * pima->channels ;
} ;
/* Decode the encoded 4 bit samples. */
for (k = pima->channels ; k < (pima->samplesperblock * pima->channels) ; k ++)
{ chan = (pima->channels > 1) ? (k % 2) : 0 ;
bytecode = pima->samples [k] & 0xF ;
step = ima_step_size [stepindx [chan]] ;
predictor = pima->samples [k - pima->channels] ;
diff = step >> 3 ;
if (bytecode & 1)
diff += step >> 2 ;
if (bytecode & 2)
diff += step >> 1 ;
if (bytecode & 4)
diff += step ;
if (bytecode & 8)
diff = -diff ;
predictor += diff ;
if (predictor > 32767)
predictor = 32767 ;
else if (predictor < -32768)
predictor = -32768 ;
stepindx [chan] += ima_indx_adjust [bytecode] ;
stepindx [chan] = clamp_ima_step_index (stepindx [chan]) ;
pima->samples [k] = predictor ;
} ;
return 1 ;
} /* wav_w64_ima_decode_block */
static int
wav_w64_ima_encode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima)
{ int chan, k, step, diff, vpdiff, blockindx, indx, indxstart ;
short bytecode, mask ;
/* Encode the block header. */
for (chan = 0 ; chan < pima->channels ; chan++)
{ pima->block [chan*4] = pima->samples [chan] & 0xFF ;
pima->block [chan*4+1] = (pima->samples [chan] >> 8) & 0xFF ;
pima->block [chan*4+2] = pima->stepindx [chan] ;
pima->block [chan*4+3] = 0 ;
pima->previous [chan] = pima->samples [chan] ;
} ;
/* Encode the samples as 4 bit. */
for (k = pima->channels ; k < (pima->samplesperblock * pima->channels) ; k ++)
{ chan = (pima->channels > 1) ? (k % 2) : 0 ;
diff = pima->samples [k] - pima->previous [chan] ;
bytecode = 0 ;
step = ima_step_size [pima->stepindx [chan]] ;
vpdiff = step >> 3 ;
if (diff < 0)
{ bytecode = 8 ;
diff = -diff ;
} ;
mask = 4 ;
while (mask)
{ if (diff >= step)
{ bytecode |= mask ;
diff -= step ;
vpdiff += step ;
} ;
step >>= 1 ;
mask >>= 1 ;
} ;
if (bytecode & 8)
pima->previous [chan] -= vpdiff ;
else
pima->previous [chan] += vpdiff ;
if (pima->previous [chan] > 32767)
pima->previous [chan] = 32767 ;
else if (pima->previous [chan] < -32768)
pima->previous [chan] = -32768 ;
pima->stepindx [chan] += ima_indx_adjust [bytecode] ;
pima->stepindx [chan] = clamp_ima_step_index (pima->stepindx [chan]) ;
pima->samples [k] = bytecode ;
} ;
/* Pack the 4 bit encoded samples. */
blockindx = 4 * pima->channels ;
indxstart = pima->channels ;
while (blockindx < pima->blocksize)
{ for (chan = 0 ; chan < pima->channels ; chan++)
{ indx = indxstart + chan ;
for (k = 0 ; k < 4 ; k++)
{ pima->block [blockindx] = pima->samples [indx] & 0x0F ;
indx += pima->channels ;
pima->block [blockindx] |= (pima->samples [indx] << 4) & 0xF0 ;
indx += pima->channels ;
blockindx ++ ;
} ;
} ;
indxstart += 8 * pima->channels ;
} ;
/* Write the block to disk. */
if ((k = psf_fwrite (pima->block, 1, pima->blocksize, psf)) != pima->blocksize)
psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pima->blocksize) ;
memset (pima->samples, 0, pima->samplesperblock * sizeof (short)) ;
pima->samplecount = 0 ;
pima->blockcount ++ ;
return 1 ;
} /* wav_w64_ima_encode_block */
static int
ima_read_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima, short *ptr, int len)
{ int count, total = 0, indx = 0 ;
while (indx < len)
{ if (pima->blockcount >= pima->blocks && pima->samplecount >= pima->samplesperblock)
{ memset (&(ptr [indx]), 0, (size_t) ((len - indx) * sizeof (short))) ;
return total ;
} ;
if (pima->samplecount >= pima->samplesperblock)
pima->decode_block (psf, pima) ;
count = (pima->samplesperblock - pima->samplecount) * pima->channels ;
count = (len - indx > count) ? count : len - indx ;
memcpy (&(ptr [indx]), &(pima->samples [pima->samplecount * pima->channels]), count * sizeof (short)) ;
indx += count ;
pima->samplecount += count / pima->channels ;
total = indx ;
} ;
return total ;
} /* ima_read_block */
static sf_count_t
ima_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
{ IMA_ADPCM_PRIVATE *pima ;
int readcount, count ;
sf_count_t total = 0 ;
if (! psf->codec_data)
return 0 ;
pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ;
while (len > 0)
{ readcount = (len > 0x10000000) ? 0x10000000 : (int) len ;
count = ima_read_block (psf, pima, ptr, readcount) ;
total += count ;
len -= count ;
if (count != readcount)
break ;
} ;
return total ;
} /* ima_read_s */
static sf_count_t
ima_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
{ IMA_ADPCM_PRIVATE *pima ;
short *sptr ;
int k, bufferlen, readcount, count ;
sf_count_t total = 0 ;
if (! psf->codec_data)
return 0 ;
pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : (int) len ;
count = ima_read_block (psf, pima, sptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = ((int) sptr [k]) << 16 ;
total += count ;
len -= readcount ;
if (count != readcount)
break ;
} ;
return total ;
} /* ima_read_i */
static sf_count_t
ima_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
{ IMA_ADPCM_PRIVATE *pima ;
short *sptr ;
int k, bufferlen, readcount, count ;
sf_count_t total = 0 ;
float normfact ;
if (! psf->codec_data)
return 0 ;
pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : (int) len ;
count = ima_read_block (psf, pima, sptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = normfact * (float) (sptr [k]) ;
total += count ;
len -= readcount ;
if (count != readcount)
break ;
} ;
return total ;
} /* ima_read_f */
static sf_count_t
ima_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
{ IMA_ADPCM_PRIVATE *pima ;
short *sptr ;
int k, bufferlen, readcount, count ;
sf_count_t total = 0 ;
double normfact ;
if (! psf->codec_data)
return 0 ;
pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : (int) len ;
count = ima_read_block (psf, pima, sptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = normfact * (double) (sptr [k]) ;
total += count ;
len -= readcount ;
if (count != readcount)
break ;
} ;
return total ;
} /* ima_read_d */
static sf_count_t
ima_seek (SF_PRIVATE *psf, int mode, sf_count_t offset)
{ IMA_ADPCM_PRIVATE *pima ;
int newblock, newsample ;
if (! psf->codec_data)
return 0 ;
pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ;
if (psf->datalength < 0 || psf->dataoffset < 0)
{ psf->error = SFE_BAD_SEEK ;
return PSF_SEEK_ERROR ;
} ;
if (offset == 0)
{ psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
pima->blockcount = 0 ;
pima->decode_block (psf, pima) ;
pima->samplecount = 0 ;
return 0 ;
} ;
if (offset < 0 || offset > pima->blocks * pima->samplesperblock)
{ psf->error = SFE_BAD_SEEK ;
return PSF_SEEK_ERROR ;
} ;
newblock = offset / pima->samplesperblock ;
newsample = offset % pima->samplesperblock ;
if (mode == SFM_READ)
{ psf_fseek (psf, psf->dataoffset + newblock * pima->blocksize, SEEK_SET) ;
pima->blockcount = newblock ;
pima->decode_block (psf, pima) ;
pima->samplecount = newsample ;
}
else
{ /* What to do about write??? */
psf->error = SFE_BAD_SEEK ;
return PSF_SEEK_ERROR ;
} ;
return newblock * pima->samplesperblock + newsample ;
} /* ima_seek */
/*==========================================================================================
** IMA ADPCM Write Functions.
*/
static int
ima_writer_init (SF_PRIVATE *psf, int blockalign)
{ IMA_ADPCM_PRIVATE *pima ;
int samplesperblock ;
unsigned int pimasize ;
if (psf->file.mode != SFM_WRITE)
return SFE_BAD_MODE_RW ;
samplesperblock = 2 * (blockalign - 4 * psf->sf.channels) / psf->sf.channels + 1 ;
pimasize = sizeof (IMA_ADPCM_PRIVATE) + blockalign + 3 * psf->sf.channels * samplesperblock ;
if ((pima = calloc (1, pimasize)) == NULL)
return SFE_MALLOC_FAILED ;
psf->codec_data = (void*) pima ;
pima->channels = psf->sf.channels ;
pima->blocksize = blockalign ;
pima->samplesperblock = samplesperblock ;
pima->block = (unsigned char*) pima->data ;
pima->samples = (short*) (pima->data + blockalign) ;
pima->samplecount = 0 ;
switch (SF_CONTAINER (psf->sf.format))
{ case SF_FORMAT_WAV :
case SF_FORMAT_W64 :
pima->encode_block = wav_w64_ima_encode_block ;
break ;
case SF_FORMAT_AIFF :
pima->encode_block = aiff_ima_encode_block ;
break ;
default :
psf_log_printf (psf, "ima_reader_init: bad psf->sf.format\n") ;
return SFE_INTERNAL ;
} ;
psf->write_short = ima_write_s ;
psf->write_int = ima_write_i ;
psf->write_float = ima_write_f ;
psf->write_double = ima_write_d ;
return 0 ;
} /* ima_writer_init */
/*==========================================================================================
*/
static int
ima_write_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima, const short *ptr, int len)
{ int count, total = 0, indx = 0 ;
while (indx < len)
{ count = (pima->samplesperblock - pima->samplecount) * pima->channels ;
if (count > len - indx)
count = len - indx ;
memcpy (&(pima->samples [pima->samplecount * pima->channels]), &(ptr [total]), count * sizeof (short)) ;
indx += count ;
pima->samplecount += count / pima->channels ;
total = indx ;
if (pima->samplecount >= pima->samplesperblock)
pima->encode_block (psf, pima) ;
} ;
return total ;
} /* ima_write_block */
static sf_count_t
ima_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
{ IMA_ADPCM_PRIVATE *pima ;
int writecount, count ;
sf_count_t total = 0 ;
if (! psf->codec_data)
return 0 ;
pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ;
while (len)
{ writecount = (len > 0x10000000) ? 0x10000000 : (int) len ;
count = ima_write_block (psf, pima, ptr, writecount) ;
total += count ;
len -= count ;
if (count != writecount)
break ;
} ;
return total ;
} /* ima_write_s */
static sf_count_t
ima_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
{ IMA_ADPCM_PRIVATE *pima ;
short *sptr ;
int k, bufferlen, writecount, count ;
sf_count_t total = 0 ;
if (! psf->codec_data)
return 0 ;
pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : (int) len ;
for (k = 0 ; k < writecount ; k++)
sptr [k] = ptr [total + k] >> 16 ;
count = ima_write_block (psf, pima, sptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* ima_write_i */
static sf_count_t
ima_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
{ IMA_ADPCM_PRIVATE *pima ;
short *sptr ;
int k, bufferlen, writecount, count ;
sf_count_t total = 0 ;
float normfact ;
if (! psf->codec_data)
return 0 ;
pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : (int) len ;
for (k = 0 ; k < writecount ; k++)
sptr [k] = lrintf (normfact * ptr [total + k]) ;
count = ima_write_block (psf, pima, sptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* ima_write_f */
static sf_count_t
ima_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
{ IMA_ADPCM_PRIVATE *pima ;
short *sptr ;
int k, bufferlen, writecount, count ;
sf_count_t total = 0 ;
double normfact ;
if (! psf->codec_data)
return 0 ;
pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : (int) len ;
for (k = 0 ; k < writecount ; k++)
sptr [k] = lrint (normfact * ptr [total + k]) ;
count = ima_write_block (psf, pima, sptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* ima_write_d */

View File

@@ -0,0 +1,297 @@
/*
** Copyright (C) 2007-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
** Copyright (c) 2007 <robs@users.sourceforge.net>
**
** This library is free software; you can redistribute it and/or modify it
** under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation; either version 2 of the License, or (at
** your option) any later version.
**
** This library is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
** General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this library. If not, write to the Free Software Foundation,
** Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
*/
/* ADPCM: IMA, OKI <==> 16-bit PCM. */
#include "sfconfig.h"
#include <string.h>
/* Set up for libsndfile environment: */
#include "common.h"
#include "ima_oki_adpcm.h"
#define MIN_SAMPLE -0x8000
#define MAX_SAMPLE 0x7fff
static int const ima_steps [] = /* ~16-bit precision */
{ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230,
253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963,
1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442,
11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
32767
} ;
static int const oki_steps [] = /* ~12-bit precision */
{ 256, 272, 304, 336, 368, 400, 448, 496, 544, 592, 656, 720, 800, 880, 960,
1056, 1168, 1280, 1408, 1552, 1712, 1888, 2080, 2288, 2512, 2768, 3040, 3344,
3680, 4048, 4464, 4912, 5392, 5936, 6528, 7184, 7904, 8704, 9568, 10528,
11584, 12736, 14016, 15408, 16960, 18656, 20512, 22576, 24832
} ;
static int const step_changes [] = { -1, -1, -1, -1, 2, 4, 6, 8 } ;
void
ima_oki_adpcm_init (IMA_OKI_ADPCM * state, IMA_OKI_ADPCM_TYPE type)
{
memset (state, 0, sizeof (*state)) ;
if (type == IMA_OKI_ADPCM_TYPE_IMA)
{ state->max_step_index = ARRAY_LEN (ima_steps) - 1 ;
state->steps = ima_steps ;
state->mask = (~0) ;
}
else
{ state->max_step_index = ARRAY_LEN (oki_steps) - 1 ;
state->steps = oki_steps ;
state->mask = (~0) << 4 ;
} ;
} /* ima_oki_adpcm_init */
int
adpcm_decode (IMA_OKI_ADPCM * state, int code)
{ int s ;
s = ((code & 7) << 1) | 1 ;
s = ((state->steps [state->step_index] * s) >> 3) & state->mask ;
if (code & 8)
s = -s ;
s += state->last_output ;
if (s < MIN_SAMPLE || s > MAX_SAMPLE)
{ int grace ;
grace = (state->steps [state->step_index] >> 3) & state->mask ;
if (s < MIN_SAMPLE - grace || s > MAX_SAMPLE + grace)
state->errors ++ ;
s = s < MIN_SAMPLE ? MIN_SAMPLE : MAX_SAMPLE ;
} ;
state->step_index += step_changes [code & 7] ;
state->step_index = SF_MIN (SF_MAX (state->step_index, 0), state->max_step_index) ;
state->last_output = s ;
return s ;
} /* adpcm_decode */
int
adpcm_encode (IMA_OKI_ADPCM * state, int sample)
{ int delta, sign = 0, code ;
delta = sample - state->last_output ;
if (delta < 0)
{ sign = 8 ;
delta = -delta ;
} ;
code = 4 * delta / state->steps [state->step_index] ;
code = sign | SF_MIN (code, 7) ;
adpcm_decode (state, code) ; /* Update encoder state */
return code ;
} /* adpcm_encode */
void
ima_oki_adpcm_decode_block (IMA_OKI_ADPCM * state)
{ unsigned char code ;
int k ;
for (k = 0 ; k < state->code_count ; k++)
{ code = state->codes [k] ;
state->pcm [2 * k] = adpcm_decode (state, code >> 4) ;
state->pcm [2 * k + 1] = adpcm_decode (state, code) ;
} ;
state->pcm_count = 2 * k ;
} /* ima_oki_adpcm_decode_block */
void
ima_oki_adpcm_encode_block (IMA_OKI_ADPCM * state)
{ unsigned char code ;
int k ;
/*
** The codec expects an even number of input samples.
**
** Samples should always be passed in even length blocks. If the last block to
** be encoded is odd length, extend that block by one zero valued sample.
*/
if (state->pcm_count % 2 == 1)
state->pcm [state->pcm_count ++] = 0 ;
for (k = 0 ; k < state->pcm_count / 2 ; k++)
{ code = adpcm_encode (state, state->pcm [2 * k]) << 4 ;
code |= adpcm_encode (state, state->pcm [2 * k + 1]) ;
state->codes [k] = code ;
} ;
state->code_count = k ;
} /* ima_oki_adpcm_encode_block */
#ifdef TEST
static const unsigned char test_codes [] =
{ 0x08, 0x08, 0x04, 0x7f, 0x72, 0xf7, 0x9f, 0x7c, 0xd7, 0xbc, 0x7a, 0xa7, 0xb8,
0x4b, 0x0b, 0x38, 0xf6, 0x9d, 0x7a, 0xd7, 0xbc, 0x7a, 0xd7, 0xa8, 0x6c, 0x81,
0x98, 0xe4, 0x0e, 0x7a, 0xd7, 0x9e, 0x7b, 0xc7, 0xab, 0x7a, 0x85, 0xc0, 0xb3,
0x8f, 0x58, 0xd7, 0xad, 0x7a, 0xd7, 0xad, 0x7a, 0x87, 0xd0, 0x2b, 0x0e, 0x48,
0xd7, 0xad, 0x78, 0xf7, 0xbc, 0x7a, 0xb7, 0xa8, 0x4b, 0x88, 0x18, 0xd5, 0x8d,
0x6a, 0xa4, 0x98, 0x08, 0x00, 0x80, 0x88,
} ;
static const short test_pcm [] =
{ 32, 0, 32, 0, 32, 320, 880, -336, 2304, 4192, -992, 10128, 5360, -16352,
30208, 2272, -31872, 14688, -7040, -32432, 14128, -1392, -15488, 22960,
1232, -1584, 21488, -240, 2576, -15360, 960, -1152, -30032, 10320, 1008,
-30032, 16528, 1008, -30032, 16528, -5200, -30592, 15968, 448, -30592,
15968, 448, -2368, 30960, 3024, -80, 8384, 704, -1616, -29168, -1232, 1872,
-32768, 13792, -1728, -32768, 13792, 4480, -32192, 14368, -7360, -32752,
13808, -1712, -21456, 16992, 1472, -1344, 26848, -1088, 2016, -17728, 208,
-2112, -32768, 1376, -1728, -32768, 13792, -1728, -32768, 13792, -1728,
-32768, 13792, -1728, -32768, 13792, -1728, -4544, 32767, -1377, 1727,
15823, -2113, 207, -27345, 591, -2513, -32768, 13792, -1728, -32768, 13792,
10688, -31632, 14928, -6800, -32192, 14368, -1152, -20896, 17552, 2032,
-784, 22288, 560, -2256, -4816, 2176, 64, -21120, 9920, 6816, -24224, 16128,
608, -13488, 9584, 272, -2544, 16, -2304, -192, 1728, -16, 1568, 128, -1184,
} ;
static void
test_oki_adpcm (void)
{
IMA_OKI_ADPCM adpcm ;
unsigned char code ;
int i, j ;
printf (" Testing encoder : ") ;
fflush (stdout) ;
ima_oki_adpcm_init (&adpcm, IMA_OKI_ADPCM_TYPE_OKI) ;
for (i = 0 ; i < ARRAY_LEN (test_codes) ; i++)
for (j = 0, code = test_codes [i] ; j < 2 ; j++, code <<= 4)
if (adpcm_decode (&adpcm, code >> 4) != test_pcm [2 * i + j])
{ printf ("\n\nFail at i = %d, j = %d.\n\n", i, j) ;
exit (1) ;
} ;
puts ("ok") ;
printf (" Testing decoder : ") ;
fflush (stdout) ;
ima_oki_adpcm_init (&adpcm, IMA_OKI_ADPCM_TYPE_OKI) ;
for (i = 0 ; i < ARRAY_LEN (test_pcm) ; i += j)
{ code = adpcm_encode (&adpcm, test_pcm [i]) ;
code = (code << 4) | adpcm_encode (&adpcm, test_pcm [i + 1]) ;
if (code != test_codes [i / 2])
{ printf ("\n\nFail at i = %d, %d should be %d\n\n", i, code, test_codes [i / 2]) ;
exit (1) ;
} ;
} ;
puts ("ok") ;
} /* test_oki_adpcm */
static void
test_oki_adpcm_block (void)
{
IMA_OKI_ADPCM adpcm ;
int k ;
if (ARRAY_LEN (adpcm.pcm) < ARRAY_LEN (test_pcm))
{ printf ("\n\nLine %d : ARRAY_LEN (adpcm->pcm) > ARRAY_LEN (test_pcm) (%d > %d).\n\n", __LINE__, ARRAY_LEN (adpcm.pcm), ARRAY_LEN (test_pcm)) ;
exit (1) ;
} ;
if (ARRAY_LEN (adpcm.codes) < ARRAY_LEN (test_codes))
{ printf ("\n\nLine %d : ARRAY_LEN (adcodes->codes) > ARRAY_LEN (test_codes).n", __LINE__) ;
exit (1) ;
} ;
printf (" Testing block encoder : ") ;
fflush (stdout) ;
ima_oki_adpcm_init (&adpcm, IMA_OKI_ADPCM_TYPE_OKI) ;
memcpy (adpcm.pcm, test_pcm, sizeof (adpcm.pcm [0]) * ARRAY_LEN (test_pcm)) ;
adpcm.pcm_count = ARRAY_LEN (test_pcm) ;
adpcm.code_count = 13 ;
ima_oki_adpcm_encode_block (&adpcm) ;
if (adpcm.code_count * 2 != ARRAY_LEN (test_pcm))
{ printf ("\n\nLine %d : %d * 2 != %d\n\n", __LINE__, adpcm.code_count * 2, ARRAY_LEN (test_pcm)) ;
exit (1) ;
} ;
for (k = 0 ; k < ARRAY_LEN (test_codes) ; k++)
if (adpcm.codes [k] != test_codes [k])
{ printf ("\n\nLine %d : Fail at k = %d, %d should be %d\n\n", __LINE__, k, adpcm.codes [k], test_codes [k]) ;
exit (1) ;
} ;
puts ("ok") ;
printf (" Testing block decoder : ") ;
fflush (stdout) ;
ima_oki_adpcm_init (&adpcm, IMA_OKI_ADPCM_TYPE_OKI) ;
memcpy (adpcm.codes, test_codes, sizeof (adpcm.codes [0]) * ARRAY_LEN (test_codes)) ;
adpcm.code_count = ARRAY_LEN (test_codes) ;
adpcm.pcm_count = 13 ;
ima_oki_adpcm_decode_block (&adpcm) ;
if (adpcm.pcm_count != 2 * ARRAY_LEN (test_codes))
{ printf ("\n\nLine %d : %d * 2 != %d\n\n", __LINE__, adpcm.pcm_count, 2 * ARRAY_LEN (test_codes)) ;
exit (1) ;
} ;
for (k = 0 ; k < ARRAY_LEN (test_pcm) ; k++)
if (adpcm.pcm [k] != test_pcm [k])
{ printf ("\n\nLine %d : Fail at i = %d, %d should be %d.\n\n", __LINE__, k, adpcm.pcm [k], test_pcm [k]) ;
exit (1) ;
} ;
puts ("ok") ;
} /* test_oki_adpcm_block */
int
main (void)
{
test_oki_adpcm () ;
test_oki_adpcm_block () ;
return 0 ;
} /* main */
#endif

View File

@@ -0,0 +1,54 @@
/*
** Copyright (C) 2007-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
** Copyright (c) 2007 <robs@users.sourceforge.net>
**
** This library is free software; you can redistribute it and/or modify it
** under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation; either version 2 of the License, or (at
** your option) any later version.
**
** This library is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
** General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this library. If not, write to the Free Software Foundation,
** Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
*/
/* ADPCM: IMA, OKI <==> 16-bit PCM. */
#define IMA_OKI_ADPCM_CODE_LEN 256
#define IMA_OKI_ADPCM_PCM_LEN (IMA_OKI_ADPCM_CODE_LEN *2)
typedef struct
{
/* private: */
int mask ;
int last_output ;
int step_index ;
int max_step_index ;
int const * steps ;
/* public: */
int errors ;
int code_count, pcm_count ;
unsigned char codes [IMA_OKI_ADPCM_CODE_LEN] ;
short pcm [IMA_OKI_ADPCM_PCM_LEN] ;
} IMA_OKI_ADPCM ;
typedef enum
{ IMA_OKI_ADPCM_TYPE_IMA,
IMA_OKI_ADPCM_TYPE_OKI
} IMA_OKI_ADPCM_TYPE ;
void ima_oki_adpcm_init (IMA_OKI_ADPCM * state, IMA_OKI_ADPCM_TYPE type) ;
int adpcm_decode (IMA_OKI_ADPCM * state, int /* 0..15 */ code) ;
int adpcm_encode (IMA_OKI_ADPCM * state, int /* -32768..32767 */ sample) ;
void ima_oki_adpcm_decode_block (IMA_OKI_ADPCM * state) ;
void ima_oki_adpcm_encode_block (IMA_OKI_ADPCM * state) ;

View File

@@ -0,0 +1,300 @@
/*
** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfendian.h"
#include <stdlib.h>
#include "sndfile.h"
#include "common.h"
#define INTERLEAVE_CHANNELS 6
typedef struct
{ double buffer [SF_BUFFER_LEN / sizeof (double)] ;
sf_count_t channel_len ;
sf_count_t (*read_short) (SF_PRIVATE*, short *ptr, sf_count_t len) ;
sf_count_t (*read_int) (SF_PRIVATE*, int *ptr, sf_count_t len) ;
sf_count_t (*read_float) (SF_PRIVATE*, float *ptr, sf_count_t len) ;
sf_count_t (*read_double) (SF_PRIVATE*, double *ptr, sf_count_t len) ;
} INTERLEAVE_DATA ;
static sf_count_t interleave_read_short (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
static sf_count_t interleave_read_int (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
static sf_count_t interleave_read_float (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
static sf_count_t interleave_read_double (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
static sf_count_t interleave_seek (SF_PRIVATE*, int mode, sf_count_t samples_from_start) ;
int
interleave_init (SF_PRIVATE *psf)
{ INTERLEAVE_DATA *pdata ;
if (psf->file.mode != SFM_READ)
return SFE_INTERLEAVE_MODE ;
if (psf->interleave)
{ psf_log_printf (psf, "*** Weird, already have interleave.\n") ;
return 666 ;
} ;
/* Free this in sf_close() function. */
if (! (pdata = malloc (sizeof (INTERLEAVE_DATA))))
return SFE_MALLOC_FAILED ;
puts ("interleave_init") ;
psf->interleave = pdata ;
/* Save the existing methods. */
pdata->read_short = psf->read_short ;
pdata->read_int = psf->read_int ;
pdata->read_float = psf->read_float ;
pdata->read_double = psf->read_double ;
pdata->channel_len = psf->sf.frames * psf->bytewidth ;
/* Insert our new methods. */
psf->read_short = interleave_read_short ;
psf->read_int = interleave_read_int ;
psf->read_float = interleave_read_float ;
psf->read_double = interleave_read_double ;
psf->seek = interleave_seek ;
return 0 ;
} /* pcm_interleave_init */
/*------------------------------------------------------------------------------
*/
static sf_count_t
interleave_read_short (SF_PRIVATE *psf, short *ptr, sf_count_t len)
{ INTERLEAVE_DATA *pdata ;
sf_count_t offset, templen ;
int chan, count, k ;
short *inptr, *outptr ;
if (! (pdata = psf->interleave))
return 0 ;
inptr = (short*) pdata->buffer ;
for (chan = 0 ; chan < psf->sf.channels ; chan++)
{ outptr = ptr + chan ;
offset = psf->dataoffset + chan * psf->bytewidth * psf->read_current ;
if (psf_fseek (psf, offset, SEEK_SET) != offset)
{ psf->error = SFE_INTERLEAVE_SEEK ;
return 0 ;
} ;
templen = len / psf->sf.channels ;
while (templen > 0)
{ if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (short))
count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (short) ;
else
count = (int) templen ;
if (pdata->read_short (psf, inptr, count) != count)
{ psf->error = SFE_INTERLEAVE_READ ;
return 0 ;
} ;
for (k = 0 ; k < count ; k++)
{ *outptr = inptr [k] ;
outptr += psf->sf.channels ;
} ;
templen -= count ;
} ;
} ;
return len ;
} /* interleave_read_short */
static sf_count_t
interleave_read_int (SF_PRIVATE *psf, int *ptr, sf_count_t len)
{ INTERLEAVE_DATA *pdata ;
sf_count_t offset, templen ;
int chan, count, k ;
int *inptr, *outptr ;
if (! (pdata = psf->interleave))
return 0 ;
inptr = (int*) pdata->buffer ;
for (chan = 0 ; chan < psf->sf.channels ; chan++)
{ outptr = ptr + chan ;
offset = psf->dataoffset + chan * psf->bytewidth * psf->read_current ;
if (psf_fseek (psf, offset, SEEK_SET) != offset)
{ psf->error = SFE_INTERLEAVE_SEEK ;
return 0 ;
} ;
templen = len / psf->sf.channels ;
while (templen > 0)
{ if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (int))
count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (int) ;
else
count = (int) templen ;
if (pdata->read_int (psf, inptr, count) != count)
{ psf->error = SFE_INTERLEAVE_READ ;
return 0 ;
} ;
for (k = 0 ; k < count ; k++)
{ *outptr = inptr [k] ;
outptr += psf->sf.channels ;
} ;
templen -= count ;
} ;
} ;
return len ;
} /* interleave_read_int */
static sf_count_t
interleave_read_float (SF_PRIVATE *psf, float *ptr, sf_count_t len)
{ INTERLEAVE_DATA *pdata ;
sf_count_t offset, templen ;
int chan, count, k ;
float *inptr, *outptr ;
if (! (pdata = psf->interleave))
return 0 ;
inptr = (float*) pdata->buffer ;
for (chan = 0 ; chan < psf->sf.channels ; chan++)
{ outptr = ptr + chan ;
offset = psf->dataoffset + pdata->channel_len * chan + psf->read_current * psf->bytewidth ;
/*-printf ("chan : %d read_current : %6lld offset : %6lld\n", chan, psf->read_current, offset) ;-*/
if (psf_fseek (psf, offset, SEEK_SET) != offset)
{ psf->error = SFE_INTERLEAVE_SEEK ;
/*-puts ("interleave_seek error") ; exit (1) ;-*/
return 0 ;
} ;
templen = len / psf->sf.channels ;
while (templen > 0)
{ if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (float))
count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (float) ;
else
count = (int) templen ;
if (pdata->read_float (psf, inptr, count) != count)
{ psf->error = SFE_INTERLEAVE_READ ;
/*-puts ("interleave_read error") ; exit (1) ;-*/
return 0 ;
} ;
for (k = 0 ; k < count ; k++)
{ *outptr = inptr [k] ;
outptr += psf->sf.channels ;
} ;
templen -= count ;
} ;
} ;
return len ;
} /* interleave_read_float */
static sf_count_t
interleave_read_double (SF_PRIVATE *psf, double *ptr, sf_count_t len)
{ INTERLEAVE_DATA *pdata ;
sf_count_t offset, templen ;
int chan, count, k ;
double *inptr, *outptr ;
if (! (pdata = psf->interleave))
return 0 ;
inptr = (double*) pdata->buffer ;
for (chan = 0 ; chan < psf->sf.channels ; chan++)
{ outptr = ptr + chan ;
offset = psf->dataoffset + chan * psf->bytewidth * psf->read_current ;
if (psf_fseek (psf, offset, SEEK_SET) != offset)
{ psf->error = SFE_INTERLEAVE_SEEK ;
return 0 ;
} ;
templen = len / psf->sf.channels ;
while (templen > 0)
{ if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (double))
count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (double) ;
else
count = (int) templen ;
if (pdata->read_double (psf, inptr, count) != count)
{ psf->error = SFE_INTERLEAVE_READ ;
return 0 ;
} ;
for (k = 0 ; k < count ; k++)
{ *outptr = inptr [k] ;
outptr += psf->sf.channels ;
} ;
templen -= count ;
} ;
} ;
return len ;
} /* interleave_read_double */
/*------------------------------------------------------------------------------
*/
static sf_count_t
interleave_seek (SF_PRIVATE *psf, int mode, sf_count_t samples_from_start)
{ psf = psf ; mode = mode ;
/*
** Do nothing here. This is a place holder to prevent the default
** seek function from being called.
*/
return samples_from_start ;
} /* interleave_seek */

View File

@@ -0,0 +1,322 @@
/*
** Copyright (C) 2001-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
/*------------------------------------------------------------------------------
** Macros to handle big/little endian issues.
*/
/* The IRCAM magic number is weird in that one byte in the number can have
** values of 0x1, 0x2, 0x03 or 0x04. Hence the need for a marker and a mask.
*/
#define IRCAM_BE_MASK (MAKE_MARKER (0xFF, 0xFF, 0x00, 0xFF))
#define IRCAM_BE_MARKER (MAKE_MARKER (0x64, 0xA3, 0x00, 0x00))
#define IRCAM_LE_MASK (MAKE_MARKER (0xFF, 0x00, 0xFF, 0xFF))
#define IRCAM_LE_MARKER (MAKE_MARKER (0x00, 0x00, 0xA3, 0x64))
#define IRCAM_02B_MARKER (MAKE_MARKER (0x64, 0xA3, 0x02, 0x00))
#define IRCAM_03L_MARKER (MAKE_MARKER (0x64, 0xA3, 0x03, 0x00))
#define IRCAM_DATA_OFFSET (1024)
/*------------------------------------------------------------------------------
** Typedefs.
*/
enum
{ IRCAM_PCM_16 = 0x00002,
IRCAM_FLOAT = 0x00004,
IRCAM_ALAW = 0x10001,
IRCAM_ULAW = 0x20001,
IRCAM_PCM_32 = 0x40004
} ;
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int ircam_close (SF_PRIVATE *psf) ;
static int ircam_write_header (SF_PRIVATE *psf, int calc_length) ;
static int ircam_read_header (SF_PRIVATE *psf) ;
static int get_encoding (int subformat) ;
static const char* get_encoding_str (int encoding) ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
ircam_open (SF_PRIVATE *psf)
{ int subformat ;
int error = SFE_NO_ERROR ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = ircam_read_header (psf)))
return error ;
} ;
subformat = SF_CODEC (psf->sf.format) ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_IRCAM)
return SFE_BAD_OPEN_FORMAT ;
psf->endian = SF_ENDIAN (psf->sf.format) ;
if (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU)
psf->endian = (CPU_IS_BIG_ENDIAN) ? SF_ENDIAN_BIG : SF_ENDIAN_LITTLE ;
psf->dataoffset = IRCAM_DATA_OFFSET ;
if ((error = ircam_write_header (psf, SF_FALSE)))
return error ;
psf->write_header = ircam_write_header ;
} ;
psf->container_close = ircam_close ;
switch (subformat)
{ case SF_FORMAT_ULAW : /* 8-bit Ulaw encoding. */
error = ulaw_init (psf) ;
break ;
case SF_FORMAT_ALAW : /* 8-bit Alaw encoding. */
error = alaw_init (psf) ;
break ;
case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */
case SF_FORMAT_PCM_32 : /* 32-bit linear PCM. */
error = pcm_init (psf) ;
break ;
case SF_FORMAT_FLOAT : /* 32-bit linear PCM. */
error = float32_init (psf) ;
break ;
default : break ;
} ;
return error ;
} /* ircam_open */
/*------------------------------------------------------------------------------
*/
static int
ircam_read_header (SF_PRIVATE *psf)
{ unsigned int marker, encoding ;
float samplerate ;
int error = SFE_NO_ERROR ;
psf_binheader_readf (psf, "epmf44", 0, &marker, &samplerate, &(psf->sf.channels), &encoding) ;
if (((marker & IRCAM_BE_MASK) != IRCAM_BE_MARKER) && ((marker & IRCAM_LE_MASK) != IRCAM_LE_MARKER))
{ psf_log_printf (psf, "marker: 0x%X\n", marker) ;
return SFE_IRCAM_NO_MARKER ;
} ;
psf->endian = SF_ENDIAN_LITTLE ;
if (psf->sf.channels > 256)
{ psf_binheader_readf (psf, "Epmf44", 0, &marker, &samplerate, &(psf->sf.channels), &encoding) ;
/* Sanity checking for endian-ness detection. */
if (psf->sf.channels > 256)
{ psf_log_printf (psf, "marker: 0x%X\n", marker) ;
return SFE_IRCAM_BAD_CHANNELS ;
} ;
psf->endian = SF_ENDIAN_BIG ;
} ;
psf_log_printf (psf, "marker: 0x%X\n", marker) ;
psf->sf.samplerate = (int) samplerate ;
psf_log_printf (psf, " Sample Rate : %d\n"
" Channels : %d\n"
" Encoding : %X => %s\n", psf->sf.samplerate, psf->sf.channels, encoding, get_encoding_str (encoding)) ;
switch (encoding)
{ case IRCAM_PCM_16 :
psf->bytewidth = 2 ;
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_PCM_16 ;
break ;
case IRCAM_PCM_32 :
psf->bytewidth = 4 ;
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_PCM_32 ;
break ;
case IRCAM_FLOAT :
psf->bytewidth = 4 ;
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_FLOAT ;
break ;
case IRCAM_ALAW :
psf->bytewidth = 1 ;
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_ALAW ;
break ;
case IRCAM_ULAW :
psf->bytewidth = 1 ;
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_ULAW ;
break ;
default :
error = SFE_IRCAM_UNKNOWN_FORMAT ;
break ;
} ;
if (psf->endian == SF_ENDIAN_BIG)
psf->sf.format |= SF_ENDIAN_BIG ;
else
psf->sf.format |= SF_ENDIAN_LITTLE ;
if (error)
return error ;
psf->dataoffset = IRCAM_DATA_OFFSET ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf->sf.frames == 0 && psf->blockwidth)
psf->sf.frames = psf->datalength / psf->blockwidth ;
psf_log_printf (psf, " Samples : %d\n", psf->sf.frames) ;
psf_binheader_readf (psf, "p", IRCAM_DATA_OFFSET) ;
return 0 ;
} /* ircam_read_header */
static int
ircam_close (SF_PRIVATE *psf)
{
psf_log_printf (psf, "close\n") ;
return 0 ;
} /* ircam_close */
static int
ircam_write_header (SF_PRIVATE *psf, int UNUSED (calc_length))
{ int encoding ;
float samplerate ;
sf_count_t current ;
if (psf->pipeoffset > 0)
return 0 ;
current = psf_ftell (psf) ;
/* This also sets psf->endian. */
encoding = get_encoding (SF_CODEC (psf->sf.format)) ;
if (encoding == 0)
return SFE_BAD_OPEN_FORMAT ;
/* Reset the current header length to zero. */
psf->header [0] = 0 ;
psf->headindex = 0 ;
if (psf->is_pipe == SF_FALSE)
psf_fseek (psf, 0, SEEK_SET) ;
samplerate = psf->sf.samplerate ;
switch (psf->endian)
{ case SF_ENDIAN_BIG :
psf_binheader_writef (psf, "Emf", IRCAM_02B_MARKER, samplerate) ;
psf_binheader_writef (psf, "E44", psf->sf.channels, encoding) ;
break ;
case SF_ENDIAN_LITTLE :
psf_binheader_writef (psf, "emf", IRCAM_03L_MARKER, samplerate) ;
psf_binheader_writef (psf, "e44", psf->sf.channels, encoding) ;
break ;
default : return SFE_BAD_OPEN_FORMAT ;
} ;
psf_binheader_writef (psf, "z", (size_t) (IRCAM_DATA_OFFSET - psf->headindex)) ;
/* Header construction complete so write it out. */
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
if (psf->error)
return psf->error ;
if (current > 0)
psf_fseek (psf, current, SEEK_SET) ;
return psf->error ;
} /* ircam_write_header */
static int
get_encoding (int subformat)
{ switch (subformat)
{ case SF_FORMAT_PCM_16 : return IRCAM_PCM_16 ;
case SF_FORMAT_PCM_32 : return IRCAM_PCM_32 ;
case SF_FORMAT_FLOAT : return IRCAM_FLOAT ;
case SF_FORMAT_ULAW : return IRCAM_ULAW ;
case SF_FORMAT_ALAW : return IRCAM_ALAW ;
default : break ;
} ;
return 0 ;
} /* get_encoding */
static const char*
get_encoding_str (int encoding)
{ switch (encoding)
{ case IRCAM_PCM_16 : return "16 bit PCM" ;
case IRCAM_FLOAT : return "32 bit float" ;
case IRCAM_ALAW : return "A law" ;
case IRCAM_ULAW : return "u law" ;
case IRCAM_PCM_32 : return "32 bit PCM" ;
} ;
return "Unknown encoding" ;
} /* get_encoding_str */

View File

@@ -0,0 +1,45 @@
/*
** Copyright (C) 2003-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdlib.h>
#include <string.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#if (OS_IS_MACOSX == 1)
int
macbinary3_open (SF_PRIVATE * UNUSED (psf))
{
return 0 ;
} /* macbinary3_open */
#else
int
macbinary3_open (SF_PRIVATE * UNUSED (psf))
{
return 0 ;
} /* macbinary3_open */
#endif /* OS_IS_MACOSX */

View File

@@ -0,0 +1,51 @@
/*
** Copyright (C) 2003-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#define STR_MARKER MAKE_MARKER ('S', 'T', 'R', ' ')
int
macos_guess_file_type (SF_PRIVATE * psf, const char *filename)
{ static char rsrc_name [1024] ;
struct stat statbuf ;
snprintf (rsrc_name, sizeof (rsrc_name), "%s/rsrc", filename) ;
/* If there is no resource fork, just return. */
if (stat (rsrc_name, &statbuf) != 0)
{ psf_log_printf (psf, "No resource fork.\n") ;
return 0 ;
} ;
if (statbuf.st_size == 0)
{ psf_log_printf (psf, "Have zero size resource fork.\n") ;
return 0 ;
} ;
return 0 ;
} /* macos_guess_file_type */

View File

@@ -0,0 +1,389 @@
/*
** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
/*------------------------------------------------------------------------------
** Information on how to decode and encode this file was obtained in a PDF
** file which I found on http://www.wotsit.org/.
** Also did a lot of testing with GNU Octave but do not have access to
** Matlab (tm) and so could not test it there.
*/
/*------------------------------------------------------------------------------
** Macros to handle big/little endian issues.
*/
#define MAT4_BE_DOUBLE (MAKE_MARKER (0, 0, 0x03, 0xE8))
#define MAT4_LE_DOUBLE (MAKE_MARKER (0, 0, 0, 0))
#define MAT4_BE_FLOAT (MAKE_MARKER (0, 0, 0x03, 0xF2))
#define MAT4_LE_FLOAT (MAKE_MARKER (0x0A, 0, 0, 0))
#define MAT4_BE_PCM_32 (MAKE_MARKER (0, 0, 0x03, 0xFC))
#define MAT4_LE_PCM_32 (MAKE_MARKER (0x14, 0, 0, 0))
#define MAT4_BE_PCM_16 (MAKE_MARKER (0, 0, 0x04, 0x06))
#define MAT4_LE_PCM_16 (MAKE_MARKER (0x1E, 0, 0, 0))
/* Can't see any reason to ever implement this. */
#define MAT4_BE_PCM_U8 (MAKE_MARKER (0, 0, 0x04, 0x1A))
#define MAT4_LE_PCM_U8 (MAKE_MARKER (0x32, 0, 0, 0))
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int mat4_close (SF_PRIVATE *psf) ;
static int mat4_format_to_encoding (int format, int endian) ;
static int mat4_write_header (SF_PRIVATE *psf, int calc_length) ;
static int mat4_read_header (SF_PRIVATE *psf) ;
static const char * mat4_marker_to_str (int marker) ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
mat4_open (SF_PRIVATE *psf)
{ int subformat, error = 0 ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = mat4_read_header (psf)))
return error ;
} ;
if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_MAT4)
return SFE_BAD_OPEN_FORMAT ;
subformat = SF_CODEC (psf->sf.format) ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if (psf->is_pipe)
return SFE_NO_PIPE_WRITE ;
psf->endian = SF_ENDIAN (psf->sf.format) ;
if (CPU_IS_LITTLE_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0))
psf->endian = SF_ENDIAN_LITTLE ;
else if (CPU_IS_BIG_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0))
psf->endian = SF_ENDIAN_BIG ;
if ((error = mat4_write_header (psf, SF_FALSE)))
return error ;
psf->write_header = mat4_write_header ;
} ;
psf->container_close = mat4_close ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
switch (subformat)
{ case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_32 :
error = pcm_init (psf) ;
break ;
case SF_FORMAT_FLOAT :
error = float32_init (psf) ;
break ;
case SF_FORMAT_DOUBLE :
error = double64_init (psf) ;
break ;
default : break ;
} ;
if (error)
return error ;
return error ;
} /* mat4_open */
/*------------------------------------------------------------------------------
*/
static int
mat4_close (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
mat4_write_header (psf, SF_TRUE) ;
return 0 ;
} /* mat4_close */
/*------------------------------------------------------------------------------
*/
static int
mat4_write_header (SF_PRIVATE *psf, int calc_length)
{ sf_count_t current ;
int encoding ;
double samplerate ;
current = psf_ftell (psf) ;
if (calc_length)
{ psf->filelength = psf_get_filelen (psf) ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf->dataend)
psf->datalength -= psf->filelength - psf->dataend ;
psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
} ;
encoding = mat4_format_to_encoding (SF_CODEC (psf->sf.format), psf->endian) ;
if (encoding == -1)
return SFE_BAD_OPEN_FORMAT ;
/* Reset the current header length to zero. */
psf->header [0] = 0 ;
psf->headindex = 0 ;
psf_fseek (psf, 0, SEEK_SET) ;
/* Need sample rate as a double for writing to the header. */
samplerate = psf->sf.samplerate ;
if (psf->endian == SF_ENDIAN_BIG)
{ psf_binheader_writef (psf, "Em444", MAT4_BE_DOUBLE, 1, 1, 0) ;
psf_binheader_writef (psf, "E4bd", 11, "samplerate", make_size_t (11), samplerate) ;
psf_binheader_writef (psf, "tEm484", encoding, psf->sf.channels, psf->sf.frames, 0) ;
psf_binheader_writef (psf, "E4b", 9, "wavedata", make_size_t (9)) ;
}
else if (psf->endian == SF_ENDIAN_LITTLE)
{ psf_binheader_writef (psf, "em444", MAT4_LE_DOUBLE, 1, 1, 0) ;
psf_binheader_writef (psf, "e4bd", 11, "samplerate", make_size_t (11), samplerate) ;
psf_binheader_writef (psf, "tem484", encoding, psf->sf.channels, psf->sf.frames, 0) ;
psf_binheader_writef (psf, "e4b", 9, "wavedata", make_size_t (9)) ;
}
else
return SFE_BAD_OPEN_FORMAT ;
/* Header construction complete so write it out. */
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
if (psf->error)
return psf->error ;
psf->dataoffset = psf->headindex ;
if (current > 0)
psf_fseek (psf, current, SEEK_SET) ;
return psf->error ;
} /* mat4_write_header */
static int
mat4_read_header (SF_PRIVATE *psf)
{ int marker, rows, cols, imag ;
unsigned namesize ;
double value ;
const char *marker_str ;
char name [64] ;
psf_binheader_readf (psf, "pm", 0, &marker) ;
/* MAT4 file must start with a double for the samplerate. */
if (marker == MAT4_BE_DOUBLE)
{ psf->endian = psf->rwf_endian = SF_ENDIAN_BIG ;
marker_str = "big endian double" ;
}
else if (marker == MAT4_LE_DOUBLE)
{ psf->endian = psf->rwf_endian = SF_ENDIAN_LITTLE ;
marker_str = "little endian double" ;
}
else
return SFE_UNIMPLEMENTED ;
psf_log_printf (psf, "GNU Octave 2.0 / MATLAB v4.2 format\nMarker : %s\n", marker_str) ;
psf_binheader_readf (psf, "444", &rows, &cols, &imag) ;
psf_log_printf (psf, " Rows : %d\n Cols : %d\n Imag : %s\n", rows, cols, imag ? "True" : "False") ;
psf_binheader_readf (psf, "4", &namesize) ;
if (namesize >= SIGNED_SIZEOF (name))
return SFE_MAT4_BAD_NAME ;
psf_binheader_readf (psf, "b", name, namesize) ;
name [namesize] = 0 ;
psf_log_printf (psf, " Name : %s\n", name) ;
psf_binheader_readf (psf, "d", &value) ;
snprintf (psf->u.cbuf, sizeof (psf->u.cbuf), " Value : %f\n", value) ;
psf_log_printf (psf, psf->u.cbuf) ;
if ((rows != 1) || (cols != 1))
return SFE_MAT4_NO_SAMPLERATE ;
psf->sf.samplerate = lrint (value) ;
/* Now write out the audio data. */
psf_binheader_readf (psf, "m", &marker) ;
psf_log_printf (psf, "Marker : %s\n", mat4_marker_to_str (marker)) ;
psf_binheader_readf (psf, "444", &rows, &cols, &imag) ;
psf_log_printf (psf, " Rows : %d\n Cols : %d\n Imag : %s\n", rows, cols, imag ? "True" : "False") ;
psf_binheader_readf (psf, "4", &namesize) ;
if (namesize >= SIGNED_SIZEOF (name))
return SFE_MAT4_BAD_NAME ;
psf_binheader_readf (psf, "b", name, namesize) ;
name [namesize] = 0 ;
psf_log_printf (psf, " Name : %s\n", name) ;
psf->dataoffset = psf_ftell (psf) ;
if (rows == 0 && cols == 0)
{ psf_log_printf (psf, "*** Error : zero channel count.\n") ;
return SFE_CHANNEL_COUNT_ZERO ;
} ;
psf->sf.channels = rows ;
psf->sf.frames = cols ;
psf->sf.format = psf->endian | SF_FORMAT_MAT4 ;
switch (marker)
{ case MAT4_BE_DOUBLE :
case MAT4_LE_DOUBLE :
psf->sf.format |= SF_FORMAT_DOUBLE ;
psf->bytewidth = 8 ;
break ;
case MAT4_BE_FLOAT :
case MAT4_LE_FLOAT :
psf->sf.format |= SF_FORMAT_FLOAT ;
psf->bytewidth = 4 ;
break ;
case MAT4_BE_PCM_32 :
case MAT4_LE_PCM_32 :
psf->sf.format |= SF_FORMAT_PCM_32 ;
psf->bytewidth = 4 ;
break ;
case MAT4_BE_PCM_16 :
case MAT4_LE_PCM_16 :
psf->sf.format |= SF_FORMAT_PCM_16 ;
psf->bytewidth = 2 ;
break ;
default :
psf_log_printf (psf, "*** Error : Bad marker %08X\n", marker) ;
return SFE_UNIMPLEMENTED ;
} ;
if ((psf->filelength - psf->dataoffset) < psf->sf.channels * psf->sf.frames * psf->bytewidth)
{ psf_log_printf (psf, "*** File seems to be truncated. %D <--> %D\n",
psf->filelength - psf->dataoffset, psf->sf.channels * psf->sf.frames * psf->bytewidth) ;
}
else if ((psf->filelength - psf->dataoffset) > psf->sf.channels * psf->sf.frames * psf->bytewidth)
psf->dataend = psf->dataoffset + rows * cols * psf->bytewidth ;
psf->datalength = psf->filelength - psf->dataoffset - psf->dataend ;
psf->sf.sections = 1 ;
return 0 ;
} /* mat4_read_header */
static int
mat4_format_to_encoding (int format, int endian)
{
switch (format | endian)
{ case (SF_FORMAT_PCM_16 | SF_ENDIAN_BIG) :
return MAT4_BE_PCM_16 ;
case (SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE) :
return MAT4_LE_PCM_16 ;
case (SF_FORMAT_PCM_32 | SF_ENDIAN_BIG) :
return MAT4_BE_PCM_32 ;
case (SF_FORMAT_PCM_32 | SF_ENDIAN_LITTLE) :
return MAT4_LE_PCM_32 ;
case (SF_FORMAT_FLOAT | SF_ENDIAN_BIG) :
return MAT4_BE_FLOAT ;
case (SF_FORMAT_FLOAT | SF_ENDIAN_LITTLE) :
return MAT4_LE_FLOAT ;
case (SF_FORMAT_DOUBLE | SF_ENDIAN_BIG) :
return MAT4_BE_DOUBLE ;
case (SF_FORMAT_DOUBLE | SF_ENDIAN_LITTLE) :
return MAT4_LE_DOUBLE ;
default : break ;
} ;
return -1 ;
} /* mat4_format_to_encoding */
static const char *
mat4_marker_to_str (int marker)
{ static char str [32] ;
switch (marker)
{
case MAT4_BE_PCM_16 : return "big endian 16 bit PCM" ;
case MAT4_LE_PCM_16 : return "little endian 16 bit PCM" ;
case MAT4_BE_PCM_32 : return "big endian 32 bit PCM" ;
case MAT4_LE_PCM_32 : return "little endian 32 bit PCM" ;
case MAT4_BE_FLOAT : return "big endian float" ;
case MAT4_LE_FLOAT : return "big endian float" ;
case MAT4_BE_DOUBLE : return "big endian double" ;
case MAT4_LE_DOUBLE : return "little endian double" ;
} ;
/* This is a little unsafe but is really only for debugging. */
str [sizeof (str) - 1] = 0 ;
snprintf (str, sizeof (str) - 1, "%08X", marker) ;
return str ;
} /* mat4_marker_to_str */

View File

@@ -0,0 +1,501 @@
/*
** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
/*------------------------------------------------------------------------------
** Information on how to decode and encode this file was obtained in a PDF
** file which I found on http://www.wotsit.org/.
** Also did a lot of testing with GNU Octave but do not have access to
** Matlab (tm) and so could not test it there.
*/
/*------------------------------------------------------------------------------
** Macros to handle big/little endian issues.
*/
#define MATL_MARKER (MAKE_MARKER ('M', 'A', 'T', 'L'))
#define IM_MARKER (('I' << 8) + 'M')
#define MI_MARKER (('M' << 8) + 'I')
/*------------------------------------------------------------------------------
** Enums and typedefs.
*/
enum
{ MAT5_TYPE_SCHAR = 0x1,
MAT5_TYPE_UCHAR = 0x2,
MAT5_TYPE_INT16 = 0x3,
MAT5_TYPE_UINT16 = 0x4,
MAT5_TYPE_INT32 = 0x5,
MAT5_TYPE_UINT32 = 0x6,
MAT5_TYPE_FLOAT = 0x7,
MAT5_TYPE_DOUBLE = 0x9,
MAT5_TYPE_ARRAY = 0xE,
MAT5_TYPE_COMP_USHORT = 0x00020004,
MAT5_TYPE_COMP_UINT = 0x00040006
} ;
typedef struct
{ sf_count_t size ;
int rows, cols ;
char name [32] ;
} MAT5_MATRIX ;
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int mat5_close (SF_PRIVATE *psf) ;
static int mat5_write_header (SF_PRIVATE *psf, int calc_length) ;
static int mat5_read_header (SF_PRIVATE *psf) ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
mat5_open (SF_PRIVATE *psf)
{ int subformat, error = 0 ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = mat5_read_header (psf)))
return error ;
} ;
if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_MAT5)
return SFE_BAD_OPEN_FORMAT ;
subformat = SF_CODEC (psf->sf.format) ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if (psf->is_pipe)
return SFE_NO_PIPE_WRITE ;
psf->endian = SF_ENDIAN (psf->sf.format) ;
if (CPU_IS_LITTLE_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0))
psf->endian = SF_ENDIAN_LITTLE ;
else if (CPU_IS_BIG_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0))
psf->endian = SF_ENDIAN_BIG ;
if ((error = mat5_write_header (psf, SF_FALSE)))
return error ;
psf->write_header = mat5_write_header ;
} ;
psf->container_close = mat5_close ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
switch (subformat)
{ case SF_FORMAT_PCM_U8 :
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_32 :
error = pcm_init (psf) ;
break ;
case SF_FORMAT_FLOAT :
error = float32_init (psf) ;
break ;
case SF_FORMAT_DOUBLE :
error = double64_init (psf) ;
break ;
default : break ;
} ;
return error ;
} /* mat5_open */
/*------------------------------------------------------------------------------
*/
static int
mat5_close (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
mat5_write_header (psf, SF_TRUE) ;
return 0 ;
} /* mat5_close */
/*------------------------------------------------------------------------------
*/
static int
mat5_write_header (SF_PRIVATE *psf, int calc_length)
{ static const char *filename = "MATLAB 5.0 MAT-file, written by " PACKAGE "-" VERSION ", " ;
static const char *sr_name = "samplerate\0\0\0\0\0\0\0\0\0\0\0" ;
static const char *wd_name = "wavedata\0" ;
sf_count_t current, datasize ;
int encoding ;
current = psf_ftell (psf) ;
if (calc_length)
{ psf_fseek (psf, 0, SEEK_END) ;
psf->filelength = psf_ftell (psf) ;
psf_fseek (psf, 0, SEEK_SET) ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf->dataend)
psf->datalength -= psf->filelength - psf->dataend ;
psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
} ;
switch (SF_CODEC (psf->sf.format))
{ case SF_FORMAT_PCM_U8 :
encoding = MAT5_TYPE_UCHAR ;
break ;
case SF_FORMAT_PCM_16 :
encoding = MAT5_TYPE_INT16 ;
break ;
case SF_FORMAT_PCM_32 :
encoding = MAT5_TYPE_INT32 ;
break ;
case SF_FORMAT_FLOAT :
encoding = MAT5_TYPE_FLOAT ;
break ;
case SF_FORMAT_DOUBLE :
encoding = MAT5_TYPE_DOUBLE ;
break ;
default :
return SFE_BAD_OPEN_FORMAT ;
} ;
/* Reset the current header length to zero. */
psf->header [0] = 0 ;
psf->headindex = 0 ;
psf_fseek (psf, 0, SEEK_SET) ;
psf_get_date_str (psf->u.cbuf, sizeof (psf->u.scbuf)) ;
psf_binheader_writef (psf, "bb", filename, strlen (filename), psf->u.cbuf, strlen (psf->u.cbuf) + 1) ;
memset (psf->u.scbuf, ' ', 124 - psf->headindex) ;
psf_binheader_writef (psf, "b", psf->u.scbuf, make_size_t (124 - psf->headindex)) ;
psf->rwf_endian = psf->endian ;
if (psf->rwf_endian == SF_ENDIAN_BIG)
psf_binheader_writef (psf, "2b", 0x0100, "MI", make_size_t (2)) ;
else
psf_binheader_writef (psf, "2b", 0x0100, "IM", make_size_t (2)) ;
psf_binheader_writef (psf, "444444", MAT5_TYPE_ARRAY, 64, MAT5_TYPE_UINT32, 8, 6, 0) ;
psf_binheader_writef (psf, "4444", MAT5_TYPE_INT32, 8, 1, 1) ;
psf_binheader_writef (psf, "44b", MAT5_TYPE_SCHAR, strlen (sr_name), sr_name, make_size_t (16)) ;
if (psf->sf.samplerate > 0xFFFF)
psf_binheader_writef (psf, "44", MAT5_TYPE_COMP_UINT, psf->sf.samplerate) ;
else
{ unsigned short samplerate = psf->sf.samplerate ;
psf_binheader_writef (psf, "422", MAT5_TYPE_COMP_USHORT, samplerate, 0) ;
} ;
datasize = psf->sf.frames * psf->sf.channels * psf->bytewidth ;
psf_binheader_writef (psf, "t484444", MAT5_TYPE_ARRAY, datasize + 64, MAT5_TYPE_UINT32, 8, 6, 0) ;
psf_binheader_writef (psf, "t4448", MAT5_TYPE_INT32, 8, psf->sf.channels, psf->sf.frames) ;
psf_binheader_writef (psf, "44b", MAT5_TYPE_SCHAR, strlen (wd_name), wd_name, strlen (wd_name)) ;
datasize = psf->sf.frames * psf->sf.channels * psf->bytewidth ;
if (datasize > 0x7FFFFFFF)
datasize = 0x7FFFFFFF ;
psf_binheader_writef (psf, "t48", encoding, datasize) ;
/* Header construction complete so write it out. */
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
if (psf->error)
return psf->error ;
psf->dataoffset = psf->headindex ;
if (current > 0)
psf_fseek (psf, current, SEEK_SET) ;
return psf->error ;
} /* mat5_write_header */
static int
mat5_read_header (SF_PRIVATE *psf)
{ char name [32] ;
short version, endian ;
int type, flags1, flags2, rows, cols ;
unsigned size ;
psf_binheader_readf (psf, "pb", 0, psf->u.cbuf, 124) ;
psf->u.scbuf [125] = 0 ;
if (strlen (psf->u.cbuf) >= 124)
return SFE_UNIMPLEMENTED ;
if (strstr (psf->u.cbuf, "MATLAB 5.0 MAT-file") == psf->u.cbuf)
psf_log_printf (psf, "%s\n", psf->u.scbuf) ;
psf_binheader_readf (psf, "E22", &version, &endian) ;
if (endian == MI_MARKER)
{ psf->endian = psf->rwf_endian = SF_ENDIAN_BIG ;
if (CPU_IS_LITTLE_ENDIAN) version = ENDSWAP_SHORT (version) ;
}
else if (endian == IM_MARKER)
{ psf->endian = psf->rwf_endian = SF_ENDIAN_LITTLE ;
if (CPU_IS_BIG_ENDIAN) version = ENDSWAP_SHORT (version) ;
}
else
return SFE_MAT5_BAD_ENDIAN ;
if ((CPU_IS_LITTLE_ENDIAN && endian == IM_MARKER) ||
(CPU_IS_BIG_ENDIAN && endian == MI_MARKER))
version = ENDSWAP_SHORT (version) ;
psf_log_printf (psf, "Version : 0x%04X\n", version) ;
psf_log_printf (psf, "Endian : 0x%04X => %s\n", endian,
(psf->endian == SF_ENDIAN_LITTLE) ? "Little" : "Big") ;
/*========================================================*/
psf_binheader_readf (psf, "44", &type, &size) ;
psf_log_printf (psf, "Block\n Type : %X Size : %d\n", type, size) ;
if (type != MAT5_TYPE_ARRAY)
return SFE_MAT5_NO_BLOCK ;
psf_binheader_readf (psf, "44", &type, &size) ;
psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
if (type != MAT5_TYPE_UINT32)
return SFE_MAT5_NO_BLOCK ;
psf_binheader_readf (psf, "44", &flags1, &flags2) ;
psf_log_printf (psf, " Flg1 : %X Flg2 : %d\n", flags1, flags2) ;
psf_binheader_readf (psf, "44", &type, &size) ;
psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
if (type != MAT5_TYPE_INT32)
return SFE_MAT5_NO_BLOCK ;
psf_binheader_readf (psf, "44", &rows, &cols) ;
psf_log_printf (psf, " Rows : %X Cols : %d\n", rows, cols) ;
if (rows != 1 || cols != 1)
return SFE_MAT5_SAMPLE_RATE ;
psf_binheader_readf (psf, "4", &type) ;
if (type == MAT5_TYPE_SCHAR)
{ psf_binheader_readf (psf, "4", &size) ;
psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
if (size > SIGNED_SIZEOF (name) - 1)
{ psf_log_printf (psf, "Error : Bad name length.\n") ;
return SFE_MAT5_NO_BLOCK ;
} ;
psf_binheader_readf (psf, "bj", name, size, (8 - (size % 8)) % 8) ;
name [size] = 0 ;
}
else if ((type & 0xFFFF) == MAT5_TYPE_SCHAR)
{ size = type >> 16 ;
if (size > 4)
{ psf_log_printf (psf, "Error : Bad name length.\n") ;
return SFE_MAT5_NO_BLOCK ;
} ;
psf_log_printf (psf, " Type : %X\n", type) ;
psf_binheader_readf (psf, "4", &name) ;
name [size] = 0 ;
}
else
return SFE_MAT5_NO_BLOCK ;
psf_log_printf (psf, " Name : %s\n", name) ;
/*-----------------------------------------*/
psf_binheader_readf (psf, "44", &type, &size) ;
switch (type)
{ case MAT5_TYPE_DOUBLE :
{ double samplerate ;
psf_binheader_readf (psf, "d", &samplerate) ;
snprintf (name, sizeof (name), "%f\n", samplerate) ;
psf_log_printf (psf, " Val : %s\n", name) ;
psf->sf.samplerate = lrint (samplerate) ;
} ;
break ;
case MAT5_TYPE_COMP_USHORT :
{ unsigned short samplerate ;
psf_binheader_readf (psf, "j2j", -4, &samplerate, 2) ;
psf_log_printf (psf, " Val : %u\n", samplerate) ;
psf->sf.samplerate = samplerate ;
}
break ;
case MAT5_TYPE_COMP_UINT :
psf_log_printf (psf, " Val : %u\n", size) ;
psf->sf.samplerate = size ;
break ;
default :
psf_log_printf (psf, " Type : %X Size : %d ***\n", type, size) ;
return SFE_MAT5_SAMPLE_RATE ;
} ;
/*-----------------------------------------*/
psf_binheader_readf (psf, "44", &type, &size) ;
psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
if (type != MAT5_TYPE_ARRAY)
return SFE_MAT5_NO_BLOCK ;
psf_binheader_readf (psf, "44", &type, &size) ;
psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
if (type != MAT5_TYPE_UINT32)
return SFE_MAT5_NO_BLOCK ;
psf_binheader_readf (psf, "44", &flags1, &flags2) ;
psf_log_printf (psf, " Flg1 : %X Flg2 : %d\n", flags1, flags2) ;
psf_binheader_readf (psf, "44", &type, &size) ;
psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
if (type != MAT5_TYPE_INT32)
return SFE_MAT5_NO_BLOCK ;
psf_binheader_readf (psf, "44", &rows, &cols) ;
psf_log_printf (psf, " Rows : %X Cols : %d\n", rows, cols) ;
psf_binheader_readf (psf, "4", &type) ;
if (type == MAT5_TYPE_SCHAR)
{ psf_binheader_readf (psf, "4", &size) ;
psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
if (size > SIGNED_SIZEOF (name) - 1)
{ psf_log_printf (psf, "Error : Bad name length.\n") ;
return SFE_MAT5_NO_BLOCK ;
} ;
psf_binheader_readf (psf, "bj", name, size, (8 - (size % 8)) % 8) ;
name [size] = 0 ;
}
else if ((type & 0xFFFF) == MAT5_TYPE_SCHAR)
{ size = type >> 16 ;
if (size > 4)
{ psf_log_printf (psf, "Error : Bad name length.\n") ;
return SFE_MAT5_NO_BLOCK ;
} ;
psf_log_printf (psf, " Type : %X\n", type) ;
psf_binheader_readf (psf, "4", &name) ;
name [size] = 0 ;
}
else
return SFE_MAT5_NO_BLOCK ;
psf_log_printf (psf, " Name : %s\n", name) ;
psf_binheader_readf (psf, "44", &type, &size) ;
psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
/*++++++++++++++++++++++++++++++++++++++++++++++++++*/
if (rows == 0 && cols == 0)
{ psf_log_printf (psf, "*** Error : zero channel count.\n") ;
return SFE_CHANNEL_COUNT_ZERO ;
} ;
psf->sf.channels = rows ;
psf->sf.frames = cols ;
psf->sf.format = psf->endian | SF_FORMAT_MAT5 ;
switch (type)
{ case MAT5_TYPE_DOUBLE :
psf_log_printf (psf, "Data type : double\n") ;
psf->sf.format |= SF_FORMAT_DOUBLE ;
psf->bytewidth = 8 ;
break ;
case MAT5_TYPE_FLOAT :
psf_log_printf (psf, "Data type : float\n") ;
psf->sf.format |= SF_FORMAT_FLOAT ;
psf->bytewidth = 4 ;
break ;
case MAT5_TYPE_INT32 :
psf_log_printf (psf, "Data type : 32 bit PCM\n") ;
psf->sf.format |= SF_FORMAT_PCM_32 ;
psf->bytewidth = 4 ;
break ;
case MAT5_TYPE_INT16 :
psf_log_printf (psf, "Data type : 16 bit PCM\n") ;
psf->sf.format |= SF_FORMAT_PCM_16 ;
psf->bytewidth = 2 ;
break ;
case MAT5_TYPE_UCHAR :
psf_log_printf (psf, "Data type : unsigned 8 bit PCM\n") ;
psf->sf.format |= SF_FORMAT_PCM_U8 ;
psf->bytewidth = 1 ;
break ;
default :
psf_log_printf (psf, "*** Error : Bad marker %08X\n", type) ;
return SFE_UNIMPLEMENTED ;
} ;
psf->dataoffset = psf_ftell (psf) ;
psf->datalength = psf->filelength - psf->dataoffset ;
return 0 ;
} /* mat5_read_header */

View File

@@ -0,0 +1,204 @@
/*
** Copyright (C) 2008-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
/*
** Info from Olivier Tristan <o.tristan@ultimatesoundbank.com>
**
** HEADER
** 2 magic bytes: 1 and 4.
** 17 char for the name of the sample.
** 3 bytes: level, tune and channels (0 for channels is mono while 1 is stereo)
** 4 uint32: sampleStart, loopEnd, sampleFrames and loopLength
** 1 byte: loopMode (0 no loop, 1 forward looping)
** 1 byte: number of beat in loop
** 1 uint16: sampleRate
**
** DATA
** Data are always non compressed 16 bits interleaved
*/
#define HEADER_LENGTH 42 /* Sum of above data fields. */
#define HEADER_NAME_LEN 17 /* Length of name string. */
#define SFE_MPC_NO_MARKER 666
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int mpc2k_close (SF_PRIVATE *psf) ;
static int mpc2k_write_header (SF_PRIVATE *psf, int calc_length) ;
static int mpc2k_read_header (SF_PRIVATE *psf) ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
mpc2k_open (SF_PRIVATE *psf)
{ int error = 0 ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = mpc2k_read_header (psf)))
return error ;
} ;
if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_MPC2K)
return SFE_BAD_OPEN_FORMAT ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if (mpc2k_write_header (psf, SF_FALSE))
return psf->error ;
psf->write_header = mpc2k_write_header ;
} ;
psf->container_close = mpc2k_close ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
error = pcm_init (psf) ;
return error ;
} /* mpc2k_open */
/*------------------------------------------------------------------------------
*/
static int
mpc2k_close (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
mpc2k_write_header (psf, SF_TRUE) ;
return 0 ;
} /* mpc2k_close */
static int
mpc2k_write_header (SF_PRIVATE *psf, int calc_length)
{ char sample_name [HEADER_NAME_LEN + 1] ;
sf_count_t current ;
if (psf->pipeoffset > 0)
return 0 ;
current = psf_ftell (psf) ;
if (calc_length)
{ psf->filelength = psf_get_filelen (psf) ;
psf->dataoffset = HEADER_LENGTH ;
psf->datalength = psf->filelength - psf->dataoffset ;
psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
} ;
/* Reset the current header length to zero. */
psf->header [0] = 0 ;
psf->headindex = 0 ;
/*
** Only attempt to seek if we are not writng to a pipe. If we are
** writing to a pipe we shouldn't be here anyway.
*/
if (psf->is_pipe == SF_FALSE)
psf_fseek (psf, 0, SEEK_SET) ;
snprintf (sample_name, sizeof (sample_name), "%s ", psf->file.name.c) ;
psf_binheader_writef (psf, "e11b", 1, 4, sample_name, make_size_t (HEADER_NAME_LEN)) ;
psf_binheader_writef (psf, "e111", 100, 0, (psf->sf.channels - 1) & 1) ;
psf_binheader_writef (psf, "et4888", 0, psf->sf.frames, psf->sf.frames, psf->sf.frames) ;
psf_binheader_writef (psf, "e112", 0, 1, (uint16_t) psf->sf.samplerate) ;
/* Always 16 bit little endian data. */
psf->bytewidth = 2 ;
psf->endian = SF_ENDIAN_LITTLE ;
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
if (psf->error)
return psf->error ;
psf->dataoffset = psf->headindex ;
if (current > 0)
psf_fseek (psf, current, SEEK_SET) ;
return psf->error ;
} /* mpc2k_write_header */
static int
mpc2k_read_header (SF_PRIVATE *psf)
{ char sample_name [HEADER_NAME_LEN + 1] ;
unsigned char bytes [4] ;
uint32_t sample_start, loop_end, sample_frames, loop_length ;
uint16_t sample_rate ;
psf_binheader_readf (psf, "pebb", 0, bytes, 2, sample_name, make_size_t (HEADER_NAME_LEN)) ;
if (bytes [0] != 1 || bytes [1] != 4)
return SFE_MPC_NO_MARKER ;
sample_name [HEADER_NAME_LEN] = 0 ;
psf_log_printf (psf, "MPC2000\n Name : %s\n", sample_name) ;
psf_binheader_readf (psf, "eb4444", bytes, 3, &sample_start, &loop_end, &sample_frames, &loop_length) ;
psf->sf.channels = bytes [2] ? 2 : 1 ;
psf_log_printf (psf, " Level : %d\n Tune : %d\n Stereo : %s\n", bytes [0], bytes [1], bytes [2] ? "Yes" : "No") ;
psf_log_printf (psf, " Sample start : %d\n Loop end : %d\n Frames : %d\n Length : %d\n", sample_start, loop_end, sample_frames, loop_length) ;
psf_binheader_readf (psf, "eb2", bytes, 2, &sample_rate) ;
psf_log_printf (psf, " Loop mode : %s\n Beats : %d\n Sample rate : %d\nEnd\n", bytes [0] ? "None" : "Fwd", bytes [1], sample_rate) ;
psf->sf.samplerate = sample_rate ;
psf->sf.format = SF_FORMAT_MPC2K | SF_FORMAT_PCM_16 ;
psf->dataoffset = psf_ftell (psf) ;
/* Always 16 bit little endian data. */
psf->bytewidth = 2 ;
psf->endian = SF_ENDIAN_LITTLE ;
psf->datalength = psf->filelength - psf->dataoffset ;
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
psf->sf.frames = psf->datalength / psf->blockwidth ;
psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ;
return 0 ;
} /* mpc2k_read_header */

View File

@@ -0,0 +1,834 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#include "wav_w64.h"
/* These required here because we write the header in this file. */
#define RIFF_MARKER (MAKE_MARKER ('R', 'I', 'F', 'F'))
#define WAVE_MARKER (MAKE_MARKER ('W', 'A', 'V', 'E'))
#define fmt_MARKER (MAKE_MARKER ('f', 'm', 't', ' '))
#define fact_MARKER (MAKE_MARKER ('f', 'a', 'c', 't'))
#define data_MARKER (MAKE_MARKER ('d', 'a', 't', 'a'))
#define WAVE_FORMAT_MS_ADPCM 0x0002
typedef struct
{ int channels, blocksize, samplesperblock, blocks, dataremaining ;
int blockcount ;
sf_count_t samplecount ;
short *samples ;
unsigned char *block ;
#if HAVE_FLEXIBLE_ARRAY
short dummydata [] ; /* ISO C99 struct flexible array. */
#else
short dummydata [0] ; /* This is a hack an might not work. */
#endif
} MSADPCM_PRIVATE ;
/*============================================================================================
** MS ADPCM static data and functions.
*/
static int AdaptationTable [] =
{ 230, 230, 230, 230, 307, 409, 512, 614,
768, 614, 512, 409, 307, 230, 230, 230
} ;
/* TODO : The first 7 coef's are are always hardcode and must
appear in the actual WAVE file. They should be read in
in case a sound program added extras to the list. */
static int AdaptCoeff1 [MSADPCM_ADAPT_COEFF_COUNT] =
{ 256, 512, 0, 192, 240, 460, 392
} ;
static int AdaptCoeff2 [MSADPCM_ADAPT_COEFF_COUNT] =
{ 0, -256, 0, 64, 0, -208, -232
} ;
/*============================================================================================
** MS ADPCM Block Layout.
** ======================
** Block is usually 256, 512 or 1024 bytes depending on sample rate.
** For a mono file, the block is laid out as follows:
** byte purpose
** 0 block predictor [0..6]
** 1,2 initial idelta (positive)
** 3,4 sample 1
** 5,6 sample 0
** 7..n packed bytecodes
**
** For a stereo file, the block is laid out as follows:
** byte purpose
** 0 block predictor [0..6] for left channel
** 1 block predictor [0..6] for right channel
** 2,3 initial idelta (positive) for left channel
** 4,5 initial idelta (positive) for right channel
** 6,7 sample 1 for left channel
** 8,9 sample 1 for right channel
** 10,11 sample 0 for left channel
** 12,13 sample 0 for right channel
** 14..n packed bytecodes
*/
/*============================================================================================
** Static functions.
*/
static int msadpcm_decode_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms) ;
static sf_count_t msadpcm_read_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms, short *ptr, int len) ;
static int msadpcm_encode_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms) ;
static sf_count_t msadpcm_write_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms, const short *ptr, int len) ;
static sf_count_t msadpcm_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
static sf_count_t msadpcm_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
static sf_count_t msadpcm_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
static sf_count_t msadpcm_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
static sf_count_t msadpcm_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
static sf_count_t msadpcm_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
static sf_count_t msadpcm_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
static sf_count_t msadpcm_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
static sf_count_t msadpcm_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
static int msadpcm_close (SF_PRIVATE *psf) ;
static void choose_predictor (unsigned int channels, short *data, int *bpred, int *idelta) ;
/*============================================================================================
** MS ADPCM Read Functions.
*/
int
wav_w64_msadpcm_init (SF_PRIVATE *psf, int blockalign, int samplesperblock)
{ MSADPCM_PRIVATE *pms ;
unsigned int pmssize ;
int count ;
if (psf->codec_data != NULL)
{ psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ;
return SFE_INTERNAL ;
} ;
if (psf->file.mode == SFM_WRITE)
samplesperblock = 2 + 2 * (blockalign - 7 * psf->sf.channels) / psf->sf.channels ;
pmssize = sizeof (MSADPCM_PRIVATE) + blockalign + 3 * psf->sf.channels * samplesperblock ;
if (! (psf->codec_data = calloc (1, pmssize)))
return SFE_MALLOC_FAILED ;
pms = (MSADPCM_PRIVATE*) psf->codec_data ;
pms->samples = pms->dummydata ;
pms->block = (unsigned char*) (pms->dummydata + psf->sf.channels * samplesperblock) ;
pms->channels = psf->sf.channels ;
pms->blocksize = blockalign ;
pms->samplesperblock = samplesperblock ;
if (pms->blocksize == 0)
{ psf_log_printf (psf, "*** Error : pms->blocksize should not be zero.\n") ;
return SFE_INTERNAL ;
} ;
if (psf->file.mode == SFM_READ)
{ pms->dataremaining = psf->datalength ;
if (psf->datalength % pms->blocksize)
pms->blocks = psf->datalength / pms->blocksize + 1 ;
else
pms->blocks = psf->datalength / pms->blocksize ;
count = 2 * (pms->blocksize - 6 * pms->channels) / pms->channels ;
if (pms->samplesperblock != count)
{ psf_log_printf (psf, "*** Error : samplesperblock should be %d.\n", count) ;
return SFE_INTERNAL ;
} ;
psf->sf.frames = (psf->datalength / pms->blocksize) * pms->samplesperblock ;
psf_log_printf (psf, " bpred idelta\n") ;
msadpcm_decode_block (psf, pms) ;
psf->read_short = msadpcm_read_s ;
psf->read_int = msadpcm_read_i ;
psf->read_float = msadpcm_read_f ;
psf->read_double = msadpcm_read_d ;
} ;
if (psf->file.mode == SFM_WRITE)
{ pms->samples = pms->dummydata ;
pms->samplecount = 0 ;
psf->write_short = msadpcm_write_s ;
psf->write_int = msadpcm_write_i ;
psf->write_float = msadpcm_write_f ;
psf->write_double = msadpcm_write_d ;
} ;
psf->codec_close = msadpcm_close ;
psf->seek = msadpcm_seek ;
return 0 ;
} /* wav_w64_msadpcm_init */
static int
msadpcm_decode_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms)
{ int chan, k, blockindx, sampleindx ;
short bytecode, bpred [2], chan_idelta [2] ;
int predict ;
int current ;
int idelta ;
pms->blockcount ++ ;
pms->samplecount = 0 ;
if (pms->blockcount > pms->blocks)
{ memset (pms->samples, 0, pms->samplesperblock * pms->channels) ;
return 1 ;
} ;
if ((k = psf_fread (pms->block, 1, pms->blocksize, psf)) != pms->blocksize)
psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pms->blocksize) ;
/* Read and check the block header. */
if (pms->channels == 1)
{ bpred [0] = pms->block [0] ;
if (bpred [0] >= 7)
psf_log_printf (psf, "MS ADPCM synchronisation error (%d).\n", bpred [0]) ;
chan_idelta [0] = pms->block [1] | (pms->block [2] << 8) ;
chan_idelta [1] = 0 ;
psf_log_printf (psf, "(%d) (%d)\n", bpred [0], chan_idelta [0]) ;
pms->samples [1] = pms->block [3] | (pms->block [4] << 8) ;
pms->samples [0] = pms->block [5] | (pms->block [6] << 8) ;
blockindx = 7 ;
}
else
{ bpred [0] = pms->block [0] ;
bpred [1] = pms->block [1] ;
if (bpred [0] >= 7 || bpred [1] >= 7)
psf_log_printf (psf, "MS ADPCM synchronisation error (%d %d).\n", bpred [0], bpred [1]) ;
chan_idelta [0] = pms->block [2] | (pms->block [3] << 8) ;
chan_idelta [1] = pms->block [4] | (pms->block [5] << 8) ;
psf_log_printf (psf, "(%d, %d) (%d, %d)\n", bpred [0], bpred [1], chan_idelta [0], chan_idelta [1]) ;
pms->samples [2] = pms->block [6] | (pms->block [7] << 8) ;
pms->samples [3] = pms->block [8] | (pms->block [9] << 8) ;
pms->samples [0] = pms->block [10] | (pms->block [11] << 8) ;
pms->samples [1] = pms->block [12] | (pms->block [13] << 8) ;
blockindx = 14 ;
} ;
/*--------------------------------------------------------
This was left over from a time when calculations were done
as ints rather than shorts. Keep this around as a reminder
in case I ever find a file which decodes incorrectly.
if (chan_idelta [0] & 0x8000)
chan_idelta [0] -= 0x10000 ;
if (chan_idelta [1] & 0x8000)
chan_idelta [1] -= 0x10000 ;
--------------------------------------------------------*/
/* Pull apart the packed 4 bit samples and store them in their
** correct sample positions.
*/
sampleindx = 2 * pms->channels ;
while (blockindx < pms->blocksize)
{ bytecode = pms->block [blockindx++] ;
pms->samples [sampleindx++] = (bytecode >> 4) & 0x0F ;
pms->samples [sampleindx++] = bytecode & 0x0F ;
} ;
/* Decode the encoded 4 bit samples. */
for (k = 2 * pms->channels ; k < (pms->samplesperblock * pms->channels) ; k ++)
{ chan = (pms->channels > 1) ? (k % 2) : 0 ;
bytecode = pms->samples [k] & 0xF ;
/* Compute next Adaptive Scale Factor (ASF) */
idelta = chan_idelta [chan] ;
chan_idelta [chan] = (AdaptationTable [bytecode] * idelta) >> 8 ; /* => / 256 => FIXED_POINT_ADAPTATION_BASE == 256 */
if (chan_idelta [chan] < 16)
chan_idelta [chan] = 16 ;
if (bytecode & 0x8)
bytecode -= 0x10 ;
predict = ((pms->samples [k - pms->channels] * AdaptCoeff1 [bpred [chan]])
+ (pms->samples [k - 2 * pms->channels] * AdaptCoeff2 [bpred [chan]])) >> 8 ; /* => / 256 => FIXED_POINT_COEFF_BASE == 256 */
current = (bytecode * idelta) + predict ;
if (current > 32767)
current = 32767 ;
else if (current < -32768)
current = -32768 ;
pms->samples [k] = current ;
} ;
return 1 ;
} /* msadpcm_decode_block */
static sf_count_t
msadpcm_read_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms, short *ptr, int len)
{ int count, total = 0, indx = 0 ;
while (indx < len)
{ if (pms->blockcount >= pms->blocks && pms->samplecount >= pms->samplesperblock)
{ memset (&(ptr [indx]), 0, (size_t) ((len - indx) * sizeof (short))) ;
return total ;
} ;
if (pms->samplecount >= pms->samplesperblock)
msadpcm_decode_block (psf, pms) ;
count = (pms->samplesperblock - pms->samplecount) * pms->channels ;
count = (len - indx > count) ? count : len - indx ;
memcpy (&(ptr [indx]), &(pms->samples [pms->samplecount * pms->channels]), count * sizeof (short)) ;
indx += count ;
pms->samplecount += count / pms->channels ;
total = indx ;
} ;
return total ;
} /* msadpcm_read_block */
static sf_count_t
msadpcm_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
{ MSADPCM_PRIVATE *pms ;
int readcount, count ;
sf_count_t total = 0 ;
if (! psf->codec_data)
return 0 ;
pms = (MSADPCM_PRIVATE*) psf->codec_data ;
while (len > 0)
{ readcount = (len > 0x10000000) ? 0x10000000 : (int) len ;
count = msadpcm_read_block (psf, pms, ptr, readcount) ;
total += count ;
len -= count ;
if (count != readcount)
break ;
} ;
return total ;
} /* msadpcm_read_s */
static sf_count_t
msadpcm_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
{ MSADPCM_PRIVATE *pms ;
short *sptr ;
int k, bufferlen, readcount = 0, count ;
sf_count_t total = 0 ;
if (! psf->codec_data)
return 0 ;
pms = (MSADPCM_PRIVATE*) psf->codec_data ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = msadpcm_read_block (psf, pms, sptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = sptr [k] << 16 ;
total += count ;
len -= readcount ;
if (count != readcount)
break ;
} ;
return total ;
} /* msadpcm_read_i */
static sf_count_t
msadpcm_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
{ MSADPCM_PRIVATE *pms ;
short *sptr ;
int k, bufferlen, readcount = 0, count ;
sf_count_t total = 0 ;
float normfact ;
if (! psf->codec_data)
return 0 ;
pms = (MSADPCM_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = msadpcm_read_block (psf, pms, sptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = normfact * (float) (sptr [k]) ;
total += count ;
len -= readcount ;
if (count != readcount)
break ;
} ;
return total ;
} /* msadpcm_read_f */
static sf_count_t
msadpcm_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
{ MSADPCM_PRIVATE *pms ;
short *sptr ;
int k, bufferlen, readcount = 0, count ;
sf_count_t total = 0 ;
double normfact ;
normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ;
if (! psf->codec_data)
return 0 ;
pms = (MSADPCM_PRIVATE*) psf->codec_data ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = msadpcm_read_block (psf, pms, sptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = normfact * (double) (sptr [k]) ;
total += count ;
len -= readcount ;
if (count != readcount)
break ;
} ;
return total ;
} /* msadpcm_read_d */
static sf_count_t
msadpcm_seek (SF_PRIVATE *psf, int mode, sf_count_t offset)
{ MSADPCM_PRIVATE *pms ;
int newblock, newsample ;
if (! psf->codec_data)
return 0 ;
pms = (MSADPCM_PRIVATE*) psf->codec_data ;
if (psf->datalength < 0 || psf->dataoffset < 0)
{ psf->error = SFE_BAD_SEEK ;
return PSF_SEEK_ERROR ;
} ;
if (offset == 0)
{ psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
pms->blockcount = 0 ;
msadpcm_decode_block (psf, pms) ;
pms->samplecount = 0 ;
return 0 ;
} ;
if (offset < 0 || offset > pms->blocks * pms->samplesperblock)
{ psf->error = SFE_BAD_SEEK ;
return PSF_SEEK_ERROR ;
} ;
newblock = offset / pms->samplesperblock ;
newsample = offset % pms->samplesperblock ;
if (mode == SFM_READ)
{ psf_fseek (psf, psf->dataoffset + newblock * pms->blocksize, SEEK_SET) ;
pms->blockcount = newblock ;
msadpcm_decode_block (psf, pms) ;
pms->samplecount = newsample ;
}
else
{ /* What to do about write??? */
psf->error = SFE_BAD_SEEK ;
return PSF_SEEK_ERROR ;
} ;
return newblock * pms->samplesperblock + newsample ;
} /* msadpcm_seek */
/*==========================================================================================
** MS ADPCM Write Functions.
*/
void
msadpcm_write_adapt_coeffs (SF_PRIVATE *psf)
{ int k ;
for (k = 0 ; k < MSADPCM_ADAPT_COEFF_COUNT ; k++)
psf_binheader_writef (psf, "22", AdaptCoeff1 [k], AdaptCoeff2 [k]) ;
} /* msadpcm_write_adapt_coeffs */
/*==========================================================================================
*/
static int
msadpcm_encode_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms)
{ unsigned int blockindx ;
unsigned char byte ;
int chan, k, predict, bpred [2], idelta [2], errordelta, newsamp ;
choose_predictor (pms->channels, pms->samples, bpred, idelta) ;
/* Write the block header. */
if (pms->channels == 1)
{ pms->block [0] = bpred [0] ;
pms->block [1] = idelta [0] & 0xFF ;
pms->block [2] = idelta [0] >> 8 ;
pms->block [3] = pms->samples [1] & 0xFF ;
pms->block [4] = pms->samples [1] >> 8 ;
pms->block [5] = pms->samples [0] & 0xFF ;
pms->block [6] = pms->samples [0] >> 8 ;
blockindx = 7 ;
byte = 0 ;
/* Encode the samples as 4 bit. */
for (k = 2 ; k < pms->samplesperblock ; k++)
{ predict = (pms->samples [k-1] * AdaptCoeff1 [bpred [0]] + pms->samples [k-2] * AdaptCoeff2 [bpred [0]]) >> 8 ;
errordelta = (pms->samples [k] - predict) / idelta [0] ;
if (errordelta < -8)
errordelta = -8 ;
else if (errordelta > 7)
errordelta = 7 ;
newsamp = predict + (idelta [0] * errordelta) ;
if (newsamp > 32767)
newsamp = 32767 ;
else if (newsamp < -32768)
newsamp = -32768 ;
if (errordelta < 0)
errordelta += 0x10 ;
byte = (byte << 4) | (errordelta & 0xF) ;
if (k % 2)
{ pms->block [blockindx++] = byte ;
byte = 0 ;
} ;
idelta [0] = (idelta [0] * AdaptationTable [errordelta]) >> 8 ;
if (idelta [0] < 16)
idelta [0] = 16 ;
pms->samples [k] = newsamp ;
} ;
}
else
{ /* Stereo file. */
pms->block [0] = bpred [0] ;
pms->block [1] = bpred [1] ;
pms->block [2] = idelta [0] & 0xFF ;
pms->block [3] = idelta [0] >> 8 ;
pms->block [4] = idelta [1] & 0xFF ;
pms->block [5] = idelta [1] >> 8 ;
pms->block [6] = pms->samples [2] & 0xFF ;
pms->block [7] = pms->samples [2] >> 8 ;
pms->block [8] = pms->samples [3] & 0xFF ;
pms->block [9] = pms->samples [3] >> 8 ;
pms->block [10] = pms->samples [0] & 0xFF ;
pms->block [11] = pms->samples [0] >> 8 ;
pms->block [12] = pms->samples [1] & 0xFF ;
pms->block [13] = pms->samples [1] >> 8 ;
blockindx = 14 ;
byte = 0 ;
chan = 1 ;
for (k = 4 ; k < 2 * pms->samplesperblock ; k++)
{ chan = k & 1 ;
predict = (pms->samples [k-2] * AdaptCoeff1 [bpred [chan]] + pms->samples [k-4] * AdaptCoeff2 [bpred [chan]]) >> 8 ;
errordelta = (pms->samples [k] - predict) / idelta [chan] ;
if (errordelta < -8)
errordelta = -8 ;
else if (errordelta > 7)
errordelta = 7 ;
newsamp = predict + (idelta [chan] * errordelta) ;
if (newsamp > 32767)
newsamp = 32767 ;
else if (newsamp < -32768)
newsamp = -32768 ;
if (errordelta < 0)
errordelta += 0x10 ;
byte = (byte << 4) | (errordelta & 0xF) ;
if (chan)
{ pms->block [blockindx++] = byte ;
byte = 0 ;
} ;
idelta [chan] = (idelta [chan] * AdaptationTable [errordelta]) >> 8 ;
if (idelta [chan] < 16)
idelta [chan] = 16 ;
pms->samples [k] = newsamp ;
} ;
} ;
/* Write the block to disk. */
if ((k = psf_fwrite (pms->block, 1, pms->blocksize, psf)) != pms->blocksize)
psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pms->blocksize) ;
memset (pms->samples, 0, pms->samplesperblock * sizeof (short)) ;
pms->blockcount ++ ;
pms->samplecount = 0 ;
return 1 ;
} /* msadpcm_encode_block */
static sf_count_t
msadpcm_write_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms, const short *ptr, int len)
{ int count, total = 0, indx = 0 ;
while (indx < len)
{ count = (pms->samplesperblock - pms->samplecount) * pms->channels ;
if (count > len - indx)
count = len - indx ;
memcpy (&(pms->samples [pms->samplecount * pms->channels]), &(ptr [total]), count * sizeof (short)) ;
indx += count ;
pms->samplecount += count / pms->channels ;
total = indx ;
if (pms->samplecount >= pms->samplesperblock)
msadpcm_encode_block (psf, pms) ;
} ;
return total ;
} /* msadpcm_write_block */
static sf_count_t
msadpcm_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
{ MSADPCM_PRIVATE *pms ;
int writecount, count ;
sf_count_t total = 0 ;
if (! psf->codec_data)
return 0 ;
pms = (MSADPCM_PRIVATE*) psf->codec_data ;
while (len > 0)
{ writecount = (len > 0x10000000) ? 0x10000000 : (int) len ;
count = msadpcm_write_block (psf, pms, ptr, writecount) ;
total += count ;
len -= count ;
if (count != writecount)
break ;
} ;
return total ;
} /* msadpcm_write_s */
static sf_count_t
msadpcm_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
{ MSADPCM_PRIVATE *pms ;
short *sptr ;
int k, bufferlen, writecount, count ;
sf_count_t total = 0 ;
if (! psf->codec_data)
return 0 ;
pms = (MSADPCM_PRIVATE*) psf->codec_data ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
sptr [k] = ptr [total + k] >> 16 ;
count = msadpcm_write_block (psf, pms, sptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* msadpcm_write_i */
static sf_count_t
msadpcm_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
{ MSADPCM_PRIVATE *pms ;
short *sptr ;
int k, bufferlen, writecount, count ;
sf_count_t total = 0 ;
float normfact ;
if (! psf->codec_data)
return 0 ;
pms = (MSADPCM_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
sptr [k] = lrintf (normfact * ptr [total + k]) ;
count = msadpcm_write_block (psf, pms, sptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* msadpcm_write_f */
static sf_count_t
msadpcm_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
{ MSADPCM_PRIVATE *pms ;
short *sptr ;
int k, bufferlen, writecount, count ;
sf_count_t total = 0 ;
double normfact ;
normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ;
if (! psf->codec_data)
return 0 ;
pms = (MSADPCM_PRIVATE*) psf->codec_data ;
sptr = psf->u.sbuf ;
bufferlen = ARRAY_LEN (psf->u.sbuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
sptr [k] = lrint (normfact * ptr [total + k]) ;
count = msadpcm_write_block (psf, pms, sptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* msadpcm_write_d */
/*========================================================================================
*/
static int
msadpcm_close (SF_PRIVATE *psf)
{ MSADPCM_PRIVATE *pms ;
pms = (MSADPCM_PRIVATE*) psf->codec_data ;
if (psf->file.mode == SFM_WRITE)
{ /* Now we know static int for certain the length of the file we can
** re-write the header.
*/
if (pms->samplecount && pms->samplecount < pms->samplesperblock)
msadpcm_encode_block (psf, pms) ;
} ;
return 0 ;
} /* msadpcm_close */
/*========================================================================================
** Static functions.
*/
/*----------------------------------------------------------------------------------------
** Choosing the block predictor.
** Each block requires a predictor and an idelta for each channel.
** The predictor is in the range [0..6] which is an indx into the two AdaptCoeff tables.
** The predictor is chosen by trying all of the possible predictors on a small set of
** samples at the beginning of the block. The predictor with the smallest average
** abs (idelta) is chosen as the best predictor for this block.
** The value of idelta is chosen to to give a 4 bit code value of +/- 4 (approx. half the
** max. code value). If the average abs (idelta) is zero, the sixth predictor is chosen.
** If the value of idelta is less then 16 it is set to 16.
**
** Microsoft uses an IDELTA_COUNT (number of sample pairs used to choose best predictor)
** value of 3. The best possible results would be obtained by using all the samples to
** choose the predictor.
*/
#define IDELTA_COUNT 3
static void
choose_predictor (unsigned int channels, short *data, int *block_pred, int *idelta)
{ unsigned int chan, k, bpred, idelta_sum, best_bpred, best_idelta ;
for (chan = 0 ; chan < channels ; chan++)
{ best_bpred = best_idelta = 0 ;
for (bpred = 0 ; bpred < 7 ; bpred++)
{ idelta_sum = 0 ;
for (k = 2 ; k < 2 + IDELTA_COUNT ; k++)
idelta_sum += abs (data [k * channels] - ((data [(k - 1) * channels] * AdaptCoeff1 [bpred] + data [(k - 2) * channels] * AdaptCoeff2 [bpred]) >> 8)) ;
idelta_sum /= (4 * IDELTA_COUNT) ;
if (bpred == 0 || idelta_sum < best_idelta)
{ best_bpred = bpred ;
best_idelta = idelta_sum ;
} ;
if (! idelta_sum)
{ best_bpred = bpred ;
best_idelta = 16 ;
break ;
} ;
} ; /* for bpred ... */
if (best_idelta < 16)
best_idelta = 16 ;
block_pred [chan] = best_bpred ;
idelta [chan] = best_idelta ;
} ;
return ;
} /* choose_predictor */

View File

@@ -0,0 +1,377 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
** Some of the information used to read NIST files was gleaned from
** reading the code of Bill Schottstaedt's sndlib library
** ftp://ccrma-ftp.stanford.edu/pub/Lisp/sndlib.tar.gz
** However, no code from that package was used.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
/*------------------------------------------------------------------------------
*/
#define NIST_HEADER_LENGTH 1024
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int nist_close (SF_PRIVATE *psf) ;
static int nist_write_header (SF_PRIVATE *psf, int calc_length) ;
static int nist_read_header (SF_PRIVATE *psf) ;
/*------------------------------------------------------------------------------
*/
int
nist_open (SF_PRIVATE *psf)
{ int error ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = nist_read_header (psf)))
return error ;
} ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if (psf->is_pipe)
return SFE_NO_PIPE_WRITE ;
if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_NIST)
return SFE_BAD_OPEN_FORMAT ;
psf->endian = SF_ENDIAN (psf->sf.format) ;
if (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU)
psf->endian = (CPU_IS_BIG_ENDIAN) ? SF_ENDIAN_BIG : SF_ENDIAN_LITTLE ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
psf->sf.frames = 0 ;
if ((error = nist_write_header (psf, SF_FALSE)))
return error ;
psf->write_header = nist_write_header ;
} ;
psf->container_close = nist_close ;
switch (SF_CODEC (psf->sf.format))
{ case SF_FORMAT_PCM_S8 :
error = pcm_init (psf) ;
break ;
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_24 :
case SF_FORMAT_PCM_32 :
error = pcm_init (psf) ;
break ;
case SF_FORMAT_ULAW :
error = ulaw_init (psf) ;
break ;
case SF_FORMAT_ALAW :
error = alaw_init (psf) ;
break ;
default : error = SFE_UNIMPLEMENTED ;
break ;
} ;
return error ;
} /* nist_open */
/*------------------------------------------------------------------------------
*/
static char bad_header [] =
{ 'N', 'I', 'S', 'T', '_', '1', 'A', 0x0d, 0x0a,
' ', ' ', ' ', '1', '0', '2', '4', 0x0d, 0x0a,
0
} ;
static int
nist_read_header (SF_PRIVATE *psf)
{ char *psf_header ;
int bitwidth = 0, count, encoding ;
unsigned bytes = 0 ;
char str [64], *cptr ;
long samples ;
psf_header = psf->u.cbuf ;
if (sizeof (psf->header) <= NIST_HEADER_LENGTH)
return SFE_INTERNAL ;
/* Go to start of file and read in the whole header. */
psf_binheader_readf (psf, "pb", 0, psf_header, NIST_HEADER_LENGTH) ;
/* Header is a string, so make sure it is null terminated. */
psf_header [NIST_HEADER_LENGTH] = 0 ;
/* Now trim the header after the end marker. */
if ((cptr = strstr (psf_header, "end_head")))
{ cptr += strlen ("end_head") + 1 ;
cptr [0] = 0 ;
} ;
if (strstr (psf_header, bad_header) == psf_header)
return SFE_NIST_CRLF_CONVERISON ;
/* Make sure its a NIST file. */
if (strstr (psf_header, "NIST_1A\n") != psf_header)
{ psf_log_printf (psf, "Not a NIST file.\n") ;
return SFE_NIST_BAD_HEADER ;
} ;
if (sscanf (psf_header, "NIST_1A\n%d\n", &count) == 1)
psf->dataoffset = count ;
else
{ psf_log_printf (psf, "*** Suspicious header length.\n") ;
psf->dataoffset = NIST_HEADER_LENGTH ;
} ;
/* Determine sample encoding, start by assuming PCM. */
encoding = SF_FORMAT_PCM_U8 ;
if ((cptr = strstr (psf_header, "sample_coding -s")))
{ sscanf (cptr, "sample_coding -s%d %63s", &count, str) ;
if (strcmp (str, "pcm") == 0)
{ /* Correct this later when we find out the bitwidth. */
encoding = SF_FORMAT_PCM_U8 ;
}
else if (strcmp (str, "alaw") == 0)
encoding = SF_FORMAT_ALAW ;
else if ((strcmp (str, "ulaw") == 0) || (strcmp (str, "mu-law") == 0))
encoding = SF_FORMAT_ULAW ;
else
{ psf_log_printf (psf, "*** Unknown encoding : %s\n", str) ;
encoding = 0 ;
} ;
} ;
if ((cptr = strstr (psf_header, "channel_count -i ")) != NULL)
sscanf (cptr, "channel_count -i %d", &(psf->sf.channels)) ;
if ((cptr = strstr (psf_header, "sample_rate -i ")) != NULL)
sscanf (cptr, "sample_rate -i %d", &(psf->sf.samplerate)) ;
if ((cptr = strstr (psf_header, "sample_count -i ")) != NULL)
{ sscanf (cptr, "sample_count -i %ld", &samples) ;
psf->sf.frames = samples ;
} ;
if ((cptr = strstr (psf_header, "sample_n_bytes -i ")) != NULL)
sscanf (cptr, "sample_n_bytes -i %d", &(psf->bytewidth)) ;
/* Default endian-ness (for 8 bit, u-law, A-law. */
psf->endian = (CPU_IS_BIG_ENDIAN) ? SF_ENDIAN_BIG : SF_ENDIAN_LITTLE ;
/* This is where we figure out endian-ness. */
if ((cptr = strstr (psf_header, "sample_byte_format -s"))
&& sscanf (cptr, "sample_byte_format -s%u %8s", &bytes, str) == 2)
{
if (bytes != strlen (str))
psf_log_printf (psf, "Weird sample_byte_format : strlen '%s' != %d\n", str, bytes) ;
if (bytes > 1)
{ if (psf->bytewidth == 0)
psf->bytewidth = bytes ;
else if (psf->bytewidth - bytes != 0)
{ psf_log_printf (psf, "psf->bytewidth (%d) != bytes (%d)\n", psf->bytewidth, bytes) ;
return SFE_NIST_BAD_ENCODING ;
} ;
if (strcmp (str, "01") == 0)
psf->endian = SF_ENDIAN_LITTLE ;
else if (strcmp (str, "10") == 0)
psf->endian = SF_ENDIAN_BIG ;
else
{ psf_log_printf (psf, "Weird endian-ness : %s\n", str) ;
return SFE_NIST_BAD_ENCODING ;
} ;
} ;
psf->sf.format |= psf->endian ;
} ;
if ((cptr = strstr (psf_header, "sample_sig_bits -i ")))
sscanf (cptr, "sample_sig_bits -i %d", &bitwidth) ;
if (strstr (psf_header, "channels_interleaved -s5 FALSE"))
{ psf_log_printf (psf, "Non-interleaved data unsupported.\n", str) ;
return SFE_NIST_BAD_ENCODING ;
} ;
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
psf->datalength = psf->filelength - psf->dataoffset ;
psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
if (encoding == SF_FORMAT_PCM_U8)
{ switch (psf->bytewidth)
{ case 1 :
psf->sf.format |= SF_FORMAT_PCM_S8 ;
break ;
case 2 :
psf->sf.format |= SF_FORMAT_PCM_16 ;
break ;
case 3 :
psf->sf.format |= SF_FORMAT_PCM_24 ;
break ;
case 4 :
psf->sf.format |= SF_FORMAT_PCM_32 ;
break ;
default : break ;
} ;
}
else if (encoding != 0)
psf->sf.format |= encoding ;
else
return SFE_UNIMPLEMENTED ;
/* Sanitize psf->sf.format. */
switch (SF_CODEC (psf->sf.format))
{ case SF_FORMAT_ULAW :
case SF_FORMAT_ALAW :
case SF_FORMAT_PCM_U8 :
/* Blank out endian bits. */
psf->sf.format = SF_FORMAT_NIST | SF_CODEC (psf->sf.format) ;
break ;
default :
break ;
} ;
return 0 ;
} /* nist_read_header */
static int
nist_close (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
nist_write_header (psf, SF_TRUE) ;
return 0 ;
} /* nist_close */
/*=========================================================================
*/
static int
nist_write_header (SF_PRIVATE *psf, int calc_length)
{ const char *end_str ;
long samples ;
sf_count_t current ;
current = psf_ftell (psf) ;
if (calc_length)
{ psf->filelength = psf_get_filelen (psf) ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf->dataend)
psf->datalength -= psf->filelength - psf->dataend ;
if (psf->bytewidth > 0)
psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
} ;
if (psf->endian == SF_ENDIAN_BIG)
end_str = "10" ;
else if (psf->endian == SF_ENDIAN_LITTLE)
end_str = "01" ;
else
end_str = "error" ;
/* Clear the whole header. */
memset (psf->header, 0, sizeof (psf->header)) ;
psf->headindex = 0 ;
psf_fseek (psf, 0, SEEK_SET) ;
psf_asciiheader_printf (psf, "NIST_1A\n 1024\n") ;
psf_asciiheader_printf (psf, "channel_count -i %d\n", psf->sf.channels) ;
psf_asciiheader_printf (psf, "sample_rate -i %d\n", psf->sf.samplerate) ;
switch (SF_CODEC (psf->sf.format))
{ case SF_FORMAT_PCM_S8 :
psf_asciiheader_printf (psf, "sample_coding -s3 pcm\n") ;
psf_asciiheader_printf (psf, "sample_n_bytes -i 1\n"
"sample_sig_bits -i 8\n") ;
break ;
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_24 :
case SF_FORMAT_PCM_32 :
psf_asciiheader_printf (psf, "sample_n_bytes -i %d\n", psf->bytewidth) ;
psf_asciiheader_printf (psf, "sample_sig_bits -i %d\n", psf->bytewidth * 8) ;
psf_asciiheader_printf (psf, "sample_coding -s3 pcm\n"
"sample_byte_format -s%d %s\n", psf->bytewidth, end_str) ;
break ;
case SF_FORMAT_ALAW :
psf_asciiheader_printf (psf, "sample_coding -s4 alaw\n") ;
psf_asciiheader_printf (psf, "sample_n_bytes -s1 1\n") ;
break ;
case SF_FORMAT_ULAW :
psf_asciiheader_printf (psf, "sample_coding -s4 ulaw\n") ;
psf_asciiheader_printf (psf, "sample_n_bytes -s1 1\n") ;
break ;
default : return SFE_UNIMPLEMENTED ;
} ;
psf->dataoffset = NIST_HEADER_LENGTH ;
/* Fix this */
samples = psf->sf.frames ;
psf_asciiheader_printf (psf, "sample_count -i %ld\n", samples) ;
psf_asciiheader_printf (psf, "end_head\n") ;
/* Zero fill to dataoffset. */
psf_binheader_writef (psf, "z", (size_t) (NIST_HEADER_LENGTH - psf->headindex)) ;
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
if (psf->error)
return psf->error ;
if (current > 0)
psf_fseek (psf, current, SEEK_SET) ;
return psf->error ;
} /* nist_write_header */

View File

@@ -0,0 +1,250 @@
/*
** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
** Copyright (C) 2007 John ffitch
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY ; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program ; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <math.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#if HAVE_EXTERNAL_LIBS
#include <ogg/ogg.h>
#include "ogg.h"
static int ogg_close (SF_PRIVATE *psf) ;
static int ogg_stream_classify (SF_PRIVATE *psf, OGG_PRIVATE * odata) ;
static int ogg_page_classify (SF_PRIVATE * psf, const ogg_page * og) ;
int
ogg_open (SF_PRIVATE *psf)
{ OGG_PRIVATE* odata = calloc (1, sizeof (OGG_PRIVATE)) ;
sf_count_t pos = psf_ftell (psf) ;
int error = 0 ;
psf->container_data = odata ;
psf->container_close = ogg_close ;
if (psf->file.mode == SFM_RDWR)
return SFE_BAD_MODE_RW ;
if (psf->file.mode == SFM_READ)
if ((error = ogg_stream_classify (psf, odata)) != 0)
return error ;
/* Reset everything to an initial state. */
ogg_sync_clear (&odata->osync) ;
ogg_stream_clear (&odata->ostream) ;
psf_fseek (psf, pos, SEEK_SET) ;
switch (psf->sf.format)
{ case SF_FORMAT_OGG | SF_FORMAT_VORBIS :
return ogg_vorbis_open (psf) ;
case SF_FORMAT_OGGFLAC :
free (psf->container_data) ;
psf->container_data = NULL ;
psf->container_close = NULL ;
return flac_open (psf) ;
#if ENABLE_EXPERIMENTAL_CODE
case SF_FORMAT_OGG | SF_FORMAT_SPEEX :
return ogg_speex_open (psf) ;
case SF_FORMAT_OGG | SF_FORMAT_PCM_16 :
case SF_FORMAT_OGG | SF_FORMAT_PCM_24 :
return ogg_pcm_open (psf) ;
#endif
default :
break ;
} ;
psf_log_printf (psf, "%s : mode should be SFM_READ or SFM_WRITE.\n", __func__) ;
return SFE_INTERNAL ;
} /* ogg_open */
static int
ogg_close (SF_PRIVATE *psf)
{ OGG_PRIVATE* odata = psf->container_data ;
ogg_sync_clear (&odata->osync) ;
ogg_stream_clear (&odata->ostream) ;
return 0 ;
} /* ogg_close */
static int
ogg_stream_classify (SF_PRIVATE *psf, OGG_PRIVATE* odata)
{ char *buffer ;
int bytes, nn ;
/* Call this here so it only gets called once, so no memory is leaked. */
ogg_sync_init (&odata->osync) ;
odata->eos = 0 ;
/* Weird stuff happens if these aren't called. */
ogg_stream_reset (&odata->ostream) ;
ogg_sync_reset (&odata->osync) ;
/*
** Grab some data at the head of the stream. We want the first page
** (which is guaranteed to be small and only contain the Vorbis
** stream initial header) We need the first page to get the stream
** serialno.
*/
/* Expose the buffer */
buffer = ogg_sync_buffer (&odata->osync, 4096L) ;
/* Grab the part of the header that has already been read. */
memcpy (buffer, psf->header, psf->headindex) ;
bytes = psf->headindex ;
/* Submit a 4k block to libvorbis' Ogg layer */
bytes += psf_fread (buffer + psf->headindex, 1, 4096 - psf->headindex, psf) ;
ogg_sync_wrote (&odata->osync, bytes) ;
/* Get the first page. */
if ((nn = ogg_sync_pageout (&odata->osync, &odata->opage)) != 1)
{
/* Have we simply run out of data? If so, we're done. */
if (bytes < 4096)
return 0 ;
/* Error case. Must not be Vorbis data */
psf_log_printf (psf, "Input does not appear to be an Ogg bitstream.\n") ;
return SFE_MALFORMED_FILE ;
} ;
/*
** Get the serial number and set up the rest of decode.
** Serialno first ; use it to set up a logical stream.
*/
ogg_stream_clear (&odata->ostream) ;
ogg_stream_init (&odata->ostream, ogg_page_serialno (&odata->opage)) ;
if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0)
{ /* Error ; stream version mismatch perhaps. */
psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ;
return SFE_MALFORMED_FILE ;
} ;
if (ogg_stream_packetout (&odata->ostream, &odata->opacket) != 1)
{ /* No page? must not be vorbis. */
psf_log_printf (psf, "Error reading initial header packet.\n") ;
return SFE_MALFORMED_FILE ;
} ;
odata->codec = ogg_page_classify (psf, &odata->opage) ;
switch (odata->codec)
{ case OGG_VORBIS :
psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ;
return 0 ;
case OGG_FLAC :
case OGG_FLAC0 :
psf->sf.format = SF_FORMAT_OGGFLAC ;
return 0 ;
case OGG_SPEEX :
psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_SPEEX ;
return 0 ;
case OGG_PCM :
psf_log_printf (psf, "Detected Ogg/PCM data. This is not supported yet.\n") ;
return SFE_UNIMPLEMENTED ;
default :
break ;
} ;
psf_log_printf (psf, "This Ogg bitstream contains some uknown data type.\n") ;
return SFE_UNIMPLEMENTED ;
} /* ogg_stream_classify */
/*==============================================================================
*/
static struct
{ const char *str, *name ;
int len, codec ;
} codec_lookup [] =
{ { "Annodex", "Annodex", 8, OGG_ANNODEX },
{ "AnxData", "AnxData", 7, OGG_ANXDATA },
{ "\177FLAC", "Flac1", 5, OGG_FLAC },
{ "fLaC", "Flac0", 4, OGG_FLAC0 },
{ "PCM ", "PCM", 8, OGG_PCM },
{ "Speex", "Speex", 5, OGG_SPEEX },
{ "\001vorbis", "Vorbis", 7, OGG_VORBIS },
} ;
static int
ogg_page_classify (SF_PRIVATE * psf, const ogg_page * og)
{ int k, len ;
for (k = 0 ; k < ARRAY_LEN (codec_lookup) ; k++)
{ if (codec_lookup [k].len > og->body_len)
continue ;
if (memcmp (og->body, codec_lookup [k].str, codec_lookup [k].len) == 0)
{ psf_log_printf (psf, "Ogg stream data : %s\n", codec_lookup [k].name) ;
psf_log_printf (psf, "Stream serialno : %010D\n", (int64_t) ogg_page_serialno (og)) ;
return codec_lookup [k].codec ;
} ;
} ;
len = og->body_len < 8 ? og->body_len : 8 ;
psf_log_printf (psf, "Ogg_stream data : '") ;
for (k = 0 ; k < len ; k++)
psf_log_printf (psf, "%c", isprint (og->body [k]) ? og->body [k] : '.') ;
psf_log_printf (psf, "' ") ;
for (k = 0 ; k < len ; k++)
psf_log_printf (psf, " %02x", og->body [k] & 0xff) ;
psf_log_printf (psf, "\n") ;
return 0 ;
} /* ogg_page_classify */
#else /* HAVE_EXTERNAL_LIBS */
int
ogg_open (SF_PRIVATE *psf)
{
psf_log_printf (psf, "This version of libsndfile was compiled without Ogg/Vorbis support.\n") ;
return SFE_UNIMPLEMENTED ;
} /* ogg_open */
#endif

View File

@@ -0,0 +1,52 @@
/*
** Copyright (C) 2008-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY ; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program ; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef SF_SRC_OGG_H
enum
{ OGG_ANNODEX = 300,
OGG_ANXDATA,
OGG_FLAC,
OGG_FLAC0,
OGG_PCM,
OGG_SPEEX,
OGG_VORBIS,
} ;
typedef struct
{ /* Sync and verify incoming physical bitstream */
ogg_sync_state osync ;
/* Take physical pages, weld into a logical stream of packets */
ogg_stream_state ostream ;
/* One Ogg bitstream page. Vorbis packets are inside */
ogg_page opage ;
/* One raw packet of data for decode */
ogg_packet opacket ;
int eos ;
int codec ;
} OGG_PRIVATE ;
#define readint(buf, base) (((buf [base + 3] << 24) & 0xff000000) | \
((buf [base + 2] <<16) & 0xff0000) | \
((buf [base + 1] << 8) & 0xff00) | \
(buf [base] & 0xff))
#endif /* SF_SRC_OGG_H */

View File

@@ -0,0 +1,164 @@
/*
** Copyright (C) 2008-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY ; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program ; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <math.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#if (ENABLE_EXPERIMENTAL_CODE && HAVE_EXTERNAL_LIBS)
#include <ogg/ogg.h>
#include "ogg.h"
typedef struct
{ int32_t serialno ;
void * state ;
} OPCM_PRIVATE ;
static int opcm_read_header (SF_PRIVATE * psf) ;
static int opcm_close (SF_PRIVATE *psf) ;
int
ogg_pcm_open (SF_PRIVATE *psf)
{ OGG_PRIVATE* odata = psf->container_data ;
OPCM_PRIVATE* opcm = calloc (1, sizeof (OPCM_PRIVATE)) ;
int error = 0 ;
if (odata == NULL)
{ psf_log_printf (psf, "%s : odata is NULL???\n", __func__) ;
return SFE_INTERNAL ;
} ;
psf->codec_data = opcm ;
if (opcm == NULL)
return SFE_MALLOC_FAILED ;
if (psf->file.mode == SFM_RDWR)
return SFE_BAD_MODE_RW ;
if (psf->file.mode == SFM_READ)
{ /* Call this here so it only gets called once, so no memory is leaked. */
ogg_sync_init (&odata->osync) ;
if ((error = opcm_read_header (psf)))
return error ;
#if 0
psf->read_short = opcm_read_s ;
psf->read_int = opcm_read_i ;
psf->read_float = opcm_read_f ;
psf->read_double = opcm_read_d ;
psf->sf.frames = opcm_length (psf) ;
#endif
} ;
psf->codec_close = opcm_close ;
if (psf->file.mode == SFM_WRITE)
{
#if 0
/* Set the default opcm quality here. */
vdata->quality = 0.4 ;
psf->write_header = opcm_write_header ;
psf->write_short = opcm_write_s ;
psf->write_int = opcm_write_i ;
psf->write_float = opcm_write_f ;
psf->write_double = opcm_write_d ;
#endif
psf->sf.frames = SF_COUNT_MAX ; /* Unknown really */
psf->str_flags = SF_STR_ALLOW_START ;
} ;
psf->bytewidth = 1 ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
#if 0
psf->seek = opcm_seek ;
psf->command = opcm_command ;
#endif
/* FIXME, FIXME, FIXME : Hack these here for now and correct later. */
psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_SPEEX ;
psf->sf.sections = 1 ;
psf->datalength = 1 ;
psf->dataoffset = 0 ;
/* End FIXME. */
return error ;
} /* ogg_pcm_open */
static int
opcm_read_header (SF_PRIVATE * UNUSED (psf))
{
return 0 ;
} /* opcm_read_header */
static int
opcm_close (SF_PRIVATE * UNUSED (psf))
{
return 0 ;
} /* opcm_close */
/*
encoded_speex_frames = (frames_per_packet * Packets)
= 1 * 272
= 272
audio_samples = encoded_speex_frames * frame_size
= 272 * 640
= 174080
duration = audio_samples / rate
= 174080 / 44100
= 3.947
*/
#else /* ENABLE_EXPERIMENTAL_CODE && HAVE_EXTERNAL_LIBS */
int
ogg_pcm_open (SF_PRIVATE *psf)
{
psf_log_printf (psf, "This version of libsndfile was compiled without Ogg/Speex support.\n") ;
return SFE_UNIMPLEMENTED ;
} /* ogg_pcm_open */
#endif

View File

@@ -0,0 +1,425 @@
/*
** Copyright (C) 2008-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY ; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program ; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <math.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#if (ENABLE_EXPERIMENTAL_CODE && HAVE_EXTERNAL_LIBS)
#include <ogg/ogg.h>
#include <speex/speex.h>
#include <speex/speex_stereo.h>
#include <speex/speex_header.h>
#include <speex/speex_callbacks.h>
#include "ogg.h"
#define OGG_SPX_READ_SIZE 200
typedef struct
{ SpeexBits bits ;
int32_t serialno ;
int frame_size, granule_frame_size, nframes ;
int force_mode ;
SpeexStereoState stereo ;
SpeexHeader header ;
void * state ;
} SPX_PRIVATE ;
static int spx_read_header (SF_PRIVATE * psf) ;
static int spx_close (SF_PRIVATE *psf) ;
static void *spx_header_read (SF_PRIVATE * psf, ogg_packet *op, spx_int32_t enh_enabled, int force_mode) ;
static void spx_print_comments (const char *comments, int length) ;
int
ogg_speex_open (SF_PRIVATE *psf)
{ OGG_PRIVATE* odata = psf->container_data ;
SPX_PRIVATE* spx = calloc (1, sizeof (SPX_PRIVATE)) ;
int error = 0 ;
if (odata == NULL)
{ psf_log_printf (psf, "%s : odata is NULL???\n", __func__) ;
return SFE_INTERNAL ;
} ;
psf->codec_data = spx ;
if (spx == NULL)
return SFE_MALLOC_FAILED ;
if (psf->file.mode == SFM_RDWR)
return SFE_BAD_MODE_RW ;
if (psf->file.mode == SFM_READ)
{ /* Call this here so it only gets called once, so no memory is leaked. */
ogg_sync_init (&odata->osync) ;
if ((error = spx_read_header (psf)))
return error ;
#if 0
psf->read_short = spx_read_s ;
psf->read_int = spx_read_i ;
psf->read_float = spx_read_f ;
psf->read_double = spx_read_d ;
psf->sf.frames = spx_length (psf) ;
#endif
} ;
psf->codec_close = spx_close ;
if (psf->file.mode == SFM_WRITE)
{
#if 0
/* Set the default spx quality here. */
vdata->quality = 0.4 ;
psf->write_header = spx_write_header ;
psf->write_short = spx_write_s ;
psf->write_int = spx_write_i ;
psf->write_float = spx_write_f ;
psf->write_double = spx_write_d ;
#endif
psf->sf.frames = SF_COUNT_MAX ; /* Unknown really */
psf->str_flags = SF_STR_ALLOW_START ;
} ;
psf->bytewidth = 1 ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
#if 0
psf->seek = spx_seek ;
psf->command = spx_command ;
#endif
/* FIXME, FIXME, FIXME : Hack these here for now and correct later. */
psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_SPEEX ;
psf->sf.sections = 1 ;
psf->datalength = 1 ;
psf->dataoffset = 0 ;
/* End FIXME. */
return error ;
} /* ogg_speex_open */
#define le_short (x) (x)
static int
spx_read_header (SF_PRIVATE * psf)
{ static SpeexStereoState STEREO_INIT = SPEEX_STEREO_STATE_INIT ;
OGG_PRIVATE* odata = psf->container_data ;
SPX_PRIVATE* spx = psf->codec_data ;
ogg_int64_t page_granule = 0 ;
int stream_init = 0 ;
int page_nb_packets = 0 ;
int packet_count = 0 ;
int enh_enabled = 1 ;
int force_mode = -1 ;
char * data ;
int nb_read ;
int lookahead ;
printf ("%s %d\n", __func__, __LINE__) ;
psf_log_printf (psf, "Speex header\n") ;
odata->eos = 0 ;
/* Reset ogg stuff which has already been used in src/ogg.c. */
ogg_stream_reset (&odata->ostream) ;
ogg_sync_reset (&odata->osync) ;
/* Seek to start of stream. */
psf_fseek (psf, 0, SEEK_SET) ;
/* Initialize. */
ogg_sync_init (&odata->osync) ;
speex_bits_init (&spx->bits) ;
/* Set defaults. */
psf->sf.channels = -1 ;
psf->sf.samplerate = 0 ;
spx->stereo = STEREO_INIT ;
/* Get a pointer to the ogg buffer and read data into it. */
data = ogg_sync_buffer (&odata->osync, OGG_SPX_READ_SIZE) ;
nb_read = psf_fread (data, 1, OGG_SPX_READ_SIZE, psf) ;
ogg_sync_wrote (&odata->osync, nb_read) ;
/* Now we chew on Ogg packets. */
while (ogg_sync_pageout (&odata->osync, &odata->opage) == 1)
{ if (stream_init == 0)
{ ogg_stream_init (&odata->ostream, ogg_page_serialno (&odata->opage)) ;
stream_init = 1 ;
} ;
if (ogg_page_serialno (&odata->opage) != odata->ostream.serialno)
{ /* so all streams are read. */
ogg_stream_reset_serialno (&odata->ostream, ogg_page_serialno (&odata->opage)) ;
} ;
/*Add page to the bitstream*/
ogg_stream_pagein (&odata->ostream, &odata->opage) ;
page_granule = ogg_page_granulepos (&odata->opage) ;
page_nb_packets = ogg_page_packets (&odata->opage) ;
/*Extract all available packets*/
while (odata->eos == 0 && ogg_stream_packetout (&odata->ostream, &odata->opacket) == 1)
{ if (odata->opacket.bytes >= 8 && memcmp (odata->opacket.packet, "Speex ", 8) == 0)
{ spx->serialno = odata->ostream.serialno ;
} ;
if (spx->serialno == -1 || odata->ostream.serialno != spx->serialno)
break ;
if (packet_count == 0)
{ spx->state = spx_header_read (psf, &odata->opacket, enh_enabled, force_mode) ;
if (! spx->state)
break ;
speex_decoder_ctl (spx->state, SPEEX_GET_LOOKAHEAD, &lookahead) ;
if (spx->nframes == 0)
spx->nframes = 1 ;
}
else if (packet_count == 1)
{ spx_print_comments ((const char*) odata->opacket.packet, odata->opacket.bytes) ;
}
else if (packet_count < 2 + spx->header.extra_headers)
{ /* Ignore extra headers */
}
packet_count ++ ;
} ;
} ;
psf_log_printf (psf, "End\n") ;
psf_log_printf (psf, "packet_count %d\n", packet_count) ;
psf_log_printf (psf, "page_nb_packets %d\n", page_nb_packets) ;
psf_log_printf (psf, "page_granule %lld\n", page_granule) ;
return 0 ;
} /* spx_read_header */
static int
spx_close (SF_PRIVATE *psf)
{ SPX_PRIVATE* spx = psf->codec_data ;
if (spx->state)
speex_decoder_destroy (spx->state) ;
if (spx)
speex_bits_destroy (&spx->bits) ;
return 0 ;
} /* spx_close */
static void *
spx_header_read (SF_PRIVATE * psf, ogg_packet *op, spx_int32_t enh_enabled, int force_mode)
{ SPX_PRIVATE* spx = psf->codec_data ;
void *st ;
const SpeexMode *mode ;
SpeexHeader *tmp_header ;
int modeID ;
SpeexCallback callback ;
tmp_header = speex_packet_to_header ((char*) op->packet, op->bytes) ;
if (tmp_header == NULL)
{ psf_log_printf (psf, "Cannot read Speex header\n") ;
return NULL ;
} ;
memcpy (&spx->header, tmp_header, sizeof (spx->header)) ;
free (tmp_header) ;
tmp_header = NULL ;
if (spx->header.mode >= SPEEX_NB_MODES || spx->header.mode < 0)
{ psf_log_printf (psf, "Mode number %d does not (yet/any longer) exist in this version\n", spx->header.mode) ;
return NULL ;
} ;
modeID = spx->header.mode ;
if (force_mode != -1)
modeID = force_mode ;
mode = speex_lib_get_mode (modeID) ;
if (spx->header.speex_version_id > 1)
{ psf_log_printf (psf, "This file was encoded with Speex bit-stream version %d, which I don't know how to decode\n", spx->header.speex_version_id) ;
return NULL ;
} ;
if (mode->bitstream_version < spx->header.mode_bitstream_version)
{ psf_log_printf (psf, "The file was encoded with a newer version of Speex. You need to upgrade in order to play it.\n") ;
return NULL ;
} ;
if (mode->bitstream_version > spx->header.mode_bitstream_version)
{ psf_log_printf (psf, "The file was encoded with an older version of Speex. You would need to downgrade the version in order to play it.\n") ;
return NULL ;
} ;
st = speex_decoder_init (mode) ;
if (!st)
{ psf_log_printf (psf, "Decoder initialization failed.\n") ;
return NULL ;
} ;
speex_decoder_ctl (st, SPEEX_SET_ENH, &enh_enabled) ;
speex_decoder_ctl (st, SPEEX_GET_FRAME_SIZE, &spx->frame_size) ;
spx->granule_frame_size = spx->frame_size ;
if (!psf->sf.samplerate)
psf->sf.samplerate = spx->header.rate ;
/* Adjust rate if --force-* options are used */
if (force_mode!=-1)
{ if (spx->header.mode < force_mode)
{ psf->sf.samplerate <<= (force_mode - spx->header.mode) ;
spx->granule_frame_size >>= (force_mode - spx->header.mode) ;
} ;
if (spx->header.mode > force_mode)
{ psf->sf.samplerate >>= (spx->header.mode - force_mode) ;
spx->granule_frame_size <<= (spx->header.mode - force_mode) ;
} ;
} ;
speex_decoder_ctl (st, SPEEX_SET_SAMPLING_RATE, &psf->sf.samplerate) ;
spx->nframes = spx->header.frames_per_packet ;
if (psf->sf.channels == -1)
psf->sf.channels = spx->header.nb_channels ;
if (! (psf->sf.channels == 1))
{ psf->sf.channels = 2 ;
callback.callback_id = SPEEX_INBAND_STEREO ;
callback.func = speex_std_stereo_request_handler ;
callback.data = &spx->stereo ;
speex_decoder_ctl (st, SPEEX_SET_HANDLER, &callback) ;
} ;
spx->header.speex_version [sizeof (spx->header.speex_version) - 1] = 0 ;
psf_log_printf (psf, " Encoder ver : %s\n Frames/packet : %d\n",
spx->header.speex_version, spx->header.frames_per_packet) ;
if (spx->header.bitrate > 0)
psf_log_printf (psf, " Bit rate : %d\n", spx->header.bitrate) ;
psf_log_printf (psf, " Sample rate : %d\n Mode : %s\n VBR : %s\n Channels : %d\n",
psf->sf.samplerate, mode->modeName, (spx->header.vbr ? "yes" : "no"), psf->sf.channels) ;
psf_log_printf (psf, " Extra headers : %d\n", spx->header.extra_headers) ;
return st ;
} /* spx_header_read */
static void
spx_print_comments (const char *c, int length)
{
const char *end ;
int len, i, nb_fields ;
printf ("%s %d\n", __func__, __LINE__) ;
if (length<8)
{ fprintf (stderr, "Invalid/corrupted comments\n") ;
return ;
}
end = c + length ;
len = readint (c, 0) ;
c += 4 ;
if (len < 0 || c + len > end)
{ fprintf (stderr, "Invalid/corrupted comments\n") ;
return ;
}
(void) fwrite (c, 1, len, stderr) ;
c += len ;
fprintf (stderr, "\n") ;
if (c + 4 > end)
{ fprintf (stderr, "Invalid/corrupted comments\n") ;
return ;
}
nb_fields = readint (c, 0) ;
c += 4 ;
for (i = 0 ; i < nb_fields ; i++)
{ if (c+4>end)
{ fprintf (stderr, "Invalid/corrupted comments\n") ;
return ;
} ;
len = readint (c, 0) ;
c += 4 ;
if (len < 0 || c + len > end)
{ fprintf (stderr, "Invalid/corrupted comments\n") ;
return ;
}
(void) fwrite (c, 1, len, stderr) ;
c += len ;
fprintf (stderr, "\n") ;
} ;
return ;
} /* spx_print_comments */
/*
encoded_speex_frames = (frames_per_packet * Packets)
= 1 * 272
= 272
audio_samples = encoded_speex_frames * frame_size
= 272 * 640
= 174080
duration = audio_samples / rate
= 174080 / 44100
= 3.947
*/
#else /* ENABLE_EXPERIMENTAL_CODE && HAVE_EXTERNAL_LIBS */
int
ogg_speex_open (SF_PRIVATE *psf)
{
psf_log_printf (psf, "This version of libsndfile was compiled without Ogg/Speex support.\n") ;
return SFE_UNIMPLEMENTED ;
} /* ogg_speex_open */
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,832 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
/*------------------------------------------------------------------------------
** Macros to handle big/little endian issues.
*/
#define FAP_MARKER (MAKE_MARKER ('f', 'a', 'p', ' '))
#define PAF_MARKER (MAKE_MARKER (' ', 'p', 'a', 'f'))
/*------------------------------------------------------------------------------
** Other defines.
*/
#define PAF_HEADER_LENGTH 2048
#define PAF24_SAMPLES_PER_BLOCK 10
#define PAF24_BLOCK_SIZE 32
/*------------------------------------------------------------------------------
** Typedefs.
*/
typedef struct
{ int version ;
int endianness ;
int samplerate ;
int format ;
int channels ;
int source ;
} PAF_FMT ;
typedef struct
{ int max_blocks, channels, samplesperblock, blocksize ;
int read_block, write_block, read_count, write_count ;
sf_count_t sample_count ;
int *samples ;
unsigned char *block ;
#if HAVE_FLEXIBLE_ARRAY
int data [] ; /* ISO C99 struct flexible array. */
#else
int data [1] ; /* This is a hack and may not work. */
#endif
} PAF24_PRIVATE ;
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int paf24_init (SF_PRIVATE *psf) ;
static int paf_read_header (SF_PRIVATE *psf) ;
static int paf_write_header (SF_PRIVATE *psf, int calc_length) ;
static sf_count_t paf24_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
static sf_count_t paf24_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
static sf_count_t paf24_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
static sf_count_t paf24_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
static sf_count_t paf24_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
static sf_count_t paf24_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
static sf_count_t paf24_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
static sf_count_t paf24_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
static sf_count_t paf24_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
enum
{ PAF_PCM_16 = 0,
PAF_PCM_24 = 1,
PAF_PCM_S8 = 2
} ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
paf_open (SF_PRIVATE *psf)
{ int subformat, error, endian ;
psf->dataoffset = PAF_HEADER_LENGTH ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = paf_read_header (psf)))
return error ;
} ;
subformat = SF_CODEC (psf->sf.format) ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_PAF)
return SFE_BAD_OPEN_FORMAT ;
endian = SF_ENDIAN (psf->sf.format) ;
/* PAF is by default big endian. */
psf->endian = SF_ENDIAN_BIG ;
if (endian == SF_ENDIAN_LITTLE || (CPU_IS_LITTLE_ENDIAN && (endian == SF_ENDIAN_CPU)))
psf->endian = SF_ENDIAN_LITTLE ;
if ((error = paf_write_header (psf, SF_FALSE)))
return error ;
psf->write_header = paf_write_header ;
} ;
switch (subformat)
{ case SF_FORMAT_PCM_S8 :
psf->bytewidth = 1 ;
error = pcm_init (psf) ;
break ;
case SF_FORMAT_PCM_16 :
psf->bytewidth = 2 ;
error = pcm_init (psf) ;
break ;
case SF_FORMAT_PCM_24 :
/* No bytewidth because of whacky 24 bit encoding. */
error = paf24_init (psf) ;
break ;
default : return SFE_PAF_UNKNOWN_FORMAT ;
} ;
return error ;
} /* paf_open */
/*------------------------------------------------------------------------------
*/
static int
paf_read_header (SF_PRIVATE *psf)
{ PAF_FMT paf_fmt ;
int marker ;
if (psf->filelength < PAF_HEADER_LENGTH)
return SFE_PAF_SHORT_HEADER ;
memset (&paf_fmt, 0, sizeof (paf_fmt)) ;
psf_binheader_readf (psf, "pm", 0, &marker) ;
psf_log_printf (psf, "Signature : '%M'\n", marker) ;
if (marker == PAF_MARKER)
{ psf_binheader_readf (psf, "E444444", &(paf_fmt.version), &(paf_fmt.endianness),
&(paf_fmt.samplerate), &(paf_fmt.format), &(paf_fmt.channels), &(paf_fmt.source)) ;
}
else if (marker == FAP_MARKER)
{ psf_binheader_readf (psf, "e444444", &(paf_fmt.version), &(paf_fmt.endianness),
&(paf_fmt.samplerate), &(paf_fmt.format), &(paf_fmt.channels), &(paf_fmt.source)) ;
}
else
return SFE_PAF_NO_MARKER ;
psf_log_printf (psf, "Version : %d\n", paf_fmt.version) ;
if (paf_fmt.version != 0)
{ psf_log_printf (psf, "*** Bad version number. should be zero.\n") ;
return SFE_PAF_VERSION ;
} ;
psf_log_printf (psf, "Sample Rate : %d\n", paf_fmt.samplerate) ;
psf_log_printf (psf, "Channels : %d\n", paf_fmt.channels) ;
psf_log_printf (psf, "Endianness : %d => ", paf_fmt.endianness) ;
if (paf_fmt.endianness)
{ psf_log_printf (psf, "Little\n", paf_fmt.endianness) ;
psf->endian = SF_ENDIAN_LITTLE ;
}
else
{ psf_log_printf (psf, "Big\n", paf_fmt.endianness) ;
psf->endian = SF_ENDIAN_BIG ;
} ;
if (paf_fmt.channels > SF_MAX_CHANNELS)
return SFE_PAF_BAD_CHANNELS ;
psf->datalength = psf->filelength - psf->dataoffset ;
psf_binheader_readf (psf, "p", (int) psf->dataoffset) ;
psf->sf.samplerate = paf_fmt.samplerate ;
psf->sf.channels = paf_fmt.channels ;
/* Only fill in type major. */
psf->sf.format = SF_FORMAT_PAF ;
psf_log_printf (psf, "Format : %d => ", paf_fmt.format) ;
/* PAF is by default big endian. */
psf->sf.format |= paf_fmt.endianness ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG ;
switch (paf_fmt.format)
{ case PAF_PCM_S8 :
psf_log_printf (psf, "8 bit linear PCM\n") ;
psf->bytewidth = 1 ;
psf->sf.format |= SF_FORMAT_PCM_S8 ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
psf->sf.frames = psf->datalength / psf->blockwidth ;
break ;
case PAF_PCM_16 :
psf_log_printf (psf, "16 bit linear PCM\n") ;
psf->bytewidth = 2 ;
psf->sf.format |= SF_FORMAT_PCM_16 ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
psf->sf.frames = psf->datalength / psf->blockwidth ;
break ;
case PAF_PCM_24 :
psf_log_printf (psf, "24 bit linear PCM\n") ;
psf->bytewidth = 3 ;
psf->sf.format |= SF_FORMAT_PCM_24 ;
psf->blockwidth = 0 ;
psf->sf.frames = PAF24_SAMPLES_PER_BLOCK * psf->datalength /
(PAF24_BLOCK_SIZE * psf->sf.channels) ;
break ;
default : psf_log_printf (psf, "Unknown\n") ;
return SFE_PAF_UNKNOWN_FORMAT ;
break ;
} ;
psf_log_printf (psf, "Source : %d => ", paf_fmt.source) ;
switch (paf_fmt.source)
{ case 1 : psf_log_printf (psf, "Analog Recording\n") ;
break ;
case 2 : psf_log_printf (psf, "Digital Transfer\n") ;
break ;
case 3 : psf_log_printf (psf, "Multi-track Mixdown\n") ;
break ;
case 5 : psf_log_printf (psf, "Audio Resulting From DSP Processing\n") ;
break ;
default : psf_log_printf (psf, "Unknown\n") ;
break ;
} ;
return 0 ;
} /* paf_read_header */
static int
paf_write_header (SF_PRIVATE *psf, int UNUSED (calc_length))
{ int paf_format ;
/* PAF header already written so no need to re-write. */
if (psf_ftell (psf) >= PAF_HEADER_LENGTH)
return 0 ;
psf->dataoffset = PAF_HEADER_LENGTH ;
switch (SF_CODEC (psf->sf.format))
{ case SF_FORMAT_PCM_S8 :
paf_format = PAF_PCM_S8 ;
break ;
case SF_FORMAT_PCM_16 :
paf_format = PAF_PCM_16 ;
break ;
case SF_FORMAT_PCM_24 :
paf_format = PAF_PCM_24 ;
break ;
default : return SFE_PAF_UNKNOWN_FORMAT ;
} ;
/* Reset the current header length to zero. */
psf->header [0] = 0 ;
psf->headindex = 0 ;
if (psf->endian == SF_ENDIAN_BIG)
{ /* Marker, version, endianness, samplerate */
psf_binheader_writef (psf, "Em444", PAF_MARKER, 0, 0, psf->sf.samplerate) ;
/* format, channels, source */
psf_binheader_writef (psf, "E444", paf_format, psf->sf.channels, 0) ;
}
else if (psf->endian == SF_ENDIAN_LITTLE)
{ /* Marker, version, endianness, samplerate */
psf_binheader_writef (psf, "em444", FAP_MARKER, 0, 1, psf->sf.samplerate) ;
/* format, channels, source */
psf_binheader_writef (psf, "e444", paf_format, psf->sf.channels, 0) ;
} ;
/* Zero fill to dataoffset. */
psf_binheader_writef (psf, "z", (size_t) (psf->dataoffset - psf->headindex)) ;
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
return psf->error ;
} /* paf_write_header */
/*===============================================================================
** 24 bit PAF files have a really weird encoding.
** For a mono file, 10 samples (each being 3 bytes) are packed into a 32 byte
** block. The 8 ints in this 32 byte block are then endian swapped (as ints)
** if necessary before being written to disk.
** For a stereo file, blocks of 10 samples from the same channel are encoded
** into 32 bytes as for the mono case. The 32 byte blocks are then interleaved
** on disk.
** Reading has to reverse the above process :-).
** Weird!!!
**
** The code below attempts to gain efficiency while maintaining readability.
*/
static int paf24_read_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24) ;
static int paf24_write_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24) ;
static int paf24_close (SF_PRIVATE *psf) ;
static int
paf24_init (SF_PRIVATE *psf)
{ PAF24_PRIVATE *ppaf24 ;
int paf24size ;
paf24size = sizeof (PAF24_PRIVATE) + psf->sf.channels *
(PAF24_BLOCK_SIZE + PAF24_SAMPLES_PER_BLOCK * sizeof (int)) ;
/*
** Not exatly sure why this needs to be here but the tests
** fail without it.
*/
psf->last_op = 0 ;
if (! (psf->codec_data = calloc (1, paf24size)))
return SFE_MALLOC_FAILED ;
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
ppaf24->channels = psf->sf.channels ;
ppaf24->samples = ppaf24->data ;
ppaf24->block = (unsigned char*) (ppaf24->data + PAF24_SAMPLES_PER_BLOCK * ppaf24->channels) ;
ppaf24->blocksize = PAF24_BLOCK_SIZE * ppaf24->channels ;
ppaf24->samplesperblock = PAF24_SAMPLES_PER_BLOCK ;
if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR)
{ paf24_read_block (psf, ppaf24) ; /* Read first block. */
psf->read_short = paf24_read_s ;
psf->read_int = paf24_read_i ;
psf->read_float = paf24_read_f ;
psf->read_double = paf24_read_d ;
} ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ psf->write_short = paf24_write_s ;
psf->write_int = paf24_write_i ;
psf->write_float = paf24_write_f ;
psf->write_double = paf24_write_d ;
} ;
psf->seek = paf24_seek ;
psf->container_close = paf24_close ;
psf->filelength = psf_get_filelen (psf) ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf->datalength % PAF24_BLOCK_SIZE)
{ if (psf->file.mode == SFM_READ)
psf_log_printf (psf, "*** Warning : file seems to be truncated.\n") ;
ppaf24->max_blocks = psf->datalength / ppaf24->blocksize + 1 ;
}
else
ppaf24->max_blocks = psf->datalength / ppaf24->blocksize ;
ppaf24->read_block = 0 ;
if (psf->file.mode == SFM_RDWR)
ppaf24->write_block = ppaf24->max_blocks ;
else
ppaf24->write_block = 0 ;
psf->sf.frames = ppaf24->samplesperblock * ppaf24->max_blocks ;
ppaf24->sample_count = psf->sf.frames ;
return 0 ;
} /* paf24_init */
static sf_count_t
paf24_seek (SF_PRIVATE *psf, int mode, sf_count_t offset)
{ PAF24_PRIVATE *ppaf24 ;
int newblock, newsample ;
if (psf->codec_data == NULL)
{ psf->error = SFE_INTERNAL ;
return PSF_SEEK_ERROR ;
} ;
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
if (mode == SFM_READ && ppaf24->write_count > 0)
paf24_write_block (psf, ppaf24) ;
newblock = offset / ppaf24->samplesperblock ;
newsample = offset % ppaf24->samplesperblock ;
switch (mode)
{ case SFM_READ :
if (psf->last_op == SFM_WRITE && ppaf24->write_count)
paf24_write_block (psf, ppaf24) ;
psf_fseek (psf, psf->dataoffset + newblock * ppaf24->blocksize, SEEK_SET) ;
ppaf24->read_block = newblock ;
paf24_read_block (psf, ppaf24) ;
ppaf24->read_count = newsample ;
break ;
case SFM_WRITE :
if (offset > ppaf24->sample_count)
{ psf->error = SFE_BAD_SEEK ;
return PSF_SEEK_ERROR ;
} ;
if (psf->last_op == SFM_WRITE && ppaf24->write_count)
paf24_write_block (psf, ppaf24) ;
psf_fseek (psf, psf->dataoffset + newblock * ppaf24->blocksize, SEEK_SET) ;
ppaf24->write_block = newblock ;
paf24_read_block (psf, ppaf24) ;
ppaf24->write_count = newsample ;
break ;
default :
psf->error = SFE_BAD_SEEK ;
return PSF_SEEK_ERROR ;
} ;
return newblock * ppaf24->samplesperblock + newsample ;
} /* paf24_seek */
static int
paf24_close (SF_PRIVATE *psf)
{ PAF24_PRIVATE *ppaf24 ;
if (psf->codec_data == NULL)
return 0 ;
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if (ppaf24->write_count > 0)
paf24_write_block (psf, ppaf24) ;
} ;
return 0 ;
} /* paf24_close */
/*---------------------------------------------------------------------------
*/
static int
paf24_read_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24)
{ int k, channel ;
unsigned char *cptr ;
ppaf24->read_block ++ ;
ppaf24->read_count = 0 ;
if (ppaf24->read_block * ppaf24->samplesperblock > ppaf24->sample_count)
{ memset (ppaf24->samples, 0, ppaf24->samplesperblock * ppaf24->channels) ;
return 1 ;
} ;
/* Read the block. */
if ((k = psf_fread (ppaf24->block, 1, ppaf24->blocksize, psf)) != ppaf24->blocksize)
psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, ppaf24->blocksize) ;
if (CPU_IS_LITTLE_ENDIAN)
{ /* Do endian swapping if necessary. */
if (psf->endian == SF_ENDIAN_BIG)
endswap_int_array (ppaf24->data, 8 * ppaf24->channels) ;
/* Unpack block. */
for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++)
{ channel = k % ppaf24->channels ;
cptr = ppaf24->block + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ;
ppaf24->samples [k] = (cptr [0] << 8) | (cptr [1] << 16) | (cptr [2] << 24) ;
} ;
}
else
{ /* Do endian swapping if necessary. */
if (psf->endian == SF_ENDIAN_BIG)
endswap_int_array (ppaf24->data, 8 * ppaf24->channels) ;
/* Unpack block. */
for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++)
{ channel = k % ppaf24->channels ;
cptr = ppaf24->block + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ;
ppaf24->samples [k] = (cptr [0] << 8) | (cptr [1] << 16) | (cptr [2] << 24) ;
} ;
} ;
return 1 ;
} /* paf24_read_block */
static int
paf24_read (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24, int *ptr, int len)
{ int count, total = 0 ;
while (total < len)
{ if (ppaf24->read_block * ppaf24->samplesperblock >= ppaf24->sample_count)
{ memset (&(ptr [total]), 0, (len - total) * sizeof (int)) ;
return total ;
} ;
if (ppaf24->read_count >= ppaf24->samplesperblock)
paf24_read_block (psf, ppaf24) ;
count = (ppaf24->samplesperblock - ppaf24->read_count) * ppaf24->channels ;
count = (len - total > count) ? count : len - total ;
memcpy (&(ptr [total]), &(ppaf24->samples [ppaf24->read_count * ppaf24->channels]), count * sizeof (int)) ;
total += count ;
ppaf24->read_count += count / ppaf24->channels ;
} ;
return total ;
} /* paf24_read */
static sf_count_t
paf24_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
{ PAF24_PRIVATE *ppaf24 ;
int *iptr ;
int k, bufferlen, readcount, count ;
sf_count_t total = 0 ;
if (psf->codec_data == NULL)
return 0 ;
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
iptr = psf->u.ibuf ;
bufferlen = ARRAY_LEN (psf->u.ibuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = paf24_read (psf, ppaf24, iptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = iptr [k] >> 16 ;
total += count ;
len -= readcount ;
} ;
return total ;
} /* paf24_read_s */
static sf_count_t
paf24_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
{ PAF24_PRIVATE *ppaf24 ;
int total ;
if (psf->codec_data == NULL)
return 0 ;
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
total = paf24_read (psf, ppaf24, ptr, len) ;
return total ;
} /* paf24_read_i */
static sf_count_t
paf24_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
{ PAF24_PRIVATE *ppaf24 ;
int *iptr ;
int k, bufferlen, readcount, count ;
sf_count_t total = 0 ;
float normfact ;
if (psf->codec_data == NULL)
return 0 ;
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_float == SF_TRUE) ? (1.0 / 0x80000000) : (1.0 / 0x100) ;
iptr = psf->u.ibuf ;
bufferlen = ARRAY_LEN (psf->u.ibuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = paf24_read (psf, ppaf24, iptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = normfact * iptr [k] ;
total += count ;
len -= readcount ;
} ;
return total ;
} /* paf24_read_f */
static sf_count_t
paf24_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
{ PAF24_PRIVATE *ppaf24 ;
int *iptr ;
int k, bufferlen, readcount, count ;
sf_count_t total = 0 ;
double normfact ;
if (psf->codec_data == NULL)
return 0 ;
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_double == SF_TRUE) ? (1.0 / 0x80000000) : (1.0 / 0x100) ;
iptr = psf->u.ibuf ;
bufferlen = ARRAY_LEN (psf->u.ibuf) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = paf24_read (psf, ppaf24, iptr, readcount) ;
for (k = 0 ; k < readcount ; k++)
ptr [total + k] = normfact * iptr [k] ;
total += count ;
len -= readcount ;
} ;
return total ;
} /* paf24_read_d */
/*---------------------------------------------------------------------------
*/
static int
paf24_write_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24)
{ int k, nextsample, channel ;
unsigned char *cptr ;
/* First pack block. */
if (CPU_IS_LITTLE_ENDIAN)
{ for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++)
{ channel = k % ppaf24->channels ;
cptr = ppaf24->block + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ;
nextsample = ppaf24->samples [k] >> 8 ;
cptr [0] = nextsample ;
cptr [1] = nextsample >> 8 ;
cptr [2] = nextsample >> 16 ;
} ;
/* Do endian swapping if necessary. */
if (psf->endian == SF_ENDIAN_BIG)
endswap_int_array (ppaf24->data, 8 * ppaf24->channels) ;
}
else if (CPU_IS_BIG_ENDIAN)
{ /* This is correct. */
for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++)
{ channel = k % ppaf24->channels ;
cptr = ppaf24->block + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ;
nextsample = ppaf24->samples [k] >> 8 ;
cptr [0] = nextsample ;
cptr [1] = nextsample >> 8 ;
cptr [2] = nextsample >> 16 ;
} ;
if (psf->endian == SF_ENDIAN_BIG)
endswap_int_array (ppaf24->data, 8 * ppaf24->channels) ;
} ;
/* Write block to disk. */
if ((k = psf_fwrite (ppaf24->block, 1, ppaf24->blocksize, psf)) != ppaf24->blocksize)
psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, ppaf24->blocksize) ;
if (ppaf24->sample_count < ppaf24->write_block * ppaf24->samplesperblock + ppaf24->write_count)
ppaf24->sample_count = ppaf24->write_block * ppaf24->samplesperblock + ppaf24->write_count ;
if (ppaf24->write_count == ppaf24->samplesperblock)
{ ppaf24->write_block ++ ;
ppaf24->write_count = 0 ;
} ;
return 1 ;
} /* paf24_write_block */
static int
paf24_write (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24, const int *ptr, int len)
{ int count, total = 0 ;
while (total < len)
{ count = (ppaf24->samplesperblock - ppaf24->write_count) * ppaf24->channels ;
if (count > len - total)
count = len - total ;
memcpy (&(ppaf24->samples [ppaf24->write_count * ppaf24->channels]), &(ptr [total]), count * sizeof (int)) ;
total += count ;
ppaf24->write_count += count / ppaf24->channels ;
if (ppaf24->write_count >= ppaf24->samplesperblock)
paf24_write_block (psf, ppaf24) ;
} ;
return total ;
} /* paf24_write */
static sf_count_t
paf24_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
{ PAF24_PRIVATE *ppaf24 ;
int *iptr ;
int k, bufferlen, writecount = 0, count ;
sf_count_t total = 0 ;
if (psf->codec_data == NULL)
return 0 ;
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
iptr = psf->u.ibuf ;
bufferlen = ARRAY_LEN (psf->u.ibuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
iptr [k] = ptr [total + k] << 16 ;
count = paf24_write (psf, ppaf24, iptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* paf24_write_s */
static sf_count_t
paf24_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
{ PAF24_PRIVATE *ppaf24 ;
int writecount, count ;
sf_count_t total = 0 ;
if (psf->codec_data == NULL)
return 0 ;
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
while (len > 0)
{ writecount = (len > 0x10000000) ? 0x10000000 : (int) len ;
count = paf24_write (psf, ppaf24, ptr, writecount) ;
total += count ;
len -= count ;
if (count != writecount)
break ;
} ;
return total ;
} /* paf24_write_i */
static sf_count_t
paf24_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
{ PAF24_PRIVATE *ppaf24 ;
int *iptr ;
int k, bufferlen, writecount = 0, count ;
sf_count_t total = 0 ;
float normfact ;
if (psf->codec_data == NULL)
return 0 ;
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : (1.0 / 0x100) ;
iptr = psf->u.ibuf ;
bufferlen = ARRAY_LEN (psf->u.ibuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
iptr [k] = lrintf (normfact * ptr [total + k]) ;
count = paf24_write (psf, ppaf24, iptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* paf24_write_f */
static sf_count_t
paf24_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
{ PAF24_PRIVATE *ppaf24 ;
int *iptr ;
int k, bufferlen, writecount = 0, count ;
sf_count_t total = 0 ;
double normfact ;
if (psf->codec_data == NULL)
return 0 ;
ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : (1.0 / 0x100) ;
iptr = psf->u.ibuf ;
bufferlen = ARRAY_LEN (psf->u.ibuf) ;
while (len > 0)
{ writecount = (len >= bufferlen) ? bufferlen : len ;
for (k = 0 ; k < writecount ; k++)
iptr [k] = lrint (normfact * ptr [total+k]) ;
count = paf24_write (psf, ppaf24, iptr, writecount) ;
total += count ;
len -= writecount ;
if (count != writecount)
break ;
} ;
return total ;
} /* paf24_write_d */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,188 @@
/*
** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
/*------------------------------------------------------------------------------
** Macros to handle big/little endian issues.
*/
#define PVF1_MARKER (MAKE_MARKER ('P', 'V', 'F', '1'))
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int pvf_close (SF_PRIVATE *psf) ;
static int pvf_write_header (SF_PRIVATE *psf, int calc_length) ;
static int pvf_read_header (SF_PRIVATE *psf) ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
pvf_open (SF_PRIVATE *psf)
{ int subformat ;
int error = 0 ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = pvf_read_header (psf)))
return error ;
} ;
subformat = SF_CODEC (psf->sf.format) ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_PVF)
return SFE_BAD_OPEN_FORMAT ;
psf->endian = SF_ENDIAN_BIG ;
if (pvf_write_header (psf, SF_FALSE))
return psf->error ;
psf->write_header = pvf_write_header ;
} ;
psf->container_close = pvf_close ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
switch (subformat)
{ case SF_FORMAT_PCM_S8 : /* 8-bit linear PCM. */
case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */
case SF_FORMAT_PCM_32 : /* 32-bit linear PCM. */
error = pcm_init (psf) ;
break ;
default : break ;
} ;
return error ;
} /* pvf_open */
/*------------------------------------------------------------------------------
*/
static int
pvf_close (SF_PRIVATE * UNUSED (psf))
{
return 0 ;
} /* pvf_close */
static int
pvf_write_header (SF_PRIVATE *psf, int UNUSED (calc_length))
{ sf_count_t current ;
if (psf->pipeoffset > 0)
return 0 ;
current = psf_ftell (psf) ;
/* Reset the current header length to zero. */
psf->header [0] = 0 ;
psf->headindex = 0 ;
if (psf->is_pipe == SF_FALSE)
psf_fseek (psf, 0, SEEK_SET) ;
snprintf ((char*) psf->header, sizeof (psf->header), "PVF1\n%d %d %d\n",
psf->sf.channels, psf->sf.samplerate, psf->bytewidth * 8) ;
psf->headindex = strlen ((char*) psf->header) ;
/* Header construction complete so write it out. */
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
if (psf->error)
return psf->error ;
psf->dataoffset = psf->headindex ;
if (current > 0)
psf_fseek (psf, current, SEEK_SET) ;
return psf->error ;
} /* pvf_write_header */
static int
pvf_read_header (SF_PRIVATE *psf)
{ char buffer [32] ;
int marker, channels, samplerate, bitwidth ;
psf_binheader_readf (psf, "pmj", 0, &marker, 1) ;
psf_log_printf (psf, "%M\n", marker) ;
if (marker != PVF1_MARKER)
return SFE_PVF_NO_PVF1 ;
/* Grab characters up until a newline which is replaced by an EOS. */
psf_binheader_readf (psf, "G", buffer, sizeof (buffer)) ;
if (sscanf (buffer, "%d %d %d", &channels, &samplerate, &bitwidth) != 3)
return SFE_PVF_BAD_HEADER ;
psf_log_printf (psf, " Channels : %d\n Sample rate : %d\n Bit width : %d\n",
channels, samplerate, bitwidth) ;
psf->sf.channels = channels ;
psf->sf.samplerate = samplerate ;
switch (bitwidth)
{ case 8 :
psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_S8 ;
psf->bytewidth = 1 ;
break ;
case 16 :
psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_16 ;
psf->bytewidth = 2 ;
break ;
case 32 :
psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_32 ;
psf->bytewidth = 4 ;
break ;
default :
return SFE_PVF_BAD_BITWIDTH ;
} ;
psf->dataoffset = psf_ftell (psf) ;
psf_log_printf (psf, " Data Offset : %D\n", psf->dataoffset) ;
psf->endian = SF_ENDIAN_BIG ;
psf->datalength = psf->filelength - psf->dataoffset ;
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
if (! psf->sf.frames && psf->blockwidth)
psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ;
return 0 ;
} /* pvf_read_header */

View File

@@ -0,0 +1,104 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include "sndfile.h"
#include "common.h"
/*------------------------------------------------------------------------------
** Public function.
*/
int
raw_open (SF_PRIVATE *psf)
{ int subformat, error = SFE_NO_ERROR ;
subformat = SF_CODEC (psf->sf.format) ;
psf->endian = SF_ENDIAN (psf->sf.format) ;
if (CPU_IS_BIG_ENDIAN && (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU))
psf->endian = SF_ENDIAN_BIG ;
else if (CPU_IS_LITTLE_ENDIAN && (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU))
psf->endian = SF_ENDIAN_LITTLE ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
psf->dataoffset = 0 ;
psf->datalength = psf->filelength ;
switch (subformat)
{ case SF_FORMAT_PCM_S8 :
error = pcm_init (psf) ;
break ;
case SF_FORMAT_PCM_U8 :
error = pcm_init (psf) ;
break ;
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_24 :
case SF_FORMAT_PCM_32 :
error = pcm_init (psf) ;
break ;
case SF_FORMAT_ULAW :
error = ulaw_init (psf) ;
break ;
case SF_FORMAT_ALAW :
error = alaw_init (psf) ;
break ;
case SF_FORMAT_GSM610 :
error = gsm610_init (psf) ;
break ;
/* Lite remove start */
case SF_FORMAT_FLOAT :
error = float32_init (psf) ;
break ;
case SF_FORMAT_DOUBLE :
error = double64_init (psf) ;
break ;
case SF_FORMAT_DWVW_12 :
error = dwvw_init (psf, 12) ;
break ;
case SF_FORMAT_DWVW_16 :
error = dwvw_init (psf, 16) ;
break ;
case SF_FORMAT_DWVW_24 :
error = dwvw_init (psf, 24) ;
break ;
case SF_FORMAT_VOX_ADPCM :
error = vox_adpcm_init (psf) ;
break ;
/* Lite remove end */
default : return SFE_BAD_OPEN_FORMAT ;
} ;
return error ;
} /* raw_open */

View File

@@ -0,0 +1,716 @@
/*
** Copyright (C) 2008-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
** Copyright (C) 2009 Uli Franke <cls@nebadje.org>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
** This format documented at:
** http://www.sr.se/utveckling/tu/bwf/prog/RF_64v1_4.pdf
**
** But this may be a better reference:
** http://www.ebu.ch/CMSimages/en/tec_doc_t3306-2007_tcm6-42570.pdf
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#include "wav_w64.h"
/*------------------------------------------------------------------------------
** Macros to handle big/little endian issues.
*/
#define RF64_MARKER MAKE_MARKER ('R', 'F', '6', '4')
#define FFFF_MARKER MAKE_MARKER (0xff, 0xff, 0xff, 0xff)
#define WAVE_MARKER MAKE_MARKER ('W', 'A', 'V', 'E')
#define ds64_MARKER MAKE_MARKER ('d', 's', '6', '4')
#define fmt_MARKER MAKE_MARKER ('f', 'm', 't', ' ')
#define fact_MARKER MAKE_MARKER ('f', 'a', 'c', 't')
#define data_MARKER MAKE_MARKER ('d', 'a', 't', 'a')
#define bext_MARKER MAKE_MARKER ('b', 'e', 'x', 't')
#define OggS_MARKER MAKE_MARKER ('O', 'g', 'g', 'S')
#define wvpk_MARKER MAKE_MARKER ('w', 'v', 'p', 'k')
/*------------------------------------------------------------------------------
** Typedefs.
*/
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int rf64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) ;
static int rf64_write_header (SF_PRIVATE *psf, int calc_length) ;
static int rf64_close (SF_PRIVATE *psf) ;
static int rf64_command (SF_PRIVATE *psf, int command, void * UNUSED (data), int datasize) ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
rf64_open (SF_PRIVATE *psf)
{ WAV_PRIVATE *wpriv ;
int subformat, error = 0 ;
int blockalign, framesperblock ;
if ((wpriv = calloc (1, sizeof (WAV_PRIVATE))) == NULL)
return SFE_MALLOC_FAILED ;
psf->container_data = wpriv ;
wpriv->wavex_ambisonic = SF_AMBISONIC_NONE ;
/* All RF64 files are little endian. */
psf->endian = SF_ENDIAN_LITTLE ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = rf64_read_header (psf, &blockalign, &framesperblock)) != 0)
return error ;
} ;
if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RF64)
return SFE_BAD_OPEN_FORMAT ;
subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if (psf->is_pipe)
return SFE_NO_PIPE_WRITE ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
if ((error = rf64_write_header (psf, SF_FALSE)))
return error ;
psf->write_header = rf64_write_header ;
} ;
psf->container_close = rf64_close ;
psf->command = rf64_command ;
switch (subformat)
{ case SF_FORMAT_PCM_U8 :
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_24 :
case SF_FORMAT_PCM_32 :
error = pcm_init (psf) ;
break ;
case SF_FORMAT_ULAW :
error = ulaw_init (psf) ;
break ;
case SF_FORMAT_ALAW :
error = alaw_init (psf) ;
break ;
/* Lite remove start */
case SF_FORMAT_FLOAT :
error = float32_init (psf) ;
break ;
case SF_FORMAT_DOUBLE :
error = double64_init (psf) ;
break ;
/* Lite remove end */
default : return SFE_UNIMPLEMENTED ;
} ;
return error ;
} /* rf64_open */
/*------------------------------------------------------------------------------
*/
enum
{ HAVE_ds64 = 0x01,
HAVE_fmt = 0x02,
HAVE_bext = 0x04,
HAVE_data = 0x08
} ;
#define HAVE_CHUNK(CHUNK) ((parsestage & CHUNK) != 0)
static int
rf64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock)
{ WAV_PRIVATE *wpriv ;
WAV_FMT *wav_fmt ;
sf_count_t riff_size = 0, frame_count = 0, ds64_datalength = 0 ;
unsigned int size32, parsestage = 0 ;
int marker, marks [2], error, done = 0, format = 0 ;
if ((wpriv = psf->container_data) == NULL)
return SFE_INTERNAL ;
wav_fmt = &wpriv->wav_fmt ;
/* Set position to start of file to begin reading header. */
psf_binheader_readf (psf, "pmmm", 0, &marker, marks, marks + 1) ;
if (marker != RF64_MARKER || marks [1] != WAVE_MARKER)
return SFE_RF64_NOT_RF64 ;
if (marks [0] == FFFF_MARKER)
psf_log_printf (psf, "%M\n %M\n", RF64_MARKER, WAVE_MARKER) ;
else
psf_log_printf (psf, "%M : 0x%x (should be 0xFFFFFFFF)\n %M\n", RF64_MARKER, WAVE_MARKER) ;
while (NOT (done))
{ psf_binheader_readf (psf, "em4", &marker, &size32) ;
switch (marker)
{ case ds64_MARKER :
{ unsigned int table_len, bytesread ;
/* Read ds64 sizes (3 8-byte words). */
bytesread = psf_binheader_readf (psf, "888", &riff_size, &ds64_datalength, &frame_count) ;
/* Read table length. */
bytesread += psf_binheader_readf (psf, "4", &table_len) ;
/* Skip table for now. (this was "table_len + 4", why?) */
bytesread += psf_binheader_readf (psf, "j", table_len) ;
if (size32 == bytesread)
psf_log_printf (psf, "%M : %u\n", marker, size32) ;
else if (size32 >= bytesread + 4)
{ unsigned int next ;
psf_binheader_readf (psf, "m", &next) ;
if (next == fmt_MARKER)
{ psf_log_printf (psf, "%M : %u (should be %u)\n", marker, size32, bytesread) ;
psf_binheader_readf (psf, "j", -4) ;
}
else
{ psf_log_printf (psf, "%M : %u\n", marker, size32) ;
psf_binheader_readf (psf, "j", size32 - bytesread - 4) ;
} ;
} ;
if (psf->filelength != riff_size + 8)
psf_log_printf (psf, " Riff size : %D (should be %D)\n", riff_size, psf->filelength - 8) ;
else
psf_log_printf (psf, " Riff size : %D\n", riff_size) ;
psf_log_printf (psf, " Data size : %D\n", ds64_datalength) ;
psf_log_printf (psf, " Frames : %D\n", frame_count) ;
psf_log_printf (psf, " Table length : %u\n", table_len) ;
} ;
parsestage |= HAVE_ds64 ;
break ;
case fmt_MARKER:
psf_log_printf (psf, "%M : %u\n", marker, size32) ;
if ((error = wav_w64_read_fmt_chunk (psf, size32)) != 0)
return error ;
format = wav_fmt->format ;
parsestage |= HAVE_fmt ;
break ;
case bext_MARKER :
if ((error = wav_read_bext_chunk (psf, size32)) != 0)
return error ;
parsestage |= HAVE_bext ;
break ;
case data_MARKER :
/* see wav for more sophisticated parsing -> implement state machine with parsestage */
if (HAVE_CHUNK (HAVE_ds64))
{ if (size32 == 0xffffffff)
psf_log_printf (psf, "%M : 0x%x\n", marker, size32) ;
else
psf_log_printf (psf, "%M : 0x%x (should be 0xffffffff\n", marker, size32) ;
psf->datalength = ds64_datalength ;
}
else
{ if (size32 == 0xffffffff)
{ psf_log_printf (psf, "%M : 0x%x\n", marker, size32) ;
psf_log_printf (psf, " *** Data length not specified no 'ds64' chunk.\n") ;
}
else
{ psf_log_printf (psf, "%M : 0x%x\n**** Weird, RF64 file without a 'ds64' chunk and no valid 'data' size.\n", marker, size32) ;
psf->datalength = size32 ;
} ;
} ;
psf->dataoffset = psf_ftell (psf) ;
if (psf->dataoffset > 0)
{ if (size32 == 0 && riff_size == 8 && psf->filelength > 44)
{ psf_log_printf (psf, " *** Looks like a WAV file which wasn't closed properly. Fixing it.\n") ;
psf->datalength = psf->filelength - psf->dataoffset ;
} ;
/* Only set dataend if there really is data at the end. */
if (psf->datalength + psf->dataoffset < psf->filelength)
psf->dataend = psf->datalength + psf->dataoffset ;
if (NOT (psf->sf.seekable) || psf->dataoffset < 0)
break ;
/* Seek past data and continue reading header. */
psf_fseek (psf, psf->datalength, SEEK_CUR) ;
if (psf_ftell (psf) != psf->datalength + psf->dataoffset)
psf_log_printf (psf, " *** psf_fseek past end error ***\n") ;
break ;
} ;
break ;
default :
if (isprint ((marker >> 24) & 0xFF) && isprint ((marker >> 16) & 0xFF)
&& isprint ((marker >> 8) & 0xFF) && isprint (marker & 0xFF))
{ psf_log_printf (psf, "*** %M : %d (unknown marker)\n", marker, size32) ;
if (size32 < 8)
done = SF_TRUE ;
psf_binheader_readf (psf, "j", size32) ;
break ;
} ;
if (psf_ftell (psf) & 0x03)
{ psf_log_printf (psf, " Unknown chunk marker at position 0x%x. Resynching.\n", size32 - 4) ;
psf_binheader_readf (psf, "j", -3) ;
break ;
} ;
psf_log_printf (psf, "*** Unknown chunk marker (0x%X) at position 0x%X. Exiting parser.\n", marker, psf_ftell (psf) - 4) ;
done = SF_TRUE ;
break ;
} ; /* switch (marker) */
if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (marker))
{ psf_log_printf (psf, "End\n") ;
break ;
} ;
} ;
if (psf->dataoffset <= 0)
return SFE_WAV_NO_DATA ;
/* WAVs can be little or big endian */
psf->endian = psf->rwf_endian ;
psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
if (psf->is_pipe == 0)
{ /*
** Check for 'wvpk' at the start of the DATA section. Not able to
** handle this.
*/
psf_binheader_readf (psf, "4", &marker) ;
if (marker == wvpk_MARKER || marker == OggS_MARKER)
return SFE_WAV_WVPK_DATA ;
} ;
/* Seek to start of DATA section. */
psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
if (psf->blockwidth)
{ if (psf->filelength - psf->dataoffset < psf->datalength)
psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ;
else
psf->sf.frames = psf->datalength / psf->blockwidth ;
} ;
if (frame_count != psf->sf.frames)
psf_log_printf (psf, "*** Calculated frame count %d does not match value from 'ds64' chunk of %d.\n", psf->sf.frames, frame_count) ;
switch (format)
{
case WAVE_FORMAT_EXTENSIBLE :
/* with WAVE_FORMAT_EXTENSIBLE the psf->sf.format field is already set. We just have to set the major to rf64 */
psf->sf.format = (psf->sf.format & ~SF_FORMAT_TYPEMASK ) | SF_FORMAT_RF64 ;
if (psf->sf.format == (SF_FORMAT_WAVEX | SF_FORMAT_MS_ADPCM))
{ *blockalign = wav_fmt->msadpcm.blockalign ;
*framesperblock = wav_fmt->msadpcm.samplesperblock ;
} ;
break ;
case WAVE_FORMAT_PCM :
psf->sf.format = SF_FORMAT_RF64 | u_bitwidth_to_subformat (psf->bytewidth * 8) ;
break ;
case WAVE_FORMAT_MULAW :
case IBM_FORMAT_MULAW :
psf->sf.format = (SF_FORMAT_RF64 | SF_FORMAT_ULAW) ;
break ;
case WAVE_FORMAT_ALAW :
case IBM_FORMAT_ALAW :
psf->sf.format = (SF_FORMAT_RF64 | SF_FORMAT_ALAW) ;
break ;
case WAVE_FORMAT_MS_ADPCM :
psf->sf.format = (SF_FORMAT_RF64 | SF_FORMAT_MS_ADPCM) ;
*blockalign = wav_fmt->msadpcm.blockalign ;
*framesperblock = wav_fmt->msadpcm.samplesperblock ;
break ;
case WAVE_FORMAT_IMA_ADPCM :
psf->sf.format = (SF_FORMAT_RF64 | SF_FORMAT_IMA_ADPCM) ;
*blockalign = wav_fmt->ima.blockalign ;
*framesperblock = wav_fmt->ima.samplesperblock ;
break ;
case WAVE_FORMAT_GSM610 :
psf->sf.format = (SF_FORMAT_RF64 | SF_FORMAT_GSM610) ;
break ;
case WAVE_FORMAT_IEEE_FLOAT :
psf->sf.format = SF_FORMAT_RF64 ;
psf->sf.format |= (psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT ;
break ;
case WAVE_FORMAT_G721_ADPCM :
psf->sf.format = SF_FORMAT_RF64 | SF_FORMAT_G721_32 ;
break ;
default : return SFE_UNIMPLEMENTED ;
} ;
if (wpriv->fmt_is_broken)
wav_w64_analyze (psf) ;
/* Only set the format endian-ness if its non-standard big-endian. */
if (psf->endian == SF_ENDIAN_BIG)
psf->sf.format |= SF_ENDIAN_BIG ;
return 0 ;
} /* rf64_read_header */
/* known WAVEFORMATEXTENSIBLE GUIDS */
static const EXT_SUBFORMAT MSGUID_SUBTYPE_PCM =
{ 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
} ;
static const EXT_SUBFORMAT MSGUID_SUBTYPE_MS_ADPCM =
{ 0x00000002, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
} ;
static const EXT_SUBFORMAT MSGUID_SUBTYPE_IEEE_FLOAT =
{ 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
} ;
static const EXT_SUBFORMAT MSGUID_SUBTYPE_ALAW =
{ 0x00000006, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
} ;
static const EXT_SUBFORMAT MSGUID_SUBTYPE_MULAW =
{ 0x00000007, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
} ;
/*
** the next two are from
** http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html
*/
static const EXT_SUBFORMAT MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM =
{ 0x00000001, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 }
} ;
static const EXT_SUBFORMAT MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT =
{ 0x00000003, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 }
} ;
static int
rf64_write_fmt_chunk (SF_PRIVATE *psf)
{ WAV_PRIVATE *wpriv ;
int subformat, fmt_size ;
if ((wpriv = psf->container_data) == NULL)
return SFE_INTERNAL ;
subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
/* initial section (same for all, it appears) */
switch (subformat)
{ case SF_FORMAT_PCM_U8 :
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_24 :
case SF_FORMAT_PCM_32 :
case SF_FORMAT_FLOAT :
case SF_FORMAT_DOUBLE :
case SF_FORMAT_ULAW :
case SF_FORMAT_ALAW :
fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 + 4 + 4 + 2 + 2 + 8 ;
/* fmt : format, channels, samplerate */
psf_binheader_writef (psf, "4224", fmt_size, WAVE_FORMAT_EXTENSIBLE, psf->sf.channels, psf->sf.samplerate) ;
/* fmt : bytespersec */
psf_binheader_writef (psf, "4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
/* fmt : blockalign, bitwidth */
psf_binheader_writef (psf, "22", psf->bytewidth * psf->sf.channels, psf->bytewidth * 8) ;
/* cbSize 22 is sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX) */
psf_binheader_writef (psf, "2", 22) ;
/* wValidBitsPerSample, for our use same as bitwidth as we use it fully */
psf_binheader_writef (psf, "2", psf->bytewidth * 8) ;
/* For an Ambisonic file set the channel mask to zero.
** Otherwise use a default based on the channel count.
*/
if (wpriv->wavex_ambisonic != SF_AMBISONIC_NONE)
psf_binheader_writef (psf, "4", 0) ;
else if (wpriv->wavex_channelmask != 0)
psf_binheader_writef (psf, "4", wpriv->wavex_channelmask) ;
else
{ /*
** Ok some liberty is taken here to use the most commonly used channel masks
** instead of "no mapping". If you really want to use "no mapping" for 8 channels and less
** please don't use wavex. (otherwise we'll have to create a new SF_COMMAND)
*/
switch (psf->sf.channels)
{ case 1 : /* center channel mono */
psf_binheader_writef (psf, "4", 0x4) ;
break ;
case 2 : /* front left and right */
psf_binheader_writef (psf, "4", 0x1 | 0x2) ;
break ;
case 4 : /* Quad */
psf_binheader_writef (psf, "4", 0x1 | 0x2 | 0x10 | 0x20) ;
break ;
case 6 : /* 5.1 */
psf_binheader_writef (psf, "4", 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20) ;
break ;
case 8 : /* 7.1 */
psf_binheader_writef (psf, "4", 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x40 | 0x80) ;
break ;
default : /* 0 when in doubt , use direct out, ie NO mapping*/
psf_binheader_writef (psf, "4", 0x0) ;
break ;
} ;
} ;
break ;
case SF_FORMAT_MS_ADPCM : /* Todo, GUID exists might have different header as per wav_write_header */
default :
return SFE_UNIMPLEMENTED ;
} ;
/* GUID section, different for each */
switch (subformat)
{ case SF_FORMAT_PCM_U8 :
case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_24 :
case SF_FORMAT_PCM_32 :
wavex_write_guid (psf, wpriv->wavex_ambisonic == SF_AMBISONIC_NONE ?
&MSGUID_SUBTYPE_PCM : &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM) ;
break ;
case SF_FORMAT_FLOAT :
case SF_FORMAT_DOUBLE :
wavex_write_guid (psf, wpriv->wavex_ambisonic == SF_AMBISONIC_NONE ?
&MSGUID_SUBTYPE_IEEE_FLOAT : &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT) ;
break ;
case SF_FORMAT_ULAW :
wavex_write_guid (psf, &MSGUID_SUBTYPE_MULAW) ;
break ;
case SF_FORMAT_ALAW :
wavex_write_guid (psf, &MSGUID_SUBTYPE_ALAW) ;
break ;
default : return SFE_UNIMPLEMENTED ;
} ;
return 0 ;
} /* rf64_write_fmt_chunk */
static int
rf64_write_header (SF_PRIVATE *psf, int calc_length)
{ sf_count_t current ;
int error = 0, has_data = SF_FALSE ;
current = psf_ftell (psf) ;
if (psf->dataoffset > 0 && current > psf->dataoffset)
has_data = SF_TRUE ;
if (calc_length)
{ psf->filelength = psf_get_filelen (psf) ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf->dataend)
psf->datalength -= psf->filelength - psf->dataend ;
if (psf->bytewidth > 0)
psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
} ;
/* Reset the current header length to zero. */
psf->header [0] = 0 ;
psf->headindex = 0 ;
psf_fseek (psf, 0, SEEK_SET) ;
psf_binheader_writef (psf, "em4m", RF64_MARKER, 0xffffffff, WAVE_MARKER) ;
/* Currently no table. */
psf_binheader_writef (psf, "m48884", ds64_MARKER, 28, psf->filelength - 8, psf->datalength, psf->sf.frames, 0) ;
/* WAVE and 'fmt ' markers. */
psf_binheader_writef (psf, "m", fmt_MARKER) ;
/* Write the 'fmt ' chunk. */
switch (psf->sf.format & SF_FORMAT_TYPEMASK)
{ case SF_FORMAT_WAV :
psf_log_printf (psf, "ooops SF_FORMAT_WAV\n") ;
return SFE_UNIMPLEMENTED ;
break ;
case SF_FORMAT_WAVEX :
case SF_FORMAT_RF64 :
if ((error = rf64_write_fmt_chunk (psf)) != 0)
return error ;
break ;
default :
return SFE_UNIMPLEMENTED ;
} ;
if (psf->broadcast_16k != NULL)
wav_write_bext_chunk (psf) ;
#if 0
/* The LIST/INFO chunk. */
if (psf->str_flags & SF_STR_LOCATE_START)
wav_write_strings (psf, SF_STR_LOCATE_START) ;
if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_START)
{ psf_binheader_writef (psf, "m4", PEAK_MARKER, WAV_PEAK_CHUNK_SIZE (psf->sf.channels)) ;
psf_binheader_writef (psf, "44", 1, time (NULL)) ;
for (k = 0 ; k < psf->sf.channels ; k++)
psf_binheader_writef (psf, "ft8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ;
} ;
// if (psf->broadcast_info != NULL)
// wav_write_bext_chunk (psf) ;
if (psf->instrument != NULL)
{ int tmp ;
double dtune = (double) (0x40000000) / 25.0 ;
psf_binheader_writef (psf, "m4", smpl_MARKER, 9 * 4 + psf->instrument->loop_count * 6 * 4) ;
psf_binheader_writef (psf, "44", 0, 0) ; /* Manufacturer zero is everyone */
tmp = (int) (1.0e9 / psf->sf.samplerate) ; /* Sample period in nano seconds */
psf_binheader_writef (psf, "44", tmp, psf->instrument->basenote) ;
tmp = (unsigned int) (psf->instrument->detune * dtune + 0.5) ;
psf_binheader_writef (psf, "4", tmp) ;
psf_binheader_writef (psf, "44", 0, 0) ; /* SMTPE format */
psf_binheader_writef (psf, "44", psf->instrument->loop_count, 0) ;
for (tmp = 0 ; tmp < psf->instrument->loop_count ; tmp++)
{ int type ;
type = psf->instrument->loops [tmp].mode ;
type = (type == SF_LOOP_FORWARD ? 0 : type==SF_LOOP_BACKWARD ? 2 : type == SF_LOOP_ALTERNATING ? 1 : 32) ;
psf_binheader_writef (psf, "44", tmp, type) ;
psf_binheader_writef (psf, "44", psf->instrument->loops [tmp].start, psf->instrument->loops [tmp].end) ;
psf_binheader_writef (psf, "44", 0, psf->instrument->loops [tmp].count) ;
} ;
} ;
if (psf->headindex + 8 < psf->dataoffset)
{ /* Add PAD data if necessary. */
k = psf->dataoffset - 16 - psf->headindex ;
psf_binheader_writef (psf, "m4z", PAD_MARKER, k, make_size_t (k)) ;
} ;
#endif
psf_binheader_writef (psf, "m4", data_MARKER, 0xffffffff) ;
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
if (psf->error)
return psf->error ;
if (has_data && psf->dataoffset != psf->headindex)
{ printf ("Oooops : has_data && psf->dataoffset != psf->headindex\n") ;
return psf->error = SFE_INTERNAL ;
} ;
psf->dataoffset = psf->headindex ;
if (NOT (has_data))
psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
else if (current > 0)
psf_fseek (psf, current, SEEK_SET) ;
return psf->error ;
} /* rf64_write_header */
static int
rf64_close (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ // rf64_write_tailer (psf) ;
psf->write_header (psf, SF_TRUE) ;
} ;
return 0 ;
} /* rf64_close */
static int
rf64_command (SF_PRIVATE *psf, int command, void * UNUSED (data), int datasize)
{ WAV_PRIVATE *wpriv ;
if ((wpriv = psf->container_data) == NULL)
return SFE_INTERNAL ;
switch (command)
{ case SFC_WAVEX_SET_AMBISONIC :
if ((SF_CONTAINER (psf->sf.format)) == SF_FORMAT_WAVEX)
{ if (datasize == SF_AMBISONIC_NONE)
wpriv->wavex_ambisonic = SF_AMBISONIC_NONE ;
else if (datasize == SF_AMBISONIC_B_FORMAT)
wpriv->wavex_ambisonic = SF_AMBISONIC_B_FORMAT ;
else
return 0 ;
} ;
return wpriv->wavex_ambisonic ;
case SFC_WAVEX_GET_AMBISONIC :
return wpriv->wavex_ambisonic ;
case SFC_SET_CHANNEL_MAP_INFO :
wpriv->wavex_channelmask = wavex_gen_channel_mask (psf->channel_map, psf->sf.channels) ;
return (wpriv->wavex_channelmask != 0) ;
default :
break ;
} ;
return 0 ;
} /* rf64_command */

View File

@@ -0,0 +1,319 @@
/*
** Copyright (C) 2001-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#if (ENABLE_EXPERIMENTAL_CODE == 0)
int
rx2_open (SF_PRIVATE *psf)
{ if (psf)
return SFE_UNIMPLEMENTED ;
return 0 ;
} /* rx2_open */
#else
/*------------------------------------------------------------------------------
* Macros to handle big/little endian issues.
*/
#define CAT_MARKER (MAKE_MARKER ('C', 'A', 'T', ' '))
#define GLOB_MARKER (MAKE_MARKER ('G', 'L', 'O', 'B'))
#define RECY_MARKER (MAKE_MARKER ('R', 'E', 'C', 'Y'))
#define SLCL_MARKER (MAKE_MARKER ('S', 'L', 'C', 'L'))
#define SLCE_MARKER (MAKE_MARKER ('S', 'L', 'C', 'E'))
#define DEVL_MARKER (MAKE_MARKER ('D', 'E', 'V', 'L'))
#define TRSH_MARKER (MAKE_MARKER ('T', 'R', 'S', 'H'))
#define EQ_MARKER (MAKE_MARKER ('E', 'Q', ' ', ' '))
#define COMP_MARKER (MAKE_MARKER ('C', 'O', 'M', 'P'))
#define SINF_MARKER (MAKE_MARKER ('S', 'I', 'N', 'F'))
#define SDAT_MARKER (MAKE_MARKER ('S', 'D', 'A', 'T'))
/*------------------------------------------------------------------------------
* Typedefs for file chunks.
*/
/*------------------------------------------------------------------------------
* Private static functions.
*/
static int rx2_close (SF_PRIVATE *psf) ;
/*------------------------------------------------------------------------------
** Public functions.
*/
int
rx2_open (SF_PRIVATE *psf)
{ static const char *marker_type [4] =
{ "Original Enabled", "Enabled Hidden",
"Additional/PencilTool", "Disabled"
} ;
int error, marker, length, glob_offset, slce_count, frames ;
int sdat_length = 0, slce_total = 0 ;
int n_channels ;
/* So far only doing read. */
psf_binheader_readf (psf, "Epm4", 0, &marker, &length) ;
if (marker != CAT_MARKER)
{ psf_log_printf (psf, "length : %d\n", length) ;
return -1000 ;
} ;
if (length != psf->filelength - 8)
psf_log_printf (psf, "%M : %d (should be %d)\n", marker, length, psf->filelength - 8) ;
else
psf_log_printf (psf, "%M : %d\n", marker, length) ;
/* 'REX2' marker */
psf_binheader_readf (psf, "m", &marker) ;
psf_log_printf (psf, "%M", marker) ;
/* 'HEAD' marker */
psf_binheader_readf (psf, "m", &marker) ;
psf_log_printf (psf, "%M\n", marker) ;
/* Grab 'GLOB' offset. */
psf_binheader_readf (psf, "E4", &glob_offset) ;
glob_offset += 0x14 ; /* Add the current file offset. */
/* Jump to offset 0x30 */
psf_binheader_readf (psf, "p", 0x30) ;
/* Get name length */
length = 0 ;
psf_binheader_readf (psf, "1", &length) ;
if (length >= SIGNED_SIZEOF (psf->u.cbuf))
{ psf_log_printf (psf, " Text : %d *** Error : Too sf_count_t!\n") ;
return -1001 ;
}
memset (psf->u.cbuf, 0, sizeof (psf->u.cbuf)) ;
psf_binheader_readf (psf, "b", psf->u.cbuf, length) ;
psf_log_printf (psf, " Text : \"%s\"\n", psf->u.cbuf) ;
/* Jump to GLOB offset position. */
if (glob_offset & 1)
glob_offset ++ ;
psf_binheader_readf (psf, "p", glob_offset) ;
slce_count = 0 ;
/* GLOB */
while (1)
{ psf_binheader_readf (psf, "m", &marker) ;
if (marker != SLCE_MARKER && slce_count > 0)
{ psf_log_printf (psf, " SLCE count : %d\n", slce_count) ;
slce_count = 0 ;
}
switch (marker)
{ case GLOB_MARKER:
psf_binheader_readf (psf, "E4", &length) ;
psf_log_printf (psf, " %M : %d\n", marker, length) ;
psf_binheader_readf (psf, "j", length) ;
break ;
case RECY_MARKER:
psf_binheader_readf (psf, "E4", &length) ;
psf_log_printf (psf, " %M : %d\n", marker, length) ;
psf_binheader_readf (psf, "j", (length+1) & 0xFFFFFFFE) ; /* ?????? */
break ;
case CAT_MARKER:
psf_binheader_readf (psf, "E4", &length) ;
psf_log_printf (psf, " %M : %d\n", marker, length) ;
/*-psf_binheader_readf (psf, "j", length) ;-*/
break ;
case DEVL_MARKER:
psf_binheader_readf (psf, "mE4", &marker, &length) ;
psf_log_printf (psf, " DEVL%M : %d\n", marker, length) ;
if (length & 1)
length ++ ;
psf_binheader_readf (psf, "j", length) ;
break ;
case EQ_MARKER:
case COMP_MARKER:
psf_binheader_readf (psf, "E4", &length) ;
psf_log_printf (psf, " %M : %d\n", marker, length) ;
/* This is weird!!!! why make this (length - 1) */
if (length & 1)
length ++ ;
psf_binheader_readf (psf, "j", length) ;
break ;
case SLCL_MARKER:
psf_log_printf (psf, " %M\n (Offset, Next Offset, Type)\n", marker) ;
slce_count = 0 ;
break ;
case SLCE_MARKER:
{ int len [4], indx ;
psf_binheader_readf (psf, "E4444", &len [0], &len [1], &len [2], &len [3]) ;
indx = ((len [3] & 0x0000FFFF) >> 8) & 3 ;
if (len [2] == 1)
{ if (indx != 1)
indx = 3 ; /* 2 cases, where next slice offset = 1 -> disabled & enabled/hidden */
psf_log_printf (psf, " %M : (%6d, ?: 0x%X, %s)\n", marker, len [1], (len [3] & 0xFFFF0000) >> 16, marker_type [indx]) ;
}
else
{ slce_total += len [2] ;
psf_log_printf (psf, " %M : (%6d, SLCE_next_ofs:%d, ?: 0x%X, %s)\n", marker, len [1], len [2], (len [3] & 0xFFFF0000) >> 16, marker_type [indx]) ;
} ;
slce_count ++ ;
} ;
break ;
case SINF_MARKER:
psf_binheader_readf (psf, "E4", &length) ;
psf_log_printf (psf, " %M : %d\n", marker, length) ;
psf_binheader_readf (psf, "E2", &n_channels) ;
n_channels = (n_channels & 0x0000FF00) >> 8 ;
psf_log_printf (psf, " Channels : %d\n", n_channels) ;
psf_binheader_readf (psf, "E44", &psf->sf.samplerate, &frames) ;
psf->sf.frames = frames ;
psf_log_printf (psf, " Sample Rate : %d\n", psf->sf.samplerate) ;
psf_log_printf (psf, " Frames : %D\n", psf->sf.frames) ;
psf_binheader_readf (psf, "E4", &length) ;
psf_log_printf (psf, " ??????????? : %d\n", length) ;
psf_binheader_readf (psf, "E4", &length) ;
psf_log_printf (psf, " ??????????? : %d\n", length) ;
break ;
case SDAT_MARKER:
psf_binheader_readf (psf, "E4", &length) ;
sdat_length = length ;
/* Get the current offset. */
psf->dataoffset = psf_binheader_readf (psf, NULL) ;
if (psf->dataoffset + length != psf->filelength)
psf_log_printf (psf, " %M : %d (should be %d)\n", marker, length, psf->dataoffset + psf->filelength) ;
else
psf_log_printf (psf, " %M : %d\n", marker, length) ;
break ;
default :
psf_log_printf (psf, "Unknown marker : 0x%X %M", marker, marker) ;
return -1003 ;
break ;
} ;
/* SDAT always last marker in file. */
if (marker == SDAT_MARKER)
break ;
} ;
puts (psf->logbuffer) ;
puts ("-----------------------------------") ;
printf ("SDAT length : %d\n", sdat_length) ;
printf ("SLCE count : %d\n", slce_count) ;
/* Hack for zero slice count. */
if (slce_count == 0 && slce_total == 1)
slce_total = frames ;
printf ("SLCE samples : %d\n", slce_total) ;
/* Two bytes per sample. */
printf ("Comp Ratio : %f:1\n", (2.0 * slce_total * n_channels) / sdat_length) ;
puts (" ") ;
psf->logbuffer [0] = 0 ;
/* OK, have the header although not too sure what it all means. */
psf->endian = SF_ENDIAN_BIG ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf_fseek (psf, psf->dataoffset, SEEK_SET))
return SFE_BAD_SEEK ;
psf->sf.format = (SF_FORMAT_REX2 | SF_FORMAT_DWVW_12) ;
psf->sf.channels = 1 ;
psf->bytewidth = 2 ;
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
if ((error = dwvw_init (psf, 16)))
return error ;
psf->container_close = rx2_close ;
if (! psf->sf.frames && psf->blockwidth)
psf->sf.frames = psf->datalength / psf->blockwidth ;
/* All done. */
return 0 ;
} /* rx2_open */
/*------------------------------------------------------------------------------
*/
static int
rx2_close (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_WRITE)
{ /* Now we know for certain the length of the file we can re-write
** correct values for the FORM, 8SVX and BODY chunks.
*/
} ;
return 0 ;
} /* rx2_close */
#endif

View File

@@ -0,0 +1,632 @@
/*
** Copyright (C) 2001-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
** Copyright (C) 2004 Paavo Jumppanen
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
** The sd2 support implemented in this file was partially sponsored
** (financially) by Paavo Jumppanen.
*/
/*
** Documentation on the Mac resource fork was obtained here :
** http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
/*------------------------------------------------------------------------------
* Markers.
*/
#define Sd2f_MARKER MAKE_MARKER ('S', 'd', '2', 'f')
#define Sd2a_MARKER MAKE_MARKER ('S', 'd', '2', 'a')
#define ALCH_MARKER MAKE_MARKER ('A', 'L', 'C', 'H')
#define lsf1_MARKER MAKE_MARKER ('l', 's', 'f', '1')
#define STR_MARKER MAKE_MARKER ('S', 'T', 'R', ' ')
#define sdML_MARKER MAKE_MARKER ('s', 'd', 'M', 'L')
enum
{ RSRC_STR = 111,
RSRC_BIN
} ;
typedef struct
{ unsigned char * rsrc_data ;
int rsrc_len ;
int need_to_free_rsrc_data ;
int data_offset, data_length ;
int map_offset, map_length ;
int type_count, type_offset ;
int item_offset ;
int str_index, str_count ;
int string_offset ;
/* All the above just to get these three. */
int sample_size, sample_rate, channels ;
} SD2_RSRC ;
typedef struct
{ int type ;
int id ;
char name [32] ;
char value [32] ;
int value_len ;
} STR_RSRC ;
/*------------------------------------------------------------------------------
* Private static functions.
*/
static int sd2_close (SF_PRIVATE *psf) ;
static int sd2_parse_rsrc_fork (SF_PRIVATE *psf) ;
static int parse_str_rsrc (SF_PRIVATE *psf, SD2_RSRC * rsrc) ;
static int sd2_write_rsrc_fork (SF_PRIVATE *psf, int calc_length) ;
/*------------------------------------------------------------------------------
** Public functions.
*/
int
sd2_open (SF_PRIVATE *psf)
{ int subformat, error = 0, valid ;
/* SD2 is always big endian. */
psf->endian = SF_ENDIAN_BIG ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->rsrclength > 0))
{ psf_use_rsrc (psf, SF_TRUE) ;
valid = psf_file_valid (psf) ;
psf_use_rsrc (psf, SF_FALSE) ;
if (! valid)
{ psf_log_printf (psf, "sd2_open : psf->rsrc.filedes < 0\n") ;
return SFE_SD2_BAD_RSRC ;
} ;
error = sd2_parse_rsrc_fork (psf) ;
if (error)
goto error_cleanup ;
} ;
if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_SD2)
{ error = SFE_BAD_OPEN_FORMAT ;
goto error_cleanup ;
} ;
subformat = SF_CODEC (psf->sf.format) ;
psf->dataoffset = 0 ;
/* Only open and write the resource in RDWR mode is its current length is zero. */
if (psf->file.mode == SFM_WRITE || (psf->file.mode == SFM_RDWR && psf->rsrclength == 0))
{ psf->rsrc.mode = psf->file.mode ;
psf_open_rsrc (psf) ;
error = sd2_write_rsrc_fork (psf, SF_FALSE) ;
if (error)
goto error_cleanup ;
/* Not needed. */
psf->write_header = NULL ;
} ;
psf->container_close = sd2_close ;
psf->blockwidth = psf->bytewidth * psf->sf.channels ;
switch (subformat)
{ case SF_FORMAT_PCM_S8 : /* 8-bit linear PCM. */
case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */
case SF_FORMAT_PCM_24 : /* 24-bit linear PCM */
error = pcm_init (psf) ;
break ;
default :
error = SFE_UNIMPLEMENTED ;
break ;
} ;
psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
error_cleanup:
/* Close the resource fork regardless. We won't need it again. */
psf_close_rsrc (psf) ;
return error ;
} /* sd2_open */
/*------------------------------------------------------------------------------
*/
static int
sd2_close (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_WRITE)
{ /* Now we know for certain the audio_length of the file we can re-write
** correct values for the FORM, 8SVX and BODY chunks.
*/
} ;
return 0 ;
} /* sd2_close */
/*------------------------------------------------------------------------------
*/
static inline void
write_char (unsigned char * data, int offset, char value)
{ data [offset] = value ;
} /* write_char */
static inline void
write_short (unsigned char * data, int offset, short value)
{ data [offset] = value >> 8 ;
data [offset + 1] = value ;
} /* write_char */
static inline void
write_int (unsigned char * data, int offset, int value)
{ data [offset] = value >> 24 ;
data [offset + 1] = value >> 16 ;
data [offset + 2] = value >> 8 ;
data [offset + 3] = value ;
} /* write_int */
static inline void
write_marker (unsigned char * data, int offset, int value)
{
if (CPU_IS_BIG_ENDIAN)
{ data [offset] = value >> 24 ;
data [offset + 1] = value >> 16 ;
data [offset + 2] = value >> 8 ;
data [offset + 3] = value ;
}
else
{ data [offset] = value ;
data [offset + 1] = value >> 8 ;
data [offset + 2] = value >> 16 ;
data [offset + 3] = value >> 24 ;
} ;
} /* write_marker */
static void
write_str (unsigned char * data, int offset, const char * buffer, int buffer_len)
{ memcpy (data + offset, buffer, buffer_len) ;
} /* write_str */
static int
sd2_write_rsrc_fork (SF_PRIVATE *psf, int UNUSED (calc_length))
{ SD2_RSRC rsrc ;
STR_RSRC str_rsrc [] =
{ { RSRC_STR, 1000, "_sample-size", "", 0 },
{ RSRC_STR, 1001, "_sample-rate", "", 0 },
{ RSRC_STR, 1002, "_channels", "", 0 },
{ RSRC_BIN, 1000, "_Markers", "", 8 }
} ;
int k, str_offset, data_offset, next_str ;
psf_use_rsrc (psf, SF_TRUE) ;
memset (&rsrc, 0, sizeof (rsrc)) ;
rsrc.sample_rate = psf->sf.samplerate ;
rsrc.sample_size = psf->bytewidth ;
rsrc.channels = psf->sf.channels ;
rsrc.rsrc_data = psf->header ;
rsrc.rsrc_len = sizeof (psf->header) ;
memset (rsrc.rsrc_data, 0xea, rsrc.rsrc_len) ;
snprintf (str_rsrc [0].value, sizeof (str_rsrc [0].value), "_%d", rsrc.sample_size) ;
snprintf (str_rsrc [1].value, sizeof (str_rsrc [1].value), "_%d.000000", rsrc.sample_rate) ;
snprintf (str_rsrc [2].value, sizeof (str_rsrc [2].value), "_%d", rsrc.channels) ;
for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++)
{ if (str_rsrc [k].value_len == 0)
{ str_rsrc [k].value_len = strlen (str_rsrc [k].value) ;
str_rsrc [k].value [0] = str_rsrc [k].value_len - 1 ;
} ;
/* Turn name string into a pascal string. */
str_rsrc [k].name [0] = strlen (str_rsrc [k].name) - 1 ;
} ;
rsrc.data_offset = 0x100 ;
/*
** Calculate data length :
** length of strings, plus the length of the sdML chunk.
*/
rsrc.data_length = 0 ;
for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++)
rsrc.data_length += str_rsrc [k].value_len + 4 ;
rsrc.map_offset = rsrc.data_offset + rsrc.data_length ;
/* Very start of resource fork. */
write_int (rsrc.rsrc_data, 0, rsrc.data_offset) ;
write_int (rsrc.rsrc_data, 4, rsrc.map_offset) ;
write_int (rsrc.rsrc_data, 8, rsrc.data_length) ;
write_char (rsrc.rsrc_data, 0x30, strlen (psf->file.name.c)) ;
write_str (rsrc.rsrc_data, 0x31, psf->file.name.c, strlen (psf->file.name.c)) ;
write_short (rsrc.rsrc_data, 0x50, 0) ;
write_marker (rsrc.rsrc_data, 0x52, Sd2f_MARKER) ;
write_marker (rsrc.rsrc_data, 0x56, lsf1_MARKER) ;
/* Very start of resource map. */
write_int (rsrc.rsrc_data, rsrc.map_offset + 0, rsrc.data_offset) ;
write_int (rsrc.rsrc_data, rsrc.map_offset + 4, rsrc.map_offset) ;
write_int (rsrc.rsrc_data, rsrc.map_offset + 8, rsrc.data_length) ;
/* These I don't currently understand. */
if (1)
{ write_char (rsrc.rsrc_data, rsrc.map_offset+ 16, 1) ;
/* Next resource map. */
write_int (rsrc.rsrc_data, rsrc.map_offset + 17, 0x12345678) ;
/* File ref number. */
write_short (rsrc.rsrc_data, rsrc.map_offset + 21, 0xabcd) ;
/* Fork attributes. */
write_short (rsrc.rsrc_data, rsrc.map_offset + 23, 0) ;
} ;
/* Resource type offset. */
rsrc.type_offset = rsrc.map_offset + 30 ;
write_short (rsrc.rsrc_data, rsrc.map_offset + 24, rsrc.type_offset - rsrc.map_offset - 2) ;
/* Type index max. */
rsrc.type_count = 2 ;
write_short (rsrc.rsrc_data, rsrc.map_offset + 28, rsrc.type_count - 1) ;
rsrc.item_offset = rsrc.type_offset + rsrc.type_count * 8 ;
rsrc.str_count = ARRAY_LEN (str_rsrc) ;
rsrc.string_offset = rsrc.item_offset + (rsrc.str_count + 1) * 12 - rsrc.map_offset ;
write_short (rsrc.rsrc_data, rsrc.map_offset + 26, rsrc.string_offset) ;
/* Write 'STR ' resource type. */
rsrc.str_count = 3 ;
write_marker (rsrc.rsrc_data, rsrc.type_offset, STR_MARKER) ;
write_short (rsrc.rsrc_data, rsrc.type_offset + 4, rsrc.str_count - 1) ;
write_short (rsrc.rsrc_data, rsrc.type_offset + 6, 0x12) ;
/* Write 'sdML' resource type. */
write_marker (rsrc.rsrc_data, rsrc.type_offset + 8, sdML_MARKER) ;
write_short (rsrc.rsrc_data, rsrc.type_offset + 12, 0) ;
write_short (rsrc.rsrc_data, rsrc.type_offset + 14, 0x36) ;
str_offset = rsrc.map_offset + rsrc.string_offset ;
next_str = 0 ;
data_offset = rsrc.data_offset ;
for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++)
{ write_str (rsrc.rsrc_data, str_offset, str_rsrc [k].name, strlen (str_rsrc [k].name)) ;
write_short (rsrc.rsrc_data, rsrc.item_offset + k * 12, str_rsrc [k].id) ;
write_short (rsrc.rsrc_data, rsrc.item_offset + k * 12 + 2, next_str) ;
str_offset += strlen (str_rsrc [k].name) ;
next_str += strlen (str_rsrc [k].name) ;
write_int (rsrc.rsrc_data, rsrc.item_offset + k * 12 + 4, data_offset - rsrc.data_offset) ;
write_int (rsrc.rsrc_data, data_offset, str_rsrc [k].value_len) ;
write_str (rsrc.rsrc_data, data_offset + 4, str_rsrc [k].value, str_rsrc [k].value_len) ;
data_offset += 4 + str_rsrc [k].value_len ;
} ;
/* Finally, calculate and set map length. */
rsrc.map_length = str_offset - rsrc.map_offset ;
write_int (rsrc.rsrc_data, 12, rsrc.map_length) ;
write_int (rsrc.rsrc_data, rsrc.map_offset + 12, rsrc.map_length) ;
rsrc.rsrc_len = rsrc.map_offset + rsrc.map_length ;
psf_fwrite (rsrc.rsrc_data, rsrc.rsrc_len, 1, psf) ;
psf_use_rsrc (psf, SF_FALSE) ;
if (psf->error)
return psf->error ;
return 0 ;
} /* sd2_write_rsrc_fork */
/*------------------------------------------------------------------------------
*/
static inline int
read_char (const unsigned char * data, int offset)
{ return data [offset] ;
} /* read_char */
static inline int
read_short (const unsigned char * data, int offset)
{ return (data [offset] << 8) + data [offset + 1] ;
} /* read_short */
static inline int
read_int (const unsigned char * data, int offset)
{ return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ;
} /* read_int */
static inline int
read_marker (const unsigned char * data, int offset)
{
if (CPU_IS_BIG_ENDIAN)
return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ;
else if (CPU_IS_LITTLE_ENDIAN)
return data [offset] + (data [offset + 1] << 8) + (data [offset + 2] << 16) + (data [offset + 3] << 24) ;
else
return 0x666 ;
} /* read_marker */
static void
read_str (const unsigned char * data, int offset, char * buffer, int buffer_len)
{ int k ;
memset (buffer, 0, buffer_len) ;
for (k = 0 ; k < buffer_len - 1 ; k++)
{ if (psf_isprint (data [offset + k]) == 0)
return ;
buffer [k] = data [offset + k] ;
} ;
return ;
} /* read_str */
static int
sd2_parse_rsrc_fork (SF_PRIVATE *psf)
{ SD2_RSRC rsrc ;
int k, marker, error = 0 ;
psf_use_rsrc (psf, SF_TRUE) ;
memset (&rsrc, 0, sizeof (rsrc)) ;
rsrc.rsrc_len = psf_get_filelen (psf) ;
psf_log_printf (psf, "Resource length : %d (0x%04X)\n", rsrc.rsrc_len, rsrc.rsrc_len) ;
if (rsrc.rsrc_len > SIGNED_SIZEOF (psf->header))
{ rsrc.rsrc_data = calloc (1, rsrc.rsrc_len) ;
rsrc.need_to_free_rsrc_data = SF_TRUE ;
}
else
rsrc.rsrc_data = psf->header ;
/* Read in the whole lot. */
psf_fread (rsrc.rsrc_data, rsrc.rsrc_len, 1, psf) ;
/* Reset the header storage because we have changed to the rsrcdes. */
psf->headindex = psf->headend = rsrc.rsrc_len ;
rsrc.data_offset = read_int (rsrc.rsrc_data, 0) ;
rsrc.map_offset = read_int (rsrc.rsrc_data, 4) ;
rsrc.data_length = read_int (rsrc.rsrc_data, 8) ;
rsrc.map_length = read_int (rsrc.rsrc_data, 12) ;
if (rsrc.data_offset == 0x51607 && rsrc.map_offset == 0x20000)
{ psf_log_printf (psf, "Trying offset of 0x52 bytes.\n") ;
rsrc.data_offset = read_int (rsrc.rsrc_data, 0x52 + 0) + 0x52 ;
rsrc.map_offset = read_int (rsrc.rsrc_data, 0x52 + 4) + 0x52 ;
rsrc.data_length = read_int (rsrc.rsrc_data, 0x52 + 8) ;
rsrc.map_length = read_int (rsrc.rsrc_data, 0x52 + 12) ;
} ;
psf_log_printf (psf, " data offset : 0x%04X\n map offset : 0x%04X\n"
" data length : 0x%04X\n map length : 0x%04X\n",
rsrc.data_offset, rsrc.map_offset, rsrc.data_length, rsrc.map_length) ;
if (rsrc.data_offset > rsrc.rsrc_len)
{ psf_log_printf (psf, "Error : rsrc.data_offset (%d, 0x%x) > len\n", rsrc.data_offset, rsrc.data_offset) ;
error = SFE_SD2_BAD_DATA_OFFSET ;
goto parse_rsrc_fork_cleanup ;
} ;
if (rsrc.map_offset > rsrc.rsrc_len)
{ psf_log_printf (psf, "Error : rsrc.map_offset > len\n") ;
error = SFE_SD2_BAD_MAP_OFFSET ;
goto parse_rsrc_fork_cleanup ;
} ;
if (rsrc.data_length > rsrc.rsrc_len)
{ psf_log_printf (psf, "Error : rsrc.data_length > len\n") ;
error = SFE_SD2_BAD_DATA_LENGTH ;
goto parse_rsrc_fork_cleanup ;
} ;
if (rsrc.map_length > rsrc.rsrc_len)
{ psf_log_printf (psf, "Error : rsrc.map_length > len\n") ;
error = SFE_SD2_BAD_MAP_LENGTH ;
goto parse_rsrc_fork_cleanup ;
} ;
if (rsrc.data_offset + rsrc.data_length != rsrc.map_offset || rsrc.map_offset + rsrc.map_length != rsrc.rsrc_len)
{ psf_log_printf (psf, "Error : This does not look like a MacOSX resource fork.\n") ;
error = SFE_SD2_BAD_RSRC ;
goto parse_rsrc_fork_cleanup ;
} ;
if (rsrc.map_offset + 28 >= rsrc.rsrc_len)
{ psf_log_printf (psf, "Bad map offset (%d + 28 > %d).\n", rsrc.map_offset, rsrc.rsrc_len) ;
error = SFE_SD2_BAD_RSRC ;
goto parse_rsrc_fork_cleanup ;
} ;
rsrc.string_offset = rsrc.map_offset + read_short (rsrc.rsrc_data, rsrc.map_offset + 26) ;
if (rsrc.string_offset > rsrc.rsrc_len)
{ psf_log_printf (psf, "Bad string offset (%d).\n", rsrc.string_offset) ;
error = SFE_SD2_BAD_RSRC ;
goto parse_rsrc_fork_cleanup ;
} ;
rsrc.type_offset = rsrc.map_offset + 30 ;
rsrc.type_count = read_short (rsrc.rsrc_data, rsrc.map_offset + 28) + 1 ;
if (rsrc.type_count < 1)
{ psf_log_printf (psf, "Bad type count.\n") ;
error = SFE_SD2_BAD_RSRC ;
goto parse_rsrc_fork_cleanup ;
} ;
rsrc.item_offset = rsrc.type_offset + rsrc.type_count * 8 ;
if (rsrc.item_offset < 0 || rsrc.item_offset > rsrc.rsrc_len)
{ psf_log_printf (psf, "Bad item offset (%d).\n", rsrc.item_offset) ;
error = SFE_SD2_BAD_RSRC ;
goto parse_rsrc_fork_cleanup ;
} ;
rsrc.str_index = -1 ;
for (k = 0 ; k < rsrc.type_count ; k ++)
{ marker = read_marker (rsrc.rsrc_data, rsrc.type_offset + k * 8) ;
if (marker == STR_MARKER)
{ rsrc.str_index = k ;
rsrc.str_count = read_short (rsrc.rsrc_data, rsrc.type_offset + k * 8 + 4) + 1 ;
error = parse_str_rsrc (psf, &rsrc) ;
goto parse_rsrc_fork_cleanup ;
} ;
} ;
psf_log_printf (psf, "No 'STR ' resource.\n") ;
error = SFE_SD2_BAD_RSRC ;
parse_rsrc_fork_cleanup :
psf_use_rsrc (psf, SF_FALSE) ;
if (rsrc.need_to_free_rsrc_data)
free (rsrc.rsrc_data) ;
return error ;
} /* sd2_parse_rsrc_fork */
static int
parse_str_rsrc (SF_PRIVATE *psf, SD2_RSRC * rsrc)
{ char name [32], value [32] ;
int k, str_offset, rsrc_id, data_offset = 0, data_len = 0 ;
psf_log_printf (psf, "Finding parameters :\n") ;
str_offset = rsrc->string_offset ;
psf_log_printf (psf, " Offset RsrcId dlen slen Value\n") ;
for (k = 0 ; data_offset + data_len < rsrc->rsrc_len ; k++)
{ int slen ;
slen = read_char (rsrc->rsrc_data, str_offset) ;
read_str (rsrc->rsrc_data, str_offset + 1, name, SF_MIN (SIGNED_SIZEOF (name), slen + 1)) ;
str_offset += slen + 1 ;
rsrc_id = read_short (rsrc->rsrc_data, rsrc->item_offset + k * 12) ;
data_offset = rsrc->data_offset + read_int (rsrc->rsrc_data, rsrc->item_offset + k * 12 + 4) ;
if (data_offset < 0 || data_offset > rsrc->rsrc_len)
{ psf_log_printf (psf, "Exiting parser on data offset of %d.\n", data_offset) ;
break ;
} ;
data_len = read_int (rsrc->rsrc_data, data_offset) ;
if (data_len < 0 || data_len > rsrc->rsrc_len)
{ psf_log_printf (psf, "Exiting parser on data length of %d.\n", data_len) ;
break ;
} ;
slen = read_char (rsrc->rsrc_data, data_offset + 4) ;
read_str (rsrc->rsrc_data, data_offset + 5, value, SF_MIN (SIGNED_SIZEOF (value), slen + 1)) ;
psf_log_printf (psf, " 0x%04x %4d %4d %3d '%s'\n", data_offset, rsrc_id, data_len, slen, value) ;
if (rsrc_id == 1000 && rsrc->sample_size == 0)
rsrc->sample_size = strtol (value, NULL, 10) ;
else if (rsrc_id == 1001 && rsrc->sample_rate == 0)
rsrc->sample_rate = strtol (value, NULL, 10) ;
else if (rsrc_id == 1002 && rsrc->channels == 0)
rsrc->channels = strtol (value, NULL, 10) ;
} ;
psf_log_printf (psf, "Found Parameters :\n") ;
psf_log_printf (psf, " sample-size : %d\n", rsrc->sample_size) ;
psf_log_printf (psf, " sample-rate : %d\n", rsrc->sample_rate) ;
psf_log_printf (psf, " channels : %d\n", rsrc->channels) ;
if (rsrc->sample_rate <= 4 && rsrc->sample_size > 4)
{ int temp ;
psf_log_printf (psf, "Geez!! Looks like sample rate and sample size got switched.\nCorrecting this screw up.\n") ;
temp = rsrc->sample_rate ;
rsrc->sample_rate = rsrc->sample_size ;
rsrc->sample_size = temp ;
} ;
if (rsrc->sample_rate < 0)
{ psf_log_printf (psf, "Bad sample rate (%d)\n", rsrc->sample_rate) ;
return SFE_SD2_BAD_RSRC ;
} ;
if (rsrc->channels < 0)
{ psf_log_printf (psf, "Bad channel count (%d)\n", rsrc->channels) ;
return SFE_SD2_BAD_RSRC ;
} ;
psf->sf.samplerate = rsrc->sample_rate ;
psf->sf.channels = rsrc->channels ;
psf->bytewidth = rsrc->sample_size ;
switch (rsrc->sample_size)
{ case 1 :
psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_S8 ;
break ;
case 2 :
psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_16 ;
break ;
case 3 :
psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_24 ;
break ;
default :
psf_log_printf (psf, "Bad sample size (%d)\n", rsrc->sample_size) ;
return SFE_SD2_BAD_SAMPLE_SIZE ;
} ;
psf_log_printf (psf, "ok\n") ;
return 0 ;
} /* parse_str_rsrc */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,63 @@
/*
** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Some defines that microsoft 'forgot' to implement. */
#ifndef S_IRWXU
#define S_IRWXU 0000700 /* rwx, owner */
#endif
#ifndef S_IRUSR
#define S_IRUSR 0000400 /* read permission, owner */
#endif
#ifndef S_IWUSR
#define S_IWUSR 0000200 /* write permission, owner */
#endif
#ifndef S_IXUSR
#define S_IXUSR 0000100 /* execute/search permission, owner */
#endif
/* Windows doesn't have group permissions so set all these to zero. */
#define S_IRWXG 0 /* rwx, group */
#define S_IRGRP 0 /* read permission, group */
#define S_IWGRP 0 /* write permission, grougroup */
#define S_IXGRP 0 /* execute/search permission, group */
/* Windows doesn't have others permissions so set all these to zero. */
#define S_IRWXO 0 /* rwx, other */
#define S_IROTH 0 /* read permission, other */
#define S_IWOTH 0 /* write permission, other */
#define S_IXOTH 0 /* execute/search permission, other */
#ifndef S_ISFIFO
#define S_ISFIFO(mode) (((mode) & _S_IFMT) == _S_IFIFO)
#endif
#ifndef S_ISREG
#define S_ISREG(mode) (((mode) & _S_IFREG) == _S_IFREG)
#endif
/*
** Don't know if these are still needed.
**
** #define _IFMT _S_IFMT
** #define _IFREG _S_IFREG
*/

View File

@@ -0,0 +1,113 @@
/*
** Copyright (C) 2005-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
** Autoconf leaves many config parameters undefined.
** Here we change then from being undefined to defining them to 0.
** This allows things like:
**
** #if HAVE_CONFIG_PARAM
**
** and
**
** if (HAVE_CONFIG_PARAM)
** do_something () ;
*/
#ifndef SFCONFIG_H
#define SFCONFIG_H
/* Include the Autoconf generated file. */
#include "config.h"
/* Now fiddle the values. */
#ifndef HAVE_ALSA_ASOUNDLIB_H
#define HAVE_ALSA_ASOUNDLIB_H 0
#endif
#ifndef HAVE_BYTESWAP_H
#define HAVE_BYTESWAP_H 0
#endif
#ifndef HAVE_DECL_S_IRGRP
#define HAVE_DECL_S_IRGRP 0
#endif
#ifndef HAVE_ENDIAN_H
#define HAVE_ENDIAN_H 0
#endif
#ifndef HAVE_FSYNC
#define HAVE_FSYNC 0
#endif
#ifndef HAVE_LOCALE_H
#define HAVE_LOCALE_H 0
#endif
#ifndef HAVE_LRINT
#define HAVE_LRINT 0
#endif
#ifndef HAVE_LRINTF
#define HAVE_LRINTF 0
#endif
#ifndef HAVE_MMAP
#define HAVE_MMAP 0
#endif
#ifndef HAVE_PREAD
#define HAVE_PREAD 0
#endif
#ifndef HAVE_PWRITE
#define HAVE_PWRITE 0
#endif
#ifndef HAVE_SETLOCALE
#define HAVE_SETLOCALE 0
#endif
#ifndef HAVE_SQLITE3
#define HAVE_SQLITE3 0
#endif
#ifndef HAVE_STDINT_H
#define HAVE_STDINT_H 0
#endif
#ifndef HAVE_SYS_WAIT_H
#define HAVE_SYS_WAIT_H 0
#endif
#ifndef HAVE_UNISTD_H
#define HAVE_UNISTD_H 0
#endif
#ifndef HAVE_PIPE
#define HAVE_PIPE 0
#endif
#ifndef HAVE_WAITPID
#define HAVE_WAITPID 0
#endif
#endif

View File

@@ -0,0 +1,254 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef SFENDIAN_INCLUDED
#define SFENDIAN_INCLUDED
#include "sfconfig.h"
#if HAVE_STDINT_H
#include <stdint.h>
#elif HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#if (defined (SIZEOF_INT64_T) && (SIZEOF_INT64_T == 8))
/* Good, we have int64_t. */
#elif (defined (SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == 8))
typedef long long int64_t ;
#elif (defined (SIZEOF_LONG) && (SIZEOF_LONG == 8))
typedef long int64_t ;
#elif (defined (WIN32) || defined (_WIN32))
typedef __int64 int64_t ;
#else
#error "No 64 bit integer type."
#endif
#if HAVE_BYTESWAP_H
#include <byteswap.h>
#define ENDSWAP_SHORT(x) ((short) bswap_16 (x))
#define ENDSWAP_INT(x) ((int) bswap_32 (x))
#else
#define ENDSWAP_SHORT(x) ((((x) >> 8) & 0xFF) + (((x) & 0xFF) << 8))
#define ENDSWAP_INT(x) ((((x) >> 24) & 0xFF) + (((x) >> 8) & 0xFF00) + (((x) & 0xFF00) << 8) + (((x) & 0xFF) << 24))
#endif
/*
** Many file types (ie WAV, AIFF) use sets of four consecutive bytes as a
** marker indicating different sections of the file.
** The following MAKE_MARKER macro allows th creation of integer constants
** for these markers.
*/
#if (CPU_IS_LITTLE_ENDIAN == 1)
#define MAKE_MARKER(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
#elif (CPU_IS_BIG_ENDIAN == 1)
#define MAKE_MARKER(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
#else
#error "Target CPU endian-ness unknown. May need to hand edit src/sfconfig.h"
#endif
/*
** Macros to handle reading of data of a specific endian-ness into host endian
** shorts and ints. The single input is an unsigned char* pointer to the start
** of the object. There are two versions of each macro as we need to deal with
** both big and little endian CPUs.
*/
#if (CPU_IS_LITTLE_ENDIAN == 1)
#define LES2H_SHORT(x) (x)
#define LEI2H_INT(x) (x)
#define BES2H_SHORT(x) ENDSWAP_SHORT (x)
#define BEI2H_INT(x) ENDSWAP_INT (x)
#define H2BE_SHORT(x) ENDSWAP_SHORT (x)
#define H2BE_INT(x) ENDSWAP_INT (x)
#elif (CPU_IS_BIG_ENDIAN == 1)
#define LES2H_SHORT(x) ENDSWAP_SHORT (x)
#define LEI2H_INT(x) ENDSWAP_INT (x)
#define BES2H_SHORT(x) (x)
#define BEI2H_INT(x) (x)
#define H2LE_SHORT(x) ENDSWAP_SHORT (x)
#define H2LE_INT(x) ENDSWAP_INT (x)
#else
#error "Target CPU endian-ness unknown. May need to hand edit src/sfconfig.h"
#endif
#define LET2H_SHORT_PTR(x) ((x) [1] + ((x) [2] << 8))
#define LET2H_INT_PTR(x) (((x) [0] << 8) + ((x) [1] << 16) + ((x) [2] << 24))
#define BET2H_SHORT_PTR(x) (((x) [0] << 8) + (x) [1])
#define BET2H_INT_PTR(x) (((x) [0] << 24) + ((x) [1] << 16) + ((x) [2] << 8))
/*-----------------------------------------------------------------------------------------------
** Generic functions for performing endian swapping on integer arrays.
*/
static inline void
endswap_short_array (short *ptr, int len)
{ short temp ;
while (--len >= 0)
{ temp = ptr [len] ;
ptr [len] = ENDSWAP_SHORT (temp) ;
} ;
} /* endswap_short_array */
static inline void
endswap_short_copy (short *dest, const short *src, int len)
{
while (--len >= 0)
{ dest [len] = ENDSWAP_SHORT (src [len]) ;
} ;
} /* endswap_short_copy */
static inline void
endswap_int_array (int *ptr, int len)
{ int temp ;
while (--len >= 0)
{ temp = ptr [len] ;
ptr [len] = ENDSWAP_INT (temp) ;
} ;
} /* endswap_int_array */
static inline void
endswap_int_copy (int *dest, const int *src, int len)
{
while (--len >= 0)
{ dest [len] = ENDSWAP_INT (src [len]) ;
} ;
} /* endswap_int_copy */
/*========================================================================================
*/
#if (HAVE_BYTESWAP_H && defined (SIZEOF_INT64_T) && (SIZEOF_INT64_T == 8))
static inline void
endswap_int64_t_array (int64_t *ptr, int len)
{ int64_t value ;
while (--len >= 0)
{ value = ptr [len] ;
ptr [len] = bswap_64 (value) ;
} ;
} /* endswap_int64_t_array */
static inline void
endswap_int64_t_copy (int64_t *dest, const int64_t *src, int len)
{ int64_t value ;
while (--len >= 0)
{ value = src [len] ;
dest [len] = bswap_64 (value) ;
} ;
} /* endswap_int64_t_copy */
#else
static inline void
endswap_int64_t_array (int64_t *ptr, int len)
{ unsigned char *ucptr, temp ;
ucptr = (unsigned char *) ptr ;
ucptr += 8 * len ;
while (--len >= 0)
{ ucptr -= 8 ;
temp = ucptr [0] ;
ucptr [0] = ucptr [7] ;
ucptr [7] = temp ;
temp = ucptr [1] ;
ucptr [1] = ucptr [6] ;
ucptr [6] = temp ;
temp = ucptr [2] ;
ucptr [2] = ucptr [5] ;
ucptr [5] = temp ;
temp = ucptr [3] ;
ucptr [3] = ucptr [4] ;
ucptr [4] = temp ;
} ;
} /* endswap_int64_t_array */
static inline void
endswap_int64_t_copy (int64_t *dest, const int64_t *src, int len)
{ const unsigned char *psrc ;
unsigned char *pdest ;
if (dest == src)
{ endswap_int64_t_array (dest, len) ;
return ;
} ;
psrc = ((const unsigned char *) src) + 8 * len ;
pdest = ((unsigned char *) dest) + 8 * len ;
while (--len >= 0)
{ psrc -= 8 ;
pdest -= 8 ;
pdest [0] = psrc [7] ;
pdest [2] = psrc [5] ;
pdest [4] = psrc [3] ;
pdest [6] = psrc [1] ;
pdest [7] = psrc [0] ;
pdest [1] = psrc [6] ;
pdest [3] = psrc [4] ;
pdest [5] = psrc [2] ;
} ;
} /* endswap_int64_t_copy */
#endif
/* A couple of wrapper functions. */
static inline void
endswap_float_array (float *ptr, int len)
{ endswap_int_array ((void *) ptr, len) ;
} /* endswap_float_array */
static inline void
endswap_double_array (double *ptr, int len)
{ endswap_int64_t_array ((void *) ptr, len) ;
} /* endswap_double_array */
static inline void
endswap_float_copy (float *dest, const float *src, int len)
{ endswap_int_copy ((int *) dest, (const int *) src, len) ;
} /* endswap_float_copy */
static inline void
endswap_double_copy (double *dest, const double *src, int len)
{ endswap_int64_t_copy ((int64_t *) dest, (const int64_t *) src, len) ;
} /* endswap_double_copy */
#endif /* SFENDIAN_INCLUDED */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,666 @@
/*
** Copyright (C) 1999-2011Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
** sndfile.h -- system-wide definitions
**
** API documentation is in the doc/ directory of the source code tarball
** and at http://www.mega-nerd.com/libsndfile/api.html.
*/
#ifndef SNDFILE_H
#define SNDFILE_H
/* This is the version 1.0.X header file. */
#define SNDFILE_1
#include <stdio.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* The following file types can be read and written.
** A file type would consist of a major type (ie SF_FORMAT_WAV) bitwise
** ORed with a minor type (ie SF_FORMAT_PCM). SF_FORMAT_TYPEMASK and
** SF_FORMAT_SUBMASK can be used to separate the major and minor file
** types.
*/
enum
{ /* Major formats. */
SF_FORMAT_WAV = 0x010000, /* Microsoft WAV format (little endian default). */
SF_FORMAT_AIFF = 0x020000, /* Apple/SGI AIFF format (big endian). */
SF_FORMAT_AU = 0x030000, /* Sun/NeXT AU format (big endian). */
SF_FORMAT_RAW = 0x040000, /* RAW PCM data. */
SF_FORMAT_PAF = 0x050000, /* Ensoniq PARIS file format. */
SF_FORMAT_SVX = 0x060000, /* Amiga IFF / SVX8 / SV16 format. */
SF_FORMAT_NIST = 0x070000, /* Sphere NIST format. */
SF_FORMAT_VOC = 0x080000, /* VOC files. */
SF_FORMAT_IRCAM = 0x0A0000, /* Berkeley/IRCAM/CARL */
SF_FORMAT_W64 = 0x0B0000, /* Sonic Foundry's 64 bit RIFF/WAV */
SF_FORMAT_MAT4 = 0x0C0000, /* Matlab (tm) V4.2 / GNU Octave 2.0 */
SF_FORMAT_MAT5 = 0x0D0000, /* Matlab (tm) V5.0 / GNU Octave 2.1 */
SF_FORMAT_PVF = 0x0E0000, /* Portable Voice Format */
SF_FORMAT_XI = 0x0F0000, /* Fasttracker 2 Extended Instrument */
SF_FORMAT_HTK = 0x100000, /* HMM Tool Kit format */
SF_FORMAT_SDS = 0x110000, /* Midi Sample Dump Standard */
SF_FORMAT_AVR = 0x120000, /* Audio Visual Research */
SF_FORMAT_WAVEX = 0x130000, /* MS WAVE with WAVEFORMATEX */
SF_FORMAT_SD2 = 0x160000, /* Sound Designer 2 */
SF_FORMAT_FLAC = 0x170000, /* FLAC lossless file format */
SF_FORMAT_CAF = 0x180000, /* Core Audio File format */
SF_FORMAT_WVE = 0x190000, /* Psion WVE format */
SF_FORMAT_OGG = 0x200000, /* Xiph OGG container */
SF_FORMAT_MPC2K = 0x210000, /* Akai MPC 2000 sampler */
SF_FORMAT_RF64 = 0x220000, /* RF64 WAV file */
/* Subtypes from here on. */
SF_FORMAT_PCM_S8 = 0x0001, /* Signed 8 bit data */
SF_FORMAT_PCM_16 = 0x0002, /* Signed 16 bit data */
SF_FORMAT_PCM_24 = 0x0003, /* Signed 24 bit data */
SF_FORMAT_PCM_32 = 0x0004, /* Signed 32 bit data */
SF_FORMAT_PCM_U8 = 0x0005, /* Unsigned 8 bit data (WAV and RAW only) */
SF_FORMAT_FLOAT = 0x0006, /* 32 bit float data */
SF_FORMAT_DOUBLE = 0x0007, /* 64 bit float data */
SF_FORMAT_ULAW = 0x0010, /* U-Law encoded. */
SF_FORMAT_ALAW = 0x0011, /* A-Law encoded. */
SF_FORMAT_IMA_ADPCM = 0x0012, /* IMA ADPCM. */
SF_FORMAT_MS_ADPCM = 0x0013, /* Microsoft ADPCM. */
SF_FORMAT_GSM610 = 0x0020, /* GSM 6.10 encoding. */
SF_FORMAT_VOX_ADPCM = 0x0021, /* OKI / Dialogix ADPCM */
SF_FORMAT_G721_32 = 0x0030, /* 32kbs G721 ADPCM encoding. */
SF_FORMAT_G723_24 = 0x0031, /* 24kbs G723 ADPCM encoding. */
SF_FORMAT_G723_40 = 0x0032, /* 40kbs G723 ADPCM encoding. */
SF_FORMAT_DWVW_12 = 0x0040, /* 12 bit Delta Width Variable Word encoding. */
SF_FORMAT_DWVW_16 = 0x0041, /* 16 bit Delta Width Variable Word encoding. */
SF_FORMAT_DWVW_24 = 0x0042, /* 24 bit Delta Width Variable Word encoding. */
SF_FORMAT_DWVW_N = 0x0043, /* N bit Delta Width Variable Word encoding. */
SF_FORMAT_DPCM_8 = 0x0050, /* 8 bit differential PCM (XI only) */
SF_FORMAT_DPCM_16 = 0x0051, /* 16 bit differential PCM (XI only) */
SF_FORMAT_VORBIS = 0x0060, /* Xiph Vorbis encoding. */
/* Endian-ness options. */
SF_ENDIAN_FILE = 0x00000000, /* Default file endian-ness. */
SF_ENDIAN_LITTLE = 0x10000000, /* Force little endian-ness. */
SF_ENDIAN_BIG = 0x20000000, /* Force big endian-ness. */
SF_ENDIAN_CPU = 0x30000000, /* Force CPU endian-ness. */
SF_FORMAT_SUBMASK = 0x0000FFFF,
SF_FORMAT_TYPEMASK = 0x0FFF0000,
SF_FORMAT_ENDMASK = 0x30000000
} ;
/*
** The following are the valid command numbers for the sf_command()
** interface. The use of these commands is documented in the file
** command.html in the doc directory of the source code distribution.
*/
enum
{ SFC_GET_LIB_VERSION = 0x1000,
SFC_GET_LOG_INFO = 0x1001,
SFC_GET_CURRENT_SF_INFO = 0x1002,
SFC_GET_NORM_DOUBLE = 0x1010,
SFC_GET_NORM_FLOAT = 0x1011,
SFC_SET_NORM_DOUBLE = 0x1012,
SFC_SET_NORM_FLOAT = 0x1013,
SFC_SET_SCALE_FLOAT_INT_READ = 0x1014,
SFC_SET_SCALE_INT_FLOAT_WRITE = 0x1015,
SFC_GET_SIMPLE_FORMAT_COUNT = 0x1020,
SFC_GET_SIMPLE_FORMAT = 0x1021,
SFC_GET_FORMAT_INFO = 0x1028,
SFC_GET_FORMAT_MAJOR_COUNT = 0x1030,
SFC_GET_FORMAT_MAJOR = 0x1031,
SFC_GET_FORMAT_SUBTYPE_COUNT = 0x1032,
SFC_GET_FORMAT_SUBTYPE = 0x1033,
SFC_CALC_SIGNAL_MAX = 0x1040,
SFC_CALC_NORM_SIGNAL_MAX = 0x1041,
SFC_CALC_MAX_ALL_CHANNELS = 0x1042,
SFC_CALC_NORM_MAX_ALL_CHANNELS = 0x1043,
SFC_GET_SIGNAL_MAX = 0x1044,
SFC_GET_MAX_ALL_CHANNELS = 0x1045,
SFC_SET_ADD_PEAK_CHUNK = 0x1050,
SFC_SET_ADD_HEADER_PAD_CHUNK = 0x1051,
SFC_UPDATE_HEADER_NOW = 0x1060,
SFC_SET_UPDATE_HEADER_AUTO = 0x1061,
SFC_FILE_TRUNCATE = 0x1080,
SFC_SET_RAW_START_OFFSET = 0x1090,
SFC_SET_DITHER_ON_WRITE = 0x10A0,
SFC_SET_DITHER_ON_READ = 0x10A1,
SFC_GET_DITHER_INFO_COUNT = 0x10A2,
SFC_GET_DITHER_INFO = 0x10A3,
SFC_GET_EMBED_FILE_INFO = 0x10B0,
SFC_SET_CLIPPING = 0x10C0,
SFC_GET_CLIPPING = 0x10C1,
SFC_GET_INSTRUMENT = 0x10D0,
SFC_SET_INSTRUMENT = 0x10D1,
SFC_GET_LOOP_INFO = 0x10E0,
SFC_GET_BROADCAST_INFO = 0x10F0,
SFC_SET_BROADCAST_INFO = 0x10F1,
SFC_GET_CHANNEL_MAP_INFO = 0x1100,
SFC_SET_CHANNEL_MAP_INFO = 0x1101,
SFC_RAW_DATA_NEEDS_ENDSWAP = 0x1110,
/* Support for Wavex Ambisonics Format */
SFC_WAVEX_SET_AMBISONIC = 0x1200,
SFC_WAVEX_GET_AMBISONIC = 0x1201,
SFC_SET_VBR_ENCODING_QUALITY = 0x1300,
/* Following commands for testing only. */
SFC_TEST_IEEE_FLOAT_REPLACE = 0x6001,
/*
** SFC_SET_ADD_* values are deprecated and will disappear at some
** time in the future. They are guaranteed to be here up to and
** including version 1.0.8 to avoid breakage of existng software.
** They currently do nothing and will continue to do nothing.
*/
SFC_SET_ADD_DITHER_ON_WRITE = 0x1070,
SFC_SET_ADD_DITHER_ON_READ = 0x1071
} ;
/*
** String types that can be set and read from files. Not all file types
** support this and even the file types which support one, may not support
** all string types.
*/
enum
{ SF_STR_TITLE = 0x01,
SF_STR_COPYRIGHT = 0x02,
SF_STR_SOFTWARE = 0x03,
SF_STR_ARTIST = 0x04,
SF_STR_COMMENT = 0x05,
SF_STR_DATE = 0x06,
SF_STR_ALBUM = 0x07,
SF_STR_LICENSE = 0x08,
SF_STR_TRACKNUMBER = 0x09,
SF_STR_GENRE = 0x10
} ;
/*
** Use the following as the start and end index when doing metadata
** transcoding.
*/
#define SF_STR_FIRST SF_STR_TITLE
#define SF_STR_LAST SF_STR_GENRE
enum
{ /* True and false */
SF_FALSE = 0,
SF_TRUE = 1,
/* Modes for opening files. */
SFM_READ = 0x10,
SFM_WRITE = 0x20,
SFM_RDWR = 0x30,
SF_AMBISONIC_NONE = 0x40,
SF_AMBISONIC_B_FORMAT = 0x41
} ;
/* Public error values. These are guaranteed to remain unchanged for the duration
** of the library major version number.
** There are also a large number of private error numbers which are internal to
** the library which can change at any time.
*/
enum
{ SF_ERR_NO_ERROR = 0,
SF_ERR_UNRECOGNISED_FORMAT = 1,
SF_ERR_SYSTEM = 2,
SF_ERR_MALFORMED_FILE = 3,
SF_ERR_UNSUPPORTED_ENCODING = 4
} ;
/* Channel map values (used with SFC_SET/GET_CHANNEL_MAP).
*/
enum
{ SF_CHANNEL_MAP_INVALID = 0,
SF_CHANNEL_MAP_MONO = 1,
SF_CHANNEL_MAP_LEFT, /* Apple calls this 'Left' */
SF_CHANNEL_MAP_RIGHT, /* Apple calls this 'Right' */
SF_CHANNEL_MAP_CENTER, /* Apple calls this 'Center' */
SF_CHANNEL_MAP_FRONT_LEFT,
SF_CHANNEL_MAP_FRONT_RIGHT,
SF_CHANNEL_MAP_FRONT_CENTER,
SF_CHANNEL_MAP_REAR_CENTER, /* Apple calls this 'Center Surround', Msft calls this 'Back Center' */
SF_CHANNEL_MAP_REAR_LEFT, /* Apple calls this 'Left Surround', Msft calls this 'Back Left' */
SF_CHANNEL_MAP_REAR_RIGHT, /* Apple calls this 'Right Surround', Msft calls this 'Back Right' */
SF_CHANNEL_MAP_LFE, /* Apple calls this 'LFEScreen', Msft calls this 'Low Frequency' */
SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER, /* Apple calls this 'Left Center' */
SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER, /* Apple calls this 'Right Center */
SF_CHANNEL_MAP_SIDE_LEFT, /* Apple calls this 'Left Surround Direct' */
SF_CHANNEL_MAP_SIDE_RIGHT, /* Apple calls this 'Right Surround Direct' */
SF_CHANNEL_MAP_TOP_CENTER, /* Apple calls this 'Top Center Surround' */
SF_CHANNEL_MAP_TOP_FRONT_LEFT, /* Apple calls this 'Vertical Height Left' */
SF_CHANNEL_MAP_TOP_FRONT_RIGHT, /* Apple calls this 'Vertical Height Right' */
SF_CHANNEL_MAP_TOP_FRONT_CENTER, /* Apple calls this 'Vertical Height Center' */
SF_CHANNEL_MAP_TOP_REAR_LEFT, /* Apple and MS call this 'Top Back Left' */
SF_CHANNEL_MAP_TOP_REAR_RIGHT, /* Apple and MS call this 'Top Back Right' */
SF_CHANNEL_MAP_TOP_REAR_CENTER, /* Apple and MS call this 'Top Back Center' */
SF_CHANNEL_MAP_AMBISONIC_B_W,
SF_CHANNEL_MAP_AMBISONIC_B_X,
SF_CHANNEL_MAP_AMBISONIC_B_Y,
SF_CHANNEL_MAP_AMBISONIC_B_Z,
SF_CHANNEL_MAP_MAX
} ;
/* A SNDFILE* pointer can be passed around much like stdio.h's FILE* pointer. */
typedef struct SNDFILE_tag SNDFILE ;
/* The following typedef is system specific and is defined when libsndfile is
** compiled. sf_count_t will be a 64 bit value when the underlying OS allows
** 64 bit file offsets.
** On windows, we need to allow the same header file to be compiler by both GCC
** and the Microsoft compiler.
*/
#if (defined (_MSCVER) || defined (_MSC_VER))
typedef __int64 sf_count_t ;
#define SF_COUNT_MAX 0x7fffffffffffffffi64
#else
typedef int64_t sf_count_t ;
#define SF_COUNT_MAX 0x7FFFFFFFFFFFFFFFLL
#endif
/* A pointer to a SF_INFO structure is passed to sf_open () and filled in.
** On write, the SF_INFO structure is filled in by the user and passed into
** sf_open ().
*/
struct SF_INFO
{ sf_count_t frames ; /* Used to be called samples. Changed to avoid confusion. */
int samplerate ;
int channels ;
int format ;
int sections ;
int seekable ;
} ;
typedef struct SF_INFO SF_INFO ;
/* The SF_FORMAT_INFO struct is used to retrieve information about the sound
** file formats libsndfile supports using the sf_command () interface.
**
** Using this interface will allow applications to support new file formats
** and encoding types when libsndfile is upgraded, without requiring
** re-compilation of the application.
**
** Please consult the libsndfile documentation (particularly the information
** on the sf_command () interface) for examples of its use.
*/
typedef struct
{ int format ;
const char *name ;
const char *extension ;
} SF_FORMAT_INFO ;
/*
** Enums and typedefs for adding dither on read and write.
** See the html documentation for sf_command(), SFC_SET_DITHER_ON_WRITE
** and SFC_SET_DITHER_ON_READ.
*/
enum
{ SFD_DEFAULT_LEVEL = 0,
SFD_CUSTOM_LEVEL = 0x40000000,
SFD_NO_DITHER = 500,
SFD_WHITE = 501,
SFD_TRIANGULAR_PDF = 502
} ;
typedef struct
{ int type ;
double level ;
const char *name ;
} SF_DITHER_INFO ;
/* Struct used to retrieve information about a file embedded within a
** larger file. See SFC_GET_EMBED_FILE_INFO.
*/
typedef struct
{ sf_count_t offset ;
sf_count_t length ;
} SF_EMBED_FILE_INFO ;
/*
** Structs used to retrieve music sample information from a file.
*/
enum
{ /*
** The loop mode field in SF_INSTRUMENT will be one of the following.
*/
SF_LOOP_NONE = 800,
SF_LOOP_FORWARD,
SF_LOOP_BACKWARD,
SF_LOOP_ALTERNATING
} ;
typedef struct
{ int gain ;
char basenote, detune ;
char velocity_lo, velocity_hi ;
char key_lo, key_hi ;
int loop_count ;
struct
{ int mode ;
unsigned int start ;
unsigned int end ;
unsigned int count ;
} loops [16] ; /* make variable in a sensible way */
} SF_INSTRUMENT ;
/* Struct used to retrieve loop information from a file.*/
typedef struct
{
short time_sig_num ; /* any positive integer > 0 */
short time_sig_den ; /* any positive power of 2 > 0 */
int loop_mode ; /* see SF_LOOP enum */
int num_beats ; /* this is NOT the amount of quarter notes !!!*/
/* a full bar of 4/4 is 4 beats */
/* a full bar of 7/8 is 7 beats */
float bpm ; /* suggestion, as it can be calculated using other fields:*/
/* file's lenght, file's sampleRate and our time_sig_den*/
/* -> bpms are always the amount of _quarter notes_ per minute */
int root_key ; /* MIDI note, or -1 for None */
int future [6] ;
} SF_LOOP_INFO ;
/* Struct used to retrieve broadcast (EBU) information from a file.
** Strongly (!) based on EBU "bext" chunk format used in Broadcast WAVE.
*/
#define SF_BROADCAST_INFO_VAR(coding_hist_size) \
struct \
{ char description [256] ; \
char originator [32] ; \
char originator_reference [32] ; \
char origination_date [10] ; \
char origination_time [8] ; \
unsigned int time_reference_low ; \
unsigned int time_reference_high ; \
short version ; \
char umid [64] ; \
char reserved [190] ; \
unsigned int coding_history_size ; \
char coding_history [coding_hist_size] ; \
}
/* SF_BROADCAST_INFO is the above struct with coding_history field of 256 bytes. */
typedef SF_BROADCAST_INFO_VAR (256) SF_BROADCAST_INFO ;
/* Virtual I/O functionality. */
typedef sf_count_t (*sf_vio_get_filelen) (void *user_data) ;
typedef sf_count_t (*sf_vio_seek) (sf_count_t offset, int whence, void *user_data) ;
typedef sf_count_t (*sf_vio_read) (void *ptr, sf_count_t count, void *user_data) ;
typedef sf_count_t (*sf_vio_write) (const void *ptr, sf_count_t count, void *user_data) ;
typedef sf_count_t (*sf_vio_tell) (void *user_data) ;
struct SF_VIRTUAL_IO
{ sf_vio_get_filelen get_filelen ;
sf_vio_seek seek ;
sf_vio_read read ;
sf_vio_write write ;
sf_vio_tell tell ;
} ;
typedef struct SF_VIRTUAL_IO SF_VIRTUAL_IO ;
/* Open the specified file for read, write or both. On error, this will
** return a NULL pointer. To find the error number, pass a NULL SNDFILE
** to sf_strerror ().
** All calls to sf_open() should be matched with a call to sf_close().
*/
SNDFILE* sf_open (const char *path, int mode, SF_INFO *sfinfo) ;
/* Use the existing file descriptor to create a SNDFILE object. If close_desc
** is TRUE, the file descriptor will be closed when sf_close() is called. If
** it is FALSE, the descritor will not be closed.
** When passed a descriptor like this, the library will assume that the start
** of file header is at the current file offset. This allows sound files within
** larger container files to be read and/or written.
** On error, this will return a NULL pointer. To find the error number, pass a
** NULL SNDFILE to sf_strerror ().
** All calls to sf_open_fd() should be matched with a call to sf_close().
*/
SNDFILE* sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc) ;
SNDFILE* sf_open_virtual (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data) ;
/* sf_error () returns a error number which can be translated to a text
** string using sf_error_number().
*/
int sf_error (SNDFILE *sndfile) ;
/* sf_strerror () returns to the caller a pointer to the current error message for
** the given SNDFILE.
*/
const char* sf_strerror (SNDFILE *sndfile) ;
/* sf_error_number () allows the retrieval of the error string for each internal
** error number.
**
*/
const char* sf_error_number (int errnum) ;
/* The following two error functions are deprecated but they will remain in the
** library for the forseeable future. The function sf_strerror() should be used
** in their place.
*/
int sf_perror (SNDFILE *sndfile) ;
int sf_error_str (SNDFILE *sndfile, char* str, size_t len) ;
/* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */
int sf_command (SNDFILE *sndfile, int command, void *data, int datasize) ;
/* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */
int sf_format_check (const SF_INFO *info) ;
/* Seek within the waveform data chunk of the SNDFILE. sf_seek () uses
** the same values for whence (SEEK_SET, SEEK_CUR and SEEK_END) as
** stdio.h function fseek ().
** An offset of zero with whence set to SEEK_SET will position the
** read / write pointer to the first data sample.
** On success sf_seek returns the current position in (multi-channel)
** samples from the start of the file.
** Please see the libsndfile documentation for moving the read pointer
** separately from the write pointer on files open in mode SFM_RDWR.
** On error all of these functions return -1.
*/
sf_count_t sf_seek (SNDFILE *sndfile, sf_count_t frames, int whence) ;
/* Functions for retrieving and setting string data within sound files.
** Not all file types support this features; AIFF and WAV do. For both
** functions, the str_type parameter must be one of the SF_STR_* values
** defined above.
** On error, sf_set_string() returns non-zero while sf_get_string()
** returns NULL.
*/
int sf_set_string (SNDFILE *sndfile, int str_type, const char* str) ;
const char* sf_get_string (SNDFILE *sndfile, int str_type) ;
/* Return the library version string. */
const char * sf_version_string (void) ;
/* Functions for reading/writing the waveform data of a sound file.
*/
sf_count_t sf_read_raw (SNDFILE *sndfile, void *ptr, sf_count_t bytes) ;
sf_count_t sf_write_raw (SNDFILE *sndfile, const void *ptr, sf_count_t bytes) ;
/* Functions for reading and writing the data chunk in terms of frames.
** The number of items actually read/written = frames * number of channels.
** sf_xxxx_raw read/writes the raw data bytes from/to the file
** sf_xxxx_short passes data in the native short format
** sf_xxxx_int passes data in the native int format
** sf_xxxx_float passes data in the native float format
** sf_xxxx_double passes data in the native double format
** All of these read/write function return number of frames read/written.
*/
sf_count_t sf_readf_short (SNDFILE *sndfile, short *ptr, sf_count_t frames) ;
sf_count_t sf_writef_short (SNDFILE *sndfile, const short *ptr, sf_count_t frames) ;
sf_count_t sf_readf_int (SNDFILE *sndfile, int *ptr, sf_count_t frames) ;
sf_count_t sf_writef_int (SNDFILE *sndfile, const int *ptr, sf_count_t frames) ;
sf_count_t sf_readf_float (SNDFILE *sndfile, float *ptr, sf_count_t frames) ;
sf_count_t sf_writef_float (SNDFILE *sndfile, const float *ptr, sf_count_t frames) ;
sf_count_t sf_readf_double (SNDFILE *sndfile, double *ptr, sf_count_t frames) ;
sf_count_t sf_writef_double (SNDFILE *sndfile, const double *ptr, sf_count_t frames) ;
/* Functions for reading and writing the data chunk in terms of items.
** Otherwise similar to above.
** All of these read/write function return number of items read/written.
*/
sf_count_t sf_read_short (SNDFILE *sndfile, short *ptr, sf_count_t items) ;
sf_count_t sf_write_short (SNDFILE *sndfile, const short *ptr, sf_count_t items) ;
sf_count_t sf_read_int (SNDFILE *sndfile, int *ptr, sf_count_t items) ;
sf_count_t sf_write_int (SNDFILE *sndfile, const int *ptr, sf_count_t items) ;
sf_count_t sf_read_float (SNDFILE *sndfile, float *ptr, sf_count_t items) ;
sf_count_t sf_write_float (SNDFILE *sndfile, const float *ptr, sf_count_t items) ;
sf_count_t sf_read_double (SNDFILE *sndfile, double *ptr, sf_count_t items) ;
sf_count_t sf_write_double (SNDFILE *sndfile, const double *ptr, sf_count_t items) ;
/* Close the SNDFILE and clean up all memory allocations associated with this
** file.
** Returns 0 on success, or an error number.
*/
int sf_close (SNDFILE *sndfile) ;
/* If the file is opened SFM_WRITE or SFM_RDWR, call fsync() on the file
** to force the writing of data to disk. If the file is opened SFM_READ
** no action is taken.
*/
void sf_write_sync (SNDFILE *sndfile) ;
/* The function sf_wchar_open() is Windows Only!
** Open a file passing in a Windows Unicode filename. Otherwise, this is
** the same as sf_open().
**
** In order for this to work, you need to do the following:
**
** #include <windows.h>
** #define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1
** #including <sndfile.h>
*/
#if (defined (ENABLE_SNDFILE_WINDOWS_PROTOTYPES) && ENABLE_SNDFILE_WINDOWS_PROTOTYPES)
SNDFILE* sf_wchar_open (LPCWSTR wpath, int mode, SF_INFO *sfinfo) ;
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* SNDFILE_H */

View File

@@ -0,0 +1,666 @@
/*
** Copyright (C) 1999-2011Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
** sndfile.h -- system-wide definitions
**
** API documentation is in the doc/ directory of the source code tarball
** and at http://www.mega-nerd.com/libsndfile/api.html.
*/
#ifndef SNDFILE_H
#define SNDFILE_H
/* This is the version 1.0.X header file. */
#define SNDFILE_1
#include <stdio.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* The following file types can be read and written.
** A file type would consist of a major type (ie SF_FORMAT_WAV) bitwise
** ORed with a minor type (ie SF_FORMAT_PCM). SF_FORMAT_TYPEMASK and
** SF_FORMAT_SUBMASK can be used to separate the major and minor file
** types.
*/
enum
{ /* Major formats. */
SF_FORMAT_WAV = 0x010000, /* Microsoft WAV format (little endian default). */
SF_FORMAT_AIFF = 0x020000, /* Apple/SGI AIFF format (big endian). */
SF_FORMAT_AU = 0x030000, /* Sun/NeXT AU format (big endian). */
SF_FORMAT_RAW = 0x040000, /* RAW PCM data. */
SF_FORMAT_PAF = 0x050000, /* Ensoniq PARIS file format. */
SF_FORMAT_SVX = 0x060000, /* Amiga IFF / SVX8 / SV16 format. */
SF_FORMAT_NIST = 0x070000, /* Sphere NIST format. */
SF_FORMAT_VOC = 0x080000, /* VOC files. */
SF_FORMAT_IRCAM = 0x0A0000, /* Berkeley/IRCAM/CARL */
SF_FORMAT_W64 = 0x0B0000, /* Sonic Foundry's 64 bit RIFF/WAV */
SF_FORMAT_MAT4 = 0x0C0000, /* Matlab (tm) V4.2 / GNU Octave 2.0 */
SF_FORMAT_MAT5 = 0x0D0000, /* Matlab (tm) V5.0 / GNU Octave 2.1 */
SF_FORMAT_PVF = 0x0E0000, /* Portable Voice Format */
SF_FORMAT_XI = 0x0F0000, /* Fasttracker 2 Extended Instrument */
SF_FORMAT_HTK = 0x100000, /* HMM Tool Kit format */
SF_FORMAT_SDS = 0x110000, /* Midi Sample Dump Standard */
SF_FORMAT_AVR = 0x120000, /* Audio Visual Research */
SF_FORMAT_WAVEX = 0x130000, /* MS WAVE with WAVEFORMATEX */
SF_FORMAT_SD2 = 0x160000, /* Sound Designer 2 */
SF_FORMAT_FLAC = 0x170000, /* FLAC lossless file format */
SF_FORMAT_CAF = 0x180000, /* Core Audio File format */
SF_FORMAT_WVE = 0x190000, /* Psion WVE format */
SF_FORMAT_OGG = 0x200000, /* Xiph OGG container */
SF_FORMAT_MPC2K = 0x210000, /* Akai MPC 2000 sampler */
SF_FORMAT_RF64 = 0x220000, /* RF64 WAV file */
/* Subtypes from here on. */
SF_FORMAT_PCM_S8 = 0x0001, /* Signed 8 bit data */
SF_FORMAT_PCM_16 = 0x0002, /* Signed 16 bit data */
SF_FORMAT_PCM_24 = 0x0003, /* Signed 24 bit data */
SF_FORMAT_PCM_32 = 0x0004, /* Signed 32 bit data */
SF_FORMAT_PCM_U8 = 0x0005, /* Unsigned 8 bit data (WAV and RAW only) */
SF_FORMAT_FLOAT = 0x0006, /* 32 bit float data */
SF_FORMAT_DOUBLE = 0x0007, /* 64 bit float data */
SF_FORMAT_ULAW = 0x0010, /* U-Law encoded. */
SF_FORMAT_ALAW = 0x0011, /* A-Law encoded. */
SF_FORMAT_IMA_ADPCM = 0x0012, /* IMA ADPCM. */
SF_FORMAT_MS_ADPCM = 0x0013, /* Microsoft ADPCM. */
SF_FORMAT_GSM610 = 0x0020, /* GSM 6.10 encoding. */
SF_FORMAT_VOX_ADPCM = 0x0021, /* OKI / Dialogix ADPCM */
SF_FORMAT_G721_32 = 0x0030, /* 32kbs G721 ADPCM encoding. */
SF_FORMAT_G723_24 = 0x0031, /* 24kbs G723 ADPCM encoding. */
SF_FORMAT_G723_40 = 0x0032, /* 40kbs G723 ADPCM encoding. */
SF_FORMAT_DWVW_12 = 0x0040, /* 12 bit Delta Width Variable Word encoding. */
SF_FORMAT_DWVW_16 = 0x0041, /* 16 bit Delta Width Variable Word encoding. */
SF_FORMAT_DWVW_24 = 0x0042, /* 24 bit Delta Width Variable Word encoding. */
SF_FORMAT_DWVW_N = 0x0043, /* N bit Delta Width Variable Word encoding. */
SF_FORMAT_DPCM_8 = 0x0050, /* 8 bit differential PCM (XI only) */
SF_FORMAT_DPCM_16 = 0x0051, /* 16 bit differential PCM (XI only) */
SF_FORMAT_VORBIS = 0x0060, /* Xiph Vorbis encoding. */
/* Endian-ness options. */
SF_ENDIAN_FILE = 0x00000000, /* Default file endian-ness. */
SF_ENDIAN_LITTLE = 0x10000000, /* Force little endian-ness. */
SF_ENDIAN_BIG = 0x20000000, /* Force big endian-ness. */
SF_ENDIAN_CPU = 0x30000000, /* Force CPU endian-ness. */
SF_FORMAT_SUBMASK = 0x0000FFFF,
SF_FORMAT_TYPEMASK = 0x0FFF0000,
SF_FORMAT_ENDMASK = 0x30000000
} ;
/*
** The following are the valid command numbers for the sf_command()
** interface. The use of these commands is documented in the file
** command.html in the doc directory of the source code distribution.
*/
enum
{ SFC_GET_LIB_VERSION = 0x1000,
SFC_GET_LOG_INFO = 0x1001,
SFC_GET_CURRENT_SF_INFO = 0x1002,
SFC_GET_NORM_DOUBLE = 0x1010,
SFC_GET_NORM_FLOAT = 0x1011,
SFC_SET_NORM_DOUBLE = 0x1012,
SFC_SET_NORM_FLOAT = 0x1013,
SFC_SET_SCALE_FLOAT_INT_READ = 0x1014,
SFC_SET_SCALE_INT_FLOAT_WRITE = 0x1015,
SFC_GET_SIMPLE_FORMAT_COUNT = 0x1020,
SFC_GET_SIMPLE_FORMAT = 0x1021,
SFC_GET_FORMAT_INFO = 0x1028,
SFC_GET_FORMAT_MAJOR_COUNT = 0x1030,
SFC_GET_FORMAT_MAJOR = 0x1031,
SFC_GET_FORMAT_SUBTYPE_COUNT = 0x1032,
SFC_GET_FORMAT_SUBTYPE = 0x1033,
SFC_CALC_SIGNAL_MAX = 0x1040,
SFC_CALC_NORM_SIGNAL_MAX = 0x1041,
SFC_CALC_MAX_ALL_CHANNELS = 0x1042,
SFC_CALC_NORM_MAX_ALL_CHANNELS = 0x1043,
SFC_GET_SIGNAL_MAX = 0x1044,
SFC_GET_MAX_ALL_CHANNELS = 0x1045,
SFC_SET_ADD_PEAK_CHUNK = 0x1050,
SFC_SET_ADD_HEADER_PAD_CHUNK = 0x1051,
SFC_UPDATE_HEADER_NOW = 0x1060,
SFC_SET_UPDATE_HEADER_AUTO = 0x1061,
SFC_FILE_TRUNCATE = 0x1080,
SFC_SET_RAW_START_OFFSET = 0x1090,
SFC_SET_DITHER_ON_WRITE = 0x10A0,
SFC_SET_DITHER_ON_READ = 0x10A1,
SFC_GET_DITHER_INFO_COUNT = 0x10A2,
SFC_GET_DITHER_INFO = 0x10A3,
SFC_GET_EMBED_FILE_INFO = 0x10B0,
SFC_SET_CLIPPING = 0x10C0,
SFC_GET_CLIPPING = 0x10C1,
SFC_GET_INSTRUMENT = 0x10D0,
SFC_SET_INSTRUMENT = 0x10D1,
SFC_GET_LOOP_INFO = 0x10E0,
SFC_GET_BROADCAST_INFO = 0x10F0,
SFC_SET_BROADCAST_INFO = 0x10F1,
SFC_GET_CHANNEL_MAP_INFO = 0x1100,
SFC_SET_CHANNEL_MAP_INFO = 0x1101,
SFC_RAW_DATA_NEEDS_ENDSWAP = 0x1110,
/* Support for Wavex Ambisonics Format */
SFC_WAVEX_SET_AMBISONIC = 0x1200,
SFC_WAVEX_GET_AMBISONIC = 0x1201,
SFC_SET_VBR_ENCODING_QUALITY = 0x1300,
/* Following commands for testing only. */
SFC_TEST_IEEE_FLOAT_REPLACE = 0x6001,
/*
** SFC_SET_ADD_* values are deprecated and will disappear at some
** time in the future. They are guaranteed to be here up to and
** including version 1.0.8 to avoid breakage of existng software.
** They currently do nothing and will continue to do nothing.
*/
SFC_SET_ADD_DITHER_ON_WRITE = 0x1070,
SFC_SET_ADD_DITHER_ON_READ = 0x1071
} ;
/*
** String types that can be set and read from files. Not all file types
** support this and even the file types which support one, may not support
** all string types.
*/
enum
{ SF_STR_TITLE = 0x01,
SF_STR_COPYRIGHT = 0x02,
SF_STR_SOFTWARE = 0x03,
SF_STR_ARTIST = 0x04,
SF_STR_COMMENT = 0x05,
SF_STR_DATE = 0x06,
SF_STR_ALBUM = 0x07,
SF_STR_LICENSE = 0x08,
SF_STR_TRACKNUMBER = 0x09,
SF_STR_GENRE = 0x10
} ;
/*
** Use the following as the start and end index when doing metadata
** transcoding.
*/
#define SF_STR_FIRST SF_STR_TITLE
#define SF_STR_LAST SF_STR_GENRE
enum
{ /* True and false */
SF_FALSE = 0,
SF_TRUE = 1,
/* Modes for opening files. */
SFM_READ = 0x10,
SFM_WRITE = 0x20,
SFM_RDWR = 0x30,
SF_AMBISONIC_NONE = 0x40,
SF_AMBISONIC_B_FORMAT = 0x41
} ;
/* Public error values. These are guaranteed to remain unchanged for the duration
** of the library major version number.
** There are also a large number of private error numbers which are internal to
** the library which can change at any time.
*/
enum
{ SF_ERR_NO_ERROR = 0,
SF_ERR_UNRECOGNISED_FORMAT = 1,
SF_ERR_SYSTEM = 2,
SF_ERR_MALFORMED_FILE = 3,
SF_ERR_UNSUPPORTED_ENCODING = 4
} ;
/* Channel map values (used with SFC_SET/GET_CHANNEL_MAP).
*/
enum
{ SF_CHANNEL_MAP_INVALID = 0,
SF_CHANNEL_MAP_MONO = 1,
SF_CHANNEL_MAP_LEFT, /* Apple calls this 'Left' */
SF_CHANNEL_MAP_RIGHT, /* Apple calls this 'Right' */
SF_CHANNEL_MAP_CENTER, /* Apple calls this 'Center' */
SF_CHANNEL_MAP_FRONT_LEFT,
SF_CHANNEL_MAP_FRONT_RIGHT,
SF_CHANNEL_MAP_FRONT_CENTER,
SF_CHANNEL_MAP_REAR_CENTER, /* Apple calls this 'Center Surround', Msft calls this 'Back Center' */
SF_CHANNEL_MAP_REAR_LEFT, /* Apple calls this 'Left Surround', Msft calls this 'Back Left' */
SF_CHANNEL_MAP_REAR_RIGHT, /* Apple calls this 'Right Surround', Msft calls this 'Back Right' */
SF_CHANNEL_MAP_LFE, /* Apple calls this 'LFEScreen', Msft calls this 'Low Frequency' */
SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER, /* Apple calls this 'Left Center' */
SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER, /* Apple calls this 'Right Center */
SF_CHANNEL_MAP_SIDE_LEFT, /* Apple calls this 'Left Surround Direct' */
SF_CHANNEL_MAP_SIDE_RIGHT, /* Apple calls this 'Right Surround Direct' */
SF_CHANNEL_MAP_TOP_CENTER, /* Apple calls this 'Top Center Surround' */
SF_CHANNEL_MAP_TOP_FRONT_LEFT, /* Apple calls this 'Vertical Height Left' */
SF_CHANNEL_MAP_TOP_FRONT_RIGHT, /* Apple calls this 'Vertical Height Right' */
SF_CHANNEL_MAP_TOP_FRONT_CENTER, /* Apple calls this 'Vertical Height Center' */
SF_CHANNEL_MAP_TOP_REAR_LEFT, /* Apple and MS call this 'Top Back Left' */
SF_CHANNEL_MAP_TOP_REAR_RIGHT, /* Apple and MS call this 'Top Back Right' */
SF_CHANNEL_MAP_TOP_REAR_CENTER, /* Apple and MS call this 'Top Back Center' */
SF_CHANNEL_MAP_AMBISONIC_B_W,
SF_CHANNEL_MAP_AMBISONIC_B_X,
SF_CHANNEL_MAP_AMBISONIC_B_Y,
SF_CHANNEL_MAP_AMBISONIC_B_Z,
SF_CHANNEL_MAP_MAX
} ;
/* A SNDFILE* pointer can be passed around much like stdio.h's FILE* pointer. */
typedef struct SNDFILE_tag SNDFILE ;
/* The following typedef is system specific and is defined when libsndfile is
** compiled. sf_count_t will be a 64 bit value when the underlying OS allows
** 64 bit file offsets.
** On windows, we need to allow the same header file to be compiler by both GCC
** and the Microsoft compiler.
*/
#if (defined (_MSCVER) || defined (_MSC_VER))
typedef __int64 sf_count_t ;
#define SF_COUNT_MAX 0x7fffffffffffffffi64
#else
typedef @TYPEOF_SF_COUNT_T@ sf_count_t ;
#define SF_COUNT_MAX @SF_COUNT_MAX@
#endif
/* A pointer to a SF_INFO structure is passed to sf_open () and filled in.
** On write, the SF_INFO structure is filled in by the user and passed into
** sf_open ().
*/
struct SF_INFO
{ sf_count_t frames ; /* Used to be called samples. Changed to avoid confusion. */
int samplerate ;
int channels ;
int format ;
int sections ;
int seekable ;
} ;
typedef struct SF_INFO SF_INFO ;
/* The SF_FORMAT_INFO struct is used to retrieve information about the sound
** file formats libsndfile supports using the sf_command () interface.
**
** Using this interface will allow applications to support new file formats
** and encoding types when libsndfile is upgraded, without requiring
** re-compilation of the application.
**
** Please consult the libsndfile documentation (particularly the information
** on the sf_command () interface) for examples of its use.
*/
typedef struct
{ int format ;
const char *name ;
const char *extension ;
} SF_FORMAT_INFO ;
/*
** Enums and typedefs for adding dither on read and write.
** See the html documentation for sf_command(), SFC_SET_DITHER_ON_WRITE
** and SFC_SET_DITHER_ON_READ.
*/
enum
{ SFD_DEFAULT_LEVEL = 0,
SFD_CUSTOM_LEVEL = 0x40000000,
SFD_NO_DITHER = 500,
SFD_WHITE = 501,
SFD_TRIANGULAR_PDF = 502
} ;
typedef struct
{ int type ;
double level ;
const char *name ;
} SF_DITHER_INFO ;
/* Struct used to retrieve information about a file embedded within a
** larger file. See SFC_GET_EMBED_FILE_INFO.
*/
typedef struct
{ sf_count_t offset ;
sf_count_t length ;
} SF_EMBED_FILE_INFO ;
/*
** Structs used to retrieve music sample information from a file.
*/
enum
{ /*
** The loop mode field in SF_INSTRUMENT will be one of the following.
*/
SF_LOOP_NONE = 800,
SF_LOOP_FORWARD,
SF_LOOP_BACKWARD,
SF_LOOP_ALTERNATING
} ;
typedef struct
{ int gain ;
char basenote, detune ;
char velocity_lo, velocity_hi ;
char key_lo, key_hi ;
int loop_count ;
struct
{ int mode ;
unsigned int start ;
unsigned int end ;
unsigned int count ;
} loops [16] ; /* make variable in a sensible way */
} SF_INSTRUMENT ;
/* Struct used to retrieve loop information from a file.*/
typedef struct
{
short time_sig_num ; /* any positive integer > 0 */
short time_sig_den ; /* any positive power of 2 > 0 */
int loop_mode ; /* see SF_LOOP enum */
int num_beats ; /* this is NOT the amount of quarter notes !!!*/
/* a full bar of 4/4 is 4 beats */
/* a full bar of 7/8 is 7 beats */
float bpm ; /* suggestion, as it can be calculated using other fields:*/
/* file's lenght, file's sampleRate and our time_sig_den*/
/* -> bpms are always the amount of _quarter notes_ per minute */
int root_key ; /* MIDI note, or -1 for None */
int future [6] ;
} SF_LOOP_INFO ;
/* Struct used to retrieve broadcast (EBU) information from a file.
** Strongly (!) based on EBU "bext" chunk format used in Broadcast WAVE.
*/
#define SF_BROADCAST_INFO_VAR(coding_hist_size) \
struct \
{ char description [256] ; \
char originator [32] ; \
char originator_reference [32] ; \
char origination_date [10] ; \
char origination_time [8] ; \
unsigned int time_reference_low ; \
unsigned int time_reference_high ; \
short version ; \
char umid [64] ; \
char reserved [190] ; \
unsigned int coding_history_size ; \
char coding_history [coding_hist_size] ; \
}
/* SF_BROADCAST_INFO is the above struct with coding_history field of 256 bytes. */
typedef SF_BROADCAST_INFO_VAR (256) SF_BROADCAST_INFO ;
/* Virtual I/O functionality. */
typedef sf_count_t (*sf_vio_get_filelen) (void *user_data) ;
typedef sf_count_t (*sf_vio_seek) (sf_count_t offset, int whence, void *user_data) ;
typedef sf_count_t (*sf_vio_read) (void *ptr, sf_count_t count, void *user_data) ;
typedef sf_count_t (*sf_vio_write) (const void *ptr, sf_count_t count, void *user_data) ;
typedef sf_count_t (*sf_vio_tell) (void *user_data) ;
struct SF_VIRTUAL_IO
{ sf_vio_get_filelen get_filelen ;
sf_vio_seek seek ;
sf_vio_read read ;
sf_vio_write write ;
sf_vio_tell tell ;
} ;
typedef struct SF_VIRTUAL_IO SF_VIRTUAL_IO ;
/* Open the specified file for read, write or both. On error, this will
** return a NULL pointer. To find the error number, pass a NULL SNDFILE
** to sf_strerror ().
** All calls to sf_open() should be matched with a call to sf_close().
*/
SNDFILE* sf_open (const char *path, int mode, SF_INFO *sfinfo) ;
/* Use the existing file descriptor to create a SNDFILE object. If close_desc
** is TRUE, the file descriptor will be closed when sf_close() is called. If
** it is FALSE, the descritor will not be closed.
** When passed a descriptor like this, the library will assume that the start
** of file header is at the current file offset. This allows sound files within
** larger container files to be read and/or written.
** On error, this will return a NULL pointer. To find the error number, pass a
** NULL SNDFILE to sf_strerror ().
** All calls to sf_open_fd() should be matched with a call to sf_close().
*/
SNDFILE* sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc) ;
SNDFILE* sf_open_virtual (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data) ;
/* sf_error () returns a error number which can be translated to a text
** string using sf_error_number().
*/
int sf_error (SNDFILE *sndfile) ;
/* sf_strerror () returns to the caller a pointer to the current error message for
** the given SNDFILE.
*/
const char* sf_strerror (SNDFILE *sndfile) ;
/* sf_error_number () allows the retrieval of the error string for each internal
** error number.
**
*/
const char* sf_error_number (int errnum) ;
/* The following two error functions are deprecated but they will remain in the
** library for the forseeable future. The function sf_strerror() should be used
** in their place.
*/
int sf_perror (SNDFILE *sndfile) ;
int sf_error_str (SNDFILE *sndfile, char* str, size_t len) ;
/* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */
int sf_command (SNDFILE *sndfile, int command, void *data, int datasize) ;
/* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */
int sf_format_check (const SF_INFO *info) ;
/* Seek within the waveform data chunk of the SNDFILE. sf_seek () uses
** the same values for whence (SEEK_SET, SEEK_CUR and SEEK_END) as
** stdio.h function fseek ().
** An offset of zero with whence set to SEEK_SET will position the
** read / write pointer to the first data sample.
** On success sf_seek returns the current position in (multi-channel)
** samples from the start of the file.
** Please see the libsndfile documentation for moving the read pointer
** separately from the write pointer on files open in mode SFM_RDWR.
** On error all of these functions return -1.
*/
sf_count_t sf_seek (SNDFILE *sndfile, sf_count_t frames, int whence) ;
/* Functions for retrieving and setting string data within sound files.
** Not all file types support this features; AIFF and WAV do. For both
** functions, the str_type parameter must be one of the SF_STR_* values
** defined above.
** On error, sf_set_string() returns non-zero while sf_get_string()
** returns NULL.
*/
int sf_set_string (SNDFILE *sndfile, int str_type, const char* str) ;
const char* sf_get_string (SNDFILE *sndfile, int str_type) ;
/* Return the library version string. */
const char * sf_version_string (void) ;
/* Functions for reading/writing the waveform data of a sound file.
*/
sf_count_t sf_read_raw (SNDFILE *sndfile, void *ptr, sf_count_t bytes) ;
sf_count_t sf_write_raw (SNDFILE *sndfile, const void *ptr, sf_count_t bytes) ;
/* Functions for reading and writing the data chunk in terms of frames.
** The number of items actually read/written = frames * number of channels.
** sf_xxxx_raw read/writes the raw data bytes from/to the file
** sf_xxxx_short passes data in the native short format
** sf_xxxx_int passes data in the native int format
** sf_xxxx_float passes data in the native float format
** sf_xxxx_double passes data in the native double format
** All of these read/write function return number of frames read/written.
*/
sf_count_t sf_readf_short (SNDFILE *sndfile, short *ptr, sf_count_t frames) ;
sf_count_t sf_writef_short (SNDFILE *sndfile, const short *ptr, sf_count_t frames) ;
sf_count_t sf_readf_int (SNDFILE *sndfile, int *ptr, sf_count_t frames) ;
sf_count_t sf_writef_int (SNDFILE *sndfile, const int *ptr, sf_count_t frames) ;
sf_count_t sf_readf_float (SNDFILE *sndfile, float *ptr, sf_count_t frames) ;
sf_count_t sf_writef_float (SNDFILE *sndfile, const float *ptr, sf_count_t frames) ;
sf_count_t sf_readf_double (SNDFILE *sndfile, double *ptr, sf_count_t frames) ;
sf_count_t sf_writef_double (SNDFILE *sndfile, const double *ptr, sf_count_t frames) ;
/* Functions for reading and writing the data chunk in terms of items.
** Otherwise similar to above.
** All of these read/write function return number of items read/written.
*/
sf_count_t sf_read_short (SNDFILE *sndfile, short *ptr, sf_count_t items) ;
sf_count_t sf_write_short (SNDFILE *sndfile, const short *ptr, sf_count_t items) ;
sf_count_t sf_read_int (SNDFILE *sndfile, int *ptr, sf_count_t items) ;
sf_count_t sf_write_int (SNDFILE *sndfile, const int *ptr, sf_count_t items) ;
sf_count_t sf_read_float (SNDFILE *sndfile, float *ptr, sf_count_t items) ;
sf_count_t sf_write_float (SNDFILE *sndfile, const float *ptr, sf_count_t items) ;
sf_count_t sf_read_double (SNDFILE *sndfile, double *ptr, sf_count_t items) ;
sf_count_t sf_write_double (SNDFILE *sndfile, const double *ptr, sf_count_t items) ;
/* Close the SNDFILE and clean up all memory allocations associated with this
** file.
** Returns 0 on success, or an error number.
*/
int sf_close (SNDFILE *sndfile) ;
/* If the file is opened SFM_WRITE or SFM_RDWR, call fsync() on the file
** to force the writing of data to disk. If the file is opened SFM_READ
** no action is taken.
*/
void sf_write_sync (SNDFILE *sndfile) ;
/* The function sf_wchar_open() is Windows Only!
** Open a file passing in a Windows Unicode filename. Otherwise, this is
** the same as sf_open().
**
** In order for this to work, you need to do the following:
**
** #include <windows.h>
** #define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1
** #including <sndfile.h>
*/
#if (defined (ENABLE_SNDFILE_WINDOWS_PROTOTYPES) && ENABLE_SNDFILE_WINDOWS_PROTOTYPES)
SNDFILE* sf_wchar_open (LPCWSTR wpath, int mode, SF_INFO *sfinfo) ;
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* SNDFILE_H */

View File

@@ -0,0 +1,422 @@
/*
** Copyright (C) 2005-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the author nor the names of any contributors may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
** The above modified BSD style license (GPL and LGPL compatible) applies to
** this file. It does not apply to libsndfile itself which is released under
** the GNU LGPL or the libsndfile test suite which is released under the GNU
** GPL.
** This means that this header file can be used under this modified BSD style
** license, but the LGPL still holds for the libsndfile library itself.
*/
/*
** sndfile.hh -- A lightweight C++ wrapper for the libsndfile API.
**
** All the methods are inlines and all functionality is contained in this
** file. There is no separate implementation file.
**
** API documentation is in the doc/ directory of the source code tarball
** and at http://www.mega-nerd.com/libsndfile/api.html.
*/
#ifndef SNDFILE_HH
#define SNDFILE_HH
#include <sndfile.h>
#include <string>
#include <new> // for std::nothrow
class SndfileHandle
{ private :
struct SNDFILE_ref
{ SNDFILE_ref (void) ;
~SNDFILE_ref (void) ;
SNDFILE *sf ;
SF_INFO sfinfo ;
int ref ;
} ;
SNDFILE_ref *p ;
public :
/* Default constructor */
SndfileHandle (void) : p (NULL) {} ;
SndfileHandle (const char *path, int mode = SFM_READ,
int format = 0, int channels = 0, int samplerate = 0) ;
SndfileHandle (std::string const & path, int mode = SFM_READ,
int format = 0, int channels = 0, int samplerate = 0) ;
SndfileHandle (int fd, bool close_desc, int mode = SFM_READ,
int format = 0, int channels = 0, int samplerate = 0) ;
#ifdef ENABLE_SNDFILE_WINDOWS_PROTOTYPES
SndfileHandle (LPCWSTR wpath, int mode = SFM_READ,
int format = 0, int channels = 0, int samplerate = 0) ;
#endif
~SndfileHandle (void) ;
SndfileHandle (const SndfileHandle &orig) ;
SndfileHandle & operator = (const SndfileHandle &rhs) ;
/* Mainly for debugging/testing. */
int refCount (void) const { return (p == NULL) ? 0 : p->ref ; }
operator bool () const { return (p != NULL) ; }
bool operator == (const SndfileHandle &rhs) const { return (p == rhs.p) ; }
sf_count_t frames (void) const { return p ? p->sfinfo.frames : 0 ; }
int format (void) const { return p ? p->sfinfo.format : 0 ; }
int channels (void) const { return p ? p->sfinfo.channels : 0 ; }
int samplerate (void) const { return p ? p->sfinfo.samplerate : 0 ; }
int error (void) const ;
const char * strError (void) const ;
int command (int cmd, void *data, int datasize) ;
sf_count_t seek (sf_count_t frames, int whence) ;
void writeSync (void) ;
int setString (int str_type, const char* str) ;
const char* getString (int str_type) const ;
static int formatCheck (int format, int channels, int samplerate) ;
sf_count_t read (short *ptr, sf_count_t items) ;
sf_count_t read (int *ptr, sf_count_t items) ;
sf_count_t read (float *ptr, sf_count_t items) ;
sf_count_t read (double *ptr, sf_count_t items) ;
sf_count_t write (const short *ptr, sf_count_t items) ;
sf_count_t write (const int *ptr, sf_count_t items) ;
sf_count_t write (const float *ptr, sf_count_t items) ;
sf_count_t write (const double *ptr, sf_count_t items) ;
sf_count_t readf (short *ptr, sf_count_t frames) ;
sf_count_t readf (int *ptr, sf_count_t frames) ;
sf_count_t readf (float *ptr, sf_count_t frames) ;
sf_count_t readf (double *ptr, sf_count_t frames) ;
sf_count_t writef (const short *ptr, sf_count_t frames) ;
sf_count_t writef (const int *ptr, sf_count_t frames) ;
sf_count_t writef (const float *ptr, sf_count_t frames) ;
sf_count_t writef (const double *ptr, sf_count_t frames) ;
sf_count_t readRaw (void *ptr, sf_count_t bytes) ;
sf_count_t writeRaw (const void *ptr, sf_count_t bytes) ;
/**< Raw access to the handle. SndfileHandle keeps ownership. */
SNDFILE * rawHandle (void) ;
/**< Take ownership of handle, iff reference count is 1. */
SNDFILE * takeOwnership (void) ;
} ;
/*==============================================================================
** Nothing but implementation below.
*/
inline
SndfileHandle::SNDFILE_ref::SNDFILE_ref (void)
: ref (1)
{}
inline
SndfileHandle::SNDFILE_ref::~SNDFILE_ref (void)
{ if (sf != NULL) sf_close (sf) ; }
inline
SndfileHandle::SndfileHandle (const char *path, int mode, int fmt, int chans, int srate)
: p (NULL)
{
p = new (std::nothrow) SNDFILE_ref () ;
if (p != NULL)
{ p->ref = 1 ;
p->sfinfo.frames = 0 ;
p->sfinfo.channels = chans ;
p->sfinfo.format = fmt ;
p->sfinfo.samplerate = srate ;
p->sfinfo.sections = 0 ;
p->sfinfo.seekable = 0 ;
p->sf = sf_open (path, mode, &p->sfinfo) ;
} ;
return ;
} /* SndfileHandle const char * constructor */
inline
SndfileHandle::SndfileHandle (std::string const & path, int mode, int fmt, int chans, int srate)
: p (NULL)
{
p = new (std::nothrow) SNDFILE_ref () ;
if (p != NULL)
{ p->ref = 1 ;
p->sfinfo.frames = 0 ;
p->sfinfo.channels = chans ;
p->sfinfo.format = fmt ;
p->sfinfo.samplerate = srate ;
p->sfinfo.sections = 0 ;
p->sfinfo.seekable = 0 ;
p->sf = sf_open (path.c_str (), mode, &p->sfinfo) ;
} ;
return ;
} /* SndfileHandle std::string constructor */
inline
SndfileHandle::SndfileHandle (int fd, bool close_desc, int mode, int fmt, int chans, int srate)
: p (NULL)
{
if (fd < 0)
return ;
p = new (std::nothrow) SNDFILE_ref () ;
if (p != NULL)
{ p->ref = 1 ;
p->sfinfo.frames = 0 ;
p->sfinfo.channels = chans ;
p->sfinfo.format = fmt ;
p->sfinfo.samplerate = srate ;
p->sfinfo.sections = 0 ;
p->sfinfo.seekable = 0 ;
p->sf = sf_open_fd (fd, mode, &p->sfinfo, close_desc) ;
} ;
return ;
} /* SndfileHandle fd constructor */
inline
SndfileHandle::~SndfileHandle (void)
{ if (p != NULL && --p->ref == 0)
delete p ;
} /* SndfileHandle destructor */
inline
SndfileHandle::SndfileHandle (const SndfileHandle &orig)
: p (orig.p)
{ if (p != NULL)
++p->ref ;
} /* SndfileHandle copy constructor */
inline SndfileHandle &
SndfileHandle::operator = (const SndfileHandle &rhs)
{
if (&rhs == this)
return *this ;
if (p != NULL && --p->ref == 0)
delete p ;
p = rhs.p ;
if (p != NULL)
++p->ref ;
return *this ;
} /* SndfileHandle assignment operator */
inline int
SndfileHandle::error (void) const
{ return sf_error (p->sf) ; }
inline const char *
SndfileHandle::strError (void) const
{ return sf_strerror (p->sf) ; }
inline int
SndfileHandle::command (int cmd, void *data, int datasize)
{ return sf_command (p->sf, cmd, data, datasize) ; }
inline sf_count_t
SndfileHandle::seek (sf_count_t frame_count, int whence)
{ return sf_seek (p->sf, frame_count, whence) ; }
inline void
SndfileHandle::writeSync (void)
{ sf_write_sync (p->sf) ; }
inline int
SndfileHandle::setString (int str_type, const char* str)
{ return sf_set_string (p->sf, str_type, str) ; }
inline const char*
SndfileHandle::getString (int str_type) const
{ return sf_get_string (p->sf, str_type) ; }
inline int
SndfileHandle::formatCheck (int fmt, int chans, int srate)
{
SF_INFO sfinfo ;
sfinfo.frames = 0 ;
sfinfo.channels = chans ;
sfinfo.format = fmt ;
sfinfo.samplerate = srate ;
sfinfo.sections = 0 ;
sfinfo.seekable = 0 ;
return sf_format_check (&sfinfo) ;
}
/*---------------------------------------------------------------------*/
inline sf_count_t
SndfileHandle::read (short *ptr, sf_count_t items)
{ return sf_read_short (p->sf, ptr, items) ; }
inline sf_count_t
SndfileHandle::read (int *ptr, sf_count_t items)
{ return sf_read_int (p->sf, ptr, items) ; }
inline sf_count_t
SndfileHandle::read (float *ptr, sf_count_t items)
{ return sf_read_float (p->sf, ptr, items) ; }
inline sf_count_t
SndfileHandle::read (double *ptr, sf_count_t items)
{ return sf_read_double (p->sf, ptr, items) ; }
inline sf_count_t
SndfileHandle::write (const short *ptr, sf_count_t items)
{ return sf_write_short (p->sf, ptr, items) ; }
inline sf_count_t
SndfileHandle::write (const int *ptr, sf_count_t items)
{ return sf_write_int (p->sf, ptr, items) ; }
inline sf_count_t
SndfileHandle::write (const float *ptr, sf_count_t items)
{ return sf_write_float (p->sf, ptr, items) ; }
inline sf_count_t
SndfileHandle::write (const double *ptr, sf_count_t items)
{ return sf_write_double (p->sf, ptr, items) ; }
inline sf_count_t
SndfileHandle::readf (short *ptr, sf_count_t frame_count)
{ return sf_readf_short (p->sf, ptr, frame_count) ; }
inline sf_count_t
SndfileHandle::readf (int *ptr, sf_count_t frame_count)
{ return sf_readf_int (p->sf, ptr, frame_count) ; }
inline sf_count_t
SndfileHandle::readf (float *ptr, sf_count_t frame_count)
{ return sf_readf_float (p->sf, ptr, frame_count) ; }
inline sf_count_t
SndfileHandle::readf (double *ptr, sf_count_t frame_count)
{ return sf_readf_double (p->sf, ptr, frame_count) ; }
inline sf_count_t
SndfileHandle::writef (const short *ptr, sf_count_t frame_count)
{ return sf_writef_short (p->sf, ptr, frame_count) ; }
inline sf_count_t
SndfileHandle::writef (const int *ptr, sf_count_t frame_count)
{ return sf_writef_int (p->sf, ptr, frame_count) ; }
inline sf_count_t
SndfileHandle::writef (const float *ptr, sf_count_t frame_count)
{ return sf_writef_float (p->sf, ptr, frame_count) ; }
inline sf_count_t
SndfileHandle::writef (const double *ptr, sf_count_t frame_count)
{ return sf_writef_double (p->sf, ptr, frame_count) ; }
inline sf_count_t
SndfileHandle::readRaw (void *ptr, sf_count_t bytes)
{ return sf_read_raw (p->sf, ptr, bytes) ; }
inline sf_count_t
SndfileHandle::writeRaw (const void *ptr, sf_count_t bytes)
{ return sf_write_raw (p->sf, ptr, bytes) ; }
inline SNDFILE *
SndfileHandle::rawHandle (void)
{ return (p ? p->sf : NULL) ; }
inline SNDFILE *
SndfileHandle::takeOwnership (void)
{
if (p == NULL || (p->ref != 1))
return NULL ;
SNDFILE * sf = p->sf ;
p->sf = NULL ;
delete p ;
p = NULL ;
return sf ;
}
#ifdef ENABLE_SNDFILE_WINDOWS_PROTOTYPES
inline
SndfileHandle::SndfileHandle (LPCWSTR wpath, int mode, int fmt, int chans, int srate)
: p (NULL)
{
p = new (std::nothrow) SNDFILE_ref () ;
if (p != NULL)
{ p->ref = 1 ;
p->sfinfo.frames = 0 ;
p->sfinfo.channels = chans ;
p->sfinfo.format = fmt ;
p->sfinfo.samplerate = srate ;
p->sfinfo.sections = 0 ;
p->sfinfo.seekable = 0 ;
p->sf = sf_wchar_open (wpath, mode, &p->sfinfo) ;
} ;
return ;
} /* SndfileHandle const wchar_t * constructor */
#endif
#endif /* SNDFILE_HH */

View File

@@ -0,0 +1,214 @@
/*
** Copyright (C) 2001-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "sndfile.h"
#include "common.h"
#define STRINGS_DEBUG 0
#if STRINGS_DEBUG
static void hexdump (void *data, int len) ;
#endif
int
psf_store_string (SF_PRIVATE *psf, int str_type, const char *str)
{ char new_str [128] ;
size_t len_remaining, str_len ;
int k, str_flags ;
if (str == NULL)
return SFE_STR_BAD_STRING ;
str_len = strlen (str) ;
/* A few extra checks for write mode. */
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if ((psf->str_flags & SF_STR_ALLOW_START) == 0)
return SFE_STR_NO_SUPPORT ;
if (psf->have_written && (psf->str_flags & SF_STR_ALLOW_END) == 0)
return SFE_STR_NO_SUPPORT ;
/* Only allow zero length strings for software. */
if (str_type != SF_STR_SOFTWARE && str_len == 0)
return SFE_STR_BAD_STRING ;
} ;
/* Find the next free slot in table. */
for (k = 0 ; k < SF_MAX_STRINGS ; k++)
{ /* If we find a matching entry clear it. */
if (psf->strings [k].type == str_type)
psf->strings [k].type = -1 ;
if (psf->strings [k].type == 0)
break ;
} ;
/* Determine flags */
str_flags = SF_STR_LOCATE_START ;
if (psf->file.mode == SFM_RDWR || psf->have_written)
{ if ((psf->str_flags & SF_STR_ALLOW_END) == 0)
return SFE_STR_NO_ADD_END ;
str_flags = SF_STR_LOCATE_END ;
} ;
/* More sanity checking. */
if (k >= SF_MAX_STRINGS)
return SFE_STR_MAX_COUNT ;
if (k == 0 && psf->str_end != NULL)
{ psf_log_printf (psf, "SFE_STR_WEIRD : k == 0 && psf->str_end != NULL\n") ;
return SFE_STR_WEIRD ;
} ;
if (k != 0 && psf->str_end == NULL)
{ psf_log_printf (psf, "SFE_STR_WEIRD : k != 0 && psf->str_end == NULL\n") ;
return SFE_STR_WEIRD ;
} ;
/* Special case for the first string. */
if (k == 0)
psf->str_end = psf->str_storage ;
switch (str_type)
{ case SF_STR_SOFTWARE :
/* In write mode, want to append libsndfile-version to string. */
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if (strstr (str, PACKAGE) == NULL)
{ /*
** If the supplied string does not already contain a
** libsndfile-X.Y.Z component, then add it.
*/
if (strlen (str) == 0)
snprintf (new_str, sizeof (new_str), "%s-%s", PACKAGE, VERSION) ;
else
snprintf (new_str, sizeof (new_str), "%s (%s-%s)", str, PACKAGE, VERSION) ;
}
else
snprintf (new_str, sizeof (new_str), "%s", str) ;
str = new_str ;
} ;
break ;
case SF_STR_TITLE :
case SF_STR_COPYRIGHT :
case SF_STR_ARTIST :
case SF_STR_COMMENT :
case SF_STR_DATE :
case SF_STR_ALBUM :
case SF_STR_LICENSE :
case SF_STR_TRACKNUMBER :
case SF_STR_GENRE :
break ;
default :
psf_log_printf (psf, "%s : SFE_STR_BAD_TYPE\n", __func__) ;
return SFE_STR_BAD_TYPE ;
} ;
str_len = strlen (str) ;
len_remaining = SIGNED_SIZEOF (psf->str_storage) - (psf->str_end - psf->str_storage) ;
if (len_remaining < str_len + 2)
return SFE_STR_MAX_DATA ;
psf->strings [k].type = str_type ;
psf->strings [k].str = psf->str_end ;
psf->strings [k].flags = str_flags ;
memcpy (psf->str_end, str, str_len + 1) ;
/* Plus one to catch string terminator. */
psf->str_end += str_len + 1 ;
psf->str_flags |= str_flags ;
#if STRINGS_DEBUG
psf_log_printf (psf, "str_storage : %X\n", (int) psf->str_storage) ;
psf_log_printf (psf, "str_end : %X\n", (int) psf->str_end) ;
psf_log_printf (psf, "sizeof (str_storage) : %d\n", SIGNED_SIZEOF (psf->str_storage)) ;
psf_log_printf (psf, "used : %d\n", (int ) (psf->str_end - psf->str_storage)) ;
psf_log_printf (psf, "remaining : %d\n", SIGNED_SIZEOF (psf->str_storage) - (psf->str_end - psf->str_storage)) ;
hexdump (psf->str_storage, 300) ;
#endif
return 0 ;
} /* psf_store_string */
int
psf_set_string (SF_PRIVATE *psf, int str_type, const char *str)
{ if (psf->file.mode == SFM_READ)
return SFE_STR_NOT_WRITE ;
return psf_store_string (psf, str_type, str) ;
} /* psf_set_string */
const char*
psf_get_string (SF_PRIVATE *psf, int str_type)
{ int k ;
for (k = 0 ; k < SF_MAX_STRINGS ; k++)
if (str_type == psf->strings [k].type)
return psf->strings [k].str ;
return NULL ;
} /* psf_get_string */
int
psf_location_string_count (const SF_PRIVATE * psf, int location)
{ int k, count = 0 ;
for (k = 0 ; k < SF_MAX_STRINGS ; k++)
if (psf->strings [k].type > 0 && psf->strings [k].flags & location)
count ++ ;
return count ;
} /* psf_location_string_count */
/*==============================================================================
*/
#if STRINGS_DEBUG
#include <ctype.h>
static void
hexdump (void *data, int len)
{ unsigned char *ptr ;
int k ;
ptr = data ;
puts ("---------------------------------------------------------") ;
while (len >= 16)
{ for (k = 0 ; k < 16 ; k++)
printf ("%02X ", ptr [k] & 0xFF) ;
printf (" ") ;
for (k = 0 ; k < 16 ; k++)
printf ("%c", psf_isprint (ptr [k]) ? ptr [k] : '.') ;
puts ("") ;
ptr += 16 ;
len -= 16 ;
} ;
} /* hexdump */
#endif

View File

@@ -0,0 +1,416 @@
/*
** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
/*------------------------------------------------------------------------------
* Macros to handle big/little endian issues.
*/
#define FORM_MARKER (MAKE_MARKER ('F', 'O', 'R', 'M'))
#define SVX8_MARKER (MAKE_MARKER ('8', 'S', 'V', 'X'))
#define SV16_MARKER (MAKE_MARKER ('1', '6', 'S', 'V'))
#define VHDR_MARKER (MAKE_MARKER ('V', 'H', 'D', 'R'))
#define BODY_MARKER (MAKE_MARKER ('B', 'O', 'D', 'Y'))
#define ATAK_MARKER (MAKE_MARKER ('A', 'T', 'A', 'K'))
#define RLSE_MARKER (MAKE_MARKER ('R', 'L', 'S', 'E'))
#define c_MARKER (MAKE_MARKER ('(', 'c', ')', ' '))
#define NAME_MARKER (MAKE_MARKER ('N', 'A', 'M', 'E'))
#define AUTH_MARKER (MAKE_MARKER ('A', 'U', 'T', 'H'))
#define ANNO_MARKER (MAKE_MARKER ('A', 'N', 'N', 'O'))
#define CHAN_MARKER (MAKE_MARKER ('C', 'H', 'A', 'N'))
/*------------------------------------------------------------------------------
* Typedefs for file chunks.
*/
typedef struct
{ unsigned int oneShotHiSamples, repeatHiSamples, samplesPerHiCycle ;
unsigned short samplesPerSec ;
unsigned char octave, compression ;
unsigned int volume ;
} VHDR_CHUNK ;
enum {
HAVE_FORM = 0x01,
HAVE_SVX = 0x02,
HAVE_VHDR = 0x04,
HAVE_BODY = 0x08
} ;
/*------------------------------------------------------------------------------
* Private static functions.
*/
static int svx_close (SF_PRIVATE *psf) ;
static int svx_write_header (SF_PRIVATE *psf, int calc_length) ;
static int svx_read_header (SF_PRIVATE *psf) ;
/*------------------------------------------------------------------------------
** Public function.
*/
int
svx_open (SF_PRIVATE *psf)
{ int error ;
if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
{ if ((error = svx_read_header (psf)))
return error ;
psf->endian = SF_ENDIAN_BIG ; /* All SVX files are big endian. */
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
if (psf->blockwidth)
psf->sf.frames = psf->datalength / psf->blockwidth ;
psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
} ;
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
{ if (psf->is_pipe)
return SFE_NO_PIPE_WRITE ;
if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_SVX)
return SFE_BAD_OPEN_FORMAT ;
psf->endian = SF_ENDIAN (psf->sf.format) ;
if (psf->endian == SF_ENDIAN_LITTLE || (CPU_IS_LITTLE_ENDIAN && psf->endian == SF_ENDIAN_CPU))
return SFE_BAD_ENDIAN ;
psf->endian = SF_ENDIAN_BIG ; /* All SVX files are big endian. */
error = svx_write_header (psf, SF_FALSE) ;
if (error)
return error ;
psf->write_header = svx_write_header ;
} ;
psf->container_close = svx_close ;
if ((error = pcm_init (psf)))
return error ;
return 0 ;
} /* svx_open */
/*------------------------------------------------------------------------------
*/
static int
svx_read_header (SF_PRIVATE *psf)
{ VHDR_CHUNK vhdr ;
unsigned int FORMsize, vhdrsize, dword, marker ;
int filetype = 0, parsestage = 0, done = 0 ;
int bytecount = 0, channels ;
if (psf->filelength > SF_PLATFORM_S64 (0xffffffff))
psf_log_printf (psf, "Warning : filelength > 0xffffffff. This is bad!!!!\n") ;
memset (&vhdr, 0, sizeof (vhdr)) ;
psf_binheader_readf (psf, "p", 0) ;
/* Set default number of channels. Modify later if necessary */
psf->sf.channels = 1 ;
psf->sf.format = SF_FORMAT_SVX ;
while (! done)
{ psf_binheader_readf (psf, "m", &marker) ;
switch (marker)
{ case FORM_MARKER :
if (parsestage)
return SFE_SVX_NO_FORM ;
psf_binheader_readf (psf, "E4", &FORMsize) ;
if (FORMsize != psf->filelength - 2 * sizeof (dword))
{ dword = psf->filelength - 2 * sizeof (dword) ;
psf_log_printf (psf, "FORM : %d (should be %d)\n", FORMsize, dword) ;
FORMsize = dword ;
}
else
psf_log_printf (psf, "FORM : %d\n", FORMsize) ;
parsestage |= HAVE_FORM ;
break ;
case SVX8_MARKER :
case SV16_MARKER :
if (! (parsestage & HAVE_FORM))
return SFE_SVX_NO_FORM ;
filetype = marker ;
psf_log_printf (psf, " %M\n", marker) ;
parsestage |= HAVE_SVX ;
break ;
case VHDR_MARKER :
if (! (parsestage & (HAVE_FORM | HAVE_SVX)))
return SFE_SVX_NO_FORM ;
psf_binheader_readf (psf, "E4", &vhdrsize) ;
psf_log_printf (psf, " VHDR : %d\n", vhdrsize) ;
psf_binheader_readf (psf, "E4442114", &(vhdr.oneShotHiSamples), &(vhdr.repeatHiSamples),
&(vhdr.samplesPerHiCycle), &(vhdr.samplesPerSec), &(vhdr.octave), &(vhdr.compression),
&(vhdr.volume)) ;
psf_log_printf (psf, " OneShotHiSamples : %d\n", vhdr.oneShotHiSamples) ;
psf_log_printf (psf, " RepeatHiSamples : %d\n", vhdr.repeatHiSamples) ;
psf_log_printf (psf, " samplesPerHiCycle : %d\n", vhdr.samplesPerHiCycle) ;
psf_log_printf (psf, " Sample Rate : %d\n", vhdr.samplesPerSec) ;
psf_log_printf (psf, " Octave : %d\n", vhdr.octave) ;
psf_log_printf (psf, " Compression : %d => ", vhdr.compression) ;
switch (vhdr.compression)
{ case 0 : psf_log_printf (psf, "None.\n") ;
break ;
case 1 : psf_log_printf (psf, "Fibonacci delta\n") ;
break ;
case 2 : psf_log_printf (psf, "Exponential delta\n") ;
break ;
} ;
psf_log_printf (psf, " Volume : %d\n", vhdr.volume) ;
psf->sf.samplerate = vhdr.samplesPerSec ;
if (filetype == SVX8_MARKER)
{ psf->sf.format |= SF_FORMAT_PCM_S8 ;
psf->bytewidth = 1 ;
}
else if (filetype == SV16_MARKER)
{ psf->sf.format |= SF_FORMAT_PCM_16 ;
psf->bytewidth = 2 ;
} ;
parsestage |= HAVE_VHDR ;
break ;
case BODY_MARKER :
if (! (parsestage & HAVE_VHDR))
return SFE_SVX_NO_BODY ;
psf_binheader_readf (psf, "E4", &dword) ;
psf->datalength = dword ;
psf->dataoffset = psf_ftell (psf) ;
if (psf->dataoffset < 0)
return SFE_SVX_NO_BODY ;
if (psf->datalength > psf->filelength - psf->dataoffset)
{ psf_log_printf (psf, " BODY : %D (should be %D)\n", psf->datalength, psf->filelength - psf->dataoffset) ;
psf->datalength = psf->filelength - psf->dataoffset ;
}
else
psf_log_printf (psf, " BODY : %D\n", psf->datalength) ;
parsestage |= HAVE_BODY ;
if (! psf->sf.seekable)
break ;
psf_fseek (psf, psf->datalength, SEEK_CUR) ;
break ;
case NAME_MARKER :
if (! (parsestage & HAVE_SVX))
return SFE_SVX_NO_FORM ;
psf_binheader_readf (psf, "E4", &dword) ;
psf_log_printf (psf, " %M : %d\n", marker, dword) ;
if (strlen (psf->file.name.c) != dword)
{ if (dword > sizeof (psf->file.name.c) - 1)
return SFE_SVX_BAD_NAME_LENGTH ;
psf_binheader_readf (psf, "b", psf->file.name.c, dword) ;
psf->file.name.c [dword] = 0 ;
}
else
psf_binheader_readf (psf, "j", dword) ;
break ;
case ANNO_MARKER :
if (! (parsestage & HAVE_SVX))
return SFE_SVX_NO_FORM ;
psf_binheader_readf (psf, "E4", &dword) ;
psf_log_printf (psf, " %M : %d\n", marker, dword) ;
psf_binheader_readf (psf, "j", dword) ;
break ;
case CHAN_MARKER :
if (! (parsestage & HAVE_SVX))
return SFE_SVX_NO_FORM ;
psf_binheader_readf (psf, "E4", &dword) ;
psf_log_printf (psf, " %M : %d\n", marker, dword) ;
bytecount += psf_binheader_readf (psf, "E4", &channels) ;
if (channels == 2 || channels == 4)
psf_log_printf (psf, " Channels : %d => mono\n", channels) ;
else if (channels == 6)
{ psf->sf.channels = 2 ;
psf_log_printf (psf, " Channels : %d => stereo\n", channels) ;
}
else
psf_log_printf (psf, " Channels : %d *** assuming mono\n", channels) ;
psf_binheader_readf (psf, "j", dword - bytecount) ;
break ;
case AUTH_MARKER :
case c_MARKER :
if (! (parsestage & HAVE_SVX))
return SFE_SVX_NO_FORM ;
psf_binheader_readf (psf, "E4", &dword) ;
psf_log_printf (psf, " %M : %d\n", marker, dword) ;
psf_binheader_readf (psf, "j", dword) ;
break ;
default :
if (psf_isprint ((marker >> 24) & 0xFF) && psf_isprint ((marker >> 16) & 0xFF)
&& psf_isprint ((marker >> 8) & 0xFF) && psf_isprint (marker & 0xFF))
{ psf_binheader_readf (psf, "E4", &dword) ;
psf_log_printf (psf, "%M : %d (unknown marker)\n", marker, dword) ;
psf_binheader_readf (psf, "j", dword) ;
break ;
} ;
if ((dword = psf_ftell (psf)) & 0x03)
{ psf_log_printf (psf, " Unknown chunk marker at position %d. Resynching.\n", dword - 4) ;
psf_binheader_readf (psf, "j", -3) ;
break ;
} ;
psf_log_printf (psf, "*** Unknown chunk marker : %X. Exiting parser.\n", marker) ;
done = 1 ;
} ; /* switch (marker) */
if (! psf->sf.seekable && (parsestage & HAVE_BODY))
break ;
if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (dword))
break ;
} ; /* while (1) */
if (vhdr.compression)
return SFE_SVX_BAD_COMP ;
if (psf->dataoffset <= 0)
return SFE_SVX_NO_DATA ;
return 0 ;
} /* svx_read_header */
static int
svx_close (SF_PRIVATE *psf)
{
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
svx_write_header (psf, SF_TRUE) ;
return 0 ;
} /* svx_close */
static int
svx_write_header (SF_PRIVATE *psf, int calc_length)
{ static char annotation [] = "libsndfile by Erik de Castro Lopo\0\0\0" ;
sf_count_t current ;
current = psf_ftell (psf) ;
if (calc_length)
{ psf->filelength = psf_get_filelen (psf) ;
psf->datalength = psf->filelength - psf->dataoffset ;
if (psf->dataend)
psf->datalength -= psf->filelength - psf->dataend ;
psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
} ;
psf->header [0] = 0 ;
psf->headindex = 0 ;
psf_fseek (psf, 0, SEEK_SET) ;
/* FORM marker and FORM size. */
psf_binheader_writef (psf, "Etm8", FORM_MARKER, (psf->filelength < 8) ?
psf->filelength * 0 : psf->filelength - 8) ;
psf_binheader_writef (psf, "m", (psf->bytewidth == 1) ? SVX8_MARKER : SV16_MARKER) ;
/* VHDR chunk. */
psf_binheader_writef (psf, "Em4", VHDR_MARKER, sizeof (VHDR_CHUNK)) ;
/* VHDR : oneShotHiSamples, repeatHiSamples, samplesPerHiCycle */
psf_binheader_writef (psf, "E444", psf->sf.frames, 0, 0) ;
/* VHDR : samplesPerSec, octave, compression */
psf_binheader_writef (psf, "E211", psf->sf.samplerate, 1, 0) ;
/* VHDR : volume */
psf_binheader_writef (psf, "E4", (psf->bytewidth == 1) ? 0xFF : 0xFFFF) ;
if (psf->sf.channels == 2)
psf_binheader_writef (psf, "Em44", CHAN_MARKER, 4, 6) ;
/* Filename and annotation strings. */
psf_binheader_writef (psf, "Emsms", NAME_MARKER, psf->file.name.c, ANNO_MARKER, annotation) ;
/* BODY marker and size. */
psf_binheader_writef (psf, "Etm8", BODY_MARKER, (psf->datalength < 0) ?
psf->datalength * 0 : psf->datalength) ;
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
if (psf->error)
return psf->error ;
psf->dataoffset = psf->headindex ;
if (current > 0)
psf_fseek (psf, current, SEEK_SET) ;
return psf->error ;
} /* svx_write_header */

View File

@@ -0,0 +1,372 @@
/*
** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program 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 program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*===========================================================================
** Yamaha TX16 Sampler Files.
**
** This header parser was written using information from the SoX source code
** and trial and error experimentation. The code here however is all original.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include "sndfile.h"
#include "sfendian.h"
#include "common.h"
#if (ENABLE_EXPERIMENTAL_CODE == 0)
int
txw_open (SF_PRIVATE *psf)
{ if (psf)
return SFE_UNIMPLEMENTED ;
return 0 ;
} /* txw_open */
#else
/*------------------------------------------------------------------------------
** Markers.
*/
#define TXW_DATA_OFFSET 32
#define TXW_LOOPED 0x49
#define TXW_NO_LOOP 0xC9
/*------------------------------------------------------------------------------
** Private static functions.
*/
static int txw_read_header (SF_PRIVATE *psf) ;
static sf_count_t txw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
static sf_count_t txw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
static sf_count_t txw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
static sf_count_t txw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
static sf_count_t txw_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
/*------------------------------------------------------------------------------
** Public functions.
*/
/*
* ftp://ftp.t0.or.at/pub/sound/tx16w/samples.yamaha
* ftp://ftp.t0.or.at/pub/sound/tx16w/faq/tx16w.tec
* http://www.t0.or.at/~mpakesch/tx16w/
*
* from tx16w.c sox 12.15: (7-Oct-98) (Mark Lakata and Leigh Smith)
* char filetype[6] "LM8953"
* nulls[10],
* dummy_aeg[6]
* format 0x49 = looped, 0xC9 = non-looped
* sample_rate 1 = 33 kHz, 2 = 50 kHz, 3 = 16 kHz
* atc_length[3] if sample rate 0, [2]&0xfe = 6: 33kHz, 0x10:50, 0xf6: 16,
* depending on [5] but to heck with it
* rpt_length[3] (these are for looped samples, attack and loop lengths)
* unused[2]
*/
typedef struct
{ unsigned char format, srate, sr2, sr3 ;
unsigned short srhash ;
unsigned int attacklen, repeatlen ;
} TXW_HEADER ;
#define ERROR_666 666
int
txw_open (SF_PRIVATE *psf)
{ int error ;
if (psf->file.mode != SFM_READ)
return SFE_UNIMPLEMENTED ;
if ((error = txw_read_header (psf)))
return error ;
if (psf_fseek (psf, psf->dataoffset, SEEK_SET) != psf->dataoffset)
return SFE_BAD_SEEK ;
psf->read_short = txw_read_s ;
psf->read_int = txw_read_i ;
psf->read_float = txw_read_f ;
psf->read_double = txw_read_d ;
psf->seek = txw_seek ;
return 0 ;
} /* txw_open */
/*------------------------------------------------------------------------------
*/
static int
txw_read_header (SF_PRIVATE *psf)
{ TXW_HEADER txwh ;
const char *strptr ;
memset (&txwh, 0, sizeof (txwh)) ;
memset (psf->u.cbuf, 0, sizeof (psf->u.cbuf)) ;
psf_binheader_readf (psf, "pb", 0, psf->u.cbuf, 16) ;
if (memcmp (psf->u.cbuf, "LM8953\0\0\0\0\0\0\0\0\0\0", 16) != 0)
return ERROR_666 ;
psf_log_printf (psf, "Read only : Yamaha TX-16 Sampler (.txw)\nLM8953\n") ;
/* Jump 6 bytes (dummp_aeg), read format, read sample rate. */
psf_binheader_readf (psf, "j11", 6, &txwh.format, &txwh.srate) ;
/* 8 bytes (atc_length[3], rpt_length[3], unused[2]). */
psf_binheader_readf (psf, "e33j", &txwh.attacklen, &txwh.repeatlen, 2) ;
txwh.sr2 = (txwh.attacklen >> 16) & 0xFE ;
txwh.sr3 = (txwh.repeatlen >> 16) & 0xFE ;
txwh.attacklen &= 0x1FFFF ;
txwh.repeatlen &= 0x1FFFF ;
switch (txwh.format)
{ case TXW_LOOPED :
strptr = "looped" ;
break ;
case TXW_NO_LOOP :
strptr = "non-looped" ;
break ;
default :
psf_log_printf (psf, " Format : 0x%02x => ?????\n", txwh.format) ;
return ERROR_666 ;
} ;
psf_log_printf (psf, " Format : 0x%02X => %s\n", txwh.format, strptr) ;
strptr = NULL ;
switch (txwh.srate)
{ case 1 :
psf->sf.samplerate = 33333 ;
break ;
case 2 :
psf->sf.samplerate = 50000 ;
break ;
case 3 :
psf->sf.samplerate = 16667 ;
break ;
default :
/* This is ugly and braindead. */
txwh.srhash = ((txwh.sr2 & 0xFE) << 8) | (txwh.sr3 & 0xFE) ;
switch (txwh.srhash)
{ case ((0x6 << 8) | 0x52) :
psf->sf.samplerate = 33333 ;
break ;
case ((0x10 << 8) | 0x52) :
psf->sf.samplerate = 50000 ;
break ;
case ((0xF6 << 8) | 0x52) :
psf->sf.samplerate = 166667 ;
break ;
default :
strptr = " Sample Rate : Unknown : forcing to 33333\n" ;
psf->sf.samplerate = 33333 ;
break ;
} ;
} ;
if (strptr)
psf_log_printf (psf, strptr) ;
else if (txwh.srhash)
psf_log_printf (psf, " Sample Rate : %d (0x%X) => %d\n", txwh.srate, txwh.srhash, psf->sf.samplerate) ;
else
psf_log_printf (psf, " Sample Rate : %d => %d\n", txwh.srate, psf->sf.samplerate) ;
if (txwh.format == TXW_LOOPED)
{ psf_log_printf (psf, " Attack Len : %d\n", txwh.attacklen) ;
psf_log_printf (psf, " Repeat Len : %d\n", txwh.repeatlen) ;
} ;
psf->dataoffset = TXW_DATA_OFFSET ;
psf->datalength = psf->filelength - TXW_DATA_OFFSET ;
psf->sf.frames = 2 * psf->datalength / 3 ;
if (psf->datalength % 3 == 1)
psf_log_printf (psf, "*** File seems to be truncated, %d extra bytes.\n",
(int) (psf->datalength % 3)) ;
if (txwh.attacklen + txwh.repeatlen > psf->sf.frames)
psf_log_printf (psf, "*** File has been truncated.\n") ;
psf->sf.format = SF_FORMAT_TXW | SF_FORMAT_PCM_16 ;
psf->sf.channels = 1 ;
psf->sf.sections = 1 ;
psf->sf.seekable = SF_TRUE ;
return 0 ;
} /* txw_read_header */
static sf_count_t
txw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
{ unsigned char *ucptr ;
short sample ;
int k, bufferlen, readcount, count ;
sf_count_t total = 0 ;
bufferlen = sizeof (psf->u.cbuf) / 3 ;
bufferlen -= (bufferlen & 1) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = psf_fread (psf->u.cbuf, 3, readcount, psf) ;
ucptr = psf->u.ucbuf ;
for (k = 0 ; k < readcount ; k += 2)
{ sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ;
ptr [total + k] = sample ;
sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ;
ptr [total + k + 1] = sample ;
ucptr += 3 ;
} ;
total += count ;
len -= readcount ;
} ;
return total ;
} /* txw_read_s */
static sf_count_t
txw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
{ unsigned char *ucptr ;
short sample ;
int k, bufferlen, readcount, count ;
sf_count_t total = 0 ;
bufferlen = sizeof (psf->u.cbuf) / 3 ;
bufferlen -= (bufferlen & 1) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = psf_fread (psf->u.cbuf, 3, readcount, psf) ;
ucptr = psf->u.ucbuf ;
for (k = 0 ; k < readcount ; k += 2)
{ sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ;
ptr [total + k] = sample << 16 ;
sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ;
ptr [total + k + 1] = sample << 16 ;
ucptr += 3 ;
} ;
total += count ;
len -= readcount ;
} ;
return total ;
} /* txw_read_i */
static sf_count_t
txw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
{ unsigned char *ucptr ;
short sample ;
int k, bufferlen, readcount, count ;
sf_count_t total = 0 ;
float normfact ;
if (psf->norm_float == SF_TRUE)
normfact = 1.0 / 0x8000 ;
else
normfact = 1.0 / 0x10 ;
bufferlen = sizeof (psf->u.cbuf) / 3 ;
bufferlen -= (bufferlen & 1) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = psf_fread (psf->u.cbuf, 3, readcount, psf) ;
ucptr = psf->u.ucbuf ;
for (k = 0 ; k < readcount ; k += 2)
{ sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ;
ptr [total + k] = normfact * sample ;
sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ;
ptr [total + k + 1] = normfact * sample ;
ucptr += 3 ;
} ;
total += count ;
len -= readcount ;
} ;
return total ;
} /* txw_read_f */
static sf_count_t
txw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
{ unsigned char *ucptr ;
short sample ;
int k, bufferlen, readcount, count ;
sf_count_t total = 0 ;
double normfact ;
if (psf->norm_double == SF_TRUE)
normfact = 1.0 / 0x8000 ;
else
normfact = 1.0 / 0x10 ;
bufferlen = sizeof (psf->u.cbuf) / 3 ;
bufferlen -= (bufferlen & 1) ;
while (len > 0)
{ readcount = (len >= bufferlen) ? bufferlen : len ;
count = psf_fread (psf->u.cbuf, 3, readcount, psf) ;
ucptr = psf->u.ucbuf ;
for (k = 0 ; k < readcount ; k += 2)
{ sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ;
ptr [total + k] = normfact * sample ;
sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ;
ptr [total + k + 1] = normfact * sample ;
ucptr += 3 ;
} ;
total += count ;
len -= readcount ;
} ;
return total ;
} /* txw_read_d */
static sf_count_t
txw_seek (SF_PRIVATE *psf, int mode, sf_count_t offset)
{ if (psf && mode)
return offset ;
return 0 ;
} /* txw_seek */
#endif

Some files were not shown because too many files have changed in this diff Show More